diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-05-29 17:34:49 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-05-29 17:34:49 +0300 |
commit | a3539bbb2ac51dfa2b363d3b4c11784c25d1f256 (patch) | |
tree | 6b49da1f15e5740adaf5da1c4179760a15b77dc4 | |
parent | c98e6d4b3d4d17ee429c696ac07e0bc4bbe1a81e (diff) | |
parent | 6f96ff7268dd20d6d3b61931c972e7a43c1efdff (diff) | |
download | mariadb-git-a3539bbb2ac51dfa2b363d3b4c11784c25d1f256.tar.gz |
Merge 10.2 into 10.3
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(); } |