Commit 1a0a9e6a authored by marko's avatar marko

branches/zip: Allow in-place updates of UTF-8 CHAR columns

from or to NULL in ROW_FORMAT=REDUNDANT. (Bug #44032)

rb://107 approved by Heikki Tuuri.
parent 50f3f5c8
2009-04-07 The InnoDB Team
* btr/btr0btr.c, dict/dict0dict.c, ibuf/ibuf0ibuf.c,
include/data0data.h, include/data0data.ic, include/data0type.h,
include/data0type.ic, include/dict0dict.h,
include/dict0dict.ic, include/rem0rec.ic,
mysql-test/innodb.result, mysql-test/innodb.test,
pars/pars0pars.c, rem/rem0rec.c, row/row0upd.c:
Fix Bug#44032 In ROW_FORMAT=REDUNDANT, update UTF-8 CHAR
to/from NULL is not in-place
2009-04-07 The InnoDB Team 2009-04-07 The InnoDB Team
* page/page0cur.c: * page/page0cur.c:
......
...@@ -3178,7 +3178,7 @@ btr_index_rec_validate( ...@@ -3178,7 +3178,7 @@ btr_index_rec_validate(
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
ulint fixed_size = dict_col_get_fixed_size( ulint fixed_size = dict_col_get_fixed_size(
dict_index_get_nth_col(index, i)); dict_index_get_nth_col(index, i), page_is_comp(page));
rec_get_nth_field_offs(offsets, i, &len); rec_get_nth_field_offs(offsets, i, &len);
......
...@@ -1252,7 +1252,8 @@ dict_index_too_big_for_undo( ...@@ -1252,7 +1252,8 @@ dict_index_too_big_for_undo(
ulint max_size ulint max_size
= dict_col_get_max_size(col); = dict_col_get_max_size(col);
ulint fixed_size ulint fixed_size
= dict_col_get_fixed_size(col); = dict_col_get_fixed_size(col,
dict_table_is_comp(table));
if (fixed_size) { if (fixed_size) {
/* Fixed-size columns are stored locally. */ /* Fixed-size columns are stored locally. */
...@@ -1382,7 +1383,7 @@ dict_index_too_big_for_tree( ...@@ -1382,7 +1383,7 @@ dict_index_too_big_for_tree(
case in rec_get_converted_size_comp() for case in rec_get_converted_size_comp() for
REC_STATUS_ORDINARY records. */ REC_STATUS_ORDINARY records. */
field_max_size = dict_col_get_fixed_size(col); field_max_size = dict_col_get_fixed_size(col, comp);
if (field_max_size) { if (field_max_size) {
/* dict_index_add_col() should guarantee this */ /* dict_index_add_col() should guarantee this */
ut_ad(!field->prefix_len ut_ad(!field->prefix_len
...@@ -1542,7 +1543,7 @@ too_big: ...@@ -1542,7 +1543,7 @@ too_big:
if (field->prefix_len /* prefix index */ if (field->prefix_len /* prefix index */
&& !col->ord_part /* not yet ordering column */ && !col->ord_part /* not yet ordering column */
&& !dict_col_get_fixed_size(col) /* variable-length */ && !dict_col_get_fixed_size(col, TRUE) /* variable-length */
&& dict_col_get_max_size(col) && dict_col_get_max_size(col)
> BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) { > BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
...@@ -1737,7 +1738,8 @@ dict_index_add_col( ...@@ -1737,7 +1738,8 @@ dict_index_add_col(
field = dict_index_get_nth_field(index, index->n_def - 1); field = dict_index_get_nth_field(index, index->n_def - 1);
field->col = col; field->col = col;
field->fixed_len = (unsigned int) dict_col_get_fixed_size(col); field->fixed_len = (unsigned int) dict_col_get_fixed_size(
col, dict_table_is_comp(table));
if (prefix_len && field->fixed_len > prefix_len) { if (prefix_len && field->fixed_len > prefix_len) {
field->fixed_len = (unsigned int) prefix_len; field->fixed_len = (unsigned int) prefix_len;
...@@ -1934,7 +1936,8 @@ dict_index_build_internal_clust( ...@@ -1934,7 +1936,8 @@ dict_index_build_internal_clust(
for (i = 0; i < trx_id_pos; i++) { for (i = 0; i < trx_id_pos; i++) {
fixed_size = dict_col_get_fixed_size( fixed_size = dict_col_get_fixed_size(
dict_index_get_nth_col(new_index, i)); dict_index_get_nth_col(new_index, i),
dict_table_is_comp(table));
if (fixed_size == 0) { if (fixed_size == 0) {
new_index->trx_id_offset = 0; new_index->trx_id_offset = 0;
...@@ -4070,14 +4073,15 @@ dict_index_calc_min_rec_len( ...@@ -4070,14 +4073,15 @@ dict_index_calc_min_rec_len(
{ {
ulint sum = 0; ulint sum = 0;
ulint i; ulint i;
ulint comp = dict_table_is_comp(index->table);
if (dict_table_is_comp(index->table)) { if (comp) {
ulint nullable = 0; ulint nullable = 0;
sum = REC_N_NEW_EXTRA_BYTES; sum = REC_N_NEW_EXTRA_BYTES;
for (i = 0; i < dict_index_get_n_fields(index); i++) { for (i = 0; i < dict_index_get_n_fields(index); i++) {
const dict_col_t* col const dict_col_t* col
= dict_index_get_nth_col(index, i); = dict_index_get_nth_col(index, i);
ulint size = dict_col_get_fixed_size(col); ulint size = dict_col_get_fixed_size(col, comp);
sum += size; sum += size;
if (!size) { if (!size) {
size = col->len; size = col->len;
...@@ -4096,7 +4100,7 @@ dict_index_calc_min_rec_len( ...@@ -4096,7 +4100,7 @@ dict_index_calc_min_rec_len(
for (i = 0; i < dict_index_get_n_fields(index); i++) { for (i = 0; i < dict_index_get_n_fields(index); i++) {
sum += dict_col_get_fixed_size( sum += dict_col_get_fixed_size(
dict_index_get_nth_col(index, i)); dict_index_get_nth_col(index, i), comp);
} }
if (sum > 127) { if (sum > 127) {
......
...@@ -1320,6 +1320,7 @@ ibuf_rec_get_volume( ...@@ -1320,6 +1320,7 @@ ibuf_rec_get_volume(
const byte* data; const byte* data;
ulint len; ulint len;
ulint i; ulint i;
ulint comp;
ut_ad(ibuf_inside()); ut_ad(ibuf_inside());
ut_ad(rec_get_n_fields_old(ibuf_rec) > 2); ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
...@@ -1337,6 +1338,7 @@ ibuf_rec_get_volume( ...@@ -1337,6 +1338,7 @@ ibuf_rec_get_volume(
types = rec_get_nth_field_old(ibuf_rec, 1, &len); types = rec_get_nth_field_old(ibuf_rec, 1, &len);
ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE); ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
comp = FALSE;
} else { } else {
/* >= 4.1.x format record */ /* >= 4.1.x format record */
...@@ -1345,8 +1347,10 @@ ibuf_rec_get_volume( ...@@ -1345,8 +1347,10 @@ ibuf_rec_get_volume(
types = rec_get_nth_field_old(ibuf_rec, 3, &len); types = rec_get_nth_field_old(ibuf_rec, 3, &len);
ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1); comp = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
ut_a(comp <= 1);
if (comp) {
/* compact record format */ /* compact record format */
ulint volume; ulint volume;
dict_index_t* dummy_index; dict_index_t* dummy_index;
...@@ -1380,7 +1384,7 @@ ibuf_rec_get_volume( ...@@ -1380,7 +1384,7 @@ ibuf_rec_get_volume(
} }
if (len == UNIV_SQL_NULL) { if (len == UNIV_SQL_NULL) {
data_size += dtype_get_sql_null_size(&dtype); data_size += dtype_get_sql_null_size(&dtype, comp);
} else { } else {
data_size += len; data_size += len;
} }
......
...@@ -277,7 +277,8 @@ ulint ...@@ -277,7 +277,8 @@ ulint
dtuple_get_data_size( dtuple_get_data_size(
/*=================*/ /*=================*/
/* out: sum of data lens */ /* out: sum of data lens */
const dtuple_t* tuple); /* in: typed data tuple */ const dtuple_t* tuple, /* in: typed data tuple */
ulint comp); /* in: nonzero=ROW_FORMAT=COMPACT */
/************************************************************************* /*************************************************************************
Computes the number of externally stored fields in a data tuple. */ Computes the number of externally stored fields in a data tuple. */
UNIV_INLINE UNIV_INLINE
......
...@@ -433,7 +433,8 @@ ulint ...@@ -433,7 +433,8 @@ ulint
dtuple_get_data_size( dtuple_get_data_size(
/*=================*/ /*=================*/
/* out: sum of data lengths */ /* out: sum of data lengths */
const dtuple_t* tuple) /* in: typed data tuple */ const dtuple_t* tuple, /* in: typed data tuple */
ulint comp) /* in: nonzero=ROW_FORMAT=COMPACT */
{ {
const dfield_t* field; const dfield_t* field;
ulint n_fields; ulint n_fields;
...@@ -452,7 +453,8 @@ dtuple_get_data_size( ...@@ -452,7 +453,8 @@ dtuple_get_data_size(
len = dfield_get_len(field); len = dfield_get_len(field);
if (len == UNIV_SQL_NULL) { if (len == UNIV_SQL_NULL) {
len = dtype_get_sql_null_size(dfield_get_type(field)); len = dtype_get_sql_null_size(dfield_get_type(field),
comp);
} }
sum += len; sum += len;
......
...@@ -352,7 +352,8 @@ dtype_get_fixed_size_low( ...@@ -352,7 +352,8 @@ dtype_get_fixed_size_low(
ulint prtype, /* in: precise type */ ulint prtype, /* in: precise type */
ulint len, /* in: length */ ulint len, /* in: length */
ulint mbminlen, /* in: minimum length of a multibyte char */ ulint mbminlen, /* in: minimum length of a multibyte char */
ulint mbmaxlen); /* in: maximum length of a multibyte char */ ulint mbmaxlen, /* in: maximum length of a multibyte char */
ulint comp); /* in: nonzero=ROW_FORMAT=COMPACT */
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/*************************************************************************** /***************************************************************************
Returns the minimum size of a data type. */ Returns the minimum size of a data type. */
...@@ -386,7 +387,8 @@ dtype_get_sql_null_size( ...@@ -386,7 +387,8 @@ dtype_get_sql_null_size(
/*====================*/ /*====================*/
/* out: SQL null storage size /* out: SQL null storage size
in ROW_FORMAT=REDUNDANT */ in ROW_FORMAT=REDUNDANT */
const dtype_t* type); /* in: type */ const dtype_t* type, /* in: type */
ulint comp); /* in: nonzero=ROW_FORMAT=COMPACT */
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/************************************************************************** /**************************************************************************
Reads to a type the stored information which determines its alphabetical Reads to a type the stored information which determines its alphabetical
......
...@@ -398,7 +398,8 @@ dtype_get_fixed_size_low( ...@@ -398,7 +398,8 @@ dtype_get_fixed_size_low(
ulint prtype, /* in: precise type */ ulint prtype, /* in: precise type */
ulint len, /* in: length */ ulint len, /* in: length */
ulint mbminlen, /* in: minimum length of a multibyte char */ ulint mbminlen, /* in: minimum length of a multibyte char */
ulint mbmaxlen) /* in: maximum length of a multibyte char */ ulint mbmaxlen, /* in: maximum length of a multibyte char */
ulint comp) /* in: nonzero=ROW_FORMAT=COMPACT */
{ {
switch (mtype) { switch (mtype) {
case DATA_SYS: case DATA_SYS:
...@@ -428,6 +429,8 @@ dtype_get_fixed_size_low( ...@@ -428,6 +429,8 @@ dtype_get_fixed_size_low(
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
if (prtype & DATA_BINARY_TYPE) { if (prtype & DATA_BINARY_TYPE) {
return(len); return(len);
} else if (!comp) {
return(len);
} else { } else {
/* We play it safe here and ask MySQL for /* We play it safe here and ask MySQL for
mbminlen and mbmaxlen. Although mbminlen and mbmaxlen. Although
...@@ -581,13 +584,14 @@ dtype_get_sql_null_size( ...@@ -581,13 +584,14 @@ dtype_get_sql_null_size(
/*====================*/ /*====================*/
/* out: SQL null storage size /* out: SQL null storage size
in ROW_FORMAT=REDUNDANT */ in ROW_FORMAT=REDUNDANT */
const dtype_t* type) /* in: type */ const dtype_t* type, /* in: type */
ulint comp) /* in: nonzero=ROW_FORMAT=COMPACT */
{ {
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len,
type->mbminlen, type->mbmaxlen)); type->mbminlen, type->mbmaxlen, comp));
#else /* !UNIV_HOTBACKUP */ #else /* !UNIV_HOTBACKUP */
return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len,
0, 0)); 0, 0, 0));
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
} }
...@@ -144,7 +144,8 @@ ulint ...@@ -144,7 +144,8 @@ ulint
dict_col_get_fixed_size( dict_col_get_fixed_size(
/*====================*/ /*====================*/
/* out: fixed size, or 0 */ /* out: fixed size, or 0 */
const dict_col_t* col); /* in: column */ const dict_col_t* col, /* in: column */
ulint comp); /* in: nonzero=ROW_FORMAT=COMPACT */
/*************************************************************************** /***************************************************************************
Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column. Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column.
For fixed length types it is the fixed length of the type, otherwise 0. */ For fixed length types it is the fixed length of the type, otherwise 0. */
...@@ -154,7 +155,8 @@ dict_col_get_sql_null_size( ...@@ -154,7 +155,8 @@ dict_col_get_sql_null_size(
/*=======================*/ /*=======================*/
/* out: SQL null storage size /* out: SQL null storage size
in ROW_FORMAT=REDUNDANT */ in ROW_FORMAT=REDUNDANT */
const dict_col_t* col); /* in: column */ const dict_col_t* col, /* in: column */
ulint comp); /* in: nonzero=ROW_FORMAT=COMPACT */
/************************************************************************* /*************************************************************************
Gets the column number. */ Gets the column number. */
......
...@@ -104,10 +104,11 @@ ulint ...@@ -104,10 +104,11 @@ ulint
dict_col_get_fixed_size( dict_col_get_fixed_size(
/*====================*/ /*====================*/
/* out: fixed size, or 0 */ /* out: fixed size, or 0 */
const dict_col_t* col) /* in: column */ const dict_col_t* col, /* in: column */
ulint comp) /* in: nonzero=ROW_FORMAT=COMPACT */
{ {
return(dtype_get_fixed_size_low(col->mtype, col->prtype, col->len, return(dtype_get_fixed_size_low(col->mtype, col->prtype, col->len,
col->mbminlen, col->mbmaxlen)); col->mbminlen, col->mbmaxlen, comp));
} }
/*************************************************************************** /***************************************************************************
Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column. Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column.
...@@ -118,9 +119,10 @@ dict_col_get_sql_null_size( ...@@ -118,9 +119,10 @@ dict_col_get_sql_null_size(
/*=======================*/ /*=======================*/
/* out: SQL null storage size /* out: SQL null storage size
in ROW_FORMAT=REDUNDANT */ in ROW_FORMAT=REDUNDANT */
const dict_col_t* col) /* in: column */ const dict_col_t* col, /* in: column */
ulint comp) /* in: nonzero=ROW_FORMAT=COMPACT */
{ {
return(dict_col_get_fixed_size(col)); return(dict_col_get_fixed_size(col, comp));
} }
/************************************************************************* /*************************************************************************
......
...@@ -1577,7 +1577,7 @@ rec_get_converted_size( ...@@ -1577,7 +1577,7 @@ rec_get_converted_size(
dtuple->n_fields, NULL)); dtuple->n_fields, NULL));
} }
data_size = dtuple_get_data_size(dtuple); data_size = dtuple_get_data_size(dtuple, 0);
extra_size = rec_get_converted_extra_size( extra_size = rec_get_converted_extra_size(
data_size, dtuple_get_n_fields(dtuple), n_ext); data_size, dtuple_get_n_fields(dtuple), n_ext);
......
...@@ -3306,3 +3306,10 @@ Variable_name Value ...@@ -3306,3 +3306,10 @@ Variable_name Value
Handler_update 1 Handler_update 1
Variable_name Value Variable_name Value
Handler_delete 1 Handler_delete 1
CREATE TABLE t1(c CHAR(3) CHARACTER SET UTF8) ROW_FORMAT=REDUNDANT
ENGINE=InnoDB;
INSERT INTO t1 VALUES('abc'),(0xEFBCA4EFBCA4EFBCA4);
UPDATE t1 SET c='DDD' WHERE c=0xEFBCA4EFBCA4EFBCA4;
UPDATE t1 SET c=NULL WHERE c='DDD';
UPDATE t1 SET c='DDD' WHERE c IS NULL;
DROP TABLE t1;
...@@ -2524,6 +2524,19 @@ DROP TABLE bug35537; ...@@ -2524,6 +2524,19 @@ DROP TABLE bug35537;
DISCONNECT c1; DISCONNECT c1;
CONNECTION default; CONNECTION default;
-- enable_query_log
# Bug : no update-in-place of UTF-8 columns in ROW_FORMAT=REDUNDANT
# (btr_cur_update_in_place not invoked when updating from/to NULL;
# the update is performed by delete and insert instead)
CREATE TABLE t1(c CHAR(3) CHARACTER SET UTF8) ROW_FORMAT=REDUNDANT
ENGINE=InnoDB;
INSERT INTO t1 VALUES('abc'),(0xEFBCA4EFBCA4EFBCA4);
UPDATE t1 SET c='DDD' WHERE c=0xEFBCA4EFBCA4EFBCA4;
UPDATE t1 SET c=NULL WHERE c='DDD';
UPDATE t1 SET c='DDD' WHERE c IS NULL;
DROP TABLE t1;
####################################################################### #######################################################################
# # # #
# Please, DO NOT TOUCH this file as well as the innodb.result file. # # Please, DO NOT TOUCH this file as well as the innodb.result file. #
......
...@@ -945,7 +945,8 @@ pars_process_assign_list( ...@@ -945,7 +945,8 @@ pars_process_assign_list(
if (!dict_col_get_fixed_size( if (!dict_col_get_fixed_size(
dict_index_get_nth_col(clust_index, dict_index_get_nth_col(clust_index,
upd_field->field_no))) { upd_field->field_no),
dict_table_is_comp(node->table))) {
changes_field_size = 0; changes_field_size = 0;
} }
......
...@@ -949,7 +949,7 @@ rec_convert_dtuple_to_rec_old( ...@@ -949,7 +949,7 @@ rec_convert_dtuple_to_rec_old(
ut_ad(dtuple_check_typed(dtuple)); ut_ad(dtuple_check_typed(dtuple));
n_fields = dtuple_get_n_fields(dtuple); n_fields = dtuple_get_n_fields(dtuple);
data_size = dtuple_get_data_size(dtuple); data_size = dtuple_get_data_size(dtuple, FALSE);
ut_ad(n_fields > 0); ut_ad(n_fields > 0);
...@@ -982,7 +982,7 @@ rec_convert_dtuple_to_rec_old( ...@@ -982,7 +982,7 @@ rec_convert_dtuple_to_rec_old(
if (dfield_is_null(field)) { if (dfield_is_null(field)) {
len = dtype_get_sql_null_size( len = dtype_get_sql_null_size(
dfield_get_type(field)); dfield_get_type(field), FALSE);
data_write_sql_null(rec + end_offset, len); data_write_sql_null(rec + end_offset, len);
end_offset += len; end_offset += len;
...@@ -1010,7 +1010,7 @@ rec_convert_dtuple_to_rec_old( ...@@ -1010,7 +1010,7 @@ rec_convert_dtuple_to_rec_old(
if (dfield_is_null(field)) { if (dfield_is_null(field)) {
len = dtype_get_sql_null_size( len = dtype_get_sql_null_size(
dfield_get_type(field)); dfield_get_type(field), FALSE);
data_write_sql_null(rec + end_offset, len); data_write_sql_null(rec + end_offset, len);
end_offset += len; end_offset += len;
......
...@@ -422,7 +422,8 @@ row_upd_changes_field_size_or_external( ...@@ -422,7 +422,8 @@ row_upd_changes_field_size_or_external(
new_len = dict_col_get_sql_null_size( new_len = dict_col_get_sql_null_size(
dict_index_get_nth_col(index, dict_index_get_nth_col(index,
upd_field->field_no)); upd_field->field_no),
FALSE);
} }
old_len = rec_offs_nth_size(offsets, upd_field->field_no); old_len = rec_offs_nth_size(offsets, upd_field->field_no);
......
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