diff options
author | unknown <serg@serg.mylan> | 2004-08-13 18:29:25 +0200 |
---|---|---|
committer | unknown <serg@serg.mylan> | 2004-08-13 18:29:25 +0200 |
commit | 5bdb9de84d606afa9cbe41d28813b24125b2e6ab (patch) | |
tree | 9f1d56d26b0dc04c637b834bdb89d3d7be9af018 | |
parent | 2f663d946e6854fd1204887c3f95dfe772fe3e03 (diff) | |
download | mariadb-git-5bdb9de84d606afa9cbe41d28813b24125b2e6ab.tar.gz |
apply UNIQUE constrain correctly for multi-byte charsets
only MyISAM is fixed
include/m_ctype.h:
my_charpos() macro
myisam/mi_key.c:
apply UNIQUE constrain correctly for multi-byte charsets
mysql-test/r/binary.result:
new test
mysql-test/r/key.result:
apply UNIQUE constrain correctly for multi-byte charsets
mysql-test/t/binary.test:
new test
mysql-test/t/func_gconcat.test:
make test to pass w/o InnoDB
mysql-test/t/key.test:
apply UNIQUE constrain correctly for multi-byte charsets
-rw-r--r-- | include/m_ctype.h | 4 | ||||
-rw-r--r-- | myisam/mi_key.c | 113 | ||||
-rw-r--r-- | mysql-test/r/binary.result | 4 | ||||
-rw-r--r-- | mysql-test/r/key.result | 38 | ||||
-rw-r--r-- | mysql-test/t/binary.test | 1 | ||||
-rw-r--r-- | mysql-test/t/func_gconcat.test | 2 | ||||
-rw-r--r-- | mysql-test/t/key.test | 26 |
7 files changed, 122 insertions, 66 deletions
diff --git a/include/m_ctype.h b/include/m_ctype.h index 785fa431385..1b6e7bf6739 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -391,8 +391,10 @@ extern my_bool my_parse_charset_xml(const char *bug, uint len, #define my_strnncoll(s, a, b, c, d) ((s)->coll->strnncoll((s), (a), (b), (c), (d), 0)) #define my_like_range(s, a, b, c, d, e, f, g, h, i, j) \ ((s)->coll->like_range((s), (a), (b), (c), (d), (e), (f), (g), (h), (i), (j))) -#define my_wildcmp(cs,s,se,w,we,e,o,m) ((cs)->coll->wildcmp((cs),(s),(se),(w),(we),(e),(o),(m))) +#define my_wildcmp(cs,s,se,w,we,e,o,m) ((cs)->coll->wildcmp((cs),(s),(se),(w),(we),(e),(o),(m))) #define my_strcasecmp(s, a, b) ((s)->coll->strcasecmp((s), (a), (b))) +#define my_charpos(cs, b, e, num) (cs)->cset->charpos((cs), (const char*) (b), (const char *)(e), (num)) + #define use_mb(s) ((s)->cset->ismbchar != NULL) #define my_ismbchar(s, a, b) ((s)->cset->ismbchar((s), (a), (b))) diff --git a/myisam/mi_key.c b/myisam/mi_key.c index a9b5a8b279f..a872787fecd 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -25,6 +25,10 @@ #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); \ + static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record); /* @@ -32,20 +36,18 @@ static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record); ** Ret: Length of key */ -#define my_charpos(cs, b, e, num)\ - (cs)->cset->charpos((cs), (const char*) (b), (const char *)(e), (num)) - uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, const byte *record, my_off_t filepos) { byte *pos,*end; uchar *start; reg1 HA_KEYSEG *keyseg; + my_bool is_unique=info->s->keyinfo[keynr].flag & HA_NOSAME; DBUG_ENTER("_mi_make_key"); if(info->s->keyinfo[keynr].flag & HA_SPATIAL) { - /* + /* TODO: nulls processing */ #ifdef HAVE_SPATIAL @@ -61,7 +63,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type; uint length=keyseg->length; uint char_length; - CHARSET_INFO *cs; + CHARSET_INFO *cs=keyseg->charset; if (keyseg->null_bit) { @@ -73,15 +75,8 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, *key++=1; /* Not NULL */ } - char_length= (cs= keyseg->charset) && (cs->mbmaxlen > 1) ? - length / cs->mbmaxlen : 0; - - if (info->s->keyinfo[keynr].flag & HA_FULLTEXT) - { - /* Ask Serg to make a better fix */ - char_length= 0; - } - + char_length= (is_unique && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length; + pos= (byte*) record+keyseg->start; if (keyseg->flag & HA_SPACE_PACK) { @@ -97,14 +92,10 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, pos++; } length=(uint) (end-pos); - if (char_length && length > char_length) - { - char_length= my_charpos(cs, pos, pos+length, char_length); - set_if_smaller(length, char_length); - } - store_key_length_inc(key,length); - memcpy((byte*) key,(byte*) pos,(size_t) length); - key+=length; + FIX_LENGTH; + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key+=char_length; continue; } if (keyseg->flag & HA_VAR_LENGTH) @@ -112,9 +103,10 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, uint tmp_length=uint2korr(pos); pos+=2; /* Skip VARCHAR length */ set_if_smaller(length,tmp_length); - store_key_length_inc(key,length); - memcpy((byte*) key, pos, length); - key+= length; + FIX_LENGTH; + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key+= char_length; continue; } else if (keyseg->flag & HA_BLOB_PART) @@ -122,16 +114,10 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, uint tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos); memcpy_fixed((byte*) &pos,pos+keyseg->bit_start,sizeof(char*)); set_if_smaller(length,tmp_length); -#if NOT_YET_BLOB_PART - if (char_length && length > char_length) - { - char_length= my_charpos(cs, pos, pos+length, char_length); - set_if_smaller(length, char_length); - } -#endif - store_key_length_inc(key,length); - memcpy((byte*) key, pos, length); - key+= length; + FIX_LENGTH; + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key+= char_length; continue; } else if (keyseg->flag & HA_SWAP_KEY) @@ -144,7 +130,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, if (isnan(nr)) { /* Replace NAN with zero */ - bzero(key,length); + bzero(key,length); key+=length; continue; } @@ -155,7 +141,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, float8get(nr,pos); if (isnan(nr)) { - bzero(key,length); + bzero(key,length); key+=length; continue; } @@ -168,14 +154,10 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, } continue; } -#ifdef NOT_YET_FIXED_LENGTH_KEY - if (char_length && length > char_length) - { - char_length= my_charpos(cs, pos, pos+length, char_length); - set_if_smaller(length, char_length); - } -#endif - memcpy((byte*) key, pos, length); + FIX_LENGTH; + memcpy((byte*) key, pos, char_length); + if (length > char_length) + bfill(key+char_length, length-char_length, ' '); key+= length; } _mi_dpointer(info,key,filepos); @@ -203,25 +185,27 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, RETURN length of packed key - last_use_keyseg Store pointer to the keyseg after the last used one + last_use_keyseg Store pointer to the keyseg after the last used one */ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, uint k_length, HA_KEYSEG **last_used_keyseg) { - uint length; - uchar *pos,*end,*start_key=key; - reg1 HA_KEYSEG *keyseg; - enum ha_base_keytype type; + uchar *start_key=key; + HA_KEYSEG *keyseg; + my_bool is_unique=info->s->keyinfo[keynr].flag & HA_NOSAME; DBUG_ENTER("_mi_pack_key"); - start_key=key; for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type && (int) k_length > 0; old+=keyseg->length, keyseg++) { - length=min((uint) keyseg->length,(uint) k_length); - type=(enum ha_base_keytype) keyseg->type; + enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type; + uint length=min((uint) keyseg->length,(uint) k_length); + uint char_length; + uchar *pos; + CHARSET_INFO *cs=keyseg->charset; + if (keyseg->null_bit) { k_length--; @@ -231,10 +215,11 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, continue; /* Found NULL */ } } + char_length= (is_unique && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length; pos=old; if (keyseg->flag & HA_SPACE_PACK) { - end=pos+length; + uchar *end=pos+length; if (type != HA_KEYTYPE_NUM) { while (end > pos && end[-1] == ' ') @@ -247,9 +232,10 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, } k_length-=length; length=(uint) (end-pos); - store_key_length_inc(key,length); - memcpy((byte*) key,pos,(size_t) length); - key+= length; + FIX_LENGTH; + store_key_length_inc(key,char_length); + memcpy((byte*) key,pos,(size_t) char_length); + key+= char_length; continue; } else if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART)) @@ -257,11 +243,13 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, /* Length of key-part used with mi_rkey() always 2 */ uint tmp_length=uint2korr(pos); k_length-= 2+length; + pos+=2; set_if_smaller(length,tmp_length); /* Safety */ - store_key_length_inc(key,length); + FIX_LENGTH; + store_key_length_inc(key,char_length); old+=2; /* Skip length */ - memcpy((byte*) key, pos+2,(size_t) length); - key+= length; + memcpy((byte*) key, pos,(size_t) char_length); + key+= char_length; continue; } else if (keyseg->flag & HA_SWAP_KEY) @@ -274,7 +262,10 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, } continue; } - memcpy((byte*) key,pos,(size_t) length); + FIX_LENGTH; + memcpy((byte*) key, pos, char_length); + if (length > char_length) + bfill(key+char_length, length-char_length, ' '); key+= length; k_length-=length; } diff --git a/mysql-test/r/binary.result b/mysql-test/r/binary.result index f6ad190b05a..000c0c16d77 100644 --- a/mysql-test/r/binary.result +++ b/mysql-test/r/binary.result @@ -62,6 +62,10 @@ concat("-",a,"-",b,"-") select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; concat("-",a,"-",b,"-") alter table t1 modify b tinytext not null, drop key b, add key (b(100)); +select concat("-",a,"-",b,"-") from t1; +concat("-",a,"-",b,"-") +-hello-hello- +-hello2-hello2- select concat("-",a,"-",b,"-") from t1 where b="hello "; concat("-",a,"-",b,"-") -hello-hello- diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 9b4621edc42..967ff47e1ea 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -76,13 +76,12 @@ CCident varchar(50) DEFAULT '' NOT NULL, PRIMARY KEY (name,author,category) ); INSERT INTO t1 VALUES -('patnom','patauteur',0,'p.favre@cryo-networks.fr',NULL,NULL,'#p2sndnq6ae5g1u6t','essai\nsalut','scol://195.242.78.119:patauteur.patnom',NULL,NULL,NULL,950036174,-882087474,NULL,3,0,3,'1','Pub/patnom/futur_divers.scs',NULL,'pat','CC1'); +('patnom','patauteur',0,'p.favre@cryo-networks.fr',NULL,NULL,'#p2sndnq6ae5g1u6t','essai salut','scol://195.242.78.119:patauteur.patnom',NULL,NULL,NULL,950036174,-882087474,NULL,3,0,3,'1','Pub/patnom/futur_divers.scs',NULL,'pat','CC1'); INSERT INTO t1 VALUES ('LeNomDeMonSite','Marc',0,'m.barilley@cryo-networks.fr',NULL,NULL,NULL,NULL,'scol://195.242.78.119:Marc.LeNomDeMonSite',NULL,NULL,NULL,950560434,-881563214,NULL,3,0,3,'1','Pub/LeNomDeMonSite/domus_hibere.scs',NULL,'Marq','CC1'); select * from t1 where name='patnom' and author='patauteur' and category=0; name author category email password proxy bitmap msg urlscol urlhttp timeout nbcnx creation livinguntil lang type subcat subtype reg scs capacity userISP CCident -patnom patauteur 0 p.favre@cryo-networks.fr NULL NULL #p2sndnq6ae5g1u6t essai -salut scol://195.242.78.119:patauteur.patnom NULL NULL NULL 950036174 -882087474 NULL 3 0 3 1 Pub/patnom/futur_divers.scs NULL pat CC1 +patnom patauteur 0 p.favre@cryo-networks.fr NULL NULL #p2sndnq6ae5g1u6t essai salut scol://195.242.78.119:patauteur.patnom NULL NULL NULL 950036174 -882087474 NULL 3 0 3 1 Pub/patnom/futur_divers.scs NULL pat CC1 drop table t1; create table t1 ( @@ -235,3 +234,36 @@ SELECT numeropost FROM t1 WHERE numreponse='1'; numeropost 1 drop table t1; +create table t1 (c varchar(30) character set utf8, t text character set utf8, unique (c(2)), unique (t(3))) engine=myisam; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` varchar(30) character set utf8 default NULL, + `t` text character set utf8, + UNIQUE KEY `c` (`c`(2)), + UNIQUE KEY `t` (`t`(3)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert t1 values ('cccc', 'tttt'), +(0xD0B1212223D0B1D0B1D0B1D0B1D0B1, 0xD0B1D0B1212223D0B1D0B1D0B1D0B1), +(0xD0B1222123D0B1D0B1D0B1D0B1D0B1, 0xD0B1D0B1222123D0B1D0B1D0B1D0B1); +insert t1 (c) values ('cc22'); +ERROR 23000: Duplicate entry 'cc22' for key 1 +insert t1 (t) values ('ttt22'); +ERROR 23000: Duplicate entry 'ttt22' for key 2 +insert t1 (c) values (0xD0B1212322D0B1D0B1D0B1D0B1D0B1); +ERROR 23000: Duplicate entry 'б!#"Ð' for key 1 +insert t1 (t) values (0xD0B1D0B1212322D0B1D0B1D0B1D0B1); +ERROR 23000: Duplicate entry 'бб!#"б' for key 2 +select c from t1 where c='cccc'; +c +cccc +select t from t1 where t='tttt'; +t +tttt +select c from t1 where c=0xD0B1212223D0B1D0B1D0B1D0B1D0B1; +c +?!"#????? +select t from t1 where t=0xD0B1D0B1212223D0B1D0B1D0B1D0B1; +t +??!"#???? +drop table t1; diff --git a/mysql-test/t/binary.test b/mysql-test/t/binary.test index 20a047e0b26..9f63c2ed445 100644 --- a/mysql-test/t/binary.test +++ b/mysql-test/t/binary.test @@ -38,6 +38,7 @@ select concat("-",a,"-",b,"-") from t1 where b="hello "; select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; # blob test alter table t1 modify b tinytext not null, drop key b, add key (b(100)); +select concat("-",a,"-",b,"-") from t1; select concat("-",a,"-",b,"-") from t1 where b="hello "; select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; drop table t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index d27e5d7d77f..ad19c8414ec 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -215,10 +215,12 @@ DROP TABLE t1; # check null values #1 # +--disable_warnings CREATE TABLE t1 (a_id tinyint(4) NOT NULL default '0', PRIMARY KEY (a_id)) ENGINE=InnoDB DEFAULT CHARSET=latin1; INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 (b_id tinyint(4) NOT NULL default '0',b_a tinyint(4) NOT NULL default '0', PRIMARY KEY (b_id), KEY (b_a), CONSTRAINT fk_b_a FOREIGN KEY (b_a) REFERENCES t1 (a_id) ON DELETE CASCADE ON UPDATE NO ACTION) ENGINE=InnoDB DEFAULT CHARSET=latin1; +--enable_warnings INSERT INTO t2 VALUES (1,1),(2,1),(3,1),(4,2),(5,2); SELECT * FROM (SELECT t1.*,GROUP_CONCAT(t2.b_id SEPARATOR ',') as b_list FROM (t1 LEFT JOIN (t2) on t1.a_id = t2.b_a) GROUP BY t1.a_id ) AS xyz; DROP TABLE t2; diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index 8d399abfec9..ce10f07cf07 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -97,7 +97,7 @@ CREATE TABLE t1 ( PRIMARY KEY (name,author,category) ); INSERT INTO t1 VALUES -('patnom','patauteur',0,'p.favre@cryo-networks.fr',NULL,NULL,'#p2sndnq6ae5g1u6t','essai\nsalut','scol://195.242.78.119:patauteur.patnom',NULL,NULL,NULL,950036174,-882087474,NULL,3,0,3,'1','Pub/patnom/futur_divers.scs',NULL,'pat','CC1'); +('patnom','patauteur',0,'p.favre@cryo-networks.fr',NULL,NULL,'#p2sndnq6ae5g1u6t','essai salut','scol://195.242.78.119:patauteur.patnom',NULL,NULL,NULL,950036174,-882087474,NULL,3,0,3,'1','Pub/patnom/futur_divers.scs',NULL,'pat','CC1'); INSERT INTO t1 VALUES ('LeNomDeMonSite','Marc',0,'m.barilley@cryo-networks.fr',NULL,NULL,NULL,NULL,'scol://195.242.78.119:Marc.LeNomDeMonSite',NULL,NULL,NULL,950560434,-881563214,NULL,3,0,3,'1','Pub/LeNomDeMonSite/domus_hibere.scs',NULL,'Marq','CC1'); select * from t1 where name='patnom' and author='patauteur' and category=0; @@ -228,3 +228,27 @@ EXPLAIN SELECT numeropost FROM t1 WHERE numreponse='1'; FLUSH TABLES; SELECT numeropost FROM t1 WHERE numreponse='1'; drop table t1; + +# +# UNIQUE prefix keys and multi-byte charsets +# + +create table t1 (c varchar(30) character set utf8, t text character set utf8, unique (c(2)), unique (t(3))) engine=myisam; +show create table t1; +insert t1 values ('cccc', 'tttt'), + (0xD0B1212223D0B1D0B1D0B1D0B1D0B1, 0xD0B1D0B1212223D0B1D0B1D0B1D0B1), + (0xD0B1222123D0B1D0B1D0B1D0B1D0B1, 0xD0B1D0B1222123D0B1D0B1D0B1D0B1); +--error 1062 +insert t1 (c) values ('cc22'); +--error 1062 +insert t1 (t) values ('ttt22'); +--error 1062 +insert t1 (c) values (0xD0B1212322D0B1D0B1D0B1D0B1D0B1); +--error 1062 +insert t1 (t) values (0xD0B1D0B1212322D0B1D0B1D0B1D0B1); +select c from t1 where c='cccc'; +select t from t1 where t='tttt'; +select c from t1 where c=0xD0B1212223D0B1D0B1D0B1D0B1D0B1; +select t from t1 where t=0xD0B1D0B1212223D0B1D0B1D0B1D0B1; +drop table t1; + |