diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 874983daff2..c57b06f4895 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1095,6 +1095,11 @@ char(0xff,0x8f using utf8) Warnings: Warning 1300 Invalid utf8 character string: 'FF8F' +select convert(char(0xff,0x8f) using utf8); +convert(char(0xff,0x8f) using utf8) + +Warnings: +Warning 1300 Invalid utf8 character string: 'FF8F' set sql_mode=traditional; select char(0xff,0x8f using utf8); char(0xff,0x8f using utf8) @@ -1116,6 +1121,11 @@ char(2557 using utf8) NULL Warnings: Error 1300 Invalid utf8 character string: 'FD' +select convert(char(0xff,0x8f) using utf8); +convert(char(0xff,0x8f) using utf8) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'FF8F' select hex(convert(char(2557 using latin1) using utf8)); hex(convert(char(2557 using latin1) using utf8)) 09C3BD diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 5670e9efbf9..a96564f4e76 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -884,7 +884,9 @@ SELECT DISTINCT id FROM t1 ORDER BY id; DROP TABLE t1; # -# Bugs#10504: Character set does not support traditional mode +# Bug#10504: Character set does not support traditional mode +# Bug#14146: CHAR(...USING ...) and CONVERT(CHAR(...) USING...) +# produce different results # set names utf8; # correct value @@ -894,12 +896,14 @@ select char(0xd18f using utf8); select char(53647 using utf8); # incorrect value: return with warning select char(0xff,0x8f using utf8); +select convert(char(0xff,0x8f) using utf8); # incorrect value in strict mode: return NULL with "Error" level warning set sql_mode=traditional; select char(0xff,0x8f using utf8); select char(195 using utf8); select char(196 using utf8); select char(2557 using utf8); +select convert(char(0xff,0x8f) using utf8); # # Check convert + char + using diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index a8c51bb6662..c33b7403b9c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -48,6 +48,38 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, } +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; +} + + double Item_str_func::val_real() { DBUG_ASSERT(fixed == 1); @@ -1984,34 +2016,7 @@ String *Item_func_char::val_str(String *str) } str->set_charset(collation.collation); str->realloc(str->length()); // Add end 0 (for Purify) - - /* Check whether we got a well-formed string */ - CHARSET_INFO *cs= collation.collation; - 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; + return check_well_formed_result(str); } @@ -2320,7 +2325,7 @@ String *Item_func_conv_charset::val_str(String *str) } null_value= str_value.copy(arg->ptr(),arg->length(),arg->charset(), conv_charset, &dummy_errors); - return null_value ? 0 : &str_value; + return null_value ? 0 : check_well_formed_result(&str_value); } void Item_func_conv_charset::fix_length_and_dec() diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 81f809d2b67..522b17bf80e 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -35,6 +35,7 @@ public: double val_real(); enum Item_result result_type () const { return STRING_RESULT; } void left_right_max_length(); + String *check_well_formed_result(String *str); }; class Item_func_md5 :public Item_str_func