diff options
-rw-r--r-- | mysql-test/suite/innodb/r/innodb_bug52199.result | 5 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/innodb_bug52199.test | 7 | ||||
-rw-r--r-- | storage/innobase/data/data0type.c | 11 | ||||
-rw-r--r-- | storage/innobase/dict/dict0mem.c | 31 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 30 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 6 | ||||
-rw-r--r-- | storage/innobase/include/data0type.h | 47 | ||||
-rw-r--r-- | storage/innobase/include/data0type.ic | 75 | ||||
-rw-r--r-- | storage/innobase/include/dict0dict.h | 27 | ||||
-rw-r--r-- | storage/innobase/include/dict0dict.ic | 50 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 15 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.ic | 32 | ||||
-rw-r--r-- | storage/innobase/include/row0mysql.h | 11 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.c | 63 | ||||
-rw-r--r-- | storage/innobase/row/row0merge.c | 2 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.c | 67 | ||||
-rw-r--r-- | storage/innobase/row/row0row.c | 8 | ||||
-rw-r--r-- | storage/innobase/row/row0sel.c | 58 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.c | 2 | ||||
-rw-r--r-- | storage/innobase/trx/trx0trx.c | 2 |
20 files changed, 364 insertions, 185 deletions
diff --git a/mysql-test/suite/innodb/r/innodb_bug52199.result b/mysql-test/suite/innodb/r/innodb_bug52199.result new file mode 100644 index 00000000000..7e8c1ee46e0 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug52199.result @@ -0,0 +1,5 @@ +CREATE TABLE bug52199 (a INT NOT NULL, +b CHAR(125) CHARACTER SET utf32 COLLATE utf32_bin NOT NULL +)ENGINE=InnoDB; +CREATE UNIQUE INDEX idx ON bug52199(a); +DROP TABLE bug52199; diff --git a/mysql-test/suite/innodb/t/innodb_bug52199.test b/mysql-test/suite/innodb/t/innodb_bug52199.test new file mode 100644 index 00000000000..0fec64ba243 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug52199.test @@ -0,0 +1,7 @@ +-- source include/have_innodb.inc + +CREATE TABLE bug52199 (a INT NOT NULL, +b CHAR(125) CHARACTER SET utf32 COLLATE utf32_bin NOT NULL +)ENGINE=InnoDB; +CREATE UNIQUE INDEX idx ON bug52199(a); +DROP TABLE bug52199; diff --git a/storage/innobase/data/data0type.c b/storage/innobase/data/data0type.c index e834fd2ec55..20d1f5db8d3 100644 --- a/storage/innobase/data/data0type.c +++ b/storage/innobase/data/data0type.c @@ -49,10 +49,8 @@ ulint dtype_get_at_most_n_mbchars( /*========================*/ ulint prtype, /*!< in: precise type */ - ulint mbminlen, /*!< in: minimum length of a - multi-byte character */ - ulint mbmaxlen, /*!< in: maximum length of a - multi-byte character */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of + a multi-byte character */ ulint prefix_len, /*!< in: length of the requested prefix, in characters, multiplied by dtype_get_mbmaxlen(dtype) */ @@ -60,6 +58,9 @@ dtype_get_at_most_n_mbchars( const char* str) /*!< in: the string whose prefix length is being determined */ { + ulint mbminlen = DATA_MBMINLEN(mbminmaxlen); + ulint mbmaxlen = DATA_MBMAXLEN(mbminmaxlen); + ut_a(data_len != UNIV_SQL_NULL); ut_ad(!mbmaxlen || !(prefix_len % mbmaxlen)); @@ -180,7 +181,7 @@ dtype_validate( } #ifndef UNIV_HOTBACKUP - ut_a(type->mbminlen <= type->mbmaxlen); + ut_a(dtype_get_mbminlen(type) <= dtype_get_mbmaxlen(type)); #endif /* !UNIV_HOTBACKUP */ return(TRUE); diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c index c1c1c063c3e..bbb8f810f44 100644 --- a/storage/innobase/dict/dict0mem.c +++ b/storage/innobase/dict/dict0mem.c @@ -206,6 +206,37 @@ dict_mem_table_add_col( dict_mem_fill_column_struct(col, i, mtype, prtype, len); } + +/**********************************************************************//** +This function populates a dict_col_t memory structure with +supplied information. */ +UNIV_INTERN +void +dict_mem_fill_column_struct( +/*========================*/ + dict_col_t* column, /*!< out: column struct to be + filled */ + ulint col_pos, /*!< in: column position */ + ulint mtype, /*!< in: main data type */ + ulint prtype, /*!< in: precise type */ + ulint col_len) /*!< in: column length */ +{ +#ifndef UNIV_HOTBACKUP + ulint mbminlen; + ulint mbmaxlen; +#endif /* !UNIV_HOTBACKUP */ + + column->ind = (unsigned int) col_pos; + column->ord_part = 0; + column->mtype = (unsigned int) mtype; + column->prtype = (unsigned int) prtype; + column->len = (unsigned int) col_len; +#ifndef UNIV_HOTBACKUP + dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen); + dict_col_set_mbminmaxlen(column, mbminlen, mbmaxlen); +#endif /* !UNIV_HOTBACKUP */ +} + /**********************************************************************//** Creates an index memory object. @return own: index object */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f3d9bcd8d59..7cead57be62 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1036,6 +1036,8 @@ innobase_get_cset_width( if (cs) { *mbminlen = cs->mbminlen; *mbmaxlen = cs->mbmaxlen; + ut_ad(*mbminlen < DATA_MBMAX); + ut_ad(*mbmaxlen < DATA_MBMAX); } else { THD* thd = current_thd; @@ -4433,15 +4435,14 @@ ha_innobase::store_key_val_for_row( memcpy(buff, src_start, true_len); buff += true_len; - /* Pad the unused space with spaces. Note that no - padding is ever needed for UCS-2 because in MySQL, - all UCS2 characters are 2 bytes, as MySQL does not - support surrogate pairs, which are needed to represent - characters in the range U+10000 to U+10FFFF. */ + /* Pad the unused space with spaces. */ if (true_len < key_len) { - ulint pad_len = key_len - true_len; - memset(buff, ' ', pad_len); + ulint pad_len = key_len - true_len; + ut_a(!(pad_len % cs->mbminlen)); + + cs->cset->fill(cs, buff, pad_len, + 0x20 /* space */); buff += pad_len; } } @@ -4550,6 +4551,7 @@ build_template( /* Note that in InnoDB, i is the column number. MySQL calls columns 'fields'. */ for (i = 0; i < n_fields; i++) { + const dict_col_t* col = &index->table->cols[i]; templ = prebuilt->mysql_template + n_requested_fields; field = table->field[i]; @@ -4598,7 +4600,7 @@ include_field: if (index == clust_index) { templ->rec_field_no = dict_col_get_clust_pos( - &index->table->cols[i], index); + col, index); } else { templ->rec_field_no = dict_index_get_nth_col_pos( index, i); @@ -4627,7 +4629,7 @@ include_field: mysql_prefix_len = templ->mysql_col_offset + templ->mysql_col_len; } - templ->type = index->table->cols[i].mtype; + templ->type = col->mtype; templ->mysql_type = (ulint)field->type(); if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) { @@ -4635,12 +4637,10 @@ include_field: (((Field_varstring*)field)->length_bytes); } - templ->charset = dtype_get_charset_coll( - index->table->cols[i].prtype); - templ->mbminlen = index->table->cols[i].mbminlen; - templ->mbmaxlen = index->table->cols[i].mbmaxlen; - templ->is_unsigned = index->table->cols[i].prtype - & DATA_UNSIGNED; + templ->charset = dtype_get_charset_coll(col->prtype); + templ->mbminlen = dict_col_get_mbminlen(col); + templ->mbmaxlen = dict_col_get_mbmaxlen(col); + templ->is_unsigned = col->prtype & DATA_UNSIGNED; if (templ->type == DATA_BLOB) { prebuilt->templ_contains_blob = TRUE; } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index ec17882590c..3744d16570c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -99,8 +99,10 @@ innobase_col_to_mysql( #ifdef UNIV_DEBUG case DATA_MYSQL: ut_ad(flen >= len); - ut_ad(col->mbmaxlen >= col->mbminlen); - ut_ad(col->mbmaxlen > col->mbminlen || flen == len); + ut_ad(DATA_MBMAXLEN(col->mbminmaxlen) + >= DATA_MBMINLEN(col->mbminmaxlen)); + ut_ad(DATA_MBMAXLEN(col->mbminmaxlen) + > DATA_MBMINLEN(col->mbminmaxlen) || flen == len); memcpy(dest, data, len); break; diff --git a/storage/innobase/include/data0type.h b/storage/innobase/include/data0type.h index 1a9c7bbd7ba..850cf2e2975 100644 --- a/storage/innobase/include/data0type.h +++ b/storage/innobase/include/data0type.h @@ -168,6 +168,17 @@ SQL null*/ store the charset-collation number; one byte is left unused, though */ #define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6 +/* Maximum multi-byte character length in bytes, plus 1 */ +#define DATA_MBMAX 5 + +/* Pack mbminlen, mbmaxlen to mbminmaxlen. */ +#define DATA_MBMINMAXLEN(mbminlen, mbmaxlen) \ + ((mbmaxlen) * DATA_MBMAX + (mbminlen)) +/* Get mbminlen from mbminmaxlen. */ +#define DATA_MBMINLEN(mbminmaxlen) UNIV_EXPECT(((mbminmaxlen) % DATA_MBMAX), 1) +/* Get mbmaxlen from mbminmaxlen. */ +#define DATA_MBMAXLEN(mbminmaxlen) ((mbminmaxlen) / DATA_MBMAX) + #ifndef UNIV_HOTBACKUP /*********************************************************************//** Gets the MySQL type code from a dtype. @@ -187,10 +198,8 @@ ulint dtype_get_at_most_n_mbchars( /*========================*/ ulint prtype, /*!< in: precise type */ - ulint mbminlen, /*!< in: minimum length of a - multi-byte character */ - ulint mbmaxlen, /*!< in: maximum length of a - multi-byte character */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of + a multi-byte character */ ulint prefix_len, /*!< in: length of the requested prefix, in characters, multiplied by dtype_get_mbmaxlen(dtype) */ @@ -335,6 +344,19 @@ dtype_get_mbmaxlen( /*===============*/ const dtype_t* type); /*!< in: type */ /*********************************************************************//** +Sets the minimum and maximum length of a character, in bytes. */ +UNIV_INLINE +void +dtype_set_mbminmaxlen( +/*==================*/ + dtype_t* type, /*!< in/out: type */ + ulint mbminlen, /*!< in: minimum length of a char, + in bytes, or 0 if this is not + a character type */ + ulint mbmaxlen); /*!< in: maximum length of a char, + in bytes, or 0 if this is not + a character type */ +/*********************************************************************//** Gets the padding character code for the type. @return padding character code, or ULINT_UNDEFINED if no padding specified */ UNIV_INLINE @@ -354,8 +376,8 @@ dtype_get_fixed_size_low( ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ ulint len, /*!< in: length */ - ulint mbminlen, /*!< in: minimum length of a multibyte char */ - ulint mbmaxlen, /*!< in: maximum length of a multibyte char */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of a + multibyte character, in bytes */ ulint comp); /*!< in: nonzero=ROW_FORMAT=COMPACT */ #ifndef UNIV_HOTBACKUP /***********************************************************************//** @@ -368,8 +390,8 @@ dtype_get_min_size_low( ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ ulint len, /*!< in: length */ - ulint mbminlen, /*!< in: minimum length of a multibyte char */ - ulint mbmaxlen); /*!< in: maximum length of a multibyte char */ + ulint mbminmaxlen); /*!< in: minimum and maximum length of a + multibyte character */ /***********************************************************************//** Returns the maximum size of a data type. Note: types in system tables may be incomplete and return incorrect information. @@ -472,10 +494,11 @@ struct dtype_struct{ the string, MySQL uses 1 or 2 bytes to store the string length) */ #ifndef UNIV_HOTBACKUP - unsigned mbminlen:2; /*!< minimum length of a - character, in bytes */ - unsigned mbmaxlen:3; /*!< maximum length of a - character, in bytes */ + unsigned mbminmaxlen:5; /*!< minimum and maximum length of a + character, in bytes; + DATA_MBMINMAXLEN(mbminlen,mbmaxlen); + mbminlen=DATA_MBMINLEN(mbminmaxlen); + mbmaxlen=DATA_MBMINLEN(mbminmaxlen) */ #endif /* !UNIV_HOTBACKUP */ }; diff --git a/storage/innobase/include/data0type.ic b/storage/innobase/include/data0type.ic index 2bf67a941bd..757dd815c5e 100644 --- a/storage/innobase/include/data0type.ic +++ b/storage/innobase/include/data0type.ic @@ -93,14 +93,35 @@ dtype_get_mblen( innobase_get_cset_width(dtype_get_charset_coll(prtype), mbminlen, mbmaxlen); ut_ad(*mbminlen <= *mbmaxlen); - ut_ad(*mbminlen <= 2); /* mbminlen in dtype_t is 0..3 */ - ut_ad(*mbmaxlen < 1 << 3); /* mbmaxlen in dtype_t is 0..7 */ + ut_ad(*mbminlen < DATA_MBMAX); + ut_ad(*mbmaxlen < DATA_MBMAX); } else { *mbminlen = *mbmaxlen = 0; } } /*********************************************************************//** +Sets the minimum and maximum length of a character, in bytes. */ +UNIV_INLINE +void +dtype_set_mbminmaxlen( +/*==================*/ + dtype_t* type, /*!< in/out: type */ + ulint mbminlen, /*!< in: minimum length of a char, + in bytes, or 0 if this is not + a character type */ + ulint mbmaxlen) /*!< in: maximum length of a char, + in bytes, or 0 if this is not + a character type */ +{ + ut_ad(mbminlen < DATA_MBMAX); + ut_ad(mbmaxlen < DATA_MBMAX); + ut_ad(mbminlen <= mbmaxlen); + + type->mbminmaxlen = DATA_MBMINMAXLEN(mbminlen, mbmaxlen); +} + +/*********************************************************************//** Compute the mbminlen and mbmaxlen members of a data type structure. */ UNIV_INLINE void @@ -112,8 +133,7 @@ dtype_set_mblen( ulint mbmaxlen; dtype_get_mblen(type->mtype, type->prtype, &mbminlen, &mbmaxlen); - type->mbminlen = mbminlen; - type->mbmaxlen = mbmaxlen; + dtype_set_mbminmaxlen(type, mbminlen, mbmaxlen); ut_ad(dtype_validate(type)); } @@ -210,7 +230,7 @@ dtype_get_mbminlen( const dtype_t* type) /*!< in: type */ { ut_ad(type); - return(type->mbminlen); + return(DATA_MBMINLEN(type->mbminmaxlen)); } /*********************************************************************//** Gets the maximum length of a character, in bytes. @@ -223,7 +243,7 @@ dtype_get_mbmaxlen( const dtype_t* type) /*!< in: type */ { ut_ad(type); - return(type->mbmaxlen); + return(DATA_MBMAXLEN(type->mbminmaxlen)); } /*********************************************************************//** @@ -404,8 +424,8 @@ dtype_get_fixed_size_low( ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ ulint len, /*!< in: length */ - ulint mbminlen, /*!< in: minimum length of a multibyte char */ - ulint mbmaxlen, /*!< in: maximum length of a multibyte char */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of + a multibyte character, in bytes */ ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */ { switch (mtype) { @@ -453,8 +473,9 @@ dtype_get_fixed_size_low( dtype_get_charset_coll(prtype), &i_mbminlen, &i_mbmaxlen); - if (UNIV_UNLIKELY(mbminlen != i_mbminlen) - || UNIV_UNLIKELY(mbmaxlen != i_mbmaxlen)) { + if (UNIV_UNLIKELY + (DATA_MBMINMAXLEN(i_mbminlen, i_mbmaxlen) + != mbminmaxlen)) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: " @@ -464,10 +485,10 @@ dtype_get_fixed_size_low( "type->mbmaxlen=%lu\n", (ulong) i_mbminlen, (ulong) i_mbmaxlen, - (ulong) mbminlen, - (ulong) mbmaxlen); + (ulong) DATA_MBMINLEN(mbminmaxlen), + (ulong) DATA_MBMAXLEN(mbminmaxlen)); } - if (mbminlen == mbmaxlen) { + if (i_mbminlen == i_mbmaxlen) { return(len); } } @@ -499,8 +520,8 @@ dtype_get_min_size_low( ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ ulint len, /*!< in: length */ - ulint mbminlen, /*!< in: minimum length of a multibyte char */ - ulint mbmaxlen) /*!< in: maximum length of a multibyte char */ + ulint mbminmaxlen) /*!< in: minimum and maximum length of a + multi-byte character */ { switch (mtype) { case DATA_SYS: @@ -527,14 +548,22 @@ dtype_get_min_size_low( case DATA_DOUBLE: return(len); case DATA_MYSQL: - if ((prtype & DATA_BINARY_TYPE) || mbminlen == mbmaxlen) { + if (prtype & DATA_BINARY_TYPE) { return(len); + } else { + ulint mbminlen = DATA_MBMINLEN(mbminmaxlen); + ulint mbmaxlen = DATA_MBMAXLEN(mbminmaxlen); + + if (mbminlen == mbmaxlen) { + return(len); + } + + /* this is a variable-length character set */ + ut_a(mbminlen > 0); + ut_a(mbmaxlen > mbminlen); + ut_a(len % mbmaxlen == 0); + return(len * mbminlen / mbmaxlen); } - /* this is a variable-length character set */ - ut_a(mbminlen > 0); - ut_a(mbmaxlen > mbminlen); - ut_a(len % mbmaxlen == 0); - return(len * mbminlen / mbmaxlen); case DATA_VARCHAR: case DATA_BINARY: case DATA_DECIMAL: @@ -595,9 +624,9 @@ dtype_get_sql_null_size( { #ifndef UNIV_HOTBACKUP return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, - type->mbminlen, type->mbmaxlen, comp)); + type->mbminmaxlen, comp)); #else /* !UNIV_HOTBACKUP */ return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, - 0, 0, 0)); + 0, 0)); #endif /* !UNIV_HOTBACKUP */ } diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 28fa12e4678..971173a65a5 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -102,6 +102,33 @@ void dict_load_space_id_list(void); /*=========================*/ /*********************************************************************//** +Gets the minimum number of bytes per character. +@return minimum multi-byte char size, in bytes */ +UNIV_INLINE +ulint +dict_col_get_mbminlen( +/*==================*/ + const dict_col_t* col); /*!< in: column */ +/*********************************************************************//** +Gets the maximum number of bytes per character. +@return maximum multi-byte char size, in bytes */ +UNIV_INLINE +ulint +dict_col_get_mbmaxlen( +/*==================*/ + const dict_col_t* col); /*!< in: column */ +/*********************************************************************//** +Sets the minimum and maximum number of bytes per character. */ +UNIV_INLINE +void +dict_col_set_mbminmaxlen( +/*=====================*/ + dict_col_t* col, /*!< in/out: column */ + ulint mbminlen, /*!< in: minimum multi-byte + character size, in bytes */ + ulint mbmaxlen); /*!< in: minimum multi-byte + character size, in bytes */ +/*********************************************************************//** Gets the column data type. */ UNIV_INLINE void diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index b118df87f8b..09f967aa74a 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -29,6 +29,46 @@ Created 1/8/1996 Heikki Tuuri #include "rem0types.h" /*********************************************************************//** +Gets the minimum number of bytes per character. +@return minimum multi-byte char size, in bytes */ +UNIV_INLINE +ulint +dict_col_get_mbminlen( +/*==================*/ + const dict_col_t* col) /*!< in: column */ +{ + return(DATA_MBMINLEN(col->mbminmaxlen)); +} +/*********************************************************************//** +Gets the maximum number of bytes per character. +@return maximum multi-byte char size, in bytes */ +UNIV_INLINE +ulint +dict_col_get_mbmaxlen( +/*==================*/ + const dict_col_t* col) /*!< in: column */ +{ + return(DATA_MBMAXLEN(col->mbminmaxlen)); +} +/*********************************************************************//** +Sets the minimum and maximum number of bytes per character. */ +UNIV_INLINE +void +dict_col_set_mbminmaxlen( +/*=====================*/ + dict_col_t* col, /*!< in/out: column */ + ulint mbminlen, /*!< in: minimum multi-byte + character size, in bytes */ + ulint mbmaxlen) /*!< in: minimum multi-byte + character size, in bytes */ +{ + ut_ad(mbminlen < DATA_MBMAX); + ut_ad(mbmaxlen < DATA_MBMAX); + ut_ad(mbminlen <= mbmaxlen); + + col->mbminmaxlen = DATA_MBMINMAXLEN(mbminlen, mbmaxlen); +} +/*********************************************************************//** Gets the column data type. */ UNIV_INLINE void @@ -42,8 +82,7 @@ dict_col_copy_type( type->mtype = col->mtype; type->prtype = col->prtype; type->len = col->len; - type->mbminlen = col->mbminlen; - type->mbmaxlen = col->mbmaxlen; + type->mbminmaxlen = col->mbminmaxlen; } #endif /* !UNIV_HOTBACKUP */ @@ -65,8 +104,7 @@ dict_col_type_assert_equal( ut_ad(col->prtype == type->prtype); ut_ad(col->len == type->len); # ifndef UNIV_HOTBACKUP - ut_ad(col->mbminlen == type->mbminlen); - ut_ad(col->mbmaxlen == type->mbmaxlen); + ut_ad(col->mbminmaxlen == type->mbminmaxlen); # endif /* !UNIV_HOTBACKUP */ return(TRUE); @@ -84,7 +122,7 @@ dict_col_get_min_size( const dict_col_t* col) /*!< in: column */ { return(dtype_get_min_size_low(col->mtype, col->prtype, col->len, - col->mbminlen, col->mbmaxlen)); + col->mbminmaxlen)); } /***********************************************************************//** Returns the maximum size of the column. @@ -109,7 +147,7 @@ dict_col_get_fixed_size( ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */ { return(dtype_get_fixed_size_low(col->mtype, col->prtype, col->len, - col->mbminlen, col->mbmaxlen, comp)); + col->mbminmaxlen, comp)); } /***********************************************************************//** Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column. diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 286eb408a3b..75f9acd6b26 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -151,9 +151,9 @@ dict_mem_table_add_col( ulint prtype, /*!< in: precise type */ ulint len); /*!< in: precision */ /**********************************************************************//** -This function poplulates a dict_col_t memory structure with +This function populates a dict_col_t memory structure with supplied information. */ -UNIV_INLINE +UNIV_INTERN void dict_mem_fill_column_struct( /*========================*/ @@ -162,7 +162,7 @@ dict_mem_fill_column_struct( ulint col_pos, /*!< in: column position */ ulint mtype, /*!< in: main data type */ ulint prtype, /*!< in: precise type */ - ulint col_len); /*!< in: column lenght */ + ulint col_len); /*!< in: column length */ /**********************************************************************//** This function poplulates a dict_index_t index memory structure with supplied information. */ @@ -249,10 +249,11 @@ struct dict_col_struct{ the string, MySQL uses 1 or 2 bytes to store the string length) */ - unsigned mbminlen:2; /*!< minimum length of a - character, in bytes */ - unsigned mbmaxlen:3; /*!< maximum length of a - character, in bytes */ + unsigned mbminmaxlen:5; /*!< minimum and maximum length of a + character, in bytes; + DATA_MBMINMAXLEN(mbminlen,mbmaxlen); + mbminlen=DATA_MBMINLEN(mbminmaxlen); + mbmaxlen=DATA_MBMINLEN(mbminmaxlen) */ /*----------------------*/ /* End of definitions copied from dtype_t */ /* @} */ diff --git a/storage/innobase/include/dict0mem.ic b/storage/innobase/include/dict0mem.ic index 5a851da5640..1d80ffc9b94 100644 --- a/storage/innobase/include/dict0mem.ic +++ b/storage/innobase/include/dict0mem.ic @@ -70,35 +70,3 @@ dict_mem_fill_index_struct( index->magic_n = DICT_INDEX_MAGIC_N; #endif /* UNIV_DEBUG */ } - -/**********************************************************************//** -This function poplulates a dict_col_t memory structure with -supplied information. */ -UNIV_INLINE -void -dict_mem_fill_column_struct( -/*========================*/ - dict_col_t* column, /*!< out: column struct to be - filled */ - ulint col_pos, /*!< in: column position */ - ulint mtype, /*!< in: main data type */ - ulint prtype, /*!< in: precise type */ - ulint col_len) /*!< in: column lenght */ -{ -#ifndef UNIV_HOTBACKUP - ulint mbminlen; - ulint mbmaxlen; -#endif /* !UNIV_HOTBACKUP */ - - column->ind = (unsigned int) col_pos; - column->ord_part = 0; - column->mtype = (unsigned int) mtype; - column->prtype = (unsigned int) prtype; - column->len = (unsigned int) col_len; -#ifndef UNIV_HOTBACKUP - dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen); - - column->mbminlen = (unsigned int) mbminlen; - column->mbmaxlen = (unsigned int) mbmaxlen; -#endif /* !UNIV_HOTBACKUP */ -} diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 39ea240772c..f97d90adb2b 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -103,6 +103,17 @@ row_mysql_read_blob_ref( ulint col_len); /*!< in: BLOB reference length (not BLOB length) */ /**************************************************************//** +Pad a column with spaces. */ +UNIV_INTERN +void +row_mysql_pad_col( +/*==============*/ + ulint mbminlen, /*!< in: minimum size of a character, + in bytes */ + byte* pad, /*!< out: padded buffer */ + ulint len); /*!< in: number of bytes to pad */ + +/**************************************************************//** Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format. The counterpart of this function is row_sel_field_store_in_mysql_format() in row0sel.c. diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 241f652d0bf..8fd8c4f8532 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -515,8 +515,7 @@ row_ins_cascade_calc_update_vec( if (!dfield_is_null(&ufield->new_val) && dtype_get_at_most_n_mbchars( - col->prtype, - col->mbminlen, col->mbmaxlen, + col->prtype, col->mbminmaxlen, col->len, ufield_len, dfield_get_data(&ufield->new_val)) @@ -539,49 +538,37 @@ row_ins_cascade_calc_update_vec( if (min_size > ufield_len) { - char* pad_start; - const char* pad_end; - char* padded_data - = mem_heap_alloc( - heap, min_size); - pad_start = padded_data + ufield_len; - pad_end = padded_data + min_size; + byte* pad; + ulint pad_len; + byte* padded_data; + ulint mbminlen; + + padded_data = mem_heap_alloc( + heap, min_size); + + pad = padded_data + ufield_len; + pad_len = min_size - ufield_len; memcpy(padded_data, dfield_get_data(&ufield ->new_val), - dfield_get_len(&ufield - ->new_val)); + ufield_len); - switch (UNIV_EXPECT(col->mbminlen,1)) { - default: - ut_error; - return(ULINT_UNDEFINED); - case 1: - if (UNIV_UNLIKELY - (dtype_get_charset_coll( - col->prtype) - == DATA_MYSQL_BINARY_CHARSET_COLL)) { - /* Do not pad BINARY - columns. */ - return(ULINT_UNDEFINED); - } + mbminlen = dict_col_get_mbminlen(col); + + ut_ad(!(ufield_len % mbminlen)); + ut_ad(!(min_size % mbminlen)); - /* space=0x20 */ - memset(pad_start, 0x20, - pad_end - pad_start); - break; - case 2: - /* space=0x0020 */ - ut_a(!(ufield_len % 2)); - ut_a(!(min_size % 2)); - do { - *pad_start++ = 0x00; - *pad_start++ = 0x20; - } while (pad_start < pad_end); - break; + if (mbminlen == 1 + && dtype_get_charset_coll( + col->prtype) + == DATA_MYSQL_BINARY_CHARSET_COLL) { + /* Do not pad BINARY columns */ + return(ULINT_UNDEFINED); } + row_mysql_pad_col(mbminlen, + pad, pad_len); dfield_set_data(&ufield->new_val, padded_data, min_size); } @@ -2232,7 +2219,7 @@ row_ins_index_entry_set_vals( = dict_field_get_col(ind_field); len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, col->mbminmaxlen, ind_field->prefix_len, len, dfield_get_data(row_field)); diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c index 8aa64eb82c0..3fdad6d423b 100644 --- a/storage/innobase/row/row0merge.c +++ b/storage/innobase/row/row0merge.c @@ -338,7 +338,7 @@ row_merge_buf_add( if (ifield->prefix_len) { len = dtype_get_at_most_n_mbchars( col->prtype, - col->mbminlen, col->mbmaxlen, + col->mbminmaxlen, ifield->prefix_len, len, dfield_get_data(field)); dfield_set_len(field, len); diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 1b11987a7f9..1262ac71e98 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -266,6 +266,49 @@ row_mysql_read_blob_ref( } /**************************************************************//** +Pad a column with spaces. */ +UNIV_INTERN +void +row_mysql_pad_col( +/*==============*/ + ulint mbminlen, /*!< in: minimum size of a character, + in bytes */ + byte* pad, /*!< out: padded buffer */ + ulint len) /*!< in: number of bytes to pad */ +{ + const byte* pad_end; + + switch (UNIV_EXPECT(mbminlen, 1)) { + default: + ut_error; + case 1: + /* space=0x20 */ + memset(pad, 0x20, len); + break; + case 2: + /* space=0x0020 */ + pad_end = pad + len; + ut_a(!(len % 2)); + do { + *pad++ = 0x00; + *pad++ = 0x20; + } while (pad < pad_end); + break; + case 4: + /* space=0x00000020 */ + pad_end = pad + len; + ut_a(!(len % 4)); + do { + *pad++ = 0x00; + *pad++ = 0x00; + *pad++ = 0x00; + *pad++ = 0x20; + } while (pad < pad_end); + break; + } +} + +/**************************************************************//** Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format. The counterpart of this function is row_sel_field_store_in_mysql_format() in row0sel.c. @@ -357,12 +400,28 @@ row_mysql_store_col_in_innobase_format( /* Remove trailing spaces from old style VARCHAR columns. */ - /* Handle UCS2 strings differently. */ + /* Handle Unicode strings differently. */ ulint mbminlen = dtype_get_mbminlen(dtype); ptr = mysql_data; - if (mbminlen == 2) { + switch (mbminlen) { + default: + ut_error; + case 4: + /* space=0x00000020 */ + /* Trim "half-chars", just in case. */ + col_len &= ~3; + + while (col_len >= 4 + && ptr[col_len - 4] == 0x00 + && ptr[col_len - 3] == 0x00 + && ptr[col_len - 2] == 0x00 + && ptr[col_len - 1] == 0x20) { + col_len -= 4; + } + break; + case 2: /* space=0x0020 */ /* Trim "half-chars", just in case. */ col_len &= ~1; @@ -371,8 +430,8 @@ row_mysql_store_col_in_innobase_format( && ptr[col_len - 1] == 0x20) { col_len -= 2; } - } else { - ut_a(mbminlen == 1); + break; + case 1: /* space=0x20 */ while (col_len > 0 && ptr[col_len - 1] == 0x20) { diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index 6cdfa410c15..951148977f9 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -156,7 +156,7 @@ row_build_index_entry( } len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, col->mbminmaxlen, ind_field->prefix_len, len, dfield_get_data(dfield)); dfield_set_len(dfield, len); } @@ -514,8 +514,7 @@ row_build_row_ref( dfield_set_len(dfield, dtype_get_at_most_n_mbchars( dtype->prtype, - dtype->mbminlen, - dtype->mbmaxlen, + dtype->mbminmaxlen, clust_col_prefix_len, len, (char*) field)); } @@ -629,8 +628,7 @@ notfound: dfield_set_len(dfield, dtype_get_at_most_n_mbchars( dtype->prtype, - dtype->mbminlen, - dtype->mbmaxlen, + dtype->mbminmaxlen, clust_col_prefix_len, len, (char*) field)); } diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 01742265ae2..4bd61016b21 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -88,10 +88,8 @@ row_sel_sec_rec_is_for_blob( /*========================*/ ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ - ulint mbminlen, /*!< in: minimum length of a - multi-byte character */ - ulint mbmaxlen, /*!< in: maximum length of a - multi-byte character */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of + a multi-byte character */ const byte* clust_field, /*!< in: the locally stored part of the clustered index column, including the BLOB pointer; the clustered @@ -119,7 +117,7 @@ row_sel_sec_rec_is_for_blob( return(FALSE); } - len = dtype_get_at_most_n_mbchars(prtype, mbminlen, mbmaxlen, + len = dtype_get_at_most_n_mbchars(prtype, mbminmaxlen, sec_len, len, (const char*) buf); return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len)); @@ -202,14 +200,14 @@ row_sel_sec_rec_is_for_clust_rec( } len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, col->mbminmaxlen, ifield->prefix_len, len, (char*) clust_field); if (rec_offs_nth_extern(clust_offs, clust_pos) && len < sec_len) { if (!row_sel_sec_rec_is_for_blob( col->mtype, col->prtype, - col->mbminlen, col->mbmaxlen, + col->mbminmaxlen, clust_field, clust_len, sec_field, sec_len, dict_table_zip_size( @@ -2508,13 +2506,13 @@ row_sel_field_store_in_mysql_format( ulint len) /*!< in: length of the data */ { byte* ptr; - byte* field_end; - byte* pad_ptr; ut_ad(len != UNIV_SQL_NULL); UNIV_MEM_ASSERT_RW(data, len); switch (templ->type) { + const byte* field_end; + byte* pad; case DATA_INT: /* Convert integer data from Innobase to a little-endian format, sign bit restored to normal */ @@ -2558,38 +2556,32 @@ row_sel_field_store_in_mysql_format( unused end of a >= 5.0.3 true VARCHAR column, just in case MySQL expects its contents to be deterministic. */ - pad_ptr = dest + len; + pad = dest + len; ut_ad(templ->mbminlen <= templ->mbmaxlen); - /* We handle UCS2 charset strings differently. */ - if (templ->mbminlen == 2) { - /* A space char is two bytes, 0x0020 in UCS2 */ + /* We treat some Unicode charset strings specially. */ + switch (templ->mbminlen) { + case 4: + /* InnoDB should never have stripped partial + UTF-32 characters. */ + ut_a(!(len & 3)); + break; + case 2: + /* A space char is two bytes, + 0x0020 in UCS2 and UTF-16 */ - if (len & 1) { + if (UNIV_UNLIKELY(len & 1)) { /* A 0x20 has been stripped from the column. Pad it back. */ - if (pad_ptr < field_end) { - *pad_ptr = 0x20; - pad_ptr++; + if (pad < field_end) { + *pad++ = 0x20; } } - - /* Pad the rest of the string with 0x0020 */ - - while (pad_ptr < field_end) { - *pad_ptr = 0x00; - pad_ptr++; - *pad_ptr = 0x20; - pad_ptr++; - } - } else { - ut_ad(templ->mbminlen == 1); - /* space=0x20 */ - - memset(pad_ptr, 0x20, field_end - pad_ptr); } + + row_mysql_pad_col(templ->mbminlen, pad, field_end - pad); break; case DATA_BLOB: @@ -2614,9 +2606,9 @@ row_sel_field_store_in_mysql_format( || !(templ->mysql_col_len % templ->mbmaxlen)); ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len); - if (templ->mbminlen != templ->mbmaxlen) { + if (templ->mbminlen == 1 && templ->mbmaxlen != 1) { /* Pad with spaces. This undoes the stripping - done in row0mysql.ic, function + done in row0mysql.c, function row_mysql_store_col_in_innobase_format(). */ memset(dest + len, 0x20, templ->mysql_col_len - len); diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index fd689c58b7c..8b151ec34cc 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -949,7 +949,7 @@ row_upd_index_replace_new_col_val( } len = dtype_get_at_most_n_mbchars(col->prtype, - col->mbminlen, col->mbmaxlen, + col->mbminmaxlen, field->prefix_len, len, (const char*) data); diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 0ca6c2d7f35..19e3eb26421 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -2024,7 +2024,7 @@ trx_get_trx_by_xid( while (trx) { /* Compare two X/Open XA transaction id's: their length should be the same and binary comparison - of gtrid_lenght+bqual_length bytes should be + of gtrid_length+bqual_length bytes should be the same */ if (xid->gtrid_length == trx->xid.gtrid_length |