diff options
-rw-r--r-- | mysql-test/suite/atomic/drop_db.result | 95 | ||||
-rw-r--r-- | mysql-test/suite/atomic/drop_db.test | 112 | ||||
-rw-r--r-- | mysql-test/suite/atomic/drop_db_long_names.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/atomic/drop_db_long_names.result | 11 | ||||
-rw-r--r-- | mysql-test/suite/atomic/drop_db_long_names.test | 108 | ||||
-rw-r--r-- | mysql-test/suite/atomic/drop_sequence.result | 75 | ||||
-rw-r--r-- | mysql-test/suite/atomic/drop_sequence.test | 18 | ||||
-rw-r--r-- | mysql-test/suite/atomic/drop_table.result | 110 | ||||
-rw-r--r-- | mysql-test/suite/atomic/drop_view.result | 10 | ||||
-rw-r--r-- | sql/ddl_log.cc | 360 | ||||
-rw-r--r-- | sql/ddl_log.h | 30 | ||||
-rw-r--r-- | sql/handler.cc | 5 | ||||
-rw-r--r-- | sql/handler.h | 2 | ||||
-rw-r--r-- | sql/sql_db.cc | 182 | ||||
-rw-r--r-- | sql/sql_db.h | 4 | ||||
-rw-r--r-- | sql/sql_table.cc | 68 | ||||
-rw-r--r-- | sql/sql_table.h | 6 | ||||
-rw-r--r-- | sql/sql_view.cc | 2 |
18 files changed, 913 insertions, 286 deletions
diff --git a/mysql-test/suite/atomic/drop_db.result b/mysql-test/suite/atomic/drop_db.result new file mode 100644 index 00000000000..43bb2d32f62 --- /dev/null +++ b/mysql-test/suite/atomic/drop_db.result @@ -0,0 +1,95 @@ +call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal"); +"engine: aria crash point: ddl_log_drop_before_delete_table position: 1" +t1v.frm +t2.MAD +t2.MAI +t2.frm +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foo STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +insert into test.t1 values (42) latin1 latin1_swedish_ci latin1_swedish_ci +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_before_delete_table position: 2" +t1v.frm +t2.MAD +t2.MAI +t2.frm +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foo STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +insert into test.t1 values (42) latin1 latin1_swedish_ci latin1_swedish_ci +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_before_delete_table position: 3" +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foo STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +insert into test.t1 values (42) latin1 latin1_swedish_ci latin1_swedish_ci +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_after_drop_tables position: 1" +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foo STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +insert into test.t1 values (42) latin1 latin1_swedish_ci latin1_swedish_ci +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_before_ha_drop_database position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_before_drop_db_routines position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_after_drop_db_routines position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_before_drop_option_file position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_before_drop_dir position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_after_drop_dir position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_before_binlog position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_after_binlog position: 1" +master-bin.000001 # Query # # DROP DATABASE test2 +"engine: innodb crash point: ddl_log_drop_before_delete_table position: 1" +t1v.frm +t2.frm +t2.ibd +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foo STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +insert into test.t1 values (42) latin1 latin1_swedish_ci latin1_swedish_ci +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_before_delete_table position: 2" +t1v.frm +t2.frm +t2.ibd +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foo STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +insert into test.t1 values (42) latin1 latin1_swedish_ci latin1_swedish_ci +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_before_delete_table position: 3" +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foo STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +insert into test.t1 values (42) latin1 latin1_swedish_ci latin1_swedish_ci +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_after_drop_tables position: 1" +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foo STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +insert into test.t1 values (42) latin1 latin1_swedish_ci latin1_swedish_ci +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_before_ha_drop_database position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_before_drop_db_routines position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_after_drop_db_routines position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_before_drop_option_file position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_before_drop_dir position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_after_drop_dir position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_before_binlog position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +"engine: innodb crash point: ddl_log_drop_after_binlog position: 1" +master-bin.000001 # Query # # DROP DATABASE test2 +Warnings: +Note 1008 Can't drop database 'test2'; database doesn't exist diff --git a/mysql-test/suite/atomic/drop_db.test b/mysql-test/suite/atomic/drop_db.test new file mode 100644 index 00000000000..96f6a0dd76a --- /dev/null +++ b/mysql-test/suite/atomic/drop_db.test @@ -0,0 +1,112 @@ +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/have_log_bin.inc +--source include/not_valgrind.inc + +# +# Testing of atomic DROP DATABASE with crashes in a lot of different places +# + +call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal"); +let $MYSQLD_DATADIR= `SELECT @@datadir`; + +let $engine_count=2; +let $engines='aria','innodb'; + +let $crash_count=10; +let $crash_points='ddl_log_drop_before_delete_table','ddl_log_drop_after_drop_tables','ddl_log_drop_before_ha_drop_database','ddl_log_drop_before_drop_db_routines','ddl_log_drop_after_drop_db_routines','ddl_log_drop_before_drop_option_file','ddl_log_drop_before_drop_dir','ddl_log_drop_after_drop_dir','ddl_log_drop_before_binlog','ddl_log_drop_after_binlog'; + +let $old_debug=`select @@debug_dbug`; + +let $e=0; +let $keep_include_silent=1; +let $grep_script=DROP; +--disable_query_log + +while ($e < $engine_count) +{ + inc $e; + let $engine=`select ELT($e, $engines)`; + let $default_engine=$engine; + let $extra_option=; + + if ($engine == "aria") + { + let $extra_option=transactional=1; + } + if ($engine == "aria_notrans") + { + let $default_engine="aria"; + let $extra_option=transactional=0; + } + + # Number of tables that should be dropped (we try to crash after each drop) + let $drops=3; + + let $c=0; + while ($c < $crash_count) + { + inc $c; + let $crash=`select ELT($c, $crash_points)`; + let $r=0; + while ($r < $drops) + { + inc $r; + create database test2; + use test2; + --eval set @@default_storage_engine=$default_engine; + --eval create table t1 (a int not null) $extra_option; + create view t1v as select * from t1; + --eval create table t2 (b int not null) $extra_option; + create procedure foo() + insert into test.t1 values (42); + + flush tables; + use test; + + RESET MASTER; + + echo "engine: $engine crash point: $crash position: $r"; + --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect + --disable_reconnect + --eval set @@debug_dbug="+d,$crash",@debug_crash_counter=$r + let $errno=0; + --error 0,2013 + DROP DATABASE test2; + let $error=$errno; + --enable_reconnect + --source include/wait_until_connected_again.inc + --disable_query_log + --eval set @@debug_dbug="$old_debug" + + if ($error == 0) + { + echo "No crash!"; + } + use test; + # Check which tables still exists + --error 0,1 + --list_files $MYSQLD_DATADIR/test2 t* + --error 0,ER_SP_DOES_NOT_EXIST + show create procedure test2.foo; + + --let $binlog_file=master-bin.000001 + --source include/show_binlog_events.inc + if ($error) + { + --let $binlog_file=master-bin.000002 + --source include/show_binlog_events.inc + } + # Really drop the tables. The warnings will show what was dropped + --disable_warnings + --error 0, ER_DB_DROP_EXISTS + DROP DATABASE test2; + --enable_warnings + } + # We only need to test drops for all tables for the first crash point + let $drops=1; + } +} +drop database if exists test2; + +--enable_query_log diff --git a/mysql-test/suite/atomic/drop_db_long_names.opt b/mysql-test/suite/atomic/drop_db_long_names.opt new file mode 100644 index 00000000000..968c8f1a56a --- /dev/null +++ b/mysql-test/suite/atomic/drop_db_long_names.opt @@ -0,0 +1 @@ +--max-allowed-packet=1024 --net-buffer-length=1024 diff --git a/mysql-test/suite/atomic/drop_db_long_names.result b/mysql-test/suite/atomic/drop_db_long_names.result new file mode 100644 index 00000000000..415ce717bf7 --- /dev/null +++ b/mysql-test/suite/atomic/drop_db_long_names.result @@ -0,0 +1,11 @@ +"engine: aria crash point: ddl_log_drop_after_drop_tables position: 1" +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `tABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB`,`tACCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC`,`tADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD`,`tAEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE`,`tAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF`,`tAGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG`,`tAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH`,`tAIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII`,`tAJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ`,`tAKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK`,`tALLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `tABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBv`,`tACCCCCCCCCCCCCCCCCCCCCCCCCCCCCCv`,`tADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDv`,`tAEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEv`,`tAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFv`,`tAGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGv`,`tAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHv`,`tAIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIv`,`tAJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJv`,`tAKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKv` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `tAMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM`,`tANNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN`,`tAOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO`,`tAPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP`,`tAQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ`,`tARRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR`,`tASSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS`,`tATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT`,`tAUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU`,`tAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV`,`tAWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `tALLLLLLLLLLLLLLLLLLLLLLLLLLLLLLv`,`tAMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMv`,`tANNNNNNNNNNNNNNNNNNNNNNNNNNNNNNv`,`tAOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOv`,`tAPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPv`,`tAQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQv`,`tARRRRRRRRRRRRRRRRRRRRRRRRRRRRRRv`,`tASSSSSSSSSSSSSSSSSSSSSSSSSSSSSSv`,`tATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTv`,`tAUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUv`,`tAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVv` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `tAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX`,`tAYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY`,`tAZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ`,`tBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`,`tBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB`,`tBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC`,`tBDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD`,`tBEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE` /* generated by ddl log */ +master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `tAWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWv`,`tAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXv`,`tAYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYv`,`tAZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZv`,`tBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv`,`tBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBv`,`tBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCv`,`tBDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDv`,`tBEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEv` /* generated by ddl log */ +"engine: aria crash point: ddl_log_drop_before_binlog position: 1" +master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl log */ +Warnings: +Note 1008 Can't drop database 'test2'; database doesn't exist diff --git a/mysql-test/suite/atomic/drop_db_long_names.test b/mysql-test/suite/atomic/drop_db_long_names.test new file mode 100644 index 00000000000..c96e59fb4b9 --- /dev/null +++ b/mysql-test/suite/atomic/drop_db_long_names.test @@ -0,0 +1,108 @@ +--source include/have_debug.inc +--source include/have_log_bin.inc +--source include/not_valgrind.inc + +# +# Testing of atomic DROP DATABASE when the generated query could be too long +# + +let $engine_count=1; +let $engines='aria'; + +let $crash_count=2; +let $crash_points='ddl_log_drop_after_drop_tables','ddl_log_drop_before_binlog'; + +let $max_tables=30; + +let $old_debug=`select @@debug_dbug`; + +let $keep_include_silent=1; +let $grep_script=DROP; +--disable_query_log + +let $e=0; +while ($e < $engine_count) +{ + inc $e; + let $engine=`select ELT($e, $engines)`; + let $default_engine=$engine; + let $extra_option=; + + if ($engine == "aria") + { + let $extra_option=transactional=1; + } + if ($engine == "aria_notrans") + { + let $default_engine="aria"; + let $extra_option=transactional=0; + } + + let $c=0; + while ($c < $crash_count) + { + inc $c; + let $crash=`select ELT($c, $crash_points)`; + let $r=0; + while ($r < 1) + { + inc $r; + create database test2; + use test2; + --eval set @@default_storage_engine=$default_engine + let $t=0; + while ($t < $max_tables) + { + inc $t; + let $name=`select concat("t",char(floor(65+$t/26)),repeat(char(65+mod($t,26)),60))`; + let $view=`select concat("t",char(floor(65+$t/26)),repeat(char(65+mod($t,26)),30),'v')`; + --eval create table $name (a int not null) $extra_option + --eval create view $view as select * from $name + } + + flush tables; + use test; + + RESET MASTER; + + echo "engine: $engine crash point: $crash position: $r"; + --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect + --disable_reconnect + --eval set @@debug_dbug="+d,$crash",@debug_crash_counter=$r + let $errno=0; + --error 0,2013 + DROP DATABASE test2; + let $error=$errno; + --enable_reconnect + --source include/wait_until_connected_again.inc + --disable_query_log + --eval set @@debug_dbug="$old_debug" + + if ($error == 0) + { + echo "No crash!"; + } + use test; + # Check which tables still exists + --error 0,1 + --list_files $MYSQLD_DATADIR/test2 t* + --error 0,ER_SP_DOES_NOT_EXIST + + --let $binlog_file=master-bin.000001 + --source include/show_binlog_events.inc + if ($error) + { + --let $binlog_file=master-bin.000002 + --source include/show_binlog_events.inc + } + # Really drop the tables. The warnings will show what was dropped + --disable_warnings + --error 0, ER_DB_DROP_EXISTS + DROP DATABASE test2; + --enable_warnings + } + } +} +drop database if exists test2; + +--enable_query_log diff --git a/mysql-test/suite/atomic/drop_sequence.result b/mysql-test/suite/atomic/drop_sequence.result index 73c535cbda1..4e92659d112 100644 --- a/mysql-test/suite/atomic/drop_sequence.result +++ b/mysql-test/suite/atomic/drop_sequence.result @@ -1,104 +1,105 @@ call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal"); +create database test2; "engine: aria crash point: ddl_log_drop_before_delete_table position: 1" +ts.MAD +ts.MAI +ts.frm t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -ts.MAD -ts.MAI -ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_delete_table position: 2" ts.MAD ts.MAI ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_delete_table position: 3" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_delete_table position: 1" +ts.MAD +ts.MAI +ts.frm t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -ts.MAD -ts.MAI -ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_delete_table position: 2" ts.MAD ts.MAI ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_delete_table position: 3" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1" +ts.MAD +ts.MAI +ts.frm t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -ts.MAD -ts.MAI -ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger position: 2" ts.MAD ts.MAI ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger position: 3" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1" +ts.MAD +ts.MAI +ts.frm t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -ts.MAD -ts.MAI -ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 2" ts.MAD ts.MAI ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 3" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1" +ts.MAD +ts.MAI +ts.frm t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -ts.MAD -ts.MAI -ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_drop_trigger position: 2" ts.MAD ts.MAI ts.frm -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_drop_trigger position: 3" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_binlog position: 1" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_binlog position: 2" "No crash!" -master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */ +master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`test2`.`t2`,`ts` /* generated by server */ "engine: aria crash point: ddl_log_drop_before_binlog position: 3" "No crash!" -master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */ +master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`test2`.`t2`,`ts` /* generated by server */ "engine: aria crash point: ddl_log_drop_after_binlog position: 1" -master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */ +master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`test2`.`t2`,`ts` /* generated by server */ "engine: aria crash point: ddl_log_drop_after_binlog position: 2" "No crash!" -master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */ +master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`test2`.`t2`,`ts` /* generated by server */ "engine: aria crash point: ddl_log_drop_after_binlog position: 3" "No crash!" -master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */ +master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`test2`.`t2`,`ts` /* generated by server */ Warnings: -Note 1051 Unknown table 'test.t1,test.t2,test.ts' +Note 1051 Unknown table 'test.t1,test2.t2,test.ts' diff --git a/mysql-test/suite/atomic/drop_sequence.test b/mysql-test/suite/atomic/drop_sequence.test index b2fd60e8649..a7a398a1200 100644 --- a/mysql-test/suite/atomic/drop_sequence.test +++ b/mysql-test/suite/atomic/drop_sequence.test @@ -4,11 +4,14 @@ # # Testing of atomic drop with crashes in a lot of different places +# We also test having the tables in different databases # call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal"); let $MYSQLD_DATADIR= `SELECT @@datadir`; +create database test2; + let $engine_count=1; let $engines='aria'; @@ -53,10 +56,10 @@ while ($e < $engine_count) inc $r; --eval set @@default_storage_engine=$default_engine --eval create table t1 (a int not null) $extra_option; - --eval create table t2 (b int not null) $extra_option; + --eval create table test2.t2 (b int not null) $extra_option; create sequence ts; insert into t1 values(1); - insert into t2 values(2); + insert into test2.t2 values(2); flush tables; delimiter |; @@ -66,7 +69,7 @@ while ($e < $engine_count) set new.a:= 1000; end if; end| - create trigger t2_trg before insert on t2 for each row + create trigger test2.t2_trg before insert on test2.t2 for each row begin if isnull(new.b) then set new.b:= 2000; @@ -82,7 +85,7 @@ while ($e < $engine_count) --eval set @@debug_dbug="+d,$crash",@debug_crash_counter=$r let $errno=0; --error 0,2013 - drop table t1,t2,ts; + drop table t1,test2.t2,ts; let $error=$errno; --enable_reconnect --source include/wait_until_connected_again.inc @@ -95,6 +98,7 @@ while ($e < $engine_count) } # Check which tables still exists --list_files $MYSQLD_DATADIR/test t* + --list_files $MYSQLD_DATADIR/test2 t* --let $binlog_file=master-bin.000001 --source include/show_binlog_events.inc @@ -105,11 +109,11 @@ while ($e < $engine_count) } # Really drop the tables. The warnings will show what was dropped --disable_warnings - drop table if exists t1,t2,ts; + drop table if exists t1,test2.t2,ts; --enable_warnings } } } -drop table if exists t1,t2,ts; - +drop table if exists t1,test2.t2,ts; +drop database test2; --enable_query_log diff --git a/mysql-test/suite/atomic/drop_table.result b/mysql-test/suite/atomic/drop_table.result index 096323df8f2..210ec234cfa 100644 --- a/mysql-test/suite/atomic/drop_table.result +++ b/mysql-test/suite/atomic/drop_table.result @@ -5,47 +5,47 @@ t2.MYI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_before_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_after_delete_table position: 1" t2.MYD t2.MYI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_after_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_before_drop_trigger position: 1" t2.MYD t2.MYI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_before_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_before_drop_trigger2 position: 1" t2.MYD t2.MYI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_before_drop_trigger2 position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_after_drop_trigger position: 1" t2.MYD t2.MYI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_after_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_before_binlog position: 1" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: myisam crash point: ddl_log_drop_before_binlog position: 2" "No crash!" master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ @@ -60,47 +60,47 @@ t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_delete_table position: 1" t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1" t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1" t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1" t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_binlog position: 1" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_binlog position: 2" "No crash!" master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ @@ -115,47 +115,47 @@ t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_before_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_after_delete_table position: 1" t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_after_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger position: 1" t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger2 position: 1" t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger2 position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_after_drop_trigger position: 1" t2.MAD t2.MAI t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_after_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_before_binlog position: 1" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: aria_notrans crash point: ddl_log_drop_before_binlog position: 2" "No crash!" master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ @@ -169,43 +169,43 @@ t2.TRG t2.frm t2.ibd t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_before_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_after_delete_table position: 1" t2.TRG t2.frm t2.ibd t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_after_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_before_drop_trigger position: 1" t2.TRG t2.frm t2.ibd t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_before_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_before_drop_trigger2 position: 1" t2.TRG t2.frm t2.ibd t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_before_drop_trigger2 position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_after_drop_trigger position: 1" t2.TRG t2.frm t2.ibd t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_after_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_before_binlog position: 1" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: innodb crash point: ddl_log_drop_before_binlog position: 2" "No crash!" master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ @@ -220,47 +220,47 @@ t2.CSV t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_before_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_after_delete_table position: 1" t2.CSM t2.CSV t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_after_delete_table position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_before_drop_trigger position: 1" t2.CSM t2.CSV t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_before_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_before_drop_trigger2 position: 1" t2.CSM t2.CSV t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_before_drop_trigger2 position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_after_drop_trigger position: 1" t2.CSM t2.CSV t2.TRG t2.frm t2_trg.TRN -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_after_drop_trigger position: 2" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_before_binlog position: 1" -master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl log */ "engine: csv crash point: ddl_log_drop_before_binlog position: 2" "No crash!" master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ diff --git a/mysql-test/suite/atomic/drop_view.result b/mysql-test/suite/atomic/drop_view.result index dcc4ba4f3cf..6dad41389e8 100644 --- a/mysql-test/suite/atomic/drop_view.result +++ b/mysql-test/suite/atomic/drop_view.result @@ -1,15 +1,15 @@ "engine: aria crash point: ddl_log_drop_before_delete_view position: 1" v2.frm -master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_delete_view position: 2" -master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1`,`test`.`v2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1`,`v2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_delete_view position: 1" v2.frm -master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_after_delete_view position: 2" -master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1`,`test`.`v2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1`,`v2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_binlog position: 1" -master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1`,`test`.`v2` /* generated by ddl log */ +master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1`,`v2` /* generated by ddl log */ "engine: aria crash point: ddl_log_drop_before_binlog position: 2" "No crash!" master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2 diff --git a/sql/ddl_log.cc b/sql/ddl_log.cc index 81598a2bf9c..24168e5a7e1 100644 --- a/sql/ddl_log.cc +++ b/sql/ddl_log.cc @@ -27,6 +27,7 @@ #include "sql_view.h" // mysql_rename_view() #include "strfunc.h" // strconvert #include "sql_show.h" // append_identifier() +#include "sql_db.h" // drop_database_objects() #include <mysys_err.h> // EE_LINK @@ -86,13 +87,16 @@ const char *ddl_log_action_name[DDL_LOG_LAST_ACTION]= "partitioning replace", "partitioning exchange", "rename table", "rename view", "initialize drop table", "drop table", - "initialize drop view", "drop view", "drop trigger", + "drop view", "drop trigger", "drop db", }; /* Number of phases per entry */ const uchar ddl_log_entry_phases[DDL_LOG_LAST_ACTION]= { - 0, 1, 1, 2, 3, 4, 1, 1, 3, 1, 1, 1 + 0, 1, 1, 2, + (uchar) EXCH_PHASE_END, (uchar) DDL_RENAME_PHASE_END, 1, 1, + (uchar) DDL_DROP_PHASE_END, 1, 1, + (uchar) DDL_DROP_DB_PHASE_END }; @@ -109,8 +113,17 @@ struct st_global_ddl_log bool open; }; -st_global_ddl_log global_ddl_log; -String ddl_drop_query; // Used during startup recovery +/* The following structure is only used during startup recovery */ +class st_ddl_recovery { +public: + String drop_table; + String drop_view; + size_t drop_table_init_length, drop_view_init_length; + char current_db[NAME_LEN]; +}; + +static st_global_ddl_log global_ddl_log; +static st_ddl_recovery recovery_state; mysql_mutex_t LOCK_gdl; @@ -757,6 +770,8 @@ static bool ddl_log_increment_phase_no_lock(uint entry_pos) Ignore errors from the file system about: - Non existing tables or file (from drop table or delete file) - Error about tables files that already exists. + - Error from delete table (from Drop_table_error_handler) + - Wrong trigger definer (from Drop_table_error_handler) */ class ddl_log_error_handler : public Internal_error_handler @@ -764,8 +779,10 @@ class ddl_log_error_handler : public Internal_error_handler public: int handled_errors; int unhandled_errors; + int first_error; - ddl_log_error_handler() : handled_errors(0), unhandled_errors(0) + ddl_log_error_handler() : handled_errors(0), unhandled_errors(0), + first_error(0) {} bool handle_condition(THD *thd, @@ -776,11 +793,14 @@ public: Sql_condition ** cond_hdl) { *cond_hdl= NULL; - if (non_existing_table_error(sql_errno) || sql_errno == EE_LINK) + if (non_existing_table_error(sql_errno) || sql_errno == EE_LINK || + sql_errno == EE_DELETE || sql_errno == ER_TRG_NO_DEFINER) { handled_errors++; return TRUE; } + if (!first_error) + first_error= sql_errno; if (*level == Sql_condition::WARN_LEVEL_ERROR) unhandled_errors++; @@ -819,6 +839,77 @@ static bool build_filename_and_delete_tmp_file(char *path, size_t path_length, } +static LEX_CSTRING end_comment= +{ STRING_WITH_LEN(" /* generated by ddl log */")}; + + +/** + Log DROP query to binary log with comment + + This function is only run during recovery +*/ + +static void ddl_log_to_binary_log(THD *thd, String *query) +{ + LEX_CSTRING thd_db= thd->db; + + lex_string_set(&thd->db, recovery_state.current_db); + query->length(query->length()-1); // Removed end ',' + query->append(&end_comment); + mysql_mutex_unlock(&LOCK_gdl); + (void) thd->binlog_query(THD::STMT_QUERY_TYPE, + query->ptr(), query->length(), + TRUE, FALSE, FALSE, 0); + mysql_mutex_lock(&LOCK_gdl); + thd->db= thd_db; +} + + +/** + Log DROP TABLE/VIEW to binary log when needed + + @result 0 Nothing was done + @result 1 Query was logged to binary log & query was reset + + Logging happens in the following cases + - This is the last DROP entry + - The query could be longer than max_packet_length if we would add another + table name to the query + + When we log, we always log all found tables and views at the same time. This + is done to simply the exceute code as otherwise we would have to keep + information of what was logged. +*/ + +static bool ddl_log_drop_to_binary_log(THD *thd, DDL_LOG_ENTRY *ddl_log_entry, + String *query) +{ + DBUG_ENTER("ddl_log_binary_log"); + if (mysql_bin_log.is_open()) + { + if (!ddl_log_entry->next_entry || + query->length() + end_comment.length + NAME_LEN + 100 > + thd->variables.max_allowed_packet) + { + if (recovery_state.drop_table.length() > + recovery_state.drop_table_init_length) + { + ddl_log_to_binary_log(thd, &recovery_state.drop_table); + recovery_state.drop_table.length(recovery_state.drop_table_init_length); + } + if (recovery_state.drop_view.length() > + recovery_state.drop_view_init_length) + { + ddl_log_to_binary_log(thd, &recovery_state.drop_view); + recovery_state.drop_view.length(recovery_state.drop_view_init_length); + } + DBUG_RETURN(1); + } + } + DBUG_RETURN(0); +} + + /** Execute one action in a ddl log entry @@ -829,10 +920,6 @@ static bool build_filename_and_delete_tmp_file(char *path, size_t path_length, @retval FALSE Success */ -static LEX_CSTRING end_comment= -{ STRING_WITH_LEN(" /* generated by ddl log */")}; - - static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, DDL_LOG_ENTRY *ddl_log_entry) { @@ -848,10 +935,11 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, mysql_mutex_assert_owner(&LOCK_gdl); DBUG_PRINT("ddl_log", - ("entry type: %u action type: %u phase: %u next: %u " + ("entry type: %u action type: %u (%s) phase: %u next: %u " "handler: '%s' name: '%s' from_name: '%s' tmp_name: '%s'", (uint) ddl_log_entry->entry_type, (uint) ddl_log_entry->action_type, + ddl_log_action_name[ddl_log_entry->action_type], (uint) ddl_log_entry->phase, ddl_log_entry->next_entry, ddl_log_entry->handler_name.str, @@ -1147,17 +1235,32 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, (void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE); } break; - case DDL_LOG_DROP_TABLE_INIT_ACTION: + /* + Initialize variables for DROP TABLE and DROP VIEW + In normal cases a query only contains one action. However in case of + DROP DATABASE we may get a mix of both and we have to keep these + separate. + */ + case DDL_LOG_DROP_INIT_ACTION: { LEX_CSTRING *comment= &ddl_log_entry->tmp_name; - ddl_drop_query.length(0); - ddl_drop_query.set_charset(default_charset_info); - ddl_drop_query.append(STRING_WITH_LEN("DROP TABLE IF EXISTS ")); + recovery_state.drop_table.length(0); + recovery_state.drop_table.set_charset(default_charset_info); + recovery_state.drop_table.append(STRING_WITH_LEN("DROP TABLE IF EXISTS ")); if (comment->length) { - ddl_drop_query.append(comment); - ddl_drop_query.append(' '); + recovery_state.drop_table.append(comment); + recovery_state.drop_table.append(' '); } + recovery_state.drop_table_init_length= recovery_state.drop_table.length(); + + recovery_state.drop_view.length(0); + recovery_state.drop_view.set_charset(default_charset_info); + recovery_state.drop_view.append(STRING_WITH_LEN("DROP VIEW IF EXISTS ")); + recovery_state.drop_view_init_length= recovery_state.drop_view.length(); + + strmake(recovery_state.current_db, + ddl_log_entry->from_db.str, sizeof(recovery_state.current_db)-1); /* We don't increment phase as we want to retry this in case of crash */ break; } @@ -1200,37 +1303,31 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, (void) ddl_log_sync_no_lock(); /* Fall through */ - case DDL_DROP_PHASE_COLLECT: - append_identifier(thd, &ddl_drop_query, &db); - ddl_drop_query.append('.'); - append_identifier(thd, &ddl_drop_query, &table); - ddl_drop_query.append(','); + case DDL_DROP_PHASE_COLLECT: + if (strcmp(recovery_state.current_db, db.str)) + { + append_identifier(thd, &recovery_state.drop_table, &db); + recovery_state.drop_table.append('.'); + } + append_identifier(thd, &recovery_state.drop_table, &table); + recovery_state.drop_table.append(','); /* We don't increment phase as we want to retry this in case of crash */ - if (!ddl_log_entry->next_entry && mysql_bin_log.is_open()) + if (ddl_log_drop_to_binary_log(thd, ddl_log_entry, + &recovery_state.drop_table)) { - /* Last drop table. Write query to binlog */ - ddl_drop_query.length(ddl_drop_query.length()-1); - ddl_drop_query.append(&end_comment); - - mysql_mutex_unlock(&LOCK_gdl); - (void) thd->binlog_query(THD::STMT_QUERY_TYPE, ddl_drop_query.ptr(), - ddl_drop_query.length(), TRUE, FALSE, - FALSE, 0); - mysql_mutex_lock(&LOCK_gdl); + if (ddl_log_increment_phase_no_lock(entry_pos)) + break; } break; + case DDL_DROP_PHASE_RESET: + /* We have already logged all previous drop's. Clear the query */ + recovery_state.drop_table.length(recovery_state.drop_table_init_length); + recovery_state.drop_view.length(recovery_state.drop_view_init_length); + break; } break; } - case DDL_LOG_DROP_VIEW_INIT_ACTION: - { - ddl_drop_query.length(0); - ddl_drop_query.set_charset(default_charset_info); - ddl_drop_query.append(STRING_WITH_LEN("DROP VIEW IF EXISTS ")); - /* We don't increment phase as we want to retry this in case of crash */ - break; - } case DDL_LOG_DROP_VIEW_ACTION: { LEX_CSTRING db, table, path; @@ -1239,23 +1336,29 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, /* Note that for views path is WITH .frm extension */ path= ddl_log_entry->tmp_name; - mysql_file_delete(key_file_frm, path.str, MYF(MY_WME|MY_IGNORE_ENOENT)); - append_identifier(thd, &ddl_drop_query, &db); - ddl_drop_query.append('.'); - append_identifier(thd, &ddl_drop_query, &table); - ddl_drop_query.append(','); - - if (!ddl_log_entry->next_entry && mysql_bin_log.is_open()) + if (ddl_log_entry->phase == 0) { - /* Last drop view. Write query to binlog */ - ddl_drop_query.length(ddl_drop_query.length()-1); - ddl_drop_query.append(&end_comment); + mysql_file_delete(key_file_frm, path.str, MYF(MY_WME|MY_IGNORE_ENOENT)); + if (strcmp(recovery_state.current_db, db.str)) + { + append_identifier(thd, &recovery_state.drop_view, &db); + recovery_state.drop_view.append('.'); + } + append_identifier(thd, &recovery_state.drop_view, &table); + recovery_state.drop_view.append(','); - mysql_mutex_unlock(&LOCK_gdl); - (void) thd->binlog_query(THD::STMT_QUERY_TYPE, ddl_drop_query.ptr(), - ddl_drop_query.length(), TRUE, FALSE, - FALSE, 0); - mysql_mutex_lock(&LOCK_gdl); + if (ddl_log_drop_to_binary_log(thd, ddl_log_entry, + &recovery_state.drop_view)) + { + if (ddl_log_increment_phase_no_lock(entry_pos)) + break; + } + } + else + { + /* We have already logged all previous drop's. Clear the query */ + recovery_state.drop_table.length(recovery_state.drop_table_init_length); + recovery_state.drop_view.length(recovery_state.drop_table_init_length); } break; } @@ -1294,24 +1397,27 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, &ddl_log_entry->from_name, MYF(0)); - ddl_drop_query.length(0); - ddl_drop_query.set_charset(default_charset_info); + recovery_state.drop_table.length(0); + recovery_state.drop_table.set_charset(default_charset_info); if (ddl_log_entry->tmp_name.length) { /* We can use the original query */ - ddl_drop_query.append(&ddl_log_entry->tmp_name); + recovery_state.drop_table.append(&ddl_log_entry->tmp_name); } else { /* Generate new query */ - ddl_drop_query.append(STRING_WITH_LEN("DROP TRIGGER IF EXISTS ")); - append_identifier(thd, &ddl_drop_query, &ddl_log_entry->from_name); - ddl_drop_query.append(&end_comment); + recovery_state.drop_table.append(STRING_WITH_LEN("DROP TRIGGER IF " + "EXISTS ")); + append_identifier(thd, &recovery_state.drop_table, + &ddl_log_entry->from_name); + recovery_state.drop_table.append(&end_comment); } mysql_mutex_unlock(&LOCK_gdl); thd->db= ddl_log_entry->db; - (void) thd->binlog_query(THD::STMT_QUERY_TYPE, ddl_drop_query.ptr(), - ddl_drop_query.length(), TRUE, FALSE, + (void) thd->binlog_query(THD::STMT_QUERY_TYPE, + recovery_state.drop_table.ptr(), + recovery_state.drop_table.length(), TRUE, FALSE, FALSE, 0); thd->db= thd_db; mysql_mutex_lock(&LOCK_gdl); @@ -1319,6 +1425,45 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, (void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE); break; } + case DDL_LOG_DROP_DB_ACTION: + { + LEX_CSTRING db, path; + db= ddl_log_entry->db; + path= ddl_log_entry->tmp_name; + + switch (ddl_log_entry->phase) { + case DDL_DROP_DB_PHASE_INIT: + drop_database_objects(thd, &path, &db, + !my_strcasecmp(system_charset_info, + MYSQL_SCHEMA_NAME.str, db.str)); + + strxnmov(to_path, sizeof(to_path)-1, path.str, MY_DB_OPT_FILE, NullS); + mysql_file_delete_with_symlink(key_file_misc, to_path, "", MYF(0)); + + (void) rm_dir_w_symlink(path.str, 0); + if (ddl_log_increment_phase_no_lock(entry_pos)) + break; + /* Fall through */ + case DDL_DROP_DB_PHASE_LOG: + { + String *query= &recovery_state.drop_table; + + query->length(0); + query->append(STRING_WITH_LEN("DROP DATABASE IF EXISTS ")); + append_identifier(thd, query, &db); + query->append(&end_comment); + + mysql_mutex_unlock(&LOCK_gdl); + (void) thd->binlog_query(THD::STMT_QUERY_TYPE, + query->ptr(), query->length(), + TRUE, FALSE, FALSE, 0); + mysql_mutex_lock(&LOCK_gdl); + (void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE); + break; + } + } + break; + } default: DBUG_ASSERT(0); break; @@ -1326,7 +1471,8 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, end: delete file; - error= no_such_table_handler.unhandled_errors > 0; + if ((error= no_such_table_handler.unhandled_errors > 0)) + my_errno= no_such_table_handler.first_error; thd->pop_internal_handler(); DBUG_RETURN(error); } @@ -1446,9 +1592,10 @@ static bool ddl_log_execute_entry_no_lock(THD *thd, uint first_entry) action_type= 0; /* Write to error log and continue with next log entry */ - sql_print_error("Failed to execute action for entry %u of type '%s' " - "from ddl log", - read_entry, ddl_log_action_name[action_type]); + sql_print_error("Got error %d when trying to execute action for entry %u " + "of type '%s'", + (int) my_errno, read_entry, + ddl_log_action_name[action_type]); break; } read_entry= ddl_log_entry.next_entry; @@ -1482,7 +1629,6 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry, DDL_LOG_MEMORY_ENTRY **active_entry) { bool error; - uchar *pos, *end; DBUG_ENTER("ddl_log_write_entry"); *active_entry= 0; @@ -1500,20 +1646,18 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry, DBUG_RETURN(TRUE); error= FALSE; - pos= global_ddl_log.file_entry_buf + global_ddl_log.name_pos; - end= global_ddl_log.file_entry_buf + global_ddl_log.io_size; DBUG_PRINT("ddl_log", - ("type: %c next: %u handler: %s " - "to_name: '%s.%s' from_name: '%s.%s' " - "tmp_name: '%s'", - (char) global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS], + ("entry type: %u action type: %u (%s) phase: %u next: %u " + "handler: '%s' name: '%s' from_name: '%s' tmp_name: '%s'", + (uint) ddl_log_entry->entry_type, + (uint) ddl_log_entry->action_type, + ddl_log_action_name[ddl_log_entry->action_type], + (uint) ddl_log_entry->phase, ddl_log_entry->next_entry, - get_string(&pos, end).str, // Handler - get_string(&pos, end).str, // to db.table - get_string(&pos, end).str, - get_string(&pos, end).str, // From db.table - get_string(&pos, end).str, - get_string(&pos, end).str)); // Tmp name + ddl_log_entry->handler_name.str, + ddl_log_entry->name.str, + ddl_log_entry->from_name.str, + ddl_log_entry->tmp_name.str)); if (unlikely(write_ddl_log_file_entry((*active_entry)->entry_pos))) { @@ -1595,8 +1739,9 @@ bool ddl_log_write_execute_entry(uint first_entry, DBUG_RETURN(FALSE); } + /** - Increment phase for enty. Will deactivate entry after all phases are done + Increment phase for entry. Will deactivate entry after all phases are done @details see ddl_log_increment_phase_no_lock. @@ -1756,7 +1901,8 @@ int ddl_log_execute_recovery() } thd->thread_stack= (char*) &thd; thd->store_globals(); - ddl_drop_query.free(); + recovery_state.drop_table.free(); + recovery_state.drop_view.free(); thd->set_query(recover_query_string, strlen(recover_query_string)); @@ -1778,7 +1924,8 @@ int ddl_log_execute_recovery() } } } - ddl_drop_query.free(); + recovery_state.drop_table.free(); + recovery_state.drop_view.free(); close_ddl_log(); mysql_mutex_unlock(&LOCK_gdl); thd->reset_query(); @@ -1885,12 +2032,13 @@ void ddl_log_complete(DDL_LOG_STATE *state) ddl_log_disable_execute_entry(&state->execute_entry); ddl_log_release_entries(state); mysql_mutex_unlock(&LOCK_gdl); + state->list= 0; DBUG_VOID_RETURN; }; /** - Revert all entries in the ddl log + Revert (execute) all entries in the ddl log */ void ddl_log_revert(THD *thd, DDL_LOG_STATE *state) @@ -1908,6 +2056,7 @@ void ddl_log_revert(THD *thd, DDL_LOG_STATE *state) } ddl_log_release_entries(state); mysql_mutex_unlock(&LOCK_gdl); + state->list= 0; DBUG_VOID_RETURN; } @@ -2045,6 +2194,7 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, static bool ddl_log_drop_init(THD *thd, DDL_LOG_STATE *ddl_state, ddl_log_action_code action_code, + const LEX_CSTRING *db, const LEX_CSTRING *comment) { DDL_LOG_ENTRY ddl_log_entry; @@ -2053,26 +2203,26 @@ static bool ddl_log_drop_init(THD *thd, DDL_LOG_STATE *ddl_state, bzero(&ddl_log_entry, sizeof(ddl_log_entry)); ddl_log_entry.action_type= action_code; - ddl_log_entry.next_entry= 0; + ddl_log_entry.from_db= *const_cast<LEX_CSTRING*>(db); ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(comment); - ddl_log_entry.phase= 0; DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry)); } bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state, + const LEX_CSTRING *db, const LEX_CSTRING *comment) { - return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_TABLE_INIT_ACTION, - comment); + return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_INIT_ACTION, + db, comment); } -bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state) +bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state, + const LEX_CSTRING *db) { - LEX_CSTRING comment= {0,0}; - return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_VIEW_INIT_ACTION, - &comment); + return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_INIT_ACTION, + db, &empty_clex_str); } static bool ddl_log_drop(THD *thd, DDL_LOG_STATE *ddl_state, @@ -2157,7 +2307,7 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state, char path[FN_REFLEN+1]; off_t frm_length= 0; size_t max_query_length; - DBUG_ENTER("ddl_log_drop"); + DBUG_ENTER("ddl_log_drop_trigger"); build_table_filename(path, sizeof(path)-1, db->str, table->str, TRG_EXT, 0); @@ -2184,3 +2334,27 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state, DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry)); } + + +/** + Log DROP DATABASE + + This is logged after all DROP TABLE's for the database. + As now know we are going to log DROP DATABASE to the binary log, we want + to ignore want to ignore all preceding DROP TABLE entries. We do that by + linking this entry directly after the execute entry and forgetting the + link to the previous entries (not setting ddl_log_entry.next_entry) +*/ + +bool ddl_log_drop_db(THD *thd, DDL_LOG_STATE *ddl_state, + const LEX_CSTRING *db, const LEX_CSTRING *path) +{ + DDL_LOG_ENTRY ddl_log_entry; + DBUG_ENTER("ddl_log_drop_db"); + + bzero(&ddl_log_entry, sizeof(ddl_log_entry)); + ddl_log_entry.action_type= DDL_LOG_DROP_DB_ACTION; + ddl_log_entry.db= *const_cast<LEX_CSTRING*>(db); + ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(path); + DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry)); +} diff --git a/sql/ddl_log.h b/sql/ddl_log.h index 2f36431d9b5..b8e2c3fc91d 100644 --- a/sql/ddl_log.h +++ b/sql/ddl_log.h @@ -78,11 +78,11 @@ enum ddl_log_action_code */ DDL_LOG_RENAME_TABLE_ACTION= 5, DDL_LOG_RENAME_VIEW_ACTION= 6, - DDL_LOG_DROP_TABLE_INIT_ACTION= 7, + DDL_LOG_DROP_INIT_ACTION= 7, DDL_LOG_DROP_TABLE_ACTION= 8, - DDL_LOG_DROP_VIEW_INIT_ACTION= 9, - DDL_LOG_DROP_VIEW_ACTION= 10, - DDL_LOG_DROP_TRIGGER_ACTION= 11, + DDL_LOG_DROP_VIEW_ACTION= 9, + DDL_LOG_DROP_TRIGGER_ACTION= 10, + DDL_LOG_DROP_DB_ACTION=11, DDL_LOG_LAST_ACTION /* End marker */ }; @@ -94,13 +94,15 @@ extern const uchar ddl_log_entry_phases[DDL_LOG_LAST_ACTION]; enum enum_ddl_log_exchange_phase { EXCH_PHASE_NAME_TO_TEMP= 0, EXCH_PHASE_FROM_TO_NAME= 1, - EXCH_PHASE_TEMP_TO_FROM= 2 + EXCH_PHASE_TEMP_TO_FROM= 2, + EXCH_PHASE_END }; enum enum_ddl_log_rename_table_phase { DDL_RENAME_PHASE_TRIGGER= 0, DDL_RENAME_PHASE_STAT, DDL_RENAME_PHASE_TABLE, + DDL_RENAME_PHASE_END }; enum enum_ddl_log_drop_table_phase { @@ -111,6 +113,12 @@ enum enum_ddl_log_drop_table_phase { DDL_DROP_PHASE_END }; +enum enum_ddl_log_drop_db_phase { + DDL_DROP_DB_PHASE_INIT=0, + DDL_DROP_DB_PHASE_LOG, + DDL_DROP_DB_PHASE_END +}; + /* Setting ddl_log_entry.phase to this has the same effect as setting action_type to DDL_IGNORE_LOG_ENTRY_CODE @@ -199,8 +207,10 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *new_db, const LEX_CSTRING *new_alias); bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state, + const LEX_CSTRING *db, const LEX_CSTRING *comment); -bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state); +bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state, + const LEX_CSTRING *db); bool ddl_log_drop_table(THD *thd, DDL_LOG_STATE *ddl_state, handlerton *hton, const LEX_CSTRING *path, @@ -215,5 +225,13 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *table, const LEX_CSTRING *trigger_name, const LEX_CSTRING *query); +bool ddl_log_drop_view(THD *thd, DDL_LOG_STATE *ddl_state, + const LEX_CSTRING *path, + const LEX_CSTRING *db, + const LEX_CSTRING *table); +bool ddl_log_drop_view(THD *thd, DDL_LOG_STATE *ddl_state, + const LEX_CSTRING *db); +bool ddl_log_drop_db(THD *thd, DDL_LOG_STATE *ddl_state, + const LEX_CSTRING *db, const LEX_CSTRING *path); extern mysql_mutex_t LOCK_gdl; #endif /* DDL_LOG_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index 13616d0b949..1a8f9d2d96f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -837,9 +837,10 @@ static my_bool dropdb_handlerton(THD *unused1, plugin_ref plugin, } -void ha_drop_database(char* path) +void ha_drop_database(const char* path) { - plugin_foreach(NULL, dropdb_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, path); + plugin_foreach(NULL, dropdb_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, + (char*) path); } diff --git a/sql/handler.h b/sql/handler.h index 76a8ad82dd1..12f36b7a4e1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -5110,7 +5110,7 @@ int ha_panic(enum ha_panic_function flag); void ha_close_connection(THD* thd); void ha_kill_query(THD* thd, enum thd_kill_levels level); bool ha_flush_logs(); -void ha_drop_database(char* path); +void ha_drop_database(const char* path); void ha_checkpoint_state(bool disable); void ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *)); int ha_create_table(THD *thd, const char *path, diff --git a/sql/sql_db.cc b/sql/sql_db.cc index fe95b54cbc9..278ec83fa41 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -40,6 +40,7 @@ #include "events.h" #include "sql_handler.h" #include "sql_statistics.h" +#include "ddl_log.h" // ddl_log functions #include <my_dir.h> #include <m_ctype.h> #include "log.h" @@ -58,7 +59,7 @@ static bool find_db_tables_and_rm_known_files(THD *, MY_DIR *, const char *, const char *, TABLE_LIST **); long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path); -static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error); +my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error); static void mysql_change_db_impl(THD *thd, LEX_CSTRING *new_db_name, privilege_t new_db_access, @@ -952,6 +953,56 @@ bool mysql_alter_db(THD *thd, const LEX_CSTRING *db, /** + Drop database objects + + @param thd THD object + @param path Path to database (for ha_drop_database) + @param db Normalized database name + @param rm_mysql_schema If the schema is 'mysql', in which case we don't + log the query to binary log or delete related + routines or events. +*/ + +void drop_database_objects(THD *thd, const LEX_CSTRING *path, + const LEX_CSTRING *db, + bool rm_mysql_schema) +{ + debug_crash_here("ddl_log_drop_before_ha_drop_database"); + + ha_drop_database(path->str); + + /* + We temporarily disable the binary log while dropping the objects + in the database. Since the DROP DATABASE statement is always + replicated as a statement, execution of it will drop all objects + in the database on the slave as well, so there is no need to + replicate the removal of the individual objects in the database + as well. + + This is more of a safety precaution, since normally no objects + should be dropped while the database is being cleaned, but in + the event that a change in the code to remove other objects is + made, these drops should still not be logged. + */ + + debug_crash_here("ddl_log_drop_before_drop_db_routines"); + + query_cache_invalidate1(thd, db->str); + + if (!rm_mysql_schema) + { + tmp_disable_binlog(thd); + (void) sp_drop_db_routines(thd, db->str); /* @todo Do not ignore errors */ +#ifdef HAVE_EVENT_SCHEDULER + Events::drop_schema_events(thd, db->str); +#endif + reenable_binlog(thd); + } + debug_crash_here("ddl_log_drop_after_drop_db_routines"); +} + + +/** Drop all tables, routines and events in a database and the database itself. @param thd Thread handle @@ -967,41 +1018,31 @@ bool mysql_alter_db(THD *thd, const LEX_CSTRING *db, */ static bool -mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silent) +mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, + bool silent) { ulong deleted_tables= 0; bool error= true, rm_mysql_schema; char path[FN_REFLEN + 16]; MY_DIR *dirp; - uint length; + uint path_length; TABLE_LIST *tables= NULL; TABLE_LIST *table; + DDL_LOG_STATE ddl_log_state; Drop_table_error_handler err_handler; + LEX_CSTRING rm_db; + char db_tmp[SAFE_NAME_LEN+1]; + const char *dbnorm; DBUG_ENTER("mysql_rm_db"); - char db_tmp[SAFE_NAME_LEN+1]; - const char *dbnorm= normalize_db_name(db->str, db_tmp, sizeof(db_tmp)); + dbnorm= normalize_db_name(db->str, db_tmp, sizeof(db_tmp)); + lex_string_set(&rm_db, dbnorm); + bzero(&ddl_log_state, sizeof(ddl_log_state)); if (lock_schema_name(thd, dbnorm)) DBUG_RETURN(true); - length= build_table_filename(path, sizeof(path) - 1, db->str, "", "", 0); - strmov(path+length, MY_DB_OPT_FILE); // Append db option file name - del_dbopt(path); // Remove dboption hash entry - /* - Now remove the db.opt file. - The 'find_db_tables_and_rm_known_files' doesn't remove this file - if there exists a table with the name 'db', so let's just do it - separately. We know this file exists and needs to be deleted anyway. - */ - if (mysql_file_delete_with_symlink(key_file_misc, path, "", MYF(0)) && - my_errno != ENOENT) - { - my_error(EE_DELETE, MYF(0), path, my_errno); - DBUG_RETURN(true); - } - - path[length]= '\0'; // Remove file name + path_length= build_table_filename(path, sizeof(path) - 1, db->str, "", "", 0); /* See if the directory exists */ if (!(dirp= my_dir(path,MYF(MY_DONT_SORT)))) @@ -1052,7 +1093,10 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen } } - /* mysql_ha_rm_tables() requires a non-null TABLE_LIST. */ + /* + Close active HANDLER's for tables in the database. + Note that mysql_ha_rm_tables() requires a non-null TABLE_LIST. + */ if (tables) mysql_ha_rm_tables(thd, tables); @@ -1062,41 +1106,45 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen thd->push_internal_handler(&err_handler); if (!thd->killed && !(tables && - mysql_rm_table_no_locks(thd, tables, true, false, true, false, true, - false))) + mysql_rm_table_no_locks(thd, tables, &rm_db, &ddl_log_state, true, false, + true, false, true, false))) { + debug_crash_here("ddl_log_drop_after_drop_tables"); + + LEX_CSTRING cpath{ path, path_length}; + ddl_log_drop_db(thd, &ddl_log_state, &rm_db, &cpath); + + drop_database_objects(thd, &cpath, &rm_db, rm_mysql_schema); + /* - We temporarily disable the binary log while dropping the objects - in the database. Since the DROP DATABASE statement is always - replicated as a statement, execution of it will drop all objects - in the database on the slave as well, so there is no need to - replicate the removal of the individual objects in the database - as well. - - This is more of a safety precaution, since normally no objects - should be dropped while the database is being cleaned, but in - the event that a change in the code to remove other objects is - made, these drops should still not be logged. + Now remove the db.opt file. + The 'find_db_tables_and_rm_known_files' doesn't remove this file + if there exists a table with the name 'db', so let's just do it + separately. We know this file exists and needs to be deleted anyway. */ - - ha_drop_database(path); - tmp_disable_binlog(thd); - query_cache_invalidate1(thd, dbnorm); - if (!rm_mysql_schema) + debug_crash_here("ddl_log_drop_before_drop_option_file"); + strmov(path+path_length, MY_DB_OPT_FILE); // Append db option file name + if (mysql_file_delete_with_symlink(key_file_misc, path, "", MYF(0)) && + my_errno != ENOENT) { - (void) sp_drop_db_routines(thd, dbnorm); /* @todo Do not ignore errors */ -#ifdef HAVE_EVENT_SCHEDULER - Events::drop_schema_events(thd, dbnorm); -#endif + thd->pop_internal_handler(); + my_error(EE_DELETE, MYF(0), path, my_errno); + error= true; + ddl_log_complete(&ddl_log_state); + goto end; } - reenable_binlog(thd); + del_dbopt(path); // Remove dboption hash entry + path[path_length]= '\0'; // Remove file name /* If the directory is a symbolic link, remove the link first, then remove the directory the symbolic link pointed at */ + debug_crash_here("ddl_log_drop_before_drop_dir"); error= rm_dir_w_symlink(path, true); + debug_crash_here("ddl_log_drop_after_drop_dir"); } + thd->pop_internal_handler(); update_binlog: @@ -1112,6 +1160,7 @@ update_binlog: if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, TRUE); + int res; Query_log_event qinfo(thd, query, query_length, FALSE, TRUE, /* suppress_use */ TRUE, errcode); /* @@ -1126,7 +1175,14 @@ update_binlog: These DDL methods and logging are protected with the exclusive metadata lock on the schema. */ - if (mysql_bin_log.write(&qinfo)) + debug_crash_here("ddl_log_drop_before_binlog"); + thd->binlog_xid= thd->query_id; + ddl_log_update_xid(&ddl_log_state, thd->binlog_xid); + res= mysql_bin_log.write(&qinfo); + thd->binlog_xid= 0; + debug_crash_here("ddl_log_drop_after_binlog"); + + if (res) { error= true; goto exit; @@ -1176,13 +1232,21 @@ update_binlog: *query_pos++ = ','; } - if (query_pos != query_data_start) + if (query_pos != query_data_start) // If database was not empty { + int res; /* These DDL methods and logging are protected with the exclusive metadata lock on the schema. */ - if (write_to_binlog(thd, query, (uint)(query_pos -1 - query), db->str, db->length)) + debug_crash_here("ddl_log_drop_before_binlog"); + thd->binlog_xid= thd->query_id; + ddl_log_update_xid(&ddl_log_state, thd->binlog_xid); + res= write_to_binlog(thd, query, (uint)(query_pos -1 - query), db->str, + db->length); + thd->binlog_xid= 0; + debug_crash_here("ddl_log_drop_after_binlog"); + if (res) { error= true; goto exit; @@ -1191,6 +1255,7 @@ update_binlog: } exit: + ddl_log_complete(&ddl_log_state); /* If this database was the client's selected database, we silently change the client's selected database to nothing (to have an empty @@ -1202,6 +1267,7 @@ exit: mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server); thd->session_tracker.current_schema.mark_as_changed(thd); } +end: my_dirend(dirp); DBUG_RETURN(error); } @@ -1332,22 +1398,24 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp, 1 ERROR */ -static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error) +my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error) { char tmp_path[FN_REFLEN], *pos; char *path= tmp_path; DBUG_ENTER("rm_dir_w_symlink"); unpack_filename(tmp_path, org_path); -#ifdef HAVE_READLINK - int error; - char tmp2_path[FN_REFLEN]; - /* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */ + /* Remove end FN_LIBCHAR as this causes problem on Linux and OS/2 */ pos= strend(path); if (pos > path && pos[-1] == FN_LIBCHAR) *--pos=0; - if (unlikely((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0)) +#ifdef HAVE_READLINK + int error; + char tmp2_path[FN_REFLEN]; + + if (unlikely((error= my_readlink(tmp2_path, path, + MYF(send_error ? MY_WME : 0))) < 0)) DBUG_RETURN(1); if (likely(!error)) { @@ -1359,11 +1427,7 @@ static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error) path= tmp2_path; } #endif - /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */ - pos= strend(path); - if (pos > path && pos[-1] == FN_LIBCHAR) - *--pos=0; if (unlikely(my_rmdir(path) < 0 && send_error)) { my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno); diff --git a/sql/sql_db.h b/sql/sql_db.h index c9f1ed068e6..3c037d668e0 100644 --- a/sql/sql_db.h +++ b/sql/sql_db.h @@ -47,6 +47,10 @@ void my_dbopt_cleanup(void); const char *normalize_db_name(const char *db, char *buffer, size_t buffer_size); +void drop_database_objects(THD *thd, const LEX_CSTRING *path, + const LEX_CSTRING *db, + bool rm_mysql_schema); +my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error); #define MY_DB_OPT_FILE "db.opt" #endif /* SQL_DB_INCLUDED */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 99b5e299077..f201e62a4a9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1039,7 +1039,9 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists, /* mark for close and remove all cached entries */ thd->push_internal_handler(&err_handler); - error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary, + error= mysql_rm_table_no_locks(thd, tables, &thd->db, (DDL_LOG_STATE*) 0, + if_exists, + drop_temporary, false, drop_sequence, dont_log_query, false); thd->pop_internal_handler(); @@ -1100,6 +1102,11 @@ static uint32 comment_length(THD *thd, uint32 comment_pos, @param thd Thread handler @param tables Tables to drop + @param current_db Current database, used for ddl logs + @param ddl_log_state DDL log state, for global ddl logging (used by + DROP DATABASE. If not set, an internal ddl log state + will be used. If set then the caller must call + ddl_log_complete(ddl_log_state); @param if_exists If set, don't give an error if table doesn't exists. In this case we give an warning of level 'NOTE' @param drop_temporary Only drop temporary tables @@ -1128,7 +1135,10 @@ static uint32 comment_length(THD *thd, uint32 comment_pos, not all. */ -int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, +int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, + const LEX_CSTRING *current_db, + DDL_LOG_STATE *ddl_log_state, + bool if_exists, bool drop_temporary, bool drop_view, bool drop_sequence, bool dont_log_query, @@ -1138,7 +1148,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, char path[FN_REFLEN + 1]; LEX_CSTRING alias= null_clex_str; StringBuffer<160> unknown_tables(system_charset_info); - DDL_LOG_STATE ddl_log_state; + DDL_LOG_STATE local_ddl_log_state; const char *comment_start; uint32 comment_len; uint not_found_errors= 0, first_table= 0; @@ -1156,6 +1166,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, String built_trans_tmp_query, built_non_trans_tmp_query; DBUG_ENTER("mysql_rm_table_no_locks"); + if (!ddl_log_state) + { + ddl_log_state= &local_ddl_log_state; + bzero(ddl_log_state, sizeof(*ddl_log_state)); + } + unknown_tables.length(0); comment_len= comment_length(thd, if_exists ? 17:9, &comment_start); @@ -1210,14 +1226,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, built_non_trans_tmp_query.set_charset(system_charset_info); built_non_trans_tmp_query.copy(built_trans_tmp_query); } - bzero(&ddl_log_state, sizeof(ddl_log_state)); for (table= tables; table; table= table->next_local) { bool is_trans= 0, temporary_table_was_dropped= 0; bool table_creation_was_logged= 0; bool local_non_tmp_error= 0, wrong_drop_sequence= 0; - bool table_dropped= 0; + bool table_dropped= 0, res; const LEX_CSTRING db= table->db; const LEX_CSTRING table_name= table->table_name; LEX_CSTRING cpath= {0,0}; @@ -1377,7 +1392,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (!first_table++) { LEX_CSTRING comment= {comment_start, (size_t) comment_len}; - if (ddl_log_drop_table_init(thd, &ddl_log_state, &comment)) + if (ddl_log_drop_table_init(thd, ddl_log_state, current_db, &comment)) { error= 1; goto err; @@ -1436,12 +1451,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, bool enoent_warning= !dont_log_query && !(hton && hton->discover_table); - if (ddl_log_drop_table(thd, &ddl_log_state, hton, &cpath, &db, - &table_name)) + if (was_view) + res= ddl_log_drop_view(thd, ddl_log_state, &cpath, &db, + &table_name); + else + res= ddl_log_drop_table(thd, ddl_log_state, hton, &cpath, &db, + &table_name); + if (res) { - error= -1; - goto err; + error= -1; + goto err; } + debug_crash_here("ddl_log_drop_before_delete_table"); error= ha_delete_table(thd, hton, path, &db, &table_name, enoent_warning); @@ -1513,7 +1534,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, int ferror= 0; DBUG_ASSERT(!was_view); - if (ddl_log_drop_table(thd, &ddl_log_state, hton, &cpath, &db, + if (ddl_log_drop_table(thd, ddl_log_state, 0, &cpath, &db, &table_name)) { error= -1; @@ -1553,9 +1574,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (thd->replication_flags & OPTION_IF_EXISTS) log_if_exists= 1; - debug_crash_here("ddl_log_drop_before_drop_trigger"); - ddl_log_update_phase(&ddl_log_state, DDL_DROP_PHASE_TRIGGER); - debug_crash_here("ddl_log_drop_before_drop_trigger2"); + if (!was_view) + { + debug_crash_here("ddl_log_drop_before_drop_trigger"); + ddl_log_update_phase(ddl_log_state, DDL_DROP_PHASE_TRIGGER); + debug_crash_here("ddl_log_drop_before_drop_trigger2"); + } if (likely(!error) || non_existing_table_error(error)) { @@ -1620,7 +1644,8 @@ report_error: table_name.str, (uint)table_name.length); mysql_audit_drop_table(thd, table); } - ddl_log_update_phase(&ddl_log_state, DDL_DROP_PHASE_COLLECT); + if (!was_view) + ddl_log_update_phase(ddl_log_state, DDL_DROP_PHASE_COLLECT); if (!dont_log_query && (!error || table_dropped || non_existing_table_error(error))) @@ -1726,7 +1751,7 @@ err: built_query.append(generated_by_server); int error_code = non_tmp_error ? thd->get_stmt_da()->sql_errno() : 0; thd->binlog_xid= thd->query_id; - ddl_log_update_xid(&ddl_log_state, thd->binlog_xid); + ddl_log_update_xid(ddl_log_state, thd->binlog_xid); error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, built_query.ptr(), built_query.length(), @@ -1737,7 +1762,8 @@ err: debug_crash_here("ddl_log_drop_after_binlog"); } } - ddl_log_complete(&ddl_log_state); + if (ddl_log_state == &local_ddl_log_state) + ddl_log_complete(ddl_log_state); if (!drop_temporary) { @@ -4217,7 +4243,9 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db, */ (void) trans_rollback_stmt(thd); /* Remove normal table without logging. Keep tables locked */ - if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 0, 1, 1)) + if (mysql_rm_table_no_locks(thd, &table_list, &thd->db, + (DDL_LOG_STATE*) 0, + 0, 0, 0, 0, 1, 1)) goto err; /* @@ -4435,7 +4463,9 @@ int mysql_create_table_no_lock(THD *thd, const LEX_CSTRING *db, { DBUG_ASSERT(thd->is_error()); /* Drop the table as it wasn't completely done */ - if (!mysql_rm_table_no_locks(thd, table_list, 1, + if (!mysql_rm_table_no_locks(thd, table_list, &thd->db, + (DDL_LOG_STATE*) 0, + 1, create_info->tmp_table(), false, true /* Sequence*/, true /* Don't log_query */, diff --git a/sql/sql_table.h b/sql/sql_table.h index a1661086ce5..7ac5cc90f04 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -37,6 +37,7 @@ typedef struct st_key KEY; typedef struct st_key_cache KEY_CACHE; typedef struct st_lock_param_type ALTER_PARTITION_PARAM_TYPE; typedef struct st_order ORDER; +typedef struct st_ddl_log_state DDL_LOG_STATE; enum enum_explain_filename_mode { @@ -177,7 +178,10 @@ bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list, bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists, bool drop_temporary, bool drop_sequence, bool dont_log_query); -int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, +int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, + const LEX_CSTRING *db, + DDL_LOG_STATE *ddl_log_state, + bool if_exists, bool drop_temporary, bool drop_view, bool drop_sequence, bool dont_log_query, bool dont_free_locks); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 8c9bc35e538..5cd8ad07c58 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1870,7 +1870,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) } if (!first_table++) { - if (ddl_log_drop_view_init(thd, &ddl_log_state)) + if (ddl_log_drop_view_init(thd, &ddl_log_state, &thd->db)) DBUG_RETURN(TRUE); } if (ddl_log_drop_view(thd, &ddl_log_state, &cpath, &view->db, |