diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index 145c1367a10..b2a69e69b69 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -1412,6 +1412,7 @@ innobase_init(void) ut_a(DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL == my_charset_latin1.number); + ut_a(DATA_MYSQL_BINARY_CHARSET_COLL == my_charset_bin.number); /* Store the latin1_swedish_ci character ordering table to InnoDB. For non-latin1_swedish_ci charsets we use the MySQL comparison functions, diff --git a/include/data0type.h b/include/data0type.h index 7e9692eca5a..30c0f732c34 100644 --- a/include/data0type.h +++ b/include/data0type.h @@ -13,6 +13,7 @@ Created 1/16/1996 Heikki Tuuri extern ulint data_mysql_default_charset_coll; #define DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL 8 +#define DATA_MYSQL_BINARY_CHARSET_COLL 63 /* SQL data type struct */ typedef struct dtype_struct dtype_t; @@ -311,7 +312,7 @@ dtype_get_pad_char( /*===============*/ /* out: padding character code, or ULINT_UNDEFINED if no padding specified */ - dtype_t* type); /* in: type */ + const dtype_t* type); /* in: type */ /*************************************************************************** Returns the size of a fixed size data type, 0 if not a fixed size type. */ UNIV_INLINE diff --git a/include/data0type.ic b/include/data0type.ic index d4a7b3c64b8..ad0f02fa63d 100644 --- a/include/data0type.ic +++ b/include/data0type.ic @@ -188,26 +188,35 @@ dtype_get_pad_char( /*===============*/ /* out: padding character code, or ULINT_UNDEFINED if no padding specified */ - dtype_t* type) /* in: type */ + const dtype_t* type) /* in: type */ { - if (type->mtype == DATA_CHAR - || type->mtype == DATA_VARCHAR - || type->mtype == DATA_BINARY - || type->mtype == DATA_FIXBINARY - || type->mtype == DATA_MYSQL - || type->mtype == DATA_VARMYSQL - || (type->mtype == DATA_BLOB - && (type->prtype & DATA_BINARY_TYPE) == 0)) { - + switch (type->mtype) { + case DATA_FIXBINARY: + case DATA_BINARY: + if (UNIV_UNLIKELY(dtype_get_charset_coll(type->prtype) + == DATA_MYSQL_BINARY_CHARSET_COLL)) { + /* Starting from 5.0.18, do not pad + VARBINARY or BINARY columns. */ + return(ULINT_UNDEFINED); + } + /* Fall through */ + case DATA_CHAR: + case DATA_VARCHAR: + case DATA_MYSQL: + case DATA_VARMYSQL: /* Space is the padding character for all char and binary strings, and starting from 5.0.3, also for TEXT strings. */ - return((ulint)' '); + return(0x20); + case DATA_BLOB: + if ((type->prtype & DATA_BINARY_TYPE) == 0) { + return(0x20); + } + /* Fall through */ + default: + /* No padding specified */ + return(ULINT_UNDEFINED); } - - /* No padding specified */ - - return(ULINT_UNDEFINED); } /************************************************************************** diff --git a/mysql-test/innodb.result b/mysql-test/innodb.result index 39098f1bab9..f99b83b12d4 100644 --- a/mysql-test/innodb.result +++ b/mysql-test/innodb.result @@ -2875,3 +2875,105 @@ d varchar(255) character set utf8, e varchar(255) character set utf8, key (a,b,c,d,e)) engine=innodb; ERROR 42000: Specified key was too long; max key length is 3072 bytes +create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; +create table t2 (s1 binary(2),primary key (s1)) engine=innodb; +create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; +create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; +insert into t1 values (0x41),(0x4120),(0x4100); +insert into t2 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A' for key 1 +insert into t2 values (0x41),(0x4120); +insert into t3 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A ' for key 1 +insert into t3 values (0x41),(0x4100); +insert into t4 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A' for key 1 +insert into t4 values (0x41),(0x4100); +select hex(s1) from t1; +hex(s1) +41 +4100 +4120 +select hex(s1) from t2; +hex(s1) +4100 +4120 +select hex(s1) from t3; +hex(s1) +4100 +41 +select hex(s1) from t4; +hex(s1) +4100 +41 +drop table t1,t2,t3,t4; +create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb; +create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; +insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); +insert into t2 values(0x42); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +insert into t2 values(0x41); +select hex(s1) from t2; +hex(s1) +4100 +update t1 set s1=0x123456 where a=2; +select hex(s1) from t2; +hex(s1) +4100 +update t1 set s1=0x12 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x12345678 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x123457 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x1220 where a=1; +select hex(s1) from t2; +hex(s1) +1220 +update t1 set s1=0x1200 where a=1; +select hex(s1) from t2; +hex(s1) +1200 +update t1 set s1=0x4200 where a=1; +select hex(s1) from t2; +hex(s1) +4200 +delete from t1 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +delete from t1 where a=2; +update t2 set s1=0x4120; +delete from t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +delete from t1 where a!=3; +select a,hex(s1) from t1; +a hex(s1) +3 4120 +select hex(s1) from t2; +hex(s1) +4120 +drop table t2,t1; +create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb; +create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; +insert into t1 values(1,0x4100),(2,0x41); +insert into t2 values(0x41); +select hex(s1) from t2; +hex(s1) +41 +update t1 set s1=0x1234 where a=1; +select hex(s1) from t2; +hex(s1) +41 +update t1 set s1=0x12 where a=2; +select hex(s1) from t2; +hex(s1) +12 +delete from t1 where a=1; +delete from t1 where a=2; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +select a,hex(s1) from t1; +a hex(s1) +2 12 +select hex(s1) from t2; +hex(s1) +12 +drop table t2,t1; diff --git a/mysql-test/innodb.test b/mysql-test/innodb.test index f642ca29a35..e7c0c7a4085 100644 --- a/mysql-test/innodb.test +++ b/mysql-test/innodb.test @@ -1868,3 +1868,78 @@ create table t1 (a varchar(255) character set utf8, e varchar(255) character set utf8, key (a,b,c,d,e)) engine=innodb; + +# test the padding of BINARY types and collations (Bug #14189) + +create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; +create table t2 (s1 binary(2),primary key (s1)) engine=innodb; +create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; +create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; + +insert into t1 values (0x41),(0x4120),(0x4100); +-- error 1062 +insert into t2 values (0x41),(0x4120),(0x4100); +insert into t2 values (0x41),(0x4120); +-- error 1062 +insert into t3 values (0x41),(0x4120),(0x4100); +insert into t3 values (0x41),(0x4100); +-- error 1062 +insert into t4 values (0x41),(0x4120),(0x4100); +insert into t4 values (0x41),(0x4100); +select hex(s1) from t1; +select hex(s1) from t2; +select hex(s1) from t3; +select hex(s1) from t4; +drop table t1,t2,t3,t4; + +create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb; +create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; + +insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); +-- error 1452 +insert into t2 values(0x42); +insert into t2 values(0x41); +select hex(s1) from t2; +update t1 set s1=0x123456 where a=2; +select hex(s1) from t2; +-- error 1451 +update t1 set s1=0x12 where a=1; +-- error 1451 +update t1 set s1=0x12345678 where a=1; +-- error 1451 +update t1 set s1=0x123457 where a=1; +update t1 set s1=0x1220 where a=1; +select hex(s1) from t2; +update t1 set s1=0x1200 where a=1; +select hex(s1) from t2; +update t1 set s1=0x4200 where a=1; +select hex(s1) from t2; +-- error 1451 +delete from t1 where a=1; +delete from t1 where a=2; +update t2 set s1=0x4120; +-- error 1451 +delete from t1; +delete from t1 where a!=3; +select a,hex(s1) from t1; +select hex(s1) from t2; + +drop table t2,t1; + +create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb; +create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; + +insert into t1 values(1,0x4100),(2,0x41); +insert into t2 values(0x41); +select hex(s1) from t2; +update t1 set s1=0x1234 where a=1; +select hex(s1) from t2; +update t1 set s1=0x12 where a=2; +select hex(s1) from t2; +delete from t1 where a=1; +-- error 1451 +delete from t1 where a=2; +select a,hex(s1) from t1; +select hex(s1) from t2; + +drop table t2,t1; diff --git a/row/row0ins.c b/row/row0ins.c index 32aa0385596..be1a48a4b46 100644 --- a/row/row0ins.c +++ b/row/row0ins.c @@ -549,6 +549,15 @@ row_ins_cascade_calc_update_vec( default: ut_error; case 1: + if (UNIV_UNLIKELY( + dtype_get_charset_coll( + dtype_get_prtype(type)) + == DATA_MYSQL_BINARY_CHARSET_COLL)) { + /* Do not pad BINARY + columns. */ + return(ULINT_UNDEFINED); + } + /* space=0x20 */ memset(pad_start, 0x20, pad_end - pad_start);