From 1d12ac8849c10c77f46ab8b051d881605e1016cf Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Fri, 16 Sep 2005 10:24:37 +0500 Subject: [PATCH] Bug#10504 Character set does not support traditional mode ctype_utf8.result, ctype_utf8.test: adding test case. password.c, mysql_com.h Changeing octet2hex availability from static to public. item_strfunc.cc: Result string is now checked to be well-formed. Warning/error is generated, depending on sql_mode. --- include/mysql_com.h | 1 + mysql-test/r/ctype_utf8.result | 33 +++++++++++++++++++++++++++++++++ mysql-test/t/ctype_utf8.test | 16 ++++++++++++++++ sql/item_strfunc.cc | 27 +++++++++++++++++++++++++++ sql/password.c | 4 ++-- 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 969fba4a433..c4eb33a6c9a 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -409,6 +409,7 @@ my_bool check_scramble(const char *reply, const char *message, const unsigned char *hash_stage2); void get_salt_from_password(unsigned char *res, const char *password); void make_password_from_salt(char *to, const unsigned char *hash_stage2); +void octet2hex(char *to, const unsigned char *str, unsigned int len); /* end of password.c */ diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 844750e3fed..eeeb0897b88 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1028,6 +1028,39 @@ xxx yyy DROP TABLE t1; set names utf8; +select hex(char(1)); +hex(char(1)) +01 +select char(0xd1,0x8f); +char(0xd1,0x8f) +я +select char(0xff,0x8f); +char(0xff,0x8f) + +Warnings: +Warning 1300 Invalid utf8 character string: 'FF8F' +set sql_mode=traditional; +select char(0xff,0x8f); +char(0xff,0x8f) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'FF8F' +select char(195); +char(195) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'C3' +select char(196); +char(196) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'C4' +select char(2557); +char(2557) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'FD' +set names utf8; create table t1 (a char(1)) default character set utf8; create table t2 (a char(1)) default character set utf8; insert into t1 values('a'),('a'),(0xE38182),(0xE38182); diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 3a89da3a41e..920506a0eb9 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -864,6 +864,22 @@ SELECT DISTINCT id FROM t1 ORDER BY id; DROP TABLE t1; +# +# Bugs#10504: Character set does not support traditional mode +# +set names utf8; +# correct value +select hex(char(1)); +select char(0xd1,0x8f); +# incorrect value: return with warning +select char(0xff,0x8f); +# incorrect value in strict mode: return NULL with "Error" level warning +set sql_mode=traditional; +select char(0xff,0x8f); +select char(195); +select char(196); +select char(2557); + # # Bug#12891: UNION doesn't return DISTINCT result for multi-byte characters # diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4fd33c06095..309e6dcdcd2 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1980,6 +1980,33 @@ b1: str->append((char)(num>>8)); } 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, (const uchar*) 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; } diff --git a/sql/password.c b/sql/password.c index 60cc0ac0c97..aa05be8c740 100644 --- a/sql/password.c +++ b/sql/password.c @@ -318,8 +318,8 @@ void create_random_string(char *to, uint length, struct rand_struct *rand_st) str, len IN the beginning and the length of the input string */ -static void -octet2hex(char *to, const uint8 *str, uint len) +void +octet2hex(char *to, const unsigned char *str, uint len) { const uint8 *str_end= str + len; for (; str != str_end; ++str)