From 6b90806a4a5ee31ec9f5d9e59f1cd9e722dd1866 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Thu, 19 Aug 2004 15:00:55 +0500 Subject: [PATCH 1/7] ctype_utf8.test, ctype_utf8.result: Typo fix --- mysql-test/r/ctype_utf8.result | 4 ++-- mysql-test/t/ctype_utf8.test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 793e2ceff19..0cc3ea2cf17 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -362,13 +362,13 @@ c_a б drop table t1; create table t1 ( -c char(10) character set utf8 collate utf8_bin, +c char(10) character set utf8, unique key a using btree (c(1)) ) engine=heap; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `c` char(10) character set utf8 collate utf8_bin default NULL, + `c` char(10) character set utf8 default NULL, UNIQUE KEY `a` TYPE BTREE (`c`(1)) ) ENGINE=HEAP DEFAULT CHARSET=latin1 insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f'); diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 808e04c56d8..0d3bec258bc 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -265,7 +265,7 @@ drop table t1; # Check HEAP+BTREE, case insensitive collation # create table t1 ( -c char(10) character set utf8 collate utf8_bin, +c char(10) character set utf8, unique key a using btree (c(1)) ) engine=heap; show create table t1; From 2496e85b84aad64a273dcb6ee45bb4a706c4b87d Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Thu, 19 Aug 2004 15:15:10 +0500 Subject: [PATCH 2/7] Bug#4521: unique key prefix interacts poorly with utf8. Fix for binary collations for MyISAM and HEAP BTREE. This patch also changes trailing spaces behaviour for binary collations. Binary collations now have PAD characteristic too. --- myisam/mi_search.c | 15 +++- mysql-test/r/binary.result | 2 + mysql-test/r/ctype_utf8.result | 92 ++++++++++++++++++++++ mysql-test/r/endspace.result | 2 +- mysql-test/r/myisam.result | 1 + mysql-test/t/ctype_utf8.test | 106 ++++++++++++++++++++++++- sql/field.h | 2 +- sql/ha_berkeley.cc | 6 +- sql/item_cmpfunc.cc | 4 +- strings/ctype-bin.c | 138 ++++++++++++++++++++++++++------- strings/ctype-mb.c | 57 +++++++++++++- 11 files changed, 384 insertions(+), 41 deletions(-) diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 2f1c37e4f21..24f5db1401d 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -396,9 +396,18 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, matched=prefix_len+left; - for (my_flag=0;left;left--) - if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++])) - break; + if (sort_order) + { + for (my_flag=0;left;left--) + if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++])) + break; + } + else + { + for (my_flag=0;left;left--) + if ((my_flag= (int) *vseg++ - (int) *k++)) + break; + } if (my_flag>0) /* mismatch */ break; diff --git a/mysql-test/r/binary.result b/mysql-test/r/binary.result index 000c0c16d77..a4ced14bb12 100644 --- a/mysql-test/r/binary.result +++ b/mysql-test/r/binary.result @@ -59,8 +59,10 @@ concat("-",a,"-",b,"-") -hello-hello- select concat("-",a,"-",b,"-") from t1 where b="hello "; concat("-",a,"-",b,"-") +-hello-hello- select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; concat("-",a,"-",b,"-") +-hello-hello- alter table t1 modify b tinytext not null, drop key b, add key (b(100)); select concat("-",a,"-",b,"-") from t1; concat("-",a,"-",b,"-") diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 0cc3ea2cf17..cfad82fa053 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -397,3 +397,95 @@ select c as c_a from t1 where c='б'; c_a б drop table t1; +create table t1 (c varchar(30) character set utf8 collate utf8_bin, unique(c(10))); +insert into t1 values ('1'),('2'),('3'),('x'),('y'),('z'); +insert into t1 values ('aaaaaaaaaa'); +insert into t1 values ('aaaaaaaaaaa'); +ERROR 23000: Duplicate entry 'aaaaaaaaaaa' for key 1 +insert into t1 values ('aaaaaaaaaaaa'); +ERROR 23000: Duplicate entry 'aaaaaaaaaaaa' for key 1 +insert into t1 values (repeat('b',20)); +select c c1 from t1 where c='1'; +c1 +1 +select c c2 from t1 where c='2'; +c2 +2 +select c c3 from t1 where c='3'; +c3 +3 +select c cx from t1 where c='x'; +cx +x +select c cy from t1 where c='y'; +cy +y +select c cz from t1 where c='z'; +cz +z +select c ca10 from t1 where c='aaaaaaaaaa'; +ca10 +aaaaaaaaaa +select c cb20 from t1 where c=repeat('b',20); +cb20 +bbbbbbbbbbbbbbbbbbbb +drop table t1; +create table t1 (c char(3) character set utf8 collate utf8_bin, unique (c(2))); +insert into t1 values ('1'),('2'),('3'),('4'),('x'),('y'),('z'); +insert into t1 values ('a'); +insert into t1 values ('aa'); +insert into t1 values ('aaa'); +ERROR 23000: Duplicate entry 'aaa' for key 1 +insert into t1 values ('b'); +insert into t1 values ('bb'); +insert into t1 values ('bbb'); +ERROR 23000: Duplicate entry 'bbb' for key 1 +insert into t1 values ('а'); +insert into t1 values ('аа'); +insert into t1 values ('ааа'); +ERROR 23000: Duplicate entry 'ааа' for key 1 +insert into t1 values ('б'); +insert into t1 values ('бб'); +insert into t1 values ('ббб'); +ERROR 23000: Duplicate entry 'ббб' for key 1 +insert into t1 values ('ꪪ'); +insert into t1 values ('ꪪꪪ'); +insert into t1 values ('ꪪꪪꪪ'); +ERROR 23000: Duplicate entry 'ꪪꪪ' for key 1 +drop table t1; +create table t1 ( +c char(10) character set utf8 collate utf8_bin, +unique key a using btree (c(1)) +) engine=heap; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` char(10) character set utf8 collate utf8_bin default NULL, + UNIQUE KEY `a` TYPE BTREE (`c`(1)) +) ENGINE=HEAP DEFAULT CHARSET=latin1 +insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f'); +insert into t1 values ('aa'); +ERROR 23000: Duplicate entry 'aa' for key 1 +insert into t1 values ('aaa'); +ERROR 23000: Duplicate entry 'aaa' for key 1 +insert into t1 values ('б'); +insert into t1 values ('бб'); +ERROR 23000: Duplicate entry 'бÐ' for key 1 +insert into t1 values ('ббб'); +ERROR 23000: Duplicate entry 'бÐ' for key 1 +select c as c_all from t1 order by c; +c_all +a +b +c +d +e +f +б +select c as c_a from t1 where c='a'; +c_a +a +select c as c_a from t1 where c='б'; +c_a +б +drop table t1; diff --git a/mysql-test/r/endspace.result b/mysql-test/r/endspace.result index 4800bbf4ecb..167adea6674 100644 --- a/mysql-test/r/endspace.result +++ b/mysql-test/r/endspace.result @@ -19,7 +19,7 @@ select 'a a' > 'a', 'a \0' < 'a'; 1 1 select binary 'a a' > 'a', binary 'a \0' > 'a', binary 'a\0' > 'a'; binary 'a a' > 'a' binary 'a \0' > 'a' binary 'a\0' > 'a' -1 1 1 +1 0 0 create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)); insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); check table t1; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 354675cd4d4..0109097d3a1 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -412,6 +412,7 @@ aaa. aaa . select concat(a,'.') from t1 where binary a='aaa'; concat(a,'.') +aaa . aaa. update t1 set a='bbb' where a='aaa'; select concat(a,'.') from t1; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 0d3bec258bc..a8a02118269 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -189,7 +189,7 @@ drop table t2; # # Bug 4521: unique key prefix interacts poorly with utf8 -# Check keys with prefix compression +# MYISAM: keys with prefix compression, case insensitive collation. # create table t1 (c varchar(30) character set utf8, unique(c(10))); insert into t1 values ('1'),('2'),('3'),('x'),('y'),('z'); @@ -211,7 +211,8 @@ drop table t1; # # Bug 4521: unique key prefix interacts poorly with utf8 -# Check fixed length keys +# MYISAM: fixed length keys, case insensitive collation +# create table t1 (c char(3) character set utf8, unique (c(2))); insert into t1 values ('1'),('2'),('3'),('4'),('x'),('y'),('z'); insert into t1 values ('a'); @@ -283,3 +284,104 @@ select c as c_all from t1 order by c; select c as c_a from t1 where c='a'; select c as c_a from t1 where c='б'; drop table t1; + + +# +# Bug 4521: unique key prefix interacts poorly with utf8 +# MYISAM: keys with prefix compression, binary collation. +# +create table t1 (c varchar(30) character set utf8 collate utf8_bin, unique(c(10))); +insert into t1 values ('1'),('2'),('3'),('x'),('y'),('z'); +insert into t1 values ('aaaaaaaaaa'); +--error 1062 +insert into t1 values ('aaaaaaaaaaa'); +--error 1062 +insert into t1 values ('aaaaaaaaaaaa'); +insert into t1 values (repeat('b',20)); +select c c1 from t1 where c='1'; +select c c2 from t1 where c='2'; +select c c3 from t1 where c='3'; +select c cx from t1 where c='x'; +select c cy from t1 where c='y'; +select c cz from t1 where c='z'; +select c ca10 from t1 where c='aaaaaaaaaa'; +select c cb20 from t1 where c=repeat('b',20); +drop table t1; + +# +# Bug 4521: unique key prefix interacts poorly with utf8 +# MYISAM: fixed length keys, binary collation +# +create table t1 (c char(3) character set utf8 collate utf8_bin, unique (c(2))); +insert into t1 values ('1'),('2'),('3'),('4'),('x'),('y'),('z'); +insert into t1 values ('a'); +insert into t1 values ('aa'); +--error 1062 +insert into t1 values ('aaa'); +insert into t1 values ('b'); +insert into t1 values ('bb'); +--error 1062 +insert into t1 values ('bbb'); +insert into t1 values ('а'); +insert into t1 values ('аа'); +--error 1062 +insert into t1 values ('ааа'); +insert into t1 values ('б'); +insert into t1 values ('бб'); +--error 1062 +insert into t1 values ('ббб'); +insert into t1 values ('ꪪ'); +insert into t1 values ('ꪪꪪ'); +--error 1062 +insert into t1 values ('ꪪꪪꪪ'); +drop table t1; + +# +# Bug 4531: unique key prefix interacts poorly with utf8 +# Check HEAP+HASH, binary collation +# +# This doesn't work correctly yet. +# +#create table t1 ( +#c char(10) character set utf8 collate utf8_bin, +#unique key a using hash (c(1)) +#) engine=heap; +#show create table t1; +#insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f'); +#--error 1062 +#insert into t1 values ('aa'); +#--error 1062 +#insert into t1 values ('aaa'); +#insert into t1 values ('б'); +#--error 1062 +#insert into t1 values ('бб'); +#--error 1062 +#insert into t1 values ('ббб'); +#select c as c_all from t1 order by c; +#select c as c_a from t1 where c='a'; +#select c as c_a from t1 where c='б'; +#drop table t1; + +# +# Bug 4531: unique key prefix interacts poorly with utf8 +# Check HEAP+BTREE, binary collation +# +create table t1 ( +c char(10) character set utf8 collate utf8_bin, +unique key a using btree (c(1)) +) engine=heap; +show create table t1; +insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f'); +--error 1062 +insert into t1 values ('aa'); +--error 1062 +insert into t1 values ('aaa'); +insert into t1 values ('б'); +--error 1062 +insert into t1 values ('бб'); +--error 1062 +insert into t1 values ('ббб'); +select c as c_all from t1 order by c; +select c as c_a from t1 where c='a'; +select c as c_a from t1 where c='б'; +drop table t1; diff --git a/sql/field.h b/sql/field.h index fe06cd96f1a..83c5a71f07f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -357,7 +357,7 @@ public: uint size_of() const { return sizeof(*this); } CHARSET_INFO *charset(void) const { return field_charset; } void set_charset(CHARSET_INFO *charset) { field_charset=charset; } - bool binary() const { return field_charset->state & MY_CS_BINSORT ? 1 : 0; } + bool binary() const { return field_charset == &my_charset_bin; } uint32 max_length() { return field_length; } friend class create_field; }; diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 39ef6ca855a..7cd534d60b3 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -357,9 +357,11 @@ ulong ha_berkeley::index_flags(uint idx, uint part, bool all_parts) const case HA_KEYTYPE_VARTEXT: /* As BDB stores only one copy of equal strings, we can't use key read - on these + on these. Binary collations do support key read though. */ - flags&= ~HA_KEYREAD_ONLY; + if (!(table->key_info[idx].key_part[i].field->charset()->state + & MY_CS_BINSORT)) + flags&= ~HA_KEYREAD_ONLY; break; default: // Keep compiler happy break; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 23bdad1aae5..3c75dba42da 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -303,10 +303,10 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name()); return 1; } - if (my_binary_compare(cmp_collation.collation)) + if (cmp_collation.collation == &my_charset_bin) { /* - We are using binary collation, change to compare byte by byte, + We are using BLOB/BINARY/VARBINARY, change to compare byte by byte, without removing end space */ if (func == &Arg_comparator::compare_string) diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index cc83471f264..e759a5654f1 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -68,31 +68,10 @@ static uchar bin_char_array[] = -/* - Compare two strings. Result is sign(first_argument - second_argument) - - SYNOPSIS - my_strnncoll_binary() - cs Chararacter set - s String to compare - slen Length of 's' - t String to compare - tlen Length of 't' - - NOTE - This is used also when comparing with end space removal, as end space - is significant for binary strings - - RETURN - < 0 s < t - 0 s == t - > 0 s > t -*/ - static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)), - const uchar *s, uint slen, - const uchar *t, uint tlen, - my_bool t_is_prefix) + const uchar *s, uint slen, + const uchar *t, uint tlen, + my_bool t_is_prefix) { uint len=min(slen,tlen); int cmp= memcmp(s,t,len); @@ -100,14 +79,105 @@ static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)), } +/* + Compare two strings. Result is sign(first_argument - second_argument) + + SYNOPSIS + my_strnncollsp_binary() + cs Chararacter set + s String to compare + slen Length of 's' + t String to compare + tlen Length of 't' + + NOTE + This function is used for real binary strings, i.e. for + BLOB, BINARY(N) and VARBINARY(N). + It does not ignore trailing spaces. + + RETURN + < 0 s < t + 0 s == t + > 0 s > t +*/ + static int my_strnncollsp_binary(CHARSET_INFO * cs __attribute__((unused)), - const uchar *s, uint slen, - const uchar *t, uint tlen) + const uchar *s, uint slen, + const uchar *t, uint tlen) { return my_strnncoll_binary(cs,s,slen,t,tlen,0); } +static int my_strnncoll_8bit_bin(CHARSET_INFO * cs __attribute__((unused)), + const uchar *s, uint slen, + const uchar *t, uint tlen, + my_bool t_is_prefix) +{ + uint len=min(slen,tlen); + int cmp= memcmp(s,t,len); + return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen); +} + + +/* + Compare two strings. Result is sign(first_argument - second_argument) + + SYNOPSIS + my_strnncollsp_8bit_bin() + cs Chararacter set + s String to compare + slen Length of 's' + t String to compare + tlen Length of 't' + + NOTE + This function is used for character strings with binary collations. + It ignores trailing spaces. + + RETURN + < 0 s < t + 0 s == t + > 0 s > t +*/ + +static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)), + const uchar *a, uint a_length, + const uchar *b, uint b_length) +{ + const uchar *end; + uint length; + + end= a + (length= min(a_length, b_length)); + while (a < end) + { + if (*a++ != *b++) + return ((int) a[-1] - (int) b[-1]); + } + if (a_length != b_length) + { + int swap= 0; + /* + Check the next not space character of the longer key. If it's < ' ', + then it's smaller than the other key. + */ + if (a_length < b_length) + { + /* put shorter key in s */ + a_length= b_length; + a= b; + swap= -1; /* swap sign of result */ + } + for (end= a + a_length-length; a < end ; a++) + { + if (*a != ' ') + return ((int) *a - (int) ' ') ^ swap; + } + } + return 0; +} + + /* This function is used for all conversion functions */ static void my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)), @@ -342,6 +412,20 @@ skip: MY_COLLATION_HANDLER my_collation_8bit_bin_handler = +{ + NULL, /* init */ + my_strnncoll_8bit_bin, + my_strnncollsp_8bit_bin, + my_strnxfrm_bin, + my_like_range_simple, + my_wildcmp_bin, + my_strcasecmp_bin, + my_instr_bin, + my_hash_sort_bin +}; + + +static MY_COLLATION_HANDLER my_collation_binary_handler = { NULL, /* init */ my_strnncoll_binary, @@ -407,5 +491,5 @@ CHARSET_INFO my_charset_bin = 0, /* min_sort_char */ 255, /* max_sort_char */ &my_charset_handler, - &my_collation_8bit_bin_handler + &my_collation_binary_handler }; diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index 7b0dadcfa19..ecafa6356d5 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -360,11 +360,62 @@ static int my_strnncoll_mb_bin(CHARSET_INFO * cs __attribute__((unused)), return cmp ? cmp : (int) ((t_is_prefix ? len : slen) - tlen); } + +/* + Compare two strings. + + SYNOPSIS + my_strnncollsp_mb_bin() + cs Chararacter set + s String to compare + slen Length of 's' + t String to compare + tlen Length of 't' + + NOTE + This function is used for character strings with binary collations. + It ignores trailing spaces. + + RETURN + A negative number if s < t + A positive number if s > t + 0 if strings are equal +*/ + static int my_strnncollsp_mb_bin(CHARSET_INFO * cs __attribute__((unused)), - const uchar *s, uint slen, - const uchar *t, uint tlen) + const uchar *a, uint a_length, + const uchar *b, uint b_length) { - return my_strnncoll_mb_bin(cs,s,slen,t,tlen,0); + const uchar *end; + uint length; + + end= a + (length= min(a_length, b_length)); + while (a < end) + { + if (*a++ != *b++) + return ((int) a[-1] - (int) b[-1]); + } + if (a_length != b_length) + { + int swap= 0; + /* + Check the next not space character of the longer key. If it's < ' ', + then it's smaller than the other key. + */ + if (a_length < b_length) + { + /* put shorter key in s */ + a_length= b_length; + a= b; + swap= -1; /* swap sign of result */ + } + for (end= a + a_length-length; a < end ; a++) + { + if (*a != ' ') + return ((int) *a - (int) ' ') ^ swap; + } + } + return 0; } From a7510c70fc24acc5df48cdc9535bc63e260a1b28 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Thu, 19 Aug 2004 15:21:35 +0500 Subject: [PATCH 3/7] Fix trailing spaces behaviour for binary collation. --- mysql-test/r/ctype_utf8.result | 15 +++++++++++++++ mysql-test/t/ctype_utf8.test | 9 +++++++++ 2 files changed, 24 insertions(+) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index cfad82fa053..d00092a806f 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -79,6 +79,21 @@ SELECT 'a\t' < 'a'; SELECT 'a\t' < 'a '; 'a\t' < 'a ' 1 +SELECT 'a' = 'a ' collate utf8_bin; +'a' = 'a ' collate utf8_bin +1 +SELECT 'a\0' < 'a' collate utf8_bin; +'a\0' < 'a' collate utf8_bin +1 +SELECT 'a\0' < 'a ' collate utf8_bin; +'a\0' < 'a ' collate utf8_bin +1 +SELECT 'a\t' < 'a' collate utf8_bin; +'a\t' < 'a' collate utf8_bin +1 +SELECT 'a\t' < 'a ' collate utf8_bin; +'a\t' < 'a ' collate utf8_bin +1 CREATE TABLE t1 (a char(10) character set utf8 not null); INSERT INTO t1 VALUES ('a'),('a\0'),('a\t'),('a '); SELECT hex(a),STRCMP(a,'a'), STRCMP(a,'a ') FROM t1; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index a8a02118269..4c2898adae7 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -46,6 +46,15 @@ SELECT 'a\0' < 'a '; SELECT 'a\t' < 'a'; SELECT 'a\t' < 'a '; +# +# The same for binary collation +# +SELECT 'a' = 'a ' collate utf8_bin; +SELECT 'a\0' < 'a' collate utf8_bin; +SELECT 'a\0' < 'a ' collate utf8_bin; +SELECT 'a\t' < 'a' collate utf8_bin; +SELECT 'a\t' < 'a ' collate utf8_bin; + CREATE TABLE t1 (a char(10) character set utf8 not null); INSERT INTO t1 VALUES ('a'),('a\0'),('a\t'),('a '); SELECT hex(a),STRCMP(a,'a'), STRCMP(a,'a ') FROM t1; From d81136e3e159f5fe2dd0eb3021b012aa4eb382d0 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Thu, 19 Aug 2004 16:07:18 +0500 Subject: [PATCH 4/7] Bug 4531: unique key prefix interacts poorly with utf8 Check HEAP+HASH, binary collation --- mysql-test/r/ctype_utf8.result | 36 ++++++++++++++++++++++++++++++ mysql-test/t/ctype_utf8.test | 40 ++++++++++++++++------------------ sql/ha_heap.cc | 2 +- 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index d00092a806f..6c6e5114cf8 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -470,6 +470,42 @@ ERROR 23000: Duplicate entry 'ꪪꪪ' for key 1 drop table t1; create table t1 ( c char(10) character set utf8 collate utf8_bin, +unique key a using hash (c(1)) +) engine=heap; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` char(10) character set utf8 collate utf8_bin default NULL, + UNIQUE KEY `a` (`c`(1)) +) ENGINE=HEAP DEFAULT CHARSET=latin1 +insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f'); +insert into t1 values ('aa'); +ERROR 23000: Duplicate entry 'aa' for key 1 +insert into t1 values ('aaa'); +ERROR 23000: Duplicate entry 'aaa' for key 1 +insert into t1 values ('б'); +insert into t1 values ('бб'); +ERROR 23000: Duplicate entry 'бÐ' for key 1 +insert into t1 values ('ббб'); +ERROR 23000: Duplicate entry 'бÐ' for key 1 +select c as c_all from t1 order by c; +c_all +a +b +c +d +e +f +б +select c as c_a from t1 where c='a'; +c_a +a +select c as c_a from t1 where c='б'; +c_a +б +drop table t1; +create table t1 ( +c char(10) character set utf8 collate utf8_bin, unique key a using btree (c(1)) ) engine=heap; show create table t1; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 4c2898adae7..21880732e47 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -349,27 +349,25 @@ drop table t1; # Bug 4531: unique key prefix interacts poorly with utf8 # Check HEAP+HASH, binary collation # -# This doesn't work correctly yet. -# -#create table t1 ( -#c char(10) character set utf8 collate utf8_bin, -#unique key a using hash (c(1)) -#) engine=heap; -#show create table t1; -#insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f'); -#--error 1062 -#insert into t1 values ('aa'); -#--error 1062 -#insert into t1 values ('aaa'); -#insert into t1 values ('б'); -#--error 1062 -#insert into t1 values ('бб'); -#--error 1062 -#insert into t1 values ('ббб'); -#select c as c_all from t1 order by c; -#select c as c_a from t1 where c='a'; -#select c as c_a from t1 where c='б'; -#drop table t1; +create table t1 ( +c char(10) character set utf8 collate utf8_bin, +unique key a using hash (c(1)) +) engine=heap; +show create table t1; +insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f'); +--error 1062 +insert into t1 values ('aa'); +--error 1062 +insert into t1 values ('aaa'); +insert into t1 values ('б'); +--error 1062 +insert into t1 values ('бб'); +--error 1062 +insert into t1 values ('ббб'); +select c as c_all from t1 order by c; +select c as c_a from t1 where c='a'; +select c as c_a from t1 where c='б'; +drop table t1; # # Bug 4531: unique key prefix interacts poorly with utf8 diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index a7f6cc45831..d7327362286 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -430,7 +430,7 @@ int ha_heap::create(const char *name, TABLE *table_arg, { if (!f_is_packed(flag) && f_packtype(flag) == (int) FIELD_TYPE_DECIMAL && - !(flag & FIELDFLAG_BINARY)) + !(field->charset() == &my_charset_bin)) seg->type= (int) HA_KEYTYPE_TEXT; else seg->type= (int) HA_KEYTYPE_BINARY; From f1e8bc8535d346f99c65c2cc87640b171bef104b Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 19 Aug 2004 15:10:59 +0200 Subject: [PATCH 5/7] mysql_com.h: Better names for defines, as these are visible in API --- VC++Files/winmysqladmin/mysql_com.h | 18 +++++++++--------- include/mysql_com.h | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/VC++Files/winmysqladmin/mysql_com.h b/VC++Files/winmysqladmin/mysql_com.h index a732953a8d7..cab10f55771 100644 --- a/VC++Files/winmysqladmin/mysql_com.h +++ b/VC++Files/winmysqladmin/mysql_com.h @@ -159,10 +159,10 @@ enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY, /* Shutdown/kill enums and constants */ /* Bits for THD::killable. */ -#define KILLABLE_CONNECT (unsigned char)(1 << 0) -#define KILLABLE_TRANS (unsigned char)(1 << 1) -#define KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) -#define KILLABLE_UPDATE (unsigned char)(1 << 3) +#define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) +#define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) +#define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) +#define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) enum enum_shutdown_level { /* @@ -172,15 +172,15 @@ enum enum_shutdown_level { */ SHUTDOWN_DEFAULT= 0, /* wait for existing connections to finish */ - SHUTDOWN_WAIT_CONNECTIONS= KILLABLE_CONNECT, + SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, /* wait for existing trans to finish */ - SHUTDOWN_WAIT_TRANSACTIONS= KILLABLE_TRANS, + SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, /* wait for existing updates to finish (=> no partial MyISAM update) */ - SHUTDOWN_WAIT_UPDATES= KILLABLE_UPDATE, + SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, /* flush InnoDB buffers and other storage engines' buffers*/ - SHUTDOWN_WAIT_ALL_BUFFERS= (KILLABLE_UPDATE << 1), + SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), /* don't flush InnoDB buffers, flush other storage engines' buffers*/ - SHUTDOWN_WAIT_CRITICAL_BUFFERS= (KILLABLE_UPDATE << 1) + 1, + SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, /* Now the 2 levels of the KILL command */ #if MYSQL_VERSION_ID >= 50000 KILL_QUERY= 254, diff --git a/include/mysql_com.h b/include/mysql_com.h index fa25db5f11a..f006c38aad2 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -227,10 +227,10 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, /* Shutdown/kill enums and constants */ /* Bits for THD::killable. */ -#define KILLABLE_CONNECT (unsigned char)(1 << 0) -#define KILLABLE_TRANS (unsigned char)(1 << 1) -#define KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) -#define KILLABLE_UPDATE (unsigned char)(1 << 3) +#define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) +#define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) +#define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) +#define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) enum enum_shutdown_level { /* @@ -240,15 +240,15 @@ enum enum_shutdown_level { */ SHUTDOWN_DEFAULT= 0, /* wait for existing connections to finish */ - SHUTDOWN_WAIT_CONNECTIONS= KILLABLE_CONNECT, + SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, /* wait for existing trans to finish */ - SHUTDOWN_WAIT_TRANSACTIONS= KILLABLE_TRANS, + SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, /* wait for existing updates to finish (=> no partial MyISAM update) */ - SHUTDOWN_WAIT_UPDATES= KILLABLE_UPDATE, + SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, /* flush InnoDB buffers and other storage engines' buffers*/ - SHUTDOWN_WAIT_ALL_BUFFERS= (KILLABLE_UPDATE << 1), + SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), /* don't flush InnoDB buffers, flush other storage engines' buffers*/ - SHUTDOWN_WAIT_CRITICAL_BUFFERS= (KILLABLE_UPDATE << 1) + 1, + SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, /* Now the 2 levels of the KILL command */ #if MYSQL_VERSION_ID >= 50000 KILL_QUERY= 254, From 22a65bcf266fdf2a206b6cc234f16d0ced7fec5d Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 19 Aug 2004 15:15:52 +0200 Subject: [PATCH 6/7] mysql_com.h: still better names for enum; removing unneeded symbol --- VC++Files/winmysqladmin/mysql_com.h | 18 +++++++----------- include/mysql_com.h | 18 +++++++----------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/VC++Files/winmysqladmin/mysql_com.h b/VC++Files/winmysqladmin/mysql_com.h index cab10f55771..2a7eb57d745 100644 --- a/VC++Files/winmysqladmin/mysql_com.h +++ b/VC++Files/winmysqladmin/mysql_com.h @@ -164,23 +164,23 @@ enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY, #define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) #define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) -enum enum_shutdown_level { +enum mysql_enum_shutdown_level { /* We want levels to be in growing order of hardness (because we use number comparisons). Note that DEFAULT does not respect the growing property, but it's ok. */ - SHUTDOWN_DEFAULT= 0, + DEFAULT= 0, /* wait for existing connections to finish */ - SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, + WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, /* wait for existing trans to finish */ - SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, + WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, /* wait for existing updates to finish (=> no partial MyISAM update) */ - SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, + WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, /* flush InnoDB buffers and other storage engines' buffers*/ - SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), + WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), /* don't flush InnoDB buffers, flush other storage engines' buffers*/ - SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, + WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, /* Now the 2 levels of the KILL command */ #if MYSQL_VERSION_ID >= 50000 KILL_QUERY= 254, @@ -188,10 +188,6 @@ enum enum_shutdown_level { KILL_CONNECTION= 255 }; -/* Same value and type (0, enum_shutdown_level) but not same meaning */ -#define NOT_KILLED SHUTDOWN_DEFAULT - - extern unsigned long max_allowed_packet; extern unsigned long net_buffer_length; diff --git a/include/mysql_com.h b/include/mysql_com.h index f006c38aad2..36d41b2964a 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -232,23 +232,23 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, #define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) #define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) -enum enum_shutdown_level { +enum mysql_enum_shutdown_level { /* We want levels to be in growing order of hardness (because we use number comparisons). Note that DEFAULT does not respect the growing property, but it's ok. */ - SHUTDOWN_DEFAULT= 0, + DEFAULT= 0, /* wait for existing connections to finish */ - SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, + WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, /* wait for existing trans to finish */ - SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, + WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, /* wait for existing updates to finish (=> no partial MyISAM update) */ - SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, + WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, /* flush InnoDB buffers and other storage engines' buffers*/ - SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), + WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), /* don't flush InnoDB buffers, flush other storage engines' buffers*/ - SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, + WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, /* Now the 2 levels of the KILL command */ #if MYSQL_VERSION_ID >= 50000 KILL_QUERY= 254, @@ -256,10 +256,6 @@ enum enum_shutdown_level { KILL_CONNECTION= 255 }; -/* Same value and type (0, enum_shutdown_level) but not same meaning */ -#define NOT_KILLED SHUTDOWN_DEFAULT - - /* options for mysql_set_option */ enum enum_mysql_set_option { From 2d7f4c30a738b089da6676a12f50b7c88fa7c2b3 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Thu, 19 Aug 2004 20:48:00 +0200 Subject: [PATCH 7/7] Fixed symbol name problems that made build fail. --- include/mysql.h | 2 +- include/mysql_com.h | 12 ++++++------ libmysql/libmysql.c | 2 +- sql/sql_parse.cc | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index 0f3fdc90548..52187c3ff28 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -454,7 +454,7 @@ int STDCALL mysql_add_slave(MYSQL* mysql, const char* host, const char* passwd); int STDCALL mysql_shutdown(MYSQL *mysql, - enum enum_shutdown_level + enum mysql_enum_shutdown_level shutdown_level); int STDCALL mysql_dump_debug_info(MYSQL *mysql); int STDCALL mysql_refresh(MYSQL *mysql, diff --git a/include/mysql_com.h b/include/mysql_com.h index 36d41b2964a..3b65d6f3fbc 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -238,17 +238,17 @@ enum mysql_enum_shutdown_level { comparisons). Note that DEFAULT does not respect the growing property, but it's ok. */ - DEFAULT= 0, + SHUTDOWN_DEFAULT = 0, /* wait for existing connections to finish */ - WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, + SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, /* wait for existing trans to finish */ - WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, + SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, /* wait for existing updates to finish (=> no partial MyISAM update) */ - WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, + SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, /* flush InnoDB buffers and other storage engines' buffers*/ - WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), + SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), /* don't flush InnoDB buffers, flush other storage engines' buffers*/ - WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, + SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, /* Now the 2 levels of the KILL command */ #if MYSQL_VERSION_ID >= 50000 KILL_QUERY= 254, diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index fbadfc2c76e..c95c5e3a982 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1291,7 +1291,7 @@ mysql_drop_db(MYSQL *mysql, const char *db) int STDCALL -mysql_shutdown(MYSQL *mysql, enum enum_shutdown_level shutdown_level) +mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level) { uchar level[1]; DBUG_ENTER("mysql_shutdown"); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 57e4022719e..5aa4a8de156 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1643,8 +1643,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in packet[0]. */ - enum enum_shutdown_level level= - (enum enum_shutdown_level) (uchar) packet[0]; + enum mysql_enum_shutdown_level level= + (enum mysql_enum_shutdown_level) (uchar) packet[0]; DBUG_PRINT("quit",("Got shutdown command for level %u", level)); if (level == SHUTDOWN_DEFAULT) level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable