From 34122240cf5fbf4ddc86ff02cf2b7584d0ec81fa Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/sin.azundris.com" <> Date: Tue, 9 Jan 2007 20:23:12 +0100 Subject: [PATCH] Bug#24660: "enum" field type definition problem ENUMs weren't allowed to have character 0xff, a perfectly good character in many locales. This was circumvented by mapping 0xff in ENUMs to ',', thereby prevent actual commas from being used (because they too would get converted to 0xff on load). Now if 0xff makes an appearance, we find a character not used in the enum and use that as a separator. If no such character exists, we throw an error. Any solution would have broken some sort of existing behaviour. This solution should serve both fractions (those with 0xff and those with ',' in their enums), but WILL REQUIRE A DUMP/RESTORE CYCLE FROM THOSE WITH 0xff IN THEIR ENUMS. :-/ That is, mysqldump with their current server, and restore when upgrading to one with this patch. (port of the original 4.1 patch. incorporates some suggestions by kaamos.) --- mysql-test/r/type_enum.result | 26 +++++++++++++++ mysql-test/t/type_enum.test | 24 +++++++++++++- sql/table.cc | 11 ------- sql/unireg.cc | 61 +++++++++++++++++++++++------------ 4 files changed, 89 insertions(+), 33 deletions(-) diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result index b7db1d95587..70ef98af420 100644 --- a/mysql-test/r/type_enum.result +++ b/mysql-test/r/type_enum.result @@ -1754,3 +1754,29 @@ t1 CREATE TABLE `t1` ( `f2` enum('') DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +End of 4.1 tests +create table t1(russian enum('E','F','EF','FE') NOT NULL DEFAULT'E'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `russian` enum('E','F','EF','FE') NOT NULL DEFAULT 'E' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1(denormal enum('E','F','E,F','F,E') NOT NULL DEFAULT'E'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `denormal` enum('E','F','E,F','F,E') NOT NULL DEFAULT 'E' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1(russian_deviant enum('E','F','EF','F,E') NOT NULL DEFAULT'E'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `russian_deviant` enum('E','F','EF','F,E') NOT NULL DEFAULT 'E' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1(exhausting_charset enum('ABCDEFGHIJKLMNOPQRSTUVWXYZ',' +  !"','#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~','xx\','yy\','zz')); +ERROR 42000: Field separator argument is not what is expected; check the manual +End of 5.1 tests diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test index 68f5664c36d..9be1b7fa10f 100644 --- a/mysql-test/t/type_enum.test +++ b/mysql-test/t/type_enum.test @@ -136,4 +136,26 @@ alter table t1 add f2 enum(0xFFFF); show create table t1; drop table t1; -# End of 4.1 tests +--echo End of 4.1 tests + +# +# Bug#24660 "enum" field type definition problem +# +create table t1(russian enum('E','F','EF','FE') NOT NULL DEFAULT'E'); +show create table t1; +drop table t1; + +create table t1(denormal enum('E','F','E,F','F,E') NOT NULL DEFAULT'E'); +show create table t1; +drop table t1; + +create table t1(russian_deviant enum('E','F','EF','F,E') NOT NULL DEFAULT'E'); +show create table t1; +drop table t1; + +# ER_WRONG_FIELD_TERMINATORS +--error 1083 +create table t1(exhausting_charset enum('ABCDEFGHIJKLMNOPQRSTUVWXYZ',' +  !"','#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~','xx\','yy\','zz')); + +--echo End of 5.1 tests diff --git a/sql/table.cc b/sql/table.cc index e4e087b0e64..4896645c140 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -803,17 +803,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, { char *val= (char*) interval->type_names[count]; interval->type_lengths[count]= strlen(val); - /* - Replace all ',' symbols with NAMES_SEP_CHAR. - See the comment in unireg.cc, pack_fields() function - for details. - */ - for (uint cnt= 0 ; cnt < interval->type_lengths[count] ; cnt++) - { - char c= val[cnt]; - if (c == ',') - val[cnt]= NAMES_SEP_CHAR; - } } interval->type_lengths[count]= 0; } diff --git a/sql/unireg.cc b/sql/unireg.cc index 2699cafa7b7..10741240940 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -788,29 +788,48 @@ static bool pack_fields(File file, List &create_fields, { if (field->interval_id > int_count) { - int_count=field->interval_id; - tmp.append(NAMES_SEP_CHAR); - for (const char **pos=field->interval->type_names ; *pos ; pos++) - { - char *val= (char*) *pos; - uint str_len= strlen(val); - /* - Note, hack: in old frm NAMES_SEP_CHAR is used to separate - names in the interval (ENUM/SET). To allow names to contain - NAMES_SEP_CHAR, we replace it with a comma before writing frm. - Backward conversion is done during frm file opening, - See table.cc, openfrm() function - */ - for (uint cnt= 0 ; cnt < str_len ; cnt++) + unsigned char sep= 0; + unsigned char occ[256]; + uint i; + unsigned char *val= NULL; + + bzero(occ, sizeof(occ)); + + for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++) + for (uint j = 0; j < field->interval->type_lengths[i]; j++) + occ[(unsigned int) (val[j])]= 1; + + if (!occ[(unsigned char)NAMES_SEP_CHAR]) + sep= (unsigned char) NAMES_SEP_CHAR; + else if (!occ[(unsigned int)',']) + sep= ','; + else + { + for (uint i=1; i<256; i++) { - char c= val[cnt]; - if (c == NAMES_SEP_CHAR) - val[cnt]= ','; + if(!occ[i]) + { + sep= i; + break; + } } - tmp.append(*pos); - tmp.append(NAMES_SEP_CHAR); - } - tmp.append('\0'); // End of intervall + + if(!sep) /* disaster, enum uses all characters, none left as separator */ + { + my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS), + MYF(0)); + DBUG_RETURN(1); + } + } + + int_count= field->interval_id; + tmp.append(sep); + for (const char **pos=field->interval->type_names ; *pos ; pos++) + { + tmp.append(*pos); + tmp.append(sep); + } + tmp.append('\0'); // End of intervall } } if (my_write(file,(byte*) tmp.ptr(),tmp.length(),MYF_RW))