diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-01-28 16:43:58 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-01-28 16:43:58 +0200 |
commit | e5737c8800f7533c97ec3b91331d14d9d4705a5c (patch) | |
tree | 774c1567feae60e76ec7474ca2cb1ea970cb14c6 | |
parent | 27139b727bc6f80ab2a882e50c3efac03f1f70c4 (diff) | |
parent | f8ad271dec770bef59dafbfda0f8cad78c3c1aa0 (diff) | |
download | mariadb-git-bb-10.4-MDEV-15563.tar.gz |
Merge branch 'midenok/555/conversion3' of https://github.com/tempesta-tech/mariadb into HEADbb-10.4-MDEV-15563
22 files changed, 854 insertions, 93 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter_convert,utf8.rdiff b/mysql-test/suite/innodb/r/instant_alter_convert,utf8.rdiff new file mode 100644 index 00000000000..5639ed0a532 --- /dev/null +++ b/mysql-test/suite/innodb/r/instant_alter_convert,utf8.rdiff @@ -0,0 +1,38 @@ +--- ./mysql-test/suite/innodb/r/instant_alter_convert.result 2019-01-17 12:50:12.929502797 +0300 ++++ ./mysql-test/suite/innodb/r/instant_alter_convert,utf8.reject 2019-01-17 13:23:48.517440727 +0300 +@@ -25,7 +25,7 @@ + test.t check status OK + call check_table('t'); + name mtype prtype len +-a 1 8100F 300 ++a 12 21100F 900 + # Case 2: VARCHAR -> CHAR, VARBINARY -> BINARY conversion + set @bigval= repeat('0123456789', 20); + create or replace table t (a varchar(300)) row_format=redundant; +@@ -47,7 +47,7 @@ + test.t check status OK + call check_table('t'); + name mtype prtype len +-a 2 800FE 200 ++a 13 2100FE 600 + # CHAR enlargement + alter table t modify a char(220), algorithm=instant; + select count(a) from t where a = @bigval; +@@ -61,7 +61,7 @@ + test.t check status OK + call check_table('t'); + name mtype prtype len +-a 2 800FE 220 ++a 13 2100FE 660 + # Convert from VARCHAR to a bigger CHAR + alter table t modify a varchar(200), algorithm=instant; + ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY +@@ -82,7 +82,7 @@ + test.t check status OK + call check_table('t'); + name mtype prtype len +-a 2 800FE 255 ++a 13 2100FE 765 + # BINARY/VARBINARY test + create or replace table t (a varbinary(300)) row_format=redundant; + alter table t modify a binary(255), algorithm=instant; diff --git a/mysql-test/suite/innodb/r/instant_alter_convert.result b/mysql-test/suite/innodb/r/instant_alter_convert.result new file mode 100644 index 00000000000..83f78c0b2b5 --- /dev/null +++ b/mysql-test/suite/innodb/r/instant_alter_convert.result @@ -0,0 +1,306 @@ +create or replace database test; +use test; +set default_storage_engine=innodb; +set @bigval= repeat('0123456789', 30); +create or replace procedure check_table(table_name varchar(255)) +begin +select table_id into @table_id +from information_schema.innodb_sys_tables +where name = concat('test/', table_name); +select name, mtype, hex(prtype) as prtype, len +from information_schema.innodb_sys_columns +where table_id = @table_id; +end~~ +# Case 1: VARCHAR(<255) -> VARCHAR(>255) conversion +create or replace table t (a varchar(2)) row_format=redundant; +alter table t modify a varchar(300), algorithm=instant; +insert into t values (@bigval); +select count(a) from t where a = @bigval; +count(a) +1 +insert into t values (repeat('X', 301)); +ERROR 22001: Data too long for column 'a' at row 1 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +a 1 8100F 300 +# Case 2: VARCHAR -> CHAR, VARBINARY -> BINARY conversion +set @bigval= repeat('0123456789', 20); +create or replace table t (a varchar(300)) row_format=redundant; +alter table t modify a char(255), algorithm=instant; +ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY +alter table t modify a char(255), algorithm=copy; +create or replace table t (a varchar(200)) row_format=redundant; +insert into t values (@bigval); +insert into t values ('z'); +alter table t modify a char(200), algorithm=instant; +select count(a) from t where a = @bigval; +count(a) +1 +select a, length(a) from t where a = 'z'; +a length(a) +z 1 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +a 2 800FE 200 +# CHAR enlargement +alter table t modify a char(220), algorithm=instant; +select count(a) from t where a = @bigval; +count(a) +1 +select a, length(a) from t where a = 'z'; +a length(a) +z 1 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +a 2 800FE 220 +# Convert from VARCHAR to a bigger CHAR +alter table t modify a varchar(200), algorithm=instant; +ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY +alter table t modify a varchar(200), algorithm=copy; +alter table t modify a char(255), algorithm=instant; +select count(a) from t where a = @bigval; +count(a) +1 +select a, length(a) from t where a = 'z'; +a length(a) +z 1 +select * from t; +a +01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +z +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +a 2 800FE 255 +# BINARY/VARBINARY test +create or replace table t (a varbinary(300)) row_format=redundant; +alter table t modify a binary(255), algorithm=instant; +ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY +alter table t modify a binary(255), algorithm=copy; +create or replace table t (a varbinary(200)) row_format=redundant; +insert into t values (@bigval); +insert into t values ('z'); +alter table t modify a binary(200), algorithm=instant; +select count(a) from t where a = @bigval; +count(a) +1 +select length(a) from t where left(a, 1) = 'z'; +length(a) +200 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +a 3 3F04FE 200 +# BINARY enlargement +alter table t modify a binary(220), algorithm=instant; +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +a 3 3F04FE 220 +# Convert from VARBINARY to a bigger BINARY +alter table t modify a varbinary(220), algorithm=instant; +ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY +alter table t modify a varbinary(220), algorithm=copy; +alter table t modify a binary(255), algorithm=instant; +select count(a) from t where a = @bigval; +count(a) +0 +select a, length(a) from t where a = 'z'; +a length(a) +select * from t; +a +01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +z +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +a 3 3F04FE 255 +# Case 3: integer conversions +create or replace table t (x tinyint) row_format=redundant; +insert into t values (127); +alter table t modify x smallint, algorithm=instant; +select * from t; +x +127 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +x 6 402 2 +update t set x= 32767; +alter table t modify x mediumint, algorithm=instant; +select * from t; +x +32767 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +x 6 409 3 +update t set x= 8388607; +alter table t modify x int, algorithm=instant; +select * from t; +x +8388607 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +x 6 403 4 +update t set x= 2147483647; +alter table t modify x bigint, algorithm=instant; +select * from t; +x +2147483647 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +x 6 408 8 +# Check IMPORT TABLESPACE +create or replace table t2 (x int) row_format redundant; +alter table t2 discard tablespace; +create or replace table t1 (x tinyint) row_format redundant; +insert into t1 set x= 42; +alter table t1 modify x int; +flush tables t1 for export; +unlock tables; +alter table t2 import tablespace; +select * from t2; +x +42 +check table t2 extended; +Table Op Msg_type Msg_text +test.t2 check status OK +call check_table('t2'); +name mtype prtype len +x 6 403 4 +# Case 4: instant conversion unsigned -> signed +create or replace table t(x int) row_format=redundant; +alter table t modify x int unsigned, algorithm=instant; +ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY +alter table t modify x bigint unsigned, algorithm=instant; +ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY +create or replace table t(x tinyint unsigned) row_format=redundant; +insert into t values (255); +alter table t modify x smallint unsigned, algorithm=instant; +insert into t values (255); +select * from t; +x +255 +255 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +x 6 602 2 +alter table t modify x mediumint, algorithm=instant; +insert into t values (255); +select * from t; +x +255 +255 +255 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +x 6 409 3 +alter table t modify x int, algorithm=instant; +insert into t values (255); +select * from t; +x +255 +255 +255 +255 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +x 6 403 4 +alter table t modify x bigint, algorithm=instant; +insert into t values (255); +select * from t; +x +255 +255 +255 +255 +255 +check table t extended; +Table Op Msg_type Msg_text +test.t check status OK +call check_table('t'); +name mtype prtype len +x 6 408 8 +# Check innobase_col_to_mysql() len < flen +create or replace table t1 (x mediumint) row_format=redundant; +insert into t1 values (1); +insert into t1 values (1); +alter table t1 add column y int first, modify x int, algorithm instant; +alter table t1 add column z int first, add primary key (x); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +# Check assertion in wrong instant operation +create or replace table t1 (a varchar(26) not null) default character set utf8mb4 row_format=redundant; +alter table t1 modify a varchar(25) not null; +# Check row_mysql_store_col_in_innobase_format() +create or replace table t1(x int primary key, a varchar(20)) row_format=redundant; +insert into t1 (x) values (1); +update t1 set a= 'foo' where x = 2; +# +# MDEV-18124 PK on inplace-enlarged type fails +# +create or replace table t1 (x int, y int) row_format redundant; +insert into t1 (x, y) values (11, 22); +alter table t1 modify x bigint, algorithm instant; +alter table t1 add primary key (x), algorithm inplace; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +create or replace table t1 (a varchar(10), y int) row_format redundant; +insert into t1 (a, y) values ("0123456789", 33); +alter table t1 modify a char(15), algorithm instant; +alter table t1 add primary key (a), algorithm inplace; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +create or replace table t1 (x int primary key, y int) row_format redundant; +insert into t1 (x, y) values (44, 55); +alter table t1 modify x bigint, algorithm inplace; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +create or replace table t1 (x int primary key, y int) row_format redundant; +insert into t1 values (66, 77); +alter table t1 add column z int, algorithm instant; +alter table t1 drop column y, algorithm instant; +create or replace table t1 (x integer, a varchar(20)) row_format redundant; +alter table t1 add index idx3 (a); +insert into t1 (x, a) values (73, 'a'); +alter table t1 modify a char(20); +create or replace database test charset latin1; diff --git a/mysql-test/suite/innodb/t/instant_alter_convert.combinations b/mysql-test/suite/innodb/t/instant_alter_convert.combinations new file mode 100644 index 00000000000..1465bf59ad7 --- /dev/null +++ b/mysql-test/suite/innodb/t/instant_alter_convert.combinations @@ -0,0 +1,5 @@ +[latin1] +character-set-server=latin1 + +[utf8] +character-set-server=utf8 diff --git a/mysql-test/suite/innodb/t/instant_alter_convert.test b/mysql-test/suite/innodb/t/instant_alter_convert.test new file mode 100644 index 00000000000..3a7ab92cad6 --- /dev/null +++ b/mysql-test/suite/innodb/t/instant_alter_convert.test @@ -0,0 +1,275 @@ +--source include/have_innodb.inc +--source include/maybe_debug.inc + +# Use character-set-server in test db +create or replace database test; +use test; + +set default_storage_engine=innodb; +set @bigval= repeat('0123456789', 30); + +delimiter ~~; +create or replace procedure check_table(table_name varchar(255)) +begin + select table_id into @table_id + from information_schema.innodb_sys_tables + where name = concat('test/', table_name); + select name, mtype, hex(prtype) as prtype, len + from information_schema.innodb_sys_columns + where table_id = @table_id; +end~~ +delimiter ;~~ + + +--echo # Case 1: VARCHAR(<255) -> VARCHAR(>255) conversion +create or replace table t (a varchar(2)) row_format=redundant; +if ($have_debug) { +--disable_query_log +--disable_result_log +set debug_dbug= '+d,ib_instant_error'; +--error ER_RECORD_FILE_FULL +alter table t modify a varchar(300); +set debug_dbug= default; +--enable_query_log +--enable_result_log +} +alter table t modify a varchar(300), algorithm=instant; +insert into t values (@bigval); +select count(a) from t where a = @bigval; +--error ER_DATA_TOO_LONG +insert into t values (repeat('X', 301)); + +check table t extended; +call check_table('t'); + + +--echo # Case 2: VARCHAR -> CHAR, VARBINARY -> BINARY conversion +set @bigval= repeat('0123456789', 20); + +create or replace table t (a varchar(300)) row_format=redundant; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +alter table t modify a char(255), algorithm=instant; +alter table t modify a char(255), algorithm=copy; + +create or replace table t (a varchar(200)) row_format=redundant; +if ($have_debug) { +--disable_query_log +--disable_result_log +set debug_dbug= '+d,ib_instant_error'; +--error ER_RECORD_FILE_FULL +alter table t modify a char(200); +set debug_dbug= default; +--enable_query_log +--enable_result_log +} +insert into t values (@bigval); +insert into t values ('z'); +alter table t modify a char(200), algorithm=instant; +select count(a) from t where a = @bigval; +select a, length(a) from t where a = 'z'; + +check table t extended; +call check_table('t'); + +--echo # CHAR enlargement +alter table t modify a char(220), algorithm=instant; +select count(a) from t where a = @bigval; +select a, length(a) from t where a = 'z'; + +check table t extended; +call check_table('t'); + +--echo # Convert from VARCHAR to a bigger CHAR +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +alter table t modify a varchar(200), algorithm=instant; +alter table t modify a varchar(200), algorithm=copy; +alter table t modify a char(255), algorithm=instant; +select count(a) from t where a = @bigval; +select a, length(a) from t where a = 'z'; + +select * from t; +check table t extended; +call check_table('t'); + +--echo # BINARY/VARBINARY test +create or replace table t (a varbinary(300)) row_format=redundant; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +alter table t modify a binary(255), algorithm=instant; +alter table t modify a binary(255), algorithm=copy; + +create or replace table t (a varbinary(200)) row_format=redundant; +if ($have_debug) { +--disable_query_log +--disable_result_log +set debug_dbug= '+d,ib_instant_error'; +--error ER_RECORD_FILE_FULL +alter table t modify a binary(200); +set debug_dbug= default; +--enable_query_log +--enable_result_log +} +insert into t values (@bigval); +insert into t values ('z'); +alter table t modify a binary(200), algorithm=instant; +select count(a) from t where a = @bigval; +select length(a) from t where left(a, 1) = 'z'; + +check table t extended; +call check_table('t'); + +--echo # BINARY enlargement +alter table t modify a binary(220), algorithm=instant; + +check table t extended; +call check_table('t'); + +--echo # Convert from VARBINARY to a bigger BINARY +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +alter table t modify a varbinary(220), algorithm=instant; +alter table t modify a varbinary(220), algorithm=copy; +alter table t modify a binary(255), algorithm=instant; +select count(a) from t where a = @bigval; +select a, length(a) from t where a = 'z'; + +select * from t; +check table t extended; +call check_table('t'); + + +--echo # Case 3: integer conversions +create or replace table t (x tinyint) row_format=redundant; +if ($have_debug) { +--disable_query_log +--disable_result_log +set debug_dbug= '+d,ib_instant_error'; +--error ER_RECORD_FILE_FULL +alter table t modify x smallint; +set debug_dbug= default; +--enable_query_log +--enable_result_log +} +insert into t values (127); +alter table t modify x smallint, algorithm=instant; +select * from t; +check table t extended; +call check_table('t'); + +update t set x= 32767; +alter table t modify x mediumint, algorithm=instant; +select * from t; +check table t extended; +call check_table('t'); + +update t set x= 8388607; +alter table t modify x int, algorithm=instant; +select * from t; +check table t extended; +call check_table('t'); + +update t set x= 2147483647; +alter table t modify x bigint, algorithm=instant; +select * from t; +check table t extended; +call check_table('t'); + +--echo # Check IMPORT TABLESPACE +--let $MYSQLD_DATADIR= `select @@datadir` +create or replace table t2 (x int) row_format redundant; +alter table t2 discard tablespace; + +create or replace table t1 (x tinyint) row_format redundant; +insert into t1 set x= 42; +alter table t1 modify x int; +flush tables t1 for export; +--move_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/t2.cfg +--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd +unlock tables; + +alter table t2 import tablespace; + +select * from t2; +check table t2 extended; +call check_table('t2'); + +--echo # Case 4: instant conversion unsigned -> signed +create or replace table t(x int) row_format=redundant; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +alter table t modify x int unsigned, algorithm=instant; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +alter table t modify x bigint unsigned, algorithm=instant; + +create or replace table t(x tinyint unsigned) row_format=redundant; +insert into t values (255); + +alter table t modify x smallint unsigned, algorithm=instant; +insert into t values (255); +select * from t; +check table t extended; +call check_table('t'); + +alter table t modify x mediumint, algorithm=instant; +insert into t values (255); +select * from t; +check table t extended; +call check_table('t'); + +alter table t modify x int, algorithm=instant; +insert into t values (255); +select * from t; +check table t extended; +call check_table('t'); + +alter table t modify x bigint, algorithm=instant; +insert into t values (255); +select * from t; +check table t extended; +call check_table('t'); + +--echo # Check innobase_col_to_mysql() len < flen +create or replace table t1 (x mediumint) row_format=redundant; +insert into t1 values (1); +insert into t1 values (1); +alter table t1 add column y int first, modify x int, algorithm instant; +--error ER_DUP_ENTRY +alter table t1 add column z int first, add primary key (x); + +--echo # Check assertion in wrong instant operation +create or replace table t1 (a varchar(26) not null) default character set utf8mb4 row_format=redundant; +alter table t1 modify a varchar(25) not null; + +--echo # Check row_mysql_store_col_in_innobase_format() +create or replace table t1(x int primary key, a varchar(20)) row_format=redundant; +insert into t1 (x) values (1); +update t1 set a= 'foo' where x = 2; + +--echo # +--echo # MDEV-18124 PK on inplace-enlarged type fails +--echo # +create or replace table t1 (x int, y int) row_format redundant; +insert into t1 (x, y) values (11, 22); +alter table t1 modify x bigint, algorithm instant; +alter table t1 add primary key (x), algorithm inplace; +check table t1; + +create or replace table t1 (a varchar(10), y int) row_format redundant; +insert into t1 (a, y) values ("0123456789", 33); +alter table t1 modify a char(15), algorithm instant; +alter table t1 add primary key (a), algorithm inplace; +check table t1; + +create or replace table t1 (x int primary key, y int) row_format redundant; +insert into t1 (x, y) values (44, 55); +alter table t1 modify x bigint, algorithm inplace; +check table t1; + +create or replace table t1 (x int primary key, y int) row_format redundant; +insert into t1 values (66, 77); +alter table t1 add column z int, algorithm instant; +alter table t1 drop column y, algorithm instant; + +create or replace table t1 (x integer, a varchar(20)) row_format redundant; +alter table t1 add index idx3 (a); +insert into t1 (x, a) values (73, 'a'); +alter table t1 modify a char(20); + +create or replace database test charset latin1; diff --git a/sql/field.cc b/sql/field.cc index dd125a06bad..b2cc721c258 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7063,9 +7063,16 @@ uint Field::is_equal(Create_field *new_field) uint Field_str::is_equal(Create_field *new_field) { - return new_field->type_handler() == type_handler() && - new_field->charset == field_charset && - new_field->length == max_display_length(); + if (new_field->type_handler() == type_handler() && + new_field->charset == field_charset) + { + if (new_field->length == max_display_length()) + return IS_EQUAL_YES; + if (new_field->length > max_display_length() && + (table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION)) + return IS_EQUAL_PACK_LENGTH; + } + return IS_EQUAL_NO; } @@ -7901,16 +7908,26 @@ Field *Field_varstring::new_key_field(MEM_ROOT *root, TABLE *new_table, uint Field_varstring::is_equal(Create_field *new_field) { - if (new_field->type_handler() == type_handler() && - new_field->charset == field_charset && + if (new_field->charset == field_charset && !new_field->compression_method() == !compression_method()) { - if (new_field->length == field_length) - return IS_EQUAL_YES; - if (new_field->length > field_length && - ((new_field->length <= 255 && field_length <= 255) || - (new_field->length > 255 && field_length > 255))) - return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length + bool extended= (table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION); + if (extended && new_field->type_handler() == &type_handler_string && + new_field->length >= field_length) + { + return IS_EQUAL_PACK_LENGTH; + } + if (new_field->type_handler() == type_handler()) + { + if (new_field->length == field_length) + return IS_EQUAL_YES; + if (new_field->length > field_length) + { + if (extended || (new_field->length <= 255 && field_length <= 255) || + (new_field->length > 255 && field_length > 255)) + return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length + } + } } return IS_EQUAL_NO; } @@ -9480,12 +9497,21 @@ bool Field_num::eq_def(const Field *field) const uint Field_num::is_equal(Create_field *new_field) { - return ((new_field->type_handler() == type_handler()) && - ((new_field->flags & UNSIGNED_FLAG) == - (uint) (flags & UNSIGNED_FLAG)) && - ((new_field->flags & AUTO_INCREMENT_FLAG) == - (uint) (flags & AUTO_INCREMENT_FLAG)) && - (new_field->pack_length == pack_length())); + bool extended= (table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION); + bool signed_equal= ((new_field->flags & UNSIGNED_FLAG) == + (uint) (flags & UNSIGNED_FLAG)); + if ((extended ? + new_field->type_handler()->result_type() == type_handler()->result_type() : + new_field->type_handler() == type_handler()) && + ((new_field->flags & AUTO_INCREMENT_FLAG) == (uint) (flags & AUTO_INCREMENT_FLAG))) + { + if (signed_equal && new_field->pack_length == pack_length()) + return IS_EQUAL_YES; + if (extended && new_field->pack_length > pack_length() && + (signed_equal || !(new_field->flags & UNSIGNED_FLAG))) + return IS_EQUAL_PACK_LENGTH; + } + return IS_EQUAL_NO; } diff --git a/sql/field.h b/sql/field.h index e762e45c024..25d9f0e0ca4 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4564,7 +4564,7 @@ public: :Type_handler_hybrid_field_type(&type_handler_null), compression_method_ptr(0), comment(null_clex_str), - on_update(NULL), invisible(VISIBLE), decimals(0), + on_update(NULL), invisible(VISIBLE), char_length(0), decimals(0), flags(0), pack_length(0), key_length(0), option_list(NULL), vcol_info(0), default_value(0), check_constraint(0), diff --git a/sql/handler.cc b/sql/handler.cc index 1b5aaebe3cf..d1fa5aff58e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4684,7 +4684,6 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table, DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); alter_table_operations inplace_offline_operations= - ALTER_COLUMN_EQUAL_PACK_LENGTH | ALTER_COLUMN_NAME | ALTER_RENAME_COLUMN | ALTER_CHANGE_COLUMN_DEFAULT | diff --git a/sql/handler.h b/sql/handler.h index f5a7051a4e2..89a852670be 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -319,6 +319,9 @@ enum enum_alter_inplace_result { /* Safe for online backup */ #define HA_CAN_ONLINE_BACKUPS (1ULL << 56) +#define HA_EXTENDED_TYPES_CONVERSION (1ULL << 57) +#define HA_LAST_TABLE_FLAG HA_EXTENDED_TYPES_CONVERSION + /* bits in index_flags(index_number) for what you can do with index */ #define HA_READ_NEXT 1 /* TODO really use this flag */ #define HA_READ_PREV 2 /* supports ::index_prev */ @@ -3135,7 +3138,11 @@ public: /** The cached_table_flags is set at ha_open and ha_external_lock */ - Table_flags ha_table_flags() const { return cached_table_flags; } + Table_flags ha_table_flags() const + { + DBUG_ASSERT(cached_table_flags < (HA_LAST_TABLE_FLAG << 1)); + return cached_table_flags; + } /** These functions represent the public interface to *users* of the handler class, hence they are *not* virtual. For the inheritance diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 1ac93de4800..be34d2dbe8d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9431,6 +9431,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, DBUG_RETURN(true); } + DBUG_PRINT("info", ("Using fast alter parition")); // In-place execution of ALTER TABLE for partitioning. DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info, create_info, table_list, @@ -9582,6 +9583,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, if (alter_info->requested_algorithm != Alter_info::ALTER_TABLE_ALGORITHM_COPY) { + DBUG_PRINT("alter", ("Requested algorithm: %d", alter_info->requested_algorithm)); Alter_inplace_info ha_alter_info(create_info, alter_info, key_info, key_count, IF_PARTITIONING(thd->work_part_info, NULL), @@ -9682,6 +9684,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, if (use_inplace) { + DBUG_PRINT("alter", ("Using INPLACE alter")); table->s->frm_image= &frm; enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; /* @@ -9707,6 +9710,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, } /* ALTER TABLE using copy algorithm. */ + DBUG_PRINT("alter", ("Using COPY alter")); /* Check if ALTER TABLE is compatible with foreign key definitions. */ if (fk_prepare_copy_alter_table(thd, table, alter_info, &alter_ctx)) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 1b3ea2eb487..74c9d6fe2e8 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -4844,7 +4844,9 @@ n_field_mismatch: if (len_is_stored(len) && (field->prefix_len ? len > field->prefix_len - : (fixed_size && len != fixed_size))) { + : (fixed_size && (page_is_comp(page) + ? len != fixed_size + : len > fixed_size)))) { len_mismatch: btr_index_rec_validate_report(page, rec, index); ib::error error; diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index f4cbb4e51a3..590e89cff7d 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -485,8 +485,14 @@ incompatible: For the metadata record, variable-length columns are always written with zero length. The DB_TRX_ID will start right after any fixed-length columns. */ - for (uint i = index->n_uniq; i--; ) { - trx_id_offset += index->fields[i].fixed_len; + if (index->table->not_redundant()) { + for (uint i = index->n_uniq; i--; ) { + trx_id_offset += index->fields[i] + .fixed_len; + } + } else { + trx_id_offset = rec_get_field_start_offs( + rec, index->n_uniq); } } diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 4ea5a5b30e9..b17a05e38ff 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -650,6 +650,9 @@ const char* dict_col_t::name(const dict_table_t& table) const } if (s) { + /* midenok: isn't it strange to use serialized array in memory? + TODO: Refactor to member dict_col_t::name, serialize only when + required. */ for (size_t i = 0; i < col_nr; i++) { s += strlen(s) + 1; } @@ -2204,6 +2207,14 @@ dict_index_too_big_for_tree( } field_max_size = dict_col_get_max_size(col); + if (!comp && (col->mtype == DATA_INT + || col->mtype == DATA_CHAR + || col->mtype == DATA_FIXBINARY)) { + /* DATA_INT, DATA_FIXBINARY and DATA_CHAR are variable- + length (enlarged instantly), but are stored locally. */ + field_ext_max_size = 0; + goto add_field_size; + } field_ext_max_size = field_max_size < 256 ? 1 : 2; if (field->prefix_len) { diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 3d373bf37d8..94070aeefdd 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -714,6 +714,7 @@ dict_mem_fill_column_struct( dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen); column->mbminlen = mbminlen; column->mbmaxlen = mbmaxlen; + column->unsigned_len = 0; column->def_val.data = NULL; column->def_val.len = UNIV_SQL_DEFAULT; ut_ad(!column->is_dropped()); @@ -1217,6 +1218,7 @@ inline void dict_index_t::reconstruct_fields() n_nullable++; n_core_null += i <= n_core_fields; } + f.col->unsigned_len = c.unsigned_len(); } fields = tfields; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 683a6417747..f94c9269726 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6110,6 +6110,11 @@ no_such_table: DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); } + if (!ib_table->not_redundant()) { + m_int_table_flags |= HA_EXTENDED_TYPES_CONVERSION; + cached_table_flags |= HA_EXTENDED_TYPES_CONVERSION; + } + size_t n_fields = omits_virtual_cols(*table_share) ? table_share->stored_fields : table_share->fields; size_t n_cols = dict_table_get_n_user_cols(ib_table) @@ -9951,7 +9956,7 @@ innobase_fts_create_doc_id_key( /* The unique Doc ID field should be an eight-bytes integer */ dict_field_t* field = dict_index_get_nth_field(index, 0); ut_a(field->col->mtype == DATA_INT); - ut_ad(sizeof(*doc_id) == field->fixed_len); + ut_ad(sizeof(*doc_id) == field->col->len); ut_ad(!strcmp(index->name, FTS_DOC_ID_INDEX_NAME)); #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index cf24a4df8a9..4d9244f858f 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -84,6 +84,7 @@ static const alter_table_operations INNOBASE_ALTER_REBUILD | ALTER_OPTIONS /* ALTER_OPTIONS needs to check alter_options_need_rebuild() */ | ALTER_COLUMN_NULLABLE + | ALTER_COLUMN_EQUAL_PACK_LENGTH | INNOBASE_DEFAULTS | ALTER_STORED_COLUMN_ORDER | ALTER_DROP_STORED_COLUMN @@ -132,7 +133,6 @@ static const alter_table_operations INNOBASE_ALTER_INSTANT #endif | ALTER_ADD_VIRTUAL_COLUMN | INNOBASE_FOREIGN_OPERATIONS - | ALTER_COLUMN_EQUAL_PACK_LENGTH | ALTER_COLUMN_UNVERSIONED | ALTER_DROP_VIRTUAL_COLUMN; @@ -182,12 +182,16 @@ inline void dict_table_t::init_instant(const dict_table_t& table) ut_d(unsigned n_nullable = 0); for (unsigned i = u; i < index.n_fields; i++) { auto& f = index.fields[i]; + /* FIXME: CHAR of arbitrary size is now allowed. */ DBUG_ASSERT(dict_col_get_fixed_size(f.col, not_redundant()) - <= DICT_MAX_FIXED_COL_LEN); + <= DICT_MAX_FIXED_COL_LEN + || !not_redundant()); ut_d(n_nullable += f.col->is_nullable()); if (!f.col->is_dropped()) { - (*field_map_it++).set_ind(f.col->ind); + field_map_it->set_ind(f.col->ind); + field_map_it->or_unsigned_len(f.col->unsigned_len); + field_map_it++; continue; } @@ -264,7 +268,8 @@ inline void dict_table_t::prepare_instant(const dict_table_t& old, if (index.n_fields == oindex.n_fields) { for (unsigned i = index.n_fields; i--; ) { ut_ad(index.fields[i].col->same_format( - *oindex.fields[i].col)); + *oindex.fields[i].col, + !not_redundant())); } } #endif @@ -452,9 +457,13 @@ inline void dict_index_t::instant_add_field(const dict_index_t& instant) as this index. Fields for any added columns are appended at the end. */ #ifndef DBUG_OFF for (unsigned i = 0; i < n_fields; i++) { - DBUG_ASSERT(fields[i].same(instant.fields[i])); - DBUG_ASSERT(instant.fields[i].col->same_format(*fields[i] - .col)); + DBUG_ASSERT(fields[i].prefix_len + == instant.fields[i].prefix_len); + DBUG_ASSERT(fields[i].fixed_len + == instant.fields[i].fixed_len + || !table->not_redundant()); + DBUG_ASSERT(instant.fields[i].col->same_format( + *fields[i].col, !table->not_redundant())); /* Instant conversion from NULL to NOT NULL is not allowed. */ DBUG_ASSERT(!fields[i].col->is_nullable() || instant.fields[i].col->is_nullable()); @@ -530,10 +539,17 @@ inline bool dict_table_t::instant_column(const dict_table_t& table, if (const dict_col_t* o = find(old_cols, col_map, n_cols, i)) { c.def_val = o->def_val; - DBUG_ASSERT(!((c.prtype ^ o->prtype) - & ~(DATA_NOT_NULL | DATA_VERSIONED))); - DBUG_ASSERT(c.mtype == o->mtype); - DBUG_ASSERT(c.len >= o->len); + ut_ad(c.same_format(*o, !not_redundant())); + + if (o->mtype == DATA_INT && !(c.prtype & DATA_UNSIGNED)) { + DBUG_ASSERT(c.mtype == o->mtype); + if (o->prtype & DATA_UNSIGNED) { + DBUG_ASSERT(c.len > o->len); + c.unsigned_len = o->len; + } else { + c.unsigned_len = o->unsigned_len; + } + } if (o->vers_sys_start()) { ut_ad(o->ind == vers_start); @@ -1510,7 +1526,8 @@ instant_alter_column_possible( = ALTER_ADD_STORED_BASE_COLUMN | ALTER_DROP_STORED_COLUMN | ALTER_STORED_COLUMN_ORDER - | ALTER_COLUMN_NULLABLE; + | ALTER_COLUMN_NULLABLE + | ALTER_COLUMN_EQUAL_PACK_LENGTH; if (!(ha_alter_info->handler_flags & avoid_rebuild)) { alter_table_operations flags = ha_alter_info->handler_flags @@ -1551,6 +1568,7 @@ instant_alter_column_possible( & ~ALTER_STORED_COLUMN_ORDER & ~ALTER_ADD_STORED_BASE_COLUMN & ~ALTER_COLUMN_NULLABLE + & ~ALTER_COLUMN_EQUAL_PACK_LENGTH & ~ALTER_OPTIONS)) { return false; } @@ -2947,7 +2965,7 @@ innobase_col_to_mysql( switch (col->mtype) { case DATA_INT: - ut_ad(len == flen); + ut_ad(len <= flen); /* Convert integer data from Innobase to little-endian format, sign bit restored to normal */ @@ -2956,7 +2974,7 @@ innobase_col_to_mysql( *--ptr = *data++; } - if (!(col->prtype & DATA_UNSIGNED)) { + if (!(col->prtype & DATA_UNSIGNED) && len > col->unsigned_len) { ((byte*) dest)[len - 1] ^= 0x80; } @@ -4240,6 +4258,8 @@ innobase_build_col_map( } col_map[old_i - num_old_v] = i; + new_table->cols[i].unsigned_len = + old_table->cols[old_i].unsigned_len; if (old_table->versioned() && altered_table->versioned()) { if (old_i == old_table->vers_start) { @@ -4972,7 +4992,7 @@ static bool innobase_insert_sys_virtual( return false; } -/** Insert a record to the SYS_COLUMNS dictionary table. +/** Insert or update a record in the SYS_COLUMNS dictionary table. @param[in] table_id table id @param[in] pos position of the column @param[in] field_name field name @@ -5587,7 +5607,8 @@ static bool innobase_instant_try( bool update = old && (!ctx->first_alter_pos || i < ctx->first_alter_pos - 1); - DBUG_ASSERT(!old || col->same_format(*old)); + ut_ad(!old || col->same_format( + *old, !user_table->not_redundant())); if (update && old->prtype == d->type.prtype && old->len == d->type.len) { @@ -5677,6 +5698,8 @@ add_all_virtual: NULL, trx, ctx->heap, NULL); dberr_t err = DB_SUCCESS; + DBUG_EXECUTE_IF("ib_instant_error", + err = DB_OUT_OF_FILE_SPACE; goto func_exit;); if (rec_is_metadata(rec, *index)) { ut_ad(page_rec_is_user_rec(rec)); if (!page_has_next(block->frame) @@ -5769,9 +5792,6 @@ empty_table: index->clear_instant_alter(); goto func_exit; } else if (!user_table->is_instant()) { - ut_ad(!user_table->not_redundant() - || (ha_alter_info->handler_flags - & ALTER_COLUMN_UNVERSIONED)); goto func_exit; } @@ -9020,7 +9040,6 @@ as part of commit_cache_norebuild(). static MY_ATTRIBUTE((nonnull)) void innobase_rename_columns_cache( -/*=====================================*/ Alter_inplace_info* ha_alter_info, const TABLE* table, dict_table_t* user_table) diff --git a/storage/innobase/include/data0type.ic b/storage/innobase/include/data0type.ic index 56a588562ee..2b1a00b60ef 100644 --- a/storage/innobase/include/data0type.ic +++ b/storage/innobase/include/data0type.ic @@ -472,12 +472,18 @@ dtype_get_fixed_size_low( } #endif /* UNIV_DEBUG */ /* fall through */ - case DATA_CHAR: - case DATA_FIXBINARY: - case DATA_INT: case DATA_FLOAT: case DATA_DOUBLE: return(len); + case DATA_FIXBINARY: + case DATA_CHAR: + case DATA_INT: + /* Treat these types as variable length for redundant + row format. We can't rely on fixed_len anymore because record + can have shorter length from before instant enlargement + [MDEV-15563]. Note, that importing such tablespace to 10.3 + produces ER_TABLE_SCHEMA_MISMATCH. */ + return(comp ? len : 0); case DATA_MYSQL: if (prtype & DATA_BINARY_TYPE) { return(len); @@ -625,6 +631,14 @@ dtype_get_sql_null_size( const dtype_t* type, /*!< in: type */ ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */ { + switch (type->mtype) { + case DATA_INT: + case DATA_CHAR: + case DATA_FIXBINARY: + return(type->len); + default: + break; + } return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, type->mbminlen, type->mbmaxlen, comp)); } diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 5f6cd3d13c5..4c1cfcf2884 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -47,6 +47,7 @@ Created 1/8/1996 Heikki Tuuri #include "os0once.h" #include "fil0fil.h" #include "fil0crypt.h" +#include "my_sys.h" #include <sql_const.h> #include <set> #include <algorithm> @@ -581,6 +582,9 @@ struct dict_col_t{ this column. Our current max limit is 3072 (REC_VERSION_56_MAX_INDEX_COL_LEN) bytes. */ + unsigned unsigned_len:16; /*!< before ALTER to signed the field + was unsigned and was of this length. */ + private: /** Special value of ind for a dropped column */ static const unsigned DROPPED = 1023; @@ -685,15 +689,54 @@ public: /** Determine if the columns have the same format except for is_nullable() and is_versioned(). @param[in] other column to compare to + @param[in] redundant table is redundant row format @return whether the columns have the same format */ - bool same_format(const dict_col_t& other) const + bool same_format(const dict_col_t& other, bool redundant = false) const { - return mtype == other.mtype + bool charset_equal = true; + if (dtype_is_non_binary_string_type(mtype, prtype) + && dtype_is_non_binary_string_type(other.mtype, + other.prtype)) { + uint csn1 = (uint) dtype_get_charset_coll(prtype); + uint csn2 = (uint) dtype_get_charset_coll(other.prtype); + CHARSET_INFO* cs1 = get_charset(csn1, MYF(MY_WME)); + CHARSET_INFO* cs2 = get_charset(csn2, MYF(MY_WME)); + charset_equal = my_charset_same(cs1, cs2); + } + bool mtype_equal = (mtype == other.mtype); + bool prtype_equal = !((prtype ^ other.prtype) + & ~(DATA_NOT_NULL | DATA_VERSIONED)); + if (redundant && !prtype_equal) { + std::set<int> s; + switch (other.mtype) { + case DATA_CHAR: + case DATA_MYSQL: + case DATA_VARCHAR: + case DATA_VARMYSQL: + s = {DATA_CHAR, DATA_MYSQL, DATA_VARCHAR, + DATA_VARMYSQL}; + mtype_equal = (s.find(mtype) != s.end()); + prtype_equal = mtype_equal; + break; + case DATA_FIXBINARY: + case DATA_BINARY: + s = {DATA_FIXBINARY, DATA_BINARY}; + mtype_equal = (s.find(mtype) != s.end()); + prtype_equal = mtype_equal; + break; + case DATA_INT: + prtype_equal = true; + break; + default: + break; + } + } + return charset_equal + && mtype_equal + && prtype_equal && len >= other.len && mbminlen == other.mbminlen - && mbmaxlen == other.mbmaxlen - && !((prtype ^ other.prtype) - & ~(DATA_NOT_NULL | DATA_VERSIONED)); + && mbmaxlen == other.mbmaxlen; } }; @@ -1555,6 +1598,15 @@ class field_map_element_t /** Set if the column was dropped and originally declared NOT NULL */ static constexpr uint16_t NOT_NULL = 1U << (IND_BITS + 4); + /** The field was unsigned before ALTER to signed: + 0: never + 1: tinyint + 2: smallint + 3: mediumint + 4: int + */ + static constexpr uint16_t UNSIGNED_SIZE = 7U << (IND_BITS + 1); + /** Column index (if !(data & DROPPED)): table->cols[data & IND], or field length (if (data & DROPPED)): (data & IND) = 0 if variable-length with max_len < 256 bytes; @@ -1571,6 +1623,15 @@ public: void set_dropped() { data |= DROPPED; } bool is_not_null() const { return data & NOT_NULL; } void set_not_null() { ut_ad(is_dropped()); data |= NOT_NULL; } + uint16_t unsigned_len() const + { + return (data & UNSIGNED_SIZE) >> (IND_BITS + 1); + } + void or_unsigned_len(uint16_t unsigned_len) + { + ut_ad(unsigned_len <= 4); + data |= unsigned_len << (IND_BITS + 1); + } uint16_t ind() const { return data & IND; } void set_ind(uint16_t i) { @@ -1708,7 +1769,8 @@ struct dict_table_t { const ulint* col_map, unsigned& first_alter_pos); - /** Adjust table metadata for instant ADD/DROP/reorder COLUMN. + /** Adjust table metadata for instant ADD/DROP/reorder COLUMN, + unsigned -> bigger signed. @param[in] table table on which prepare_instant() was invoked @param[in] col_map mapping from cols[] and v_cols[] to table @return whether the metadata record must be updated */ diff --git a/storage/innobase/include/row0sel.h b/storage/innobase/include/row0sel.h index 1e58686dfcb..7674a20bc46 100644 --- a/storage/innobase/include/row0sel.h +++ b/storage/innobase/include/row0sel.h @@ -438,23 +438,10 @@ enum row_sel_match_mode { of a fixed length column) */ }; -#ifdef UNIV_DEBUG -/** Convert a non-SQL-NULL field from Innobase format to MySQL format. */ -# define row_sel_field_store_in_mysql_format(dest,templ,idx,field,src,len) \ - row_sel_field_store_in_mysql_format_func(dest,templ,idx,field,src,len) -#else /* UNIV_DEBUG */ -/** Convert a non-SQL-NULL field from Innobase format to MySQL format. */ -# define row_sel_field_store_in_mysql_format(dest,templ,idx,field,src,len) \ - row_sel_field_store_in_mysql_format_func(dest,templ,src,len) -#endif /* UNIV_DEBUG */ - /**************************************************************//** Stores a non-SQL-NULL field in the MySQL format. The counterpart of this function is row_mysql_store_col_in_innobase_format() in row0mysql.cc. */ - -void -row_sel_field_store_in_mysql_format_func( -/*=====================================*/ +void row_sel_field_store_in_mysql_format( byte* dest, /*!< in/out: buffer where to store; NOTE that BLOBs are not in themselves stored here: the caller must allocate @@ -466,16 +453,14 @@ row_sel_field_store_in_mysql_format_func( Its following fields are referenced: type, is_unsigned, mysql_col_len, mbminlen, mbmaxlen */ -#ifdef UNIV_DEBUG const dict_index_t* index, /*!< in: InnoDB index */ ulint field_no, /*!< in: templ->rec_field_no or templ->clust_rec_field_no or templ->icp_rec_field_no */ -#endif /* UNIV_DEBUG */ const byte* data, /*!< in: data to store */ - ulint len); /*!< in: length of the data */ + ulint len); /*!< in: length of the data */ #include "row0sel.ic" diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index 19764318c1a..8435ecd6aa5 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -612,11 +612,12 @@ rec_init_offsets( ulint i = 0; ulint offs; - ut_ad(index->n_core_null_bytes <= UT_BITS_IN_BYTES(index->n_nullable)); ut_d(offsets[2] = ulint(rec)); ut_d(offsets[3] = ulint(index)); if (dict_table_is_comp(index->table)) { + ut_ad(index->n_core_null_bytes + <= UT_BITS_IN_BYTES(index->n_nullable)); const byte* nulls; const byte* lens; dict_field_t* field; diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 50d70b22a5a..0624fe318f7 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -706,11 +706,6 @@ row_merge_buf_add( row_field, field, col->len, dict_table_page_size(old_table), conv_heap); - } else { - /* Field length mismatch should not - happen when rebuilding redundant row - format table. */ - ut_ad(dict_table_is_comp(index->table)); } } } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 28c6a1abf21..342b37bf8e7 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -890,7 +890,7 @@ row_create_prebuilt( ulint type = temp_index->fields[i].col->mtype; if (type == DATA_INT) { temp_len += - temp_index->fields[i].fixed_len; + temp_index->fields[i].col->len; } } srch_key_len = std::max(srch_key_len,temp_len); diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 8d7824bfc56..cc84490d82d 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -2698,23 +2698,19 @@ row_sel_convert_mysql_key_to_innobase( /**************************************************************//** Stores a non-SQL-NULL field in the MySQL format. The counterpart of this function is row_mysql_store_col_in_innobase_format() in row0mysql.cc. */ -void -row_sel_field_store_in_mysql_format_func( +void row_sel_field_store_in_mysql_format( byte* dest, const mysql_row_templ_t* templ, -#ifdef UNIV_DEBUG const dict_index_t* index, ulint field_no, -#endif /* UNIV_DEBUG */ const byte* data, ulint len) { byte* ptr; -#ifdef UNIV_DEBUG const dict_field_t* field = templ->is_virtual ? NULL : dict_index_get_nth_field(index, field_no); -#endif /* UNIV_DEBUG */ + uint16_t unsigned_len; ut_ad(len != UNIV_SQL_NULL); UNIV_MEM_ASSERT_RW(data, len); @@ -2739,16 +2735,21 @@ row_sel_field_store_in_mysql_format_func( data++; } - if (!templ->is_unsigned) { + unsigned_len = field ? field->col->unsigned_len : 0; + + if (!templ->is_unsigned && len > unsigned_len) { dest[len - 1] = (byte) (dest[len - 1] ^ 128); } - ut_ad(templ->mysql_col_len == len); + ut_ad(templ->mysql_col_len == len + || !index->table->not_redundant()); break; case DATA_VARCHAR: case DATA_VARMYSQL: case DATA_BINARY: + case DATA_CHAR: + case DATA_FIXBINARY: field_end = dest + templ->mysql_col_len; if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) { @@ -2836,7 +2837,8 @@ row_sel_field_store_in_mysql_format_func( ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len || (field_no == templ->icp_rec_field_no && field->prefix_len > 0) - || templ->rec_field_is_prefix); + || templ->rec_field_is_prefix + || !index->table->not_redundant()); ut_ad(templ->is_virtual || !(field->prefix_len % templ->mbmaxlen)); @@ -2858,8 +2860,6 @@ row_sel_field_store_in_mysql_format_func( ut_ad(0); /* fall through */ - case DATA_CHAR: - case DATA_FIXBINARY: case DATA_FLOAT: case DATA_DOUBLE: case DATA_DECIMAL: @@ -2886,8 +2886,7 @@ row_sel_field_store_in_mysql_format_func( @param[in] templ row template */ static MY_ATTRIBUTE((warn_unused_result)) -ibool -row_sel_store_mysql_field( +bool row_sel_store_mysql_field( byte* mysql_rec, row_prebuilt_t* prebuilt, const rec_t* rec, @@ -2949,7 +2948,7 @@ row_sel_store_mysql_field( ut_a(prebuilt->trx->isolation_level == TRX_ISO_READ_UNCOMMITTED); - DBUG_RETURN(FALSE); + DBUG_RETURN(false); } ut_a(len != UNIV_SQL_NULL); @@ -2980,7 +2979,7 @@ row_sel_store_mysql_field( (const byte*) prebuilt->default_rec + templ->mysql_col_offset, templ->mysql_col_len); - DBUG_RETURN(TRUE); + DBUG_RETURN(true); } if (DATA_LARGE_MTYPE(templ->type) @@ -3021,7 +3020,7 @@ row_sel_store_mysql_field( &= ~(byte) templ->mysql_null_bit_mask; } - DBUG_RETURN(TRUE); + DBUG_RETURN(true); } /** Convert a row in the Innobase format to a row in the MySQL format. |