summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2019-01-28 16:43:58 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2019-01-28 16:43:58 +0200
commite5737c8800f7533c97ec3b91331d14d9d4705a5c (patch)
tree774c1567feae60e76ec7474ca2cb1ea970cb14c6
parent27139b727bc6f80ab2a882e50c3efac03f1f70c4 (diff)
parentf8ad271dec770bef59dafbfda0f8cad78c3c1aa0 (diff)
downloadmariadb-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
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_convert,utf8.rdiff38
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_convert.result306
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_convert.combinations5
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_convert.test275
-rw-r--r--sql/field.cc60
-rw-r--r--sql/field.h2
-rw-r--r--sql/handler.cc1
-rw-r--r--sql/handler.h9
-rw-r--r--sql/sql_table.cc4
-rw-r--r--storage/innobase/btr/btr0btr.cc4
-rw-r--r--storage/innobase/btr/btr0cur.cc10
-rw-r--r--storage/innobase/dict/dict0dict.cc11
-rw-r--r--storage/innobase/dict/dict0mem.cc2
-rw-r--r--storage/innobase/handler/ha_innodb.cc7
-rw-r--r--storage/innobase/handler/handler0alter.cc59
-rw-r--r--storage/innobase/include/data0type.ic20
-rw-r--r--storage/innobase/include/dict0mem.h74
-rw-r--r--storage/innobase/include/row0sel.h19
-rw-r--r--storage/innobase/rem/rem0rec.cc3
-rw-r--r--storage/innobase/row/row0merge.cc5
-rw-r--r--storage/innobase/row/row0mysql.cc2
-rw-r--r--storage/innobase/row/row0sel.cc31
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.