Commit e3cfb7c8 authored by Monty's avatar Monty Committed by Sergei Golubchik

MDEV-23844 Atomic DROP TABLE (single table)

Logging logic:
- Log tables, just before they are dropped, to the ddl log
- After the last table for the statement is dropped, log an xid for the
  whole ddl log event

In case of crash:
- Remove first any active DROP TABLE events from the ddl log that matches
  xids found in binary log (this mean the drop was successful and was
  propery logged).
- Loop over all active DROP TABLE events
  - Ensure that the table is completely dropped
- Write a DROP TABLE entry to the binary log with the dropped tables.

Other things:
- Added code to ha_drop_table() to be able to tell the difference if
  a get_new_handler() failed because of out-of-memory or because the
  handler refused/was not able to create a a handler. This was needed
  to get sequences to work as sequences needs a share object to be passed
  to get_new_handler()
- TC_LOG_BINLOG::recover() was changed to always collect Xid's from the
  binary log and always call ddl_log_close_binlogged_events(). This was
  needed to be able to collect DROP TABLE events with embedded Xid's
  (used by ddl log).
- Added a new variable "$grep_script" to binlog filter to be able to find
  only rows that matches a regexp.
- Had to adjust some test that changed because drop statements are a bit
  larger in the binary log than before (as we have to store the xid)

Other things:
- MDEV-25588 Atomic DDL: Binlog query event written upon recovery is corrupt
  fixed (in the original commit).
parent 47010ccf
...@@ -56,6 +56,9 @@ ...@@ -56,6 +56,9 @@
# #
# $filter_script # $filter_script
# If set, rows matching this regexp will be filtered out # If set, rows matching this regexp will be filtered out
#
# $grep_script
# If set, only include rows matching this regexp
--let $include_filename= filter_file.inc --let $include_filename= filter_file.inc
--source include/begin_include_file.inc --source include/begin_include_file.inc
...@@ -71,6 +74,7 @@ if ($rpl_debug) ...@@ -71,6 +74,7 @@ if ($rpl_debug)
--let _FF_PRE_SCRIPT= $pre_script --let _FF_PRE_SCRIPT= $pre_script
--let _FF_SCRIPT= $script --let _FF_SCRIPT= $script
--let _FF_FILTER_SCRIPT= $filter_script --let _FF_FILTER_SCRIPT= $filter_script
--let _FF_GREP_SCRIPT= $grep_script
--let _FF_INPUT_FILE= $input_file --let _FF_INPUT_FILE= $input_file
--let _FF_OUTPUT_FILE= $output_file --let _FF_OUTPUT_FILE= $output_file
--let _FF_SELECT_COLUMNS= $select_columns --let _FF_SELECT_COLUMNS= $select_columns
...@@ -85,6 +89,7 @@ perl; ...@@ -85,6 +89,7 @@ perl;
$pre_script =~ s/DOLLAR/\$/g; $pre_script =~ s/DOLLAR/\$/g;
my $script = $ENV{'_FF_SCRIPT'}; my $script = $ENV{'_FF_SCRIPT'};
my $filter_script = $ENV{'_FF_FILTER_SCRIPT'}; my $filter_script = $ENV{'_FF_FILTER_SCRIPT'};
my $grep_script = $ENV{'_FF_GREP_SCRIPT'};
$script =~ s/DOLLAR/\$/g; $script =~ s/DOLLAR/\$/g;
my $input_file = $ENV{'_FF_INPUT_FILE'}; my $input_file = $ENV{'_FF_INPUT_FILE'};
my $output_file = $ENV{'_FF_OUTPUT_FILE'}; my $output_file = $ENV{'_FF_OUTPUT_FILE'};
...@@ -129,7 +134,8 @@ perl; ...@@ -129,7 +134,8 @@ perl;
{ {
' . $script . ' ' . $script . '
} }
if (!$filter_script || ! m/$filter_script/) if ((!$filter_script || ! m/$filter_script/) &&
(!$grep_script || m/$grep_script/))
{ {
$filtered_contents .= $_."\n"; $filtered_contents .= $_."\n";
} }
......
call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal");
"engine: aria crash point: ddl_log_drop_before_delete_table position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_delete_table position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"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 */
"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 */
"engine: aria crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
"engine: aria crash point: ddl_log_drop_before_binlog position: 3"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
"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 */
"engine: aria crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
"engine: aria crash point: ddl_log_drop_after_binlog position: 3"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
Warnings:
Note 1051 Unknown table 'test.t1,test.t2,test.ts'
--source include/have_debug.inc
--source include/have_log_bin.inc
--source include/not_valgrind.inc
#
# Testing of atomic drop 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=1;
let $engines='aria';
let $crash_count=7;
let $crash_points='ddl_log_drop_before_delete_table', 'ddl_log_drop_after_delete_table', 'ddl_log_drop_before_drop_trigger', 'ddl_log_drop_before_drop_trigger2', 'ddl_log_drop_after_drop_trigger', 'ddl_log_drop_before_binlog', 'ddl_log_drop_after_binlog';
# Number of drops in the tested statement
let $drops=3;
let $old_debug=`select @@debug_dbug`;
let $e=0;
let $keep_include_silent=1;
let $grep_script=DROP TABLE;
--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;
}
let $c=0;
while ($c < $crash_count)
{
inc $c;
let $crash=`select ELT($c, $crash_points)`;
let $r=0;
while ($r < $drops)
{
inc $r;
--eval set @@default_storage_engine=$default_engine
--eval create table t1 (a int not null) $extra_option;
--eval create table t2 (b int not null) $extra_option;
create sequence ts;
insert into t1 values(1);
insert into t2 values(2);
flush tables;
delimiter |;
create trigger t1_trg before insert on t1 for each row
begin
if isnull(new.a) then
set new.a:= 1000;
end if;
end|
create trigger t2_trg before insert on t2 for each row
begin
if isnull(new.b) then
set new.b:= 2000;
end if;
end|
delimiter ;|
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 table t1,t2,ts;
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!";
}
# Check which tables still exists
--list_files $MYSQLD_DATADIR/test t*
--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
drop table if exists t1,t2,ts;
--enable_warnings
}
}
}
drop table if exists t1,t2,ts;
--enable_query_log
call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal");
"engine: myisam crash point: ddl_log_drop_before_delete_table position: 1"
t2.MYD
t2.MYI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: myisam crash point: ddl_log_drop_after_delete_table position: 1"
t2.MYD
t2.MYI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: myisam crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.MYD
t2.MYI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: myisam crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.MYD
t2.MYI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: myisam crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.MYD
t2.MYI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"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 */
"engine: myisam crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: myisam crash point: ddl_log_drop_after_binlog position: 1"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: myisam crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: aria crash point: ddl_log_drop_before_delete_table position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"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 */
"engine: aria crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: aria crash point: ddl_log_drop_after_binlog position: 1"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: aria crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: aria_notrans crash point: ddl_log_drop_before_delete_table position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: aria_notrans crash point: ddl_log_drop_after_delete_table position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: aria_notrans crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: aria_notrans crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"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 */
"engine: aria_notrans crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: aria_notrans crash point: ddl_log_drop_after_binlog position: 1"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: aria_notrans crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: innodb crash point: ddl_log_drop_before_delete_table position: 1"
t2.TRG
t2.frm
t2.ibd
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: innodb crash point: ddl_log_drop_after_delete_table position: 1"
t2.TRG
t2.frm
t2.ibd
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: innodb crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.TRG
t2.frm
t2.ibd
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: innodb crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.TRG
t2.frm
t2.ibd
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: innodb crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.TRG
t2.frm
t2.ibd
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"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 */
"engine: innodb crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: innodb crash point: ddl_log_drop_after_binlog position: 1"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: innodb crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: csv crash point: ddl_log_drop_before_delete_table position: 1"
t2.CSM
t2.CSV
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: csv crash point: ddl_log_drop_after_delete_table position: 1"
t2.CSM
t2.CSV
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: csv crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.CSM
t2.CSV
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: csv crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.CSM
t2.CSV
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"engine: csv crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.CSM
t2.CSV
t2.TRG
t2.frm
t2_trg.TRN
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"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 */
"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 */
"engine: csv crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: csv crash point: ddl_log_drop_after_binlog position: 1"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
"engine: csv crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
Warnings:
Note 1051 Unknown table 'test.t1,test.t2'
--source include/have_debug.inc
--source include/have_innodb.inc
--source include/have_csv.inc
--source include/have_log_bin.inc
--source include/not_valgrind.inc
#
# Testing of atomic drop 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=5;
let $engines='myisam','aria','aria_notrans','innodb','csv';
let $crash_count=7;
let $crash_points='ddl_log_drop_before_delete_table', 'ddl_log_drop_after_delete_table', 'ddl_log_drop_before_drop_trigger', 'ddl_log_drop_before_drop_trigger2', 'ddl_log_drop_after_drop_trigger', 'ddl_log_drop_before_binlog', 'ddl_log_drop_after_binlog';
# Number of drops in the tested statement
let $drops=2;
let $old_debug=`select @@debug_dbug`;
let $e=0;
let $keep_include_silent=1;
let $grep_script=DROP TABLE;
--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;
}
let $c=0;
while ($c < $crash_count)
{
inc $c;
let $crash=`select ELT($c, $crash_points)`;
let $r=0;
while ($r < $drops)
{
inc $r;
--eval set @@default_storage_engine=$default_engine
--eval create table t1 (a int not null) $extra_option;
--eval create table t2 (b int not null) $extra_option;
insert into t1 values(1);
insert into t2 values(2);
flush tables;
delimiter |;
create trigger t1_trg before insert on t1 for each row
begin
if isnull(new.a) then
set new.a:= 1000;
end if;
end|
create trigger t2_trg before insert on t2 for each row
begin
if isnull(new.b) then
set new.b:= 2000;
end if;
end|
delimiter ;|
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 table t1,t2;
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!";
}
# Check which tables still exists
--list_files $MYSQLD_DATADIR/test t*
--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
drop table if exists t1,t2;
--enable_warnings
}
}
}
drop table if exists t1,t2;
--enable_query_log
"engine: aria crash point: ddl_log_drop_before_delete_view position: 1"
v2.frm
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1` /* generated by ddl recovery */
"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 */
"engine: aria crash point: ddl_log_drop_after_delete_view position: 1"
v2.frm
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1` /* generated by ddl recovery */
"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 */
"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 */
"engine: aria crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2
"engine: aria crash point: ddl_log_drop_after_binlog position: 1"
master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2
"engine: aria crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2
--source include/have_debug.inc
--source include/have_log_bin.inc
--source include/not_valgrind.inc
#
# Testing of atomic drop of view with crashes in a lot of different places
#
let $MYSQLD_DATADIR= `SELECT @@datadir`;
let $engine_count=1;
let $engines='aria';
let $crash_count=4;
let $crash_points='ddl_log_drop_before_delete_view', 'ddl_log_drop_after_delete_view', 'ddl_log_drop_before_binlog', 'ddl_log_drop_after_binlog';
# Number of drops in the tested statement
let $drops=2;
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;
}
--eval set @@default_storage_engine=$default_engine
--eval create table t1 (a int not null) $extra_option;
--eval create table t2 (b int not null) $extra_option;
insert into t1 values(1);
insert into t2 values(2);
flush tables;
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 view v1 as select * from t1;
create view v2 as select * from t1;
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 VIEW v1,v2;
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!";
}
# Check which tables still exists
--list_files $MYSQLD_DATADIR/test v*
--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 views
--disable_warnings
drop view if exists v1,v2;
--enable_warnings
}
}
drop table t1,t2;
}
--enable_query_log
...@@ -506,6 +506,7 @@ master-bin.000001 # Query # # COMMIT ...@@ -506,6 +506,7 @@ master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `mysql`; DELETE FROM db WHERE host='localhost' AND user='@#@' master-bin.000001 # Query # # use `mysql`; DELETE FROM db WHERE host='localhost' AND user='@#@'
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
master-bin.000001 # Rotate # # master-bin.000002;pos=POS
drop table t1,t2,t3,tt1; drop table t1,t2,t3,tt1;
reset master; reset master;
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
......
...@@ -39,9 +39,9 @@ stop slave 'master1'; ...@@ -39,9 +39,9 @@ stop slave 'master1';
--let $datadir = `SELECT @@datadir` --let $datadir = `SELECT @@datadir`
let read_master_log_pos=`select $binlog_start_pos + 590`; let read_master_log_pos=`select $binlog_start_pos + 599`;
let relay_log_pos=`select 2*$binlog_start_pos + 634`; let relay_log_pos=`select 2*$binlog_start_pos + 643`;
let relay_log_space=`select 3*$binlog_start_pos + 696`; let relay_log_space=`select 3*$binlog_start_pos + 705`;
--replace_result $SERVER_MYPORT_1 MYPORT_1 $read_master_log_pos <read_master_log_pos> $relay_log_pos <relay_log_pos> $relay_log_space <relay_log_space> --replace_result $SERVER_MYPORT_1 MYPORT_1 $read_master_log_pos <read_master_log_pos> $relay_log_pos <relay_log_pos> $relay_log_space <relay_log_space>
show slave 'master1' status; show slave 'master1' status;
--list_files $datadir mysqld* --list_files $datadir mysqld*
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "sql_statistics.h" // rename_table_in_stats_tables #include "sql_statistics.h" // rename_table_in_stats_tables
#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 <mysys_err.h> // EE_LINK #include <mysys_err.h> // EE_LINK
...@@ -81,17 +82,19 @@ uchar ddl_log_file_magic[]= ...@@ -81,17 +82,19 @@ uchar ddl_log_file_magic[]=
/* Action names for ddl_log_action_code */ /* Action names for ddl_log_action_code */
const char *ddl_log_action_name[DDL_LOG_LAST_ACTION]= const char *ddl_log_action_name[]=
{ {
"Unknown", "partitioning delete", "partitioning rename", "Unknown", "partitioning delete", "partitioning rename",
"partitioning replace", "partitioning exchange", "partitioning replace", "partitioning exchange",
"rename table", "rename view" "rename table", "rename view",
"initialize drop table", "drop table",
"initialize drop view", "drop view"
}; };
/* 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]=
{ {
1, 1, 2, 3, 4, 1 0, 1, 1, 2, 3, 4, 1, 1, 3, 1, 1
}; };
...@@ -109,6 +112,7 @@ struct st_global_ddl_log ...@@ -109,6 +112,7 @@ struct st_global_ddl_log
}; };
st_global_ddl_log global_ddl_log; st_global_ddl_log global_ddl_log;
String ddl_drop_query; // Used during startup recovery
mysql_mutex_t LOCK_gdl; mysql_mutex_t LOCK_gdl;
...@@ -285,6 +289,19 @@ static bool update_phase(uint entry_pos, uchar phase) ...@@ -285,6 +289,19 @@ static bool update_phase(uint entry_pos, uchar phase)
} }
static bool update_next_entry_pos(uint entry_pos, uint next_entry)
{
uchar buff[4];
DBUG_ENTER("update_next_entry_pos");
int4store(buff, next_entry);
DBUG_RETURN(mysql_file_pwrite(global_ddl_log.file_id, buff, sizeof(buff),
global_ddl_log.io_size * entry_pos +
DDL_LOG_NEXT_ENTRY_POS,
MYF(MY_WME | MY_NABP)));
}
static bool update_xid(uint entry_pos, ulonglong xid) static bool update_xid(uint entry_pos, ulonglong xid)
{ {
uchar buff[8]; uchar buff[8];
...@@ -1130,6 +1147,122 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, ...@@ -1130,6 +1147,122 @@ 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:
{
LEX_CSTRING *comment= &ddl_log_entry->tmp_name;
ddl_drop_query.length(0);
ddl_drop_query.set_charset(system_charset_info);
ddl_drop_query.append(STRING_WITH_LEN("DROP TABLE IF EXISTS "));
if (comment->length)
{
ddl_drop_query.append(comment);
ddl_drop_query.append(' ');
}
/* We don't increment phase as we want to retry this in case of crash */
break;
}
case DDL_LOG_DROP_TABLE_ACTION:
{
LEX_CSTRING db, table, path;
db= ddl_log_entry->db;
table= ddl_log_entry->name;
/* Note that path is without .frm extension */
path= ddl_log_entry->tmp_name;
switch (ddl_log_entry->phase) {
case DDL_DROP_PHASE_TABLE:
if (hton)
{
if ((error= hton->drop_table(hton, path.str)))
{
if (!non_existing_table_error(error))
break;
error= -1;
}
}
else
error= ha_delete_table_force(thd, path.str, &db, &table);
if (error <= 0)
{
/* Not found or already deleted. Delete .frm if it exists */
strxnmov(to_path, sizeof(to_path)-1, path.str, reg_ext, NullS);
mysql_file_delete(key_file_frm, to_path, MYF(MY_WME|MY_IGNORE_ENOENT));
}
if (ddl_log_increment_phase_no_lock(entry_pos))
break;
(void) ddl_log_sync_no_lock();
/* Fall through */
case DDL_DROP_PHASE_TRIGGER:
Table_triggers_list::drop_all_triggers(thd, &db, &table,
MYF(MY_WME | MY_IGNORE_ENOENT));
if (ddl_log_increment_phase_no_lock(entry_pos))
break;
(void) ddl_log_sync_no_lock();
/* Fall through */
case DDL_DROP_PHASE_BINLOG:
append_identifier(thd, &ddl_drop_query, &db);
ddl_drop_query.append('.');
append_identifier(thd, &ddl_drop_query, &table);
ddl_drop_query.append(',');
/* We don't increment phase as we want to retry this in case of crash */
if (!ddl_log_entry->next_entry && mysql_bin_log.is_open())
{
/* Last drop table. Write query to binlog */
LEX_CSTRING end_comment=
{ STRING_WITH_LEN(" /* generated by ddl recovery */")};
ddl_drop_query.length(ddl_drop_query.length()-1);
ddl_drop_query.append(&end_comment);
mysql_mutex_unlock(&LOCK_gdl);
(void) thd->binlog_query(THD::STMT_QUERY_TYPE, ddl_drop_query.ptr(),
ddl_drop_query.length(), TRUE, FALSE,
FALSE, 0);
mysql_mutex_lock(&LOCK_gdl);
}
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:
{
LEX_CSTRING db, table, path;
db= ddl_log_entry->db;
table= ddl_log_entry->name;
/* Note that for views path is WITH .frm extension */
path= ddl_log_entry->tmp_name;
mysql_file_delete(key_file_frm, path.str, MYF(MY_WME|MY_IGNORE_ENOENT));
append_identifier(thd, &ddl_drop_query, &db);
ddl_drop_query.append('.');
append_identifier(thd, &ddl_drop_query, &table);
ddl_drop_query.append(',');
if (!ddl_log_entry->next_entry)
{
/* Last drop view. Write query to binlog */
LEX_CSTRING end_comment=
{ STRING_WITH_LEN(" /* generated by ddl recovery */")};
ddl_drop_query.length(ddl_drop_query.length()-1);
ddl_drop_query.append(&end_comment);
mysql_mutex_unlock(&LOCK_gdl);
(void) thd->binlog_query(THD::STMT_QUERY_TYPE, ddl_drop_query.ptr(),
ddl_drop_query.length(), TRUE, FALSE,
FALSE, 0);
mysql_mutex_lock(&LOCK_gdl);
}
break;
}
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
break; break;
...@@ -1298,9 +1431,14 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry, ...@@ -1298,9 +1431,14 @@ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry,
uchar *pos, *end; uchar *pos, *end;
DBUG_ENTER("ddl_log_write_entry"); DBUG_ENTER("ddl_log_write_entry");
*active_entry= 0;
mysql_mutex_assert_owner(&LOCK_gdl); mysql_mutex_assert_owner(&LOCK_gdl);
if (!global_ddl_log.open) DBUG_ASSERT(global_ddl_log.open);
if (unlikely(!global_ddl_log.open))
{
my_error(ER_INTERNAL_ERROR, MYF(0), "ddl log not initialized");
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
}
ddl_log_entry->entry_type= DDL_LOG_ENTRY_CODE; ddl_log_entry->entry_type= DDL_LOG_ENTRY_CODE;
set_global_from_ddl_log_entry(ddl_log_entry); set_global_from_ddl_log_entry(ddl_log_entry);
...@@ -1383,7 +1521,7 @@ bool ddl_log_write_execute_entry(uint first_entry, ...@@ -1383,7 +1521,7 @@ bool ddl_log_write_execute_entry(uint first_entry,
if (ddl_log_get_free_entry(active_entry)) if (ddl_log_get_free_entry(active_entry))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
got_free_entry= TRUE; got_free_entry= TRUE;
} }
if (write_ddl_log_file_entry((*active_entry)->entry_pos)) if (write_ddl_log_file_entry((*active_entry)->entry_pos))
{ {
if (got_free_entry) if (got_free_entry)
...@@ -1509,6 +1647,7 @@ bool ddl_log_close_binlogged_events(HASH *xids) ...@@ -1509,6 +1647,7 @@ bool ddl_log_close_binlogged_events(HASH *xids)
{ {
if (read_ddl_log_entry(i, &ddl_log_entry)) if (read_ddl_log_entry(i, &ddl_log_entry))
break; // Read error. Stop reading break; // Read error. Stop reading
DBUG_PRINT("xid",("xid: %llu", ddl_log_entry.xid));
if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE && if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE &&
ddl_log_entry.xid != 0 && ddl_log_entry.xid != 0 &&
my_hash_search(xids, (uchar*) &ddl_log_entry.xid, my_hash_search(xids, (uchar*) &ddl_log_entry.xid,
...@@ -1562,6 +1701,7 @@ int ddl_log_execute_recovery() ...@@ -1562,6 +1701,7 @@ 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();
thd->set_query(recover_query_string, strlen(recover_query_string)); thd->set_query(recover_query_string, strlen(recover_query_string));
...@@ -1599,6 +1739,7 @@ int ddl_log_execute_recovery() ...@@ -1599,6 +1739,7 @@ int ddl_log_execute_recovery()
count++; count++;
} }
} }
ddl_drop_query.free();
close_ddl_log(); close_ddl_log();
mysql_mutex_unlock(&LOCK_gdl); mysql_mutex_unlock(&LOCK_gdl);
thd->reset_query(); thd->reset_query();
...@@ -1682,6 +1823,7 @@ void ddl_log_release_entries(DDL_LOG_STATE *ddl_log_state) ...@@ -1682,6 +1823,7 @@ void ddl_log_release_entries(DDL_LOG_STATE *ddl_log_state)
next= log_entry->next_active_log_entry; next= log_entry->next_active_log_entry;
ddl_log_release_memory_entry(log_entry); ddl_log_release_memory_entry(log_entry);
} }
ddl_log_state->list= 0;
if (ddl_log_state->execute_entry) if (ddl_log_state->execute_entry)
{ {
...@@ -1779,6 +1921,33 @@ bool ddl_log_update_xid(DDL_LOG_STATE *state, ulonglong xid) ...@@ -1779,6 +1921,33 @@ bool ddl_log_update_xid(DDL_LOG_STATE *state, ulonglong xid)
} }
/*
Write ddl_log_entry and write or update ddl_execute_entry
*/
static bool ddl_log_write(DDL_LOG_STATE *ddl_state,
DDL_LOG_ENTRY *ddl_log_entry)
{
int error;
DDL_LOG_MEMORY_ENTRY *log_entry;
DBUG_ENTER("ddl_log_write");
mysql_mutex_lock(&LOCK_gdl);
error= ((ddl_log_write_entry(ddl_log_entry, &log_entry)) ||
ddl_log_write_execute_entry(log_entry->entry_pos,
&ddl_state->execute_entry));
mysql_mutex_unlock(&LOCK_gdl);
if (error)
{
if (log_entry)
ddl_log_release_memory_entry(log_entry);
DBUG_RETURN(1);
}
add_log_entry(ddl_state, log_entry);
DBUG_RETURN(0);
}
/** /**
Logging of rename table Logging of rename table
*/ */
...@@ -1791,13 +1960,10 @@ bool ddl_log_rename_table(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -1791,13 +1960,10 @@ bool ddl_log_rename_table(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *new_alias) const LEX_CSTRING *new_alias)
{ {
DDL_LOG_ENTRY ddl_log_entry; DDL_LOG_ENTRY ddl_log_entry;
DDL_LOG_MEMORY_ENTRY *log_entry;
DBUG_ENTER("ddl_log_rename_file"); DBUG_ENTER("ddl_log_rename_file");
bzero(&ddl_log_entry, sizeof(ddl_log_entry)); bzero(&ddl_log_entry, sizeof(ddl_log_entry));
mysql_mutex_lock(&LOCK_gdl);
ddl_log_entry.action_type= DDL_LOG_RENAME_TABLE_ACTION; ddl_log_entry.action_type= DDL_LOG_RENAME_TABLE_ACTION;
ddl_log_entry.next_entry= ddl_state->list ? ddl_state->list->entry_pos : 0; ddl_log_entry.next_entry= ddl_state->list ? ddl_state->list->entry_pos : 0;
lex_string_set(&ddl_log_entry.handler_name, lex_string_set(&ddl_log_entry.handler_name,
...@@ -1808,20 +1974,7 @@ bool ddl_log_rename_table(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -1808,20 +1974,7 @@ bool ddl_log_rename_table(THD *thd, DDL_LOG_STATE *ddl_state,
ddl_log_entry.from_name= *const_cast<LEX_CSTRING*>(org_alias); ddl_log_entry.from_name= *const_cast<LEX_CSTRING*>(org_alias);
ddl_log_entry.phase= DDL_RENAME_PHASE_TABLE; ddl_log_entry.phase= DDL_RENAME_PHASE_TABLE;
if (ddl_log_write_entry(&ddl_log_entry, &log_entry)) DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry));
goto error;
if (ddl_log_write_execute_entry(log_entry->entry_pos,
&ddl_state->execute_entry))
goto error;
add_log_entry(ddl_state, log_entry);
mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(0);
error:
mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(1);
} }
/* /*
...@@ -1835,13 +1988,10 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -1835,13 +1988,10 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *new_alias) const LEX_CSTRING *new_alias)
{ {
DDL_LOG_ENTRY ddl_log_entry; DDL_LOG_ENTRY ddl_log_entry;
DDL_LOG_MEMORY_ENTRY *log_entry;
DBUG_ENTER("ddl_log_rename_file"); DBUG_ENTER("ddl_log_rename_file");
bzero(&ddl_log_entry, sizeof(ddl_log_entry)); bzero(&ddl_log_entry, sizeof(ddl_log_entry));
mysql_mutex_lock(&LOCK_gdl);
ddl_log_entry.action_type= DDL_LOG_RENAME_VIEW_ACTION; ddl_log_entry.action_type= DDL_LOG_RENAME_VIEW_ACTION;
ddl_log_entry.next_entry= ddl_state->list ? ddl_state->list->entry_pos : 0; ddl_log_entry.next_entry= ddl_state->list ? ddl_state->list->entry_pos : 0;
ddl_log_entry.db= *const_cast<LEX_CSTRING*>(new_db); ddl_log_entry.db= *const_cast<LEX_CSTRING*>(new_db);
...@@ -1849,18 +1999,117 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -1849,18 +1999,117 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state,
ddl_log_entry.from_db= *const_cast<LEX_CSTRING*>(org_db); ddl_log_entry.from_db= *const_cast<LEX_CSTRING*>(org_db);
ddl_log_entry.from_name= *const_cast<LEX_CSTRING*>(org_alias); ddl_log_entry.from_name= *const_cast<LEX_CSTRING*>(org_alias);
DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry));
}
/**
Logging of DROP TABLE and DROP VIEW
Note that in contrast to rename, which are re-done in reverse order,
deletes are stored in a linked list according to delete order. This
is to ensure that the tables, for the query generated for binlog,
is in original delete order.
*/
static bool ddl_log_drop_init(THD *thd, DDL_LOG_STATE *ddl_state,
ddl_log_action_code action_code,
const LEX_CSTRING *comment)
{
DDL_LOG_ENTRY ddl_log_entry;
DBUG_ENTER("ddl_log_drop_file");
bzero(&ddl_log_entry, sizeof(ddl_log_entry));
ddl_log_entry.action_type= action_code;
ddl_log_entry.next_entry= 0;
ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(comment);
ddl_log_entry.phase= 0;
DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry));
}
bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *comment)
{
return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_TABLE_INIT_ACTION,
comment);
}
bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state)
{
LEX_CSTRING comment= {0,0};
return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_VIEW_INIT_ACTION,
&comment);
}
static bool ddl_log_drop(THD *thd, DDL_LOG_STATE *ddl_state,
ddl_log_action_code action_code,
uint phase,
handlerton *hton,
const LEX_CSTRING *path,
const LEX_CSTRING *db,
const LEX_CSTRING *table)
{
DDL_LOG_ENTRY ddl_log_entry;
DDL_LOG_MEMORY_ENTRY *log_entry;
DBUG_ENTER("ddl_log_drop");
DBUG_ASSERT(ddl_state->list);
bzero(&ddl_log_entry, sizeof(ddl_log_entry));
ddl_log_entry.action_type= action_code;
if (hton)
lex_string_set(&ddl_log_entry.handler_name,
ha_resolve_storage_engine_name(hton));
ddl_log_entry.db= *const_cast<LEX_CSTRING*>(db);
ddl_log_entry.name= *const_cast<LEX_CSTRING*>(table);
ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(path);
ddl_log_entry.phase= (uchar) phase;
mysql_mutex_lock(&LOCK_gdl);
if (ddl_log_write_entry(&ddl_log_entry, &log_entry)) if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
goto error; goto error;
if (ddl_log_write_execute_entry(log_entry->entry_pos, (void) ddl_log_sync_no_lock();
&ddl_state->execute_entry)) if (update_next_entry_pos(ddl_state->list->entry_pos,
log_entry->entry_pos))
{
ddl_log_release_memory_entry(log_entry);
goto error; goto error;
}
add_log_entry(ddl_state, log_entry);
mysql_mutex_unlock(&LOCK_gdl); mysql_mutex_unlock(&LOCK_gdl);
add_log_entry(ddl_state, log_entry);
DBUG_RETURN(0); DBUG_RETURN(0);
error: error:
mysql_mutex_unlock(&LOCK_gdl); mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
bool ddl_log_drop_table(THD *thd, DDL_LOG_STATE *ddl_state,
handlerton *hton,
const LEX_CSTRING *path,
const LEX_CSTRING *db,
const LEX_CSTRING *table)
{
DBUG_ENTER("ddl_log_drop_table");
DBUG_RETURN(ddl_log_drop(thd, ddl_state,
DDL_LOG_DROP_TABLE_ACTION, DDL_DROP_PHASE_TABLE,
hton, path, db, table));
}
bool ddl_log_drop_view(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *path,
const LEX_CSTRING *db,
const LEX_CSTRING *table)
{
DBUG_ENTER("ddl_log_drop_view");
DBUG_RETURN(ddl_log_drop(thd, ddl_state,
DDL_LOG_DROP_VIEW_ACTION, 0,
(handlerton*) 0, path, db, table));
}
...@@ -46,8 +46,8 @@ enum ddl_log_entry_code ...@@ -46,8 +46,8 @@ enum ddl_log_entry_code
/* /*
When adding things below, also add an entry to ddl_log_entry_phases in When adding things below, also add an entry to ddl_log_action_names and
ddl_log.cc ddl_log_entry_phases in ddl_log.cc
*/ */
enum ddl_log_action_code enum ddl_log_action_code
...@@ -77,7 +77,11 @@ enum ddl_log_action_code ...@@ -77,7 +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_LAST_ACTION /* End marker */ DDL_LOG_DROP_TABLE_INIT_ACTION= 7,
DDL_LOG_DROP_TABLE_ACTION= 8,
DDL_LOG_DROP_VIEW_INIT_ACTION= 9,
DDL_LOG_DROP_VIEW_ACTION= 10,
DDL_LOG_LAST_ACTION /* End marker */
}; };
...@@ -97,6 +101,14 @@ enum enum_ddl_log_rename_table_phase { ...@@ -97,6 +101,14 @@ enum enum_ddl_log_rename_table_phase {
DDL_RENAME_PHASE_TABLE, DDL_RENAME_PHASE_TABLE,
}; };
enum enum_ddl_log_drop_table_phase {
DDL_DROP_PHASE_TABLE=0,
DDL_DROP_PHASE_TRIGGER,
DDL_DROP_PHASE_BINLOG,
DDL_DROP_PHASE_RESET, /* Reset found list of dropped tables */
DDL_DROP_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.
...@@ -204,6 +216,17 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -204,6 +216,17 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *org_alias, const LEX_CSTRING *org_alias,
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,
const LEX_CSTRING *comment);
bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state);
bool ddl_log_drop_table(THD *thd, DDL_LOG_STATE *ddl_state,
handlerton *hton,
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 *path,
const LEX_CSTRING *db,
const LEX_CSTRING *table);
extern mysql_mutex_t LOCK_gdl; extern mysql_mutex_t LOCK_gdl;
#endif /* DDL_LOG_INCLUDED */ #endif /* DDL_LOG_INCLUDED */
...@@ -566,7 +566,13 @@ static int hton_drop_table(handlerton *hton, const char *path) ...@@ -566,7 +566,13 @@ static int hton_drop_table(handlerton *hton, const char *path)
char tmp_path[FN_REFLEN]; char tmp_path[FN_REFLEN];
handler *file= get_new_handler(nullptr, current_thd->mem_root, hton); handler *file= get_new_handler(nullptr, current_thd->mem_root, hton);
if (!file) if (!file)
return ENOMEM; {
/*
If file is not defined it means that the engine can't create a
handler if share is not set or we got an out of memory error
*/
return my_errno == ENOMEM ? ENOMEM : ENOENT;
}
path= get_canonical_filename(file, path, tmp_path); path= get_canonical_filename(file, path, tmp_path);
int error= file->delete_table(path); int error= file->delete_table(path);
delete file; delete file;
......
...@@ -9982,6 +9982,7 @@ int TC_LOG::using_heuristic_recover() ...@@ -9982,6 +9982,7 @@ int TC_LOG::using_heuristic_recover()
int TC_LOG_BINLOG::open(const char *opt_name) int TC_LOG_BINLOG::open(const char *opt_name)
{ {
int error= 1; int error= 1;
DBUG_ENTER("TC_LOG_BINLOG::open");
DBUG_ASSERT(total_ha_2pc > 1); DBUG_ASSERT(total_ha_2pc > 1);
DBUG_ASSERT(opt_name); DBUG_ASSERT(opt_name);
...@@ -9991,7 +9992,7 @@ int TC_LOG_BINLOG::open(const char *opt_name) ...@@ -9991,7 +9992,7 @@ int TC_LOG_BINLOG::open(const char *opt_name)
{ {
/* There was a failure to open the index file, can't open the binlog */ /* There was a failure to open the index file, can't open the binlog */
cleanup(); cleanup();
return 1; DBUG_RETURN(1);
} }
if (using_heuristic_recover()) if (using_heuristic_recover())
...@@ -10001,12 +10002,12 @@ int TC_LOG_BINLOG::open(const char *opt_name) ...@@ -10001,12 +10002,12 @@ int TC_LOG_BINLOG::open(const char *opt_name)
open(opt_name, 0, 0, WRITE_CACHE, max_binlog_size, 0, TRUE); open(opt_name, 0, 0, WRITE_CACHE, max_binlog_size, 0, TRUE);
mysql_mutex_unlock(&LOCK_log); mysql_mutex_unlock(&LOCK_log);
cleanup(); cleanup();
return 1; DBUG_RETURN(1);
} }
error= do_binlog_recovery(opt_name, true); error= do_binlog_recovery(opt_name, true);
binlog_state_recover_done= true; binlog_state_recover_done= true;
return error; DBUG_RETURN(error);
} }
/** This is called on shutdown, after ha_panic. */ /** This is called on shutdown, after ha_panic. */
...@@ -10536,6 +10537,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, ...@@ -10536,6 +10537,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
Query_log_event *query_ev= (Query_log_event*) ev; Query_log_event *query_ev= (Query_log_event*) ev;
if (query_ev->xid) if (query_ev->xid)
{ {
DBUG_PRINT("QQ", ("xid: %llu xid"));
DBUG_ASSERT(sizeof(query_ev->xid) == sizeof(my_xid)); DBUG_ASSERT(sizeof(query_ev->xid) == sizeof(my_xid));
uchar *x= (uchar *) memdup_root(&mem_root, uchar *x= (uchar *) memdup_root(&mem_root,
(uchar*) &query_ev->xid, (uchar*) &query_ev->xid,
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include "tztime.h" #include "tztime.h"
#include "sql_insert.h" // binlog_drop_table #include "sql_insert.h" // binlog_drop_table
#include "ddl_log.h" #include "ddl_log.h"
#include "debug_sync.h" // debug_crash_here()
#include <algorithm> #include <algorithm>
#ifdef __WIN__ #ifdef __WIN__
...@@ -1139,9 +1140,11 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1139,9 +1140,11 @@ 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);
uint not_found_errors= 0; DDL_LOG_STATE ddl_log_state;
const char *comment_start;
uint not_found_errors= 0, table_count= 0, non_temp_tables_count= 0;
int error= 0; int error= 0;
int non_temp_tables_count= 0; uint32 comment_len;
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0; bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
bool non_tmp_table_deleted= 0; bool non_tmp_table_deleted= 0;
bool is_drop_tmp_if_exists_added= 0; bool is_drop_tmp_if_exists_added= 0;
...@@ -1154,6 +1157,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1154,6 +1157,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
DBUG_ENTER("mysql_rm_table_no_locks"); DBUG_ENTER("mysql_rm_table_no_locks");
unknown_tables.length(0); unknown_tables.length(0);
comment_len= get_comment(thd, if_exists ? 17:9, &comment_start);
/* /*
Prepares the drop statements that will be written into the binary Prepares the drop statements that will be written into the binary
log as follows: log as follows:
...@@ -1204,6 +1209,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1204,6 +1209,7 @@ 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)
{ {
...@@ -1213,6 +1219,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1213,6 +1219,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool table_dropped= 0; bool table_dropped= 0;
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};
handlerton *hton= 0; handlerton *hton= 0;
Table_type table_type; Table_type table_type;
size_t path_length= 0; size_t path_length= 0;
...@@ -1347,6 +1354,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1347,6 +1354,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
continue; continue;
} }
lex_string_set3(&cpath, path, (size_t) (path_end - path));
{ {
char engine_buf[NAME_CHAR_LEN + 1]; char engine_buf[NAME_CHAR_LEN + 1];
LEX_CSTRING engine= { engine_buf, 0 }; LEX_CSTRING engine= { engine_buf, 0 };
...@@ -1363,6 +1372,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1363,6 +1372,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
thd->replication_flags= 0; thd->replication_flags= 0;
was_view= table_type == TABLE_TYPE_VIEW; was_view= table_type == TABLE_TYPE_VIEW;
if (!table_count++)
{
LEX_CSTRING comment= {comment_start, (size_t) comment_len};
if (ddl_log_drop_table_init(thd, &ddl_log_state, &comment))
{
error= 1;
goto err;
}
}
if ((table_type == TABLE_TYPE_UNKNOWN) || (was_view && !drop_view) || if ((table_type == TABLE_TYPE_UNKNOWN) || (was_view && !drop_view) ||
(table_type != TABLE_TYPE_SEQUENCE && drop_sequence)) (table_type != TABLE_TYPE_SEQUENCE && drop_sequence))
{ {
...@@ -1376,6 +1396,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1376,6 +1396,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
was_table|= wrong_drop_sequence; was_table|= wrong_drop_sequence;
error= table_type == TABLE_TYPE_UNKNOWN ? ENOENT : -1; error= table_type == TABLE_TYPE_UNKNOWN ? ENOENT : -1;
tdc_remove_table(thd, db.str, table_name.str); tdc_remove_table(thd, db.str, table_name.str);
if (wrong_drop_sequence)
goto report_error;
} }
else else
{ {
...@@ -1411,7 +1433,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1411,7 +1433,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
log_if_exists= 1; log_if_exists= 1;
bool enoent_warning= !dont_log_query && !(hton && hton->discover_table); bool enoent_warning= !dont_log_query && !(hton && hton->discover_table);
error= ha_delete_table(thd, hton, path, &db, &table_name, enoent_warning);
if (ddl_log_drop_table(thd, &ddl_log_state, hton, &cpath, &db,
&table_name))
{
error= -1;
goto err;
}
debug_crash_here("ddl_log_drop_before_delete_table");
error= ha_delete_table(thd, hton, path, &db, &table_name,
enoent_warning);
debug_crash_here("ddl_log_drop_after_delete_table");
if (!error) if (!error)
table_dropped= 1; table_dropped= 1;
...@@ -1473,11 +1505,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1473,11 +1505,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
scan all engines try to drop the table from there. scan all engines try to drop the table from there.
This is to ensure we don't have any partial table files left. This is to ensure we don't have any partial table files left.
*/ */
if (non_existing_table_error(error) && !wrong_drop_sequence) if (non_existing_table_error(error))
{ {
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,
&table_name))
{
error= -1;
goto err;
}
/* Remove extension for delete */ /* Remove extension for delete */
*path_end= '\0'; *path_end= '\0';
ferror= ha_delete_table_force(thd, path, &db, &table_name); ferror= ha_delete_table_force(thd, path, &db, &table_name);
...@@ -1509,13 +1548,19 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1509,13 +1548,19 @@ 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");
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))
{ {
if (Table_triggers_list::drop_all_triggers(thd, &db, &table_name, if (Table_triggers_list::drop_all_triggers(thd, &db, &table_name,
MYF(MY_WME | MY_IGNORE_ENOENT))) MYF(MY_WME | MY_IGNORE_ENOENT)))
error= error ? error : -1; error= error ? error : -1;
} }
debug_crash_here("ddl_log_drop_after_drop_trigger");
report_error:
if (error) if (error)
{ {
StringBuffer<FN_REFLEN> tbl_name(system_charset_info); StringBuffer<FN_REFLEN> tbl_name(system_charset_info);
...@@ -1565,6 +1610,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1565,6 +1610,7 @@ 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 (!dont_log_query && if (!dont_log_query &&
(!error || table_dropped || non_existing_table_error(error))) (!error || table_dropped || non_existing_table_error(error)))
...@@ -1621,6 +1667,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1621,6 +1667,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
query_cache_invalidate3(thd, tables, 0); query_cache_invalidate3(thd, tables, 0);
if (!dont_log_query && mysql_bin_log.is_open()) if (!dont_log_query && mysql_bin_log.is_open())
{ {
debug_crash_here("ddl_log_drop_before_binlog");
if (non_trans_tmp_table_deleted) if (non_trans_tmp_table_deleted)
{ {
/* Chop of the last comma */ /* Chop of the last comma */
...@@ -1648,8 +1695,6 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1648,8 +1695,6 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (non_tmp_table_deleted) if (non_tmp_table_deleted)
{ {
String built_query; String built_query;
const char *comment_start;
uint32 comment_len;
built_query.set_charset(thd->charset()); built_query.set_charset(thd->charset());
built_query.append(STRING_WITH_LEN("DROP ")); built_query.append(STRING_WITH_LEN("DROP "));
...@@ -1659,8 +1704,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1659,8 +1704,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
built_query.append(STRING_WITH_LEN("IF EXISTS ")); built_query.append(STRING_WITH_LEN("IF EXISTS "));
/* Preserve comment in original query */ /* Preserve comment in original query */
if ((comment_len= get_comment(thd, if_exists ? 17:9, if (comment_len)
&comment_start)))
{ {
built_query.append(comment_start, comment_len); built_query.append(comment_start, comment_len);
built_query.append(' '); built_query.append(' ');
...@@ -1670,13 +1714,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1670,13 +1714,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
normal_tables.chop(); normal_tables.chop();
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;
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(),
TRUE, FALSE, FALSE, 0) > 0); TRUE, FALSE, FALSE, 0) > 0);
thd->binlog_xid= 0;
} }
debug_crash_here("ddl_log_drop_after_binlog");
} }
} }
ddl_log_complete(&ddl_log_state);
if (!drop_temporary) if (!drop_temporary)
{ {
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "sql_derived.h" #include "sql_derived.h"
#include "sql_cte.h" // check_dependencies_in_with_clauses() #include "sql_cte.h" // check_dependencies_in_with_clauses()
#include "opt_trace.h" #include "opt_trace.h"
#include "ddl_log.h"
#include "wsrep_mysqld.h" #include "wsrep_mysqld.h"
#include "debug_sync.h" // debug_crash_here #include "debug_sync.h" // debug_crash_here
...@@ -1817,9 +1818,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1817,9 +1818,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
bool delete_error= FALSE, wrong_object_name= FALSE; bool delete_error= FALSE, wrong_object_name= FALSE;
bool some_views_deleted= FALSE; bool some_views_deleted= FALSE;
bool something_wrong= FALSE; bool something_wrong= FALSE;
uint not_exists_count= 0; uint not_exists_count= 0, view_count= 0;
DDL_LOG_STATE ddl_log_state;
DBUG_ENTER("mysql_drop_view"); DBUG_ENTER("mysql_drop_view");
bzero(&ddl_log_state, sizeof(ddl_log_state));
/* /*
We can't allow dropping of unlocked view under LOCK TABLES since this We can't allow dropping of unlocked view under LOCK TABLES since this
might lead to deadlock. But since we can't really lock view with LOCK might lead to deadlock. But since we can't really lock view with LOCK
...@@ -1838,9 +1842,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1838,9 +1842,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
for (view= views; view; view= view->next_local) for (view= views; view; view= view->next_local)
{ {
LEX_CSTRING cpath;
bool not_exist; bool not_exist;
build_table_filename(path, sizeof(path) - 1, size_t length;
view->db.str, view->table_name.str, reg_ext, 0); length= build_table_filename(path, sizeof(path) - 1,
view->db.str, view->table_name.str, reg_ext, 0);
lex_string_set3(&cpath, path, length);
if ((not_exist= my_access(path, F_OK)) || !dd_frm_is_view(thd, path)) if ((not_exist= my_access(path, F_OK)) || !dd_frm_is_view(thd, path))
{ {
...@@ -1861,8 +1868,18 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1861,8 +1868,18 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
not_exists_count++; not_exists_count++;
continue; continue;
} }
if (!view_count++)
{
if (ddl_log_drop_view_init(thd, &ddl_log_state))
DBUG_RETURN(TRUE);
}
if (ddl_log_drop_view(thd, &ddl_log_state, &cpath, &view->db,
&view->table_name))
DBUG_RETURN(TRUE);
debug_crash_here("ddl_log_drop_before_delete_view");
if (unlikely(mysql_file_delete(key_file_frm, path, MYF(MY_WME)))) if (unlikely(mysql_file_delete(key_file_frm, path, MYF(MY_WME))))
delete_error= TRUE; delete_error= TRUE;
debug_crash_here("ddl_log_drop_after_delete_view");
some_views_deleted= TRUE; some_views_deleted= TRUE;
...@@ -1890,10 +1907,16 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1890,10 +1907,16 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
/* if something goes wrong, bin-log with possible error code, /* if something goes wrong, bin-log with possible error code,
otherwise bin-log with error code cleared. otherwise bin-log with error code cleared.
*/ */
debug_crash_here("ddl_log_drop_before_binlog");
thd->binlog_xid= thd->query_id;
ddl_log_update_xid(&ddl_log_state, thd->binlog_xid);
if (unlikely(write_bin_log(thd, !something_wrong, thd->query(), if (unlikely(write_bin_log(thd, !something_wrong, thd->query(),
thd->query_length()))) thd->query_length())))
something_wrong= 1; something_wrong= 1;
thd->binlog_xid= 0;
debug_crash_here("ddl_log_drop_after_binlog");
} }
ddl_log_complete(&ddl_log_state);
if (unlikely(something_wrong)) if (unlikely(something_wrong))
{ {
......
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