diff options
author | Igor Babaev <igor@askmonty.org> | 2019-02-13 14:59:34 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2019-02-13 14:59:34 -0800 |
commit | 7d9f45e0729ea9b2f572cfb4023b28c16ab11145 (patch) | |
tree | 040e8f220c289652612c6cda14d277435c25ac49 | |
parent | 62fad4e8e964786cd1c8d675f3c071a405a8d187 (diff) | |
parent | a081a998a62eb0663b5691d0b5c0607465f15c0f (diff) | |
download | mariadb-git-bb-10.4-mdev17096.tar.gz |
Merge branch '10.4' into bb-10.4-mdev17096bb-10.4-mdev17096
49 files changed, 1022 insertions, 197 deletions
diff --git a/cmake/submodules.cmake b/cmake/submodules.cmake index c2a415c6063..9f04c26e8d6 100644 --- a/cmake/submodules.cmake +++ b/cmake/submodules.cmake @@ -31,7 +31,7 @@ ENDIF() IF(update_result OR NOT EXISTS ${CMAKE_SOURCE_DIR}/libmariadb/CMakeLists.txt) MESSAGE(FATAL_ERROR "No MariaDB Connector/C! Run - git submodule update --init + git submodule update --init --recursive Then restart the build. ") ENDIF() diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake index 37ed0c78cf5..603f1955e5f 100644 --- a/cmake/wsrep.cmake +++ b/cmake/wsrep.cmake @@ -32,6 +32,12 @@ IF(WITH_WSREP) # Set the patch version SET(WSREP_PATCH_VERSION "22") + IF(NOT EXISTS "${CMAKE_SOURCE_DIR}/wsrep-lib/wsrep-API/v26/wsrep_api.h") + MESSAGE(FATAL_ERROR "No MariaDB wsrep-API code! Run + ${GIT_EXECUTABLE} submodule update --init --recursive +Then restart the build. +") + ENDIF() # Obtain wsrep API version FILE(STRINGS "${CMAKE_SOURCE_DIR}/wsrep-lib/wsrep-API/v26/wsrep_api.h" WSREP_API_VERSION LIMIT_COUNT 1 REGEX "WSREP_INTERFACE_VERSION") diff --git a/mysql-test/main/information_schema-big.result b/mysql-test/main/information_schema-big.result index d4aa6deb2e2..b135621acb7 100644 --- a/mysql-test/main/information_schema-big.result +++ b/mysql-test/main/information_schema-big.result @@ -36,6 +36,7 @@ GLOBAL_VARIABLES VARIABLE_NAME INDEX_STATISTICS TABLE_SCHEMA KEY_CACHES KEY_CACHE_NAME KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +OPTIMIZER_TRACE QUERY PARAMETERS SPECIFIC_SCHEMA PARTITIONS TABLE_SCHEMA PLUGINS PLUGIN_NAME @@ -94,6 +95,7 @@ GLOBAL_VARIABLES VARIABLE_NAME INDEX_STATISTICS TABLE_SCHEMA KEY_CACHES KEY_CACHE_NAME KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +OPTIMIZER_TRACE QUERY PARAMETERS SPECIFIC_SCHEMA PARTITIONS TABLE_SCHEMA PLUGINS PLUGIN_NAME diff --git a/mysql-test/main/type_json.result b/mysql-test/main/type_json.result index 0045847097b..96e96cca404 100644 --- a/mysql-test/main/type_json.result +++ b/mysql-test/main/type_json.result @@ -2,7 +2,7 @@ create or replace table t1(a json); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL + `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`a`)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 create or replace table t1(a json character set utf8); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'character set utf8)' at line 1 @@ -10,7 +10,7 @@ create or replace table t1(a json default '{a:1}'); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '{a:1}' + `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '{a:1}' CHECK (json_valid(`a`)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 create or replace table t1(a json not null check (json_valid(a))); show create table t1; @@ -21,18 +21,79 @@ t1 CREATE TABLE `t1` ( insert t1 values ('[]'); insert t1 values ('a'); ERROR 23000: CONSTRAINT `t1.a` failed for `test`.`t1` +create or replace table t1(a json not null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`a`)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert t1 values ('[]'); +insert t1 values ('a'); +ERROR 23000: CONSTRAINT `t1.a` failed for `test`.`t1` set timestamp=unix_timestamp('2010:11:12 13:14:15'); create or replace table t1(a json default(json_object('now', now()))); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT json_object('now',current_timestamp()) + `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT json_object('now',current_timestamp()) CHECK (json_valid(`a`)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 insert t1 values (); select * from t1; a {"now": "2010-11-12 13:14:15"} drop table t1; +create table t1 (t json) as select json_quote('foo') as t; +create table t2 (a json) as select json_quote('foo') as t; +create table t3 like t1; +select * from t1; +t +"foo" +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`t`)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`a`)), + `t` varchar(38) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `t` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`t`)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1,t2,t3; +create table t1 (t json check (length(t) > 0)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (octet_length(`t`) > 0) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (t text) engine=myisam; +insert into t1 values ("{}"),(""); +create table t2 (t json) select t from t1; +ERROR 23000: CONSTRAINT `t2.t` failed for `test`.`t2` +select * from t2; +ERROR 42S02: Table 'test.t2' doesn't exist +drop table t1; +create or replace table t1(a json default(json_object('now', 1)) check (json_valid(a))); +insert into t1 values (); +insert into t1 values ("{}"); +insert into t1 values ("xxx"); +ERROR 23000: CONSTRAINT `t1.a` failed for `test`.`t1` +select * from t1; +a +{"now": 1} +{} +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT json_object('now',1) CHECK (json_valid(`a`)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; select cast('{a:1}' as text); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'text)' at line 1 select cast('{a:1}' as json); diff --git a/mysql-test/main/type_json.test b/mysql-test/main/type_json.test index 0cff9366145..bd13dc1fcf4 100644 --- a/mysql-test/main/type_json.test +++ b/mysql-test/main/type_json.test @@ -17,12 +17,47 @@ insert t1 values ('[]'); --error ER_CONSTRAINT_FAILED insert t1 values ('a'); +create or replace table t1(a json not null); +show create table t1; +insert t1 values ('[]'); +--error ER_CONSTRAINT_FAILED +insert t1 values ('a'); + set timestamp=unix_timestamp('2010:11:12 13:14:15'); create or replace table t1(a json default(json_object('now', now()))); show create table t1; insert t1 values (); select * from t1; +drop table t1; + +create table t1 (t json) as select json_quote('foo') as t; +create table t2 (a json) as select json_quote('foo') as t; +create table t3 like t1; +select * from t1; +show create table t1; +show create table t2; +show create table t3; +drop table t1,t2,t3; +create table t1 (t json check (length(t) > 0)); +show create table t1; +drop table t1; + +create table t1 (t text) engine=myisam; +insert into t1 values ("{}"),(""); +--error ER_CONSTRAINT_FAILED +create table t2 (t json) select t from t1; +--error ER_NO_SUCH_TABLE +select * from t2; +drop table t1; + +create or replace table t1(a json default(json_object('now', 1)) check (json_valid(a))); +insert into t1 values (); +insert into t1 values ("{}"); +--error ER_CONSTRAINT_FAILED +insert into t1 values ("xxx"); +select * from t1; +show create table t1; drop table t1; --error ER_PARSE_ERROR diff --git a/mysql-test/suite/galera/r/galera_defaults.result b/mysql-test/suite/galera/r/galera_defaults.result index 20ea590e2e5..4aef4f5e48c 100644 --- a/mysql-test/suite/galera/r/galera_defaults.result +++ b/mysql-test/suite/galera/r/galera_defaults.result @@ -34,7 +34,7 @@ WSREP_FORCED_BINLOG_FORMAT NONE WSREP_GTID_DOMAIN_ID 0 WSREP_GTID_MODE OFF WSREP_IGNORE_APPLY_ERRORS 7 -WSREP_LOAD_DATA_SPLITTING ON +WSREP_LOAD_DATA_SPLITTING OFF WSREP_LOG_CONFLICTS OFF WSREP_MAX_WS_ROWS 0 WSREP_MAX_WS_SIZE 2147483647 diff --git a/mysql-test/suite/galera/r/galera_var_load_data_splitting.result b/mysql-test/suite/galera/r/galera_var_load_data_splitting.result index 9078e9ea985..66bc6bc4a9a 100644 --- a/mysql-test/suite/galera/r/galera_var_load_data_splitting.result +++ b/mysql-test/suite/galera/r/galera_var_load_data_splitting.result @@ -12,7 +12,11 @@ COUNT(*) = 95000 wsrep_last_committed_diff 1 connection node_1; -SET GLOBAL wsrep_load_data_splitting = 1;; +SET GLOBAL wsrep_load_data_splitting = 0;; +Warnings: +Warning 1287 '@@wsrep_load_data_splitting' is deprecated and will be removed in a future release +connection node_2; +SET GLOBAL wsrep_load_data_splitting = 0;; Warnings: Warning 1287 '@@wsrep_load_data_splitting' is deprecated and will be removed in a future release DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/partition.result b/mysql-test/suite/galera/r/partition.result index 213f9dfdbab..2e16d06519c 100644 --- a/mysql-test/suite/galera/r/partition.result +++ b/mysql-test/suite/galera/r/partition.result @@ -159,7 +159,7 @@ wsrep_last_committed_diff AS_EXPECTED_1_or_2 DROP TABLE t1; connection node_1; -SET GLOBAL wsrep_load_data_splitting = 1;; +SET GLOBAL wsrep_load_data_splitting = 0;; Warnings: Warning 1287 '@@wsrep_load_data_splitting' is deprecated and will be removed in a future release disconnect node_2; diff --git a/mysql-test/suite/galera/t/galera_var_load_data_splitting.test b/mysql-test/suite/galera/t/galera_var_load_data_splitting.test index 38dab0a981b..621cb69fc16 100644 --- a/mysql-test/suite/galera/t/galera_var_load_data_splitting.test +++ b/mysql-test/suite/galera/t/galera_var_load_data_splitting.test @@ -36,4 +36,7 @@ SELECT COUNT(*) = 95000 FROM t1; --connection node_1 --eval SET GLOBAL wsrep_load_data_splitting = $wsrep_load_data_splitting_orig; +--connection node_2 +--eval SET GLOBAL wsrep_load_data_splitting = $wsrep_load_data_splitting_orig; + DROP TABLE t1; diff --git a/mysql-test/suite/galera_sr/r/galera_sr_load_data.result b/mysql-test/suite/galera_sr/r/galera_sr_load_data.result index a474a7e3ae8..354f9ca718a 100644 --- a/mysql-test/suite/galera_sr/r/galera_sr_load_data.result +++ b/mysql-test/suite/galera_sr/r/galera_sr_load_data.result @@ -9,5 +9,5 @@ SELECT COUNT(*) = 20000 FROM t1; COUNT(*) = 20000 1 wsrep_last_committed_diff -0 +1 DROP TABLE t1; diff --git a/mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result b/mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result index b25a8877005..61e4b56aa43 100644 --- a/mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result +++ b/mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result @@ -1,9 +1,19 @@ +connection node_2; +connection node_1; SET SESSION wsrep_trx_fragment_size = 512; SET GLOBAL wsrep_load_data_splitting = TRUE; +Warnings: +Warning 1287 '@@wsrep_load_data_splitting' is deprecated and will be removed in a future release CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; +connection node_2; +connection node_1; +connection node_2; SELECT COUNT(*) = 95000 FROM t1; COUNT(*) = 95000 1 wsrep_last_committed_diff 1 +connection node_1; +Warnings: +Warning 1287 '@@wsrep_load_data_splitting' is deprecated and will be removed in a future release DROP TABLE t1; diff --git a/mysql-test/suite/galera_sr/t/galera_sr_load_data.test b/mysql-test/suite/galera_sr/t/galera_sr_load_data.test index b430ace5d69..70f0926ed1b 100644 --- a/mysql-test/suite/galera_sr/t/galera_sr_load_data.test +++ b/mysql-test/suite/galera_sr/t/galera_sr_load_data.test @@ -33,7 +33,7 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; SELECT COUNT(*) = 20000 FROM t1; # LOAD-ing 20K rows causes 3 commits to be registered --disable_query_log ---eval SELECT $wsrep_last_committed_after - $wsrep_last_committed_before = 3 AS wsrep_last_committed_diff; +--eval SELECT $wsrep_last_committed_after - $wsrep_last_committed_before = 3 AS wsrep_last_committed_diff --enable_query_log DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/alter_varchar_change.result b/mysql-test/suite/innodb/r/alter_varchar_change.result index 25adde6ffe4..ce729fe5612 100644 --- a/mysql-test/suite/innodb/r/alter_varchar_change.result +++ b/mysql-test/suite/innodb/r/alter_varchar_change.result @@ -412,6 +412,23 @@ ALTER TABLE t1 MODIFY f2 VARCHAR(300); CALL get_table_id("test/t1", @tbl1_id); SELECT @tbl1_id = @tbl_id; @tbl1_id = @tbl_id +1 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` varchar(300) DEFAULT NULL, + KEY `idx` (`f2`(40)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1(f1 INT NOT NULL, +f2 VARCHAR(128), +INDEX idx(f2(40)))ENGINE=InnoDB; +CALL get_table_id("test/t1", @tbl_id); +ALTER TABLE t1 MODIFY f2 VARCHAR(300); +CALL get_table_id("test/t1", @tbl1_id); +SELECT @tbl1_id = @tbl_id; +@tbl1_id = @tbl_id 0 SHOW CREATE TABLE t1; Table Create Table @@ -422,6 +439,23 @@ t1 CREATE TABLE `t1` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1(f1 INT NOT NULL, +f2 VARCHAR(128), +INDEX idx(f2(40)))ENGINE=InnoDB ROW_FORMAT=REDUNDANT; +CALL get_table_id("test/t1", @tbl_id); +ALTER TABLE t1 MODIFY f2 VARCHAR(300); +CALL get_table_id("test/t1", @tbl1_id); +SELECT @tbl1_id = @tbl_id; +@tbl1_id = @tbl_id +1 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` varchar(300) DEFAULT NULL, + KEY `idx` (`f2`(40)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT +DROP TABLE t1; +CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100), INDEX idx(f2(40)))ENGINE=InnoDB; CALL get_table_id("test/t1", @tbl_id); diff --git a/mysql-test/suite/innodb/r/instant_alter_extend,utf8.rdiff b/mysql-test/suite/innodb/r/instant_alter_extend,utf8.rdiff new file mode 100644 index 00000000000..9b7196ccf9a --- /dev/null +++ b/mysql-test/suite/innodb/r/instant_alter_extend,utf8.rdiff @@ -0,0 +1,29 @@ +--- instant_alter_convert.result ++++ instant_alter_convert,utf8.result +@@ -37,7 +37,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; +@@ -51,7 +51,7 @@ + test.t check status OK + call check_table('t'); + name mtype prtype len +-a 2 800FE 200 ++a 13 2100FE 600 + # 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 +@@ -72,7 +72,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)); + alter table t modify a binary(255), algorithm=instant; diff --git a/mysql-test/suite/innodb/r/instant_alter_extend.result b/mysql-test/suite/innodb/r/instant_alter_extend.result new file mode 100644 index 00000000000..1798f47104a --- /dev/null +++ b/mysql-test/suite/innodb/r/instant_alter_extend.result @@ -0,0 +1,235 @@ +# +# MDEV-15563: Instant ROW_FORMAT=REDUNDANT column type change&extension +# +create or replace database test; +use test; +set default_storage_engine=innodb; +set @save_format= @@GLOBAL.innodb_default_row_format; +SET GLOBAL innodb_default_row_format=redundant; +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~~ +# VARCHAR -> CHAR, VARBINARY -> BINARY conversion +set @bigval= repeat('0123456789', 20); +create or replace table t (a varchar(300)); +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)); +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 200 +# 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)); +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)); +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 200 +# 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 +# Integer conversions +create or replace table t (x tinyint); +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); +alter table t2 discard tablespace; +create or replace table t1 (x tinyint); +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 +# Check innobase_col_to_mysql() len < flen +create or replace table t1 (x mediumint); +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; +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)); +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); +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); +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); +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); +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)); +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; +SET GLOBAL innodb_default_row_format=@save_format; diff --git a/mysql-test/suite/innodb/t/alter_varchar_change.test b/mysql-test/suite/innodb/t/alter_varchar_change.test index 7e0c99487b5..9769c63ac5e 100644 --- a/mysql-test/suite/innodb/t/alter_varchar_change.test +++ b/mysql-test/suite/innodb/t/alter_varchar_change.test @@ -307,6 +307,30 @@ SHOW CREATE TABLE t1; DROP TABLE t1; CREATE TABLE t1(f1 INT NOT NULL, + f2 VARCHAR(128), + INDEX idx(f2(40)))ENGINE=InnoDB; + +CALL get_table_id("test/t1", @tbl_id); +ALTER TABLE t1 MODIFY f2 VARCHAR(300); +CALL get_table_id("test/t1", @tbl1_id); + +SELECT @tbl1_id = @tbl_id; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1(f1 INT NOT NULL, + f2 VARCHAR(128), + INDEX idx(f2(40)))ENGINE=InnoDB ROW_FORMAT=REDUNDANT; + +CALL get_table_id("test/t1", @tbl_id); +ALTER TABLE t1 MODIFY f2 VARCHAR(300); +CALL get_table_id("test/t1", @tbl1_id); + +SELECT @tbl1_id = @tbl_id; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100), INDEX idx(f2(40)))ENGINE=InnoDB; diff --git a/mysql-test/suite/innodb/t/instant_alter_extend.combinations b/mysql-test/suite/innodb/t/instant_alter_extend.combinations new file mode 100644 index 00000000000..1465bf59ad7 --- /dev/null +++ b/mysql-test/suite/innodb/t/instant_alter_extend.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_extend.test b/mysql-test/suite/innodb/t/instant_alter_extend.test new file mode 100644 index 00000000000..4ffa39c4f13 --- /dev/null +++ b/mysql-test/suite/innodb/t/instant_alter_extend.test @@ -0,0 +1,226 @@ +--source include/have_innodb.inc +--source include/maybe_debug.inc + +-- echo # +-- echo # MDEV-15563: Instant ROW_FORMAT=REDUNDANT column type change&extension +-- echo # + +# Use character-set-server in test db +create or replace database test; +use test; + +set default_storage_engine=innodb; +set @save_format= @@GLOBAL.innodb_default_row_format; +SET GLOBAL innodb_default_row_format=redundant; +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 # VARCHAR -> CHAR, VARBINARY -> BINARY conversion +set @bigval= repeat('0123456789', 20); + +create or replace table t (a varchar(300)); +--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)); +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)); +--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)); +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 # Integer conversions +create or replace table t (x tinyint); +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); +alter table t2 discard tablespace; + +create or replace table t1 (x tinyint); +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 # Check innobase_col_to_mysql() len < flen +create or replace table t1 (x mediumint); +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; +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)); +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); +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); +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); +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); +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)); +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; +SET GLOBAL innodb_default_row_format=@save_format; diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result index dd3e70c587d..49eaaa965dc 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result +++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result @@ -227,9 +227,9 @@ READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME WSREP_LOAD_DATA_SPLITTING SESSION_VALUE NULL -GLOBAL_VALUE ON +GLOBAL_VALUE OFF GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE ON +DEFAULT_VALUE OFF VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BOOLEAN VARIABLE_COMMENT To commit LOAD DATA transaction after every 10K rows inserted (deprecated) diff --git a/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result index d373a3832d5..3171a690486 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result @@ -6,7 +6,7 @@ SET @wsrep_load_data_splitting_global_saved = @@global.wsrep_load_data_splitting # default SELECT @@global.wsrep_load_data_splitting; @@global.wsrep_load_data_splitting -1 +0 # scope SELECT @@session.wsrep_load_data_splitting; @@ -42,7 +42,7 @@ Warnings: Warning 1287 '@@wsrep_load_data_splitting' is deprecated and will be removed in a future release SELECT @@global.wsrep_load_data_splitting; @@global.wsrep_load_data_splitting -1 +0 # invalid values SET @@global.wsrep_load_data_splitting=NULL; diff --git a/sql/field.cc b/sql/field.cc index dd125a06bad..6e45d10d855 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2008, 2017, MariaDB + Copyright (c) 2008, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -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_EXT; + } + return IS_EQUAL_NO; } @@ -7901,16 +7908,28 @@ 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->length < field_length) + return IS_EQUAL_NO; + + 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 + const Type_handler *new_type_handler= new_field->type_handler(); + if (new_type_handler == type_handler()) + { + if (new_field->length == field_length) + return IS_EQUAL_YES; + if (field_length <= 127 || + new_field->length <= 255 || + field_length > 255 || + (table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION)) + return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer length + } + else if (new_type_handler == &type_handler_string) // converting to CHAR + { + if (table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION) + return IS_EQUAL_PACK_LENGTH_EXT; + } } return IS_EQUAL_NO; } @@ -9480,12 +9499,22 @@ 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())); + if ((new_field->flags ^ flags) & (UNSIGNED_FLAG | AUTO_INCREMENT_FLAG)) + return IS_EQUAL_NO; + + const Type_handler *th= type_handler(), *new_th = new_field->type_handler(); + + if (th == new_th && new_field->pack_length == pack_length()) + return IS_EQUAL_YES; + + if (table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION) + { + if (th->result_type() == new_th->result_type() && + new_field->pack_length >= pack_length()) + return IS_EQUAL_PACK_LENGTH_EXT; + } + + return IS_EQUAL_NO; } @@ -10733,6 +10762,7 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field, interval= dup_field->interval; vcol_info= dup_field->vcol_info; invisible= dup_field->invisible; + check_constraint= dup_field->check_constraint; } 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.h b/sql/handler.h index 350d881a934..31abb4699ca 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2,7 +2,7 @@ #define HANDLER_INCLUDED /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2018, MariaDB + Copyright (c) 2009, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -319,6 +319,11 @@ enum enum_alter_inplace_result { /* Safe for online backup */ #define HA_CAN_ONLINE_BACKUPS (1ULL << 56) +/** whether every data field explicitly stores length +(holds for InnoDB ROW_FORMAT=REDUNDANT) */ +#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 */ @@ -741,6 +746,14 @@ typedef ulonglong alter_table_operations; */ #define ALTER_COLUMN_INDEX_LENGTH (1ULL << 60) +/** + Change the column length or type such that no rebuild is needed. + Only set if ALTER_COLUMN_EQUAL_PACK_LENGTH does not apply, and + if HA_EXTENDED_TYPES_CONVERSION holds. + @see IS_EQUAL_PACK_LENGTH_EXT +*/ +#define ALTER_COLUMN_EQUAL_PACK_LENGTH_EXT (1ULL << 61) + /* Flags set in partition_flags when altering partitions */ @@ -3158,7 +3171,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/my_json_writer.h b/sql/my_json_writer.h index 4701cb4165b..3234c748f5d 100644 --- a/sql/my_json_writer.h +++ b/sql/my_json_writer.h @@ -111,7 +111,7 @@ class String_with_limit { public: - String_with_limit() : size_limit(SIZE_MAX), truncated_len(0) + String_with_limit() : size_limit(SIZE_T_MAX), truncated_len(0) { str.length(0); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index df4d8d7b94c..f5e37446b58 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -9587,3 +9587,21 @@ bool LEX::sp_proc_stmt_statement_finalize(THD *thd, bool no_lookahead) lip->get_tok_start()); return LEX::sp_proc_stmt_statement_finalize_buf(thd, qbuf); } + + +/** + Create JSON_VALID(field_name) expression +*/ + +Virtual_column_info *make_json_valid_expr(THD *thd, LEX_CSTRING *field_name) +{ + Lex_ident_sys_st str; + Item *field, *expr; + str.set_valid_utf8(field_name); + if (unlikely(!(field= thd->lex->create_item_ident_field(thd, NullS, NullS, + &str)))) + return 0; + if (unlikely(!(expr= new (thd->mem_root) Item_func_json_valid(thd, field)))) + return 0; + return add_virtual_expression(thd, expr); +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 25e8ad3c727..0fa1d96e626 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -148,6 +148,12 @@ public: bool copy_or_convert(THD *thd, const Lex_ident_cli_st *str, CHARSET_INFO *cs); bool is_null() const { return str == NULL; } bool to_size_number(ulonglong *to) const; + void set_valid_utf8(LEX_CSTRING *name) + { + DBUG_ASSERT(Well_formed_prefix(system_charset_info, name->str, + name->length).length() == name->length); + str= name->str ; length= name->length; + } }; @@ -4610,5 +4616,6 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, void sp_create_assignment_lex(THD *thd, bool no_lookahead); bool sp_create_assignment_instr(THD *thd, bool no_lookahead); +Virtual_column_info *make_json_valid_expr(THD *thd, LEX_CSTRING *field_name); #endif /* MYSQL_SERVER */ #endif /* SQL_LEX_INCLUDED */ diff --git a/sql/sql_load.cc b/sql/sql_load.cc index c95ef72a308..da5356ffb4b 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -100,41 +100,39 @@ public: #define PUSH(A) *(stack_pos++)=(A) #ifdef WITH_WSREP -/** If requested by wsrep_load_data_splitting, commit and restart -the transaction after every 10,000 inserted rows. */ - -static bool wsrep_load_data_split(THD *thd, const TABLE *table, - const COPY_INFO &info) +/** If requested by wsrep_load_data_splitting and streaming replication is + not enabled, replicate a streaming fragment every 10,000 rows.*/ +class Wsrep_load_data_split { - DBUG_ENTER("wsrep_load_data_split"); - - if (!wsrep_load_data_splitting || !WSREP(thd) - || !info.records || (info.records % 10000) - || !thd->transaction.stmt.ha_list - || thd->transaction.stmt.ha_list->ht() != binlog_hton - || !thd->transaction.stmt.ha_list->next() - || thd->transaction.stmt.ha_list->next()->next()) - DBUG_RETURN(false); - - if (handlerton* hton= thd->transaction.stmt.ha_list->next()->ht()) +public: + Wsrep_load_data_split(THD *thd) + : m_thd(thd) + , m_load_data_splitting(wsrep_load_data_splitting) + , m_fragment_unit(thd->wsrep_trx().streaming_context().fragment_unit()) + , m_fragment_size(thd->wsrep_trx().streaming_context().fragment_size()) { - if (!(hton->flags & HTON_WSREP_REPLICATION)) - DBUG_RETURN(false); - WSREP_DEBUG("intermediate transaction commit in LOAD DATA"); - wsrep_tc_log_commit(thd); - table->file->extra(HA_EXTRA_FAKE_START_STMT); + if (WSREP(m_thd) && m_load_data_splitting) + { + /* Override streaming settings with backward compatible values for + load data splitting */ + m_thd->wsrep_cs().streaming_params(wsrep::streaming_context::row, 10000); + } } - DBUG_RETURN(false); -} -# define WSREP_LOAD_DATA_SPLIT(thd,table,info) \ - if (wsrep_load_data_split(thd,table,info)) \ - { \ - table->auto_increment_field_not_null= FALSE; \ - DBUG_RETURN(1); \ + ~Wsrep_load_data_split() + { + if (WSREP(m_thd) && m_load_data_splitting) + { + /* Restore original settings */ + m_thd->wsrep_cs().streaming_params(m_fragment_unit, m_fragment_size); + } } -#else /* WITH_WSREP */ -#define WSREP_LOAD_DATA_SPLIT(thd,table,info) /* empty */ +private: + THD *m_thd; + my_bool m_load_data_splitting; + enum wsrep::streaming_context::fragment_unit m_fragment_unit; + size_t m_fragment_size; +}; #endif /* WITH_WSREP */ class READ_INFO: public Load_data_param @@ -354,6 +352,9 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, bool transactional_table __attribute__((unused)); DBUG_ENTER("mysql_load"); +#ifdef WITH_WSREP + Wsrep_load_data_split wsrep_load_data_split(thd); +#endif /* WITH_WSREP */ /* Bug #34283 mysqlbinlog leaves tmpfile after termination if binlog contains @@ -1005,7 +1006,6 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, DBUG_RETURN(-1); } - WSREP_LOAD_DATA_SPLIT(thd, table, info); err= write_record(thd, table, &info); table->auto_increment_field_not_null= FALSE; if (err) @@ -1148,7 +1148,6 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, DBUG_RETURN(-1); } - WSREP_LOAD_DATA_SPLIT(thd, table, info); err= write_record(thd, table, &info); table->auto_increment_field_not_null= FALSE; if (err) @@ -1271,7 +1270,6 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, DBUG_RETURN(-1); } - WSREP_LOAD_DATA_SPLIT(thd, table, info); err= write_record(thd, table, &info); table->auto_increment_field_not_null= false; if (err) diff --git a/sql/sql_priv.h b/sql/sql_priv.h index fa12b645041..d5a69d740ea 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2010, 2018, Monty Program Ab. + Copyright (c) 2010, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -345,11 +345,21 @@ #ifndef MYSQL_CLIENT /* - Some defines for exit codes for ::is_equal class functions. + Field::is_equal() return codes. */ #define IS_EQUAL_NO 0 #define IS_EQUAL_YES 1 +/** + new_field has compatible packed representation with old type, + so it is theoretically possible to perform change by only updating + data dictionary without changing table rows +*/ #define IS_EQUAL_PACK_LENGTH 2 +/** + new_field has a representation that is compatible with the old type + when the storage engine advertises HA_EXTENDED_TYPES_CONVERSION +*/ +#define IS_EQUAL_PACK_LENGTH_EXT 3 enum enum_parsing_place { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8086950ea5b..24ba12b9323 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6615,6 +6615,9 @@ static bool fill_alter_inplace_info(THD *thd, */ ha_alter_info->handler_flags|= ALTER_COLUMN_EQUAL_PACK_LENGTH; break; + case IS_EQUAL_PACK_LENGTH_EXT: + ha_alter_info->handler_flags|= ALTER_COLUMN_EQUAL_PACK_LENGTH_EXT; + break; default: DBUG_ASSERT(0); /* Safety. */ diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 96a73a85267..6cccc785fee 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -66,6 +66,7 @@ Type_handler_tiny_blob type_handler_tiny_blob; Type_handler_medium_blob type_handler_medium_blob; Type_handler_long_blob type_handler_long_blob; Type_handler_blob type_handler_blob; +Type_handler_json type_handler_json; static Type_handler_blob_compressed type_handler_blob_compressed; Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff; diff --git a/sql/sql_type.h b/sql/sql_type.h index 3eb7d39742c..d507241075e 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -3280,6 +3280,7 @@ public: return true; } virtual bool is_scalar_type() const { return true; } + virtual bool is_json_type() const { return false; } virtual bool can_return_int() const { return true; } virtual bool can_return_decimal() const { return true; } virtual bool can_return_real() const { return true; } @@ -5890,6 +5891,14 @@ public: }; +class Type_handler_json: public Type_handler_long_blob +{ +public: + virtual ~Type_handler_json() {} + virtual bool is_json_type() const { return true; } +}; + + class Type_handler_blob: public Type_handler_blob_common { static const Name m_name_blob; @@ -6218,6 +6227,7 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_hex_hybrid type_handler_hex_hybrid; extern MYSQL_PLUGIN_IMPORT Type_handler_tiny_blob type_handler_tiny_blob; extern MYSQL_PLUGIN_IMPORT Type_handler_medium_blob type_handler_medium_blob; extern MYSQL_PLUGIN_IMPORT Type_handler_long_blob type_handler_long_blob; +extern MYSQL_PLUGIN_IMPORT Type_handler_json type_handler_json; extern MYSQL_PLUGIN_IMPORT Type_handler_blob type_handler_blob; extern MYSQL_PLUGIN_IMPORT Type_handler_bool type_handler_bool; @@ -6243,11 +6253,6 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_datetime2 type_handler_datetime2; extern MYSQL_PLUGIN_IMPORT Type_handler_timestamp type_handler_timestamp; extern MYSQL_PLUGIN_IMPORT Type_handler_timestamp2 type_handler_timestamp2; -extern MYSQL_PLUGIN_IMPORT Type_handler_tiny_blob type_handler_tiny_blob; -extern MYSQL_PLUGIN_IMPORT Type_handler_blob type_handler_blob; -extern MYSQL_PLUGIN_IMPORT Type_handler_medium_blob type_handler_medium_blob; -extern MYSQL_PLUGIN_IMPORT Type_handler_long_blob type_handler_long_blob; - extern MYSQL_PLUGIN_IMPORT Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 81ece13e1c5..2077ea52557 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6690,6 +6690,10 @@ field_spec: $$= $<create_field>2; $$->check_constraint= $4; + if (!$4 && lex->last_field->type_handler()->is_json_type() && + !($$->check_constraint= make_json_valid_expr(thd, + &$$->field_name))) + MYSQL_YYABORT; if (unlikely($$->check(thd))) MYSQL_YYABORT; @@ -7083,7 +7087,7 @@ field_type_lob: | JSON_SYM { Lex->charset= &my_charset_utf8mb4_bin; - $$.set(&type_handler_long_blob); + $$.set(&type_handler_json); } ; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index aa622b61771..4e14be598ce 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -6628,6 +6628,10 @@ field_spec: $$= $<create_field>2; $$->check_constraint= $4; + if (!$4 && lex->last_field->type_handler()->is_json_type() && + !($$->check_constraint= make_json_valid_expr(thd, + &$$->field_name))) + MYSQL_YYABORT; if (unlikely($$->check(thd))) MYSQL_YYABORT; @@ -7073,7 +7077,7 @@ field_type_lob: | JSON_SYM { Lex->charset= &my_charset_utf8mb4_bin; - $$.set(&type_handler_long_blob); + $$.set(&type_handler_json); } ; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index a8b557c90c8..ad576280d3d 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -5540,7 +5540,7 @@ static Sys_var_mybool Sys_wsrep_load_data_splitting( "wsrep_load_data_splitting", "To commit LOAD DATA " "transaction after every 10K rows inserted (deprecated)", GLOBAL_VAR(wsrep_load_data_splitting), - CMD_LINE(OPT_ARG), DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, + CMD_LINE(OPT_ARG), DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0), DEPRECATED("")); static Sys_var_mybool Sys_wsrep_slave_FK_checks( diff --git a/sql/table.cc b/sql/table.cc index d5c88b226c7..1ef216a2991 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -52,7 +52,8 @@ static Virtual_column_info * unpack_vcol_info_from_frm(THD *, MEM_ROOT *, TABLE *, String *, Virtual_column_info **, bool *); -static bool check_vcol_forward_refs(Field *, Virtual_column_info *); +static bool check_vcol_forward_refs(Field *, Virtual_column_info *, + bool check_constraint); /* INFORMATION_SCHEMA name */ LEX_CSTRING INFORMATION_SCHEMA_NAME= {STRING_WITH_LEN("information_schema")}; @@ -1189,9 +1190,9 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, for (field_ptr= table->field; *field_ptr; field_ptr++) { Field *field= *field_ptr; - if (check_vcol_forward_refs(field, field->vcol_info) || - check_vcol_forward_refs(field, field->check_constraint) || - check_vcol_forward_refs(field, field->default_value)) + if (check_vcol_forward_refs(field, field->vcol_info, 0) || + check_vcol_forward_refs(field, field->check_constraint, 1) || + check_vcol_forward_refs(field, field->default_value, 0)) goto end; } @@ -3133,11 +3134,19 @@ end: DBUG_RETURN(vcol_info); } -static bool check_vcol_forward_refs(Field *field, Virtual_column_info *vcol) +static bool check_vcol_forward_refs(Field *field, Virtual_column_info *vcol, + bool check_constraint) { - bool res= vcol && - vcol->expr->walk(&Item::check_field_expression_processor, 0, - field); + bool res; + uint32 flags= field->flags; + if (check_constraint) + { + /* Check constraints can refer it itself */ + field->flags|= NO_DEFAULT_VALUE_FLAG; + } + res= (vcol && + vcol->expr->walk(&Item::check_field_expression_processor, 0, field)); + field->flags= flags; return res; } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 401b40590df..06e713ceda0 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -2499,57 +2499,6 @@ int wsrep_ordered_commit_if_no_binlog(THD* thd, bool all) return 0; } -wsrep_status_t wsrep_tc_log_commit(THD* thd) -{ - int cookie; - my_xid xid= thd->transaction.xid_state.xid.get_my_xid(); - - DBUG_ASSERT(thd->lex->sql_command == SQLCOM_LOAD); - if (wsrep_before_commit(thd, true)) - { - WSREP_DEBUG("wsrep_tc_log_commit: wsrep_before_commit failed %llu", - thd->thread_id); - return WSREP_TRX_FAIL; - } - cookie= tc_log->log_and_order(thd, xid, 1, false, true); - if (wsrep_after_commit(thd, true)) - { - WSREP_DEBUG("wsrep_tc_log_commit: wsrep_after_commit failed %llu", - thd->thread_id); - return WSREP_TRX_FAIL; - } - if (!cookie) - { - WSREP_DEBUG("log_and_order has failed %llu %d", thd->thread_id, cookie); - return WSREP_TRX_FAIL; - } - if (tc_log->unlog(cookie, xid)) - { - WSREP_DEBUG("log_and_order has failed %llu %d", thd->thread_id, cookie); - return WSREP_TRX_FAIL; - } - - if (wsrep_after_statement(thd)) - { - return WSREP_TRX_FAIL; - } - /* Set wsrep transaction id if not set. */ - if (thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID) - { - if (thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID) - { - thd->set_wsrep_next_trx_id(thd->query_id); - } - DBUG_ASSERT(thd->wsrep_next_trx_id() != WSREP_UNDEFINED_TRX_ID); - } - if (wsrep_start_transaction(thd, thd->wsrep_next_trx_id())) - { - return WSREP_TRX_FAIL; - } - DBUG_ASSERT(thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID); - return WSREP_OK; -} - int wsrep_thd_retry_counter(const THD *thd) { return thd->wsrep_retry_counter; diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 957f1ef3ab1..3c430ccf487 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -445,15 +445,6 @@ bool wsrep_provider_is_SR_capable(); int wsrep_ordered_commit_if_no_binlog(THD*, bool); /** - * Commit the current transaction with the - * MySQL "Transaction Coordinator Log" (see `class TC_LOG` in sql/log.h). - * Calling this function will generate and assign a new wsrep transaction id - * for `thd`. - * @return WSREP_OK on success or other WSREP_* error code on failure - */ -wsrep_status_t wsrep_tc_log_commit(THD* thd); - -/** * Initialize WSREP server instance. * * @return Zero on success, non-zero on error. diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 29696f96aa0..2db08b1a537 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -4839,7 +4839,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 59704201c4e..ed9fd219d91 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -486,8 +486,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/data/data0type.cc b/storage/innobase/data/data0type.cc index 84962d097aa..0e07ca5182b 100644 --- a/storage/innobase/data/data0type.cc +++ b/storage/innobase/data/data0type.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -24,7 +24,8 @@ Data types Created 1/16/1996 Heikki Tuuri *******************************************************/ -#include "data0type.h" +#include "dict0mem.h" +#include "my_sys.h" /** The DB_TRX_ID,DB_ROLL_PTR values for "no history is available" */ const byte reset_trx_id[DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN] = { @@ -160,6 +161,22 @@ dtype_validate( return(TRUE); } +bool dict_col_t::same_charset(const dict_col_t& other) const +{ + 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)); + if (!my_charset_same(cs1, cs2)) { + return false; + } + } + + return true; +} + #ifdef UNIV_DEBUG /** Print a data type structure. @param[in] type data type */ diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 7664bc2064d..232a21b99d2 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -2203,6 +2203,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/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ee986d55f77..c50d6e05fff 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6121,6 +6121,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) @@ -9962,7 +9967,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 4af97951570..30ca3975bf6 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_EXT | INNOBASE_DEFAULTS | ALTER_STORED_COLUMN_ORDER | ALTER_DROP_STORED_COLUMN @@ -268,7 +269,7 @@ inline void dict_table_t::prepare_instant(const dict_table_t& old, ut_ad(!not_redundant()); for (unsigned i = index.n_fields; i--; ) { ut_ad(index.fields[i].col->same_format( - *oindex.fields[i].col)); + *oindex.fields[i].col, true)); } } #endif @@ -456,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()); @@ -534,10 +539,7 @@ 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->vers_sys_start()) { ut_ad(o->ind == vers_start); @@ -1505,7 +1507,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_EXT; if (!(ha_alter_info->handler_flags & avoid_rebuild)) { alter_table_operations flags = ha_alter_info->handler_flags @@ -1548,6 +1551,7 @@ instant_alter_column_possible( & ~ALTER_STORED_COLUMN_ORDER & ~ALTER_ADD_STORED_BASE_COLUMN & ~ALTER_COLUMN_NULLABLE + & ~ALTER_COLUMN_EQUAL_PACK_LENGTH_EXT & ~ALTER_OPTIONS)) { return false; } @@ -1748,6 +1752,10 @@ ha_innobase::check_if_supported_inplace_alter( { DBUG_ENTER("check_if_supported_inplace_alter"); + DBUG_ASSERT(!(ALTER_COLUMN_EQUAL_PACK_LENGTH_EXT + & ha_alter_info->handler_flags) + || !m_prebuilt->table->not_redundant()); + if ((ha_alter_info->handler_flags & INNOBASE_ALTER_VERSIONED_REBUILD) && altered_table->versioned(VERS_TIMESTAMP)) { @@ -2943,7 +2951,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 */ @@ -5583,7 +5591,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) { /* The record is already present in SYS_COLUMNS. */ @@ -5672,6 +5681,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) @@ -9050,12 +9061,16 @@ innobase_enlarge_column_try( #ifdef UNIV_DEBUG ut_ad(col->len < new_len); switch (col->mtype) { + case DATA_FIXBINARY: + case DATA_CHAR: case DATA_MYSQL: /* NOTE: we could allow this when !(prtype & DATA_BINARY_TYPE) and ROW_FORMAT is not REDUNDANT and mbminlen<mbmaxlen. That is, we treat a UTF-8 CHAR(n) column somewhat like a VARCHAR. */ - ut_error; + if (user_table->not_redundant()) { + ut_error; + } case DATA_BINARY: case DATA_VARCHAR: case DATA_VARMYSQL: @@ -9188,14 +9203,16 @@ innobase_rename_or_enlarge_columns_cache( ulint col_n = is_virtual ? num_v : i - num_v; if ((*fp)->is_equal(cf) == IS_EQUAL_PACK_LENGTH) { - if (is_virtual) { - dict_table_get_nth_v_col( - user_table, col_n)->m_col.len - = cf->length; - } else { - dict_table_get_nth_col( - user_table, col_n)->len - = cf->length; + dict_col_t *col = is_virtual ? + &dict_table_get_nth_v_col( + user_table, col_n)->m_col + : dict_table_get_nth_col( + user_table, col_n); + col->len = cf->length; + if (col->len > 255 + && (col->prtype & DATA_MYSQL_TRUE_VARCHAR) + == DATA_MYSQL_TRUE_VARCHAR) { + col->prtype |= DATA_LONG_TRUE_VARCHAR; } } diff --git a/storage/innobase/include/data0type.ic b/storage/innobase/include/data0type.ic index 56a588562ee..39f00364ea2 100644 --- a/storage/innobase/include/data0type.ic +++ b/storage/innobase/include/data0type.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -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 + earlier MariaDB versions 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..e9ffa660354 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -2,7 +2,7 @@ Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2018, MariaDB Corporation. +Copyright (c) 2013, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -682,18 +682,52 @@ public: def_val.data = NULL; } +private: + /** Determine if the columns have the same character set + @param[in] other column to compare to + @return whether the columns have the same character set */ + bool same_charset(const dict_col_t& other) const; +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 - && len >= other.len - && mbminlen == other.mbminlen - && mbmaxlen == other.mbmaxlen - && !((prtype ^ other.prtype) - & ~(DATA_NOT_NULL | DATA_VERSIONED)); + if (len < other.len + || mbminlen != other.mbminlen + || mbmaxlen != other.mbmaxlen) { + return false; + } + + if (!((prtype ^ other.prtype) + & ~(DATA_NOT_NULL | DATA_VERSIONED))) { + return mtype == other.mtype; + } + + if (redundant) { + switch (other.mtype) { + case DATA_CHAR: + case DATA_MYSQL: + case DATA_VARCHAR: + case DATA_VARMYSQL: + return (mtype == DATA_CHAR + || mtype == DATA_MYSQL + || mtype == DATA_VARCHAR + || mtype == DATA_VARMYSQL) + && same_charset(other); + case DATA_FIXBINARY: + case DATA_BINARY: + return (mtype == DATA_FIXBINARY + || mtype == DATA_BINARY) + && same_charset(other); + case DATA_INT: + return mtype == DATA_INT; + } + } + + return false; } }; diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index f1776dd07ee..6de4dda93b1 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, old_table->space->zip_size(), 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 071ef9ffd92..1e82c6b6551 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -887,10 +887,15 @@ row_create_prebuilt( == MAX_REF_PARTS);); uint temp_len = 0; for (uint i = 0; i < temp_index->n_uniq; i++) { - ulint type = temp_index->fields[i].col->mtype; - if (type == DATA_INT) { - temp_len += - temp_index->fields[i].fixed_len; + const dict_field_t& f = temp_index->fields[i]; + if (f.col->mtype == DATA_INT) { + ut_ad(f.col->len >= f.fixed_len); + /* dtype_get_fixed_size_low() returns 0 + for ROW_FORMAT=REDUNDANT */ + ut_ad(table->not_redundant() + ? f.col->len == f.fixed_len + : f.fixed_len == 0); + temp_len += f.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 215ed0fe1e9..a03a4fa4acf 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -2742,12 +2742,15 @@ row_sel_field_store_in_mysql_format_func( 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) { @@ -2835,7 +2838,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)); @@ -2857,8 +2861,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: diff --git a/wsrep-lib b/wsrep-lib -Subproject e7d72ae7f6a6995a21d743389426a963429a1ff +Subproject 20b52ff1ddc3b2f547b7081471f46dcfa5efabc |