Bug#30981 CHAR(0x41 USING ucs2) doesn't add leading zero

Bug#30982 CHAR(..USING..) can return a not-well-formed string
Bug#30986 Character set introducer followed by a HEX string can return bad result
check_well_formed_result moved to Item from Item_str_func
fixed Item_func_char::val_str for proper ucs symbols converting
added check for well formed strings for correct conversion of constants with underscore
charset
parent 20ec6605
...@@ -922,4 +922,7 @@ ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_gen ...@@ -922,4 +922,7 @@ ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_gen
select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0); select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0);
ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_general_ci,COERCIBLE) for operation '=' ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_general_ci,COERCIBLE) for operation '='
drop table t1; drop table t1;
select hex(char(0x41 using ucs2));
hex(char(0x41 using ucs2))
0041
End of 5.0 tests End of 5.0 tests
...@@ -1538,12 +1538,12 @@ char(53647 using utf8) ...@@ -1538,12 +1538,12 @@ char(53647 using utf8)
я я
select char(0xff,0x8f using utf8); select char(0xff,0x8f using utf8);
char(0xff,0x8f using utf8) char(0xff,0x8f using utf8)
Warnings: Warnings:
Warning 1300 Invalid utf8 character string: 'FF8F' Warning 1300 Invalid utf8 character string: 'FF8F'
select convert(char(0xff,0x8f) using utf8); select convert(char(0xff,0x8f) using utf8);
convert(char(0xff,0x8f) using utf8) convert(char(0xff,0x8f) using utf8)
Warnings: Warnings:
Warning 1300 Invalid utf8 character string: 'FF8F' Warning 1300 Invalid utf8 character string: 'FF8F'
set sql_mode=traditional; set sql_mode=traditional;
...@@ -1730,3 +1730,65 @@ i ...@@ -1730,3 +1730,65 @@ i
1 1
н1234567890 н1234567890
DROP TABLE t1, t2; DROP TABLE t1, t2;
set sql_mode=traditional;
select hex(char(0xFF using utf8));
hex(char(0xFF using utf8))
NULL
Warnings:
Error 1300 Invalid utf8 character string: 'FF'
select hex(convert(0xFF using utf8));
hex(convert(0xFF using utf8))
NULL
Warnings:
Error 1300 Invalid utf8 character string: 'FF'
select hex(_utf8 0x616263FF);
hex(_utf8 0x616263FF)
NULL
Warnings:
Error 1300 Invalid utf8 character string: 'FF'
select hex(_utf8 X'616263FF');
hex(_utf8 X'616263FF')
NULL
Warnings:
Error 1300 Invalid utf8 character string: 'FF'
select hex(_utf8 B'001111111111');
hex(_utf8 B'001111111111')
NULL
Warnings:
Error 1300 Invalid utf8 character string: 'FF'
select (_utf8 X'616263FF');
(_utf8 X'616263FF')
NULL
Warnings:
Error 1300 Invalid utf8 character string: 'FF'
set sql_mode=default;
select hex(char(0xFF using utf8));
hex(char(0xFF using utf8))
Warnings:
Warning 1300 Invalid utf8 character string: 'FF'
select hex(convert(0xFF using utf8));
hex(convert(0xFF using utf8))
Warnings:
Warning 1300 Invalid utf8 character string: 'FF'
select hex(_utf8 0x616263FF);
hex(_utf8 0x616263FF)
616263
Warnings:
Warning 1300 Invalid utf8 character string: 'FF'
select hex(_utf8 X'616263FF');
hex(_utf8 X'616263FF')
616263
Warnings:
Warning 1300 Invalid utf8 character string: 'FF'
select hex(_utf8 B'001111111111');
hex(_utf8 B'001111111111')
03
Warnings:
Warning 1300 Invalid utf8 character string: 'FF'
select (_utf8 X'616263FF');
(_utf8 X'616263FF')
abc
Warnings:
Warning 1300 Invalid utf8 character string: 'FF'
...@@ -651,4 +651,9 @@ select * from t1 where a=if(b<10,_ucs2 0x00C0,_ucs2 0x0062); ...@@ -651,4 +651,9 @@ select * from t1 where a=if(b<10,_ucs2 0x00C0,_ucs2 0x0062);
select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0); select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0);
drop table t1; drop table t1;
#
# Bug#30981 CHAR(0x41 USING ucs2) doesn't add leading zero
#
select hex(char(0x41 using ucs2));
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -1403,3 +1403,22 @@ SELECT b FROM t2 UNION SELECT c FROM t1; ...@@ -1403,3 +1403,22 @@ SELECT b FROM t2 UNION SELECT c FROM t1;
SELECT i FROM t2 UNION SELECT c FROM t1; SELECT i FROM t2 UNION SELECT c FROM t1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# Bug#30982: CHAR(..USING..) can return a not-well-formed string
# Bug #30986: Character set introducer followed by a HEX string can return bad result
#
set sql_mode=traditional;
select hex(char(0xFF using utf8));
select hex(convert(0xFF using utf8));
select hex(_utf8 0x616263FF);
select hex(_utf8 X'616263FF');
select hex(_utf8 B'001111111111');
select (_utf8 X'616263FF');
set sql_mode=default;
select hex(char(0xFF using utf8));
select hex(convert(0xFF using utf8));
select hex(_utf8 0x616263FF);
select hex(_utf8 X'616263FF');
select hex(_utf8 B'001111111111');
select (_utf8 X'616263FF');
...@@ -4247,6 +4247,41 @@ bool Item::is_datetime() ...@@ -4247,6 +4247,41 @@ bool Item::is_datetime()
} }
String *Item::check_well_formed_result(String *str)
{
/* Check whether we got a well-formed string */
CHARSET_INFO *cs= str->charset();
int well_formed_error;
uint wlen= cs->cset->well_formed_len(cs,
str->ptr(), str->ptr() + str->length(),
str->length(), &well_formed_error);
if (wlen < str->length())
{
THD *thd= current_thd;
char hexbuf[7];
enum MYSQL_ERROR::enum_warning_level level;
uint diff= str->length() - wlen;
set_if_smaller(diff, 3);
octet2hex(hexbuf, str->ptr() + wlen, diff);
if (thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))
{
level= MYSQL_ERROR::WARN_LEVEL_ERROR;
null_value= 1;
str= 0;
}
else
{
level= MYSQL_ERROR::WARN_LEVEL_WARN;
str->length(wlen);
}
push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
}
return str;
}
/* /*
Create a field to hold a string value from an item Create a field to hold a string value from an item
......
...@@ -870,6 +870,7 @@ public: ...@@ -870,6 +870,7 @@ public:
*/ */
virtual bool result_as_longlong() { return FALSE; } virtual bool result_as_longlong() { return FALSE; }
bool is_datetime(); bool is_datetime();
String *check_well_formed_result(String *str);
}; };
......
...@@ -38,36 +38,6 @@ C_MODE_END ...@@ -38,36 +38,6 @@ C_MODE_END
String my_empty_string("",default_charset_info); String my_empty_string("",default_charset_info);
String *Item_str_func::check_well_formed_result(String *str)
{
/* Check whether we got a well-formed string */
CHARSET_INFO *cs= str->charset();
int well_formed_error;
uint wlen= cs->cset->well_formed_len(cs,
str->ptr(), str->ptr() + str->length(),
str->length(), &well_formed_error);
if (wlen < str->length())
{
THD *thd= current_thd;
char hexbuf[7];
enum MYSQL_ERROR::enum_warning_level level;
uint diff= str->length() - wlen;
set_if_smaller(diff, 3);
octet2hex(hexbuf, str->ptr() + wlen, diff);
if (thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))
{
level= MYSQL_ERROR::WARN_LEVEL_ERROR;
null_value= 1;
str= 0;
}
else
level= MYSQL_ERROR::WARN_LEVEL_WARN;
push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
}
return str;
}
bool Item_str_func::fix_fields(THD *thd, Item **ref) bool Item_str_func::fix_fields(THD *thd, Item **ref)
...@@ -2229,11 +2199,13 @@ String *Item_func_char::val_str(String *str) ...@@ -2229,11 +2199,13 @@ String *Item_func_char::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
str->length(0); str->length(0);
str->set_charset(collation.collation);
for (uint i=0 ; i < arg_count ; i++) for (uint i=0 ; i < arg_count ; i++)
{ {
int32 num=(int32) args[i]->val_int(); int32 num=(int32) args[i]->val_int();
if (!args[i]->null_value) if (!args[i]->null_value)
{ {
char char_num= (char) num;
if (num&0xFF000000L) { if (num&0xFF000000L) {
str->append((char)(num>>24)); str->append((char)(num>>24));
goto b2; goto b2;
...@@ -2243,10 +2215,9 @@ String *Item_func_char::val_str(String *str) ...@@ -2243,10 +2215,9 @@ String *Item_func_char::val_str(String *str)
} else if (num&0xFF00L) { } else if (num&0xFF00L) {
b1: str->append((char)(num>>8)); b1: str->append((char)(num>>8));
} }
str->append((char) num); str->append(&char_num, 1);
} }
} }
str->set_charset(collation.collation);
str->realloc(str->length()); // Add end 0 (for Purify) str->realloc(str->length()); // Add end 0 (for Purify)
return check_well_formed_result(str); return check_well_formed_result(str);
} }
......
...@@ -35,7 +35,6 @@ public: ...@@ -35,7 +35,6 @@ public:
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return STRING_RESULT; } enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length(); void left_right_max_length();
String *check_well_formed_result(String *str);
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
}; };
......
...@@ -7716,11 +7716,19 @@ literal: ...@@ -7716,11 +7716,19 @@ literal:
String *str= tmp ? String *str= tmp ?
tmp->quick_fix_field(), tmp->val_str((String*) 0) : tmp->quick_fix_field(), tmp->val_str((String*) 0) :
(String*) 0; (String*) 0;
$$= new Item_string(str ? str->ptr() : "", $$= new Item_string(NULL, /* name will be set in select_item */
str ? str->ptr() : "",
str ? str->length() : 0, str ? str->length() : 0,
Lex->underscore_charset); Lex->underscore_charset);
if ($$) if ($$)
{
((Item_string *) $$)->set_repertoire_from_value(); ((Item_string *) $$)->set_repertoire_from_value();
if (!$$->check_well_formed_result(&$$->str_value))
{
$$= new Item_null();
$$->set_name(NULL, 0, system_charset_info);
}
}
} }
| UNDERSCORE_CHARSET BIN_NUM | UNDERSCORE_CHARSET BIN_NUM
{ {
...@@ -7732,9 +7740,15 @@ literal: ...@@ -7732,9 +7740,15 @@ literal:
String *str= tmp ? String *str= tmp ?
tmp->quick_fix_field(), tmp->val_str((String*) 0) : tmp->quick_fix_field(), tmp->val_str((String*) 0) :
(String*) 0; (String*) 0;
$$= new Item_string(str ? str->ptr() : "", $$= new Item_string(NULL, /* name will be set in select_item */
str ? str->length() : 0, str ? str->ptr() : "",
Lex->charset); str ? str->length() : 0,
Lex->underscore_charset);
if ($$ && !$$->check_well_formed_result(&$$->str_value))
{
$$= new Item_null();
$$->set_name(NULL, 0, system_charset_info);
}
} }
| DATE_SYM text_literal { $$ = $2; } | DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; } | TIME_SYM text_literal { $$ = $2; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment