diff options
author | marko@hundin.mysql.fi <> | 2005-02-08 16:41:34 +0200 |
---|---|---|
committer | marko@hundin.mysql.fi <> | 2005-02-08 16:41:34 +0200 |
commit | e7c10dd2d806f84c7c3b8a9447153d1ac17fc6ae (patch) | |
tree | 1d41c43c651ff0ac97e4022bf7e9181709da34e2 | |
parent | 6e6daf818943e34d72017f64e496d6d94c90134f (diff) | |
download | mariadb-git-e7c10dd2d806f84c7c3b8a9447153d1ac17fc6ae.tar.gz |
InnoDB: Fix Bug #7350 without hard-coding charset-collation numbers.
-rw-r--r-- | innobase/data/data0type.c | 4 | ||||
-rw-r--r-- | innobase/include/data0type.h | 23 | ||||
-rw-r--r-- | innobase/include/data0type.ic | 86 | ||||
-rw-r--r-- | innobase/include/row0mysql.h | 4 | ||||
-rw-r--r-- | innobase/include/row0mysql.ic | 15 | ||||
-rw-r--r-- | innobase/row/row0sel.c | 23 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 25 |
7 files changed, 126 insertions, 54 deletions
diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c index b1297fe7a5b..b8e4dd9c7f2 100644 --- a/innobase/data/data0type.c +++ b/innobase/data/data0type.c @@ -41,7 +41,7 @@ charset-collation code for them. */ ulint data_mysql_default_charset_coll = 99999999; ulint data_mysql_latin1_swedish_charset_coll = 99999999; -dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0}; +dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0, 0, 0}; dtype_t* dtype_binary = &dtype_binary_val; /************************************************************************* @@ -216,6 +216,8 @@ dtype_validate( ut_a((type->prtype & DATA_MYSQL_TYPE_MASK) < DATA_N_SYS_COLS); } + ut_a(type->mbminlen <= type->mbmaxlen); + return(TRUE); } diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h index 02c874836fd..bebb77ae57c 100644 --- a/innobase/include/data0type.h +++ b/innobase/include/data0type.h @@ -271,6 +271,24 @@ dtype_get_prec( /*===========*/ dtype_t* type); /************************************************************************* +Gets the minimum length of a character, in bytes. */ +UNIV_INLINE +ulint +dtype_get_mbminlen( +/*===============*/ + /* out: minimum length of a char, in bytes, + or 0 if this is not a character type */ + const dtype_t* type); /* in: type */ +/************************************************************************* +Gets the maximum length of a character, in bytes. */ +UNIV_INLINE +ulint +dtype_get_mbmaxlen( +/*===============*/ + /* out: maximum length of a char, in bytes, + or 0 if this is not a character type */ + const dtype_t* type); /* in: type */ +/************************************************************************* Gets the padding character code for the type. */ UNIV_INLINE ulint @@ -358,10 +376,13 @@ struct dtype_struct{ ulint mtype; /* main data type */ ulint prtype; /* precise type; MySQL data type */ - /* the remaining two fields do not affect alphabetical ordering: */ + /* the remaining fields do not affect alphabetical ordering: */ ulint len; /* length */ ulint prec; /* precision */ + + ulint mbminlen; /* minimum length of a character, in bytes */ + ulint mbmaxlen; /* maximum length of a character, in bytes */ }; #ifndef UNIV_NONINL diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic index 15833905761..95da830198e 100644 --- a/innobase/include/data0type.ic +++ b/innobase/include/data0type.ic @@ -9,15 +9,46 @@ Created 1/16/1996 Heikki Tuuri #include "mach0data.h" /********************************************************************** -Determines whether the given character set is of variable length. +Get the variable length bounds of the given character set. NOTE: the prototype of this function is copied from ha_innodb.cc! If you change this function, you MUST change also the prototype here! */ extern -ibool -innobase_is_mb_cset( -/*================*/ - ulint cset); /* in: MySQL charset-collation code */ +void +innobase_get_mb_cset( +/*=================*/ + ulint cset, /* in: MySQL charset-collation code */ + ulint* mbminlen, /* out: minimum length of a char (in bytes) */ + ulint* mbmaxlen); /* out: maximum length of a char (in bytes) */ + +/************************************************************************* +Gets the MySQL charset-collation code for MySQL string types. */ +UNIV_INLINE +ulint +dtype_get_charset_coll( +/*===================*/ + ulint prtype) /* in: precise data type */ +{ + return((prtype >> 16) & 0xFFUL); +} + +/************************************************************************* +Sets the mbminlen and mbmaxlen members of a data type structure. */ +UNIV_INLINE +void +dtype_set_mblen( +/*============*/ + dtype_t* type) /* in/out: type struct */ +{ + ut_ad(type); + if (dtype_is_string_type(type->mtype)) { + innobase_get_mb_cset(dtype_get_charset_coll(type->prtype), + &type->mbminlen, &type->mbmaxlen); + ut_ad(type->mbminlen <= type->mbmaxlen); + } else { + type->mbminlen = type->mbmaxlen = 0; + } +} /************************************************************************* Sets a data type structure. */ @@ -39,6 +70,7 @@ dtype_set( type->len = len; type->prec = prec; + dtype_set_mblen(type); ut_ad(dtype_validate(type)); } @@ -83,17 +115,6 @@ dtype_get_prtype( } /************************************************************************* -Gets the MySQL charset-collation code for MySQL string types. */ -UNIV_INLINE -ulint -dtype_get_charset_coll( -/*===================*/ - ulint prtype) /* in: precise data type */ -{ - return((prtype >> 16) & 0xFFUL); -} - -/************************************************************************* Gets the type length. */ UNIV_INLINE ulint @@ -120,6 +141,33 @@ dtype_get_prec( } /************************************************************************* +Gets the minimum length of a character, in bytes. */ +UNIV_INLINE +ulint +dtype_get_mbminlen( +/*===============*/ + /* out: minimum length of a char, in bytes, + or 0 if this is not a character type */ + const dtype_t* type) /* in: type */ +{ + ut_ad(type); + return(type->mbminlen); +} +/************************************************************************* +Gets the maximum length of a character, in bytes. */ +UNIV_INLINE +ulint +dtype_get_mbmaxlen( +/*===============*/ + /* out: maximum length of a char, in bytes, + or 0 if this is not a character type */ + const dtype_t* type) /* in: type */ +{ + ut_ad(type); + return(type->mbmaxlen); +} + +/************************************************************************* Gets the padding character code for the type. */ UNIV_INLINE ulint @@ -211,6 +259,7 @@ dtype_read_for_order_and_null_size( type->prtype = dtype_form_prtype(type->prtype, data_mysql_default_charset_coll); + dtype_set_mblen(type); } /************************************************************************** @@ -262,6 +311,7 @@ dtype_new_read_for_order_and_null_size( type->prtype = dtype_form_prtype(type->prtype, charset_coll); } + dtype_set_mblen(type); } /*************************************************************************** @@ -306,9 +356,7 @@ dtype_get_fixed_size( case DATA_DOUBLE: case DATA_MYSQL: if ((type->prtype & DATA_BINARY_TYPE) - || !innobase_is_mb_cset( - dtype_get_charset_coll( - type->prtype))) { + || type->mbminlen == type->mbmaxlen) { return(dtype_get_len(type)); } /* fall through for variable-length charsets */ diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 2ef260829fc..7ffa6ebf87d 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -458,6 +458,10 @@ struct mysql_row_templ_struct { numbers DATA_CHAR... */ ulint charset; /* MySQL charset-collation code of the column, or zero */ + ulint mbminlen; /* minimum length of a char, in bytes, + or zero if not a char type */ + ulint mbmaxlen; /* maximum length of a char, in bytes, + or zero if not a char type */ ulint is_unsigned; /* if a column type is an integer type and this field is != 0, then it is an unsigned integer type */ diff --git a/innobase/include/row0mysql.ic b/innobase/include/row0mysql.ic index fc922b52d0a..1f5d0b0c990 100644 --- a/innobase/include/row0mysql.ic +++ b/innobase/include/row0mysql.ic @@ -93,17 +93,11 @@ row_mysql_store_col_in_innobase_format( || type == DATA_BINARY) { /* Remove trailing spaces. */ - /* Handle UCS2 strings differently. As no new - collations will be introduced in 4.1, we hardcode the - charset-collation codes here. In 5.0, the logic will - be based on mbminlen. */ - ulint cset = dtype_get_charset_coll( - dtype_get_prtype(dfield_get_type(dfield))); + /* Handle UCS2 strings differently. */ + ulint mbminlen = dtype_get_mbminlen( + dfield_get_type(dfield)); ptr = row_mysql_read_var_ref(&col_len, mysql_data); - if (cset == 35/*ucs2_general_ci*/ - || cset == 90/*ucs2_bin*/ - || (cset >= 128/*ucs2_unicode_ci*/ - && cset <= 144/*ucs2_persian_ci*/)) { + if (mbminlen == 2) { /* space=0x0020 */ /* Trim "half-chars", just in case. */ col_len &= ~1; @@ -113,6 +107,7 @@ row_mysql_store_col_in_innobase_format( col_len -= 2; } } else { + ut_a(mbminlen == 1); /* space=0x20 */ while (col_len > 0 && ptr[col_len - 1] == 0x20) { col_len--; diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 8512e796a72..c0141f896ce 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2410,14 +2410,9 @@ row_sel_store_mysql_rec( /* Pad with trailing spaces */ data = mysql_rec + templ->mysql_col_offset; - /* Handle UCS2 strings differently. As no new - collations will be introduced in 4.1, we - hardcode the charset-collation codes here. - 5.0 will use a different approach. */ - if (templ->charset == 35 - || templ->charset == 90 - || (templ->charset >= 128 - && templ->charset <= 144)) { + ut_ad(templ->mbminlen <= templ->mbmaxlen); + /* Handle UCS2 strings differently. */ + if (templ->mbminlen == 2) { /* space=0x0020 */ ulint col_len = templ->mysql_col_len; @@ -2436,6 +2431,7 @@ row_sel_store_mysql_rec( data[len++] = 0x20; } } else { + ut_ad(templ->mbminlen == 1); /* space=0x20 */ memset(data + len, 0x20, templ->mysql_col_len - len); @@ -2477,14 +2473,8 @@ row_sel_store_mysql_rec( pad_char = '\0'; } - /* Handle UCS2 strings differently. As no new - collations will be introduced in 4.1, - we hardcode the charset-collation codes here. - 5.0 will use a different approach. */ - if (templ->charset == 35 - || templ->charset == 90 - || (templ->charset >= 128 - && templ->charset <= 144)) { + /* Handle UCS2 strings differently. */ + if (templ->mbminlen == 2) { /* There are two bytes per char, so the length has to be an even number. */ ut_a(!(templ->mysql_col_len & 1)); @@ -2497,6 +2487,7 @@ row_sel_store_mysql_rec( len -= 2; } } else { + ut_ad(templ->mbminlen == 1); memset(mysql_rec + templ->mysql_col_offset, pad_char, templ->mysql_col_len); } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index be493138fd0..16e9760d624 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -535,22 +535,31 @@ innobase_mysql_print_thd( } /********************************************************************** -Determines whether the given character set is of variable length. +Get the variable length bounds of the given character set. NOTE that the exact prototype of this function has to be in /innobase/data/data0type.ic! */ extern "C" -ibool -innobase_is_mb_cset( -/*================*/ - ulint cset) /* in: MySQL charset-collation code */ +void +innobase_get_mb_cset( +/*=================*/ + ulint cset, /* in: MySQL charset-collation code */ + ulint* mbminlen, /* out: minimum length of a char (in bytes) */ + ulint* mbmaxlen) /* out: maximum length of a char (in bytes) */ { CHARSET_INFO* cs; ut_ad(cset < 256); + ut_ad(mbminlen); + ut_ad(mbmaxlen); cs = all_charsets[cset]; - - return(cs && cs->mbminlen != cs->mbmaxlen); + if (cs) { + *mbminlen = cs->mbminlen; + *mbmaxlen = cs->mbmaxlen; + } else { + ut_a(cset == 0); + *mbminlen = *mbmaxlen = 0; + } } /********************************************************************** @@ -2453,6 +2462,8 @@ build_template( templ->type = get_innobase_type_from_mysql_type(field); templ->charset = dtype_get_charset_coll_noninline( index->table->cols[i].type.prtype); + templ->mbminlen = index->table->cols[i].type.mbminlen; + templ->mbmaxlen = index->table->cols[i].type.mbmaxlen; templ->is_unsigned = (ulint) (field->flags & UNSIGNED_FLAG); if (templ->type == DATA_BLOB) { |