From: Date: June 7 2008 10:32am Subject: commit into mysql-6.0-rpl branch (bar:2655) Bug#34391 List-Archive: http://lists.mysql.com/commits/47567 X-Bug: 34391 Message-Id: <200806070832.m578WTxt025592@bar.myoffice.izhnet.ru> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit #At file:///home/bar/mysql-bzr/mysql-6.0.b34391/ 2655 Alexander Barkov 2008-06-07 Bug#34391 Character sets: crash if char(), utf32, innodb Problem: mbminlen in dict_col_t and dtype_t uses 2 bits, which cannot store the value of "4" required for UTF32. Fix: adding macros to pack/unpack the range 1..4 to 0..3. added: mysql-test/r/innodb-utf32.result mysql-test/t/innodb-utf32.test modified: storage/innobase/data/data0type.c storage/innobase/dict/dict0mem.c storage/innobase/handler/ha_innodb.cc storage/innobase/include/data0type.h storage/innobase/include/data0type.ic storage/innobase/include/dict0dict.ic storage/innobase/include/dict0mem.h storage/innobase/row/row0ins.c storage/innobase/row/row0row.c storage/innobase/row/row0sel.c storage/innobase/row/row0upd.c === added file 'mysql-test/r/innodb-utf32.result' --- a/mysql-test/r/innodb-utf32.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/r/innodb-utf32.result 2008-06-07 08:28:10 +0000 @@ -0,0 +1,10 @@ +drop table if exists t1; +create table t1 (s1 char(1) character set utf32) engine=innodb; +insert into t1 values ('a'),('b'),('c'); +select s1, hex(s1) from t1 order by s1; +s1 hex(s1) +a 00000061 +b 00000062 +c 00000063 +drop table t1; +End of 6.0 tests === added file 'mysql-test/t/innodb-utf32.test' --- a/mysql-test/t/innodb-utf32.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/t/innodb-utf32.test 2008-06-07 08:28:10 +0000 @@ -0,0 +1,16 @@ +-- source include/have_innodb.inc +-- source include/have_utf32.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Bug#34391 Character sets: crash if char(), utf32, innodb +# +create table t1 (s1 char(1) character set utf32) engine=innodb; +insert into t1 values ('a'),('b'),('c'); +select s1, hex(s1) from t1 order by s1; +drop table t1; + +--echo End of 6.0 tests === modified file 'storage/innobase/data/data0type.c' --- a/storage/innobase/data/data0type.c 2007-07-10 11:37:43 +0000 +++ b/storage/innobase/data/data0type.c 2008-06-07 08:28:10 +0000 @@ -197,7 +197,7 @@ ut_a((type->prtype & DATA_MYSQL_TYPE_MASK) < DATA_N_SYS_COLS); } - ut_a(type->mbminlen <= type->mbmaxlen); + ut_a(dtype_unpack_mbminlen(type) <= dtype_unpack_mbmaxlen(type)); return(TRUE); } === modified file 'storage/innobase/dict/dict0mem.c' --- a/storage/innobase/dict/dict0mem.c 2007-08-28 00:18:14 +0000 +++ b/storage/innobase/dict/dict0mem.c 2008-06-07 08:28:10 +0000 @@ -218,8 +218,8 @@ dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen); - col->mbminlen = (unsigned int) mbminlen; - col->mbmaxlen = (unsigned int) mbmaxlen; + dcol_pack_mbminlen(col, (unsigned int) mbminlen); + dcol_pack_mbmaxlen(col, (unsigned int) mbmaxlen); } /************************************************************************** === modified file 'storage/innobase/handler/ha_innodb.cc' --- a/storage/innobase/handler/ha_innodb.cc 2008-04-01 13:19:15 +0000 +++ b/storage/innobase/handler/ha_innodb.cc 2008-06-07 08:28:10 +0000 @@ -3235,8 +3235,8 @@ templ->charset = dtype_get_charset_coll_noninline( index->table->cols[i].prtype); - templ->mbminlen = index->table->cols[i].mbminlen; - templ->mbmaxlen = index->table->cols[i].mbmaxlen; + templ->mbminlen = dcol_unpack_mbminlen(&(index->table->cols[i])); + templ->mbmaxlen = dcol_unpack_mbmaxlen(&(index->table->cols[i])); templ->is_unsigned = index->table->cols[i].prtype & DATA_UNSIGNED; if (templ->type == DATA_BLOB) { === modified file 'storage/innobase/include/data0type.h' --- a/storage/innobase/include/data0type.h 2006-09-21 09:48:26 +0000 +++ b/storage/innobase/include/data0type.h 2008-06-07 08:28:10 +0000 @@ -437,12 +437,18 @@ the string, MySQL uses 1 or 2 bytes to store the string length) */ - unsigned mbminlen:2; /* minimum length of a + unsigned mb_minlen:2; /* minimum length of a character, in bytes */ - unsigned mbmaxlen:3; /* maximum length of a + unsigned mb_maxlen:3; /* maximum length of a character, in bytes */ }; +#define dtype_unpack_mbminlen(x) ((x)->mb_minlen + 1) +#define dtype_unpack_mbmaxlen(x) ((x)->mb_maxlen + 1) +#define dtype_pack_mbminlen(x,l) ((x)->mb_minlen= l - 1) +#define dtype_pack_mbmaxlen(x,l) ((x)->mb_maxlen= l - 1) + + #ifndef UNIV_NONINL #include "data0type.ic" #endif === modified file 'storage/innobase/include/data0type.ic' --- a/storage/innobase/include/data0type.ic 2007-01-05 02:51:34 +0000 +++ b/storage/innobase/include/data0type.ic 2008-06-07 08:28:10 +0000 @@ -88,8 +88,9 @@ ulint mbmaxlen; dtype_get_mblen(type->mtype, type->prtype, &mbminlen, &mbmaxlen); - type->mbminlen = mbminlen; - type->mbmaxlen = mbmaxlen; + ut_ad(mbminlen > 0 && mbmaxlen > 0); + dtype_pack_mbminlen(type, mbminlen); + dtype_pack_mbmaxlen(type, mbmaxlen); ut_ad(dtype_validate(type)); } @@ -179,7 +180,7 @@ const dtype_t* type) /* in: type */ { ut_ad(type); - return(type->mbminlen); + return(dtype_unpack_mbminlen(type)); } /************************************************************************* Gets the maximum length of a character, in bytes. */ @@ -192,7 +193,7 @@ const dtype_t* type) /* in: type */ { ut_ad(type); - return(type->mbmaxlen); + return(dtype_unpack_mbmaxlen(type)); } /************************************************************************* @@ -558,5 +559,6 @@ const dtype_t* type) /* in: type */ { return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, - type->mbminlen, type->mbmaxlen) > 0); + dtype_unpack_mbminlen(type), + dtype_unpack_mbmaxlen(type)) > 0); } === modified file 'storage/innobase/include/dict0dict.ic' --- a/storage/innobase/include/dict0dict.ic 2007-07-10 14:34:21 +0000 +++ b/storage/innobase/include/dict0dict.ic 2008-06-07 08:28:10 +0000 @@ -26,8 +26,8 @@ type->mtype = col->mtype; type->prtype = col->prtype; type->len = col->len; - type->mbminlen = col->mbminlen; - type->mbmaxlen = col->mbmaxlen; + dtype_pack_mbminlen(type, dcol_unpack_mbminlen(col)); + dtype_pack_mbmaxlen(type, dcol_unpack_mbmaxlen(col)); } #ifdef UNIV_DEBUG @@ -64,7 +64,8 @@ const dict_col_t* col) /* in: column */ { return(dtype_get_min_size_low(col->mtype, col->prtype, col->len, - col->mbminlen, col->mbmaxlen)); + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col))); } /*************************************************************************** Returns the maximum size of the column. */ @@ -87,7 +88,8 @@ const dict_col_t* col) /* in: column */ { return(dtype_get_fixed_size_low(col->mtype, col->prtype, col->len, - col->mbminlen, col->mbmaxlen)); + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col))); } /*************************************************************************** Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column. === modified file 'storage/innobase/include/dict0mem.h' --- a/storage/innobase/include/dict0mem.h 2008-03-27 01:56:18 +0000 +++ b/storage/innobase/include/dict0mem.h 2008-06-07 08:28:10 +0000 @@ -145,9 +145,9 @@ the string, MySQL uses 1 or 2 bytes to store the string length) */ - unsigned mbminlen:2; /* minimum length of a + unsigned mb_minlen:2; /* minimum length of a character, in bytes */ - unsigned mbmaxlen:3; /* maximum length of a + unsigned mb_maxlen:3; /* maximum length of a character, in bytes */ /*----------------------*/ /* End of definitions copied from dtype_t */ @@ -159,6 +159,11 @@ of an index */ }; +#define dcol_unpack_mbminlen(x) ((x)->mb_minlen + 1) +#define dcol_unpack_mbmaxlen(x) ((x)->mb_maxlen + 1) +#define dcol_pack_mbminlen(x,l) ((x)->mb_minlen= l - 1) +#define dcol_pack_mbmaxlen(x,l) ((x)->mb_maxlen= l - 1) + /* DICT_MAX_INDEX_COL_LEN is measured in bytes and is the maximum indexed column length (or indexed prefix length). It is set to 3*256, so that one can create a column prefix index on 256 characters of a === modified file 'storage/innobase/row/row0ins.c' --- a/storage/innobase/row/row0ins.c 2007-07-10 11:37:43 +0000 +++ b/storage/innobase/row/row0ins.c 2008-06-07 08:28:10 +0000 @@ -500,7 +500,8 @@ if (ufield->new_val.len != UNIV_SQL_NULL && dtype_get_at_most_n_mbchars( col->prtype, - col->mbminlen, col->mbmaxlen, + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col), col->len, ufield->new_val.len, ufield->new_val.data) @@ -535,7 +536,7 @@ parent_ufield->new_val.data, parent_ufield->new_val.len); - switch (UNIV_EXPECT(col->mbminlen,1)) { + switch (UNIV_EXPECT(dcol_unpack_mbminlen(col),1)) { default: ut_error; case 1: @@ -2226,7 +2227,9 @@ = dict_field_get_col(ind_field); field->len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col), ind_field->prefix_len, row_field->len, row_field->data); } else { === modified file 'storage/innobase/row/row0row.c' --- a/storage/innobase/row/row0row.c 2007-07-10 11:37:43 +0000 +++ b/storage/innobase/row/row0row.c 2008-06-07 08:28:10 +0000 @@ -146,7 +146,9 @@ && dfield_get_len(dfield2) != UNIV_SQL_NULL) { storage_len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col), ind_field->prefix_len, dfield_get_len(dfield2), dfield2->data); @@ -426,8 +428,8 @@ dfield_set_len(dfield, dtype_get_at_most_n_mbchars( dtype->prtype, - dtype->mbminlen, - dtype->mbmaxlen, + dtype_unpack_mbminlen(dtype), + dtype_unpack_mbmaxlen(dtype), clust_col_prefix_len, len, (char*) field)); } @@ -530,8 +532,8 @@ dfield_set_len(dfield, dtype_get_at_most_n_mbchars( dtype->prtype, - dtype->mbminlen, - dtype->mbmaxlen, + dtype_unpack_mbminlen(dtype), + dtype_unpack_mbmaxlen(dtype), clust_col_prefix_len, len, (char*) field)); } @@ -591,7 +593,9 @@ && dfield->len != UNIV_SQL_NULL) { dfield->len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col), field->prefix_len, dfield->len, dfield->data); } } === modified file 'storage/innobase/row/row0sel.c' --- a/storage/innobase/row/row0sel.c 2008-04-01 13:19:15 +0000 +++ b/storage/innobase/row/row0sel.c 2008-06-07 08:28:10 +0000 @@ -107,7 +107,9 @@ if (ifield->prefix_len > 0 && clust_len != UNIV_SQL_NULL) { clust_len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col), ifield->prefix_len, clust_len, (char*) clust_field); } === modified file 'storage/innobase/row/row0upd.c' --- a/storage/innobase/row/row0upd.c 2007-01-05 02:51:34 +0000 +++ b/storage/innobase/row/row0upd.c 2008-06-07 08:28:10 +0000 @@ -929,8 +929,8 @@ dfield->len = dtype_get_at_most_n_mbchars( col->prtype, - col->mbminlen, - col->mbmaxlen, + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col), field->prefix_len, new_val->len, new_val->data); @@ -1005,8 +1005,8 @@ dfield->len = dtype_get_at_most_n_mbchars( col->prtype, - col->mbminlen, - col->mbmaxlen, + dcol_unpack_mbminlen(col), + dcol_unpack_mbmaxlen(col), field->prefix_len, new_val->len, new_val->data);