Commit edf5f0ec authored by unknown's avatar unknown

InnoDB: Fix Bug #7350 without hard-coding charset-collation numbers.


innobase/data/data0type.c:
  Add mbminlen and mbmaxlen to dtype_t
innobase/include/data0type.h:
  Add mbminlen and mbmaxlen to dtype_t
  Add dtype_get_mbminlen() and dtype_get_mbmaxlen()
innobase/include/data0type.ic:
  Add dtype_set_mblen()
  Add dtype_get_mbminlen() and dtype_get_mbmaxlen()
  Replace innobase_is_mb_cset() with innobase_get_mb_cset()
innobase/include/row0mysql.h:
  Add mbminlen and mbmaxlen
innobase/include/row0mysql.ic:
  Detect UCS2 collations based on mbminlen
innobase/row/row0sel.c:
  Detect UCS2 collations based on mbminlen
sql/ha_innodb.cc:
  Replace innobase_is_mb_cset() with innobase_get_mb_cset()
  build_template(): Initialize templ->mbminlen and templ->mbmaxlen
parent 61e36a96
......@@ -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);
}
......
......@@ -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
......
......@@ -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));
}
......@@ -82,17 +114,6 @@ dtype_get_prtype(
return(type->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
......@@ -119,6 +140,33 @@ dtype_get_prec(
return(type->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
......@@ -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 */
......
......@@ -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 */
......
......@@ -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--;
......
......@@ -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);
}
......
......@@ -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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment