summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2019-02-13 14:59:34 -0800
committerIgor Babaev <igor@askmonty.org>2019-02-13 14:59:34 -0800
commit7d9f45e0729ea9b2f572cfb4023b28c16ab11145 (patch)
tree040e8f220c289652612c6cda14d277435c25ac49
parent62fad4e8e964786cd1c8d675f3c071a405a8d187 (diff)
parenta081a998a62eb0663b5691d0b5c0607465f15c0f (diff)
downloadmariadb-git-bb-10.4-mdev17096.tar.gz
Merge branch '10.4' into bb-10.4-mdev17096bb-10.4-mdev17096
-rw-r--r--cmake/submodules.cmake2
-rw-r--r--cmake/wsrep.cmake6
-rw-r--r--mysql-test/main/information_schema-big.result2
-rw-r--r--mysql-test/main/type_json.result67
-rw-r--r--mysql-test/main/type_json.test35
-rw-r--r--mysql-test/suite/galera/r/galera_defaults.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_load_data_splitting.result6
-rw-r--r--mysql-test/suite/galera/r/partition.result2
-rw-r--r--mysql-test/suite/galera/t/galera_var_load_data_splitting.test3
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_load_data.result2
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result10
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_load_data.test2
-rw-r--r--mysql-test/suite/innodb/r/alter_varchar_change.result34
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_extend,utf8.rdiff29
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_extend.result235
-rw-r--r--mysql-test/suite/innodb/t/alter_varchar_change.test24
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_extend.combinations5
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_extend.test226
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_wsrep.result4
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result4
-rw-r--r--sql/field.cc66
-rw-r--r--sql/field.h2
-rw-r--r--sql/handler.h21
-rw-r--r--sql/my_json_writer.h2
-rw-r--r--sql/sql_lex.cc18
-rw-r--r--sql/sql_lex.h7
-rw-r--r--sql/sql_load.cc64
-rw-r--r--sql/sql_priv.h14
-rw-r--r--sql/sql_table.cc3
-rw-r--r--sql/sql_type.cc1
-rw-r--r--sql/sql_type.h15
-rw-r--r--sql/sql_yacc.yy6
-rw-r--r--sql/sql_yacc_ora.yy6
-rw-r--r--sql/sys_vars.cc2
-rw-r--r--sql/table.cc25
-rw-r--r--sql/wsrep_mysqld.cc51
-rw-r--r--sql/wsrep_mysqld.h9
-rw-r--r--storage/innobase/btr/btr0btr.cc4
-rw-r--r--storage/innobase/btr/btr0cur.cc10
-rw-r--r--storage/innobase/data/data0type.cc21
-rw-r--r--storage/innobase/dict/dict0dict.cc8
-rw-r--r--storage/innobase/handler/ha_innodb.cc7
-rw-r--r--storage/innobase/handler/handler0alter.cc57
-rw-r--r--storage/innobase/include/data0type.ic22
-rw-r--r--storage/innobase/include/dict0mem.h50
-rw-r--r--storage/innobase/row/row0merge.cc5
-rw-r--r--storage/innobase/row/row0mysql.cc13
-rw-r--r--storage/innobase/row/row0sel.cc10
m---------wsrep-lib0
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