Commit 2bb6cefa authored by Marko Mäkelä's avatar Marko Mäkelä

Bug#15874001 CREATE INDEX ON A UTF8 CHAR COLUMN FAILS WITH ROW_FORMAT=REDUNDANT

CHAR(n) in ROW_FORMAT=REDUNDANT tables is always fixed-length
(n*mbmaxlen bytes), but in the temporary file it is variable-length
(n*mbminlen to n*mbmaxlen bytes) for variable-length character sets,
such as UTF-8.

The temporary file format used during index creation and online ALTER
TABLE is based on ROW_FORMAT=COMPACT. Thus, it should use the
variable-length encoding even if the base table is in
ROW_FORMAT=REDUNDNAT.

dtype_get_fixed_size_low(): Replace an assertion-like check with a
debug assertion.

rec_init_offsets_comp_ordinary(), rec_convert_dtuple_to_rec_comp():
Make this an inline function.  Replace 'ulint extra' with 'bool temp'.

rec_get_converted_size_comp_prefix_low(): Renamed from
rec_get_converted_size_comp_prefix(), and made inline. Add the
parameter 'bool temp'. If temp=true, do not add REC_N_NEW_EXTRA_BYTES.

rec_get_converted_size_comp_prefix(): Remove the comment about
dict_table_is_comp(). This function is only to be called for other
than ROW_FORMAT=REDUNDANT records.

rec_get_converted_size_temp(): New function for computing temporary
file record size. Omit REC_N_NEW_EXTRA_BYTES from the sizes.

rec_init_offsets_temp(), rec_convert_dtuple_to_temp(): New functions,
for operating on temporary file records.

rb:1559 approved by Jimmy Yang
parent abc554d1
2012-11-15 The InnoDB Team
* include/data0type.ic, include/rem0rec.h,
rem/rem0rec.c, row/row0merge.c:
Fix Bug#15874001 CREATE INDEX ON A UTF8 CHAR COLUMN FAILS WITH
ROW_FORMAT=REDUNDANT
2012-10-18 The InnoDB Team 2012-10-18 The InnoDB Team
* row/row0sel.c: * row/row0sel.c:
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -439,34 +439,16 @@ dtype_get_fixed_size_low( ...@@ -439,34 +439,16 @@ dtype_get_fixed_size_low(
} else if (!comp) { } else if (!comp) {
return(len); return(len);
} else { } else {
/* We play it safe here and ask MySQL for #ifdef UNIV_DEBUG
mbminlen and mbmaxlen. Although
mbminlen and mbmaxlen are
initialized if and only if prtype
is (in one of the 3 functions in this file),
it could be that none of these functions
has been called. */
ulint i_mbminlen, i_mbmaxlen; ulint i_mbminlen, i_mbmaxlen;
innobase_get_cset_width( innobase_get_cset_width(
dtype_get_charset_coll(prtype), dtype_get_charset_coll(prtype),
&i_mbminlen, &i_mbmaxlen); &i_mbminlen, &i_mbmaxlen);
if (UNIV_UNLIKELY(mbminlen != i_mbminlen) ut_ad(mbminlen == i_mbminlen);
|| UNIV_UNLIKELY(mbmaxlen != i_mbmaxlen)) { ut_ad(mbmaxlen == i_mbmaxlen);
#endif /* UNIV_DEBUG */
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: "
"mbminlen=%lu, "
"mbmaxlen=%lu, "
"type->mbminlen=%lu, "
"type->mbmaxlen=%lu\n",
(ulong) i_mbminlen,
(ulong) i_mbmaxlen,
(ulong) mbminlen,
(ulong) mbmaxlen);
}
if (mbminlen == mbmaxlen) { if (mbminlen == mbmaxlen) {
return(len); return(len);
} }
......
...@@ -361,24 +361,6 @@ rec_get_offsets_func( ...@@ -361,24 +361,6 @@ rec_get_offsets_func(
#define rec_get_offsets(rec,index,offsets,n,heap) \ #define rec_get_offsets(rec,index,offsets,n,heap) \
rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__) rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__)
/******************************************************//**
Determine the offset to each field in a leaf-page record
in ROW_FORMAT=COMPACT. This is a special case of
rec_init_offsets() and rec_get_offsets_func(). */
UNIV_INTERN
void
rec_init_offsets_comp_ordinary(
/*===========================*/
const rec_t* rec, /*!< in: physical record in
ROW_FORMAT=COMPACT */
ulint extra, /*!< in: number of bytes to reserve
between the record header and
the data payload
(usually REC_N_NEW_EXTRA_BYTES) */
const dict_index_t* index, /*!< in: record descriptor */
ulint* offsets);/*!< in/out: array of offsets;
in: n=rec_offs_n_fields(offsets) */
/******************************************************//** /******************************************************//**
The following function determines the offsets to each field The following function determines the offsets to each field
in the record. It can reuse a previously allocated array. */ in the record. It can reuse a previously allocated array. */
...@@ -639,8 +621,48 @@ rec_copy( ...@@ -639,8 +621,48 @@ rec_copy(
/*=====*/ /*=====*/
void* buf, /*!< in: buffer */ void* buf, /*!< in: buffer */
const rec_t* rec, /*!< in: physical record */ const rec_t* rec, /*!< in: physical record */
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
__attribute__((nonnull));
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/**********************************************************//**
Determines the size of a data tuple prefix in a temporary file.
@return total size */
UNIV_INTERN
ulint
rec_get_converted_size_temp(
/*========================*/
const dict_index_t* index, /*!< in: record descriptor */
const dfield_t* fields, /*!< in: array of data fields */
ulint n_fields,/*!< in: number of data fields */
ulint* extra) /*!< out: extra size */
__attribute__((warn_unused_result, nonnull));
/******************************************************//**
Determine the offset to each field in temporary file.
@see rec_convert_dtuple_to_temp() */
UNIV_INTERN
void
rec_init_offsets_temp(
/*==================*/
const rec_t* rec, /*!< in: temporary file record */
const dict_index_t* index, /*!< in: record descriptor */
ulint* offsets)/*!< in/out: array of offsets;
in: n=rec_offs_n_fields(offsets) */
__attribute__((nonnull));
/*********************************************************//**
Builds a temporary file record out of a data tuple.
@see rec_init_offsets_temp() */
UNIV_INTERN
void
rec_convert_dtuple_to_temp(
/*=======================*/
rec_t* rec, /*!< out: record */
const dict_index_t* index, /*!< in: record descriptor */
const dfield_t* fields, /*!< in: array of data fields */
ulint n_fields) /*!< in: number of fields */
__attribute__((nonnull));
/**************************************************************//** /**************************************************************//**
Copies the first n fields of a physical record to a new physical record in Copies the first n fields of a physical record to a new physical record in
a buffer. a buffer.
...@@ -675,21 +697,6 @@ rec_fold( ...@@ -675,21 +697,6 @@ rec_fold(
__attribute__((pure)); __attribute__((pure));
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
/*********************************************************//** /*********************************************************//**
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
UNIV_INTERN
void
rec_convert_dtuple_to_rec_comp(
/*===========================*/
rec_t* rec, /*!< in: origin of record */
ulint extra, /*!< in: number of bytes to
reserve between the record
header and the data payload
(normally REC_N_NEW_EXTRA_BYTES) */
const dict_index_t* index, /*!< in: record descriptor */
ulint status, /*!< in: status bits of the record */
const dfield_t* fields, /*!< in: array of data fields */
ulint n_fields);/*!< in: number of data fields */
/*********************************************************//**
Builds a physical record out of a data tuple and Builds a physical record out of a data tuple and
stores it into the given buffer. stores it into the given buffer.
@return pointer to the origin of physical record */ @return pointer to the origin of physical record */
...@@ -722,10 +729,7 @@ UNIV_INTERN ...@@ -722,10 +729,7 @@ UNIV_INTERN
ulint ulint
rec_get_converted_size_comp_prefix( rec_get_converted_size_comp_prefix(
/*===============================*/ /*===============================*/
const dict_index_t* index, /*!< in: record descriptor; const dict_index_t* index, /*!< in: record descriptor */
dict_table_is_comp() is
assumed to hold, even if
it does not */
const dfield_t* fields, /*!< in: array of data fields */ const dfield_t* fields, /*!< in: array of data fields */
ulint n_fields,/*!< in: number of data fields */ ulint n_fields,/*!< in: number of data fields */
ulint* extra); /*!< out: extra size */ ulint* extra); /*!< out: extra size */
......
This diff is collapsed.
...@@ -291,6 +291,7 @@ row_merge_buf_add( ...@@ -291,6 +291,7 @@ row_merge_buf_add(
const dict_field_t* ifield; const dict_field_t* ifield;
const dict_col_t* col; const dict_col_t* col;
ulint col_no; ulint col_no;
ulint fixed_len;
const dfield_t* row_field; const dfield_t* row_field;
ulint len; ulint len;
...@@ -340,9 +341,21 @@ row_merge_buf_add( ...@@ -340,9 +341,21 @@ row_merge_buf_add(
ut_ad(len <= col->len || col->mtype == DATA_BLOB); ut_ad(len <= col->len || col->mtype == DATA_BLOB);
if (ifield->fixed_len) { fixed_len = ifield->fixed_len;
ut_ad(len == ifield->fixed_len); if (fixed_len && !dict_table_is_comp(index->table)
&& col->mbminlen != col->mbmaxlen) {
/* CHAR in ROW_FORMAT=REDUNDANT is always
fixed-length, but in the temporary file it is
variable-length for variable-length character
sets. */
fixed_len = 0;
}
if (fixed_len) {
ut_ad(len == fixed_len);
ut_ad(!dfield_is_ext(field)); ut_ad(!dfield_is_ext(field));
ut_ad(!col->mbmaxlen || len >= col->mbminlen
* (fixed_len / col->mbmaxlen));
} else if (dfield_is_ext(field)) { } else if (dfield_is_ext(field)) {
extra_size += 2; extra_size += 2;
} else if (len < 128 } else if (len < 128
...@@ -363,12 +376,11 @@ row_merge_buf_add( ...@@ -363,12 +376,11 @@ row_merge_buf_add(
ulint size; ulint size;
ulint extra; ulint extra;
size = rec_get_converted_size_comp(index, size = rec_get_converted_size_temp(
REC_STATUS_ORDINARY, index, entry, n_fields, &extra);
entry, n_fields, &extra);
ut_ad(data_size + extra_size + REC_N_NEW_EXTRA_BYTES == size); ut_ad(data_size + extra_size == size);
ut_ad(extra_size + REC_N_NEW_EXTRA_BYTES == extra); ut_ad(extra_size == extra);
} }
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
...@@ -572,14 +584,9 @@ row_merge_buf_write( ...@@ -572,14 +584,9 @@ row_merge_buf_write(
ulint extra_size; ulint extra_size;
const dfield_t* entry = buf->tuples[i]; const dfield_t* entry = buf->tuples[i];
size = rec_get_converted_size_comp(index, size = rec_get_converted_size_temp(
REC_STATUS_ORDINARY, index, entry, n_fields, &extra_size);
entry, n_fields,
&extra_size);
ut_ad(size >= extra_size); ut_ad(size >= extra_size);
ut_ad(extra_size >= REC_N_NEW_EXTRA_BYTES);
extra_size -= REC_N_NEW_EXTRA_BYTES;
size -= REC_N_NEW_EXTRA_BYTES;
/* Encode extra_size + 1 */ /* Encode extra_size + 1 */
if (extra_size + 1 < 0x80) { if (extra_size + 1 < 0x80) {
...@@ -592,8 +599,7 @@ row_merge_buf_write( ...@@ -592,8 +599,7 @@ row_merge_buf_write(
ut_ad(b + size < block[1]); ut_ad(b + size < block[1]);
rec_convert_dtuple_to_rec_comp(b + extra_size, 0, index, rec_convert_dtuple_to_temp(b + extra_size, index,
REC_STATUS_ORDINARY,
entry, n_fields); entry, n_fields);
b += size; b += size;
...@@ -841,7 +847,7 @@ err_exit: ...@@ -841,7 +847,7 @@ err_exit:
*mrec = *buf + extra_size; *mrec = *buf + extra_size;
rec_init_offsets_comp_ordinary(*mrec, 0, index, offsets); rec_init_offsets_temp(*mrec, index, offsets);
data_size = rec_offs_data_size(offsets); data_size = rec_offs_data_size(offsets);
...@@ -860,7 +866,7 @@ err_exit: ...@@ -860,7 +866,7 @@ err_exit:
*mrec = b + extra_size; *mrec = b + extra_size;
rec_init_offsets_comp_ordinary(*mrec, 0, index, offsets); rec_init_offsets_temp(*mrec, index, offsets);
data_size = rec_offs_data_size(offsets); data_size = rec_offs_data_size(offsets);
ut_ad(extra_size + data_size < sizeof *buf); ut_ad(extra_size + data_size < sizeof *buf);
......
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