diff options
author | Monty <monty@mariadb.org> | 2017-11-09 23:21:41 +0200 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2017-11-09 23:21:41 +0200 |
commit | 0bb0d52221af99c46d17486382806caa6dd7338e (patch) | |
tree | 92b2ddfceaf8df5be6d47774b25fd3006ac5bb35 | |
parent | 7dbff2c513aeec3b3f3d0fa4952ae97deba22282 (diff) | |
parent | d40c23570ff1a9ba5aa317b85a32a4b27780b8ab (diff) | |
download | mariadb-git-0bb0d52221af99c46d17486382806caa6dd7338e.tar.gz |
Merge remote-tracking branch 'origin/10.2' into bb-10.2-ext
Conflicts:
mysql-test/r/cte_recursive.result
mysql-test/r/derived_cond_pushdown.result
mysql-test/t/cte_recursive.test
mysql-test/t/derived_cond_pushdown.test
sql/datadict.cc
sql/handler.cc
100 files changed, 1187 insertions, 897 deletions
diff --git a/client/mysql.cc b/client/mysql.cc index 5fe940eeca7..50114ee8b65 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1094,7 +1094,7 @@ inline bool is_delimiter_command(char *name, ulong len) only name(first DELIMITER_NAME_LEN bytes) is checked. */ return (len >= DELIMITER_NAME_LEN && - !my_strnncoll(charset_info, (uchar*) name, DELIMITER_NAME_LEN, + !my_strnncoll(&my_charset_latin1, (uchar*) name, DELIMITER_NAME_LEN, (uchar *) DELIMITER_NAME, DELIMITER_NAME_LEN)); } diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index bc37f347532..0b501970efa 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -46,6 +46,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include <ut0mem.h> #include <srv0start.h> #include <fil0fil.h> +#include <trx0sys.h> #include <set> #include <string> #include <mysqld.h> @@ -1680,26 +1681,30 @@ copy_back() ut_crc32_init(); /* copy undo tablespaces */ - if (srv_undo_tablespaces > 0) { - dst_dir = (srv_undo_dir && *srv_undo_dir) - ? srv_undo_dir : mysql_data_home; - ds_data = ds_create(dst_dir, DS_TYPE_LOCAL); + dst_dir = (srv_undo_dir && *srv_undo_dir) + ? srv_undo_dir : mysql_data_home; - for (ulong i = 1; i <= srv_undo_tablespaces; i++) { - char filename[20]; - sprintf(filename, "undo%03lu", i); - if (!(ret = copy_or_move_file(filename, filename, - dst_dir, 1))) { - goto cleanup; - } - } + ds_data = ds_create(dst_dir, DS_TYPE_LOCAL); - ds_destroy(ds_data); - ds_data = NULL; + for (uint i = 1; i <= TRX_SYS_MAX_UNDO_SPACES; i++) { + char filename[20]; + sprintf(filename, "undo%03u", i); + if (!file_exists(filename)) { + break; + } + if (!(ret = copy_or_move_file(filename, filename, + dst_dir, 1))) { + goto cleanup; + } } + ds_destroy(ds_data); + ds_data = NULL; + + /* copy redo logs */ + dst_dir = (srv_log_group_home_dir && *srv_log_group_home_dir) ? srv_log_group_home_dir : mysql_data_home; @@ -1825,7 +1830,7 @@ copy_back() } } - /* copy buufer pool dump */ + /* copy buffer pool dump */ if (innobase_buffer_pool_filename) { const char *src_name; diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index a6bc4dab552..de32b5b864f 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2838,7 +2838,7 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback) /* We found a symlink or a file */ if (strlen(fileinfo.name) > 4) { bool is_isl= false; - if (ends_with(fileinfo.name, ".ibd") || ((is_isl = ends_with(fileinfo.name, ".ibd")))) + if (ends_with(fileinfo.name, ".ibd") || ((is_isl = ends_with(fileinfo.name, ".isl")))) (*callback)(dbinfo.name, fileinfo.name, is_isl); } } diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test index 3b2c2a46590..a282201857e 100644 --- a/mysql-test/include/check-testcase.test +++ b/mysql-test/include/check-testcase.test @@ -82,6 +82,8 @@ call mtr.check_testcase(); let $datadir=`select @@datadir`; list_files $datadir mysql_upgrade_info; +list_files $datadir/test #sql*; +list_files $datadir/mysql #sql*; --enable_query_log diff --git a/mysql-test/r/cte_nonrecursive.result b/mysql-test/r/cte_nonrecursive.result index 3ad6fb8fabe..d0e42cf4042 100644 --- a/mysql-test/r/cte_nonrecursive.result +++ b/mysql-test/r/cte_nonrecursive.result @@ -1079,3 +1079,71 @@ id select_type table type possible_keys key key_len ref rows Extra 3 DERIVED t2 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) NULL UNION RESULT <union1,4> ALL NULL NULL NULL NULL NULL DROP TABLE t1,t2; +# +# MDEV-13780: tower of embedding CTEs with multiple usage of them +# +create table t1 (a int); +insert into t1 values (3), (2), (4), (7), (1), (2), (5); +with cte_e as +( +with cte_o as +( +with cte_i as (select * from t1 where a < 7) +select * from cte_i where a > 1 +) +select * from cte_o as cto_o1 where a < 3 +union +select * from cte_o as cto_o2 where a > 4 +) +select * from cte_e as cte_e1 where a > 1 +union +select * from cte_e as cte_e2; +a +2 +5 +explain extended with cte_e as +( +with cte_o as +( +with cte_i as (select * from t1 where a < 7) +select * from cte_i where a > 1 +) +select * from cte_o as cto_o1 where a < 3 +union +select * from cte_o as cto_o2 where a > 4 +) +select * from cte_e as cte_e1 where a > 1 +union +select * from cte_e as cte_e2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 14 100.00 Using where +2 DERIVED t1 ALL NULL NULL NULL NULL 7 100.00 Using where +5 UNION t1 ALL NULL NULL NULL NULL 7 100.00 Using where +NULL UNION RESULT <union2,5> ALL NULL NULL NULL NULL NULL NULL +6 UNION <derived9> ALL NULL NULL NULL NULL 14 100.00 +9 DERIVED t1 ALL NULL NULL NULL NULL 7 100.00 Using where +12 UNION t1 ALL NULL NULL NULL NULL 7 100.00 Using where +NULL UNION RESULT <union9,12> ALL NULL NULL NULL NULL NULL NULL +NULL UNION RESULT <union1,6> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1003 with cte_e as (with cte_o as (with cte_i as (/* select#4 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` < 7)/* select#3 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` > 1)/* select#2 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` < 3 and `test`.`t1`.`a` > 1 and `test`.`t1`.`a` < 7 and `test`.`t1`.`a` > 1 union /* select#5 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` > 4 and `test`.`t1`.`a` > 1 and `test`.`t1`.`a` < 7 and `test`.`t1`.`a` > 1)/* select#1 */ select `cte_e1`.`a` AS `a` from `cte_e` `cte_e1` where `cte_e1`.`a` > 1 union /* select#6 */ select `cte_e2`.`a` AS `a` from `cte_e` `cte_e2` +drop table t1; +# +# MDEV-13753: embedded CTE in a VIEW created in prepared statement +# +SET @sql_query = " + CREATE OR REPLACE VIEW cte_test AS + WITH cte1 AS ( SELECT 1 as a from dual ) + , cte2 AS ( SELECT * FROM cte1 ) + SELECT * FROM cte2; +"; +PREPARE stmt FROM @sql_query; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +SHOW CREATE VIEW cte_test; +View Create View character_set_client collation_connection +cte_test CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `cte_test` AS with cte1 as (select 1 AS `a`), cte2 as (select `cte1`.`a` AS `a` from `cte1`)select `cte2`.`a` AS `a` from `cte2` latin1 latin1_swedish_ci +SELECT * FROM cte_test; +a +1 +DROP VIEW cte_test; diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result index 8cb47190a6f..b902333ddc4 100644 --- a/mysql-test/r/cte_recursive.result +++ b/mysql-test/r/cte_recursive.result @@ -2882,6 +2882,28 @@ f set standard_compliant_cte=default; DROP TABLE t; # +# mdev-14184: recursive CTE embedded into CTE with multiple references +# +WITH +cte1 AS ( +SELECT n FROM ( +WITH RECURSIVE rec_cte(n) AS ( +SELECT 1 as n1 +UNION ALL +SELECT n+1 as n2 FROM rec_cte WHERE n < 3 +) SELECT n FROM rec_cte +) AS X +), +cte2 as ( +SELECT 2 FROM cte1 +) +SELECT * +FROM cte1; +n +1 +2 +3 +# # MDEV-14217 [db crash] Recursive CTE when SELECT includes new field # CREATE TEMPORARY TABLE a_tbl ( diff --git a/mysql-test/r/delimiter_command_case_sensitivity.result b/mysql-test/r/delimiter_command_case_sensitivity.result new file mode 100644 index 00000000000..6ed281c757a --- /dev/null +++ b/mysql-test/r/delimiter_command_case_sensitivity.result @@ -0,0 +1,2 @@ +1 +1 diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index 9001c5fef43..d8d03d6d062 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -8783,6 +8783,47 @@ EXPLAIN DROP VIEW v2; DROP TABLE t1,t2; # +# MDEV-14237: derived with regexp_substr() in select list +# +create table t1 (a char(8)); +insert into t1 values ('b'), ('a'), ('xx'); +select * +from ( select distinct regexp_substr(t1.a,'^[A-Za-z]+') as f from t1) as t +where t.f = 'a' or t.f = 'b'; +f +b +a +explain format=json select * +from ( select distinct regexp_substr(t1.a,'^[A-Za-z]+') as f from t1) as t +where t.f = 'a' or t.f = 'b'; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<derived2>", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t.f = 'a' or t.f = 'b'", + "materialized": { + "query_block": { + "select_id": 2, + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + } + } + } + } +} +drop table t1; +# # MDEV-10855: Pushdown into derived with window functions # set @save_optimizer_switch= @@optimizer_switch; diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 299b6344192..f2934804426 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -1458,6 +1458,20 @@ CONCAT(NAME_CONST('name',15),'오') 15오 SET NAMES latin1; # +# MDEV-14116 INET6_NTOA output is set as null to varchar(39) variable +# +CREATE PROCEDURE p1() +BEGIN +DECLARE ip_full_addr varchar(39) DEFAULT ""; +SELECT INET6_NTOA(UNHEX('20000000000000000000000000000000')) into ip_full_addr; +SELECT ip_full_addr; +END; +$$ +CALL p1(); +ip_full_addr +2000:: +DROP PROCEDURE p1; +# # Start of 10.2 tests # # diff --git a/mysql-test/r/subselect_exists2in.result b/mysql-test/r/subselect_exists2in.result index 8b525436c2f..95fc1c19b82 100644 --- a/mysql-test/r/subselect_exists2in.result +++ b/mysql-test/r/subselect_exists2in.result @@ -934,5 +934,42 @@ f2 foo set optimizer_switch= @optimizer_switch_save; DROP TABLE t1; +# +# MDEV-14164: Unknown column error when adding aggregate to function +# in oracle style procedure FOR loop +# +CREATE TABLE t1(id INT, val INT); +CREATE PROCEDURE p1() +BEGIN +DECLARE cur1 CURSOR FOR SELECT * FROM ( +SELECT DISTINCT id FROM t1) a +WHERE NOT EXISTS (SELECT * FROM ( SELECT id FROM t1) b +WHERE a.id=b.id); +OPEN cur1; +CLOSE cur1; +OPEN cur1; +CLOSE cur1; +END; +// +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; +CREATE TABLE t1(id INT, val INT); +CREATE PROCEDURE p1() +BEGIN +SELECT * FROM (SELECT DISTINCT id FROM t1) a +WHERE NOT a.id IN (SELECT b.id FROM t1 b); +SELECT * FROM (SELECT DISTINCT id FROM t1) a +WHERE NOT EXISTS (SELECT * FROM t1 b WHERE a.id=b.id); +END; +// +CALL p1(); +id +id +CALL p1(); +id +id +DROP PROCEDURE p1; +DROP TABLE t1; # End of 10.0 tests set optimizer_switch=default; diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index b2067907391..30cd94c9277 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -806,3 +806,27 @@ SUM(a) NULL DROP TABLE t1; End of 5.1 tests +# +# Start of 10.1 tests +# +# +# MDEV-8867 Wrong field type or metadata for COALESCE(bit_column, 1) +# +CREATE TABLE t1 (val bit(1)); +INSERT INTO t1 VALUES (0); +CREATE TABLE t2 AS SELECT COALESCE(val, 1) AS c FROM t1; +SELECT * FROM t2; +c +0 +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `c` decimal(1,0) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +SELECT COALESCE(val, 1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(val, 1) 246 2 1 Y 32896 0 63 +COALESCE(val, 1) +0 +DROP TABLE t1; diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index d56fac962fe..69bdf569787 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -852,6 +852,17 @@ Warning 1292 Incorrect datetime value: '1' Warning 1292 Incorrect datetime value: '1' DROP TABLE t1; # +# MDEV-14221 Assertion `0' failed in Item::field_type_for_temporal_comparison +# +CREATE TABLE t1 (d DATE); +INSERT INTO t1 VALUES ('1985-05-13'),('1989-12-24'); +SELECT d, COUNT(*) FROM t1 GROUP BY d WITH ROLLUP HAVING CASE d WHEN '2017-05-25' THEN 0 ELSE 1 END; +d COUNT(*) +1985-05-13 1 +1989-12-24 1 +NULL 2 +DROP TABLE t1; +# # End of 10.1 tests # # diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result index 1600732cec3..89718ea8363 100644 --- a/mysql-test/r/type_time.result +++ b/mysql-test/r/type_time.result @@ -1245,6 +1245,20 @@ a b c 2070 00:00:00 00:00:00 DROP TABLE t1,t2; # +# MDEV-10817 CAST(MAX(DATE'2001-01-01') AS TIME) returns a wrong result +# +SELECT CAST(DATE'2001-01-01' AS TIME); +CAST(DATE'2001-01-01' AS TIME) +00:00:00 +SELECT CAST(MAX(DATE'2001-01-01') AS TIME); +CAST(MAX(DATE'2001-01-01') AS TIME) +00:00:00 +CREATE FUNCTION f1() RETURNS DATE RETURN DATE'2001-01-01'; +SELECT CAST(f1() AS TIME); +CAST(f1() AS TIME) +00:00:00 +DROP FUNCTION f1; +# # End of 10.2 tests # # diff --git a/mysql-test/suite/mariabackup/data_directory.result b/mysql-test/suite/mariabackup/data_directory.result new file mode 100644 index 00000000000..e7201918cbd --- /dev/null +++ b/mysql-test/suite/mariabackup/data_directory.result @@ -0,0 +1,13 @@ +CREATE TABLE t(a INT) ENGINE=InnoDB DATA DIRECTORY='table_data_dir'; +INSERT INTO t VALUES(1); +# xtrabackup backup +# xtrabackup prepare +DROP TABLE t; +# shutdown server +# remove datadir +# xtrabackup move back +# restart server +SELECT * FROM t; +a +1 +DROP TABLE t; diff --git a/mysql-test/suite/mariabackup/data_directory.test b/mysql-test/suite/mariabackup/data_directory.test new file mode 100644 index 00000000000..50789a34c78 --- /dev/null +++ b/mysql-test/suite/mariabackup/data_directory.test @@ -0,0 +1,23 @@ +let $table_data_dir=$MYSQLTEST_VARDIR/ddir; +mkdir $table_data_dir; +--replace_result $table_data_dir table_data_dir +EVAL CREATE TABLE t(a INT) ENGINE=InnoDB DATA DIRECTORY='$table_data_dir'; +INSERT INTO t VALUES(1); +echo # xtrabackup backup; +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +--enable_result_log +--source include/shutdown_mysqld.inc +echo # xtrabackup prepare; +--disable_result_log +exec $XTRABACKUP --prepare --target-dir=$targetdir; +--source include/start_mysqld.inc +DROP TABLE t; +rmdir $table_data_dir; +-- source include/restart_and_restore.inc +--enable_result_log +SELECT * FROM t; +DROP TABLE t; +rmdir $targetdir; +rmdir $table_data_dir; diff --git a/mysql-test/suite/mariabackup/incremental_backup.result b/mysql-test/suite/mariabackup/incremental_backup.result index eeedc751d83..cc7277bdde9 100644 --- a/mysql-test/suite/mariabackup/incremental_backup.result +++ b/mysql-test/suite/mariabackup/incremental_backup.result @@ -1,13 +1,22 @@ call mtr.add_suppression("InnoDB: New log files created"); -CREATE TABLE t(i INT) ENGINE INNODB; +CREATE TABLE t(i INT PRIMARY KEY) ENGINE INNODB; +BEGIN; +INSERT INTO t VALUES(2); +connect con1,localhost,root,,; +SET GLOBAL innodb_flush_log_at_trx_commit = 1; INSERT INTO t VALUES(1); # Create full backup , modify table, then create incremental/differential backup -INSERT INTO t VALUES(2); +BEGIN; +INSERT INTO t VALUES(0); +DELETE FROM t WHERE i=0; +connection default; +COMMIT; SELECT * FROM t; i 1 2 # Prepare full backup, apply incremental one +disconnect con1; # Restore and check results # shutdown server # remove datadir diff --git a/mysql-test/suite/mariabackup/incremental_backup.test b/mysql-test/suite/mariabackup/incremental_backup.test index b60b151563f..8fbfa701999 100644 --- a/mysql-test/suite/mariabackup/incremental_backup.test +++ b/mysql-test/suite/mariabackup/incremental_backup.test @@ -5,14 +5,22 @@ call mtr.add_suppression("InnoDB: New log files created"); let $basedir=$MYSQLTEST_VARDIR/tmp/backup; let $incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1; -CREATE TABLE t(i INT) ENGINE INNODB; +CREATE TABLE t(i INT PRIMARY KEY) ENGINE INNODB; +BEGIN; +INSERT INTO t VALUES(2); +connect (con1,localhost,root,,); +SET GLOBAL innodb_flush_log_at_trx_commit = 1; INSERT INTO t VALUES(1); echo # Create full backup , modify table, then create incremental/differential backup; --disable_result_log exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; --enable_result_log -INSERT INTO t VALUES(2); +BEGIN; +INSERT INTO t VALUES(0); +DELETE FROM t WHERE i=0; +connection default; +COMMIT; SELECT * FROM t; exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --ftwrl-wait-timeout=5 --ftwrl-wait-threshold=300 --ftwrl-wait-query-type=all --target-dir=$incremental_dir --incremental-basedir=$basedir; @@ -21,6 +29,7 @@ echo # Prepare full backup, apply incremental one; exec $XTRABACKUP --prepare --target-dir=$basedir; exec $XTRABACKUP --prepare --target-dir=$basedir --incremental-dir=$incremental_dir ; +disconnect con1; echo # Restore and check results; let $targetdir=$basedir; -- source include/restart_and_restore.inc diff --git a/mysql-test/suite/mariabackup/partition_datadir.opt b/mysql-test/suite/mariabackup/partition_datadir.opt new file mode 100644 index 00000000000..8a3240370eb --- /dev/null +++ b/mysql-test/suite/mariabackup/partition_datadir.opt @@ -0,0 +1 @@ +--partition
\ No newline at end of file diff --git a/mysql-test/suite/mariabackup/partition_datadir.result b/mysql-test/suite/mariabackup/partition_datadir.result new file mode 100644 index 00000000000..3fc5fe30907 --- /dev/null +++ b/mysql-test/suite/mariabackup/partition_datadir.result @@ -0,0 +1,22 @@ +CREATE TABLE t(i int) +ENGINE=InnoDB +PARTITION BY RANGE (i) +(PARTITION p0 VALUES LESS THAN (100), +PARTITION P1 VALUES LESS THAN (200), +PARTITION p2 VALUES LESS THAN (300) DATA DIRECTORY = 'MYSQLTEST_VARDIR/partitdata', +PARTITION p3 VALUES LESS THAN (400) DATA DIRECTORY = 'MYSQLTEST_VARDIR/partitdata', +PARTITION p4 VALUES LESS THAN MAXVALUE); +INSERT INTO t VALUES (1), (101), (201), (301), (401); +DROP TABLE t; +# shutdown server +# remove datadir +# xtrabackup move back +# restart server +SELECT * FROM t; +i +1 +101 +201 +301 +401 +DROP TABLE t; diff --git a/mysql-test/suite/mariabackup/partition_datadir.test b/mysql-test/suite/mariabackup/partition_datadir.test new file mode 100644 index 00000000000..882b0111267 --- /dev/null +++ b/mysql-test/suite/mariabackup/partition_datadir.test @@ -0,0 +1,24 @@ +let $targetdir=$MYSQLTEST_VARDIR/backup; +mkdir $targetdir; +mkdir $MYSQLTEST_VARDIR/partitdata; + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval CREATE TABLE t(i int) +ENGINE=InnoDB +PARTITION BY RANGE (i) +(PARTITION p0 VALUES LESS THAN (100), + PARTITION P1 VALUES LESS THAN (200), + PARTITION p2 VALUES LESS THAN (300) DATA DIRECTORY = '$MYSQLTEST_VARDIR/partitdata', + PARTITION p3 VALUES LESS THAN (400) DATA DIRECTORY = '$MYSQLTEST_VARDIR/partitdata', + PARTITION p4 VALUES LESS THAN MAXVALUE); +INSERT INTO t VALUES (1), (101), (201), (301), (401); +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +exec $XTRABACKUP --prepare --target-dir=$targetdir; +DROP TABLE t; +rmdir $MYSQLTEST_VARDIR/partitdata; +--source include/restart_and_restore.inc +--enable_result_log +SELECT * FROM t; +DROP TABLE t; +rmdir $targetdir; +rmdir $MYSQLTEST_VARDIR/partitdata; diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 45206c8bcb4..0d02ae47586 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -52,6 +52,7 @@ alter table t1 rename renamed_t1; set global server_audit_events='connect,query'; select 1, 2, +# comment 3; 1 2 3 1 2 3 @@ -170,7 +171,9 @@ id 2 CREATE USER u1 IDENTIFIED BY 'pwd-123'; GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321"; -SET PASSWORD FOR u1 = PASSWORD('pwd 098'); +SET PASSWORD +# comment +FOR u1 = PASSWORD('pwd 098'); SET PASSWORD FOR u1=<secret>; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<secret>' at line 1 CREATE USER u3 IDENTIFIED BY ''; @@ -262,7 +265,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,index_stats, TIME,HOSTNAME,root,localhost,ID,ID,RENAME,test,t1|test.renamed_t1, TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'alter table t1 rename renamed_t1',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_events=\'connect,query\'',0 -TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 1, 2, 3',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 1,\n2,\n# comment\n3',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'insert into t2 values (1), (2)',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select * from t2',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select * from t_doesnt_exist',ID @@ -345,7 +348,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'/*! select 2*/',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'/*comment*/ select 2',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u1 IDENTIFIED BY *****',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'GRANT ALL ON sa_db TO u2 IDENTIFIED BY *****',0 -TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SET PASSWORD FOR u1 = PASSWORD(*****)',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SET PASSWORD \n# comment\nFOR u1 = PASSWORD(*****)',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SET PASSWORD FOR u1=<secret>',ID TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u3 IDENTIFIED BY *****',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop user u1, u2, u3',0 diff --git a/mysql-test/suite/plugins/r/thread_pool_server_audit.result b/mysql-test/suite/plugins/r/thread_pool_server_audit.result index 45206c8bcb4..cf09ccb3a51 100644 --- a/mysql-test/suite/plugins/r/thread_pool_server_audit.result +++ b/mysql-test/suite/plugins/r/thread_pool_server_audit.result @@ -52,6 +52,7 @@ alter table t1 rename renamed_t1; set global server_audit_events='connect,query'; select 1, 2, +# comment 3; 1 2 3 1 2 3 @@ -170,7 +171,9 @@ id 2 CREATE USER u1 IDENTIFIED BY 'pwd-123'; GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321"; -SET PASSWORD FOR u1 = PASSWORD('pwd 098'); +SET PASSWORD +# comment +FOR u1 = PASSWORD('pwd 098'); SET PASSWORD FOR u1=<secret>; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '<secret>' at line 1 CREATE USER u3 IDENTIFIED BY ''; @@ -262,7 +265,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,index_stats, TIME,HOSTNAME,root,localhost,ID,ID,RENAME,test,t1|test.renamed_t1, TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'alter table t1 rename renamed_t1',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_events=\'connect,query\'',0 -TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 1, 2, 3',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 1,\n2,\n# comment\n3',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'insert into t2 values (1), (2)',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select * from t2',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select * from t_doesnt_exist',ID @@ -345,7 +348,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'/*! select 2*/',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'/*comment*/ select 2',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u1 IDENTIFIED BY *****',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'GRANT ALL ON sa_db TO u2 IDENTIFIED BY *****',0 -TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SET PASSWORD FOR u1 = PASSWORD(*****)',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SET PASSWORD\n# comment\nFOR u1 = PASSWORD(*****)',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SET PASSWORD FOR u1=<secret>',ID TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u3 IDENTIFIED BY *****',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop user u1, u2, u3',0 diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test index 52428909c3b..9be0d5556f0 100644 --- a/mysql-test/suite/plugins/t/server_audit.test +++ b/mysql-test/suite/plugins/t/server_audit.test @@ -38,6 +38,7 @@ alter table t1 rename renamed_t1; set global server_audit_events='connect,query'; select 1, 2, +# comment 3; insert into t2 values (1), (2); select * from t2; @@ -106,7 +107,9 @@ insert into t1 values (1), (2); select * from t1; CREATE USER u1 IDENTIFIED BY 'pwd-123'; GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321"; -SET PASSWORD FOR u1 = PASSWORD('pwd 098'); +SET PASSWORD +# comment +FOR u1 = PASSWORD('pwd 098'); --error 1064 SET PASSWORD FOR u1=<secret>; CREATE USER u3 IDENTIFIED BY ''; diff --git a/mysql-test/suite/plugins/t/thread_pool_server_audit.test b/mysql-test/suite/plugins/t/thread_pool_server_audit.test index 626d4136c47..724000c9789 100644 --- a/mysql-test/suite/plugins/t/thread_pool_server_audit.test +++ b/mysql-test/suite/plugins/t/thread_pool_server_audit.test @@ -38,6 +38,7 @@ alter table t1 rename renamed_t1; set global server_audit_events='connect,query'; select 1, 2, +# comment 3; insert into t2 values (1), (2); select * from t2; @@ -106,7 +107,9 @@ insert into t1 values (1), (2); select * from t1; CREATE USER u1 IDENTIFIED BY 'pwd-123'; GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321"; -SET PASSWORD FOR u1 = PASSWORD('pwd 098'); +SET PASSWORD +# comment +FOR u1 = PASSWORD('pwd 098'); --error 1064 SET PASSWORD FOR u1=<secret>; CREATE USER u3 IDENTIFIED BY ''; diff --git a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_now_basic.result b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_now_basic.result index 9c3a37f892b..522d5731a6d 100644 --- a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_now_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_now_basic.result @@ -1,7 +1,8 @@ -SET @orig = @@global.innodb_buffer_pool_dump_now; -SELECT @orig; -@orig +SELECT @@global.innodb_buffer_pool_dump_now; +@@global.innodb_buffer_pool_dump_now 0 +SELECT variable_value INTO @old_dump_status FROM information_schema.global_status +WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status'; SET GLOBAL innodb_buffer_pool_dump_now = ON; SELECT @@global.innodb_buffer_pool_dump_now; @@global.innodb_buffer_pool_dump_now diff --git a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_pct_basic.result b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_pct_basic.result index 485136ccc4c..93a85ffbf43 100644 --- a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_pct_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_pct_basic.result @@ -1,7 +1,9 @@ SET @orig = @@global.innodb_buffer_pool_dump_pct; -SELECT @@global.innodb_buffer_pool_dump_pct; -@@global.innodb_buffer_pool_dump_pct +SELECT @orig; +@orig 25 +SET GLOBAL innodb_buffer_pool_dump_pct=3; +# Do the dump SET GLOBAL innodb_buffer_pool_dump_pct=20; SELECT @@global.innodb_buffer_pool_dump_pct; @@global.innodb_buffer_pool_dump_pct diff --git a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_load_now_basic.result b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_load_now_basic.result index 3185d1ca170..eebed4d0f4a 100644 --- a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_load_now_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_load_now_basic.result @@ -1,8 +1,6 @@ -SET @orig = @@global.innodb_buffer_pool_load_now; -SELECT @orig; -@orig +SELECT @@global.innodb_buffer_pool_load_now; +@@global.innodb_buffer_pool_load_now 0 -SET GLOBAL innodb_buffer_pool_dump_now = ON; SET GLOBAL innodb_buffer_pool_load_now = ON; SELECT variable_value FROM information_schema.global_status diff --git a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_now_basic.test b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_now_basic.test index 0bae347428e..8c5f8fa7bf0 100644 --- a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_now_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_now_basic.test @@ -5,8 +5,31 @@ -- source include/have_innodb.inc # Check the default value -SET @orig = @@global.innodb_buffer_pool_dump_now; -SELECT @orig; +SELECT @@global.innodb_buffer_pool_dump_now; + +-- let $file = `SELECT CONCAT(@@datadir, @@global.innodb_buffer_pool_filename)` +-- error 0,1 +-- remove_file $file + +SELECT variable_value INTO @old_dump_status FROM information_schema.global_status + WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status'; + +# A previous test could have run buffer pool dump already; +# in this case we want to make sure that the current time is different +# from the timestamp in the status variable. +# We should have had a smart wait condition here, like the commented one below, +# let $wait_condition = +# SELECT TRIM(SUBSTR('$old_status', -8)) != DATE_FORMAT(CURTIME(), '%k:%i:%s'); +# -- source include/wait_condition.inc + +# ... but we can't because of MDEV-9867, so there will be just sleep instead. +# And it might be not enough to sleep one second, so we'll have to sleep two. + +if (`SELECT variable_value LIKE '%completed at%' FROM information_schema.global_status + WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status'`) +{ + -- sleep 2 +} # Do the dump SET GLOBAL innodb_buffer_pool_dump_now = ON; @@ -15,11 +38,11 @@ SELECT @@global.innodb_buffer_pool_dump_now; # Wait for the dump to complete let $wait_condition = - SELECT SUBSTR(variable_value, 1, 33) = 'Buffer pool(s) dump completed at ' + SELECT variable_value != @old_dump_status + AND SUBSTR(variable_value, 1, 33) = 'Buffer pool(s) dump completed at ' FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status'; -- source include/wait_condition.inc # Confirm that the dump file has been created --- let $file = `SELECT CONCAT(@@datadir, @@global.innodb_buffer_pool_filename)` -- file_exists $file diff --git a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_pct_basic.test b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_pct_basic.test index 99d3f79fb27..9b4edafb17e 100644 --- a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_pct_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_pct_basic.test @@ -11,9 +11,17 @@ # Save the default value SET @orig = @@global.innodb_buffer_pool_dump_pct; +SELECT @orig; -# Check the default value -SELECT @@global.innodb_buffer_pool_dump_pct; +SET GLOBAL innodb_buffer_pool_dump_pct=3; + +--echo # Do the dump + +--disable_query_log +--disable_result_log +--source innodb_buffer_pool_dump_now_basic.test +--enable_result_log +--enable_query_log # Set the valid value SET GLOBAL innodb_buffer_pool_dump_pct=20; diff --git a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_load_now_basic.opt b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_load_now_basic.opt new file mode 100644 index 00000000000..e462be3c368 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_load_now_basic.opt @@ -0,0 +1 @@ +--innodb-buffer-pool-load-at-startup=off diff --git a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_load_now_basic.test b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_load_now_basic.test index a260dc2516b..15536d338e1 100644 --- a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_load_now_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_load_now_basic.test @@ -5,44 +5,22 @@ -- source include/have_innodb.inc # Check the default value -SET @orig = @@global.innodb_buffer_pool_load_now; -SELECT @orig; +SELECT @@global.innodb_buffer_pool_load_now; -let $old_status= `SELECT variable_value FROM information_schema.global_status - WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status'`; +# Make sure there is a dump file to load -# A previous test could have run buffer pool dump already; -# in this case we want to make sure that the current time is different -# from the timestamp in the status variable. -# We should have had a smart wait condition here, like the commented one below, -# but we can't because of MDEV-9867, so there will be just sleep instead. -# And it might be not enough to sleep one second, so we'll have to sleep two. -# let $wait_condition = -# SELECT TRIM(SUBSTR('$old_status', -8)) != DATE_FORMAT(CURTIME(), '%k:%i:%s'); -# -- source include/wait_condition.inc -if (`SELECT count(*) > 0 FROM information_schema.global_status - WHERE (LOWER(variable_name) = 'innodb_buffer_pool_dump_status' or - LOWER(variable_name) = 'innodb_buffer_pool_load_status') - and variable_value LIKE '%completed at%'`) -{ - -- sleep 2 -} -# Do the dump -SET GLOBAL innodb_buffer_pool_dump_now = ON; - -# Wait for the dump to complete -let $wait_condition = - SELECT variable_value != '$old_status' - AND SUBSTR(variable_value, 1, 33) = 'Buffer pool(s) dump completed at ' - FROM information_schema.global_status - WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status'; ---disable_warnings --- source include/wait_condition.inc ---enable_warnings - -# Confirm the file is really created -- let $file = `SELECT CONCAT(@@datadir, @@global.innodb_buffer_pool_filename)` +-- error 0,1 -- file_exists $file +if ($errno) +{ + # Dump file does not exist, get it created + --disable_query_log + --disable_result_log + --source innodb_buffer_pool_dump_now_basic.test + --enable_result_log + --enable_query_log +} let $old_load_status= `SELECT variable_value FROM information_schema.global_status diff --git a/mysql-test/t/cte_nonrecursive.test b/mysql-test/t/cte_nonrecursive.test index 57b7ae1658f..742e8f6e4d7 100644 --- a/mysql-test/t/cte_nonrecursive.test +++ b/mysql-test/t/cte_nonrecursive.test @@ -743,3 +743,50 @@ eval $q; eval explain $q; DROP TABLE t1,t2; + +--echo # +--echo # MDEV-13780: tower of embedding CTEs with multiple usage of them +--echo # + +create table t1 (a int); +insert into t1 values (3), (2), (4), (7), (1), (2), (5); + +let $q= +with cte_e as +( + with cte_o as + ( + with cte_i as (select * from t1 where a < 7) + select * from cte_i where a > 1 + ) + select * from cte_o as cto_o1 where a < 3 + union + select * from cte_o as cto_o2 where a > 4 +) +select * from cte_e as cte_e1 where a > 1 +union +select * from cte_e as cte_e2; + +eval $q; +eval explain extended $q; + +drop table t1; + +--echo # +--echo # MDEV-13753: embedded CTE in a VIEW created in prepared statement +--echo # + +SET @sql_query = " + CREATE OR REPLACE VIEW cte_test AS + WITH cte1 AS ( SELECT 1 as a from dual ) + , cte2 AS ( SELECT * FROM cte1 ) + SELECT * FROM cte2; +"; +PREPARE stmt FROM @sql_query; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SHOW CREATE VIEW cte_test; +SELECT * FROM cte_test; + +DROP VIEW cte_test; diff --git a/mysql-test/t/cte_recursive.test b/mysql-test/t/cte_recursive.test index 67be840c002..7d7600f0e88 100644 --- a/mysql-test/t/cte_recursive.test +++ b/mysql-test/t/cte_recursive.test @@ -1928,6 +1928,25 @@ set standard_compliant_cte=default; DROP TABLE t; +--echo # +--echo # mdev-14184: recursive CTE embedded into CTE with multiple references +--echo # + +WITH +cte1 AS ( + SELECT n FROM ( + WITH RECURSIVE rec_cte(n) AS ( + SELECT 1 as n1 + UNION ALL + SELECT n+1 as n2 FROM rec_cte WHERE n < 3 + ) SELECT n FROM rec_cte + ) AS X +), +cte2 as ( + SELECT 2 FROM cte1 +) +SELECT * +FROM cte1; --echo # --echo # MDEV-14217 [db crash] Recursive CTE when SELECT includes new field @@ -1956,3 +1975,4 @@ DROP TABLE a_tbl; --error ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT WITH RECURSIVE x AS (SELECT 1,2 UNION ALL SELECT 1 FROM x) SELECT * FROM x; + diff --git a/mysql-test/t/delimiter_case_mdev_10728.sql b/mysql-test/t/delimiter_case_mdev_10728.sql new file mode 100644 index 00000000000..72a1dcd9a9e --- /dev/null +++ b/mysql-test/t/delimiter_case_mdev_10728.sql @@ -0,0 +1,3 @@ +DeLiMiTeR A; +SELECT 1 A; +delimiter ; diff --git a/mysql-test/t/delimiter_command_case_sensitivity.test b/mysql-test/t/delimiter_command_case_sensitivity.test new file mode 100644 index 00000000000..11d1cf75aa0 --- /dev/null +++ b/mysql-test/t/delimiter_command_case_sensitivity.test @@ -0,0 +1,4 @@ +source include/not_embedded.inc; + +# MDEV-10728 +--exec $MYSQL --default-character-set=binary < "t/delimiter_case_mdev_10728.sql" diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test index c4f1ee7d734..a9bb998bc33 100644 --- a/mysql-test/t/derived_cond_pushdown.test +++ b/mysql-test/t/derived_cond_pushdown.test @@ -1550,6 +1550,23 @@ DROP VIEW v2; DROP TABLE t1,t2; --echo # +--echo # MDEV-14237: derived with regexp_substr() in select list +--echo # + +create table t1 (a char(8)); +insert into t1 values ('b'), ('a'), ('xx'); + +let $q= +select * +from ( select distinct regexp_substr(t1.a,'^[A-Za-z]+') as f from t1) as t +where t.f = 'a' or t.f = 'b'; + +eval $q; +eval explain format=json $q; + +drop table t1; + +--echo # --echo # MDEV-10855: Pushdown into derived with window functions --echo # @@ -1834,3 +1851,4 @@ SELECT * FROM v3 JOIN t1 ON (bmax = b); DROP VIEW v1,v2,v3; DROP TABLE t1,t2; + diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index ac983048129..da4a7633166 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -1104,6 +1104,23 @@ SELECT CONCAT(NAME_CONST('name',15),'오'); SET NAMES latin1; --echo # +--echo # MDEV-14116 INET6_NTOA output is set as null to varchar(39) variable +--echo # + +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE ip_full_addr varchar(39) DEFAULT ""; + SELECT INET6_NTOA(UNHEX('20000000000000000000000000000000')) into ip_full_addr; + SELECT ip_full_addr; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + + +--echo # --echo # Start of 10.2 tests --echo # diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index 13ca9a528c6..4024d2e522c 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -423,7 +423,7 @@ create table t1 ( SHOW CREATE TABLE t1; DROP TABLE t1; -# Test for Bug#93 4.1 protocl crash on corupted frm and SHOW TABLE STATUS +# Test for Bug#93 4.1 protocol crash on corrupted frm and SHOW TABLE STATUS flush tables; @@ -437,7 +437,7 @@ show create table t1; --disable_warnings drop table if exists t1; --enable_warnings ---error 1,0 +--error 0,1 --remove_file $MYSQLD_DATADIR/test/t1.frm # diff --git a/mysql-test/t/subselect_exists2in.test b/mysql-test/t/subselect_exists2in.test index a4fdbe5c50b..5a8ddb3612f 100644 --- a/mysql-test/t/subselect_exists2in.test +++ b/mysql-test/t/subselect_exists2in.test @@ -786,6 +786,46 @@ set optimizer_switch= @optimizer_switch_save; DROP TABLE t1; +--echo # +--echo # MDEV-14164: Unknown column error when adding aggregate to function +--echo # in oracle style procedure FOR loop +--echo # + +CREATE TABLE t1(id INT, val INT); +DELIMITER //; +CREATE PROCEDURE p1() +BEGIN + DECLARE cur1 CURSOR FOR SELECT * FROM ( + SELECT DISTINCT id FROM t1) a + WHERE NOT EXISTS (SELECT * FROM ( SELECT id FROM t1) b + WHERE a.id=b.id); + OPEN cur1; + CLOSE cur1; + OPEN cur1; + CLOSE cur1; +END; +// +DELIMITER ;// +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + +CREATE TABLE t1(id INT, val INT); +DELIMITER //; +CREATE PROCEDURE p1() +BEGIN + SELECT * FROM (SELECT DISTINCT id FROM t1) a + WHERE NOT a.id IN (SELECT b.id FROM t1 b); + SELECT * FROM (SELECT DISTINCT id FROM t1) a + WHERE NOT EXISTS (SELECT * FROM t1 b WHERE a.id=b.id); +END; +// +DELIMITER ;// +CALL p1(); +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + --echo # End of 10.0 tests #restore defaults diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index 761f200fe0c..bb282fc15e5 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -439,3 +439,22 @@ SELECT SUM(a) FROM t1 GROUP BY c, b, a; DROP TABLE t1; --echo End of 5.1 tests + +--echo # +--echo # Start of 10.1 tests +--echo # + +--echo # +--echo # MDEV-8867 Wrong field type or metadata for COALESCE(bit_column, 1) +--echo # + +CREATE TABLE t1 (val bit(1)); +INSERT INTO t1 VALUES (0); +CREATE TABLE t2 AS SELECT COALESCE(val, 1) AS c FROM t1; +SELECT * FROM t2; +SHOW CREATE TABLE t2; +DROP TABLE t2; +--enable_metadata +SELECT COALESCE(val, 1) FROM t1; +--disable_metadata +DROP TABLE t1; diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test index 7c4af618c23..8d29a54a26c 100644 --- a/mysql-test/t/type_date.test +++ b/mysql-test/t/type_date.test @@ -582,6 +582,15 @@ SELECT DATE(a), DATE(b), DATE(c) FROM t1; SELECT DATE(COALESCE(a)), DATE(COALESCE(b)), DATE(COALESCE(c)) FROM t1; DROP TABLE t1; +--echo # +--echo # MDEV-14221 Assertion `0' failed in Item::field_type_for_temporal_comparison +--echo # + +CREATE TABLE t1 (d DATE); +INSERT INTO t1 VALUES ('1985-05-13'),('1989-12-24'); +SELECT d, COUNT(*) FROM t1 GROUP BY d WITH ROLLUP HAVING CASE d WHEN '2017-05-25' THEN 0 ELSE 1 END; +DROP TABLE t1; + --echo # --echo # End of 10.1 tests diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test index 6662a3d9bb0..5f3f58df166 100644 --- a/mysql-test/t/type_time.test +++ b/mysql-test/t/type_time.test @@ -747,6 +747,17 @@ DROP TABLE t1,t2; --echo # +--echo # MDEV-10817 CAST(MAX(DATE'2001-01-01') AS TIME) returns a wrong result +--echo # + +SELECT CAST(DATE'2001-01-01' AS TIME); +SELECT CAST(MAX(DATE'2001-01-01') AS TIME); +CREATE FUNCTION f1() RETURNS DATE RETURN DATE'2001-01-01'; +SELECT CAST(f1() AS TIME); +DROP FUNCTION f1; + + +--echo # --echo # End of 10.2 tests --echo # diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 4850b6c06cb..847fb843ec8 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1,3 +1,4 @@ +--source include/have_partition.inc # Save the initial number of concurrent sessions. --source include/count_sessions.inc diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 87a18e47fc5..b75f6b9a863 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -15,7 +15,7 @@ #define PLUGIN_VERSION 0x104 -#define PLUGIN_STR_VERSION "1.4.2" +#define PLUGIN_STR_VERSION "1.4.3" #define _my_thread_var loc_thread_var @@ -1118,6 +1118,21 @@ do { \ } while(0) +#define ESC_MAP_SIZE 0x60 +static const char esc_map[ESC_MAP_SIZE]= +{ + 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '\'', 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0 +}; + +static char escaped_char(char c) +{ + return ((unsigned char ) c) >= ESC_MAP_SIZE ? 0 : esc_map[(unsigned char) c]; +} static void setup_connection_initdb(struct connection_info *cn, @@ -1324,21 +1339,16 @@ static size_t escape_string(const char *str, unsigned int len, const char *res_end= result + result_len - 2; while (len) { + char esc_c; + if (result >= res_end) break; - if (*str == '\'') - { - if (result+1 >= res_end) - break; - *(result++)= '\\'; - *(result++)= '\''; - } - else if (*str == '\\') + if ((esc_c= escaped_char(*str))) { if (result+1 >= res_end) break; *(result++)= '\\'; - *(result++)= '\\'; + *(result++)= esc_c; } else if (is_space(*str)) *(result++)= ' '; @@ -1427,19 +1437,12 @@ static size_t escape_string_hide_passwords(const char *str, unsigned int len, no_password: if (result >= res_end) break; - if (*str == '\'') + if ((b_char= escaped_char(*str))) { if (result+1 >= res_end) break; *(result++)= '\\'; - *(result++)= '\''; - } - else if (*str == '\\') - { - if (result+1 >= res_end) - break; - *(result++)= '\\'; - *(result++)= '\\'; + *(result++)= b_char; } else if (is_space(*str)) *(result++)= ' '; diff --git a/sql/datadict.cc b/sql/datadict.cc index edc9fe5681b..5b70639174c 100644 --- a/sql/datadict.cc +++ b/sql/datadict.cc @@ -46,11 +46,13 @@ static int read_string(File file, uchar**to, size_t length) engine_name is a LEX_CSTRING, where engine_name->str must point to a buffer of at least NAME_CHAR_LEN+1 bytes. + If engine_name is 0, then the function will only test if the file is a + view or not @param[out] is_sequence 1 if table is a SEQUENCE, 0 otherwise @retval TABLE_TYPE_UNKNOWN error - @retval TABLE_TYPE_TABLE table + @retval TABLE_TYPE_NORMAL table @retval TABLE_TYPE_SEQUENCE sequence table @retval TABLE_TYPE_VIEW view */ @@ -80,12 +82,26 @@ Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name, goto err; } + /* + We return TABLE_TYPE_NORMAL if we can read the .frm file. This allows us + to drop a bad .frm file with DROP TABLE + */ type= TABLE_TYPE_NORMAL; - if (!is_binary_frm_header(header) || !engine_name) + /* engine_name is 0 if we only want to know if table is view or not */ + if (!engine_name) goto err; + /* + Initialize engine name in case we are not able to find it out + The cast is safe, as engine_name->str points to a usable buffer. + */ engine_name->length= 0; + ((char*) (engine_name->str))[0]= 0; + + if (!is_binary_frm_header(header)) + goto err; + dbt= header[3]; if (((header[39] >> 4) & 3) == HA_CHOICE_YES) diff --git a/sql/handler.cc b/sql/handler.cc index 589a82200be..81c6b60d256 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5089,8 +5089,13 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name, { char engine_buf[NAME_CHAR_LEN + 1]; LEX_CSTRING engine= { engine_buf, 0 }; + Table_type type; - if (dd_frm_type(thd, path, &engine, is_sequence) != TABLE_TYPE_VIEW) + if ((type= dd_frm_type(thd, path, &engine, is_sequence)) == + TABLE_TYPE_UNKNOWN) + DBUG_RETURN(0); + + if (type != TABLE_TYPE_VIEW) { plugin_ref p= plugin_lock_by_name(thd, &engine, MYSQL_STORAGE_ENGINE_PLUGIN); diff --git a/sql/item.cc b/sql/item.cc index e5e1d83f228..3daf1e8393e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3238,7 +3238,8 @@ table_map Item_field::all_used_tables() const return (get_depended_from() ? OUTER_REF_TABLE_BIT : field->table->map); } -void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { if (new_parent == get_depended_from()) depended_from= NULL; @@ -3282,6 +3283,19 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref) if (!need_change) return; + if (!merge) + { + /* + It is transformation without merge. + This field was "outer" for the inner SELECT where it was taken and + moved up. + "Outer" fields uses normal SELECT_LEX context of upper SELECTs for + name resolution, so we can switch everything to it safely. + */ + this->context= &new_parent->context; + return; + } + Name_resolution_context *ctx= new Name_resolution_context(); if (context->select_lex == new_parent) { @@ -8698,18 +8712,19 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference) void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, - Item **ref_arg) + Item **ref_arg, bool merge) { if (get_depended_from() == new_parent) { *ref_arg= outer_ref; - (*ref_arg)->fix_after_pullout(new_parent, ref_arg); + (*ref_arg)->fix_after_pullout(new_parent, ref_arg, merge); } } -void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr) +void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr, + bool merge) { - (*ref)->fix_after_pullout(new_parent, ref); + (*ref)->fix_after_pullout(new_parent, ref, merge); if (get_depended_from() == new_parent) depended_from= NULL; } diff --git a/sql/item.h b/sql/item.h index c128251dae9..b7ba236e4b1 100644 --- a/sql/item.h +++ b/sql/item.h @@ -733,7 +733,9 @@ public: Fix after some tables has been pulled out. Basically re-calculate all attributes that are dependent on the tables. */ - virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref) {}; + virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) + {}; /* This method should be used in case where we are sure that we do not need @@ -2760,7 +2762,7 @@ public: bool send(Protocol *protocol, st_value *buffer); void reset_field(Field *f); bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void make_field(THD *thd, Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field, fast_field_copier optimizer_data); @@ -3026,6 +3028,17 @@ public: Field *result_field; Item_null_result(THD *thd): Item_null(thd), result_field(0) {} bool is_result_field() { return result_field != 0; } +#if MARIADB_VERSION_ID < 100300 + enum_field_types field_type() const + { + return result_field->type(); + } +#else + const Type_handler *type_handler() const + { + return result_field->type_handler(); + } +#endif void save_in_result_field(bool no_conversions) { save_in_field(result_field, no_conversions); @@ -4390,7 +4403,7 @@ public: bool send(Protocol *prot, st_value *buffer); void make_field(THD *thd, Send_field *field); bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); int save_in_field(Field *field, bool no_conversions); void save_org_in_field(Field *field, fast_field_copier optimizer_data); fast_field_copier setup_fast_field_copier(Field *field) @@ -4698,9 +4711,9 @@ public: Item *it= ((Item *) item)->real_item(); return orig_item->eq(it, binary_cmp); } - void fix_after_pullout(st_select_lex *new_parent, Item **refptr) + void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge) { - orig_item->fix_after_pullout(new_parent, &orig_item); + orig_item->fix_after_pullout(new_parent, &orig_item, merge); } int save_in_field(Field *to, bool no_conversions); const Type_handler *type_handler() const { return orig_item->type_handler(); } @@ -4969,7 +4982,7 @@ public: outer_ref->save_org_in_field(result_field, NULL); } bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); table_map used_tables() const { return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 90b150a8b4a..f72426bd18c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1220,10 +1220,11 @@ bool Item_in_optimizer::is_top_level_item() } -void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { /* This will re-calculate attributes of our Item_in_subselect: */ - Item_bool_func::fix_after_pullout(new_parent, ref); + Item_bool_func::fix_after_pullout(new_parent, ref, merge); /* Then, re-calculate not_null_tables_cache: */ eval_not_null_tables(NULL); @@ -2050,10 +2051,11 @@ bool Item_func_between::count_sargable_conds(void *arg) } -void Item_func_between::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_func_between::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { /* This will re-calculate attributes of the arguments */ - Item_func_opt_neg::fix_after_pullout(new_parent, ref); + Item_func_opt_neg::fix_after_pullout(new_parent, ref, merge); /* Then, re-calculate not_null_tables_cache according to our special rules */ eval_not_null_tables(NULL); } @@ -2378,10 +2380,11 @@ Item_func_if::eval_not_null_tables(void *opt_arg) } -void Item_func_if::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_func_if::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { /* This will re-calculate attributes of the arguments */ - Item_func::fix_after_pullout(new_parent, ref); + Item_func::fix_after_pullout(new_parent, ref, merge); /* Then, re-calculate not_null_tables_cache according to our special rules */ eval_not_null_tables(NULL); } @@ -4144,10 +4147,11 @@ Item_func_in::eval_not_null_tables(void *opt_arg) } -void Item_func_in::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_func_in::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { /* This will re-calculate attributes of the arguments */ - Item_func_opt_neg::fix_after_pullout(new_parent, ref); + Item_func_opt_neg::fix_after_pullout(new_parent, ref, merge); /* Then, re-calculate not_null_tables_cache according to our special rules */ eval_not_null_tables(NULL); } @@ -4651,7 +4655,8 @@ Item_cond::eval_not_null_tables(void *opt_arg) } -void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { List_iterator<Item> li(list); Item *item; @@ -4664,7 +4669,7 @@ void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref) while ((item=li++)) { table_map tmp_table_map; - item->fix_after_pullout(new_parent, li.ref()); + item->fix_after_pullout(new_parent, li.ref(), merge); item= *li.ref(); used_tables_and_const_cache_join(item); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 62066ef61e5..49716fb3c8f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -375,7 +375,7 @@ public: virtual void get_cache_parameters(List<Item> ¶meters); bool is_top_level_item(); bool eval_not_null_tables(void *opt_arg); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); bool invisible_mode(); void reset_cache() { cache= NULL; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -908,7 +908,7 @@ public: bool fix_length_and_dec_numeric(THD *); virtual void print(String *str, enum_query_type query_type); bool eval_not_null_tables(void *opt_arg); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); bool count_sargable_conds(void *arg); void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, @@ -1144,7 +1144,7 @@ public: } const char *func_name() const { return "if"; } bool eval_not_null_tables(void *opt_arg); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_if>(thd, mem_root, this); } private: @@ -2378,7 +2378,7 @@ public: const char *func_name() const { return "in"; } enum precedence precedence() const { return CMP_PRECEDENCE; } bool eval_not_null_tables(void *opt_arg); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); bool count_sargable_conds(void *arg); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_func_in>(thd, mem_root, this); } @@ -2902,7 +2902,7 @@ public: list.append(nlist); } bool fix_fields(THD *, Item **ref); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); enum Type type() const { return COND_ITEM; } List<Item>* argument_list() { return &list; } diff --git a/sql/item_func.cc b/sql/item_func.cc index fc7417411e8..e9cf5a695d0 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -406,7 +406,8 @@ Item_func::eval_not_null_tables(void *opt_arg) } -void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { Item **arg,**arg_end; @@ -417,7 +418,7 @@ void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref) { for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { - (*arg)->fix_after_pullout(new_parent, arg); + (*arg)->fix_after_pullout(new_parent, arg, merge); Item *item= *arg; used_tables_and_const_cache_join(item); diff --git a/sql/item_func.h b/sql/item_func.h index 409a712a5c5..58df7b8b3c6 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -129,7 +129,7 @@ public: Item_func_or_sum::cleanup(); used_tables_and_const_cache_init(); } - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void quick_fix_field(); table_map not_null_tables() const; void update_used_tables() @@ -2809,6 +2809,13 @@ public: return sp_result_field->val_decimal(dec_buf); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + if (execute()) + return true; + return sp_result_field->get_date(ltime, fuzzydate); + } + String *val_str(String *str) { String buf; diff --git a/sql/item_inetfunc.cc b/sql/item_inetfunc.cc index 9aaa64823f7..ff671536002 100644 --- a/sql/item_inetfunc.cc +++ b/sql/item_inetfunc.cc @@ -181,7 +181,8 @@ String *Item_func_inet_str_base::val_str_ascii(String *buffer) return NULL; } - String *arg_str= args[0]->val_str(buffer); + StringBuffer<STRING_BUFFER_USUAL_SIZE> tmp; + String *arg_str= args[0]->val_str(&tmp); if (!arg_str) // Out-of memory happened. The error has been reported. { // Or: the underlying field is NULL null_value= true; @@ -679,7 +680,7 @@ static void ipv6_to_str(const in6_addr *ipv6, char *str) @retval true The string has been converted sucessfully. */ -bool Item_func_inet6_aton::calc_value(String *arg, String *buffer) +bool Item_func_inet6_aton::calc_value(const String *arg, String *buffer) { // ipv4-string -> varbinary(4) // ipv6-string -> varbinary(16) @@ -719,7 +720,7 @@ bool Item_func_inet6_aton::calc_value(String *arg, String *buffer) @retval true The string has been converted sucessfully. */ -bool Item_func_inet6_ntoa::calc_value(String *arg, String *buffer) +bool Item_func_inet6_ntoa::calc_value(const String *arg, String *buffer) { if (arg->charset() != &my_charset_bin) return false; diff --git a/sql/item_inetfunc.h b/sql/item_inetfunc.h index 13ce003a374..bd0a95b5270 100644 --- a/sql/item_inetfunc.h +++ b/sql/item_inetfunc.h @@ -105,7 +105,7 @@ public: virtual String *val_str_ascii(String *buffer); protected: - virtual bool calc_value(String *arg, String *buffer) = 0; + virtual bool calc_value(const String *arg, String *buffer) = 0; }; @@ -134,7 +134,7 @@ public: { return get_item_copy<Item_func_inet6_aton>(thd, mem_root, this); } protected: - virtual bool calc_value(String *arg, String *buffer); + virtual bool calc_value(const String *arg, String *buffer); }; @@ -168,7 +168,7 @@ public: { return get_item_copy<Item_func_inet6_ntoa>(thd, mem_root, this); } protected: - virtual bool calc_value(String *arg, String *buffer); + virtual bool calc_value(const String *arg, String *buffer); }; diff --git a/sql/item_row.cc b/sql/item_row.cc index 6486bb66615..3660c983f87 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -110,13 +110,14 @@ void Item_row::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, } -void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { used_tables_and_const_cache_init(); not_null_tables_cache= 0; for (uint i= 0; i < arg_count; i++) { - args[i]->fix_after_pullout(new_parent, &args[i]); + args[i]->fix_after_pullout(new_parent, &args[i], merge); used_tables_and_const_cache_join(args[i]); not_null_tables_cache|= args[i]->not_null_tables(); } diff --git a/sql/item_row.h b/sql/item_row.h index 83e9743fede..a6fdd2b212c 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -81,7 +81,7 @@ public: return 0; }; bool fix_fields(THD *thd, Item **ref); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void cleanup(); void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, uint flags); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index c322136bef2..fbcf69d00ce 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -400,8 +400,7 @@ public: bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); const char *func_name() const { return "regexp_replace"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_regexp_replace>(thd, mem_root, this); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0;} }; @@ -423,8 +422,7 @@ public: bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); const char *func_name() const { return "regexp_substr"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_regexp_substr>(thd, mem_root, this); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 63d1fd99f62..678b4192f45 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -452,7 +452,8 @@ bool Item_subselect::mark_as_dependent(THD *thd, st_select_lex *select, OUTER_REF_TABLE_BIT. */ -void Item_subselect::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_subselect::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { recalc_used_tables(new_parent, TRUE); parent_select= new_parent; @@ -1160,7 +1161,8 @@ Item_singlerow_subselect::select_transformer(JOIN *join) /* as far as we moved content to upper level we have to fix dependences & Co */ - substitution->fix_after_pullout(select_lex->outer_select(), &substitution); + substitution->fix_after_pullout(select_lex->outer_select(), + &substitution, TRUE); } DBUG_RETURN(false); } @@ -2937,7 +2939,7 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg) goto out; } } - outer_exp->fix_after_pullout(unit->outer_select(), &outer_exp); + outer_exp->fix_after_pullout(unit->outer_select(), &outer_exp, FALSE); outer_exp->update_used_tables(); outer.push_back(outer_exp, thd->mem_root); } @@ -3318,10 +3320,11 @@ err: } -void Item_in_subselect::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_in_subselect::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { - left_expr->fix_after_pullout(new_parent, &left_expr); - Item_subselect::fix_after_pullout(new_parent, ref); + left_expr->fix_after_pullout(new_parent, &left_expr, merge); + Item_subselect::fix_after_pullout(new_parent, ref, merge); used_tables_cache |= left_expr->used_tables(); } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 6112c1c22f4..df94ceb2493 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -183,7 +183,7 @@ public: } bool fix_fields(THD *thd, Item **ref); bool mark_as_dependent(THD *thd, st_select_lex *select, Item *item); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void recalc_used_tables(st_select_lex *new_parent, bool after_pullout); virtual bool exec(); /* @@ -624,7 +624,7 @@ public: enum precedence precedence() const { return CMP_PRECEDENCE; } bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); bool const_item() const { return Item_subselect::const_item() && left_expr->const_item(); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 4a3f107796d..c0c5e1a43b4 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2019,6 +2019,18 @@ void Item_sum_hybrid::clear() null_value= 1; } +bool +Item_sum_hybrid::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return true; + bool retval= value->get_date(ltime, fuzzydate); + if ((null_value= value->null_value)) + DBUG_ASSERT(retval == true); + return retval; +} + double Item_sum_hybrid::val_real() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_sum.h b/sql/item_sum.h index 7845ed3318f..0cb5be391a2 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1034,6 +1034,7 @@ protected: double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); void reset_field(); String *val_str(String *); const Type_handler *real_type_handler() const diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index cc9cfbd127f..04d0a9b4a3f 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1642,7 +1642,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) { tl->jtbm_table_no= table_no; Item *dummy= tl->jtbm_subselect; - tl->jtbm_subselect->fix_after_pullout(parent_lex, &dummy); + tl->jtbm_subselect->fix_after_pullout(parent_lex, &dummy, true); DBUG_ASSERT(dummy == tl->jtbm_subselect); } SELECT_LEX *old_sl= tl->select_lex; @@ -1783,7 +1783,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) Walk through sj nest's WHERE and ON expressions and call item->fix_table_changes() for all items. */ - sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr); + sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr, + TRUE); fix_list_after_tbl_changes(parent_lex, &sj_nest->nested_join->join_list); @@ -1942,7 +1943,7 @@ static bool convert_subq_to_jtbm(JOIN *parent_join, DBUG_ASSERT(parent_join->table_count < MAX_TABLES); Item *conds= hash_sj_engine->semi_join_conds; - conds->fix_after_pullout(parent_lex, &conds); + conds->fix_after_pullout(parent_lex, &conds, TRUE); DBUG_EXECUTE("where", print_where(conds,"SJ-EXPR", QT_ORDINARY);); @@ -1994,7 +1995,7 @@ void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist) while ((table= it++)) { if (table->on_expr) - table->on_expr->fix_after_pullout(new_parent, &table->on_expr); + table->on_expr->fix_after_pullout(new_parent, &table->on_expr, TRUE); if (table->nested_join) fix_list_after_tbl_changes(new_parent, &table->nested_join->join_list); } diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 54a56103d21..0d91d813dfc 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -349,7 +349,10 @@ void With_element::check_dependencies_in_select(st_select_lex *sl, /* Now look for the dependencies in the subqueries of sl */ st_select_lex_unit *inner_unit= sl->first_inner_unit(); for (; inner_unit; inner_unit= inner_unit->next_unit()) - check_dependencies_in_unit(inner_unit, ctxt, in_subq, dep_map); + { + if (!inner_unit->with_element) + check_dependencies_in_unit(inner_unit, ctxt, in_subq, dep_map); + } } @@ -837,7 +840,6 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd, with_table->next_global= spec_tables; } res= &lex->unit; - res->set_with_clause(owner); lex->unit.include_down(with_table->select_lex); lex->unit.set_slave(with_select); @@ -846,6 +848,8 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd, insert_chain_before( (st_select_lex_node **) &(old_lex->all_selects_list), with_select)); + if (check_dependencies_in_with_clauses(lex->with_clauses_list)) + res= NULL; lex_end(lex); err: if (arena) @@ -989,14 +993,18 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) and it was unsuccesful. Yet for units cloned from the spec it has not been done yet. */ - if (with_elem && sl->master_unit() == with_elem->spec) + With_clause *attached_with_clause=sl->get_with_clause(); + if (attached_with_clause && + (found= attached_with_clause->find_table_def(table, NULL))) break; - With_clause *with_clause=sl->get_with_clause(); - if (with_clause) + if (with_elem) { - With_element *barrier= with_clause->with_recursive ? NULL : with_elem; - if ((found= with_clause->find_table_def(table, barrier))) + With_clause *containing_with_clause= with_elem->get_owner(); + With_element *barrier= containing_with_clause->with_recursive ? + NULL : with_elem; + if ((found= containing_with_clause->find_table_def(table, barrier))) break; + sl= sl->master_unit()->outer_select(); } master_unit= sl->master_unit(); /* Do not look for the table's definition beyond the scope of the view */ diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 8dff001d4d0..5554faf7baf 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -468,7 +468,8 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) // Update used tables cache according to new table map if (derived->on_expr) { - derived->on_expr->fix_after_pullout(parent_lex, &derived->on_expr); + derived->on_expr->fix_after_pullout(parent_lex, &derived->on_expr, + TRUE); fix_list_after_tbl_changes(parent_lex, &derived->nested_join->join_list); } } @@ -641,7 +642,8 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) SELECT_LEX_UNIT *unit= derived->get_unit(); DBUG_ENTER("mysql_derived_prepare"); bool res= FALSE; - DBUG_PRINT("enter", ("unit %p", unit)); + DBUG_PRINT("enter", ("unit: %p table_list: %p Alias '%s'", + unit, derived, derived->alias)); if (!unit) DBUG_RETURN(FALSE); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 5ce8b1d584d..3a201f5cef4 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -4168,7 +4168,8 @@ buf_page_get_gen( ulint retries = 0; buf_pool_t* buf_pool = buf_pool_get(page_id); - ut_ad(mtr->is_active()); + ut_ad((mtr == NULL) == (mode == BUF_EVICT_IF_IN_POOL)); + ut_ad(!mtr || mtr->is_active()); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH) || (rw_latch == RW_SX_LATCH) @@ -4180,29 +4181,31 @@ buf_page_get_gen( #ifdef UNIV_DEBUG switch (mode) { + case BUF_EVICT_IF_IN_POOL: + /* After DISCARD TABLESPACE, the tablespace would not exist, + but in IMPORT TABLESPACE, PageConverter::operator() must + replace any old pages, which were not evicted during DISCARD. + Skip the assertion on space_page_size. */ + break; + default: + ut_error; case BUF_GET_NO_LATCH: ut_ad(rw_latch == RW_NO_LATCH); - break; + /* fall through */ case BUF_GET: case BUF_GET_IF_IN_POOL: case BUF_PEEK_IF_IN_POOL: case BUF_GET_IF_IN_POOL_OR_WATCH: case BUF_GET_POSSIBLY_FREED: - break; - default: - ut_error; + bool found; + const page_size_t& space_page_size + = fil_space_get_page_size(page_id.space(), &found); + ut_ad(found); + ut_ad(page_size.equals_to(space_page_size)); } - - bool found; - const page_size_t& space_page_size - = fil_space_get_page_size(page_id.space(), &found); - - ut_ad(found); - - ut_ad(page_size.equals_to(space_page_size)); #endif /* UNIV_DEBUG */ - ut_ad(!ibuf_inside(mtr) + ut_ad(!mtr || !ibuf_inside(mtr) || ibuf_page_low(page_id, page_size, FALSE, file, line, NULL)); buf_pool->stat.n_page_gets++; @@ -4290,13 +4293,15 @@ loop: rw_lock_x_unlock(hash_lock); } - if (mode == BUF_GET_IF_IN_POOL - || mode == BUF_PEEK_IF_IN_POOL - || mode == BUF_GET_IF_IN_POOL_OR_WATCH) { - + switch (mode) { + case BUF_GET_IF_IN_POOL: + case BUF_GET_IF_IN_POOL_OR_WATCH: + case BUF_PEEK_IF_IN_POOL: + case BUF_EVICT_IF_IN_POOL: +#ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X)); ut_ad(!rw_lock_own(hash_lock, RW_LOCK_S)); - +#endif /* UNIV_SYNC_DEBUG */ return(NULL); } @@ -4390,8 +4395,10 @@ loop: got_block: - if (mode == BUF_GET_IF_IN_POOL || mode == BUF_PEEK_IF_IN_POOL) { - + switch (mode) { + case BUF_GET_IF_IN_POOL: + case BUF_PEEK_IF_IN_POOL: + case BUF_EVICT_IF_IN_POOL: buf_page_t* fix_page = &fix_block->page; BPageMutex* fix_mutex = buf_page_get_mutex(fix_page); mutex_enter(fix_mutex); @@ -4423,6 +4430,20 @@ got_block: os_thread_sleep(WAIT_FOR_WRITE); goto loop; } + + if (UNIV_UNLIKELY(mode == BUF_EVICT_IF_IN_POOL)) { +evict_from_pool: + ut_ad(!fix_block->page.oldest_modification); + buf_pool_mutex_enter(buf_pool); + buf_block_unfix(fix_block); + + if (!buf_LRU_free_page(&fix_block->page, true)) { + ut_ad(0); + } + + buf_pool_mutex_exit(buf_pool); + return(NULL); + } break; case BUF_BLOCK_ZIP_PAGE: @@ -4455,6 +4476,10 @@ got_block: goto loop; } + if (UNIV_UNLIKELY(mode == BUF_EVICT_IF_IN_POOL)) { + goto evict_from_pool; + } + /* Buffer-fix the block so that it cannot be evicted or relocated while we are attempting to allocate an uncompressed page. */ diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index e7a2a844330..4661a4e0d14 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -3821,24 +3821,16 @@ FlushObserver::notify_remove( void FlushObserver::flush() { - buf_remove_t buf_remove; - - if (m_interrupted) { - buf_remove = BUF_REMOVE_FLUSH_NO_WRITE; - } else { - buf_remove = BUF_REMOVE_FLUSH_WRITE; - - if (m_stage != NULL) { - ulint pages_to_flush = - buf_flush_get_dirty_pages_count( - m_space_id, this); - - m_stage->begin_phase_flush(pages_to_flush); - } + if (!m_interrupted && m_stage) { + m_stage->begin_phase_flush(buf_flush_get_dirty_pages_count( + m_space_id, this)); } - /* Flush or remove dirty pages. */ - buf_LRU_flush_or_remove_pages(m_space_id, buf_remove, m_trx); + /* MDEV-14317 FIXME: Discard all changes to only those pages + that will be freed by the clean-up of the ALTER operation. + (Maybe, instead of buf_pool->flush_list, use a dedicated list + for pages on which redo logging has been disabled.) */ + buf_LRU_flush_or_remove_pages(m_space_id, m_trx); /* Wait for all dirty pages were flushed. */ for (ulint i = 0; i < srv_buf_pool_instances; i++) { diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 2137760e815..9d0d9627d26 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -586,8 +586,8 @@ rescan: /* If flush observer is NULL, flush page for space id, or flush page for flush observer. */ - if ((observer != NULL && observer != bpage->flush_observer) - || (observer == NULL && id != bpage->id.space())) { + if (observer ? (observer != bpage->flush_observer) + : (id != bpage->id.space())) { /* Skip this block, as it does not belong to the target space. */ @@ -657,24 +657,27 @@ rescan: return(all_freed ? DB_SUCCESS : DB_FAIL); } -/******************************************************************//** -Remove or flush all the dirty pages that belong to a given tablespace +/** Remove or flush all the dirty pages that belong to a given tablespace inside a specific buffer pool instance. The pages will remain in the LRU list and will be evicted from the LRU list as they age and move towards -the tail of the LRU list. */ +the tail of the LRU list. +@param[in,out] buf_pool buffer pool +@param[in] id tablespace identifier +@param[in] observer flush observer, + or NULL if the files should not be written to +@param[in] trx transaction (to check for interrupt), + or NULL if the files should not be written to +*/ static void buf_flush_dirty_pages( -/*==================*/ - buf_pool_t* buf_pool, /*!< buffer pool instance */ - ulint id, /*!< in: space id */ - FlushObserver* observer, /*!< in: flush observer */ - bool flush, /*!< in: flush to disk if true otherwise - remove the pages without flushing */ - const trx_t* trx) /*!< to check if the operation must - be interrupted */ + buf_pool_t* buf_pool, + ulint id, + FlushObserver* observer, + const trx_t* trx) { dberr_t err; + bool flush = trx != NULL; do { buf_pool_mutex_enter(buf_pool); @@ -708,238 +711,30 @@ buf_flush_dirty_pages( || buf_pool_get_dirty_pages_count(buf_pool, id, observer) == 0); } -/******************************************************************//** -Remove all pages that belong to a given tablespace inside a specific -buffer pool instance when we are DISCARDing the tablespace. */ -static -void -buf_LRU_remove_all_pages( -/*=====================*/ - buf_pool_t* buf_pool, /*!< buffer pool instance */ - ulint id) /*!< in: space id */ -{ - buf_page_t* bpage; - ibool all_freed; - -scan_again: - buf_pool_mutex_enter(buf_pool); - - all_freed = TRUE; - - for (bpage = UT_LIST_GET_LAST(buf_pool->LRU); - bpage != NULL; - /* No op */) { - - rw_lock_t* hash_lock; - buf_page_t* prev_bpage; - BPageMutex* block_mutex; - - ut_a(buf_page_in_file(bpage)); - ut_ad(bpage->in_LRU_list); - - prev_bpage = UT_LIST_GET_PREV(LRU, bpage); - - /* bpage->id.space() and bpage->io_fix are protected by - buf_pool->mutex and the block_mutex. It is safe to check - them while holding buf_pool->mutex only. */ - - if (bpage->id.space() != id) { - /* Skip this block, as it does not belong to - the space that is being invalidated. */ - goto next_page; - } else if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) { - /* We cannot remove this page during this scan - yet; maybe the system is currently reading it - in, or flushing the modifications to the file */ - - all_freed = FALSE; - goto next_page; - } else { - hash_lock = buf_page_hash_lock_get(buf_pool, bpage->id); - - rw_lock_x_lock(hash_lock); - - block_mutex = buf_page_get_mutex(bpage); - - mutex_enter(block_mutex); - - if (bpage->buf_fix_count > 0) { - - mutex_exit(block_mutex); - - rw_lock_x_unlock(hash_lock); - - /* We cannot remove this page during - this scan yet; maybe the system is - currently reading it in, or flushing - the modifications to the file */ - - all_freed = FALSE; - - goto next_page; - } - } - - ut_ad(mutex_own(block_mutex)); - - DBUG_PRINT("ib_buf", ("evict page %u:%u" - " state %u", - bpage->id.space(), - bpage->id.page_no(), - bpage->state)); -#ifdef BTR_CUR_HASH_ADAPT - if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { - /* Do nothing, because the adaptive hash index - covers uncompressed pages only. */ - } else if (((buf_block_t*) bpage)->index) { - buf_pool_mutex_exit(buf_pool); - - rw_lock_x_unlock(hash_lock); - - mutex_exit(block_mutex); - - /* Note that the following call will acquire - and release block->lock X-latch. - Note that the table cannot be evicted during - the execution of ALTER TABLE...DISCARD TABLESPACE - because MySQL is keeping the table handle open. */ - - btr_search_drop_page_hash_when_freed( - bpage->id, bpage->size); - - goto scan_again; - } else { - /* This debug check uses a dirty read that could - theoretically cause false positives while - buf_pool_clear_hash_index() is executing, - if the writes to block->index=NULL and - block->n_pointers=0 are reordered. - (Other conflicting access paths to the adaptive hash - index should not be possible, because when a - tablespace is being discarded or dropped, there must - be no concurrect access to the contained tables.) */ - assert_block_ahi_empty((buf_block_t*) bpage); - } -#endif /* BTR_CUR_HASH_ADAPT */ - - if (bpage->oldest_modification != 0) { - - buf_flush_remove(bpage); - } - - ut_ad(!bpage->in_flush_list); - - /* Remove from the LRU list. */ - - if (buf_LRU_block_remove_hashed(bpage, true)) { - buf_LRU_block_free_hashed_page((buf_block_t*) bpage); - } else { - ut_ad(block_mutex == &buf_pool->zip_mutex); - } - - ut_ad(!mutex_own(block_mutex)); - - /* buf_LRU_block_remove_hashed() releases the hash_lock */ - ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X)); - ut_ad(!rw_lock_own(hash_lock, RW_LOCK_S)); - -next_page: - bpage = prev_bpage; - } - - buf_pool_mutex_exit(buf_pool); - - if (!all_freed) { - os_thread_sleep(20000); - - goto scan_again; - } -} - -/******************************************************************//** -Remove pages belonging to a given tablespace inside a specific -buffer pool instance when we are deleting the data file(s) of that -tablespace. The pages still remain a part of LRU and are evicted from -the list as they age towards the tail of the LRU only if buf_remove -is BUF_REMOVE_FLUSH_NO_WRITE. */ -static +/** Empty the flush list for all pages belonging to a tablespace. +@param[in] id tablespace identifier +@param[in] trx transaction, for checking for user interrupt; + or NULL if nothing is to be written +@param[in] drop_ahi whether to drop the adaptive hash index */ void -buf_LRU_remove_pages( -/*=================*/ - buf_pool_t* buf_pool, /*!< buffer pool instance */ - ulint id, /*!< in: space id */ - buf_remove_t buf_remove, /*!< in: remove or flush strategy */ - const trx_t* trx) /*!< to check if the operation must - be interrupted */ +buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx, bool drop_ahi) { FlushObserver* observer = (trx == NULL) ? NULL : trx->flush_observer; + /* Pages in the system tablespace must never be discarded. */ + ut_ad(id || trx); - switch (buf_remove) { - case BUF_REMOVE_ALL_NO_WRITE: - buf_LRU_remove_all_pages(buf_pool, id); - break; - - case BUF_REMOVE_FLUSH_NO_WRITE: - /* Pass trx as NULL to avoid interruption check. */ - buf_flush_dirty_pages(buf_pool, id, observer, false, NULL); - break; - - case BUF_REMOVE_FLUSH_WRITE: - buf_flush_dirty_pages(buf_pool, id, observer, true, trx); - - if (observer == NULL) { - /* Ensure that all asynchronous IO is completed. */ - os_aio_wait_until_no_pending_writes(); - fil_flush(id); + for (ulint i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool = buf_pool_from_array(i); + if (drop_ahi) { + buf_LRU_drop_page_hash_for_tablespace(buf_pool, id); } - - break; + buf_flush_dirty_pages(buf_pool, id, observer, trx); } -} -/******************************************************************//** -Flushes all dirty pages or removes all pages belonging -to a given tablespace. A PROBLEM: if readahead is being started, what -guarantees that it will not try to read in pages after this operation -has completed? */ -void -buf_LRU_flush_or_remove_pages( -/*==========================*/ - ulint id, /*!< in: space id */ - buf_remove_t buf_remove, /*!< in: remove or flush strategy */ - const trx_t* trx) /*!< to check if the operation must - be interrupted */ -{ - ulint i; - - /* Before we attempt to drop pages one by one we first - attempt to drop page hash index entries in batches to make - it more efficient. The batching attempt is a best effort - attempt and does not guarantee that all pages hash entries - will be dropped. We get rid of remaining page hash entries - one by one below. */ - for (i = 0; i < srv_buf_pool_instances; i++) { - buf_pool_t* buf_pool; - - buf_pool = buf_pool_from_array(i); -#ifdef BTR_CUR_HASH_ADAPT - switch (buf_remove) { - case BUF_REMOVE_ALL_NO_WRITE: - buf_LRU_drop_page_hash_for_tablespace(buf_pool, id); - break; - - case BUF_REMOVE_FLUSH_NO_WRITE: - /* It is a DROP TABLE for a single table - tablespace. No AHI entries exist because - we already dealt with them when freeing up - extents. */ - case BUF_REMOVE_FLUSH_WRITE: - /* We allow read-only queries against the - table, there is no need to drop the AHI entries. */ - break; - } -#endif /* BTR_CUR_HASH_ADAPT */ - buf_LRU_remove_pages(buf_pool, id, buf_remove, trx); + if (trx && !observer && !trx_is_interrupted(trx)) { + /* Ensure that all asynchronous IO is completed. */ + os_aio_wait_until_no_pending_writes(); + fil_flush(id); } } diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index c2b08f03848..3879df433e9 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1641,7 +1641,7 @@ dict_table_rename_in_cache( return(DB_OUT_OF_MEMORY); } - fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE); + fil_delete_tablespace(table->space, true); /* Delete any temp file hanging around. */ if (os_file_status(filepath, &exists, &ftype) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 73132754fdf..90a3baa6f83 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2449,7 +2449,7 @@ fil_recreate_tablespace( /* Step-1: Invalidate buffer pool pages belonging to the tablespace to re-create. */ - buf_LRU_flush_or_remove_pages(space_id, BUF_REMOVE_ALL_NO_WRITE, 0); + buf_LRU_flush_or_remove_pages(space_id, NULL); /* Remove all insert buffer entries for the tablespace */ ibuf_delete_for_discarded_space(space_id); @@ -2907,7 +2907,7 @@ fil_close_tablespace( completely and permanently. The flag stop_new_ops also prevents fil_flush() from being applied to this tablespace. */ - buf_LRU_flush_or_remove_pages(id, BUF_REMOVE_FLUSH_WRITE, trx); + buf_LRU_flush_or_remove_pages(id, trx); /* If the free is successful, the X lock will be released before the space memory data structure is freed. */ @@ -2959,17 +2959,12 @@ fil_table_accessible(const dict_table_t* table) } } -/** Deletes an IBD tablespace, either general or single-table. -The tablespace must be cached in the memory cache. This will delete the -datafile, fil_space_t & fil_node_t entries from the file_system_t cache. -@param[in] space_id Tablespace id -@param[in] buf_remove Specify the action to take on the pages -for this table in the buffer pool. -@return DB_SUCCESS or error */ +/** Delete a tablespace and associated .ibd file. +@param[in] id tablespace identifier +@param[in] drop_ahi whether to drop the adaptive hash index +@return DB_SUCCESS or error */ dberr_t -fil_delete_tablespace( - ulint id, - buf_remove_t buf_remove) +fil_delete_tablespace(ulint id, bool drop_ahi) { char* path = 0; fil_space_t* space = 0; @@ -3012,7 +3007,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, buf_remove, 0); + buf_LRU_flush_or_remove_pages(id, NULL, drop_ahi); /* If it is a delete then also delete any generated files, otherwise when we drop the database the remove directory will fail. */ @@ -3103,7 +3098,7 @@ fil_truncate_tablespace( /* Step-2: Invalidate buffer pool pages belonging to the tablespace to re-create. Remove all insert buffer entries for the tablespace */ - buf_LRU_flush_or_remove_pages(space_id, BUF_REMOVE_ALL_NO_WRITE, 0); + buf_LRU_flush_or_remove_pages(space_id, NULL); /* Step-3: Truncate the tablespace and accordingly update the fil_space_t handler that is used to access this tablespace. */ @@ -3199,7 +3194,7 @@ fil_reinit_space_header_for_table( from disabling AHI during the scan */ btr_search_s_lock_all(); DEBUG_SYNC_C("buffer_pool_scan"); - buf_LRU_flush_or_remove_pages(id, BUF_REMOVE_ALL_NO_WRITE, 0); + buf_LRU_flush_or_remove_pages(id, NULL); btr_search_s_unlock_all(); row_mysql_lock_data_dictionary(trx); @@ -3292,7 +3287,7 @@ fil_discard_tablespace( { dberr_t err; - switch (err = fil_delete_tablespace(id, BUF_REMOVE_ALL_NO_WRITE)) { + switch (err = fil_delete_tablespace(id, true)) { case DB_SUCCESS: break; @@ -4348,8 +4343,19 @@ fil_ibd_discover( /* Look for a remote file-per-table tablespace. */ - df_rem_per.set_name(db); - if (df_rem_per.open_link_file() == DB_SUCCESS) { + switch (srv_operation) { + case SRV_OPERATION_BACKUP: + case SRV_OPERATION_RESTORE_DELTA: + ut_ad(0); + break; + case SRV_OPERATION_RESTORE_EXPORT: + case SRV_OPERATION_RESTORE: + break; + case SRV_OPERATION_NORMAL: + df_rem_per.set_name(db); + if (df_rem_per.open_link_file() != DB_SUCCESS) { + break; + } /* An ISL file was found with contents. */ if (df_rem_per.open_read_only(false) != DB_SUCCESS @@ -4439,6 +4445,18 @@ fil_ibd_load( return(FIL_LOAD_OK); } + if (srv_operation == SRV_OPERATION_RESTORE) { + /* Replace absolute DATA DIRECTORY file paths with + short names relative to the backup directory. */ + if (const char* name = strrchr(filename, OS_PATH_SEPARATOR)) { + while (--name > filename + && *name != OS_PATH_SEPARATOR); + if (name > filename) { + filename = name + 1; + } + } + } + Datafile file; file.set_filepath(filename); file.open_read_only(false); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3ecbf562bdb..c2d8ac0b065 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -20217,7 +20217,7 @@ wsrep_innobase_kill_one_trx( wsrep_thd_awake(thd, signal); } else { /* abort currently executing query */ - DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", + DBUG_PRINT("wsrep",("sending KILL_QUERY to: %lu", thd_get_thread_id(thd))); WSREP_DEBUG("kill query for: %ld", thd_get_thread_id(thd)); @@ -20361,7 +20361,8 @@ wsrep_fake_trx_id( mutex_enter(&trx_sys->mutex); trx_id_t trx_id = trx_sys_get_new_trx_id(); mutex_exit(&trx_sys->mutex); - WSREP_DEBUG("innodb fake trx id: %lu thd: %s", trx_id, wsrep_thd_query(thd)); + WSREP_DEBUG("innodb fake trx id: " TRX_ID_FMT " thd: %s", + trx_id, wsrep_thd_query(thd)); wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id); } diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index ea083381757..d26391a80f4 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -4962,21 +4962,36 @@ ibuf_check_bitmap_on_import( const trx_t* trx, /*!< in: transaction */ ulint space_id) /*!< in: tablespace identifier */ { - ulint size; ulint page_no; ut_ad(space_id); ut_ad(trx->mysql_thd); - bool found; - const page_size_t& page_size - = fil_space_get_page_size(space_id, &found); - - if (!found) { + FilSpace space(space_id); + if (!space()) { return(DB_TABLE_NOT_FOUND); } - size = fil_space_get_size(space_id); + const page_size_t page_size(space->flags); + /* fil_space_t::size and fil_space_t::free_limit would still be 0 + at this point. So, we will have to read page 0. */ + ut_ad(!space->free_limit); + ut_ad(!space->size); + + mtr_t mtr; + ulint size; + mtr.start(); + if (buf_block_t* sp = buf_page_get(page_id_t(space_id, 0), page_size, + RW_S_LATCH, &mtr)) { + size = std::min( + mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + + sp->frame), + mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + + sp->frame)); + } else { + size = 0; + } + mtr.commit(); if (size == 0) { return(DB_TABLE_NOT_FOUND); @@ -4991,7 +5006,6 @@ ibuf_check_bitmap_on_import( the space, as usual. */ for (page_no = 0; page_no < size; page_no += page_size.physical()) { - mtr_t mtr; page_t* bitmap_page; ulint i; diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 516898066aa..4a54c30629b 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -65,6 +65,7 @@ struct fil_addr_t; #define BUF_GET_POSSIBLY_FREED 16 /*!< Like BUF_GET, but do not mind if the file page has been freed. */ +#define BUF_EVICT_IF_IN_POOL 20 /*!< evict a clean block if found */ /* @} */ /** @name Modes for buf_page_get_known_nowait */ /* @{ */ diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index 3cc01473da1..54c001ce478 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -50,18 +50,14 @@ 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 */ -/******************************************************************//** -Flushes all dirty pages or removes all pages belonging -to a given tablespace. A PROBLEM: if readahead is being started, what -guarantees that it will not try to read in pages after this operation -has completed? */ +/** Empty the flush list for all pages belonging to a tablespace. +@param[in] id tablespace identifier +@param[in] trx transaction, for checking for user interrupt; + or NULL if nothing is to be written +@param[in] drop_ahi whether to drop the adaptive hash index */ +UNIV_INTERN void -buf_LRU_flush_or_remove_pages( -/*==========================*/ - ulint id, /*!< in: space id */ - buf_remove_t buf_remove, /*!< in: remove or flush strategy */ - const trx_t* trx); /*!< to check if the operation must - be interrupted */ +buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx, bool drop_ahi=false); #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /********************************************************************//** diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index 102b831ec61..719699f5ee2 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/include/buf0types.h @@ -59,17 +59,6 @@ enum buf_flush_t { BUF_FLUSH_N_TYPES /*!< index of last element + 1 */ }; -/** Algorithm to remove the pages for a tablespace from the buffer pool. -See buf_LRU_flush_or_remove_pages(). */ -enum buf_remove_t { - BUF_REMOVE_ALL_NO_WRITE, /*!< Remove all pages from the buffer - pool, don't write or sync to disk */ - BUF_REMOVE_FLUSH_NO_WRITE, /*!< Remove only, from the flush list, - don't write or sync to disk */ - BUF_REMOVE_FLUSH_WRITE /*!< Flush dirty pages to disk only - don't remove from the buffer pool */ -}; - /** Flags for io_fix types */ enum buf_io_fix { BUF_IO_NONE = 0, /**< no pending I/O */ diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index d3336c5f5b5..9fa507c2114 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -929,17 +929,12 @@ bool fil_table_accessible(const dict_table_t* table) MY_ATTRIBUTE((warn_unused_result, nonnull)); -/** Deletes an IBD tablespace, either general or single-table. -The tablespace must be cached in the memory cache. This will delete the -datafile, fil_space_t & fil_node_t entries from the file_system_t cache. -@param[in] space_id Tablespace id -@param[in] buf_remove Specify the action to take on the pages -for this table in the buffer pool. -@return true if success */ +/** Delete a tablespace and associated .ibd file. +@param[in] id tablespace identifier +@param[in] drop_ahi whether to drop the adaptive hash index +@return DB_SUCCESS or error */ dberr_t -fil_delete_tablespace( - ulint id, - buf_remove_t buf_remove); +fil_delete_tablespace(ulint id, bool drop_ahi = false); /** Truncate the tablespace to needed size. @param[in] space_id id of tablespace to truncate diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 1804cba7065..f06bc878c3b 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1537,18 +1537,16 @@ PageConverter::PageConverter( : AbstractCallback(trx), m_cfg(cfg), + m_index(cfg->m_indexes), + m_current_lsn(log_get_lsn()), m_page_zip_ptr(0), - m_heap(0) UNIV_NOTHROW + m_rec_iter(), + m_offsets_(), m_offsets(m_offsets_), + m_heap(0), + m_cluster_index(dict_table_get_first_index(cfg->m_table)) UNIV_NOTHROW { - m_index = m_cfg->m_indexes; - - m_current_lsn = log_get_lsn(); ut_a(m_current_lsn > 0); - - m_offsets = m_offsets_; rec_offs_init(m_offsets_); - - m_cluster_index = dict_table_get_first_index(m_cfg->m_table); } /** Adjust the BLOB reference for a single column that is externally stored @@ -2008,7 +2006,7 @@ PageConverter::operator() ( we can work on them */ if ((err = update_page(block, page_type)) != DB_SUCCESS) { - return(err); + break; } /* Note: For compressed pages this function will write to the @@ -2047,9 +2045,15 @@ PageConverter::operator() ( << " at offset " << offset << " looks corrupted in file " << m_filepath; - return(DB_CORRUPTION); + err = DB_CORRUPTION; } + /* If we already had and old page with matching number + in the buffer pool, evict it now, because + we no longer evict the pages on DISCARD TABLESPACE. */ + buf_page_get_gen(block->page.id, get_page_size(), + RW_NO_LATCH, NULL, BUF_EVICT_IF_IN_POOL, + __FILE__, __LINE__, NULL, NULL); return(err); } @@ -3649,8 +3653,7 @@ row_import_for_mysql( The only dirty pages generated should be from the pessimistic purge of delete marked records that couldn't be purged in Phase I. */ - buf_LRU_flush_or_remove_pages( - prebuilt->table->space, BUF_REMOVE_FLUSH_WRITE, trx); + buf_LRU_flush_or_remove_pages(prebuilt->table->space, trx); if (trx_is_interrupted(trx)) { ib::info() << "Phase III - Flush interrupted"; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 3f6fa713b6d..1b71751a9dd 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2505,10 +2505,7 @@ err_exit: /* We already have .ibd file here. it should be deleted. */ if (dict_table_is_file_per_table(table) - && fil_delete_tablespace( - table->space, - BUF_REMOVE_FLUSH_NO_WRITE) - != DB_SUCCESS) { + && fil_delete_tablespace(table->space) != DB_SUCCESS) { ib::error() << "Not able to delete tablespace " << table->space << " of table " @@ -3175,9 +3172,6 @@ row_discard_tablespace( 4) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we do not allow the discard. */ - /* Play safe and remove all insert buffer entries, though we should - have removed them already when DISCARD TABLESPACE was called */ - ibuf_delete_for_discarded_space(table->space); table_id_t new_id; @@ -3542,8 +3536,7 @@ row_drop_single_table_tablespace( ib::info() << "Removed datafile " << filepath << " for table " << tablename; - } else if (fil_delete_tablespace(space_id, BUF_REMOVE_FLUSH_NO_WRITE) - != DB_SUCCESS) { + } else if (fil_delete_tablespace(space_id) != DB_SUCCESS) { ib::error() << "We removed the InnoDB internal data" " dictionary entry of table " << tablename diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc index 54583956107..ccf58b9e73f 100644 --- a/storage/innobase/row/row0quiesce.cc +++ b/storage/innobase/row/row0quiesce.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -536,8 +537,7 @@ row_quiesce_table_start( } if (!trx_is_interrupted(trx)) { - buf_LRU_flush_or_remove_pages( - table->space, BUF_REMOVE_FLUSH_WRITE, trx); + buf_LRU_flush_or_remove_pages(table->space, trx); if (trx_is_interrupted(trx)) { diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index d6dd5805186..dc1b1eca0ef 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1100,21 +1100,22 @@ srv_undo_tablespaces_init(bool create_new_db) mtr_commit(&mtr); /* Step-2: Flush the dirty pages from the buffer pool. */ + trx_t* trx = trx_allocate_for_background(); + for (undo::undo_spaces_t::const_iterator it = undo::Truncate::s_fix_up_spaces.begin(); it != undo::Truncate::s_fix_up_spaces.end(); ++it) { - buf_LRU_flush_or_remove_pages( - TRX_SYS_SPACE, BUF_REMOVE_FLUSH_WRITE, NULL); + buf_LRU_flush_or_remove_pages(TRX_SYS_SPACE, trx); - buf_LRU_flush_or_remove_pages( - *it, BUF_REMOVE_FLUSH_WRITE, NULL); + buf_LRU_flush_or_remove_pages(*it, trx); /* Remove the truncate redo log file. */ undo::Truncate undo_trunc; undo_trunc.done_logging(*it); } + trx_free_for_background(trx); } return(DB_SUCCESS); diff --git a/storage/rocksdb/mysql-test/rocksdb/r/read_only_tx.result b/storage/rocksdb/mysql-test/rocksdb/r/read_only_tx.result index b83f0a474cc..db21c3c01d4 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/read_only_tx.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/read_only_tx.result @@ -1,11 +1,14 @@ DROP TABLE IF EXISTS t1; +connect con1,localhost,root,,; +connect con2,localhost,root,,; +connection con1; CREATE TABLE t1 (id INT, value int, PRIMARY KEY (id), INDEX (value)) ENGINE=RocksDB; INSERT INTO t1 VALUES (1,1); select variable_value into @p from information_schema.global_status where variable_name='rocksdb_number_sst_entry_put'; select variable_value into @s from information_schema.global_status where variable_name='rocksdb_number_sst_entry_singledelete'; -START TRANSACTION WITH CONSISTENT ROCKSDB SNAPSHOT; -File Position Gtid_executed -master-bin.000001 734 uuid:1-3 +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection con2; +connection con1; select case when variable_value-@p < 1000 then 'true' else variable_value-@p end from information_schema.global_status where variable_name='rocksdb_number_sst_entry_put'; case when variable_value-@p < 1000 then 'true' else variable_value-@p end true @@ -27,10 +30,15 @@ id value 1 10001 2 2 BEGIN; +connection con2; +connection con1; SELECT COUNT(*) FROM t1; COUNT(*) 9998 COMMIT; +connection default; +disconnect con1; +disconnect con2; OPTIMIZE TABLE t1; Table Op Msg_type Msg_text test.t1 optimize status OK diff --git a/storage/rocksdb/mysql-test/rocksdb/t/add_index_inplace_crash.test b/storage/rocksdb/mysql-test/rocksdb/t/add_index_inplace_crash.test index 84fe0046e7b..d715eb7df7a 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/add_index_inplace_crash.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/add_index_inplace_crash.test @@ -105,3 +105,13 @@ SHOW CREATE TABLE t1; SELECT COUNT(*) FROM t1; DROP TABLE t1; + +# Cleanup temporary #sql files. In the future server will remove these +# automatically but for now we need to do the delete explicit + +--disable_query_log +--disable_result_log +let $datadir=`select @@datadir`; +--remove_files_wildcard $datadir/test #sql* +--enable_result_log +--enable_query_log diff --git a/storage/rocksdb/mysql-test/rocksdb/t/disabled.def b/storage/rocksdb/mysql-test/rocksdb/t/disabled.def index 54cafbf24ba..118d8598de3 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/disabled.def +++ b/storage/rocksdb/mysql-test/rocksdb/t/disabled.def @@ -82,5 +82,5 @@ autoinc_vars_thread: debug sync point wait timed out ## information_schema : MariaRocks: requires GTIDs mysqlbinlog_gtid_skip_empty_trans_rocksdb : MariaRocks: requires GTIDs -read_only_tx : MariaRocks: requires GTIDs +#read_only_tx : MariaRocks: requires GTIDs rpl_row_triggers : MariaRocks: requires GTIDs diff --git a/storage/rocksdb/mysql-test/rocksdb/t/read_only_tx-master.opt b/storage/rocksdb/mysql-test/rocksdb/t/read_only_tx-master.opt index 52f4895dc2f..221b35c672a 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/read_only_tx-master.opt +++ b/storage/rocksdb/mysql-test/rocksdb/t/read_only_tx-master.opt @@ -1 +1 @@ ---rocksdb_default_cf_options=write_buffer_size=16k --log-bin --binlog_format=row --gtid_mode=ON --enforce_gtid_consistency --log-slave-updates +--rocksdb_default_cf_options=write_buffer_size=16k --log-bin --binlog_format=row --log-slave-updates diff --git a/storage/rocksdb/mysql-test/rocksdb/t/read_only_tx.test b/storage/rocksdb/mysql-test/rocksdb/t/read_only_tx.test index 52f65095d33..3a1025a3623 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/read_only_tx.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/read_only_tx.test @@ -2,9 +2,9 @@ --source include/have_rocksdb.inc --source include/count_sessions.inc --disable_warnings ---source include/have_gtid.inc +#--source include/have_gtid.inc --enable_warnings --- let $uuid = `select @@server_uuid;` +#-- let $uuid = `select @@server_uuid;` --disable_warnings DROP TABLE IF EXISTS t1; @@ -20,8 +20,8 @@ INSERT INTO t1 VALUES (1,1); # Read-only, long-running transaction. SingleDelete/Put shouldn't increase much. select variable_value into @p from information_schema.global_status where variable_name='rocksdb_number_sst_entry_put'; select variable_value into @s from information_schema.global_status where variable_name='rocksdb_number_sst_entry_singledelete'; --- replace_result $uuid uuid -START TRANSACTION WITH CONSISTENT ROCKSDB SNAPSHOT; +#-- replace_result $uuid uuid +START TRANSACTION WITH CONSISTENT SNAPSHOT; connection con2; --disable_query_log diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index 7eb0474091e..51e2453a853 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -730,6 +730,8 @@ buf_page_is_corrupted( ulint zip_size, const fil_space_t* space) { + DBUG_EXECUTE_IF("buf_page_import_corrupt_failure", return(TRUE); ); + ulint checksum_field1; ulint checksum_field2; ulint space_id = mach_read_from_4( @@ -838,8 +840,6 @@ buf_page_is_corrupted( return(false); } - DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", return(true); ); - ulint page_no = mach_read_from_4(read_buf + FIL_PAGE_OFFSET); const srv_checksum_algorithm_t curr_algo = @@ -2956,8 +2956,8 @@ buf_page_get_gen( ib_mutex_t* fix_mutex = NULL; buf_pool_t* buf_pool = buf_pool_get(space, offset); - ut_ad(mtr); - ut_ad(mtr->state == MTR_ACTIVE); + ut_ad((mtr == NULL) == (mode == BUF_EVICT_IF_IN_POOL)); + ut_ad(!mtr || mtr->state == MTR_ACTIVE); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH) || (rw_latch == RW_NO_LATCH)); @@ -2968,23 +2968,29 @@ buf_page_get_gen( #ifdef UNIV_DEBUG switch (mode) { + case BUF_EVICT_IF_IN_POOL: + /* After DISCARD TABLESPACE, the tablespace would not exist, + but in IMPORT TABLESPACE, PageConverter::operator() must + replace any old pages, which were not evicted during DISCARD. + Skip the assertion on zip_size. */ + break; case BUF_GET_NO_LATCH: ut_ad(rw_latch == RW_NO_LATCH); - break; + /* fall through */ case BUF_GET: case BUF_GET_IF_IN_POOL: case BUF_PEEK_IF_IN_POOL: case BUF_GET_IF_IN_POOL_OR_WATCH: case BUF_GET_POSSIBLY_FREED: + ut_ad(zip_size == fil_space_get_zip_size(space)); break; default: ut_error; } #endif /* UNIV_DEBUG */ - ut_ad(zip_size == fil_space_get_zip_size(space)); ut_ad(ut_is_2pow(zip_size)); #ifndef UNIV_LOG_DEBUG - ut_ad(!ibuf_inside(mtr) + ut_ad(!mtr || !ibuf_inside(mtr) || ibuf_page_low(space, zip_size, offset, FALSE, file, line, NULL)); #endif @@ -3054,9 +3060,11 @@ loop: rw_lock_x_unlock(hash_lock); } - if (mode == BUF_GET_IF_IN_POOL - || mode == BUF_PEEK_IF_IN_POOL - || mode == BUF_GET_IF_IN_POOL_OR_WATCH) { + switch (mode) { + case BUF_GET_IF_IN_POOL: + case BUF_GET_IF_IN_POOL_OR_WATCH: + case BUF_PEEK_IF_IN_POOL: + case BUF_EVICT_IF_IN_POOL: #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)); ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED)); @@ -3145,8 +3153,10 @@ got_block: ut_ad(page_zip_get_size(&block->page.zip) == zip_size); - if (mode == BUF_GET_IF_IN_POOL || mode == BUF_PEEK_IF_IN_POOL) { - + switch (mode) { + case BUF_GET_IF_IN_POOL: + case BUF_PEEK_IF_IN_POOL: + case BUF_EVICT_IF_IN_POOL: bool must_read; { @@ -3184,6 +3194,22 @@ got_block: case BUF_BLOCK_FILE_PAGE: ut_ad(fix_mutex != &buf_pool->zip_mutex); + + if (UNIV_UNLIKELY(mode == BUF_EVICT_IF_IN_POOL)) { +evict_from_pool: + ut_ad(!fix_block->page.oldest_modification); + mutex_enter(&buf_pool->LRU_list_mutex); + buf_block_unfix(fix_block); + mutex_enter(fix_mutex); + + if (!buf_LRU_free_page(&fix_block->page, true)) { + ut_ad(0); + mutex_exit(&buf_pool->LRU_list_mutex); + } + + mutex_exit(fix_mutex); + return(NULL); + } break; case BUF_BLOCK_ZIP_PAGE: @@ -3218,6 +3244,10 @@ got_block: goto loop; } + if (UNIV_UNLIKELY(mode == BUF_EVICT_IF_IN_POOL)) { + goto evict_from_pool; + } + /* Buffer-fix the block so that it cannot be evicted or relocated while we are attempting to allocate an uncompressed page. */ @@ -4798,7 +4828,7 @@ database_corrupted: if (err != DB_SUCCESS) { /* Not a real corruption if it was triggered by error injection */ - DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", + DBUG_EXECUTE_IF("buf_page_import_corrupt_failure", if (bpage->space > TRX_SYS_SPACE) { buf_mark_space_corrupt(bpage); ib_logf(IB_LOG_LEVEL_INFO, @@ -4866,7 +4896,7 @@ database_corrupted: } } - DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", + DBUG_EXECUTE_IF("buf_page_import_corrupt_failure", page_not_corrupt: bpage = bpage; ); if (recv_recovery_is_on()) { diff --git a/storage/xtradb/buf/buf0lru.cc b/storage/xtradb/buf/buf0lru.cc index d979eb44a96..c71d45009e4 100644 --- a/storage/xtradb/buf/buf0lru.cc +++ b/storage/xtradb/buf/buf0lru.cc @@ -571,26 +571,20 @@ buf_flush_or_remove_page( return(processed); } -/******************************************************************//** -Remove all dirty pages belonging to a given tablespace inside a specific +/** Remove all dirty pages belonging to a given tablespace inside a specific buffer pool instance when we are deleting the data file(s) of that tablespace. The pages still remain a part of LRU and are evicted from the list as they age towards the tail of the LRU. +@param[in,out] buf_pool buffer pool +@param[in] id tablespace identifier +@param[in] trx transaction (to check for interrupt), + or NULL if the files should not be written to @retval DB_SUCCESS if all freed @retval DB_FAIL if not all freed @retval DB_INTERRUPTED if the transaction was interrupted */ static MY_ATTRIBUTE((nonnull(1), warn_unused_result)) dberr_t -buf_flush_or_remove_pages( -/*======================*/ - buf_pool_t* buf_pool, /*!< buffer pool instance */ - ulint id, /*!< in: target space id for which - to remove or flush pages */ - bool flush, /*!< in: flush to disk if true but - don't remove else remove without - flushing to disk */ - const trx_t* trx) /*!< to check if the operation must - be interrupted, can be 0 */ +buf_flush_or_remove_pages(buf_pool_t* buf_pool, ulint id, const trx_t* trx) { buf_page_t* prev; buf_page_t* bpage; @@ -621,7 +615,7 @@ rescan: /* Skip this block, as it does not belong to the target space. */ - } else if (!buf_flush_or_remove_page(buf_pool, bpage, flush, + } else if (!buf_flush_or_remove_page(buf_pool, bpage, trx, &must_restart)) { /* Remove was unsuccessful, we have to try again @@ -647,7 +641,7 @@ rescan: /* Cannot trust the prev pointer */ break; } - } else if (flush) { + } else if (trx) { /* The processing was successful. And during the processing we have released all the buf_pool mutexes @@ -674,19 +668,17 @@ rescan: break; } -#ifdef DBUG_OFF - if (flush) { + if (trx) { DBUG_EXECUTE_IF("ib_export_flush_crash", static ulint n_pages; if (++n_pages == 4) {DBUG_SUICIDE();}); - } -#endif /* DBUG_OFF */ - /* The check for trx is interrupted is expensive, we want - to check every N iterations. */ - if (!processed && trx && trx_is_interrupted(trx)) { - buf_flush_list_mutex_exit(buf_pool); - return(DB_INTERRUPTED); + /* The check for trx is interrupted is + expensive, we want to check every N iterations. */ + if (!processed && trx_is_interrupted(trx)) { + buf_flush_list_mutex_exit(buf_pool); + return(DB_INTERRUPTED); + } } } @@ -695,28 +687,25 @@ rescan: return(all_freed ? DB_SUCCESS : DB_FAIL); } -/******************************************************************//** -Remove or flush all the dirty pages that belong to a given tablespace +/** Remove or flush all the dirty pages that belong to a given tablespace inside a specific buffer pool instance. The pages will remain in the LRU list and will be evicted from the LRU list as they age and move towards -the tail of the LRU list. */ +the tail of the LRU list. +@param[in,out] buf_pool buffer pool +@param[in] id tablespace identifier +@param[in] trx transaction (to check for interrupt), + or NULL if the files should not be written to +*/ static MY_ATTRIBUTE((nonnull(1))) void -buf_flush_dirty_pages( -/*==================*/ - buf_pool_t* buf_pool, /*!< buffer pool instance */ - ulint id, /*!< in: space id */ - bool flush, /*!< in: flush to disk if true otherwise - remove the pages without flushing */ - const trx_t* trx) /*!< to check if the operation must - be interrupted */ +buf_flush_dirty_pages(buf_pool_t* buf_pool, ulint id, const trx_t* trx) { dberr_t err; do { mutex_enter(&buf_pool->LRU_list_mutex); - err = buf_flush_or_remove_pages(buf_pool, id, flush, trx); + err = buf_flush_or_remove_pages(buf_pool, id, trx); mutex_exit(&buf_pool->LRU_list_mutex); @@ -737,239 +726,27 @@ buf_flush_dirty_pages( || buf_pool_get_dirty_pages_count(buf_pool, id) == 0); } -/******************************************************************//** -Remove all pages that belong to a given tablespace inside a specific -buffer pool instance when we are DISCARDing the tablespace. */ -static MY_ATTRIBUTE((nonnull)) +/** Empty the flush list for all pages belonging to a tablespace. +@param[in] id tablespace identifier +@param[in] trx transaction, for checking for user interrupt; + or NULL if nothing is to be written +@param[in] drop_ahi whether to drop the adaptive hash index */ +UNIV_INTERN void -buf_LRU_remove_all_pages( -/*=====================*/ - buf_pool_t* buf_pool, /*!< buffer pool instance */ - ulint id) /*!< in: space id */ +buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx, bool drop_ahi) { - buf_page_t* bpage; - ibool all_freed; - -scan_again: - mutex_enter(&buf_pool->LRU_list_mutex); - - all_freed = TRUE; - - for (bpage = UT_LIST_GET_LAST(buf_pool->LRU); - bpage != NULL; - /* No op */) { - - prio_rw_lock_t* hash_lock; - buf_page_t* prev_bpage; - ib_mutex_t* block_mutex = NULL; - - ut_a(buf_page_in_file(bpage)); - ut_ad(bpage->in_LRU_list); - - prev_bpage = UT_LIST_GET_PREV(LRU, bpage); - - /* It is safe to check bpage->space and bpage->io_fix while - holding buf_pool->LRU_list_mutex only and later recheck - while holding the buf_page_get_mutex() mutex. */ - - if (buf_page_get_space(bpage) != id) { - /* Skip this block, as it does not belong to - the space that is being invalidated. */ - goto next_page; - } else if (UNIV_UNLIKELY(buf_page_get_io_fix_unlocked(bpage) - != BUF_IO_NONE)) { - /* We cannot remove this page during this scan - yet; maybe the system is currently reading it - in, or flushing the modifications to the file */ - - all_freed = FALSE; - goto next_page; - } else { - ulint fold = buf_page_address_fold( - bpage->space, bpage->offset); - - hash_lock = buf_page_hash_lock_get(buf_pool, fold); - - rw_lock_x_lock(hash_lock); - - block_mutex = buf_page_get_mutex(bpage); - mutex_enter(block_mutex); - - if (UNIV_UNLIKELY( - buf_page_get_space(bpage) != id - || bpage->buf_fix_count > 0 - || (buf_page_get_io_fix(bpage) - != BUF_IO_NONE))) { - - mutex_exit(block_mutex); - - rw_lock_x_unlock(hash_lock); - - /* We cannot remove this page during - this scan yet; maybe the system is - currently reading it in, or flushing - the modifications to the file */ - - all_freed = FALSE; - - goto next_page; - } - } - - ut_ad(mutex_own(block_mutex)); - -#ifdef UNIV_DEBUG - if (buf_debug_prints) { - fprintf(stderr, - "Dropping space %lu page %lu\n", - (ulong) buf_page_get_space(bpage), - (ulong) buf_page_get_page_no(bpage)); - } -#endif - if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { - /* Do nothing, because the adaptive hash index - covers uncompressed pages only. */ - } else if (((buf_block_t*) bpage)->index) { - ulint page_no; - ulint zip_size; - - mutex_exit(&buf_pool->LRU_list_mutex); - - zip_size = buf_page_get_zip_size(bpage); - page_no = buf_page_get_page_no(bpage); - - mutex_exit(block_mutex); - - rw_lock_x_unlock(hash_lock); - - /* Note that the following call will acquire - and release block->lock X-latch. */ - - btr_search_drop_page_hash_when_freed( - id, zip_size, page_no); - - goto scan_again; - } - - if (bpage->oldest_modification != 0) { - - buf_flush_remove(bpage); - } - - ut_ad(!bpage->in_flush_list); - - /* Remove from the LRU list. */ - - if (buf_LRU_block_remove_hashed(bpage, true)) { - - mutex_enter(block_mutex); - buf_LRU_block_free_hashed_page((buf_block_t*) bpage); - mutex_exit(block_mutex); - } else { - ut_ad(block_mutex == &buf_pool->zip_mutex); + for (ulint i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool = buf_pool_from_array(i); + if (drop_ahi) { + buf_LRU_drop_page_hash_for_tablespace(buf_pool, id); } - - ut_ad(!mutex_own(block_mutex)); - -#ifdef UNIV_SYNC_DEBUG - /* buf_LRU_block_remove_hashed() releases the hash_lock */ - ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)); - ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED)); -#endif /* UNIV_SYNC_DEBUG */ - -next_page: - bpage = prev_bpage; + buf_flush_dirty_pages(buf_pool, id, trx); } - mutex_exit(&buf_pool->LRU_list_mutex); - - if (!all_freed) { - os_thread_sleep(20000); - - goto scan_again; - } -} - -/******************************************************************//** -Remove pages belonging to a given tablespace inside a specific -buffer pool instance when we are deleting the data file(s) of that -tablespace. The pages still remain a part of LRU and are evicted from -the list as they age towards the tail of the LRU only if buf_remove -is BUF_REMOVE_FLUSH_NO_WRITE. */ -static MY_ATTRIBUTE((nonnull(1))) -void -buf_LRU_remove_pages( -/*=================*/ - buf_pool_t* buf_pool, /*!< buffer pool instance */ - ulint id, /*!< in: space id */ - buf_remove_t buf_remove, /*!< in: remove or flush strategy */ - const trx_t* trx) /*!< to check if the operation must - be interrupted */ -{ - switch (buf_remove) { - case BUF_REMOVE_ALL_NO_WRITE: - buf_LRU_remove_all_pages(buf_pool, id); - break; - - case BUF_REMOVE_FLUSH_NO_WRITE: - ut_a(trx == 0); - buf_flush_dirty_pages(buf_pool, id, false, NULL); - break; - - case BUF_REMOVE_FLUSH_WRITE: - ut_a(trx != 0); - buf_flush_dirty_pages(buf_pool, id, true, trx); + if (trx && !trx_is_interrupted(trx)) { /* Ensure that all asynchronous IO is completed. */ os_aio_wait_until_no_pending_writes(); fil_flush(id); - break; - } -} - -/******************************************************************//** -Flushes all dirty pages or removes all pages belonging -to a given tablespace. A PROBLEM: if readahead is being started, what -guarantees that it will not try to read in pages after this operation -has completed? */ -UNIV_INTERN -void -buf_LRU_flush_or_remove_pages( -/*==========================*/ - ulint id, /*!< in: space id */ - buf_remove_t buf_remove, /*!< in: remove or flush strategy */ - const trx_t* trx) /*!< to check if the operation must - be interrupted */ -{ - ulint i; - - /* Before we attempt to drop pages one by one we first - attempt to drop page hash index entries in batches to make - it more efficient. The batching attempt is a best effort - attempt and does not guarantee that all pages hash entries - will be dropped. We get rid of remaining page hash entries - one by one below. */ - for (i = 0; i < srv_buf_pool_instances; i++) { - buf_pool_t* buf_pool; - - buf_pool = buf_pool_from_array(i); - - switch (buf_remove) { - case BUF_REMOVE_ALL_NO_WRITE: - buf_LRU_drop_page_hash_for_tablespace(buf_pool, id); - break; - - case BUF_REMOVE_FLUSH_NO_WRITE: - /* It is a DROP TABLE for a single table - tablespace. No AHI entries exist because - we already dealt with them when freeing up - extents. */ - case BUF_REMOVE_FLUSH_WRITE: - /* We allow read-only queries against the - table, there is no need to drop the AHI entries. */ - break; - } - - buf_LRU_remove_pages(buf_pool, id, buf_remove, trx); } } diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index 1558c6d50ac..5af3a635a96 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -1679,7 +1679,7 @@ dict_table_rename_in_cache( filepath = fil_make_ibd_name(table->name, false); } - fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE); + fil_delete_tablespace(table->space, true); /* Delete any temp file hanging around. */ if (os_file_status(filepath, &exists, &ftype) diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 3dd8aa8081b..445c564e9cf 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -2572,8 +2572,7 @@ fil_op_log_parse_or_replay( switch (type) { case MLOG_FILE_DELETE: if (fil_tablespace_exists_in_mem(space_id)) { - dberr_t err = fil_delete_tablespace( - space_id, BUF_REMOVE_FLUSH_NO_WRITE); + dberr_t err = fil_delete_tablespace(space_id); ut_a(err == DB_SUCCESS); } @@ -2851,7 +2850,7 @@ fil_close_tablespace( completely and permanently. The flag stop_new_ops also prevents fil_flush() from being applied to this tablespace. */ - buf_LRU_flush_or_remove_pages(id, BUF_REMOVE_FLUSH_WRITE, trx); + buf_LRU_flush_or_remove_pages(id, trx); #endif mutex_enter(&fil_system->mutex); @@ -2878,18 +2877,13 @@ fil_close_tablespace( return(err); } -/*******************************************************************//** -Deletes a single-table tablespace. The tablespace must be cached in the -memory cache. +/** Delete a tablespace and associated .ibd file. +@param[in] id tablespace identifier +@param[in] drop_ahi whether to drop the adaptive hash index @return DB_SUCCESS or error */ UNIV_INTERN dberr_t -fil_delete_tablespace( -/*==================*/ - ulint id, /*!< in: space id */ - buf_remove_t buf_remove) /*!< in: specify the action to take - on the tables pages in the buffer - pool */ +fil_delete_tablespace(ulint id, bool drop_ahi) { char* path = 0; fil_space_t* space = 0; @@ -2945,7 +2939,7 @@ fil_delete_tablespace( To deal with potential read requests by checking the ::stop_new_ops flag in fil_io() */ - buf_LRU_flush_or_remove_pages(id, buf_remove, 0); + buf_LRU_flush_or_remove_pages(id, NULL, drop_ahi); #endif /* !UNIV_HOTBACKUP */ @@ -3056,7 +3050,7 @@ fil_discard_tablespace( { dberr_t err; - switch (err = fil_delete_tablespace(id, BUF_REMOVE_ALL_NO_WRITE)) { + switch (err = fil_delete_tablespace(id, true)) { case DB_SUCCESS: break; @@ -4863,7 +4857,7 @@ fil_load_single_table_tablespace( /* Check for a link file which locates a remote tablespace. */ - remote.success = fil_open_linked_file( + remote.success = (IS_XTRABACKUP() && !srv_backup_mode) ? 0 : fil_open_linked_file( tablename, &remote.filepath, &remote.file, FALSE); /* Read the first page of the remote tablespace */ diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 9a1a387e1d7..987e86c3927 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -10947,7 +10947,7 @@ wsrep_append_foreign_key( shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE, copy); if (rcode) { - DBUG_PRINT("wsrep", ("row key failed: %lu", rcode)); + DBUG_PRINT("wsrep", ("row key failed: %zu", rcode)); WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu", (wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void", rcode); @@ -19714,7 +19714,7 @@ wsrep_innobase_kill_one_trx( wsrep_thd_awake(thd, signal); } else { /* abort currently executing query */ - DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", + DBUG_PRINT("wsrep",("sending KILL_QUERY to: %lu", thd_get_thread_id(thd))); WSREP_DEBUG("kill query for: %ld", thd_get_thread_id(thd)); @@ -19841,7 +19841,8 @@ wsrep_fake_trx_id( mutex_enter(&trx_sys->mutex); trx_id_t trx_id = trx_sys_get_new_trx_id(); mutex_exit(&trx_sys->mutex); - WSREP_DEBUG("innodb fake trx id: %lu thd: %s", trx_id, wsrep_thd_query(thd)); + WSREP_DEBUG("innodb fake trx id: " TRX_ID_FMT " thd: %s", + trx_id, wsrep_thd_query(thd)); wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id); } diff --git a/storage/xtradb/ibuf/ibuf0ibuf.cc b/storage/xtradb/ibuf/ibuf0ibuf.cc index 17741b324c9..6925cd3abb5 100644 --- a/storage/xtradb/ibuf/ibuf0ibuf.cc +++ b/storage/xtradb/ibuf/ibuf0ibuf.cc @@ -5178,7 +5178,20 @@ ibuf_check_bitmap_on_import( return(DB_TABLE_NOT_FOUND); } - size = fil_space_get_size(space_id); + mtr_t mtr; + mtr_start(&mtr); + { + buf_block_t* sp = buf_page_get(space_id, zip_size, 0, + RW_S_LATCH, &mtr); + if (sp) { + size = mach_read_from_4( + FSP_HEADER_OFFSET + FSP_FREE_LIMIT + + sp->frame); + } else { + size = 0; + } + } + mtr_commit(&mtr); if (size == 0) { return(DB_TABLE_NOT_FOUND); @@ -5189,7 +5202,6 @@ ibuf_check_bitmap_on_import( page_size = zip_size ? zip_size : UNIV_PAGE_SIZE; for (page_no = 0; page_no < size; page_no += page_size) { - mtr_t mtr; page_t* bitmap_page; ulint i; diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h index 88ee042e8c3..7661ba1785d 100644 --- a/storage/xtradb/include/buf0buf.h +++ b/storage/xtradb/include/buf0buf.h @@ -58,6 +58,7 @@ Created 11/5/1995 Heikki Tuuri #define BUF_GET_POSSIBLY_FREED 16 /*!< Like BUF_GET, but do not mind if the file page has been freed. */ +#define BUF_EVICT_IF_IN_POOL 20 /*!< evict a clean block if found */ /* @} */ /** @name Modes for buf_page_get_known_nowait */ /* @{ */ diff --git a/storage/xtradb/include/buf0lru.h b/storage/xtradb/include/buf0lru.h index f056c6c4116..1bc11937fa1 100644 --- a/storage/xtradb/include/buf0lru.h +++ b/storage/xtradb/include/buf0lru.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -53,19 +54,14 @@ 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 */ -/******************************************************************//** -Flushes all dirty pages or removes all pages belonging -to a given tablespace. A PROBLEM: if readahead is being started, what -guarantees that it will not try to read in pages after this operation -has completed? */ +/** Empty the flush list for all pages belonging to a tablespace. +@param[in] id tablespace identifier +@param[in] trx transaction, for checking for user interrupt; + or NULL if nothing is to be written +@param[in] drop_ahi whether to drop the adaptive hash index */ UNIV_INTERN void -buf_LRU_flush_or_remove_pages( -/*==========================*/ - ulint id, /*!< in: space id */ - buf_remove_t buf_remove, /*!< in: remove or flush strategy */ - const trx_t* trx); /*!< to check if the operation must - be interrupted */ +buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx, bool drop_ahi=false); #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /********************************************************************//** diff --git a/storage/xtradb/include/buf0types.h b/storage/xtradb/include/buf0types.h index 4eb5ea18cef..6db3cb1238c 100644 --- a/storage/xtradb/include/buf0types.h +++ b/storage/xtradb/include/buf0types.h @@ -58,17 +58,6 @@ enum buf_flush_t { BUF_FLUSH_N_TYPES /*!< index of last element + 1 */ }; -/** Algorithm to remove the pages for a tablespace from the buffer pool. -See buf_LRU_flush_or_remove_pages(). */ -enum buf_remove_t { - BUF_REMOVE_ALL_NO_WRITE, /*!< Remove all pages from the buffer - pool, don't write or sync to disk */ - BUF_REMOVE_FLUSH_NO_WRITE, /*!< Remove only, from the flush list, - don't write or sync to disk */ - BUF_REMOVE_FLUSH_WRITE /*!< Flush dirty pages to disk only - don't remove from the buffer pool */ -}; - /** Flags for io_fix types */ enum buf_io_fix { BUF_IO_NONE = 0, /**< no pending I/O */ diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index a33cec65ed5..5fe2d20b4f0 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -849,18 +849,13 @@ fil_op_log_parse_or_replay( only be parsed but not replayed */ ulint log_flags); /*!< in: redo log flags (stored in the page number parameter) */ -/*******************************************************************//** -Deletes a single-table tablespace. The tablespace must be cached in the -memory cache. -@return TRUE if success */ +/** Delete a tablespace and associated .ibd file. +@param[in] id tablespace identifier +@param[in] drop_ahi whether to drop the adaptive hash index +@return DB_SUCCESS or error */ UNIV_INTERN dberr_t -fil_delete_tablespace( -/*==================*/ - ulint id, /*!< in: space id */ - buf_remove_t buf_remove); /*!< in: specify the action to take - on the tables pages in the buffer - pool */ +fil_delete_tablespace(ulint id, bool drop_ahi = false); /*******************************************************************//** Closes a single-table tablespace. The tablespace must be cached in the memory cache. Free all pages used by the tablespace. diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 8759cea9e6d..ddaeff69f10 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -2141,6 +2141,7 @@ lock_rec_insert_by_trx_age( return DB_SUCCESS; } +#ifdef UNIV_DEBUG static bool lock_queue_validate( @@ -2174,6 +2175,7 @@ lock_queue_validate( } return true; } +#endif /* UNIV_DEBUG */ static void diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 183f65bcbd8..8b0fa059100 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -2570,8 +2570,8 @@ os_file_get_size( return(offset); #else - return((os_offset_t) lseek(file, 0, SEEK_END)); - + struct stat statbuf; + return fstat(file, &statbuf) ? os_offset_t(-1) : statbuf.st_size; #endif /* __WIN__ */ } @@ -2625,19 +2625,29 @@ os_file_set_size( if (srv_use_posix_fallocate) { int err; do { - err = posix_fallocate(file, 0, size); + os_offset_t current_size = os_file_get_size(file); + err = current_size >= size + ? 0 : posix_fallocate(file, current_size, + size - current_size); } while (err == EINTR && srv_shutdown_state == SRV_SHUTDOWN_NONE); - if (err) { + switch (err) { + case 0: + return true; + default: ib_logf(IB_LOG_LEVEL_ERROR, "preallocating " INT64PF " bytes for" "file %s failed with error %d", size, name, err); + /* fall through */ + case EINTR: + errno = err; + return false; + case EINVAL: + /* fall back to the code below */ + break; } - /* Set errno because posix_fallocate() does not do it.*/ - errno = err; - return(!err); } # endif @@ -2679,11 +2689,12 @@ os_file_set_size( } current_size += n_bytes; - } while (current_size < size); + } while (current_size < size + && srv_shutdown_state == SRV_SHUTDOWN_NONE); free(buf2); - return(ret && os_file_flush(file)); + return(ret && current_size >= size && os_file_flush(file)); #endif } diff --git a/storage/xtradb/row/row0import.cc b/storage/xtradb/row/row0import.cc index 130f50ec9ed..7689c362c0d 100644 --- a/storage/xtradb/row/row0import.cc +++ b/storage/xtradb/row/row0import.cc @@ -1602,18 +1602,16 @@ PageConverter::PageConverter( : AbstractCallback(trx), m_cfg(cfg), + m_index(cfg->m_indexes), + m_current_lsn(log_get_lsn()), m_page_zip_ptr(0), - m_heap(0) UNIV_NOTHROW + m_rec_iter(), + m_offsets_(), m_offsets(m_offsets_), + m_heap(0), + m_cluster_index(dict_table_get_first_index(cfg->m_table)) UNIV_NOTHROW { - m_index = m_cfg->m_indexes; - - m_current_lsn = log_get_lsn(); ut_a(m_current_lsn > 0); - - m_offsets = m_offsets_; rec_offs_init(m_offsets_); - - m_cluster_index = dict_table_get_first_index(m_cfg->m_table); } /** @@ -2104,7 +2102,7 @@ PageConverter::operator() ( we can work on them */ if ((err = update_page(block, page_type)) != DB_SUCCESS) { - return(err); + break; } /* Note: For compressed pages this function will write to the @@ -2141,9 +2139,15 @@ PageConverter::operator() ( "%s: Page %lu at offset " UINT64PF " looks corrupted.", m_filepath, (ulong) (offset / m_page_size), offset); - return(DB_CORRUPTION); + err = DB_CORRUPTION; } + /* If we already had and old page with matching number + in the buffer pool, evict it now, because + we no longer evict the pages on DISCARD TABLESPACE. */ + buf_page_get_gen(get_space_id(), get_zip_size(), block->page.offset, + RW_NO_LATCH, NULL, BUF_EVICT_IF_IN_POOL, + __FILE__, __LINE__, NULL); return(err); } @@ -3717,8 +3721,7 @@ row_import_for_mysql( The only dirty pages generated should be from the pessimistic purge of delete marked records that couldn't be purged in Phase I. */ - buf_LRU_flush_or_remove_pages( - prebuilt->table->space, BUF_REMOVE_FLUSH_WRITE, trx); + buf_LRU_flush_or_remove_pages(prebuilt->table->space, trx); if (trx_is_interrupted(trx)) { ib_logf(IB_LOG_LEVEL_INFO, "Phase III - Flush interrupted"); diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index 67eb1d7de94..3f79c3af6c8 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -2494,10 +2494,7 @@ err_exit: /* We already have .ibd file here. it should be deleted. */ if (table->space - && fil_delete_tablespace( - table->space, - BUF_REMOVE_FLUSH_NO_WRITE) - != DB_SUCCESS) { + && fil_delete_tablespace(table->space) != DB_SUCCESS) { ut_print_timestamp(stderr); fprintf(stderr, @@ -3132,9 +3129,6 @@ row_discard_tablespace( 4) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we do not allow the discard. */ - /* Play safe and remove all insert buffer entries, though we should - have removed them already when DISCARD TABLESPACE was called */ - ibuf_delete_for_discarded_space(table->space); table_id_t new_id; @@ -4516,9 +4510,7 @@ row_drop_table_for_mysql( fil_delete_file(filepath); - } else if (fil_delete_tablespace( - space_id, - BUF_REMOVE_FLUSH_NO_WRITE) + } else if (fil_delete_tablespace(space_id) != DB_SUCCESS) { fprintf(stderr, "InnoDB: We removed now the InnoDB" diff --git a/storage/xtradb/row/row0quiesce.cc b/storage/xtradb/row/row0quiesce.cc index 583fbe60fb3..6c4e6adb96c 100644 --- a/storage/xtradb/row/row0quiesce.cc +++ b/storage/xtradb/row/row0quiesce.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -542,8 +543,7 @@ row_quiesce_table_start( } if (!trx_is_interrupted(trx)) { - buf_LRU_flush_or_remove_pages( - table->space, BUF_REMOVE_FLUSH_WRITE, trx); + buf_LRU_flush_or_remove_pages(table->space, trx); if (trx_is_interrupted(trx)) { diff --git a/storage/xtradb/trx/trx0undo.cc b/storage/xtradb/trx/trx0undo.cc index 0cc3048e624..3259bcb70b1 100644 --- a/storage/xtradb/trx/trx0undo.cc +++ b/storage/xtradb/trx/trx0undo.cc @@ -2025,6 +2025,7 @@ trx_undo_free_prepared( /* lock_trx_release_locks() assigns trx->is_recovered=false */ ut_a(srv_read_only_mode + || srv_apply_log_only || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO); break; default: |