diff --git a/mysql-test/suite/rpl/r/rpl_failed_drop_tbl_binlog.result b/mysql-test/suite/rpl/r/rpl_failed_drop_tbl_binlog.result new file mode 100644 index 00000000000..df36fa82e0f --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_failed_drop_tbl_binlog.result @@ -0,0 +1,32 @@ +include/master-slave.inc +[connection master] +create table t1 (a int) engine=innodb; +create table t2 (b longblob) engine=innodb; +create table t3 (c int) engine=innodb; +insert into t2 values (repeat('b',1024*1024)); +insert into t2 select * from t2; +insert into t2 select * from t2; +insert into t2 select * from t2; +insert into t2 select * from t2; +set debug_sync='rm_table_no_locks_before_delete_table SIGNAL nogo WAIT_FOR go EXECUTE 2'; +drop table t1, t2, t3; +connect foo,localhost,root; +set debug_sync='now SIGNAL go'; +kill query CONNECTION_ID; +connection master; +ERROR 70100: Query execution was interrupted +"Tables t2 and t3 should be listed" +SHOW TABLES; +Tables_in_test +t2 +t3 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +connection slave; +drop table t2, t3; +connection master; +set debug_sync='RESET'; +drop table t2, t3; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.test b/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.test new file mode 100644 index 00000000000..281e2a2ab47 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.test @@ -0,0 +1,64 @@ +# ==== Purpose ==== +# +# Check that when the execution of a DROP TABLE command with single table +# fails it should not be written to the binary log. Also test that when the +# execution of DROP TABLE command with multiple tables fails the command +# should be written into the binary log. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Create tables named t1, t2, t3 +# 1 - Execute DROP TABLE t1,t2,t3 command. +# 2 - Kill the DROP TABLE command while it is trying to drop table 't2'. +# 3 - Verify that tables t2,t3 are present after the DROP command execution +# was interrupted. +# 4 - Check that table 't1' is present in binary log as part of DROP +# command. +# +# ==== References ==== +# +# MDEV-20348: DROP TABLE IF EXISTS killed on master but was replicated. +# + +--source include/have_innodb.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +create table t1 (a int) engine=innodb; +create table t2 (b longblob) engine=innodb; +create table t3 (c int) engine=innodb; +insert into t2 values (repeat('b',1024*1024)); +insert into t2 select * from t2; +insert into t2 select * from t2; +insert into t2 select * from t2; +insert into t2 select * from t2; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +let $id=`select connection_id()`; +set debug_sync='rm_table_no_locks_before_delete_table SIGNAL nogo WAIT_FOR go EXECUTE 2'; +send drop table t1, t2, t3; + +connect foo,localhost,root; +set debug_sync='now SIGNAL go'; +let $wait_condition=select 1 from information_schema.processlist where state like 'debug sync point:%'; +source include/wait_condition.inc; +--replace_result $id CONNECTION_ID +eval kill query $id; + +connection master; +error ER_QUERY_INTERRUPTED; +reap; + +--echo "Tables t2 and t3 should be listed" +SHOW TABLES; +--source include/show_binlog_events.inc +--sync_slave_with_master +drop table t2, t3; + +connection master; +set debug_sync='RESET'; +drop table t2, t3; + +source include/rpl_end.inc; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9e302fb762d..be3f9b46c0f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2403,35 +2403,6 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, /* remove .frm file and engine files */ path_length= build_table_filename(path, sizeof(path) - 1, db.str, alias.str, reg_ext, 0); - - /* - This handles the case where a "DROP" was executed and a regular - table "may be" dropped as drop_temporary is FALSE and error is - TRUE. If the error was FALSE a temporary table was dropped and - regardless of the status of drop_temporary a "DROP TEMPORARY" - must be used. - */ - if (!dont_log_query) - { - /* - Note that unless if_exists is TRUE or a temporary table was deleted, - there is no means to know if the statement should be written to the - binary log. See further information on this variable in what follows. - */ - non_tmp_table_deleted= (if_exists ? TRUE : non_tmp_table_deleted); - /* - Don't write the database name if it is the current one (or if - thd->db is NULL). - */ - if (thd->db.str == NULL || cmp(&db, &thd->db) != 0) - { - append_identifier(thd, &built_query, &db); - built_query.append("."); - } - - append_identifier(thd, &built_query, &table->table_name); - built_query.append(","); - } } DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table"); error= 0; @@ -2511,9 +2482,16 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, // Remove extension for delete *(end= path + path_length - reg_ext_length)= '\0'; - error= ha_delete_table(thd, table_type, path, &db, &table->table_name, - !dont_log_query); - if (!error) + if ((error= ha_delete_table(thd, table_type, path, &db, &table->table_name, + !dont_log_query))) + { + if (thd->is_killed()) + { + error= -1; + goto err; + } + } + else { /* Delete the table definition file */ strmov(end,reg_ext); @@ -2557,7 +2535,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (error) { if (wrong_tables.length()) - wrong_tables.append(','); + wrong_tables.append(','); wrong_tables.append(&db); wrong_tables.append('.'); wrong_tables.append(&table->table_name); @@ -2570,6 +2548,22 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, mysql_audit_drop_table(thd, table); } + if (!dont_log_query && !drop_temporary) + { + non_tmp_table_deleted= (if_exists ? TRUE : non_tmp_table_deleted); + /* + Don't write the database name if it is the current one (or if + thd->db is NULL). + */ + if (thd->db.str == NULL || cmp(&db, &thd->db) != 0) + { + append_identifier(thd, &built_query, &db); + built_query.append("."); + } + + append_identifier(thd, &built_query, &table->table_name); + built_query.append(","); + } DBUG_PRINT("table", ("table: %p s: %p", table->table, table->table ? table->table->s : NULL)); }