summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--myisam/mi_key.c13
-rw-r--r--mysql-test/r/ctype_utf8.result70
-rw-r--r--mysql-test/t/ctype_utf8.test64
-rw-r--r--sql/field.cc53
-rw-r--r--sql/field.h2
5 files changed, 189 insertions, 13 deletions
diff --git a/myisam/mi_key.c b/myisam/mi_key.c
index 8f5f0e829ef..043dd7c6884 100644
--- a/myisam/mi_key.c
+++ b/myisam/mi_key.c
@@ -25,9 +25,12 @@
#define CHECK_KEYS
-#define FIX_LENGTH if (length > char_length) \
- char_length= my_charpos(cs, pos, pos+length, char_length); \
- set_if_smaller(char_length,length); \
+#define FIX_LENGTH \
+ do { \
+ if (length > char_length) \
+ char_length= my_charpos(cs, pos, pos+length, char_length); \
+ set_if_smaller(char_length,length); \
+ } while(0)
static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record);
@@ -157,7 +160,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
FIX_LENGTH;
memcpy((byte*) key, pos, char_length);
if (length > char_length)
- bfill(key+char_length, length-char_length, ' ');
+ cs->cset->fill(cs, key+char_length, length-char_length, ' ');
key+= length;
}
_mi_dpointer(info,key,filepos);
@@ -267,7 +270,7 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
FIX_LENGTH;
memcpy((byte*) key, pos, char_length);
if (length > char_length)
- bfill(key+char_length, length-char_length, ' ');
+ cs->cset->fill(cs,key+char_length, length-char_length, ' ');
key+= length;
k_length-=length;
}
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index ef5ec012078..38fc8e17d14 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -412,6 +412,36 @@ select c as c_a from t1 where c='б';
c_a
б
drop table t1;
+create table t1 (
+c char(10) character set utf8,
+unique key a (c(1))
+) engine=bdb;
+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 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');
@@ -541,6 +571,36 @@ c_a
б
drop table t1;
create table t1 (
+c char(10) character set utf8 collate utf8_bin,
+unique key a (c(1))
+) engine=bdb;
+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 (
str varchar(255) character set utf8 not null,
key str (str(2))
) engine=myisam;
@@ -570,3 +630,13 @@ select * from t1 where str='str';
str
str
drop table t1;
+create table t1 (
+str varchar(255) character set utf8 not null,
+key str (str(2))
+) engine=bdb;
+INSERT INTO t1 VALUES ('str');
+INSERT INTO t1 VALUES ('str2');
+select * from t1 where str='str';
+str
+str
+drop table t1;
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index 83055d05830..4624f2ec78c 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -294,6 +294,30 @@ 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 BDB, case insensitive collation
+#
+--disable_warnings
+create table t1 (
+c char(10) character set utf8,
+unique key a (c(1))
+) engine=bdb;
+--enable_warnings
+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 4521: unique key prefix interacts poorly with utf8
@@ -393,6 +417,31 @@ 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 BDB, binary collation
+#
+--disable_warnings
+create table t1 (
+c char(10) character set utf8 collate utf8_bin,
+unique key a (c(1))
+) engine=bdb;
+--enable_warnings
+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#4594: column index make = failed for gbk, but like works
# Check MYISAM
@@ -429,3 +478,18 @@ INSERT INTO t1 VALUES ('str');
INSERT INTO t1 VALUES ('str2');
select * from t1 where str='str';
drop table t1;
+
+# the same for BDB
+#
+
+--disable_warnings
+create table t1 (
+ str varchar(255) character set utf8 not null,
+ key str (str(2))
+) engine=bdb;
+--enable_warnings
+INSERT INTO t1 VALUES ('str');
+INSERT INTO t1 VALUES ('str2');
+select * from t1 where str='str';
+drop table t1;
+
diff --git a/sql/field.cc b/sql/field.cc
index 96f4fa8fd86..f1d1227ace8 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -4382,7 +4382,7 @@ void Field_string::sql_type(String &res) const
(field_length > 3 &&
(table->db_options_in_use &
HA_OPTION_PACK_RECORD) ?
- (has_charset() ? "varchar" : "varbinary") :
+ (has_charset() ? "varchar" : "varbinary") :
(has_charset() ? "char" : "binary")),
(int) field_length / charset()->mbmaxlen);
res.length(length);
@@ -4401,6 +4401,24 @@ char *Field_string::pack(char *to, const char *from, uint max_length)
}
+char *Field_string::pack_key(char *to, const char *from, uint max_length)
+{
+ const char *end=from+min(field_length,max_length);
+ int length;
+ while (end > from && end[-1] == ' ')
+ end--;
+ length= end-from;
+ uint char_length= (field_charset->mbmaxlen > 1) ?
+ max_length/field_charset->mbmaxlen : max_length;
+ if (length > char_length)
+ char_length= my_charpos(field_charset, from, end, char_length);
+ set_if_smaller(length, char_length);
+ *to= (uchar)length;
+ memcpy(to+1, from, length);
+ return to+1+length;
+}
+
+
const char *Field_string::unpack(char *to, const char *from)
{
uint length= (uint) (uchar) *from++;
@@ -4564,6 +4582,24 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
}
+char *Field_varstring::pack_key(char *to, const char *from, uint max_length)
+{
+ uint length=uint2korr(from);
+ uint char_length= (field_charset->mbmaxlen > 1) ?
+ max_length/field_charset->mbmaxlen : max_length;
+ from+=HA_KEY_BLOB_LENGTH;
+ if (length > char_length)
+ char_length= my_charpos(field_charset, from, from+length, char_length);
+ set_if_smaller(length, char_length);
+ *to++= (char) (length & 255);
+ if (max_length > 255)
+ *to++= (char) (length >> 8);
+ if (length)
+ memcpy(to, from, length);
+ return to+length;
+}
+
+
const char *Field_varstring::unpack(char *to, const char *from)
{
uint length;
@@ -5139,16 +5175,17 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
char *save=ptr;
ptr=(char*) from;
uint32 length=get_length(); // Length of from string
- if (length > max_length)
- length=max_length;
+ uint char_length= (field_charset->mbmaxlen > 1) ?
+ max_length/field_charset->mbmaxlen : max_length;
+ if (length)
+ get_ptr((char**) &from);
+ if (length > char_length)
+ char_length= my_charpos(field_charset, from, from+length, char_length);
+ set_if_smaller(length, char_length);
*to++= (uchar) length;
if (max_length > 255) // 2 byte length
*to++= (uchar) (length >> 8);
- if (length)
- {
- get_ptr((char**) &from);
- memcpy(to, from, length);
- }
+ memcpy(to, from, length);
ptr=save; // Restore org row pointer
return to+length;
}
diff --git a/sql/field.h b/sql/field.h
index 843961e64c3..eaf90ddc0ff 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -917,6 +917,7 @@ public:
void sort_string(char *buff,uint length);
void sql_type(String &str) const;
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+ char *pack_key(char *to, const char *from, uint max_length);
const char *unpack(char* to, const char *from);
int pack_cmp(const char *a,const char *b,uint key_length);
int pack_cmp(const char *b,uint key_length);
@@ -965,6 +966,7 @@ public:
void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
void sql_type(String &str) const;
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+ char *pack_key(char *to, const char *from, uint max_length);
const char *unpack(char* to, const char *from);
int pack_cmp(const char *a, const char *b, uint key_length);
int pack_cmp(const char *b, uint key_length);