summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2020-12-20 17:44:11 +0200
committerMonty <monty@mariadb.org>2021-02-16 16:12:38 +0200
commit7d530f2154e5b4cd78e49232c0818c4fa63b99be (patch)
tree112308446f0ea2db1ed04c9e48fe8e9e8b770360
parente04717242883509a03846ba3d69ee19092e63ee1 (diff)
downloadmariadb-git-7d530f2154e5b4cd78e49232c0818c4fa63b99be.tar.gz
MDEV-24408 Atomic DROP DATABASE
Description of how DROP DATABASE works after this patch - Collect list of tables - DDL log tables as they are dropped - DDL log drop database - Delete db.opt - Delete data directory - Log either DROP TABLE or DROP DATABASE to binary log - De active ddl log entry This is in line of how things where before (minus ddl logging) except that we delete db.opt file last to not loose it if DROP DATABASE fails. On recovery we have to ensure that all dropped tables are logged in binary log and that they are properly dropped (as with atomic drop table). No new tables be dropped as part of recovery. Recovery of active drop database ddl log entry: - If drop database was logged to ddl log but was not found in the binary log: - drop the db.opt file and database directory. - Log DROP DATABASE to binary log - If drop database was not logged to ddl log - Update binary log with DROP TABLE of the dropped tables. If table list is longer than max_allowed_packet, then the query will be split into multiple DROP TABLE/VIEW queries. Other things: - Added DDL_LOG_STATE and 'current database' as arguments to mysql_rm_table_no_locks(). This was needed to be able to combine ddl logging of DROP DATABASE and DROP TABLE and make the generated DROP TABLE statements shorter. - To make the DROP TABLE statement created by ddl log shorter, I changed the binlogged query to use current directory and omit the directory part for all tables in the current directory. - Merged some DROP TABLE and DROP VIEW code in ddl logger. This was done to be able get separate DROP VIEW and DROP TABLE statements in the binary log. - Added a 'recovery_state' variable to remember the state of dropped tables and views. - Moved out code that drops database objects (stored procedures) from mysql_rm_db_internal() to drop_database_objects() for better code reuse. - Made mysql_rm_db_internal() global so that could be used by the ddl recovery code.
-rw-r--r--mysql-test/suite/atomic/drop_db.result95
-rw-r--r--mysql-test/suite/atomic/drop_db.test112
-rw-r--r--mysql-test/suite/atomic/drop_db_long_names.opt1
-rw-r--r--mysql-test/suite/atomic/drop_db_long_names.result11
-rw-r--r--mysql-test/suite/atomic/drop_db_long_names.test108
-rw-r--r--mysql-test/suite/atomic/drop_sequence.result75
-rw-r--r--mysql-test/suite/atomic/drop_sequence.test18
-rw-r--r--mysql-test/suite/atomic/drop_table.result110
-rw-r--r--mysql-test/suite/atomic/drop_view.result10
-rw-r--r--sql/ddl_log.cc360
-rw-r--r--sql/ddl_log.h30
-rw-r--r--sql/handler.cc5
-rw-r--r--sql/handler.h2
-rw-r--r--sql/sql_db.cc182
-rw-r--r--sql/sql_db.h4
-rw-r--r--sql/sql_table.cc68
-rw-r--r--sql/sql_table.h6
-rw-r--r--sql/sql_view.cc2
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,