summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarko@hundin.mysql.fi <>2005-02-08 16:41:34 +0200
committermarko@hundin.mysql.fi <>2005-02-08 16:41:34 +0200
commite7c10dd2d806f84c7c3b8a9447153d1ac17fc6ae (patch)
tree1d41c43c651ff0ac97e4022bf7e9181709da34e2
parent6e6daf818943e34d72017f64e496d6d94c90134f (diff)
downloadmariadb-git-e7c10dd2d806f84c7c3b8a9447153d1ac17fc6ae.tar.gz
InnoDB: Fix Bug #7350 without hard-coding charset-collation numbers.
-rw-r--r--innobase/data/data0type.c4
-rw-r--r--innobase/include/data0type.h23
-rw-r--r--innobase/include/data0type.ic86
-rw-r--r--innobase/include/row0mysql.h4
-rw-r--r--innobase/include/row0mysql.ic15
-rw-r--r--innobase/row/row0sel.c23
-rw-r--r--sql/ha_innodb.cc25
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) {