From 5150fdcc04efca4e2dd7bb435bc0e3438cc2f5be Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Wed, 13 Jul 2005 13:00:17 +0500 Subject: [PATCH] ctype_utf8.result: adding test case sql_table.cc: sql_table.cc: - do not create a new item when charsets are the same - return ER_INVALID_DEFAULT if default value cannot be converted into the column character set. item.cc: - Allow conversion not only to Unicode, but also to and from "binary". - Adding safe_charset_converter() for Item_num and Item_varbinary, returning a fixed const Item. --- mysql-test/r/ctype_utf8.result | 4 ++++ mysql-test/t/ctype_utf8.test | 9 +++++++ sql/item.cc | 44 +++++++++++++++++++++++++++++++++- sql/item.h | 2 ++ sql/sql_table.cc | 11 ++++++--- 5 files changed, 66 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 3a8265b01f7..290d6d93421 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -905,6 +905,10 @@ select * from t1 where city = 'Durban '; id city 2 Durban drop table t1; +create table t1 (x set('A', 'B') default 0) character set utf8; +ERROR 42000: Invalid default value for 'x' +create table t1 (x enum('A', 'B') default 0) character set utf8; +ERROR 42000: Invalid default value for 'x' SET NAMES UTF8; CREATE TABLE t1 ( `id` int(20) NOT NULL auto_increment, diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 0a847057258..638d1f1de5c 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -747,6 +747,15 @@ select * from t1 where city = 'Durban'; select * from t1 where city = 'Durban '; drop table t1; +# +# Bug #11819 CREATE TABLE with a SET DEFAULT 0 and UTF8 crashes server. +# +--error 1067 +create table t1 (x set('A', 'B') default 0) character set utf8; +--error 1067 +create table t1 (x enum('A', 'B') default 0) character set utf8; + + # # Test for bug #11167: join for utf8 varchar value longer than 255 bytes # diff --git a/sql/item.cc b/sql/item.cc index c96794ff482..ee78d596891 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -212,15 +212,43 @@ bool Item::eq(const Item *item, bool binary_cmp) const Item *Item::safe_charset_converter(CHARSET_INFO *tocs) { /* + Allow conversion from and to "binary". Don't allow automatic conversion to non-Unicode charsets, as it potentially loses data. */ - if (!(tocs->state & MY_CS_UNICODE)) + if (collation.collation != &my_charset_bin && + tocs != &my_charset_bin && + !(tocs->state & MY_CS_UNICODE)) return NULL; // safe conversion is not possible return new Item_func_conv_charset(this, tocs); } +/* + Created mostly for mysql_prepare_table(). Important + when a string ENUM/SET column is described with a numeric default value: + + CREATE TABLE t1(a SET('a') DEFAULT 1); + + We cannot use generic Item::safe_charset_converter(), because + the latter returns a non-fixed Item, so val_str() crashes afterwards. + Override Item_num method, to return a fixed item. +*/ +Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs) +{ + Item_string *conv; + char buf[64]; + String *s, tmp(buf, sizeof(buf), &my_charset_bin); + s= val_str(&tmp); + if ((conv= new Item_string(s->ptr(), s->length(), s->charset()))) + { + conv->str_value.copy(); + conv->str_value.shrink_to_length(); + } + return conv; +} + + Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) { Item_string *conv; @@ -2151,6 +2179,20 @@ bool Item_varbinary::eq(const Item *arg, bool binary_cmp) const return FALSE; } + +Item *Item_varbinary::safe_charset_converter(CHARSET_INFO *tocs) +{ + Item_string *conv; + String tmp, *str= val_str(&tmp); + + if (!(conv= new Item_string(str->ptr(), str->length(), tocs))) + return NULL; + conv->str_value.copy(); + conv->str_value.shrink_to_length(); + return conv; +} + + /* Pack data in buffer for sending */ diff --git a/sql/item.h b/sql/item.h index 8de2adeb730..20d6718609c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -334,6 +334,7 @@ class Item_num: public Item { public: virtual Item_num *neg()= 0; + Item *safe_charset_converter(CHARSET_INFO *tocs); }; #define NO_CACHED_FIELD_INDEX ((uint)(-1)) @@ -835,6 +836,7 @@ public: // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} bool eq(const Item *item, bool binary_cmp) const; + virtual Item *safe_charset_converter(CHARSET_INFO *tocs); }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b68b20c32a3..e27cd7196ed 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -557,10 +557,15 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, Convert the default value from client character set into the column character set if necessary. */ - if (sql_field->def) + if (sql_field->def && cs != sql_field->def->collation.collation) { - sql_field->def= - sql_field->def->safe_charset_converter(cs); + if (!(sql_field->def= + sql_field->def->safe_charset_converter(cs))) + { + /* Could not convert */ + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(-1); + } } if (sql_field->sql_type == FIELD_TYPE_SET)