Commit deaba603 authored by Marko Mäkelä's avatar Marko Mäkelä

Bug#52199 utf32: mbminlen=4, mbmaxlen=4, type->mbminlen=0, type->mbmaxlen=4

Merge and adjust a forgotten change to fix this bug.
rb://393 approved by Jimmy Yang
  ------------------------------------------------------------------------
  r3794 | marko | 2009-01-07 14:14:53 +0000 (Wed, 07 Jan 2009) | 18 lines

  branches/6.0: Allow the minimum length of a multi-byte character to be
  up to 4 bytes. (Bug #35391)

  dtype_t, dict_col_t: Replace mbminlen:2, mbmaxlen:3 with mbminmaxlen:5.
  In this way, the 5 bits can hold two values of 0..4, and the storage size
  of the fields will not cross the 64-bit boundary.  Encode the values as
  DATA_MBMAX * mbmaxlen + mbminlen.  Define the auxiliary macros
  DB_MBMINLEN(mbminmaxlen), DB_MBMAXLEN(mbminmaxlen), and
  DB_MINMAXLEN(mbminlen, mbmaxlen).

  Try to trim and pad UTF-16 and UTF-32 with spaces as appropriate.

  Alexander Barkov suggested the use of cs->cset->fill(cs, buff, len, 0x20).
  ha_innobase::store_key_val_for_row() now does that, but the added function
  row_mysql_pad_col() does not, because it doesn't have the MySQL TABLE object.

  rb://49 approved by Heikki Tuuri
  ------------------------------------------------------------------------
parent 3d2c88ad
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;
-- 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;
......@@ -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);
......
......@@ -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 */
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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 */
};
......
......@@ -93,13 +93,34 @@ 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
......@@ -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 */
}
......@@ -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
......
......@@ -28,6 +28,46 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0load.h"
#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
......@@ -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.
......
......@@ -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 */
/* @} */
......
......@@ -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 */
}
......@@ -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.
......
......@@ -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));
......
......@@ -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);
......
......@@ -265,6 +265,49 @@ row_mysql_read_blob_ref(
return(data);
}
/**************************************************************//**
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
......@@ -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) {
......
......@@ -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));
}
......
......@@ -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);
......
......@@ -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);
......
......@@ -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
......
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