#At file:///export/home/x/mysql-5.5-bug11765416/ based on revid:build@stripped
3371 Jon Olav Hauglid 2011-03-04
Bug #11765416 (former 58381)
FAILED DROP DATABASE CAN BREAK STATEMENT BASED REPLICATION
The first phase of DROP DATABASE is to delete the tables in the database.
If deletion of one or more of the tables fail (e.g. due to a FOREIGN KEY
constraint), DROP DATABASE will be aborted. However, some tables could
still have been deleted. The problem was that nothing would be written
to the binary log in this case, so any slaves would not delete these tables.
Therefore the master and the slaves would get out of sync.
This patch fixes the problem by making sure that DROP TABLE is written
to the binary log for the tables that were in fact deleted by the failed
DROP DATABASE statement.
Test case added to mysqlbinlog.test.
modified:
mysql-test/r/mysqlbinlog.result
mysql-test/t/mysqlbinlog.test
sql/sql_db.cc
=== modified file 'mysql-test/r/mysqlbinlog.result'
--- a/mysql-test/r/mysqlbinlog.result 2010-12-29 05:22:52 +0000
+++ b/mysql-test/r/mysqlbinlog.result 2011-03-04 15:28:30 +0000
@@ -903,3 +903,26 @@ master-bin.000002 # Query # # CREATE DAT
master-bin.000002 # Query # # use `test1`; CREATE TABLE t1(id int)
master-bin.000002 # Query # # use `test1`; DROP TABLE `t1` /* generated by server */
master-bin.000002 # Query # # DROP DATABASE test1
+USE test;
+#
+# Bug#11765416 58381: FAILED DROP DATABASE CAN BREAK STATEMENT
+# BASED REPLICATION
+#
+DROP DATABASE IF EXISTS db1;
+DROP TABLE IF EXISTS t3;
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (a INT);
+CREATE TABLE db1.t2 (b INT, KEY(b)) engine=innodb;
+CREATE TABLE t3 (a INT, KEY (a), FOREIGN KEY(a) REFERENCES db1.t2(b))
+engine=innodb;
+RESET MASTER;
+DROP DATABASE db1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
+SHOW TABLES FROM db1;
+Tables_in_db1
+t2
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `db1`; drop table `t1`
+DROP TABLE t3;
+DROP DATABASE db1;
=== modified file 'mysql-test/t/mysqlbinlog.test'
--- a/mysql-test/t/mysqlbinlog.test 2010-12-29 05:22:52 +0000
+++ b/mysql-test/t/mysqlbinlog.test 2011-03-04 15:28:30 +0000
@@ -526,4 +526,32 @@ exec $MYSQL_BINLOG $MYSQLD_DATADIR/$mast
let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
source include/show_binlog_events.inc;
+USE test;
+let $binlog_file=;
+
+--echo #
+--echo # Bug#11765416 58381: FAILED DROP DATABASE CAN BREAK STATEMENT
+--echo # BASED REPLICATION
+--echo #
+
+--disable_warnings
+DROP DATABASE IF EXISTS db1;
+DROP TABLE IF EXISTS t3;
+--enable_warnings
+
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (a INT);
+CREATE TABLE db1.t2 (b INT, KEY(b)) engine=innodb;
+CREATE TABLE t3 (a INT, KEY (a), FOREIGN KEY(a) REFERENCES db1.t2(b))
+ engine=innodb;
+RESET MASTER;
+
+--error ER_ROW_IS_REFERENCED
+DROP DATABASE db1; # Fails because of the fk
+SHOW TABLES FROM db1; # t1 was dropped, t2 remains
+--source include/show_binlog_events.inc # Check that the binlog drops t1
+
+# Cleanup
+DROP TABLE t3;
+DROP DATABASE db1;
=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc 2010-12-10 11:32:58 +0000
+++ b/sql/sql_db.cc 2011-03-04 15:28:30 +0000
@@ -833,12 +833,9 @@ bool mysql_rm_db(THD *thd,char *db,bool
}
thd->push_internal_handler(&err_handler);
- if (thd->killed ||
- (tables && mysql_rm_table_no_locks(thd, tables, true, false, true, true)))
- {
- tables= NULL;
- }
- else
+ if (!thd->killed &&
+ !(tables &&
+ mysql_rm_table_no_locks(thd, tables, true, false, true, true)))
{
/*
We temporarily disable the binary log while dropping the objects
@@ -923,7 +920,7 @@ update_binlog:
thd->server_status|= SERVER_STATUS_DB_DROPPED;
my_ok(thd, deleted_tables);
}
- else if (mysql_bin_log.is_open())
+ else if (mysql_bin_log.is_open() && !silent)
{
char *query, *query_pos, *query_end, *query_data_start;
TABLE_LIST *tbl;
@@ -938,6 +935,16 @@ update_binlog:
for (tbl= tables; tbl; tbl= tbl->next_local)
{
uint tbl_name_len;
+ bool exists;
+
+ // Only write drop table to the binlog for tables that no longer exist.
+ if (check_if_table_exists(thd, tbl, &exists))
+ {
+ error= true;
+ goto exit;
+ }
+ if (exists)
+ continue;
/* 3 for the quotes and the comma*/
tbl_name_len= strlen(tbl->table_name) + 3;
Attachment: [text/bzr-bundle] bzr/jon.hauglid@oracle.com-20110304152830-k24dd5u0909gf7ns.bundle