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 */
......
...@@ -167,7 +167,6 @@ rec_get_n_extern_new( ...@@ -167,7 +167,6 @@ rec_get_n_extern_new(
{ {
const byte* nulls; const byte* nulls;
const byte* lens; const byte* lens;
dict_field_t* field;
ulint null_mask; ulint null_mask;
ulint n_extern; ulint n_extern;
ulint i; ulint i;
...@@ -188,10 +187,13 @@ rec_get_n_extern_new( ...@@ -188,10 +187,13 @@ rec_get_n_extern_new(
/* read the lengths of fields 0..n */ /* read the lengths of fields 0..n */
do { do {
ulint len; const dict_field_t* field
= dict_index_get_nth_field(index, i);
const dict_col_t* col
= dict_field_get_col(field);
ulint len;
field = dict_index_get_nth_field(index, i); if (!(col->prtype & DATA_NOT_NULL)) {
if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
/* nullable field => read the null flag */ /* nullable field => read the null flag */
if (UNIV_UNLIKELY(!(byte) null_mask)) { if (UNIV_UNLIKELY(!(byte) null_mask)) {
...@@ -209,8 +211,6 @@ rec_get_n_extern_new( ...@@ -209,8 +211,6 @@ rec_get_n_extern_new(
if (UNIV_UNLIKELY(!field->fixed_len)) { if (UNIV_UNLIKELY(!field->fixed_len)) {
/* Variable-length field: read the length */ /* Variable-length field: read the length */
const dict_col_t* col
= dict_field_get_col(field);
len = *lens--; len = *lens--;
/* If the maximum length of the field is up /* If the maximum length of the field is up
to 255 bytes, the actual length is always to 255 bytes, the actual length is always
...@@ -239,16 +239,15 @@ rec_get_n_extern_new( ...@@ -239,16 +239,15 @@ rec_get_n_extern_new(
Determine the offset to each field in a leaf-page record Determine the offset to each field in a leaf-page record
in ROW_FORMAT=COMPACT. This is a special case of in ROW_FORMAT=COMPACT. This is a special case of
rec_init_offsets() and rec_get_offsets_func(). */ rec_init_offsets() and rec_get_offsets_func(). */
UNIV_INTERN UNIV_INLINE __attribute__((nonnull))
void void
rec_init_offsets_comp_ordinary( rec_init_offsets_comp_ordinary(
/*===========================*/ /*===========================*/
const rec_t* rec, /*!< in: physical record in const rec_t* rec, /*!< in: physical record in
ROW_FORMAT=COMPACT */ ROW_FORMAT=COMPACT */
ulint extra, /*!< in: number of bytes to reserve ibool temp, /*!< in: whether to use the
between the record header and format for temporary files in
the data payload index creation */
(usually REC_N_NEW_EXTRA_BYTES) */
const dict_index_t* index, /*!< in: record descriptor */ const dict_index_t* index, /*!< in: record descriptor */
ulint* offsets)/*!< in/out: array of offsets; ulint* offsets)/*!< in/out: array of offsets;
in: n=rec_offs_n_fields(offsets) */ in: n=rec_offs_n_fields(offsets) */
...@@ -256,27 +255,38 @@ rec_init_offsets_comp_ordinary( ...@@ -256,27 +255,38 @@ rec_init_offsets_comp_ordinary(
ulint i = 0; ulint i = 0;
ulint offs = 0; ulint offs = 0;
ulint any_ext = 0; ulint any_ext = 0;
const byte* nulls = rec - (extra + 1); const byte* nulls = temp
? rec - 1
: rec - (1 + REC_N_NEW_EXTRA_BYTES);
const byte* lens = nulls const byte* lens = nulls
- UT_BITS_IN_BYTES(index->n_nullable); - UT_BITS_IN_BYTES(index->n_nullable);
dict_field_t* field;
ulint null_mask = 1; ulint null_mask = 1;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/* We cannot invoke rec_offs_make_valid() here, because it can hold /* We cannot invoke rec_offs_make_valid() here if temp=TRUE.
that extra != REC_N_NEW_EXTRA_BYTES. Similarly, rec_offs_validate() Similarly, rec_offs_validate() will fail in that case, because
will fail in that case, because it invokes rec_get_status(). */ it invokes rec_get_status(). */
offsets[2] = (ulint) rec; offsets[2] = (ulint) rec;
offsets[3] = (ulint) index; offsets[3] = (ulint) index;
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
ut_ad(temp || dict_table_is_comp(index->table));
if (temp && dict_table_is_comp(index->table)) {
/* No need to do adjust fixed_len=0. We only need to
adjust it for ROW_FORMAT=REDUNDANT. */
temp = FALSE;
}
/* read the lengths of fields 0..n */ /* read the lengths of fields 0..n */
do { do {
ulint len; const dict_field_t* field
= dict_index_get_nth_field(index, i);
const dict_col_t* col
= dict_field_get_col(field);
ulint len;
field = dict_index_get_nth_field(index, i); if (!(col->prtype & DATA_NOT_NULL)) {
if (!(dict_field_get_col(field)->prtype
& DATA_NOT_NULL)) {
/* nullable field => read the null flag */ /* nullable field => read the null flag */
if (UNIV_UNLIKELY(!(byte) null_mask)) { if (UNIV_UNLIKELY(!(byte) null_mask)) {
...@@ -296,10 +306,9 @@ rec_init_offsets_comp_ordinary( ...@@ -296,10 +306,9 @@ rec_init_offsets_comp_ordinary(
null_mask <<= 1; null_mask <<= 1;
} }
if (UNIV_UNLIKELY(!field->fixed_len)) { if (!field->fixed_len
|| (temp && !dict_col_get_fixed_size(col, temp))) {
/* Variable-length field: read the length */ /* Variable-length field: read the length */
const dict_col_t* col
= dict_field_get_col(field);
len = *lens--; len = *lens--;
/* If the maximum length of the field is up /* If the maximum length of the field is up
to 255 bytes, the actual length is always to 255 bytes, the actual length is always
...@@ -393,9 +402,8 @@ rec_init_offsets( ...@@ -393,9 +402,8 @@ rec_init_offsets(
= dict_index_get_n_unique_in_tree(index); = dict_index_get_n_unique_in_tree(index);
break; break;
case REC_STATUS_ORDINARY: case REC_STATUS_ORDINARY:
rec_init_offsets_comp_ordinary(rec, rec_init_offsets_comp_ordinary(
REC_N_NEW_EXTRA_BYTES, rec, FALSE, index, offsets);
index, offsets);
return; return;
} }
...@@ -766,17 +774,19 @@ rec_get_nth_field_offs_old( ...@@ -766,17 +774,19 @@ rec_get_nth_field_offs_old(
/**********************************************************//** /**********************************************************//**
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT. Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
@return total size */ @return total size */
UNIV_INTERN UNIV_INLINE __attribute__((warn_unused_result, nonnull(1,2)))
ulint ulint
rec_get_converted_size_comp_prefix( rec_get_converted_size_comp_prefix_low(
/*===============================*/ /*===================================*/
const dict_index_t* index, /*!< in: record descriptor; const dict_index_t* index, /*!< in: record descriptor;
dict_table_is_comp() is dict_table_is_comp() is
assumed to hold, even if assumed to hold, even if
it does not */ 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 */
ibool temp) /*!< in: whether this is a
temporary file record */
{ {
ulint extra_size; ulint extra_size;
ulint data_size; ulint data_size;
...@@ -785,15 +795,25 @@ rec_get_converted_size_comp_prefix( ...@@ -785,15 +795,25 @@ rec_get_converted_size_comp_prefix(
ut_ad(fields); ut_ad(fields);
ut_ad(n_fields > 0); ut_ad(n_fields > 0);
ut_ad(n_fields <= dict_index_get_n_fields(index)); ut_ad(n_fields <= dict_index_get_n_fields(index));
ut_ad(!temp || extra);
extra_size = REC_N_NEW_EXTRA_BYTES extra_size = temp
? UT_BITS_IN_BYTES(index->n_nullable)
: REC_N_NEW_EXTRA_BYTES
+ UT_BITS_IN_BYTES(index->n_nullable); + UT_BITS_IN_BYTES(index->n_nullable);
data_size = 0; data_size = 0;
if (temp && dict_table_is_comp(index->table)) {
/* No need to do adjust fixed_len=0. We only need to
adjust it for ROW_FORMAT=REDUNDANT. */
temp = FALSE;
}
/* read the lengths of fields 0..n */ /* read the lengths of fields 0..n */
for (i = 0; i < n_fields; i++) { for (i = 0; i < n_fields; i++) {
const dict_field_t* field; const dict_field_t* field;
ulint len; ulint len;
ulint fixed_len;
const dict_col_t* col; const dict_col_t* col;
field = dict_index_get_nth_field(index, i); field = dict_index_get_nth_field(index, i);
...@@ -809,8 +829,14 @@ rec_get_converted_size_comp_prefix( ...@@ -809,8 +829,14 @@ rec_get_converted_size_comp_prefix(
continue; continue;
} }
ut_ad(len <= col->len || col->mtype == DATA_BLOB); ut_ad(len <= col->len || col->mtype == DATA_BLOB
|| (col->len == 0 && col->mtype == DATA_VARCHAR));
fixed_len = field->fixed_len;
if (temp && fixed_len
&& !dict_col_get_fixed_size(col, temp)) {
fixed_len = 0;
}
/* If the maximum length of a variable-length field /* If the maximum length of a variable-length field
is up to 255 bytes, the actual length is always stored is up to 255 bytes, the actual length is always stored
in one byte. If the maximum length is more than 255 in one byte. If the maximum length is more than 255
...@@ -818,11 +844,11 @@ rec_get_converted_size_comp_prefix( ...@@ -818,11 +844,11 @@ rec_get_converted_size_comp_prefix(
0..127. The length will be encoded in two bytes when 0..127. The length will be encoded in two bytes when
it is 128 or more, or when the field is stored externally. */ it is 128 or more, or when the field is stored externally. */
if (field->fixed_len) { if (fixed_len) {
ut_ad(len == field->fixed_len); ut_ad(len == fixed_len);
/* dict_index_add_col() should guarantee this */ /* dict_index_add_col() should guarantee this */
ut_ad(!field->prefix_len ut_ad(!field->prefix_len
|| field->fixed_len == field->prefix_len); || fixed_len == field->prefix_len);
} else if (dfield_is_ext(&fields[i])) { } else if (dfield_is_ext(&fields[i])) {
ut_ad(col->len >= 256 || col->mtype == DATA_BLOB); ut_ad(col->len >= 256 || col->mtype == DATA_BLOB);
extra_size += 2; extra_size += 2;
...@@ -839,13 +865,30 @@ rec_get_converted_size_comp_prefix( ...@@ -839,13 +865,30 @@ rec_get_converted_size_comp_prefix(
data_size += len; data_size += len;
} }
if (UNIV_LIKELY_NULL(extra)) { if (extra) {
*extra = extra_size; *extra = extra_size;
} }
return(extra_size + data_size); return(extra_size + data_size);
} }
/**********************************************************//**
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
@return total size */
UNIV_INTERN
ulint
rec_get_converted_size_comp_prefix(
/*===============================*/
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 */
{
ut_ad(dict_table_is_comp(index->table));
return(rec_get_converted_size_comp_prefix_low(
index, fields, n_fields, extra, FALSE));
}
/**********************************************************//** /**********************************************************//**
Determines the size of a data tuple in ROW_FORMAT=COMPACT. Determines the size of a data tuple in ROW_FORMAT=COMPACT.
@return total size */ @return total size */
...@@ -890,8 +933,8 @@ rec_get_converted_size_comp( ...@@ -890,8 +933,8 @@ rec_get_converted_size_comp(
return(ULINT_UNDEFINED); return(ULINT_UNDEFINED);
} }
return(size + rec_get_converted_size_comp_prefix(index, fields, return(size + rec_get_converted_size_comp_prefix_low(
n_fields, extra)); index, fields, n_fields, extra, FALSE));
} }
/***********************************************************//** /***********************************************************//**
...@@ -1068,19 +1111,18 @@ rec_convert_dtuple_to_rec_old( ...@@ -1068,19 +1111,18 @@ rec_convert_dtuple_to_rec_old(
/*********************************************************//** /*********************************************************//**
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */ Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
UNIV_INTERN UNIV_INLINE __attribute__((nonnull))
void void
rec_convert_dtuple_to_rec_comp( rec_convert_dtuple_to_rec_comp(
/*===========================*/ /*===========================*/
rec_t* rec, /*!< in: origin of record */ 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 */ 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 */ 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 status, /*!< in: status bits of the record */
ibool temp) /*!< in: whether to use the
format for temporary files in
index creation */
{ {
const dfield_t* field; const dfield_t* field;
const dtype_t* type; const dtype_t* type;
...@@ -1092,31 +1134,44 @@ rec_convert_dtuple_to_rec_comp( ...@@ -1092,31 +1134,44 @@ rec_convert_dtuple_to_rec_comp(
ulint n_node_ptr_field; ulint n_node_ptr_field;
ulint fixed_len; ulint fixed_len;
ulint null_mask = 1; ulint null_mask = 1;
ut_ad(extra == 0 || dict_table_is_comp(index->table)); ut_ad(temp || dict_table_is_comp(index->table));
ut_ad(extra == 0 || extra == REC_N_NEW_EXTRA_BYTES);
ut_ad(n_fields > 0); ut_ad(n_fields > 0);
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) { if (temp) {
case REC_STATUS_ORDINARY: ut_ad(status == REC_STATUS_ORDINARY);
ut_ad(n_fields <= dict_index_get_n_fields(index)); ut_ad(n_fields <= dict_index_get_n_fields(index));
n_node_ptr_field = ULINT_UNDEFINED; n_node_ptr_field = ULINT_UNDEFINED;
break; nulls = rec - 1;
case REC_STATUS_NODE_PTR: if (dict_table_is_comp(index->table)) {
ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1); /* No need to do adjust fixed_len=0. We only
n_node_ptr_field = n_fields - 1; need to adjust it for ROW_FORMAT=REDUNDANT. */
break; temp = FALSE;
case REC_STATUS_INFIMUM: }
case REC_STATUS_SUPREMUM: } else {
ut_ad(n_fields == 1); nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
n_node_ptr_field = ULINT_UNDEFINED;
break; switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
default: case REC_STATUS_ORDINARY:
ut_error; ut_ad(n_fields <= dict_index_get_n_fields(index));
return; n_node_ptr_field = ULINT_UNDEFINED;
break;
case REC_STATUS_NODE_PTR:
ut_ad(n_fields
== dict_index_get_n_unique_in_tree(index) + 1);
n_node_ptr_field = n_fields - 1;
break;
case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM:
ut_ad(n_fields == 1);
n_node_ptr_field = ULINT_UNDEFINED;
break;
default:
ut_error;
return;
}
} }
end = rec; end = rec;
nulls = rec - (extra + 1);
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable); lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
/* clear the SQL-null flags */ /* clear the SQL-null flags */
memset(lens + 1, 0, nulls - lens); memset(lens + 1, 0, nulls - lens);
...@@ -1162,6 +1217,10 @@ rec_convert_dtuple_to_rec_comp( ...@@ -1162,6 +1217,10 @@ rec_convert_dtuple_to_rec_comp(
ifield = dict_index_get_nth_field(index, i); ifield = dict_index_get_nth_field(index, i);
fixed_len = ifield->fixed_len; fixed_len = ifield->fixed_len;
if (temp && fixed_len
&& !dict_col_get_fixed_size(ifield->col, temp)) {
fixed_len = 0;
}
/* If the maximum length of a variable-length field /* If the maximum length of a variable-length field
is up to 255 bytes, the actual length is always stored is up to 255 bytes, the actual length is always stored
in one byte. If the maximum length is more than 255 in one byte. If the maximum length is more than 255
...@@ -1222,8 +1281,7 @@ rec_convert_dtuple_to_rec_new( ...@@ -1222,8 +1281,7 @@ rec_convert_dtuple_to_rec_new(
rec = buf + extra_size; rec = buf + extra_size;
rec_convert_dtuple_to_rec_comp( rec_convert_dtuple_to_rec_comp(
rec, REC_N_NEW_EXTRA_BYTES, index, status, rec, index, dtuple->fields, dtuple->n_fields, status, FALSE);
dtuple->fields, dtuple->n_fields);
/* Set the info bits of the record */ /* Set the info bits of the record */
rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple)); rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
...@@ -1285,6 +1343,54 @@ rec_convert_dtuple_to_rec( ...@@ -1285,6 +1343,54 @@ rec_convert_dtuple_to_rec(
return(rec); return(rec);
} }
#ifndef UNIV_HOTBACKUP
/**********************************************************//**
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
@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 */
{
return(rec_get_converted_size_comp_prefix_low(
index, fields, n_fields, extra, TRUE));
}
/******************************************************//**
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) */
{
rec_init_offsets_comp_ordinary(rec, TRUE, index, offsets);
}
/*********************************************************//**
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 */
{
rec_convert_dtuple_to_rec_comp(rec, index, fields, n_fields,
REC_STATUS_ORDINARY, TRUE);
}
/**************************************************************//** /**************************************************************//**
Copies the first n fields of a physical record to a data tuple. The fields Copies the first n fields of a physical record to a data tuple. The fields
are copied to the memory heap. */ are copied to the memory heap. */
...@@ -1495,6 +1601,7 @@ rec_copy_prefix_to_buf( ...@@ -1495,6 +1601,7 @@ rec_copy_prefix_to_buf(
return(*buf + (rec - (lens + 1))); return(*buf + (rec - (lens + 1)));
} }
#endif /* UNIV_HOTBACKUP */
/***************************************************************//** /***************************************************************//**
Validates the consistency of an old-style physical record. Validates the consistency of an old-style physical record.
......
...@@ -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,9 +599,8 @@ row_merge_buf_write( ...@@ -592,9 +599,8 @@ 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