summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqltest.cc2
-rw-r--r--mysql-test/main/alter_table.result60
-rw-r--r--mysql-test/main/alter_table.test31
-rw-r--r--mysql-test/main/grant2.result3
-rw-r--r--mysql-test/main/grant2.test3
-rw-r--r--mysql-test/main/rename.result66
-rw-r--r--mysql-test/main/rename.test46
-rw-r--r--mysql-test/main/statistics_close.result11
-rw-r--r--mysql-test/main/statistics_close.test18
-rw-r--r--mysql-test/main/trigger.result13
-rw-r--r--mysql-test/main/trigger.test14
-rw-r--r--mysql-test/suite/binlog_encryption/encrypted_master.test1
-rw-r--r--mysql-test/suite/binlog_encryption/encrypted_slave.test1
-rw-r--r--mysql-test/suite/binlog_encryption/testdata.opt1
-rw-r--r--mysql-test/suite/galera/r/galera_encrypt_tmp_files.result37
-rw-r--r--mysql-test/suite/galera/t/galera_encrypt_tmp_files.cnf8
-rw-r--r--mysql-test/suite/galera/t/galera_encrypt_tmp_files.test57
-rw-r--r--mysql-test/suite/galera/t/galera_var_dirty_reads.test1
-rw-r--r--mysql-test/suite/maria/lock.result11
-rw-r--r--mysql-test/suite/maria/lock.test14
-rw-r--r--mysql-test/suite/mariabackup/lock_ddl_per_table.opt1
-rw-r--r--mysql-test/suite/mariabackup/lock_ddl_per_table.test1
-rw-r--r--mysql-test/suite/mariabackup/partition_datadir.opt1
-rw-r--r--mysql-test/suite/mariabackup/partition_datadir.test1
-rw-r--r--mysql-test/suite/mariabackup/suite.opt2
-rw-r--r--mysql-test/suite/perfschema/r/partition.result10
-rw-r--r--mysql-test/suite/perfschema/t/partition.test16
-rw-r--r--mysql-test/suite/rpl/r/rename.result36
-rw-r--r--mysql-test/suite/rpl/t/rename.test33
-rw-r--r--mysql-test/suite/vcol/r/binlog.result70
-rw-r--r--mysql-test/suite/vcol/r/update_binlog.result361
-rw-r--r--mysql-test/suite/vcol/t/binlog.test55
-rw-r--r--mysql-test/suite/vcol/t/update_binlog.test14
-rw-r--r--sql/field.h2
-rw-r--r--sql/mf_iocache_encr.cc4
-rw-r--r--sql/mysqld.cc3
-rw-r--r--sql/sql_admin.cc7
-rw-r--r--sql/sql_alter.cc7
-rw-r--r--sql/sql_base.cc10
-rw-r--r--sql/sql_class.cc29
-rw-r--r--sql/sql_class.h19
-rw-r--r--sql/sql_handler.cc4
-rw-r--r--sql/sql_parse.cc70
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_statistics.cc3
-rw-r--r--sql/sql_string.cc13
-rw-r--r--sql/sql_table.cc36
-rw-r--r--sql/sql_trigger.cc7
-rw-r--r--sql/table.cc92
-rw-r--r--sql/table.h2
-rw-r--r--sql/temporary_tables.cc18
-rw-r--r--storage/archive/ha_archive.cc12
-rw-r--r--storage/innobase/btr/btr0sea.cc9
-rw-r--r--storage/innobase/buf/buf0lru.cc54
-rw-r--r--storage/innobase/dict/dict0dict.cc27
-rw-r--r--storage/innobase/fil/fil0fil.cc6
-rw-r--r--storage/innobase/include/btr0sea.h8
-rw-r--r--storage/innobase/include/buf0lru.h18
-rw-r--r--storage/innobase/log/log0crypt.cc67
-rw-r--r--storage/innobase/row/row0import.cc12
-rw-r--r--storage/innobase/row/row0mysql.cc21
-rw-r--r--storage/maria/ha_maria.cc137
-rw-r--r--storage/maria/ha_maria.h1
-rw-r--r--storage/maria/ma_blockrec.c3
-rw-r--r--storage/maria/ma_close.c2
-rw-r--r--storage/maria/ma_commit.c17
-rw-r--r--storage/maria/ma_extra.c4
-rw-r--r--storage/maria/ma_open.c4
-rw-r--r--storage/maria/ma_state.c48
-rw-r--r--storage/maria/ma_state.h2
-rw-r--r--storage/maria/ma_trnman.h65
-rw-r--r--storage/maria/maria_def.h14
-rw-r--r--storage/maria/trnman.c1
-rw-r--r--storage/maria/trnman.h3
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test2
-rw-r--r--unittest/sql/mf_iocache-t.cc72
76 files changed, 1593 insertions, 343 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index f26ea994a4c..315e180368c 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -949,6 +949,8 @@ pthread_handler_t connection_thread(void *arg)
end_thread:
cn->query_done= 1;
+ mysql_close(cn->mysql);
+ cn->mysql= 0;
mysql_thread_end();
pthread_exit(0);
return 0;
diff --git a/mysql-test/main/alter_table.result b/mysql-test/main/alter_table.result
index 5f41e0d7a08..cb5553a086c 100644
--- a/mysql-test/main/alter_table.result
+++ b/mysql-test/main/alter_table.result
@@ -2175,6 +2175,66 @@ t1 CREATE TABLE `t1` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8
DROP TABLE t1;
#
+# MDEV-15308
+# Assertion `ha_alter_info->alter_info->drop_list.elements > 0' failed
+# in ha_innodb::prepare_inplace_alter_table
+#
+CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN b;
+Warnings:
+Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN b;
+Warnings:
+Note 1091 Can't DROP INDEX `fk`; check that it exists
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b INT, c INT, KEY(c)) ENGINE=InnoDB;
+ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN c;
+Warnings:
+Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b INT, c INT, KEY c1(c)) ENGINE=InnoDB;
+ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP INDEX c1;
+Warnings:
+Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN IF EXISTS c;
+Warnings:
+Note 1091 Can't DROP INDEX `fk`; check that it exists
+Note 1091 Can't DROP COLUMN `c`; check that it exists
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+#
# End of 10.0 tests
#
#
diff --git a/mysql-test/main/alter_table.test b/mysql-test/main/alter_table.test
index 54fa4ad8c7e..aa9faf710f5 100644
--- a/mysql-test/main/alter_table.test
+++ b/mysql-test/main/alter_table.test
@@ -1804,6 +1804,37 @@ SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
+--echo # MDEV-15308
+--echo # Assertion `ha_alter_info->alter_info->drop_list.elements > 0' failed
+--echo # in ha_innodb::prepare_inplace_alter_table
+--echo #
+
+CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN b;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN b;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INT, b INT, c INT, KEY(c)) ENGINE=InnoDB;
+ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN c;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INT, b INT, c INT, KEY c1(c)) ENGINE=InnoDB;
+ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP INDEX c1;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN IF EXISTS c;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+--echo #
--echo # End of 10.0 tests
--echo #
diff --git a/mysql-test/main/grant2.result b/mysql-test/main/grant2.result
index 2ccc01d225a..d7e42f9b7aa 100644
--- a/mysql-test/main/grant2.result
+++ b/mysql-test/main/grant2.result
@@ -809,10 +809,9 @@ LOAD INDEX INTO CACHE t3;
Table Op Msg_type Msg_text
mysqltest_db1.t3 preload_keys status OK
#
-# RENAME (doesn't work for temporary tables, thus should fail).
+# RENAME should work for temporary tables
#
RENAME TABLE t3 TO t3_1;
-ERROR 42000: INSERT, CREATE command denied to user 'mysqltest_u1'@'localhost' for table 't3_1'
#
# HANDLER OPEN/READ/CLOSE.
#
diff --git a/mysql-test/main/grant2.test b/mysql-test/main/grant2.test
index 5e8a130feea..cee5df089df 100644
--- a/mysql-test/main/grant2.test
+++ b/mysql-test/main/grant2.test
@@ -873,9 +873,8 @@ CACHE INDEX t3 IN keycache1;
LOAD INDEX INTO CACHE t3;
--echo #
---echo # RENAME (doesn't work for temporary tables, thus should fail).
+--echo # RENAME should work for temporary tables
--echo #
---error ER_TABLEACCESS_DENIED_ERROR
RENAME TABLE t3 TO t3_1;
--echo #
diff --git a/mysql-test/main/rename.result b/mysql-test/main/rename.result
index ff8566abe02..3ee9dd593d4 100644
--- a/mysql-test/main/rename.result
+++ b/mysql-test/main/rename.result
@@ -78,3 +78,69 @@ ERROR HY000: 'test.v1' is not of type 'BASE TABLE'
drop view v1;
drop table t1;
End of 5.0 tests
+CREATE OR REPLACE TABLE t1 (a INT);
+CREATE OR REPLACE TABLE t2 (a INT);
+CREATE OR REPLACE TEMPORARY TABLE t1_tmp (b INT);
+CREATE OR REPLACE TEMPORARY TABLE t2_tmp (b INT);
+rename table t1 to t2;
+ERROR 42S01: Table 't2' already exists
+rename table t1 to tmp, tmp to t2;
+ERROR 42S01: Table 't2' already exists
+rename table t1_tmp to t2_tmp;
+ERROR 42S01: Table 't2_tmp' already exists
+rename table t1_tmp to tmp, tmp to t2_tmp;
+ERROR 42S01: Table 't2_tmp' already exists
+show create table t1_tmp;
+Table Create Table
+t1_tmp CREATE TEMPORARY TABLE `t1_tmp` (
+ `b` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show create table t2_tmp;
+Table Create Table
+t2_tmp CREATE TEMPORARY TABLE `t2_tmp` (
+ `b` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+rename table t1 to t1_tmp;
+rename table t2_tmp to t2;
+rename table t2 to tmp, tmp to t2;
+rename table t1_tmp to tmp, tmp to t1_tmp;
+show tables;
+Tables_in_test
+t1_tmp
+t2
+SHOW CREATE TABLE t1_tmp;
+Table Create Table
+t1_tmp CREATE TEMPORARY TABLE `t1_tmp` (
+ `b` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1_tmp;
+SHOW CREATE TABLE t1_tmp;
+Table Create Table
+t1_tmp CREATE TABLE `t1_tmp` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1_tmp;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TEMPORARY TABLE `t2` (
+ `b` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t2;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t2;
+CREATE TABLE t1 (a INT);
+insert into t1 values (1);
+CREATE TEMPORARY TABLE t1 (b INT);
+insert into t1 values (2);
+RENAME TABLE t1 TO tmp, t1 TO t2;
+select * from tmp;
+b
+2
+select * from t2;
+a
+1
+drop table tmp,t2;
diff --git a/mysql-test/main/rename.test b/mysql-test/main/rename.test
index a55bc845acc..67732d5b5b9 100644
--- a/mysql-test/main/rename.test
+++ b/mysql-test/main/rename.test
@@ -95,3 +95,49 @@ drop table t1;
--source include/wait_until_count_sessions.inc
+#
+# Test of rename with temporary tables
+#
+
+CREATE OR REPLACE TABLE t1 (a INT);
+CREATE OR REPLACE TABLE t2 (a INT);
+CREATE OR REPLACE TEMPORARY TABLE t1_tmp (b INT);
+CREATE OR REPLACE TEMPORARY TABLE t2_tmp (b INT);
+
+# Can't rename table over another one
+--error ER_TABLE_EXISTS_ERROR
+rename table t1 to t2;
+--error ER_TABLE_EXISTS_ERROR
+rename table t1 to tmp, tmp to t2;
+--error ER_TABLE_EXISTS_ERROR
+rename table t1_tmp to t2_tmp;
+--error ER_TABLE_EXISTS_ERROR
+rename table t1_tmp to tmp, tmp to t2_tmp;
+
+show create table t1_tmp;
+show create table t2_tmp;
+
+# The following should work
+rename table t1 to t1_tmp;
+rename table t2_tmp to t2;
+rename table t2 to tmp, tmp to t2;
+rename table t1_tmp to tmp, tmp to t1_tmp;
+show tables;
+SHOW CREATE TABLE t1_tmp;
+drop table t1_tmp;
+SHOW CREATE TABLE t1_tmp;
+drop table t1_tmp;
+SHOW CREATE TABLE t2;
+drop table t2;
+SHOW CREATE TABLE t2;
+drop table t2;
+
+CREATE TABLE t1 (a INT);
+insert into t1 values (1);
+CREATE TEMPORARY TABLE t1 (b INT);
+insert into t1 values (2);
+RENAME TABLE t1 TO tmp, t1 TO t2;
+select * from tmp;
+select * from t2;
+drop table tmp,t2;
+
diff --git a/mysql-test/main/statistics_close.result b/mysql-test/main/statistics_close.result
new file mode 100644
index 00000000000..d7f76e304e4
--- /dev/null
+++ b/mysql-test/main/statistics_close.result
@@ -0,0 +1,11 @@
+CREATE TABLE t1 (i int);
+connect con1,localhost,root,,test;
+RENAME TABLE t1 TO t2;
+connection default;
+FLUSH TABLES;
+connection con1;
+disconnect con1;
+connection default;
+DROP TABLE IF EXISTS t1, t2;
+Warnings:
+Note 1051 Unknown table 'test.t1'
diff --git a/mysql-test/main/statistics_close.test b/mysql-test/main/statistics_close.test
new file mode 100644
index 00000000000..de22a5a44fe
--- /dev/null
+++ b/mysql-test/main/statistics_close.test
@@ -0,0 +1,18 @@
+#
+# MDEV-16123 ASAN heap-use-after-free handler::ha_index_or_rnd_end
+# MDEV-13828 Segmentation fault on RENAME TABLE
+#
+
+CREATE TABLE t1 (i int);
+--connect (con1,localhost,root,,test)
+--send
+RENAME TABLE t1 TO t2;
+--connection default
+FLUSH TABLES;
+--connection con1
+--reap
+
+# Cleanup
+--disconnect con1
+--connection default
+DROP TABLE IF EXISTS t1, t2;
diff --git a/mysql-test/main/trigger.result b/mysql-test/main/trigger.result
index 8473b3bb90d..537f86e9f40 100644
--- a/mysql-test/main/trigger.result
+++ b/mysql-test/main/trigger.result
@@ -2345,7 +2345,18 @@ CREATE TABLE t1 (i INT);
insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
-End of 10.1 tests.
+#
+# MDEV-16093
+# Assertion `global_status_var.global_memory_used == 0' failed or
+# bytes lost after inserting into table with non-null blob and trigger
+#
+CREATE TABLE t1 (b BLOB NOT NULL);
+CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END;
+INSERT INTO t1 VALUES ('foo');
+DROP TABLE t1;
+#
+# End of 10.1 tests.
+#
create table t1 (i int);
create trigger tr1 after insert on t1 for each row set @a=@a+1;
create trigger tr2 after insert on t1 for each row set @a=@a+1;
diff --git a/mysql-test/main/trigger.test b/mysql-test/main/trigger.test
index 1557ef200e5..020117e046f 100644
--- a/mysql-test/main/trigger.test
+++ b/mysql-test/main/trigger.test
@@ -2665,8 +2665,20 @@ insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
+--echo #
+--echo # MDEV-16093
+--echo # Assertion `global_status_var.global_memory_used == 0' failed or
+--echo # bytes lost after inserting into table with non-null blob and trigger
+--echo #
+
+CREATE TABLE t1 (b BLOB NOT NULL);
+CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END;
+INSERT INTO t1 VALUES ('foo');
+DROP TABLE t1;
---echo End of 10.1 tests.
+--echo #
+--echo # End of 10.1 tests.
+--echo #
#
# MDEV-10915 Count number of executed triggers
diff --git a/mysql-test/suite/binlog_encryption/encrypted_master.test b/mysql-test/suite/binlog_encryption/encrypted_master.test
index 503a40443d2..f67e93ce815 100644
--- a/mysql-test/suite/binlog_encryption/encrypted_master.test
+++ b/mysql-test/suite/binlog_encryption/encrypted_master.test
@@ -18,6 +18,7 @@
# - with annotated events, default checksums and minimal binlog row image
#
+--source include/have_partition.inc
--source encryption_algorithms.inc
--source include/have_innodb.inc
--enable_connect_log
diff --git a/mysql-test/suite/binlog_encryption/encrypted_slave.test b/mysql-test/suite/binlog_encryption/encrypted_slave.test
index f5697d91779..94777957b92 100644
--- a/mysql-test/suite/binlog_encryption/encrypted_slave.test
+++ b/mysql-test/suite/binlog_encryption/encrypted_slave.test
@@ -9,6 +9,7 @@
# relay logs and binary logs are encrypted on slave.
#
+--source include/have_partition.inc
--source encryption_algorithms.inc
--source include/have_innodb.inc
diff --git a/mysql-test/suite/binlog_encryption/testdata.opt b/mysql-test/suite/binlog_encryption/testdata.opt
deleted file mode 100644
index b0c5b9c8188..00000000000
--- a/mysql-test/suite/binlog_encryption/testdata.opt
+++ /dev/null
@@ -1 +0,0 @@
---partition
diff --git a/mysql-test/suite/galera/r/galera_encrypt_tmp_files.result b/mysql-test/suite/galera/r/galera_encrypt_tmp_files.result
new file mode 100644
index 00000000000..38480d186ba
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_encrypt_tmp_files.result
@@ -0,0 +1,37 @@
+SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+VARIABLE_VALUE = 'Synced'
+1
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+INSERT INTO t1 VALUES (1);
+connection node_2;
+SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+VARIABLE_VALUE = 'Synced'
+1
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
+connection node_1;
+CREATE TABLE `t1` (
+`col1` int(11) NOT NULL,
+`col2` varchar(64) NOT NULL DEFAULT '',
+`col3` varchar(32) NOT NULL DEFAULT '0',
+`col4` varchar(64) NOT NULL DEFAULT '',
+`col5` tinyint(4) NOT NULL DEFAULT '0',
+`col6` int(11) NOT NULL DEFAULT '0',
+`col7` varchar(64) NOT NULL DEFAULT '',
+`col8` tinyint(4) NOT NULL DEFAULT '0',
+`col9` tinyint(4) NOT NULL DEFAULT '0',
+`col10` text NOT NULL,
+`col11` varchar(255) NOT NULL DEFAULT '',
+`col12` tinyint(4) NOT NULL DEFAULT '1'
+) ;
+create table t2 (test int);
+insert into t2 values (1);
+drop table t1,t2;
diff --git a/mysql-test/suite/galera/t/galera_encrypt_tmp_files.cnf b/mysql-test/suite/galera/t/galera_encrypt_tmp_files.cnf
new file mode 100644
index 00000000000..0f7f80b7d0b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_encrypt_tmp_files.cnf
@@ -0,0 +1,8 @@
+!include ../galera_2nodes.cnf
+[mysqld]
+
+encrypt-tmp-files = 1
+plugin-load-add= @ENV.FILE_KEY_MANAGEMENT_SO
+file-key-management
+loose-file-key-management-filename= @ENV.MYSQL_TEST_DIR/std_data/keys.txt
+log-bin
diff --git a/mysql-test/suite/galera/t/galera_encrypt_tmp_files.test b/mysql-test/suite/galera/t/galera_encrypt_tmp_files.test
new file mode 100644
index 00000000000..c42c3dbd98a
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_encrypt_tmp_files.test
@@ -0,0 +1,57 @@
+# This file tests that mariadb cluster should not crash when encrypt_tmp_file
+# is enabled
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+SELECT COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
+
+--connection node_1
+
+CREATE TABLE `t1` (
+ `col1` int(11) NOT NULL,
+ `col2` varchar(64) NOT NULL DEFAULT '',
+ `col3` varchar(32) NOT NULL DEFAULT '0',
+ `col4` varchar(64) NOT NULL DEFAULT '',
+ `col5` tinyint(4) NOT NULL DEFAULT '0',
+ `col6` int(11) NOT NULL DEFAULT '0',
+ `col7` varchar(64) NOT NULL DEFAULT '',
+ `col8` tinyint(4) NOT NULL DEFAULT '0',
+ `col9` tinyint(4) NOT NULL DEFAULT '0',
+ `col10` text NOT NULL,
+ `col11` varchar(255) NOT NULL DEFAULT '',
+ `col12` tinyint(4) NOT NULL DEFAULT '1'
+) ;
+
+#Although we just need $counter >= 907 for IO_CACHE to use
+#encrypted temp file. Just on safe side I am using $counter
+# = 1100
+--disable_query_log
+--let $counter=1100
+--let $query= (1,'test','test','test',0,0,'-1',0,0,'','',-1)
+while($counter)
+{
+ --let $query= $query ,(1,'test','test','test',0,0,'-1',0,0,'','',-1)
+ --dec $counter
+}
+--let $query= INSERT INTO t1 values $query ;
+--eval $query
+--enable_query_log
+#INSERT INTO `t1` VALUE
+
+create table t2 (test int);
+insert into t2 values (1);
+
+drop table t1,t2;
diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
index 138b7c1c703..3e2108868af 100644
--- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test
+++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
@@ -4,6 +4,7 @@
--source include/galera_cluster.inc
--source include/have_innodb.inc
+--source include/have_perfschema.inc
# Save original auto_increment_offset values.
--let $node_1=node_1
diff --git a/mysql-test/suite/maria/lock.result b/mysql-test/suite/maria/lock.result
index 99f76e6115c..660f64070ca 100644
--- a/mysql-test/suite/maria/lock.result
+++ b/mysql-test/suite/maria/lock.result
@@ -100,6 +100,17 @@ f2
unlock tables;
DROP TABLE t1,t2,tmp;
#
+# MDEV-10378 Assertion `trn' failed in virtual int ha_maria::start_stmt
+#
+CREATE TABLE t1 (f1 VARCHAR(3), f2 INT, pk INT, PRIMARY KEY (pk)) ENGINE=Aria;
+INSERT INTO t1 VALUES ('foo',10,1), ('foo',1,2);
+LOCK TABLE t1 WRITE;
+ALTER TABLE t1 ADD UNIQUE KEY (f1);
+ERROR 23000: Duplicate entry 'foo' for key 'f1'
+ALTER TABLE t1 ADD KEY (f2);
+DROP TABLE t1;
+# End of 10.2 tests
+#
# MDEV-14669 Assertion `file->trn == trn' failed in ha_maria::start_stmt
#
CREATE TABLE t1 (i INT) ENGINE=Aria;
diff --git a/mysql-test/suite/maria/lock.test b/mysql-test/suite/maria/lock.test
index be9ec7f6bf6..37356a359d8 100644
--- a/mysql-test/suite/maria/lock.test
+++ b/mysql-test/suite/maria/lock.test
@@ -107,6 +107,20 @@ unlock tables;
DROP TABLE t1,t2,tmp;
--echo #
+--echo # MDEV-10378 Assertion `trn' failed in virtual int ha_maria::start_stmt
+--echo #
+
+CREATE TABLE t1 (f1 VARCHAR(3), f2 INT, pk INT, PRIMARY KEY (pk)) ENGINE=Aria;
+INSERT INTO t1 VALUES ('foo',10,1), ('foo',1,2);
+LOCK TABLE t1 WRITE;
+--error ER_DUP_ENTRY
+ALTER TABLE t1 ADD UNIQUE KEY (f1);
+ALTER TABLE t1 ADD KEY (f2);
+DROP TABLE t1;
+
+--echo # End of 10.2 tests
+
+--echo #
--echo # MDEV-14669 Assertion `file->trn == trn' failed in ha_maria::start_stmt
--echo #
diff --git a/mysql-test/suite/mariabackup/lock_ddl_per_table.opt b/mysql-test/suite/mariabackup/lock_ddl_per_table.opt
new file mode 100644
index 00000000000..bbb6d7f9ff4
--- /dev/null
+++ b/mysql-test/suite/mariabackup/lock_ddl_per_table.opt
@@ -0,0 +1 @@
+--loose-partition
diff --git a/mysql-test/suite/mariabackup/lock_ddl_per_table.test b/mysql-test/suite/mariabackup/lock_ddl_per_table.test
index 04edb9e05e9..2689508e554 100644
--- a/mysql-test/suite/mariabackup/lock_ddl_per_table.test
+++ b/mysql-test/suite/mariabackup/lock_ddl_per_table.test
@@ -1,4 +1,5 @@
--source include/have_debug.inc
+--source include/have_partition.inc
CREATE TABLE t(i INT) ENGINE INNODB;
INSERT INTO t VALUES(1);
diff --git a/mysql-test/suite/mariabackup/partition_datadir.opt b/mysql-test/suite/mariabackup/partition_datadir.opt
deleted file mode 100644
index 8a3240370eb..00000000000
--- a/mysql-test/suite/mariabackup/partition_datadir.opt
+++ /dev/null
@@ -1 +0,0 @@
---partition \ No newline at end of file
diff --git a/mysql-test/suite/mariabackup/partition_datadir.test b/mysql-test/suite/mariabackup/partition_datadir.test
index 882b0111267..c525d34a02c 100644
--- a/mysql-test/suite/mariabackup/partition_datadir.test
+++ b/mysql-test/suite/mariabackup/partition_datadir.test
@@ -1,3 +1,4 @@
+--source include/have_partition.inc
let $targetdir=$MYSQLTEST_VARDIR/backup;
mkdir $targetdir;
mkdir $MYSQLTEST_VARDIR/partitdata;
diff --git a/mysql-test/suite/mariabackup/suite.opt b/mysql-test/suite/mariabackup/suite.opt
index 752a2e41983..3b5cc4f4c45 100644
--- a/mysql-test/suite/mariabackup/suite.opt
+++ b/mysql-test/suite/mariabackup/suite.opt
@@ -1 +1 @@
---innodb --loose-changed_page_bitmaps --innodb-sys-tables --partition
+--innodb --loose-changed_page_bitmaps --innodb-sys-tables
diff --git a/mysql-test/suite/perfschema/r/partition.result b/mysql-test/suite/perfschema/r/partition.result
new file mode 100644
index 00000000000..9bc624268bb
--- /dev/null
+++ b/mysql-test/suite/perfschema/r/partition.result
@@ -0,0 +1,10 @@
+#
+# MDEV-10679
+# Server crashes in in mysql_create_frm_image upon query from
+# performance schema in ps-protocol mode
+#
+CREATE TABLE t1 (i INT);
+ALTER TABLE t1 ADD PARTITION (PARTITION p VALUES LESS THAN (1));
+ERROR HY000: Partition management on a not partitioned table is not possible
+SELECT * FROM performance_schema.events_stages_summary_by_user_by_event_name;
+DROP TABLE t1;
diff --git a/mysql-test/suite/perfschema/t/partition.test b/mysql-test/suite/perfschema/t/partition.test
new file mode 100644
index 00000000000..0b3b204dee7
--- /dev/null
+++ b/mysql-test/suite/perfschema/t/partition.test
@@ -0,0 +1,16 @@
+--source include/have_perfschema.inc
+--source include/have_partition.inc
+
+--echo #
+--echo # MDEV-10679
+--echo # Server crashes in in mysql_create_frm_image upon query from
+--echo # performance schema in ps-protocol mode
+--echo #
+
+CREATE TABLE t1 (i INT);
+--error ER_PARTITION_MGMT_ON_NONPARTITIONED
+ALTER TABLE t1 ADD PARTITION (PARTITION p VALUES LESS THAN (1));
+--disable_result_log
+SELECT * FROM performance_schema.events_stages_summary_by_user_by_event_name;
+--enable_result_log
+DROP TABLE t1;
diff --git a/mysql-test/suite/rpl/r/rename.result b/mysql-test/suite/rpl/r/rename.result
new file mode 100644
index 00000000000..8220ae1f3b1
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rename.result
@@ -0,0 +1,36 @@
+include/master-slave.inc
+[connection master]
+#
+# MDEV-16229 Replication aborts with ER_VIEW_SELECT_TMPTABLE after
+# half-failed RENAME
+#
+CREATE TABLE t1 (a INT);
+CREATE TEMPORARY TABLE t1 (b INT);
+RENAME TABLE t1 TO tmp, tmp TO t1;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TEMPORARY TABLE `t1` (
+ `b` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+CREATE VIEW v AS SELECT * FROM t1;
+ERROR HY000: View's SELECT refers to a temporary table 't1'
+RENAME TABLE t1 TO tmp, t1 TO t2;
+SHOW CREATE TABLE tmp;
+Table Create Table
+tmp CREATE TEMPORARY TABLE `tmp` (
+ `b` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+CREATE VIEW v AS SELECT * FROM tmp;
+ERROR HY000: View's SELECT refers to a temporary table 'tmp'
+CREATE VIEW v AS SELECT * FROM t2;
+connection slave;
+connection master;
+DROP VIEW v;
+DROP TABLE tmp;
+DROP TABLE t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rename.test b/mysql-test/suite/rpl/t/rename.test
new file mode 100644
index 00000000000..ac499157918
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rename.test
@@ -0,0 +1,33 @@
+--source include/have_binlog_format_mixed.inc
+--source include/master-slave.inc
+
+--echo #
+--echo # MDEV-16229 Replication aborts with ER_VIEW_SELECT_TMPTABLE after
+--echo # half-failed RENAME
+--echo #
+
+CREATE TABLE t1 (a INT);
+CREATE TEMPORARY TABLE t1 (b INT);
+RENAME TABLE t1 TO tmp, tmp TO t1;
+SHOW CREATE TABLE t1;
+--error ER_VIEW_SELECT_TMPTABLE
+CREATE VIEW v AS SELECT * FROM t1;
+
+RENAME TABLE t1 TO tmp, t1 TO t2;
+SHOW CREATE TABLE tmp;
+SHOW CREATE TABLE t2;
+--error ER_VIEW_SELECT_TMPTABLE
+CREATE VIEW v AS SELECT * FROM tmp;
+CREATE VIEW v AS SELECT * FROM t2;
+
+--sync_slave_with_master
+
+# Cleanup
+
+--connection master
+
+DROP VIEW v;
+DROP TABLE tmp;
+DROP TABLE t2;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/vcol/r/binlog.result b/mysql-test/suite/vcol/r/binlog.result
new file mode 100644
index 00000000000..35bfb50ba2f
--- /dev/null
+++ b/mysql-test/suite/vcol/r/binlog.result
@@ -0,0 +1,70 @@
+include/master-slave.inc
+[connection master]
+CREATE TABLE t1 (
+pk SERIAL,
+vcol_date DATE AS (col_date) PERSISTENT,
+vcol_int INT AS (col_int) VIRTUAL,
+vcol_year YEAR AS (col_year) PERSISTENT,
+vcol_blob BLOB AS (col_blob) VIRTUAL,
+col_date DATE,
+col_int INT NULL,
+col_blob BLOB NULL,
+col_year YEAR,
+PRIMARY KEY(pk)
+) ENGINE=InnoDB;
+INSERT INTO t1 (col_date,col_int,col_blob,col_year) VALUES ('2010-04-24',5,'foo',1981);
+SET SQL_MODE='';
+set binlog_row_image="FULL";
+CREATE VIEW v1 AS SELECT * FROM t1;
+REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1982 FROM t1;
+Warnings:
+Warning 1906 The value specified for generated column 'vcol_date' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_int' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_year' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_blob' in table 't1' ignored
+select col_date,col_int,col_blob,col_year from v1;
+col_date col_int col_blob col_year
+2010-04-24 5 foo 1982
+connection slave;
+select col_date,col_int,col_blob,col_year from v1;
+col_date col_int col_blob col_year
+2010-04-24 5 foo 1982
+connection master;
+DROP VIEW v1;
+set binlog_row_image="MINIMAL";
+CREATE VIEW v1 AS SELECT * FROM t1;
+REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1983 FROM t1;
+Warnings:
+Warning 1906 The value specified for generated column 'vcol_date' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_int' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_year' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_blob' in table 't1' ignored
+select col_date,col_int,col_blob,col_year from v1;
+col_date col_int col_blob col_year
+2010-04-24 5 foo 1983
+connection slave;
+select col_date,col_int,col_blob,col_year from v1;
+col_date col_int col_blob col_year
+2010-04-24 5 foo 1983
+connection master;
+DROP VIEW v1;
+set @@binlog_row_image="NOBLOB";
+CREATE VIEW v1 AS SELECT * FROM t1;
+REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1984 FROM t1;
+Warnings:
+Warning 1906 The value specified for generated column 'vcol_date' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_int' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_year' in table 't1' ignored
+Warning 1906 The value specified for generated column 'vcol_blob' in table 't1' ignored
+select col_date,col_int,col_blob,col_year from v1;
+col_date col_int col_blob col_year
+2010-04-24 5 foo 1984
+connection slave;
+select col_date,col_int,col_blob,col_year from v1;
+col_date col_int col_blob col_year
+2010-04-24 5 foo 1984
+connection master;
+DROP VIEW v1;
+set @@binlog_row_image=default;
+DROP TABLE t1;
+include/rpl_end.inc
diff --git a/mysql-test/suite/vcol/r/update_binlog.result b/mysql-test/suite/vcol/r/update_binlog.result
new file mode 100644
index 00000000000..d4102fc460a
--- /dev/null
+++ b/mysql-test/suite/vcol/r/update_binlog.result
@@ -0,0 +1,361 @@
+set binlog_row_image="FULL";
+set @@default_storage_engine="myisam";
+create table t1 (a int, b int as (a+1), c int as (b+1) stored);
+insert t1 set a=1;
+select * from t1;
+a b c
+1 2 3
+update t1 set a=2;
+select * from t1;
+a b c
+2 3 4
+drop table t1;
+create table t1 (a int, c int as(a), p varchar(20) as(y), y char(20), index (p,c));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `c` int(11) GENERATED ALWAYS AS (`a`) VIRTUAL,
+ `p` varchar(20) GENERATED ALWAYS AS (`y`) VIRTUAL,
+ `y` char(20) DEFAULT NULL,
+ KEY `p` (`p`,`c`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+insert into t1 (a,y) values(1, "yyy");
+update t1 set a = 100 where a = 1;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (
+a varchar(10000),
+b varchar(3000),
+c varchar(14000) generated always as (concat(a,b)) virtual,
+d varchar(5000) generated always as (b) virtual,
+e int(11) generated always as (10) virtual,
+h int(11) not null primary key,
+index(c(100), d(20)));
+insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
+update t1 set a = repeat(cast(1 as char), 2000);
+drop table t1;
+create table t1 (
+a varchar(10000),
+b varchar(3000),
+c varchar(14000) generated always as (concat(a,b)) virtual,
+i varchar(5000) generated always as (b) virtual,
+d varchar(5000) generated always as (i) virtual,
+e int(11) generated always as (10) virtual,
+h int(11) not null primary key,
+index(c(100), d(20)));
+insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
+update t1 set a = repeat(cast(1 as char), 2000);
+drop table t1;
+create table t1(a blob not null, b int, c varbinary (10) generated always as (a) virtual, unique (c(9)));
+insert t1 (a,b) values ('a', 1);
+replace t1 set a = 'a',b =1;
+insert t1 (a,b) values ('a', 1) on duplicate key update a='b', b=2;
+select * from t1;
+a b c
+b 2 b
+drop table t1;
+create table t (a int primary key, b int, c int as (b), index (c));
+insert t (a,b) values (9,0);
+create table t2 select * from t;
+update t, t2 set t.b=10 where t.a=t2.a;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c
+9 10 10
+drop table t, t2;
+create table t1 (a int, b int, c int, d int, e int);
+insert t1 values (1,2,3,4,5), (1,2,3,4,5);
+SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR
+create table t (a int primary key,
+b int, c blob as (b), index (c(57)),
+d blob, e blob as (d), index (e(57)))
+replace select * from t1;
+Warnings:
+Warning 1906 The value specified for generated column 'c' in table 't' ignored
+Warning 1906 The value specified for generated column 'e' in table 't' ignored
+Warning 1906 The value specified for generated column 'c' in table 't' ignored
+Warning 1906 The value specified for generated column 'e' in table 't' ignored
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+1 2 2 4 4
+update t set a=10, b=1, d=1;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 1 1 1 1
+replace t (a,b,d) values (10,2,2);
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 2 2 2 2
+insert t(a,b,d) values (10) on duplicate key update b=3;
+ERROR 21S01: Column count doesn't match value count at row 1
+insert t(a,b,d) values (10,2,2) on duplicate key update b=3, d=3;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 3 3 3 3
+replace t (a,b,d) select 10,4,4;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 4 4 4 4
+insert t(a,b,d) select 10,4,4 on duplicate key update b=5, d=5;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 5 5 5 5
+replace delayed t (a,b,d) values (10,6,6);
+flush tables;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 6 6 6 6
+insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
+flush tables;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 7 7 7 7
+load data infile 'MYSQLTEST_VARDIR/tmp/vblobs.txt' replace into table t;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 8 8 8 8
+update t set a=11, b=9, d=9 where a>5;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+11 9 9 9 9
+create table t2 select * from t;
+update t, t2 set t.b=10, t.d=10 where t.a=t2.a;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+11 10 10 10 10
+update t, t tt set t.b=11, tt.d=11 where t.a=tt.a;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+11 11 11 11 11
+drop table t, t1, t2;
+create table t (f1 int, f2 int, f3 int as (f1*2) virtual, key(f3,f2));
+insert into t (f1,f2) values (1,1),(2,2);
+create view v as
+select a2.f1, a2.f2, a1.f3
+from t a1, t a2
+where a2.f3 <> 0
+with local check option;
+update v set f3 = 52;
+drop view v;
+drop table t;
+set binlog_row_image="MINIMAL";
+create table t1 (a int, b int as (a+1), c int as (b+1) stored);
+insert t1 set a=1;
+select * from t1;
+a b c
+1 2 3
+update t1 set a=2;
+select * from t1;
+a b c
+2 3 4
+drop table t1;
+create table t1 (a int, c int as(a), p varchar(20) as(y), y char(20), index (p,c));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `c` int(11) GENERATED ALWAYS AS (`a`) VIRTUAL,
+ `p` varchar(20) GENERATED ALWAYS AS (`y`) VIRTUAL,
+ `y` char(20) DEFAULT NULL,
+ KEY `p` (`p`,`c`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+insert into t1 (a,y) values(1, "yyy");
+update t1 set a = 100 where a = 1;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (
+a varchar(10000),
+b varchar(3000),
+c varchar(14000) generated always as (concat(a,b)) virtual,
+d varchar(5000) generated always as (b) virtual,
+e int(11) generated always as (10) virtual,
+h int(11) not null primary key,
+index(c(100), d(20)));
+insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
+update t1 set a = repeat(cast(1 as char), 2000);
+drop table t1;
+create table t1 (
+a varchar(10000),
+b varchar(3000),
+c varchar(14000) generated always as (concat(a,b)) virtual,
+i varchar(5000) generated always as (b) virtual,
+d varchar(5000) generated always as (i) virtual,
+e int(11) generated always as (10) virtual,
+h int(11) not null primary key,
+index(c(100), d(20)));
+insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
+update t1 set a = repeat(cast(1 as char), 2000);
+drop table t1;
+create table t1(a blob not null, b int, c varbinary (10) generated always as (a) virtual, unique (c(9)));
+insert t1 (a,b) values ('a', 1);
+replace t1 set a = 'a',b =1;
+insert t1 (a,b) values ('a', 1) on duplicate key update a='b', b=2;
+select * from t1;
+a b c
+b 2 b
+drop table t1;
+create table t (a int primary key, b int, c int as (b), index (c));
+insert t (a,b) values (9,0);
+create table t2 select * from t;
+update t, t2 set t.b=10 where t.a=t2.a;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c
+9 10 10
+drop table t, t2;
+create table t1 (a int, b int, c int, d int, e int);
+insert t1 values (1,2,3,4,5), (1,2,3,4,5);
+SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR
+create table t (a int primary key,
+b int, c blob as (b), index (c(57)),
+d blob, e blob as (d), index (e(57)))
+replace select * from t1;
+Warnings:
+Warning 1906 The value specified for generated column 'c' in table 't' ignored
+Warning 1906 The value specified for generated column 'e' in table 't' ignored
+Warning 1906 The value specified for generated column 'c' in table 't' ignored
+Warning 1906 The value specified for generated column 'e' in table 't' ignored
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+1 2 2 4 4
+update t set a=10, b=1, d=1;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 1 1 1 1
+replace t (a,b,d) values (10,2,2);
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 2 2 2 2
+insert t(a,b,d) values (10) on duplicate key update b=3;
+ERROR 21S01: Column count doesn't match value count at row 1
+insert t(a,b,d) values (10,2,2) on duplicate key update b=3, d=3;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 3 3 3 3
+replace t (a,b,d) select 10,4,4;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 4 4 4 4
+insert t(a,b,d) select 10,4,4 on duplicate key update b=5, d=5;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 5 5 5 5
+replace delayed t (a,b,d) values (10,6,6);
+flush tables;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 6 6 6 6
+insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
+flush tables;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 7 7 7 7
+load data infile 'MYSQLTEST_VARDIR/tmp/vblobs.txt' replace into table t;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+10 8 8 8 8
+update t set a=11, b=9, d=9 where a>5;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+11 9 9 9 9
+create table t2 select * from t;
+update t, t2 set t.b=10, t.d=10 where t.a=t2.a;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+11 10 10 10 10
+update t, t tt set t.b=11, tt.d=11 where t.a=tt.a;
+check table t;
+Table Op Msg_type Msg_text
+test.t check status OK
+select * from t;
+a b c d e
+11 11 11 11 11
+drop table t, t1, t2;
+create table t (f1 int, f2 int, f3 int as (f1*2) virtual, key(f3,f2));
+insert into t (f1,f2) values (1,1),(2,2);
+create view v as
+select a2.f1, a2.f2, a1.f3
+from t a1, t a2
+where a2.f3 <> 0
+with local check option;
+update v set f3 = 52;
+drop view v;
+drop table t;
diff --git a/mysql-test/suite/vcol/t/binlog.test b/mysql-test/suite/vcol/t/binlog.test
new file mode 100644
index 00000000000..95bb4df4cc5
--- /dev/null
+++ b/mysql-test/suite/vcol/t/binlog.test
@@ -0,0 +1,55 @@
+--source include/have_innodb.inc
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+
+#
+# MDEV-15243
+# Server crashes in in Field_blob::pack upon REPLACE into view with virtual
+# columns with binlog enabled
+#
+
+CREATE TABLE t1 (
+ pk SERIAL,
+ vcol_date DATE AS (col_date) PERSISTENT,
+ vcol_int INT AS (col_int) VIRTUAL,
+ vcol_year YEAR AS (col_year) PERSISTENT,
+ vcol_blob BLOB AS (col_blob) VIRTUAL,
+ col_date DATE,
+ col_int INT NULL,
+ col_blob BLOB NULL,
+ col_year YEAR,
+ PRIMARY KEY(pk)
+) ENGINE=InnoDB;
+
+INSERT INTO t1 (col_date,col_int,col_blob,col_year) VALUES ('2010-04-24',5,'foo',1981);
+SET SQL_MODE='';
+
+set binlog_row_image="FULL";
+CREATE VIEW v1 AS SELECT * FROM t1;
+REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1982 FROM t1;
+select col_date,col_int,col_blob,col_year from v1;
+sync_slave_with_master;
+select col_date,col_int,col_blob,col_year from v1;
+connection master;
+DROP VIEW v1;
+set binlog_row_image="MINIMAL";
+CREATE VIEW v1 AS SELECT * FROM t1;
+REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1983 FROM t1;
+select col_date,col_int,col_blob,col_year from v1;
+sync_slave_with_master;
+select col_date,col_int,col_blob,col_year from v1;
+connection master;
+DROP VIEW v1;
+set @@binlog_row_image="NOBLOB";
+CREATE VIEW v1 AS SELECT * FROM t1;
+REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1984 FROM t1;
+select col_date,col_int,col_blob,col_year from v1;
+sync_slave_with_master;
+select col_date,col_int,col_blob,col_year from v1;
+connection master;
+DROP VIEW v1;
+set @@binlog_row_image=default;
+
+DROP TABLE t1;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/vcol/t/update_binlog.test b/mysql-test/suite/vcol/t/update_binlog.test
new file mode 100644
index 00000000000..458aac480c7
--- /dev/null
+++ b/mysql-test/suite/vcol/t/update_binlog.test
@@ -0,0 +1,14 @@
+#
+# Check that vcol update works with binlog enabled
+#
+
+--source include/have_binlog_format_row.inc
+
+set binlog_row_image="FULL";
+set @@default_storage_engine="myisam";
+
+--source update.test
+
+set binlog_row_image="MINIMAL";
+
+--source update.test
diff --git a/sql/field.h b/sql/field.h
index 99da0cf624f..2079c90037a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -3662,7 +3662,7 @@ public:
DBUG_ASSERT(number < UINT_MAX32);
store_length(ptr, packlength, (uint32)number);
}
- inline uint32 get_length(uint row_offset= 0) const
+ inline uint32 get_length(my_ptrdiff_t row_offset= 0) const
{ return get_length(ptr+row_offset, this->packlength); }
uint32 get_length(const uchar *ptr, uint packlength) const;
uint32 get_length(const uchar *ptr_arg) const
diff --git a/sql/mf_iocache_encr.cc b/sql/mf_iocache_encr.cc
index 9724ca4e19e..d2e6d554ba7 100644
--- a/sql/mf_iocache_encr.cc
+++ b/sql/mf_iocache_encr.cc
@@ -49,8 +49,8 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count)
if (pos_in_file == info->end_of_file)
{
- info->read_pos= info->read_end= info->buffer;
- info->pos_in_file= pos_in_file;
+ /* reading past EOF should not empty the cache */
+ info->read_pos= info->read_end;
info->error= 0;
DBUG_RETURN(MY_TEST(Count));
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index dd79cb39f80..dab0fab35e0 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2192,7 +2192,8 @@ static void mysqld_exit(int exit_code)
if (opt_endinfo && global_status_var.global_memory_used)
fprintf(stderr, "Warning: Memory not freed: %ld\n",
(long) global_status_var.global_memory_used);
- if (!opt_debugging && !my_disable_leak_check && exit_code == 0)
+ if (!opt_debugging && !my_disable_leak_check && exit_code == 0 &&
+ debug_assert_on_not_freed_memory)
{
#ifdef SAFEMALLOC
sf_report_leaked_memory(0);
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index f2523b44317..21bb086f013 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -430,7 +430,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT* check_opt,
const char *operator_name,
thr_lock_type lock_type,
- bool open_for_modify,
+ bool org_open_for_modify,
bool repair_table_use_frm,
uint extra_open_options,
int (*prepare_func)(THD *, TABLE_LIST *,
@@ -497,6 +497,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
bool fatal_error=0;
bool open_error;
bool collect_eis= FALSE;
+ bool open_for_modify= org_open_for_modify;
DBUG_PRINT("admin", ("table: '%s'.'%s'", db, table->table_name.str));
strxmov(table_name, db, ".", table->table_name.str, NullS);
@@ -1164,7 +1165,7 @@ send_result_message:
}
}
/* Error path, a admin command failed. */
- if (thd->transaction_rollback_request)
+ if (thd->transaction_rollback_request || fatal_error)
{
/*
Unlikely, but transaction rollback was requested by one of storage
@@ -1220,7 +1221,9 @@ err:
}
close_thread_tables(thd); // Shouldn't be needed
thd->mdl_context.release_transactional_locks();
+#ifdef WITH_PARTITION_STORAGE_ENGINE
err2:
+#endif
thd->resume_subsequent_commits(suspended_wfc);
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 0825e9754ad..bf78bd12192 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -402,8 +402,8 @@ bool Sql_cmd_alter_table::execute(THD *thd)
- For temporary MERGE tables we do not track if their child tables are
base or temporary. As result we can't guarantee that privilege check
- which was done in presence of temporary child will stay relevant later
- as this temporary table might be removed.
+ which was done in presence of temporary child will stay relevant
+ later as this temporary table might be removed.
If SELECT_ACL | UPDATE_ACL | DELETE_ACL privileges were not checked for
the underlying *base* tables, it would create a security breach as in
@@ -443,6 +443,9 @@ bool Sql_cmd_alter_table::execute(THD *thd)
create_info.data_file_name= create_info.index_file_name= NULL;
thd->prepare_logs_for_admin_command();
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ thd->work_part_info= 0;
+#endif
#ifdef WITH_WSREP
if ((!thd->is_current_stmt_binlog_format_row() ||
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index f89fbc59b14..64427af6319 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1481,15 +1481,15 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
return FALSE;
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
/* Set all [named] partitions as used. */
static int set_partitions_as_used(TABLE_LIST *tl, TABLE *t)
{
-#ifdef WITH_PARTITION_STORAGE_ENGINE
if (t->part_info)
return t->file->change_partitions_to_open(tl->partition_names);
-#endif
return 0;
}
+#endif
/**
@@ -1535,7 +1535,9 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
MDL_ticket *mdl_ticket;
TABLE_SHARE *share;
uint gts_flags;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
int part_names_error=0;
+#endif
DBUG_ENTER("open_table");
/*
@@ -1633,7 +1635,9 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
table= best_table;
table->query_id= thd->query_id;
DBUG_PRINT("info",("Using locked table"));
+#ifdef WITH_PARTITION_STORAGE_ENGINE
part_names_error= set_partitions_as_used(table_list, table);
+#endif
goto reset;
}
/*
@@ -1918,7 +1922,9 @@ retry_share:
{
DBUG_ASSERT(table->file != NULL);
MYSQL_REBIND_TABLE(table->file);
+#ifdef WITH_PARTITION_STORAGE_ENGINE
part_names_error= set_partitions_as_used(table_list, table);
+#endif
}
else
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index f937a8fad9f..d2e4f66dd59 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -6686,7 +6686,8 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
- Row_data_memory memory(table, max_row_length(table, record));
+ Row_data_memory memory(table, max_row_length(table, table->rpl_write_set,
+ record));
if (!memory.has_memory())
return HA_ERR_OUT_OF_MEM;
@@ -6723,8 +6724,10 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()));
- size_t const before_maxlen = max_row_length(table, before_record);
- size_t const after_maxlen = max_row_length(table, after_record);
+ size_t const before_maxlen= max_row_length(table, table->read_set,
+ before_record);
+ size_t const after_maxlen= max_row_length(table, table->rpl_write_set,
+ after_record);
Row_data_memory row_data(table, before_maxlen, after_maxlen);
if (!row_data.has_memory())
@@ -6800,7 +6803,8 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
- Row_data_memory memory(table, max_row_length(table, record));
+ Row_data_memory memory(table, max_row_length(table, table->read_set,
+ record));
if (unlikely(!memory.has_memory()))
return HA_ERR_OUT_OF_MEM;
@@ -6839,15 +6843,17 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
}
+/**
+ Remove from read_set spurious columns. The write_set has been
+ handled before in table->mark_columns_needed_for_update.
+*/
+
void THD::binlog_prepare_row_images(TABLE *table)
{
DBUG_ENTER("THD::binlog_prepare_row_images");
- /**
- Remove from read_set spurious columns. The write_set has been
- handled before in table->mark_columns_needed_for_update.
- */
- DBUG_PRINT_BITSET("debug", "table->read_set (before preparing): %s", table->read_set);
+ DBUG_PRINT_BITSET("debug", "table->read_set (before preparing): %s",
+ table->read_set);
THD *thd= table->in_use;
/**
@@ -6865,7 +6871,7 @@ void THD::binlog_prepare_row_images(TABLE *table)
*/
DBUG_ASSERT(table->read_set != &table->tmp_set);
- switch(thd->variables.binlog_row_image)
+ switch (thd->variables.binlog_row_image)
{
case BINLOG_ROW_IMAGE_MINIMAL:
/* MINIMAL: Mark only PK */
@@ -6895,7 +6901,8 @@ void THD::binlog_prepare_row_images(TABLE *table)
table->write_set);
}
- DBUG_PRINT_BITSET("debug", "table->read_set (after preparing): %s", table->read_set);
+ DBUG_PRINT_BITSET("debug", "table->read_set (after preparing): %s",
+ table->read_set);
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8295043bf02..64b75dbe7be 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4568,6 +4568,12 @@ public:
/* Members related to temporary tables. */
public:
+ /* Opened table states. */
+ enum Temporary_table_state {
+ TMP_TABLE_IN_USE,
+ TMP_TABLE_NOT_IN_USE,
+ TMP_TABLE_ANY
+ };
bool has_thd_temporary_tables();
TABLE *create_and_open_tmp_table(handlerton *hton,
@@ -4578,8 +4584,10 @@ public:
bool open_in_engine,
bool open_internal_tables);
- TABLE *find_temporary_table(const char *db, const char *table_name);
- TABLE *find_temporary_table(const TABLE_LIST *tl);
+ TABLE *find_temporary_table(const char *db, const char *table_name,
+ Temporary_table_state state= TMP_TABLE_IN_USE);
+ TABLE *find_temporary_table(const TABLE_LIST *tl,
+ Temporary_table_state state= TMP_TABLE_IN_USE);
TMP_TABLE_SHARE *find_tmp_table_share_w_base_key(const char *key,
uint key_length);
@@ -4606,13 +4614,6 @@ private:
/* Whether a lock has been acquired? */
bool m_tmp_tables_locked;
- /* Opened table states. */
- enum Temporary_table_state {
- TMP_TABLE_IN_USE,
- TMP_TABLE_NOT_IN_USE,
- TMP_TABLE_ANY
- };
-
bool has_temporary_tables();
uint create_tmp_table_def_key(char *key, const char *db,
const char *table_name);
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 02d5bbfc84f..faf9fcbe906 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -195,13 +195,14 @@ static void mysql_ha_close_childs(THD *thd, TABLE_LIST *current_table_list,
static void mysql_ha_close_table(SQL_HANDLER *handler)
{
+ DBUG_ENTER("mysql_ha_close_table");
THD *thd= handler->thd;
TABLE *table= handler->table;
TABLE_LIST *current_table_list= NULL, *next_global;
/* check if table was already closed */
if (!table)
- return;
+ DBUG_VOID_RETURN;
if ((next_global= table->file->get_next_global_for_child()))
current_table_list= next_global->parent_l;
@@ -232,6 +233,7 @@ static void mysql_ha_close_table(SQL_HANDLER *handler)
}
my_free(handler->lock);
handler->init();
+ DBUG_VOID_RETURN;
}
/*
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 40a5490b908..46a1ad22002 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -775,6 +775,8 @@ void init_update_queries(void)
There are other statements that deal with temporary tables and open
them, but which are not listed here. The thing is that the order of
pre-opening temporary tables for those statements is somewhat custom.
+
+ Note that SQLCOM_RENAME_TABLE should not be in this list!
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES;
@@ -789,7 +791,6 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DELETE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_PREOPEN_TMP_TABLES;
- sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES;
@@ -3237,10 +3238,6 @@ mysql_execute_command(THD *thd)
#endif
DBUG_ENTER("mysql_execute_command");
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- thd->work_part_info= 0;
-#endif
-
DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt);
/*
Each statement or replication event which might produce deadlock
@@ -4100,6 +4097,7 @@ mysql_execute_command(THD *thd)
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
+ thd->work_part_info= 0;
{
partition_info *part_info= thd->lex->part_info;
if (part_info && !(part_info= part_info->get_clone(thd)))
@@ -6594,6 +6592,60 @@ static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
}
+/*
+ Find out if a table is a temporary table
+
+ A table is a temporary table if it's a temporary table or
+ there has been before a temporary table that has been renamed
+ to the current name.
+
+ Some examples:
+ A->B B is a temporary table if and only if A is a temp.
+ A->B, B->C Second B is temp if A is temp
+ A->B, A->C Second A can't be temp as if A was temp then B is temp
+ and Second A can only be a normal table. C is also not temp
+*/
+
+static TABLE *find_temporary_table_for_rename(THD *thd,
+ TABLE_LIST *first_table,
+ TABLE_LIST *cur_table)
+{
+ TABLE_LIST *table;
+ TABLE *res= 0;
+ bool found= 0;
+ DBUG_ENTER("find_temporary_table_for_rename");
+
+ /* Find last instance when cur_table is in TO part */
+ for (table= first_table;
+ table != cur_table;
+ table= table->next_local->next_local)
+ {
+ TABLE_LIST *next= table->next_local;
+
+ if (!strcmp(table->get_db_name(), cur_table->get_db_name()) &&
+ !strcmp(table->get_table_name(), cur_table->get_table_name()))
+ {
+ /* Table was moved away, can't be same as 'table' */
+ found= 1;
+ res= 0; // Table can't be a temporary table
+ }
+ if (!strcmp(next->get_db_name(), cur_table->get_db_name()) &&
+ !strcmp(next->get_table_name(), cur_table->get_table_name()))
+ {
+ /*
+ Table has matching name with new name of this table. cur_table should
+ have same temporary type as this table.
+ */
+ found= 1;
+ res= table->table;
+ }
+ }
+ if (!found)
+ res= thd->find_temporary_table(table, THD::TMP_TABLE_ANY);
+ DBUG_RETURN(res);
+}
+
+
static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
TABLE_LIST *all_tables)
{
@@ -6610,13 +6662,19 @@ static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
&table->next_local->grant.m_internal,
0, 0))
return 1;
+
+ /* check if these are refering to temporary tables */
+ table->table= find_temporary_table_for_rename(thd, first_table, table);
+ table->next_local->table= table->table;
+
TABLE_LIST old_list, new_list;
/*
we do not need initialize old_list and new_list because we will
- come table[0] and table->next[0] there
+ copy table[0] and table->next[0] there
*/
old_list= table[0];
new_list= table->next_local[0];
+
if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, FALSE, 1, FALSE) ||
(!test_all_bits(table->next_local->grant.privilege,
INSERT_ACL | CREATE_ACL) &&
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 7ac555fdbe3..0f7bb7748c1 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -223,7 +223,7 @@ do_rename_temporary(THD *thd, TABLE_LIST *ren_table, TABLE_LIST *new_table,
new_alias= (lower_case_table_names == 2) ? &new_table->alias :
&new_table->table_name;
- if (is_temporary_table(new_table))
+ if (thd->find_temporary_table(new_table, THD::TMP_TABLE_ANY))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias->str);
DBUG_RETURN(1); // This can't be skipped
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 92c019d3f1b..4edcb779379 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1517,7 +1517,8 @@ public:
~Stat_table_write_iter()
{
- cleanup();
+ /* Ensure that cleanup has been run */
+ DBUG_ASSERT(rowid_buf == 0);
}
};
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index edf6c776f68..5d5cc90431b 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -240,8 +240,17 @@ bool String::copy(const char *str,size_t arg_length, CHARSET_INFO *cs)
{
if (alloc(arg_length))
return TRUE;
- DBUG_ASSERT(arg_length <= UINT_MAX32);
- if ((str_length=(uint32)arg_length))
+ DBUG_ASSERT(arg_length < UINT_MAX32);
+ if (Ptr == str && arg_length == uint32(str_length))
+ {
+ /*
+ This can happen in some cases. This code is here mainly to avoid
+ warnings from valgrind, but can also be an indication of error.
+ */
+ DBUG_PRINT("warning", ("Copying string on itself: %p %zu",
+ str, arg_length));
+ }
+ else if ((str_length=uint32(arg_length)))
memcpy(Ptr,str,arg_length);
Ptr[arg_length]=0;
str_charset=cs;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index a5c9a4541d7..6835d92773c 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6095,10 +6095,28 @@ drop_create_field:
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
Alter_drop *drop;
bool remove_drop;
+ ulonglong left_flags= 0;
while ((drop= drop_it++))
{
+ ulonglong cur_flag= 0;
+ switch (drop->type) {
+ case Alter_drop::COLUMN:
+ cur_flag= ALTER_PARSER_DROP_COLUMN;
+ break;
+ case Alter_drop::FOREIGN_KEY:
+ cur_flag= ALTER_DROP_FOREIGN_KEY;
+ break;
+ case Alter_drop::KEY:
+ cur_flag= ALTER_DROP_INDEX;
+ break;
+ default:
+ break;
+ }
if (!drop->drop_if_exists)
+ {
+ left_flags|= cur_flag;
continue;
+ }
remove_drop= TRUE;
if (drop->type == Alter_drop::COLUMN)
{
@@ -6190,12 +6208,15 @@ drop_create_field:
ER_THD(thd, ER_CANT_DROP_FIELD_OR_KEY),
drop->type_name(), drop->name);
drop_it.remove();
- if (alter_info->drop_list.is_empty())
- alter_info->flags&= ~(ALTER_PARSER_DROP_COLUMN |
- ALTER_DROP_INDEX |
- ALTER_DROP_FOREIGN_KEY);
}
+ else
+ left_flags|= cur_flag;
}
+ /* Reset state to what's left in drop list */
+ alter_info->flags&= ~(ALTER_PARSER_DROP_COLUMN |
+ ALTER_DROP_INDEX |
+ ALTER_DROP_FOREIGN_KEY);
+ alter_info->flags|= left_flags;
}
/* ALTER TABLE ADD KEY IF NOT EXISTS */
@@ -6309,8 +6330,9 @@ remove_key:
}
}
}
-
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
+ DBUG_ASSERT(thd->work_part_info == 0);
partition_info *tab_part_info= table->part_info;
thd->work_part_info= thd->lex->part_info;
if (tab_part_info)
@@ -9017,6 +9039,10 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
{
DBUG_ENTER("mysql_alter_table");
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ thd->work_part_info= 0; // Used by partitioning
+#endif
+
/*
Check if we attempt to alter mysql.slow_log or
mysql.general_log table and return an error if
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 3318faf3f90..6961f821a0a 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -624,6 +624,7 @@ end:
#endif /* WITH_WSREP */
}
+
/**
Build stmt_query to write it in the bin-log, the statement to write in
the trigger file and the trigger definer.
@@ -1191,6 +1192,12 @@ Table_triggers_list::~Table_triggers_list()
}
}
}
+
+ /* Free blobs used in insert */
+ if (record0_field)
+ for (Field **fld_ptr= record0_field; *fld_ptr; fld_ptr++)
+ (*fld_ptr)->free();
+
if (record1_field)
for (Field **fld_ptr= record1_field; *fld_ptr; fld_ptr++)
delete *fld_ptr;
diff --git a/sql/table.cc b/sql/table.cc
index 85c126098c0..4bfe726980e 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2770,6 +2770,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
goto ret;
thd->lex->create_info.db_type= hton;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ thd->work_part_info= 0; // For partitioning
+#endif
if (tabledef_version.str)
thd->lex->create_info.tabledef_version= tabledef_version;
@@ -6682,6 +6685,12 @@ void TABLE::mark_columns_per_binlog_row_image()
DBUG_ASSERT(FALSE);
}
}
+ /*
+ We have to ensure that all virtual columns that are part of read set
+ are calculated.
+ */
+ if (vcol_set)
+ bitmap_union(vcol_set, read_set);
file->column_bitmaps_signal();
}
@@ -6723,7 +6732,8 @@ bool TABLE::mark_virtual_col(Field *field)
/*
@brief Mark virtual columns for update/insert commands
- @param insert_fl <-> virtual columns are marked for insert command
+ @param insert_fl true if virtual columns are marked for insert command
+ For the moment this is not used, may be used in future.
@details
The function marks virtual columns used in a update/insert commands
@@ -6748,7 +6758,8 @@ bool TABLE::mark_virtual_col(Field *field)
be added to read_set either.
*/
-bool TABLE::mark_virtual_columns_for_write(bool insert_fl)
+bool TABLE::mark_virtual_columns_for_write(bool insert_fl
+ __attribute__((unused)))
{
Field **vfield_ptr, *tmp_vfield;
bool bitmap_updated= false;
@@ -6758,35 +6769,13 @@ bool TABLE::mark_virtual_columns_for_write(bool insert_fl)
{
tmp_vfield= *vfield_ptr;
if (bitmap_is_set(write_set, tmp_vfield->field_index))
- bitmap_updated= mark_virtual_col(tmp_vfield);
+ bitmap_updated|= mark_virtual_col(tmp_vfield);
else if (tmp_vfield->vcol_info->stored_in_db ||
(tmp_vfield->flags & (PART_KEY_FLAG | FIELD_IN_PART_FUNC_FLAG)))
{
- if (insert_fl)
- {
- bitmap_set_bit(write_set, tmp_vfield->field_index);
- mark_virtual_col(tmp_vfield);
- bitmap_updated= true;
- }
- else
- {
- MY_BITMAP *save_read_set= read_set, *save_vcol_set= vcol_set;
- Item *vcol_item= tmp_vfield->vcol_info->expr;
- DBUG_ASSERT(vcol_item);
- bitmap_clear_all(&tmp_set);
- read_set= vcol_set= &tmp_set;
- vcol_item->walk(&Item::register_field_in_read_map, 1, 0);
- read_set= save_read_set;
- vcol_set= save_vcol_set;
- if (bitmap_is_overlapping(&tmp_set, write_set))
- {
- bitmap_set_bit(write_set, tmp_vfield->field_index);
- bitmap_set_bit(vcol_set, tmp_vfield->field_index);
- bitmap_union(read_set, &tmp_set);
- bitmap_union(vcol_set, &tmp_set);
- bitmap_updated= true;
- }
- }
+ bitmap_set_bit(write_set, tmp_vfield->field_index);
+ mark_virtual_col(tmp_vfield);
+ bitmap_updated= true;
}
}
if (bitmap_updated)
@@ -7432,8 +7421,8 @@ bool TABLE_LIST::process_index_hints(TABLE *tbl)
}
/*
- TODO: get rid of tbl->force_index (on if any FORCE INDEX is specified) and
- create tbl->force_index_join instead.
+ TODO: get rid of tbl->force_index (on if any FORCE INDEX is specified)
+ and create tbl->force_index_join instead.
Then use the correct force_index_XX instead of the global one.
*/
if (!index_join[INDEX_HINT_FORCE].is_clear_all() ||
@@ -7463,21 +7452,27 @@ bool TABLE_LIST::process_index_hints(TABLE *tbl)
}
-size_t max_row_length(TABLE *table, const uchar *data)
+size_t max_row_length(TABLE *table, MY_BITMAP const *cols, const uchar *data)
{
TABLE_SHARE *table_s= table->s;
size_t length= table_s->reclength + 2 * table_s->fields;
uint *const beg= table_s->blob_field;
uint *const end= beg + table_s->blob_fields;
+ my_ptrdiff_t const rec_offset= (my_ptrdiff_t) (data - table->record[0]);
+ DBUG_ENTER("max_row_length");
for (uint *ptr= beg ; ptr != end ; ++ptr)
{
- Field_blob* const blob= (Field_blob*) table->field[*ptr];
- length+= blob->get_length((const uchar*)
- (data + blob->offset(table->record[0]))) +
- HA_KEY_BLOB_LENGTH;
+ Field * const field= table->field[*ptr];
+ if (bitmap_is_set(cols, field->field_index) &&
+ !field->is_null(rec_offset))
+ {
+ Field_blob * const blob= (Field_blob*) field;
+ length+= blob->get_length(rec_offset) + 8; /* max blob store length */
+ }
}
- return length;
+ DBUG_PRINT("exit", ("length: %lld", (longlong) length));
+ DBUG_RETURN(length);
}
@@ -7592,7 +7587,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
Query_arena backup_arena;
Turn_errors_to_warnings_handler Suppress_errors;
int error;
- bool handler_pushed= 0;
+ bool handler_pushed= 0, update_all_columns= 1;
DBUG_ASSERT(vfield);
if (h->keyread_enabled())
@@ -7609,6 +7604,16 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
in_use->push_internal_handler(&Suppress_errors);
handler_pushed= 1;
}
+ else if (update_mode == VCOL_UPDATE_FOR_REPLACE &&
+ in_use->is_current_stmt_binlog_format_row() &&
+ in_use->variables.binlog_row_image != BINLOG_ROW_IMAGE_MINIMAL)
+ {
+ /*
+ If we are doing a replace with not minimal binary logging, we have to
+ calculate all virtual columns.
+ */
+ update_all_columns= 1;
+ }
/* Iterate over virtual fields in the table */
for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++)
@@ -7621,8 +7626,8 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
bool update= 0, swap_values= 0;
switch (update_mode) {
case VCOL_UPDATE_FOR_READ:
- update= !vcol_info->stored_in_db
- && bitmap_is_set(vcol_set, vf->field_index);
+ update= (!vcol_info->stored_in_db &&
+ bitmap_is_set(vcol_set, vf->field_index));
swap_values= 1;
break;
case VCOL_UPDATE_FOR_DELETE:
@@ -7630,8 +7635,9 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
update= bitmap_is_set(vcol_set, vf->field_index);
break;
case VCOL_UPDATE_FOR_REPLACE:
- update= !vcol_info->stored_in_db && (vf->flags & PART_KEY_FLAG)
- && bitmap_is_set(vcol_set, vf->field_index);
+ update= ((!vcol_info->stored_in_db && (vf->flags & PART_KEY_FLAG) &&
+ bitmap_is_set(vcol_set, vf->field_index)) ||
+ update_all_columns);
if (update && (vf->flags & BLOB_FLAG))
{
/*
@@ -7648,8 +7654,8 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
case VCOL_UPDATE_INDEXED:
case VCOL_UPDATE_INDEXED_FOR_UPDATE:
/* Read indexed fields that was not updated in VCOL_UPDATE_FOR_READ */
- update= !vcol_info->stored_in_db && (vf->flags & PART_KEY_FLAG) &&
- bitmap_is_set(vcol_set, vf->field_index);
+ update= (!vcol_info->stored_in_db && (vf->flags & PART_KEY_FLAG) &&
+ !bitmap_is_set(vcol_set, vf->field_index));
swap_values= 1;
break;
}
diff --git a/sql/table.h b/sql/table.h
index 6655346cd45..7b411f00d21 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -2879,7 +2879,7 @@ enum get_table_share_flags {
GTS_FORCE_DISCOVERY = 16
};
-size_t max_row_length(TABLE *table, const uchar *data);
+size_t max_row_length(TABLE *table, MY_BITMAP const *cols, const uchar *data);
void init_mdl_requests(TABLE_LIST *table_list);
diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc
index 54ce3b61f79..f23ec7a1acc 100644
--- a/sql/temporary_tables.cc
+++ b/sql/temporary_tables.cc
@@ -112,12 +112,14 @@ TABLE *THD::create_and_open_tmp_table(handlerton *hton,
@param db [IN] Database name
@param table_name [IN] Table name
+ @param state [IN] State of temp table to open
@return Success Pointer to first used table instance.
Failure NULL
*/
TABLE *THD::find_temporary_table(const char *db,
- const char *table_name)
+ const char *table_name,
+ Temporary_table_state state)
{
DBUG_ENTER("THD::find_temporary_table");
@@ -134,7 +136,7 @@ TABLE *THD::find_temporary_table(const char *db,
key_length= create_tmp_table_def_key(key, db, table_name);
locked= lock_temporary_tables();
- table = find_temporary_table(key, key_length, TMP_TABLE_IN_USE);
+ table= find_temporary_table(key, key_length, state);
if (locked)
{
DBUG_ASSERT(m_tmp_tables_locked);
@@ -153,16 +155,12 @@ TABLE *THD::find_temporary_table(const char *db,
@return Success Pointer to first used table instance.
Failure NULL
*/
-TABLE *THD::find_temporary_table(const TABLE_LIST *tl)
+TABLE *THD::find_temporary_table(const TABLE_LIST *tl,
+ Temporary_table_state state)
{
DBUG_ENTER("THD::find_temporary_table");
-
- if (!has_temporary_tables())
- {
- DBUG_RETURN(NULL);
- }
-
- TABLE *table= find_temporary_table(tl->get_db_name(), tl->get_table_name());
+ TABLE *table= find_temporary_table(tl->get_db_name(), tl->get_table_name(),
+ state);
DBUG_RETURN(table);
}
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index 08d5220cfca..42d2c219ebf 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -898,18 +898,19 @@ int ha_archive::real_write_row(uchar *buf, azio_stream *writer)
the bytes required for the length in the header.
*/
-uint32 ha_archive::max_row_length(const uchar *buf)
+uint32 ha_archive::max_row_length(const uchar *record)
{
uint32 length= (uint32)(table->s->reclength + table->s->fields*2);
length+= ARCHIVE_ROW_HEADER_SIZE;
+ my_ptrdiff_t const rec_offset= record - table->record[0];
uint *ptr, *end;
for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
ptr != end ;
ptr++)
{
- if (!table->field[*ptr]->is_null())
- length += 2 + ((Field_blob*)table->field[*ptr])->get_length();
+ if (!table->field[*ptr]->is_null(rec_offset))
+ length += 2 + ((Field_blob*)table->field[*ptr])->get_length(rec_offset);
}
return length;
@@ -919,10 +920,9 @@ uint32 ha_archive::max_row_length(const uchar *buf)
unsigned int ha_archive::pack_row(uchar *record, azio_stream *writer)
{
uchar *ptr;
-
+ my_ptrdiff_t const rec_offset= record - table->record[0];
DBUG_ENTER("ha_archive::pack_row");
-
if (fix_rec_buff(max_row_length(record)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
@@ -936,7 +936,7 @@ unsigned int ha_archive::pack_row(uchar *record, azio_stream *writer)
for (Field **field=table->field ; *field ; field++)
{
- if (!((*field)->is_null()))
+ if (!((*field)->is_null(rec_offset)))
ptr= (*field)->pack(ptr, record + (*field)->offset(record));
}
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 1acdce14d7c..ca4d2e91979 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -1145,7 +1145,7 @@ retry:
#endif
ut_ad(btr_search_enabled);
- ut_ad(block->page.id.space() == index->table->space->id);
+ ut_ad(block->page.id.space() == index->table->space_id);
ut_a(index_id == index->id);
ut_a(!dict_index_is_ibuf(index));
#ifdef UNIV_DEBUG
@@ -1271,9 +1271,8 @@ cleanup:
ut_free(folds);
}
-/** Drop any adaptive hash index entries that may point to an index
-page that may be in the buffer pool, when a page is evicted from the
-buffer pool or freed in a file segment.
+/** Drop possible adaptive hash index entries when a page is evicted
+from the buffer pool or freed in a file, or the index is being dropped.
@param[in] page_id page id */
void btr_search_drop_page_hash_when_freed(const page_id_t& page_id)
{
@@ -2056,7 +2055,7 @@ btr_search_hash_table_validate(ulint hash_table_id)
ut_a(!dict_index_is_ibuf(block->index));
ut_ad(block->page.id.space()
- == block->index->table->space->id);
+ == block->index->table->space_id);
page_index_id = btr_page_get_index_id(block->frame);
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 8b32a2cb533..252f37b4495 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -225,24 +225,17 @@ particular space id.
@param[in] count number of entries in array */
static
void
-buf_LRU_drop_page_hash_batch(
- ulint space_id,
- const ulint* arr,
- ulint count)
+buf_LRU_drop_page_hash_batch(ulint space_id, const ulint* arr, ulint count)
{
ut_ad(count <= BUF_LRU_DROP_SEARCH_SIZE);
- for (ulint i = 0; i < count; ++i, ++arr) {
+ for (const ulint* const end = arr + count; arr != end; ) {
/* While our only caller
buf_LRU_drop_page_hash_for_tablespace()
is being executed for DROP TABLE or similar,
- the table cannot be evicted from the buffer pool.
- Note: this should not be executed for DROP TABLESPACE,
- because DROP TABLESPACE would be refused if tables existed
- in the tablespace, and a previous DROP TABLE would have
- already removed the AHI entries. */
+ the table cannot be evicted from the buffer pool. */
btr_search_drop_page_hash_when_freed(
- page_id_t(space_id, *arr));
+ page_id_t(space_id, *arr++));
}
}
@@ -359,6 +352,28 @@ next_page:
buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
ut_free(page_arr);
}
+
+/** Drop the adaptive hash index for a tablespace.
+@param[in,out] table table */
+void buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table)
+{
+ for (dict_index_t* index = dict_table_get_first_index(table);
+ index != NULL;
+ index = dict_table_get_next_index(index)) {
+ if (btr_search_info_get_ref_count(btr_search_get_info(index),
+ index)) {
+ goto drop_ahi;
+ }
+ }
+
+ return;
+drop_ahi:
+ ulint id = table->space_id;
+ for (ulint i = 0; i < srv_buf_pool_instances; i++) {
+ buf_LRU_drop_page_hash_for_tablespace(buf_pool_from_array(i),
+ id);
+ }
+}
#endif /* BTR_CUR_HASH_ADAPT */
/******************************************************************//**
@@ -682,26 +697,13 @@ buf_flush_dirty_pages(
@param[in] id tablespace identifier
@param[in] observer flush observer,
or NULL if nothing is to be written */
-void
-buf_LRU_flush_or_remove_pages(
- ulint id,
- FlushObserver* observer
-#ifdef BTR_CUR_HASH_ADAPT
- , bool drop_ahi /*!< whether to drop the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
- )
+void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer)
{
/* Pages in the system tablespace must never be discarded. */
ut_ad(id || observer);
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool = buf_pool_from_array(i);
-#ifdef BTR_CUR_HASH_ADAPT
- if (drop_ahi) {
- buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
- }
-#endif /* BTR_CUR_HASH_ADAPT */
- buf_flush_dirty_pages(buf_pool, id, observer);
+ buf_flush_dirty_pages(buf_pool_from_array(i), id, observer);
}
if (observer && !observer->is_interrupted()) {
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index c570efb1aba..e7acead269c 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1623,11 +1623,7 @@ dict_table_rename_in_cache(
return(DB_OUT_OF_MEMORY);
}
- fil_delete_tablespace(table->space->id
-#ifdef BTR_CUR_HASH_ADAPT
- , true
-#endif /* BTR_CUR_HASH_ADAPT */
- );
+ fil_delete_tablespace(table->space_id);
/* Delete any temp file hanging around. */
if (os_file_status(filepath, &exists, &ftype)
@@ -2593,28 +2589,13 @@ dict_index_remove_from_cache_low(
zero. See also: dict_table_can_be_evicted() */
do {
- ulint ref_count = btr_search_info_get_ref_count(info, index);
-
- if (ref_count == 0) {
+ if (!btr_search_info_get_ref_count(info, index)) {
break;
}
- /* Sleep for 10ms before trying again. */
- os_thread_sleep(10000);
- ++retries;
-
- if (retries % 500 == 0) {
- /* No luck after 5 seconds of wait. */
- ib::error() << "Waited for " << retries / 100
- << " secs for hash index"
- " ref_count (" << ref_count << ") to drop to 0."
- " index: " << index->name
- << " table: " << table->name;
- }
+ buf_LRU_drop_page_hash_for_tablespace(table);
- /* To avoid a hang here we commit suicide if the
- ref_count doesn't drop to zero in 600 seconds. */
- ut_a(retries < 60000);
+ ut_a(++retries < 10000);
} while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
#endif /* BTR_CUR_HASH_ADAPT */
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 6a563341ff9..b9c6235f92f 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -2698,11 +2698,7 @@ fil_delete_tablespace(
To deal with potential read requests, we will check the
::stop_new_ops flag in fil_io(). */
- buf_LRU_flush_or_remove_pages(id, NULL
-#ifdef BTR_CUR_HASH_ADAPT
- , drop_ahi
-#endif /* BTR_CUR_HASH_ADAPT */
- );
+ buf_LRU_flush_or_remove_pages(id, NULL);
/* If it is a delete then also delete any generated files, otherwise
when we drop the database the remove directory will fail. */
diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
index 182bcf20c91..de45bc7b39f 100644
--- a/storage/innobase/include/btr0sea.h
+++ b/storage/innobase/include/btr0sea.h
@@ -119,11 +119,9 @@ btr_search_move_or_delete_hash_entries(
i.e.: it is in state BUF_BLOCK_REMOVE_HASH */
void btr_search_drop_page_hash_index(buf_block_t* block);
-/** Drop any adaptive hash index entries that may point to an index
-page that may be in the buffer pool, when a page is evicted from the
-buffer pool or freed in a file segment.
-@param[in] page_id page id
-@param[in] page_size page size */
+/** Drop possible adaptive hash index entries when a page is evicted
+from the buffer pool or freed in a file, or the index is being dropped.
+@param[in] page_id page id */
void btr_search_drop_page_hash_when_freed(const page_id_t& page_id);
/** Updates the page hash index when a single record is inserted on a page.
diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h
index 547a09ae319..f811b5a6811 100644
--- a/storage/innobase/include/buf0lru.h
+++ b/storage/innobase/include/buf0lru.h
@@ -51,18 +51,20 @@ These are low-level functions
/** Minimum LRU list length for which the LRU_old pointer is defined */
#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */
+#ifdef BTR_CUR_HASH_ADAPT
+struct dict_table_t;
+/** Drop the adaptive hash index for a tablespace.
+@param[in,out] table table */
+void buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table);
+#else
+# define buf_LRU_drop_page_hash_for_tablespace(table)
+#endif /* BTR_CUR_HASH_ADAPT */
+
/** Empty the flush list for all pages belonging to a tablespace.
@param[in] id tablespace identifier
@param[in,out] observer flush observer,
or NULL if nothing is to be written */
-void
-buf_LRU_flush_or_remove_pages(
- ulint id,
- FlushObserver* observer
-#ifdef BTR_CUR_HASH_ADAPT
- , bool drop_ahi = false /*!< whether to drop the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
- );
+void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/********************************************************************//**
diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc
index 366c9672e45..980b26d448c 100644
--- a/storage/innobase/log/log0crypt.cc
+++ b/storage/innobase/log/log0crypt.cc
@@ -62,7 +62,9 @@ struct crypt_info_t {
static crypt_info_t info;
/** Crypt info when upgrading from 10.1 */
-static crypt_info_t infos[5];
+static crypt_info_t infos[5 * 2];
+/** First unused slot in infos[] */
+static size_t infos_used;
/*********************************************************************//**
Get a log block's start lsn.
@@ -80,28 +82,6 @@ log_block_get_start_lsn(
return start_lsn;
}
-/*********************************************************************//**
-Get crypt info from checkpoint.
-@return a crypt info or NULL if not present. */
-static
-const crypt_info_t*
-get_crypt_info(ulint checkpoint_no)
-{
- /* a log block only stores 4-bytes of checkpoint no */
- checkpoint_no &= 0xFFFFFFFF;
- for (unsigned i = 0; i < 5; i++) {
- const crypt_info_t* it = &infos[i];
-
- if (it->key_version && it->checkpoint_no == checkpoint_no) {
- return it;
- }
- }
-
- /* If checkpoint contains more than one key and we did not
- find the correct one use the first one. */
- return infos;
-}
-
/** Encrypt or decrypt log blocks.
@param[in,out] buf log blocks to encrypt or decrypt
@param[in] lsn log sequence number of the start of the buffer
@@ -166,9 +146,7 @@ log_crypt(byte* buf, lsn_t lsn, ulint size, bool decrypt)
@param[in,out] info encryption key
@param[in] upgrade whether to use the key in MariaDB 10.1 format
@return whether the operation was successful */
-static
-bool
-init_crypt_key(crypt_info_t* info, bool upgrade = false)
+static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
{
byte mysqld_key[MY_AES_MAX_KEY_LENGTH];
uint keylen = sizeof mysqld_key;
@@ -253,8 +231,20 @@ log_crypt_101_read_checkpoint(const byte* buf)
const size_t n = *buf++ == 2 ? std::min(unsigned(*buf++), 5U) : 0;
for (size_t i = 0; i < n; i++) {
- struct crypt_info_t& info = infos[i];
- info.checkpoint_no = mach_read_from_4(buf);
+ struct crypt_info_t& info = infos[infos_used];
+ unsigned checkpoint_no = mach_read_from_4(buf);
+ for (size_t j = 0; j < infos_used; j++) {
+ if (infos[j].checkpoint_no == checkpoint_no) {
+ /* Do not overwrite an existing slot. */
+ goto next_slot;
+ }
+ }
+ if (infos_used >= UT_ARR_SIZE(infos)) {
+ ut_ad(!"too many checkpoint pages");
+ goto next_slot;
+ }
+ infos_used++;
+ info.checkpoint_no = checkpoint_no;
info.key_version = mach_read_from_4(buf + 4);
memcpy(info.crypt_msg.bytes, buf + 8, sizeof info.crypt_msg);
memcpy(info.crypt_nonce.bytes, buf + 24,
@@ -263,6 +253,7 @@ log_crypt_101_read_checkpoint(const byte* buf)
if (!init_crypt_key(&info, true)) {
return false;
}
+next_slot:
buf += 4 + 4 + 2 * MY_AES_BLOCK_SIZE;
}
@@ -278,13 +269,19 @@ log_crypt_101_read_block(byte* buf)
{
ut_ad(log_block_calc_checksum_format_0(buf)
!= log_block_get_checksum(buf));
- const crypt_info_t* info = get_crypt_info(
- log_block_get_checkpoint_no(buf));
-
- if (!info || info->key_version == 0) {
- return false;
+ const uint32_t checkpoint_no
+ = uint32_t(log_block_get_checkpoint_no(buf));
+ const crypt_info_t* info = infos;
+ for (const crypt_info_t* const end = info + infos_used; info < end;
+ info++) {
+ if (info->key_version
+ && info->checkpoint_no == checkpoint_no) {
+ goto found;
+ }
}
+ return false;
+found:
byte dst[OS_FILE_LOG_BLOCK_SIZE];
uint dst_len;
byte aes_ctr_iv[MY_AES_BLOCK_SIZE];
@@ -313,9 +310,7 @@ log_crypt_101_read_block(byte* buf)
LOG_DEFAULT_ENCRYPTION_KEY,
info->key_version);
- if (rc != MY_AES_OK || dst_len != src_len
- || log_block_calc_checksum_format_0(dst)
- != log_block_get_checksum(dst)) {
+ if (rc != MY_AES_OK || dst_len != src_len) {
return false;
}
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index 3d4cd2a6aba..4746eb0aab8 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -28,6 +28,7 @@ Created 2012-02-08 by Sunny Bains.
#include "row0import.h"
#include "btr0pcur.h"
+#include "btr0sea.h"
#include "que0que.h"
#include "dict0boot.h"
#include "ibuf0ibuf.h"
@@ -3870,6 +3871,17 @@ row_import_for_mysql(
return(row_import_cleanup(prebuilt, trx, err));
}
+ /* On DISCARD TABLESPACE, we did not drop any adaptive hash
+ index entries. If we replaced the discarded tablespace with a
+ smaller one here, there could still be some adaptive hash
+ index entries that point to cached garbage pages in the buffer
+ pool, because PageConverter::operator() only evicted those
+ pages that were replaced by the imported pages. We must
+ discard all remaining adaptive hash index entries, because the
+ adaptive hash index must be a subset of the table contents;
+ false positives are not tolerated. */
+ buf_LRU_drop_page_hash_for_tablespace(table);
+
row_mysql_lock_data_dictionary(trx);
/* If the table is stored in a remote tablespace, we need to
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index cf072530020..b603292705a 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -3151,11 +3151,7 @@ row_discard_tablespace(
}
/* Discard the physical file that is used for the tablespace. */
- err = fil_delete_tablespace(table->space_id
-#ifdef BTR_CUR_HASH_ADAPT
- , true
-#endif /* BTR_CUR_HASH_ADAPT */
- );
+ err = fil_delete_tablespace(table->space_id);
switch (err) {
case DB_IO_ERROR:
ib::warn() << "ALTER TABLE " << table->name
@@ -3706,6 +3702,21 @@ defer:
rw_lock_x_unlock(dict_index_get_lock(index));
}
+ if (table->space_id != TRX_SYS_SPACE) {
+ /* On DISCARD TABLESPACE, we would not drop the
+ adaptive hash index entries. If the tablespace is
+ missing here, delete-marking the record in SYS_INDEXES
+ would not free any pages in the buffer pool. Thus,
+ dict_index_remove_from_cache() would hang due to
+ adaptive hash index entries existing in the buffer
+ pool. To prevent this hang, and also to guarantee
+ that btr_search_drop_page_hash_when_freed() will avoid
+ calling btr_search_drop_page_hash_index() while we
+ hold the InnoDB dictionary lock, we will drop any
+ adaptive hash index entries upfront. */
+ buf_LRU_drop_page_hash_for_tablespace(table);
+ }
+
/* Deleting a row from SYS_INDEXES table will invoke
dict_drop_index_tree(). */
info = pars_info_create();
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index 0442f4d8eae..94f9ade9d65 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -37,6 +37,7 @@ C_MODE_START
#include "ma_checkpoint.h"
#include "ma_recovery.h"
C_MODE_END
+#include "ma_trnman.h"
//#include "sql_priv.h"
#include "protocol.h"
@@ -1394,7 +1395,8 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
}
/* Reset trn, that may have been set by repair */
- _ma_set_trn_for_table(file, old_trn);
+ if (old_trn && old_trn != file->trn)
+ _ma_set_trn_for_table(file, old_trn);
thd_proc_info(thd, old_proc_info);
thd_progress_end(thd);
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
@@ -1528,7 +1530,8 @@ int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt)
error=maria_zerofill(param, file, share->open_file_name.str);
/* Reset trn, that may have been set by repair */
- _ma_set_trn_for_table(file, old_trn);
+ if (old_trn && old_trn != file->trn)
+ _ma_set_trn_for_table(file, old_trn);
if (!error)
{
@@ -1771,7 +1774,8 @@ int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize)
maria_lock_database(file, F_UNLCK);
/* Reset trn, that may have been set by repair */
- _ma_set_trn_for_table(file, old_trn);
+ if (old_trn && old_trn != file->trn)
+ _ma_set_trn_for_table(file, old_trn);
error= error ? HA_ADMIN_FAILED :
(optimize_done ?
(write_log_record_for_repair(param, file) ? HA_ADMIN_FAILED :
@@ -2591,9 +2595,12 @@ int ha_maria::extra(enum ha_extra_function operation)
without calling commit/rollback in between. If file->trn is not set
we can't remove file->share from the transaction list in the extra() call.
- We also ensure that we set file->trn to 0 if THD_TRN is 0 as in
- this case we have already freed the trn. This can happen when one
- implicit_commit() is called as part of alter table.
+ In current code we don't have to do this for HA_EXTRA_PREPARE_FOR_RENAME
+ as this is only used the intermediate table used by ALTER TABLE which
+ is not part of the transaction (it's not in the TRN list). Better to
+ keep this for now, to not break anything in a stable release.
+ When HA_EXTRA_PREPARE_FOR_RENAME is not handled below, we can change
+ the warnings in _ma_remove_table_from_trnman() to asserts.
table->in_use is not set in the case this is a done as part of closefrm()
as part of drop table.
@@ -2606,7 +2613,7 @@ int ha_maria::extra(enum ha_extra_function operation)
{
THD *thd= table->in_use;
TRN *trn= THD_TRN;
- _ma_set_trn_for_table(file, trn);
+ _ma_set_tmp_trn_for_table(file, trn);
}
DBUG_ASSERT(file->s->base.born_transactional || file->trn == 0 ||
file->trn == &dummy_transaction_object);
@@ -2722,6 +2729,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
if (file->trn)
{
/* This can only happen with tables created with clone() */
+ DBUG_PRINT("info",("file->trn: %p", file->trn));
trnman_increment_locked_tables(file->trn);
}
@@ -2742,7 +2750,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
}
else
{
- TRN *trn= THD_TRN;
+ TRN *trn= (file->trn != &dummy_transaction_object ? file->trn : 0);
/* End of transaction */
/*
@@ -2757,8 +2765,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
*/
if (_ma_reenable_logging_for_table(file, TRUE))
DBUG_RETURN(1);
- /** @todo zero file->trn also in commit and rollback */
- _ma_set_trn_for_table(file, NULL); // Safety
+ _ma_reset_trn_for_table(file);
/*
Ensure that file->state points to the current number of rows. This
is needed if someone calls maria_info() without first doing an
@@ -2815,13 +2822,6 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
DBUG_ASSERT(file->trn == trn);
/*
- If there was an implicit commit under this LOCK TABLES by a previous
- statement (like a DDL), at least if that previous statement was about a
- different ha_maria than 'this' then this->file->trn is a stale
- pointer. We fix it:
- */
- _ma_set_trn_for_table(file, trn);
- /*
As external_lock() was already called, don't increment locked_tables.
Note that we call the function below possibly several times when
statement starts (once per table). This is ok as long as that function
@@ -2845,6 +2845,23 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
}
+/*
+ Reset THD_TRN and all file->trn related to the transaction
+ This is needed as some calls, like extra() or external_lock() may access
+ it before next transaction is started
+*/
+
+static void reset_thd_trn(THD *thd, MARIA_HA *first_table)
+{
+ DBUG_ENTER("reset_thd_trn");
+ THD_TRN= NULL;
+ for (MARIA_HA *table= first_table; table ;
+ table= table->trn_next)
+ _ma_reset_trn_for_table(table);
+ DBUG_VOID_RETURN;
+}
+
+
/**
Performs an implicit commit of the Maria transaction and creates a new
one.
@@ -2868,10 +2885,10 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
TRN *trn;
int error;
uint locked_tables;
- DYNAMIC_ARRAY used_tables;
extern my_bool plugins_are_initialized;
-
+ MARIA_HA *used_tables, *trn_next;
DBUG_ENTER("ha_maria::implicit_commit");
+
if (!maria_hton || !plugins_are_initialized || !(trn= THD_TRN))
DBUG_RETURN(0);
if (!new_trn && (thd->locked_tables_mode == LTM_LOCK_TABLES ||
@@ -2889,48 +2906,16 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
locked_tables= trnman_has_locked_tables(trn);
- if (new_trn && trn && trn->used_tables)
- {
- MARIA_USED_TABLES *tables;
- /*
- Save locked tables so that we can move them to another transaction
- We are using a dynamic array as locked_tables in some cases can be
- smaller than the used_tables list (for example when the server does
- early unlock of tables.
- */
-
- my_init_dynamic_array2(&used_tables, sizeof(MARIA_SHARE*), (void*) 0,
- locked_tables, 8, MYF(MY_THREAD_SPECIFIC));
- for (tables= (MARIA_USED_TABLES*) trn->used_tables;
- tables;
- tables= tables->next)
- {
- if (tables->share->base.born_transactional)
- {
- if (insert_dynamic(&used_tables, (uchar*) &tables->share))
- {
- error= HA_ERR_OUT_OF_MEM;
- goto end_and_free;
- }
- }
- }
- }
- else
- bzero(&used_tables, sizeof(used_tables));
-
+ used_tables= (MARIA_HA*) trn->used_instances;
error= 0;
if (unlikely(ma_commit(trn)))
error= 1;
if (!new_trn)
{
- /*
- To be extra safe, we should also reset file->trn for all open
- tables as some calls, like extra() may access it. We take care
- of this in extra() by resetting file->trn if THD_TRN is 0.
- */
- THD_TRN= NULL;
+ reset_thd_trn(thd, used_tables);
goto end;
}
+
/*
We need to create a new transaction and put it in THD_TRN. Indeed,
tables may be under LOCK TABLES, and so they will start the next
@@ -2940,8 +2925,9 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
THD_TRN= trn;
if (unlikely(trn == NULL))
{
+ reset_thd_trn(thd, used_tables);
error= HA_ERR_OUT_OF_MEM;
- goto end_and_free;
+ goto end;
}
/*
Move all locked tables to the new transaction
@@ -2951,35 +2937,25 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
in check table, we use the table without calling start_stmt().
*/
- uint i;
- for (i= 0 ; i < used_tables.elements ; i++)
+ for (MARIA_HA *handler= used_tables; handler ;
+ handler= trn_next)
{
- MARIA_SHARE *share;
- LIST *handlers;
+ trn_next= handler->trn_next;
+ DBUG_ASSERT(handler->s->base.born_transactional);
- share= *(dynamic_element(&used_tables, i, MARIA_SHARE**));
- /* Find table instances that was used in this transaction */
- for (handlers= share->open_list; handlers; handlers= handlers->next)
+ /* If handler uses versioning */
+ if (handler->s->lock_key_trees)
{
- MARIA_HA *handler= (MARIA_HA*) handlers->data;
- if (handler->external_ref &&
- ((TABLE*) handler->external_ref)->in_use == thd)
- {
- _ma_set_trn_for_table(handler, trn);
- /* If handler uses versioning */
- if (handler->s->lock_key_trees)
- {
- if (_ma_setup_live_state(handler))
- error= HA_ERR_OUT_OF_MEM;
- }
- }
+ /* _ma_set_trn_for_table() will be called indirectly */
+ if (_ma_setup_live_state(handler))
+ error= HA_ERR_OUT_OF_MEM;
}
+ else
+ _ma_set_trn_for_table(handler, trn);
}
/* This is just a commit, tables stay locked if they were: */
trnman_reset_locked_tables(trn, locked_tables);
-end_and_free:
- delete_dynamic(&used_tables);
end:
DBUG_RETURN(error);
}
@@ -3359,10 +3335,10 @@ static int maria_commit(handlerton *hton __attribute__ ((unused)),
trnman_set_flags(trn, trnman_get_flags(trn) & ~TRN_STATE_INFO_LOGGED);
/* statement or transaction ? */
- if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all)
+ if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
+ !all)
DBUG_RETURN(0); // end of statement
- DBUG_PRINT("info", ("THD_TRN set to 0x0"));
- THD_TRN= 0;
+ reset_thd_trn(thd, (MARIA_HA*) trn->used_instances);
DBUG_RETURN(ma_commit(trn)); // end of transaction
}
@@ -3379,8 +3355,7 @@ static int maria_rollback(handlerton *hton __attribute__ ((unused)),
trnman_rollback_statement(trn);
DBUG_RETURN(0); // end of statement
}
- DBUG_PRINT("info", ("THD_TRN set to 0x0"));
- THD_TRN= 0;
+ reset_thd_trn(thd, (MARIA_HA*) trn->used_instances);
DBUG_RETURN(trnman_rollback_trn(trn) ?
HA_ERR_OUT_OF_MEM : 0); // end of transaction
}
diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h
index 51438462787..e67907039a1 100644
--- a/storage/maria/ha_maria.h
+++ b/storage/maria/ha_maria.h
@@ -195,6 +195,7 @@ public:
private:
DsMrr_impl ds_mrr;
friend ICP_RESULT index_cond_func_maria(void *arg);
+ friend void reset_thd_trn(THD *thd);
};
#endif /* HA_MARIA_INCLUDED */
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index 8eaac990741..ae9f2fae889 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -271,6 +271,7 @@
#include "maria_def.h"
#include "ma_blockrec.h"
#include "trnman.h"
+#include "ma_trnman.h"
#include "ma_key_recover.h"
#include "ma_recovery_util.h"
#include <lf.h>
@@ -7525,7 +7526,7 @@ void maria_ignore_trids(MARIA_HA *info)
if (info->s->base.born_transactional)
{
if (!info->trn)
- _ma_set_trn_for_table(info, &dummy_transaction_object);
+ _ma_set_tmp_trn_for_table(info, &dummy_transaction_object);
/* Ignore transaction id when row is read */
info->trn->min_read_from= ~(TrID) 0;
}
diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c
index 882e9f585f1..6e85551c24f 100644
--- a/storage/maria/ma_close.c
+++ b/storage/maria/ma_close.c
@@ -37,6 +37,8 @@ int maria_close(register MARIA_HA *info)
/* Check that we have unlocked key delete-links properly */
DBUG_ASSERT(info->key_del_used == 0);
+ /* Check that file is not part of any uncommited transactions */
+ DBUG_ASSERT(info->trn == 0 || info->trn == &dummy_transaction_object);
if (share->reopen == 1)
{
diff --git a/storage/maria/ma_commit.c b/storage/maria/ma_commit.c
index 68435a45c0a..0ae3868dbf6 100644
--- a/storage/maria/ma_commit.c
+++ b/storage/maria/ma_commit.c
@@ -15,6 +15,7 @@
#include "maria_def.h"
#include "trnman.h"
+#include "ma_trnman.h"
/**
writes a COMMIT record to log and commits transaction in memory
@@ -43,9 +44,9 @@ int ma_commit(TRN *trn)
COMMIT record) and this is not an issue as
* transaction's updates were not made visible to other transactions
* "commit ok" was not sent to client
- Alternatively, Recovery might commit trn (if MY_MIN(rec_lsn) is before COMMIT
- record), which is ok too. All in all it means that "trn committed" is not
- 100% equal to "COMMIT record written".
+ Alternatively, Recovery might commit trn (if MY_MIN(rec_lsn) is before
+ COMMIT record), which is ok too. All in all it means that "trn committed"
+ is not 100% equal to "COMMIT record written".
- if COMMIT record is written after trnman_commit_trn():
if crash happens between the two, trn will be rolled back which is an
issue (transaction's updates were made visible to other transactions).
@@ -93,7 +94,12 @@ int ma_commit(TRN *trn)
int maria_commit(MARIA_HA *info)
{
- return info->s->now_transactional ? ma_commit(info->trn) : 0;
+ TRN *trn;
+ if (!info->s->now_transactional)
+ return 0;
+ trn= info->trn;
+ info->trn= 0; /* checked in maria_close() */
+ return ma_commit(trn);
}
@@ -120,10 +126,7 @@ int maria_begin(MARIA_HA *info)
TRN *trn= trnman_new_trn(0);
if (unlikely(!trn))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
-
- DBUG_PRINT("info", ("TRN set to %p", trn));
_ma_set_trn_for_table(info, trn);
}
DBUG_RETURN(0);
}
-
diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c
index 41261b1422e..9feead42cf7 100644
--- a/storage/maria/ma_extra.c
+++ b/storage/maria/ma_extra.c
@@ -346,7 +346,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
_ma_decrement_open_count(info, 0);
if (info->trn)
{
- _ma_remove_table_from_trnman(share, info->trn);
+ _ma_remove_table_from_trnman(info);
/* Ensure we don't point to the deleted data in trn */
info->state= info->state_start= &share->state.state;
}
@@ -409,7 +409,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
if (info->trn)
{
mysql_mutex_lock(&share->intern_lock);
- _ma_remove_table_from_trnman(share, info->trn);
+ _ma_remove_table_from_trnman(info);
/* Ensure we don't point to the deleted data in trn */
info->state= info->state_start= &share->state.state;
mysql_mutex_unlock(&share->intern_lock);
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index 3febf879ec6..4139409d477 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -19,6 +19,8 @@
#include "ma_sp_defs.h"
#include "ma_rt_index.h"
#include "ma_blockrec.h"
+#include "trnman.h"
+#include "ma_trnman.h"
#include <m_ctype.h>
#include "ma_crypt.h"
@@ -184,7 +186,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share,
if (!share->base.born_transactional) /* For transactional ones ... */
{
/* ... force crash if no trn given */
- _ma_set_trn_for_table(&info, &dummy_transaction_object);
+ _ma_set_tmp_trn_for_table(&info, &dummy_transaction_object);
info.state= &share->state.state; /* Change global values by default */
}
else
diff --git a/storage/maria/ma_state.c b/storage/maria/ma_state.c
index a3c2d50bdc6..23cb625fc58 100644
--- a/storage/maria/ma_state.c
+++ b/storage/maria/ma_state.c
@@ -66,7 +66,7 @@ my_bool _ma_setup_live_state(MARIA_HA *info)
DBUG_RETURN(1);
trn= info->trn;
- for (tables= (MARIA_USED_TABLES*) info->trn->used_tables;
+ for (tables= (MARIA_USED_TABLES*) trn->used_tables;
tables;
tables= tables->next)
{
@@ -551,6 +551,7 @@ my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
my_free(tables);
}
trn->used_tables= 0;
+ trn->used_instances= 0;
DBUG_RETURN(error);
}
@@ -565,18 +566,25 @@ my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
share->internal_lock must be locked when function is called
*/
-void _ma_remove_table_from_trnman(MARIA_SHARE *share, TRN *trn)
+void _ma_remove_table_from_trnman(MARIA_HA *info)
{
+ MARIA_SHARE *share= info->s;
+ TRN *trn= info->trn;
MARIA_USED_TABLES *tables, **prev;
+ MARIA_HA *handler, **prev_file;
DBUG_ENTER("_ma_remove_table_from_trnman");
DBUG_PRINT("enter", ("trn: %p used_tables: %p share: %p in_trans: %d",
trn, trn->used_tables, share, share->in_trans));
mysql_mutex_assert_owner(&share->intern_lock);
+
+ if (trn == &dummy_transaction_object)
+ DBUG_VOID_RETURN;
- for (prev= (MARIA_USED_TABLES**) (char*) &trn->used_tables, tables= *prev;
- tables;
- tables= *prev)
+ /* First remove share from used_tables */
+ for (prev= (MARIA_USED_TABLES**) (char*) &trn->used_tables;
+ (tables= *prev);
+ prev= &tables->next)
{
if (tables->share == share)
{
@@ -585,8 +593,36 @@ void _ma_remove_table_from_trnman(MARIA_SHARE *share, TRN *trn)
my_free(tables);
break;
}
- prev= &tables->next;
}
+ if (tables != 0)
+ {
+ /*
+ This can only happens in case of rename of intermediate table as
+ part of alter table
+ */
+ DBUG_PRINT("warning", ("share: %p where not in used_tables_list", share));
+ }
+
+ /* unlink table from used_instances */
+ for (prev_file= (MARIA_HA**) &trn->used_instances;
+ (handler= *prev_file);
+ prev_file= &handler->trn_next)
+ {
+ if (handler == info)
+ {
+ *prev_file= info->trn_next;
+ break;
+ }
+ }
+ if (handler != 0)
+ {
+ /*
+ This can only happens in case of rename of intermediate table as
+ part of alter table
+ */
+ DBUG_PRINT("warning", ("table: %p where not in used_instances", info));
+ }
+ info->trn= 0; /* Not part of trans anymore */
DBUG_VOID_RETURN;
}
diff --git a/storage/maria/ma_state.h b/storage/maria/ma_state.h
index a86aada94fd..8728a2113e5 100644
--- a/storage/maria/ma_state.h
+++ b/storage/maria/ma_state.h
@@ -84,5 +84,5 @@ my_bool _ma_row_visible_non_transactional_table(MARIA_HA *info);
my_bool _ma_row_visible_transactional_table(MARIA_HA *info);
void _ma_remove_not_visible_states_with_lock(struct st_maria_share *share,
my_bool all);
-void _ma_remove_table_from_trnman(struct st_maria_share *share, TRN *trn);
+void _ma_remove_table_from_trnman(MARIA_HA *info);
void _ma_reset_history(struct st_maria_share *share);
diff --git a/storage/maria/ma_trnman.h b/storage/maria/ma_trnman.h
new file mode 100644
index 00000000000..9bfd1f0d047
--- /dev/null
+++ b/storage/maria/ma_trnman.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _ma_trnman_h
+#define _ma_trnman_h
+
+/**
+ Sets table's trn and prints debug information
+ Links table into used_instances if new_trn is not 0
+
+ @param tbl MARIA_HA of table
+ @param newtrn what to put into tbl->trn
+*/
+
+static inline void _ma_set_trn_for_table(MARIA_HA *tbl, TRN *newtrn)
+{
+ DBUG_PRINT("info",("table: %p trn: %p -> %p",
+ tbl, tbl->trn, newtrn));
+
+ /* check that we are not calling this twice in a row */
+ DBUG_ASSERT(newtrn->used_instances != (void*) tbl);
+
+ tbl->trn= newtrn;
+ /* Link into used list */
+ tbl->trn_next= (MARIA_HA*) newtrn->used_instances;
+ newtrn->used_instances= tbl;
+}
+
+
+/*
+ Same as _ma_set_trn_for_table(), but don't link table into used_instance list
+ Used when we want to temporary set trn for a table in extra()
+*/
+
+static inline void _ma_set_tmp_trn_for_table(MARIA_HA *tbl, TRN *newtrn)
+{
+ DBUG_PRINT("info",("table: %p trn: %p -> %p",
+ tbl, tbl->trn, newtrn));
+ tbl->trn= newtrn;
+}
+
+
+/*
+ Reset TRN in table
+*/
+
+static inline void _ma_reset_trn_for_table(MARIA_HA *tbl)
+{
+ DBUG_PRINT("info",("table: %p trn: %p -> NULL", tbl, tbl->trn));
+ tbl->trn= 0;
+}
+
+#endif /* _ma_trnman_h */
diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h
index 6867e1a08aa..76233ef4a94 100644
--- a/storage/maria/maria_def.h
+++ b/storage/maria/maria_def.h
@@ -602,6 +602,7 @@ struct st_maria_handler
{
MARIA_SHARE *s; /* Shared between open:s */
struct st_ma_transaction *trn; /* Pointer to active transaction */
+ struct st_maria_handler *trn_next;
MARIA_STATUS_INFO *state, state_save;
MARIA_STATUS_INFO *state_start; /* State at start of transaction */
MARIA_USED_TABLES *used_tables;
@@ -862,19 +863,6 @@ struct st_maria_handler
#define get_pack_length(length) ((length) >= 255 ? 3 : 1)
#define _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID)
-/**
- Sets table's trn and prints debug information
- @param tbl MARIA_HA of table
- @param newtrn what to put into tbl->trn
- @note cast of newtrn is because %p of NULL gives warning (NULL is int)
-*/
-#define _ma_set_trn_for_table(tbl, newtrn) do { \
- DBUG_PRINT("info",("table: %p trn: %p -> %p", \
- (tbl), (tbl)->trn, (void *)(newtrn))); \
- (tbl)->trn= (newtrn); \
- } while (0)
-
-
#define MARIA_MIN_BLOCK_LENGTH 20 /* Because of delete-link */
/* Don't use to small record-blocks */
#define MARIA_EXTEND_BLOCK_LENGTH 20
diff --git a/storage/maria/trnman.c b/storage/maria/trnman.c
index bc48d39baaa..5b3c9f0287a 100644
--- a/storage/maria/trnman.c
+++ b/storage/maria/trnman.c
@@ -357,6 +357,7 @@ TRN *trnman_new_trn(WT_THD *wt)
trn->commit_trid= MAX_TRID;
trn->rec_lsn= trn->undo_lsn= trn->first_undo_lsn= 0;
trn->used_tables= 0;
+ trn->used_instances= 0;
trn->locked_tables= 0;
trn->flags= 0;
diff --git a/storage/maria/trnman.h b/storage/maria/trnman.h
index 66139a31230..11c73797766 100644
--- a/storage/maria/trnman.h
+++ b/storage/maria/trnman.h
@@ -46,7 +46,8 @@ struct st_ma_transaction
LF_PINS *pins;
WT_THD *wt;
mysql_mutex_t state_lock;
- void *used_tables; /**< Tables used by transaction */
+ void *used_tables; /**< Table shares used by transaction */
+ void *used_instances; /* table files used by transaction */
TRN *next, *prev;
TrID trid, min_read_from, commit_trid;
LSN rec_lsn, undo_lsn;
diff --git a/storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test b/storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test
index 3316e7ea987..9e7c816ae6e 100644
--- a/storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test
+++ b/storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test
@@ -22,5 +22,5 @@ let SEARCH_PATTERN= RocksDB: Compatibility check against existing database optio
--enable_reconnect
--exec echo "restart" > $restart_file
--source include/wait_until_connected_again.inc
---exec find $MYSQLD_DATADIR/#rocksdb/OPTIONS* | sort -n | tail -1 | xargs -0 -I {} -t sh -c "sed -i '/hello=world/d' {}"
+--exec find $MYSQLD_DATADIR/#rocksdb/OPTIONS* | sort -n | tail -1 | xargs -0 -I {} -t sh -c "sed -i'' -e '/hello=world/d' {}"
select variable_name, variable_value from information_schema.global_variables where variable_name="rocksdb_ignore_unknown_options";
diff --git a/unittest/sql/mf_iocache-t.cc b/unittest/sql/mf_iocache-t.cc
index f27e49d7ea3..b94b4ef0905 100644
--- a/unittest/sql/mf_iocache-t.cc
+++ b/unittest/sql/mf_iocache-t.cc
@@ -188,10 +188,76 @@ void mdev9044()
close_cached_file(&info);
}
+/* 2 Reads (with my_b_fill) in cache makes second read to fail */
+void mdev10259()
+{
+ int res;
+ uchar buf[200];
+ memset(buf, FILL, sizeof(buf));
+
+ diag("MDEV-10259- mysqld crash with certain statement length and order with"
+ " Galera and encrypt-tmp-files=1");
+
+ init_io_cache_encryption();
+
+ res= open_cached_file(&info, 0, 0, CACHE_SIZE, 0);
+ ok(res == 0, "open_cached_file" INFO_TAIL);
+
+ res= my_b_write(&info, buf, sizeof(buf));
+ ok(res == 0 && info.pos_in_file == 0, "200 write" INFO_TAIL);
+
+ res= my_b_flush_io_cache(&info, 1);
+ ok(res == 0, "flush" INFO_TAIL);
+
+ my_off_t saved_pos= my_b_tell(&info);
+ res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
+ ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
+
+ res= my_b_fill(&info);
+ ok(res == 200, "fill" INFO_TAIL);
+
+ res= my_b_fill(&info);
+ ok(res == 0, "fill" INFO_TAIL);
+
+ res= my_b_fill(&info);
+ ok(res == 0, "fill" INFO_TAIL);
+
+ res= reinit_io_cache(&info, WRITE_CACHE, saved_pos, 0, 0);
+ ok(res == 0, "reinit WRITE_CACHE" INFO_TAIL);
+
+ res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
+ ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
+
+ ok(200 == my_b_bytes_in_cache(&info),"my_b_bytes_in_cache == 200");
+
+ res= my_b_fill(&info);
+ ok(res == 0, "fill" INFO_TAIL);
+
+ res= my_b_fill(&info);
+ ok(res == 0, "fill" INFO_TAIL);
+
+ res= my_b_fill(&info);
+ ok(res == 0, "fill" INFO_TAIL);
+
+ res= reinit_io_cache(&info, WRITE_CACHE, saved_pos, 0, 0);
+ ok(res == 0, "reinit WRITE_CACHE" INFO_TAIL);
+
+ res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
+ ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
+
+ ok(200 == my_b_bytes_in_cache(&info),"my_b_bytes_in_cache == 200");
+
+ res= my_b_read(&info, buf, sizeof(buf)) || data_bad(buf, sizeof(buf));
+ ok(res == 0 && info.pos_in_file == 0, "large read" INFO_TAIL);
+
+ close_cached_file(&info);
+
+}
+
int main(int argc __attribute__((unused)),char *argv[])
{
MY_INIT(argv[0]);
- plan(29);
+ plan(46);
/* temp files with and without encryption */
encrypt_tmp_files= 1;
@@ -203,6 +269,10 @@ int main(int argc __attribute__((unused)),char *argv[])
/* regression tests */
mdev9044();
+ encrypt_tmp_files= 1;
+ mdev10259();
+ encrypt_tmp_files= 0;
+
my_end(0);
return exit_status();
}