Commit 7a588c30 authored by Monty's avatar Monty Committed by Sergei Golubchik

MDEV-24408 Crash-safe 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.
parent 407e9b78
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 recovery */
"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 recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl recovery */
"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 recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl recovery */
"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 recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl recovery */
"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 recovery */
"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 recovery */
"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 recovery */
"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 recovery */
"engine: aria crash point: ddl_log_drop_before_drop_dir position: 1"
master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_dir position: 1"
master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 1"
master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl recovery */
"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 recovery */
"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 recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl recovery */
"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 recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl recovery */
"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 recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `t1v` /* generated by ddl recovery */
"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 recovery */
"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 recovery */
"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 recovery */
"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 recovery */
"engine: innodb crash point: ddl_log_drop_before_drop_dir position: 1"
master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_after_drop_dir position: 1"
master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_before_binlog position: 1"
master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl recovery */
"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
--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
--max-allowed-packet=1024 --net-buffer-length=1024
"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 recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `tABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBv`,`tACCCCCCCCCCCCCCCCCCCCCCCCCCCCCCv`,`tADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDv`,`tAEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEv`,`tAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFv`,`tAGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGv`,`tAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHv`,`tAIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIv`,`tAJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJv`,`tAKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKv` /* generated by ddl recovery */
master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `tAMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM`,`tANNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN`,`tAOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO`,`tAPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP`,`tAQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ`,`tARRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR`,`tASSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS`,`tATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT`,`tAUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU`,`tAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV`,`tAWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW` /* generated by ddl recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `tALLLLLLLLLLLLLLLLLLLLLLLLLLLLLLv`,`tAMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMv`,`tANNNNNNNNNNNNNNNNNNNNNNNNNNNNNNv`,`tAOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOv`,`tAPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPv`,`tAQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQv`,`tARRRRRRRRRRRRRRRRRRRRRRRRRRRRRRv`,`tASSSSSSSSSSSSSSSSSSSSSSSSSSSSSSv`,`tATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTv`,`tAUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUv`,`tAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVv` /* generated by ddl recovery */
master-bin.000002 # Query # # use `test2`; DROP TABLE IF EXISTS `tAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX`,`tAYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY`,`tAZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ`,`tBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`,`tBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB`,`tBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC`,`tBDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD`,`tBEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE` /* generated by ddl recovery */
master-bin.000002 # Query # # use `test2`; DROP VIEW IF EXISTS `tAWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWv`,`tAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXv`,`tAYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYv`,`tAZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZv`,`tBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv`,`tBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBv`,`tBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCv`,`tBDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDv`,`tBEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEv` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 1"
master-bin.000002 # Query # # DROP DATABASE IF EXISTS `test2` /* generated by ddl recovery */
Warnings:
Note 1008 Can't drop database 'test2'; database doesn't exist
--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
call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal"); 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" "engine: aria crash point: ddl_log_drop_before_delete_table position: 1"
ts.MAD
ts.MAI
ts.frm
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
ts.MAD master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_delete_table position: 2" "engine: aria crash point: ddl_log_drop_before_delete_table position: 2"
ts.MAD ts.MAD
ts.MAI ts.MAI
ts.frm ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_delete_table position: 3" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 1" "engine: aria crash point: ddl_log_drop_after_delete_table position: 1"
ts.MAD
ts.MAI
ts.frm
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
ts.MAD master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 2" "engine: aria crash point: ddl_log_drop_after_delete_table position: 2"
ts.MAD ts.MAD
ts.MAI ts.MAI
ts.frm ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 3" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1" "engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1"
ts.MAD
ts.MAI
ts.frm
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
ts.MAD master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 2" "engine: aria crash point: ddl_log_drop_before_drop_trigger position: 2"
ts.MAD ts.MAD
ts.MAI ts.MAI
ts.frm ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 3" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1" "engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1"
ts.MAD
ts.MAI
ts.frm
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
ts.MAD master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 2" "engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 2"
ts.MAD ts.MAD
ts.MAI ts.MAI
ts.frm ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 3" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1" "engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1"
ts.MAD
ts.MAI
ts.frm
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
ts.MAD master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 2" "engine: aria crash point: ddl_log_drop_after_drop_trigger position: 2"
ts.MAD ts.MAD
ts.MAI ts.MAI
ts.frm ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 3" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 1" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`test2`.`t2`,`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 2" "engine: aria crash point: ddl_log_drop_before_binlog position: 2"
"No crash!" "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" "engine: aria crash point: ddl_log_drop_before_binlog position: 3"
"No crash!" "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" "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" "engine: aria crash point: ddl_log_drop_after_binlog position: 2"
"No crash!" "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" "engine: aria crash point: ddl_log_drop_after_binlog position: 3"
"No crash!" "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: Warnings:
Note 1051 Unknown table 'test.t1,test.t2,test.ts' Note 1051 Unknown table 'test.t1,test2.t2,test.ts'
...@@ -4,11 +4,14 @@ ...@@ -4,11 +4,14 @@
# #
# Testing of atomic drop with crashes in a lot of different places # 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"); call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal");
let $MYSQLD_DATADIR= `SELECT @@datadir`; let $MYSQLD_DATADIR= `SELECT @@datadir`;
create database test2;
let $engine_count=1; let $engine_count=1;
let $engines='aria'; let $engines='aria';
...@@ -53,10 +56,10 @@ while ($e < $engine_count) ...@@ -53,10 +56,10 @@ while ($e < $engine_count)
inc $r; inc $r;
--eval set @@default_storage_engine=$default_engine --eval set @@default_storage_engine=$default_engine
--eval create table t1 (a int not null) $extra_option; --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; create sequence ts;
insert into t1 values(1); insert into t1 values(1);
insert into t2 values(2); insert into test2.t2 values(2);
flush tables; flush tables;
delimiter |; delimiter |;
...@@ -66,7 +69,7 @@ while ($e < $engine_count) ...@@ -66,7 +69,7 @@ while ($e < $engine_count)
set new.a:= 1000; set new.a:= 1000;
end if; end if;
end| 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 begin
if isnull(new.b) then if isnull(new.b) then
set new.b:= 2000; set new.b:= 2000;
...@@ -82,7 +85,7 @@ while ($e < $engine_count) ...@@ -82,7 +85,7 @@ while ($e < $engine_count)
--eval set @@debug_dbug="+d,$crash",@debug_crash_counter=$r --eval set @@debug_dbug="+d,$crash",@debug_crash_counter=$r
let $errno=0; let $errno=0;
--error 0,2013 --error 0,2013
drop table t1,t2,ts; drop table t1,test2.t2,ts;
let $error=$errno; let $error=$errno;
--enable_reconnect --enable_reconnect
--source include/wait_until_connected_again.inc --source include/wait_until_connected_again.inc
...@@ -95,6 +98,7 @@ while ($e < $engine_count) ...@@ -95,6 +98,7 @@ while ($e < $engine_count)
} }
# Check which tables still exists # Check which tables still exists
--list_files $MYSQLD_DATADIR/test t* --list_files $MYSQLD_DATADIR/test t*
--list_files $MYSQLD_DATADIR/test2 t*
--let $binlog_file=master-bin.000001 --let $binlog_file=master-bin.000001
--source include/show_binlog_events.inc --source include/show_binlog_events.inc
...@@ -105,11 +109,11 @@ while ($e < $engine_count) ...@@ -105,11 +109,11 @@ while ($e < $engine_count)
} }
# Really drop the tables. The warnings will show what was dropped # Really drop the tables. The warnings will show what was dropped
--disable_warnings --disable_warnings
drop table if exists t1,t2,ts; drop table if exists t1,test2.t2,ts;
--enable_warnings --enable_warnings
} }
} }
} }
drop table if exists t1,t2,ts; drop table if exists t1,test2.t2,ts;
drop database test2;
--enable_query_log --enable_query_log
...@@ -5,47 +5,47 @@ t2.MYI ...@@ -5,47 +5,47 @@ t2.MYI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_before_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_after_delete_table position: 1" "engine: myisam crash point: ddl_log_drop_after_delete_table position: 1"
t2.MYD t2.MYD
t2.MYI t2.MYI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_after_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_before_drop_trigger position: 1" "engine: myisam crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.MYD t2.MYD
t2.MYI t2.MYI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_before_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_before_drop_trigger2 position: 1" "engine: myisam crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.MYD t2.MYD
t2.MYI t2.MYI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_before_drop_trigger2 position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_after_drop_trigger position: 1" "engine: myisam crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.MYD t2.MYD
t2.MYI t2.MYI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_after_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_before_binlog position: 1" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: myisam crash point: ddl_log_drop_before_binlog position: 2" "engine: myisam crash point: ddl_log_drop_before_binlog position: 2"
"No crash!" "No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
...@@ -60,47 +60,47 @@ t2.MAI ...@@ -60,47 +60,47 @@ t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 1" "engine: aria crash point: ddl_log_drop_after_delete_table position: 1"
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1" "engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1" "engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1" "engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 1" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 2" "engine: aria crash point: ddl_log_drop_before_binlog position: 2"
"No crash!" "No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
...@@ -115,47 +115,47 @@ t2.MAI ...@@ -115,47 +115,47 @@ t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_before_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_after_delete_table position: 1" "engine: aria_notrans crash point: ddl_log_drop_after_delete_table position: 1"
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_after_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger position: 1" "engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger2 position: 1" "engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger2 position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_after_drop_trigger position: 1" "engine: aria_notrans crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.MAD t2.MAD
t2.MAI t2.MAI
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_after_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_before_binlog position: 1" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: aria_notrans crash point: ddl_log_drop_before_binlog position: 2" "engine: aria_notrans crash point: ddl_log_drop_before_binlog position: 2"
"No crash!" "No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
...@@ -169,43 +169,43 @@ t2.TRG ...@@ -169,43 +169,43 @@ t2.TRG
t2.frm t2.frm
t2.ibd t2.ibd
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_before_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_after_delete_table position: 1" "engine: innodb crash point: ddl_log_drop_after_delete_table position: 1"
t2.TRG t2.TRG
t2.frm t2.frm
t2.ibd t2.ibd
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_after_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_before_drop_trigger position: 1" "engine: innodb crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.TRG t2.TRG
t2.frm t2.frm
t2.ibd t2.ibd
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_before_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_before_drop_trigger2 position: 1" "engine: innodb crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.TRG t2.TRG
t2.frm t2.frm
t2.ibd t2.ibd
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_before_drop_trigger2 position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_after_drop_trigger position: 1" "engine: innodb crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.TRG t2.TRG
t2.frm t2.frm
t2.ibd t2.ibd
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_after_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_before_binlog position: 1" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: innodb crash point: ddl_log_drop_before_binlog position: 2" "engine: innodb crash point: ddl_log_drop_before_binlog position: 2"
"No crash!" "No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
...@@ -220,47 +220,47 @@ t2.CSV ...@@ -220,47 +220,47 @@ t2.CSV
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_before_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_after_delete_table position: 1" "engine: csv crash point: ddl_log_drop_after_delete_table position: 1"
t2.CSM t2.CSM
t2.CSV t2.CSV
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_after_delete_table position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_before_drop_trigger position: 1" "engine: csv crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.CSM t2.CSM
t2.CSV t2.CSV
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_before_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_before_drop_trigger2 position: 1" "engine: csv crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.CSM t2.CSM
t2.CSV t2.CSV
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_before_drop_trigger2 position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_after_drop_trigger position: 1" "engine: csv crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.CSM t2.CSM
t2.CSV t2.CSV
t2.TRG t2.TRG
t2.frm t2.frm
t2_trg.TRN t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_after_drop_trigger position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_before_binlog position: 1" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t2` /* generated by ddl recovery */
"engine: csv crash point: ddl_log_drop_before_binlog position: 2" "engine: csv crash point: ddl_log_drop_before_binlog position: 2"
"No crash!" "No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
......
"engine: aria crash point: ddl_log_drop_before_delete_view position: 1" "engine: aria crash point: ddl_log_drop_before_delete_view position: 1"
v2.frm v2.frm
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_delete_view position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1`,`v2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_view position: 1" "engine: aria crash point: ddl_log_drop_after_delete_view position: 1"
v2.frm v2.frm
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1` /* generated by ddl recovery */ master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_view position: 2" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1`,`v2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 1" "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 recovery */ master-bin.000002 # Query # # use `test`; DROP VIEW IF EXISTS `v1`,`v2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 2" "engine: aria crash point: ddl_log_drop_before_binlog position: 2"
"No crash!" "No crash!"
master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2 master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "sql_view.h" // mysql_rename_view() #include "sql_view.h" // mysql_rename_view()
#include "strfunc.h" // strconvert #include "strfunc.h" // strconvert
#include "sql_show.h" // append_identifier() #include "sql_show.h" // append_identifier()
#include "sql_db.h" // drop_database_objects()
#include <mysys_err.h> // EE_LINK #include <mysys_err.h> // EE_LINK
...@@ -88,13 +89,16 @@ const char *ddl_log_action_name[DDL_LOG_LAST_ACTION]= ...@@ -88,13 +89,16 @@ const char *ddl_log_action_name[DDL_LOG_LAST_ACTION]=
"partitioning replace", "partitioning exchange", "partitioning replace", "partitioning exchange",
"rename table", "rename view", "rename table", "rename view",
"initialize drop table", "drop table", "initialize drop table", "drop table",
"initialize drop view", "drop view", "drop trigger", "drop view", "drop trigger", "drop db",
}; };
/* Number of phases per entry */ /* Number of phases per entry */
const uchar ddl_log_entry_phases[DDL_LOG_LAST_ACTION]= 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
}; };
...@@ -111,8 +115,17 @@ struct st_global_ddl_log ...@@ -111,8 +115,17 @@ struct st_global_ddl_log
bool open; bool open;
}; };
st_global_ddl_log global_ddl_log; /* The following structure is only used during startup recovery */
String ddl_drop_query; // 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; mysql_mutex_t LOCK_gdl;
...@@ -786,6 +799,8 @@ static bool ddl_log_increment_phase_no_lock(uint entry_pos) ...@@ -786,6 +799,8 @@ static bool ddl_log_increment_phase_no_lock(uint entry_pos)
Ignore errors from the file system about: Ignore errors from the file system about:
- Non existing tables or file (from drop table or delete file) - Non existing tables or file (from drop table or delete file)
- Error about tables files that already exists. - 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 class ddl_log_error_handler : public Internal_error_handler
...@@ -793,8 +808,10 @@ class ddl_log_error_handler : public Internal_error_handler ...@@ -793,8 +808,10 @@ class ddl_log_error_handler : public Internal_error_handler
public: public:
int handled_errors; int handled_errors;
int unhandled_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, bool handle_condition(THD *thd,
...@@ -805,11 +822,14 @@ class ddl_log_error_handler : public Internal_error_handler ...@@ -805,11 +822,14 @@ class ddl_log_error_handler : public Internal_error_handler
Sql_condition ** cond_hdl) Sql_condition ** cond_hdl)
{ {
*cond_hdl= NULL; *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++; handled_errors++;
return TRUE; return TRUE;
} }
if (!first_error)
first_error= sql_errno;
if (*level == Sql_condition::WARN_LEVEL_ERROR) if (*level == Sql_condition::WARN_LEVEL_ERROR)
unhandled_errors++; unhandled_errors++;
...@@ -848,6 +868,77 @@ static bool build_filename_and_delete_tmp_file(char *path, size_t path_length, ...@@ -848,6 +868,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 recovery */")};
/**
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 Execute one action in a ddl log entry
...@@ -858,10 +949,6 @@ static bool build_filename_and_delete_tmp_file(char *path, size_t path_length, ...@@ -858,10 +949,6 @@ static bool build_filename_and_delete_tmp_file(char *path, size_t path_length,
@retval FALSE Success @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, static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
DDL_LOG_ENTRY *ddl_log_entry) DDL_LOG_ENTRY *ddl_log_entry)
{ {
...@@ -877,10 +964,11 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, ...@@ -877,10 +964,11 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
mysql_mutex_assert_owner(&LOCK_gdl); mysql_mutex_assert_owner(&LOCK_gdl);
DBUG_PRINT("ddl_log", 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'", "handler: '%s' name: '%s' from_name: '%s' tmp_name: '%s'",
(uint) ddl_log_entry->entry_type, (uint) ddl_log_entry->entry_type,
(uint) ddl_log_entry->action_type, (uint) ddl_log_entry->action_type,
ddl_log_action_name[ddl_log_entry->action_type],
(uint) ddl_log_entry->phase, (uint) ddl_log_entry->phase,
ddl_log_entry->next_entry, ddl_log_entry->next_entry,
ddl_log_entry->handler_name.str, ddl_log_entry->handler_name.str,
...@@ -1176,17 +1264,32 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, ...@@ -1176,17 +1264,32 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
(void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE); (void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE);
} }
break; 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; LEX_CSTRING *comment= &ddl_log_entry->tmp_name;
ddl_drop_query.length(0); recovery_state.drop_table.length(0);
ddl_drop_query.set_charset(system_charset_info); recovery_state.drop_table.set_charset(system_charset_info);
ddl_drop_query.append(STRING_WITH_LEN("DROP TABLE IF EXISTS ")); recovery_state.drop_table.append(STRING_WITH_LEN("DROP TABLE IF EXISTS "));
if (comment->length) if (comment->length)
{ {
ddl_drop_query.append(comment); recovery_state.drop_table.append(comment);
ddl_drop_query.append(' '); 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(system_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 */ /* We don't increment phase as we want to retry this in case of crash */
break; break;
} }
...@@ -1230,36 +1333,30 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, ...@@ -1230,36 +1333,30 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
/* Fall through */ /* Fall through */
case DDL_DROP_PHASE_BINLOG: case DDL_DROP_PHASE_BINLOG:
append_identifier(thd, &ddl_drop_query, &db); if (strcmp(recovery_state.current_db, db.str))
ddl_drop_query.append('.'); {
append_identifier(thd, &ddl_drop_query, &table); append_identifier(thd, &recovery_state.drop_table, &db);
ddl_drop_query.append(','); 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 */ /* 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 */ if (ddl_log_increment_phase_no_lock(entry_pos))
ddl_drop_query.length(ddl_drop_query.length()-1); break;
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);
} }
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; break;
} }
case DDL_LOG_DROP_VIEW_INIT_ACTION:
{
ddl_drop_query.length(0);
ddl_drop_query.set_charset(system_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: case DDL_LOG_DROP_VIEW_ACTION:
{ {
LEX_CSTRING db, table, path; LEX_CSTRING db, table, path;
...@@ -1268,23 +1365,29 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, ...@@ -1268,23 +1365,29 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
/* Note that for views path is WITH .frm extension */ /* Note that for views path is WITH .frm extension */
path= ddl_log_entry->tmp_name; path= ddl_log_entry->tmp_name;
mysql_file_delete(key_file_frm, path.str, MYF(MY_WME|MY_IGNORE_ENOENT)); if (ddl_log_entry->phase == 0)
append_identifier(thd, &ddl_drop_query, &db); {
ddl_drop_query.append('.'); mysql_file_delete(key_file_frm, path.str, MYF(MY_WME|MY_IGNORE_ENOENT));
append_identifier(thd, &ddl_drop_query, &table); if (strcmp(recovery_state.current_db, db.str))
ddl_drop_query.append(','); {
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(',');
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_view))
{
if (ddl_log_increment_phase_no_lock(entry_pos))
break;
}
}
else
{ {
/* Last drop view. Write query to binlog */ /* We have already logged all previous drop's. Clear the query */
ddl_drop_query.length(ddl_drop_query.length()-1); recovery_state.drop_table.length(recovery_state.drop_table_init_length);
ddl_drop_query.append(&end_comment); recovery_state.drop_view.length(recovery_state.drop_table_init_length);
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);
} }
break; break;
} }
...@@ -1323,27 +1426,29 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, ...@@ -1323,27 +1426,29 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
&ddl_log_entry->from_name, &ddl_log_entry->from_name,
MYF(0)); MYF(0));
ddl_drop_query.length(0); recovery_state.drop_table.length(0);
ddl_drop_query.set_charset(system_charset_info); recovery_state.drop_table.set_charset(system_charset_info);
if (ddl_log_entry->tmp_name.length) if (ddl_log_entry->tmp_name.length)
{ {
/* We can use the original query */ /* 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 else
{ {
/* Generate new query */ /* Generate new query */
ddl_drop_query.append(STRING_WITH_LEN("DROP TRIGGER IF EXISTS ")); recovery_state.drop_table.append(STRING_WITH_LEN("DROP TRIGGER IF "
append_identifier(thd, &ddl_drop_query, &ddl_log_entry->from_name); "EXISTS "));
ddl_drop_query.append(&end_comment); append_identifier(thd, &recovery_state.drop_table,
&ddl_log_entry->from_name);
recovery_state.drop_table.append(&end_comment);
} }
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
mysql_mutex_unlock(&LOCK_gdl); mysql_mutex_unlock(&LOCK_gdl);
thd->db= ddl_log_entry->db; thd->db= ddl_log_entry->db;
(void) thd->binlog_query(THD::STMT_QUERY_TYPE, (void) thd->binlog_query(THD::STMT_QUERY_TYPE,
ddl_drop_query.ptr(), recovery_state.drop_table.ptr(),
ddl_drop_query.length(), TRUE, FALSE, recovery_state.drop_table.length(), TRUE, FALSE,
FALSE, 0); FALSE, 0);
thd->db= thd_db; thd->db= thd_db;
mysql_mutex_lock(&LOCK_gdl); mysql_mutex_lock(&LOCK_gdl);
...@@ -1352,6 +1457,48 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, ...@@ -1352,6 +1457,48 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
(void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE); (void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE);
break; 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);
if (mysql_bin_log.is_open())
{
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: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
break; break;
...@@ -1359,7 +1506,8 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, ...@@ -1359,7 +1506,8 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
end: end:
delete file; 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(); thd->pop_internal_handler();
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -1517,7 +1665,6 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry, ...@@ -1517,7 +1665,6 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry,
DDL_LOG_MEMORY_ENTRY **active_entry) DDL_LOG_MEMORY_ENTRY **active_entry)
{ {
bool error; bool error;
uchar *pos, *end;
DBUG_ENTER("ddl_log_write_entry"); DBUG_ENTER("ddl_log_write_entry");
*active_entry= 0; *active_entry= 0;
...@@ -1535,20 +1682,18 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry, ...@@ -1535,20 +1682,18 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry,
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
error= FALSE; 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", DBUG_PRINT("ddl_log",
("type: %c next: %u handler: %s " ("entry type: %u action type: %u (%s) phase: %u next: %u "
"to_name: '%s.%s' from_name: '%s.%s' " "handler: '%s' name: '%s' from_name: '%s' tmp_name: '%s'",
"tmp_name: '%s'", (uint) ddl_log_entry->entry_type,
(char) global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS], (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->next_entry,
get_string(&pos, end).str, // Handler ddl_log_entry->handler_name.str,
get_string(&pos, end).str, // to db.table ddl_log_entry->name.str,
get_string(&pos, end).str, ddl_log_entry->from_name.str,
get_string(&pos, end).str, // From db.table ddl_log_entry->tmp_name.str));
get_string(&pos, end).str,
get_string(&pos, end).str)); // Tmp name
if (unlikely(write_ddl_log_file_entry((*active_entry)->entry_pos))) if (unlikely(write_ddl_log_file_entry((*active_entry)->entry_pos)))
{ {
...@@ -1626,8 +1771,9 @@ bool ddl_log_write_execute_entry(uint first_entry, ...@@ -1626,8 +1771,9 @@ bool ddl_log_write_execute_entry(uint first_entry,
DBUG_RETURN(FALSE); 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. @details see ddl_log_increment_phase_no_lock.
...@@ -1790,7 +1936,8 @@ int ddl_log_execute_recovery() ...@@ -1790,7 +1936,8 @@ int ddl_log_execute_recovery()
thd->store_globals(); thd->store_globals();
thd->init(); // Needed for error messages thd->init(); // Needed for error messages
thd->log_all_errors= (global_system_variables.log_warnings >= 3); thd->log_all_errors= (global_system_variables.log_warnings >= 3);
ddl_drop_query.free(); recovery_state.drop_table.free();
recovery_state.drop_view.free();
thd->set_query(recover_query_string, strlen(recover_query_string)); thd->set_query(recover_query_string, strlen(recover_query_string));
...@@ -1828,7 +1975,8 @@ int ddl_log_execute_recovery() ...@@ -1828,7 +1975,8 @@ int ddl_log_execute_recovery()
count++; count++;
} }
} }
ddl_drop_query.free(); recovery_state.drop_table.free();
recovery_state.drop_view.free();
close_ddl_log(); close_ddl_log();
mysql_mutex_unlock(&LOCK_gdl); mysql_mutex_unlock(&LOCK_gdl);
thd->reset_query(); thd->reset_query();
...@@ -1943,12 +2091,13 @@ void ddl_log_complete(DDL_LOG_STATE *state) ...@@ -1943,12 +2091,13 @@ void ddl_log_complete(DDL_LOG_STATE *state)
ddl_log_disable_execute_entry(&state->execute_entry); ddl_log_disable_execute_entry(&state->execute_entry);
ddl_log_release_entries(state); ddl_log_release_entries(state);
mysql_mutex_unlock(&LOCK_gdl); mysql_mutex_unlock(&LOCK_gdl);
state->list= 0;
DBUG_VOID_RETURN; 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) void ddl_log_revert(THD *thd, DDL_LOG_STATE *state)
...@@ -1966,6 +2115,7 @@ void ddl_log_revert(THD *thd, DDL_LOG_STATE *state) ...@@ -1966,6 +2115,7 @@ void ddl_log_revert(THD *thd, DDL_LOG_STATE *state)
} }
ddl_log_release_entries(state); ddl_log_release_entries(state);
mysql_mutex_unlock(&LOCK_gdl); mysql_mutex_unlock(&LOCK_gdl);
state->list= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2103,6 +2253,7 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -2103,6 +2253,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, static bool ddl_log_drop_init(THD *thd, DDL_LOG_STATE *ddl_state,
ddl_log_action_code action_code, ddl_log_action_code action_code,
const LEX_CSTRING *db,
const LEX_CSTRING *comment) const LEX_CSTRING *comment)
{ {
DDL_LOG_ENTRY ddl_log_entry; DDL_LOG_ENTRY ddl_log_entry;
...@@ -2111,26 +2262,26 @@ static bool ddl_log_drop_init(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -2111,26 +2262,26 @@ static bool ddl_log_drop_init(THD *thd, DDL_LOG_STATE *ddl_state,
bzero(&ddl_log_entry, sizeof(ddl_log_entry)); bzero(&ddl_log_entry, sizeof(ddl_log_entry));
ddl_log_entry.action_type= action_code; 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.tmp_name= *const_cast<LEX_CSTRING*>(comment);
ddl_log_entry.phase= 0;
DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry)); DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry));
} }
bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state, bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *db,
const LEX_CSTRING *comment) const LEX_CSTRING *comment)
{ {
return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_TABLE_INIT_ACTION, return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_INIT_ACTION,
comment); 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_INIT_ACTION,
return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_VIEW_INIT_ACTION, db, &empty_clex_str);
&comment);
} }
static bool ddl_log_drop(THD *thd, DDL_LOG_STATE *ddl_state, static bool ddl_log_drop(THD *thd, DDL_LOG_STATE *ddl_state,
...@@ -2215,7 +2366,7 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -2215,7 +2366,7 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state,
char path[FN_REFLEN+1]; char path[FN_REFLEN+1];
off_t frm_length= 0; off_t frm_length= 0;
size_t max_query_length; 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); build_table_filename(path, sizeof(path)-1, db->str, table->str, TRG_EXT, 0);
...@@ -2242,3 +2393,27 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -2242,3 +2393,27 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state,
DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry)); 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));
}
...@@ -77,11 +77,11 @@ enum ddl_log_action_code ...@@ -77,11 +77,11 @@ enum ddl_log_action_code
*/ */
DDL_LOG_RENAME_TABLE_ACTION= 5, DDL_LOG_RENAME_TABLE_ACTION= 5,
DDL_LOG_RENAME_VIEW_ACTION= 6, 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_TABLE_ACTION= 8,
DDL_LOG_DROP_VIEW_INIT_ACTION= 9, DDL_LOG_DROP_VIEW_ACTION= 9,
DDL_LOG_DROP_VIEW_ACTION= 10, DDL_LOG_DROP_TRIGGER_ACTION= 10,
DDL_LOG_DROP_TRIGGER_ACTION= 11, DDL_LOG_DROP_DB_ACTION=11,
DDL_LOG_LAST_ACTION /* End marker */ DDL_LOG_LAST_ACTION /* End marker */
}; };
...@@ -93,13 +93,15 @@ extern const uchar ddl_log_entry_phases[DDL_LOG_LAST_ACTION]; ...@@ -93,13 +93,15 @@ extern const uchar ddl_log_entry_phases[DDL_LOG_LAST_ACTION];
enum enum_ddl_log_exchange_phase { enum enum_ddl_log_exchange_phase {
EXCH_PHASE_NAME_TO_TEMP= 0, EXCH_PHASE_NAME_TO_TEMP= 0,
EXCH_PHASE_FROM_TO_NAME= 1, 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 { enum enum_ddl_log_rename_table_phase {
DDL_RENAME_PHASE_TRIGGER= 0, DDL_RENAME_PHASE_TRIGGER= 0,
DDL_RENAME_PHASE_STAT, DDL_RENAME_PHASE_STAT,
DDL_RENAME_PHASE_TABLE, DDL_RENAME_PHASE_TABLE,
DDL_RENAME_PHASE_END
}; };
enum enum_ddl_log_drop_table_phase { enum enum_ddl_log_drop_table_phase {
...@@ -110,6 +112,12 @@ enum enum_ddl_log_drop_table_phase { ...@@ -110,6 +112,12 @@ enum enum_ddl_log_drop_table_phase {
DDL_DROP_PHASE_END 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 Setting ddl_log_entry.phase to this has the same effect as setting
the phase to the maximum phase (..PHASE_END) for an entry. the phase to the maximum phase (..PHASE_END) for an entry.
...@@ -218,8 +226,10 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -218,8 +226,10 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *new_db, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_alias); const LEX_CSTRING *new_alias);
bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state, bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *db,
const LEX_CSTRING *comment); 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, bool ddl_log_drop_table(THD *thd, DDL_LOG_STATE *ddl_state,
handlerton *hton, handlerton *hton,
const LEX_CSTRING *path, const LEX_CSTRING *path,
...@@ -234,5 +244,13 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -234,5 +244,13 @@ bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *table, const LEX_CSTRING *table,
const LEX_CSTRING *trigger_name, const LEX_CSTRING *trigger_name,
const LEX_CSTRING *query); 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; extern mysql_mutex_t LOCK_gdl;
#endif /* DDL_LOG_INCLUDED */ #endif /* DDL_LOG_INCLUDED */
...@@ -839,9 +839,10 @@ static my_bool dropdb_handlerton(THD *unused1, plugin_ref plugin, ...@@ -839,9 +839,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);
} }
......
...@@ -5180,7 +5180,7 @@ int ha_panic(enum ha_panic_function flag); ...@@ -5180,7 +5180,7 @@ int ha_panic(enum ha_panic_function flag);
void ha_close_connection(THD* thd); void ha_close_connection(THD* thd);
void ha_kill_query(THD* thd, enum thd_kill_levels level); void ha_kill_query(THD* thd, enum thd_kill_levels level);
bool ha_flush_logs(); 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_checkpoint_state(bool disable);
void ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *)); void ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *));
int ha_create_table(THD *thd, const char *path, const char *db, int ha_create_table(THD *thd, const char *path, const char *db,
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "events.h" #include "events.h"
#include "sql_handler.h" #include "sql_handler.h"
#include "sql_statistics.h" #include "sql_statistics.h"
#include "ddl_log.h" // ddl_log functions
#include <my_dir.h> #include <my_dir.h>
#include <m_ctype.h> #include <m_ctype.h>
#include "log.h" #include "log.h"
...@@ -58,7 +59,7 @@ static bool find_db_tables_and_rm_known_files(THD *, MY_DIR *, const char *, ...@@ -58,7 +59,7 @@ static bool find_db_tables_and_rm_known_files(THD *, MY_DIR *, const char *,
const char *, TABLE_LIST **); const char *, TABLE_LIST **);
long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path); 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, static void mysql_change_db_impl(THD *thd,
LEX_CSTRING *new_db_name, LEX_CSTRING *new_db_name,
privilege_t new_db_access, privilege_t new_db_access,
...@@ -951,6 +952,56 @@ bool mysql_alter_db(THD *thd, const LEX_CSTRING *db, ...@@ -951,6 +952,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. Drop all tables, routines and events in a database and the database itself.
...@@ -967,41 +1018,31 @@ bool mysql_alter_db(THD *thd, const LEX_CSTRING *db, ...@@ -967,41 +1018,31 @@ bool mysql_alter_db(THD *thd, const LEX_CSTRING *db,
*/ */
static bool 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; ulong deleted_tables= 0;
bool error= true, rm_mysql_schema; bool error= true, rm_mysql_schema;
char path[FN_REFLEN + 16]; char path[FN_REFLEN + 16];
MY_DIR *dirp; MY_DIR *dirp;
uint length; uint path_length;
TABLE_LIST *tables= NULL; TABLE_LIST *tables= NULL;
TABLE_LIST *table; TABLE_LIST *table;
DDL_LOG_STATE ddl_log_state;
Drop_table_error_handler err_handler; 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"); DBUG_ENTER("mysql_rm_db");
char db_tmp[SAFE_NAME_LEN+1]; dbnorm= normalize_db_name(db->str, db_tmp, sizeof(db_tmp));
const char *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)) if (lock_schema_name(thd, dbnorm))
DBUG_RETURN(true); DBUG_RETURN(true);
length= build_table_filename(path, sizeof(path) - 1, db->str, "", "", 0); path_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
/* See if the directory exists */ /* See if the directory exists */
if (!(dirp= my_dir(path,MYF(MY_DONT_SORT)))) 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 ...@@ -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) if (tables)
mysql_ha_rm_tables(thd, 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 ...@@ -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); thd->push_internal_handler(&err_handler);
if (!thd->killed && if (!thd->killed &&
!(tables && !(tables &&
mysql_rm_table_no_locks(thd, tables, true, false, true, false, true, mysql_rm_table_no_locks(thd, tables, &rm_db, &ddl_log_state, true, false,
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 Now remove the db.opt file.
in the database. Since the DROP DATABASE statement is always The 'find_db_tables_and_rm_known_files' doesn't remove this file
replicated as a statement, execution of it will drop all objects if there exists a table with the name 'db', so let's just do it
in the database on the slave as well, so there is no need to separately. We know this file exists and needs to be deleted anyway.
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_option_file");
ha_drop_database(path); strmov(path+path_length, MY_DB_OPT_FILE); // Append db option file name
tmp_disable_binlog(thd); if (mysql_file_delete_with_symlink(key_file_misc, path, "", MYF(0)) &&
query_cache_invalidate1(thd, dbnorm); my_errno != ENOENT)
if (!rm_mysql_schema)
{ {
(void) sp_drop_db_routines(thd, dbnorm); /* @todo Do not ignore errors */ thd->pop_internal_handler();
#ifdef HAVE_EVENT_SCHEDULER my_error(EE_DELETE, MYF(0), path, my_errno);
Events::drop_schema_events(thd, dbnorm); error= true;
#endif 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 If the directory is a symbolic link, remove the link first, then
remove the directory the symbolic link pointed at remove the directory the symbolic link pointed at
*/ */
debug_crash_here("ddl_log_drop_before_drop_dir");
error= rm_dir_w_symlink(path, true); error= rm_dir_w_symlink(path, true);
debug_crash_here("ddl_log_drop_after_drop_dir");
} }
thd->pop_internal_handler(); thd->pop_internal_handler();
update_binlog: update_binlog:
...@@ -1112,6 +1160,7 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen ...@@ -1112,6 +1160,7 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
int errcode= query_error_code(thd, TRUE); int errcode= query_error_code(thd, TRUE);
int res;
Query_log_event qinfo(thd, query, query_length, FALSE, TRUE, Query_log_event qinfo(thd, query, query_length, FALSE, TRUE,
/* suppress_use */ TRUE, errcode); /* suppress_use */ TRUE, errcode);
/* /*
...@@ -1126,7 +1175,14 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen ...@@ -1126,7 +1175,14 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen
These DDL methods and logging are protected with the exclusive These DDL methods and logging are protected with the exclusive
metadata lock on the schema. 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; error= true;
goto exit; goto exit;
...@@ -1176,13 +1232,21 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen ...@@ -1176,13 +1232,21 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen
*query_pos++ = ','; *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 These DDL methods and logging are protected with the exclusive
metadata lock on the schema. 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; error= true;
goto exit; goto exit;
...@@ -1191,6 +1255,7 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen ...@@ -1191,6 +1255,7 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen
} }
exit: exit:
ddl_log_complete(&ddl_log_state);
/* /*
If this database was the client's selected database, we silently If this database was the client's selected database, we silently
change the client's selected database to nothing (to have an empty change the client's selected database to nothing (to have an empty
...@@ -1202,6 +1267,7 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen ...@@ -1202,6 +1267,7 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, bool silen
mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server); mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server);
thd->session_tracker.current_schema.mark_as_changed(thd); thd->session_tracker.current_schema.mark_as_changed(thd);
} }
end:
my_dirend(dirp); my_dirend(dirp);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -1332,22 +1398,24 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp, ...@@ -1332,22 +1398,24 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
1 ERROR 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 tmp_path[FN_REFLEN], *pos;
char *path= tmp_path; char *path= tmp_path;
DBUG_ENTER("rm_dir_w_symlink"); DBUG_ENTER("rm_dir_w_symlink");
unpack_filename(tmp_path, org_path); 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); pos= strend(path);
if (pos > path && pos[-1] == FN_LIBCHAR) if (pos > path && pos[-1] == FN_LIBCHAR)
*--pos=0; *--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); DBUG_RETURN(1);
if (likely(!error)) if (likely(!error))
{ {
...@@ -1359,11 +1427,7 @@ static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error) ...@@ -1359,11 +1427,7 @@ static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error)
path= tmp2_path; path= tmp2_path;
} }
#endif #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)) if (unlikely(my_rmdir(path) < 0 && send_error))
{ {
my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno); my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
......
...@@ -47,6 +47,10 @@ void my_dbopt_cleanup(void); ...@@ -47,6 +47,10 @@ void my_dbopt_cleanup(void);
const char *normalize_db_name(const char *db, char *buffer, const char *normalize_db_name(const char *db, char *buffer,
size_t buffer_size); 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" #define MY_DB_OPT_FILE "db.opt"
#endif /* SQL_DB_INCLUDED */ #endif /* SQL_DB_INCLUDED */
...@@ -1041,7 +1041,9 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists, ...@@ -1041,7 +1041,9 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
/* mark for close and remove all cached entries */ /* mark for close and remove all cached entries */
thd->push_internal_handler(&err_handler); 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, drop_sequence, dont_log_query,
false); false);
thd->pop_internal_handler(); thd->pop_internal_handler();
...@@ -1102,6 +1104,11 @@ static uint32 get_comment(THD *thd, uint32 comment_pos, ...@@ -1102,6 +1104,11 @@ static uint32 get_comment(THD *thd, uint32 comment_pos,
@param thd Thread handler @param thd Thread handler
@param tables Tables to drop @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. @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' In this case we give an warning of level 'NOTE'
@param drop_temporary Only drop temporary tables @param drop_temporary Only drop temporary tables
...@@ -1130,7 +1137,10 @@ static uint32 get_comment(THD *thd, uint32 comment_pos, ...@@ -1130,7 +1137,10 @@ static uint32 get_comment(THD *thd, uint32 comment_pos,
not all. 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_temporary, bool drop_view,
bool drop_sequence, bool drop_sequence,
bool dont_log_query, bool dont_log_query,
...@@ -1140,7 +1150,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1140,7 +1150,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
char path[FN_REFLEN + 1]; char path[FN_REFLEN + 1];
LEX_CSTRING alias= null_clex_str; LEX_CSTRING alias= null_clex_str;
StringBuffer<160> unknown_tables(system_charset_info); StringBuffer<160> unknown_tables(system_charset_info);
DDL_LOG_STATE ddl_log_state; DDL_LOG_STATE local_ddl_log_state;
const char *comment_start; const char *comment_start;
uint not_found_errors= 0, table_count= 0, non_temp_tables_count= 0; uint not_found_errors= 0, table_count= 0, non_temp_tables_count= 0;
int error= 0; int error= 0;
...@@ -1156,6 +1166,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -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; String built_trans_tmp_query, built_non_trans_tmp_query;
DBUG_ENTER("mysql_rm_table_no_locks"); 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); unknown_tables.length(0);
comment_len= get_comment(thd, if_exists ? 17:9, &comment_start); comment_len= get_comment(thd, if_exists ? 17:9, &comment_start);
...@@ -1209,14 +1225,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1209,14 +1225,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.set_charset(system_charset_info);
built_non_trans_tmp_query.copy(built_trans_tmp_query); 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) for (table= tables; table; table= table->next_local)
{ {
bool is_trans= 0, temporary_table_was_dropped= 0; bool is_trans= 0, temporary_table_was_dropped= 0;
bool table_creation_was_logged= 0; bool table_creation_was_logged= 0;
bool wrong_drop_sequence= 0; bool wrong_drop_sequence= 0;
bool table_dropped= 0; bool table_dropped= 0, res;
const LEX_CSTRING db= table->db; const LEX_CSTRING db= table->db;
const LEX_CSTRING table_name= table->table_name; const LEX_CSTRING table_name= table->table_name;
LEX_CSTRING cpath= {0,0}; LEX_CSTRING cpath= {0,0};
...@@ -1376,7 +1391,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1376,7 +1391,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (!table_count++) if (!table_count++)
{ {
LEX_CSTRING comment= {comment_start, (size_t) comment_len}; 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; error= 1;
goto err; goto err;
...@@ -1434,12 +1449,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1434,12 +1449,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); bool enoent_warning= !dont_log_query && !(hton && hton->discover_table);
if (ddl_log_drop_table(thd, &ddl_log_state, hton, &cpath, &db, if (was_view)
&table_name)) 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; error= -1;
goto err; goto err;
} }
debug_crash_here("ddl_log_drop_before_delete_table"); debug_crash_here("ddl_log_drop_before_delete_table");
error= ha_delete_table(thd, hton, path, &db, &table_name, error= ha_delete_table(thd, hton, path, &db, &table_name,
enoent_warning); enoent_warning);
...@@ -1510,7 +1531,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1510,7 +1531,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
int ferror= 0; int ferror= 0;
DBUG_ASSERT(!was_view); 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)) &table_name))
{ {
error= -1; error= -1;
...@@ -1548,9 +1569,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1548,9 +1569,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (thd->replication_flags & OPTION_IF_EXISTS) if (thd->replication_flags & OPTION_IF_EXISTS)
log_if_exists= 1; log_if_exists= 1;
debug_crash_here("ddl_log_drop_before_drop_trigger"); if (!was_view)
ddl_log_update_phase(&ddl_log_state, DDL_DROP_PHASE_TRIGGER); {
debug_crash_here("ddl_log_drop_before_drop_trigger2"); 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)) if (likely(!error) || non_existing_table_error(error))
{ {
...@@ -1610,7 +1634,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1610,7 +1634,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
table_name.str, (uint)table_name.length); table_name.str, (uint)table_name.length);
mysql_audit_drop_table(thd, table); mysql_audit_drop_table(thd, table);
} }
ddl_log_update_phase(&ddl_log_state, DDL_DROP_PHASE_BINLOG); if (!was_view)
ddl_log_update_phase(ddl_log_state, DDL_DROP_PHASE_BINLOG);
if (!dont_log_query && if (!dont_log_query &&
(!error || table_dropped || non_existing_table_error(error))) (!error || table_dropped || non_existing_table_error(error)))
...@@ -1715,7 +1740,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1715,7 +1740,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
built_query.append(normal_tables.ptr(), normal_tables.length()); built_query.append(normal_tables.ptr(), normal_tables.length());
built_query.append(generated_by_server); built_query.append(generated_by_server);
thd->binlog_xid= thd->query_id; 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, error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
built_query.ptr(), built_query.ptr(),
built_query.length(), built_query.length(),
...@@ -1725,7 +1750,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1725,7 +1750,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
debug_crash_here("ddl_log_drop_after_binlog"); 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) if (!drop_temporary)
{ {
...@@ -4234,7 +4260,9 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db, ...@@ -4234,7 +4260,9 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db,
*/ */
(void) trans_rollback_stmt(thd); (void) trans_rollback_stmt(thd);
/* Remove normal table without logging. Keep tables locked */ /* 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; goto err;
/* /*
...@@ -4453,7 +4481,9 @@ int mysql_create_table_no_lock(THD *thd, const LEX_CSTRING *db, ...@@ -4453,7 +4481,9 @@ int mysql_create_table_no_lock(THD *thd, const LEX_CSTRING *db,
{ {
DBUG_ASSERT(thd->is_error()); DBUG_ASSERT(thd->is_error());
/* Drop the table as it wasn't completely done */ /* 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(), create_info->tmp_table(),
false, true /* Sequence*/, false, true /* Sequence*/,
true /* Don't log_query */, true /* Don't log_query */,
......
...@@ -37,6 +37,7 @@ typedef struct st_key KEY; ...@@ -37,6 +37,7 @@ typedef struct st_key KEY;
typedef struct st_key_cache KEY_CACHE; typedef struct st_key_cache KEY_CACHE;
typedef struct st_lock_param_type ALTER_PARTITION_PARAM_TYPE; typedef struct st_lock_param_type ALTER_PARTITION_PARAM_TYPE;
typedef struct st_order ORDER; typedef struct st_order ORDER;
typedef struct st_ddl_log_state DDL_LOG_STATE;
enum enum_explain_filename_mode enum enum_explain_filename_mode
{ {
...@@ -177,7 +178,10 @@ bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list, ...@@ -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 mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool drop_sequence, bool drop_temporary, bool drop_sequence,
bool dont_log_query); 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_temporary, bool drop_view,
bool drop_sequence, bool drop_sequence,
bool dont_log_query, bool dont_free_locks); bool dont_log_query, bool dont_free_locks);
......
...@@ -1870,7 +1870,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1870,7 +1870,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
} }
if (!view_count++) if (!view_count++)
{ {
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); DBUG_RETURN(TRUE);
} }
if (ddl_log_drop_view(thd, &ddl_log_state, &cpath, &view->db, if (ddl_log_drop_view(thd, &ddl_log_state, &cpath, &view->db,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment