Commit f94e7288 authored by Jon Olav Hauglid's avatar Jon Olav Hauglid

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 binlog.binlog_database.test.
parent dd14e376
...@@ -30,3 +30,30 @@ drop table tt1, t1; ...@@ -30,3 +30,30 @@ drop table tt1, t1;
source include/show_binlog_events.inc; source include/show_binlog_events.inc;
FLUSH STATUS; FLUSH STATUS;
--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;
...@@ -39,6 +39,28 @@ master-bin.000001 # Query # # COMMIT ...@@ -39,6 +39,28 @@ master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE `tt1` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE `tt1` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
FLUSH STATUS; FLUSH STATUS;
#
# 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;
set binlog_format=mixed; set binlog_format=mixed;
reset master; reset master;
create database testing_1; create database testing_1;
...@@ -80,6 +102,28 @@ master-bin.000001 # Query # # COMMIT ...@@ -80,6 +102,28 @@ master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE `tt1` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE `tt1` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
FLUSH STATUS; FLUSH STATUS;
#
# 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;
set binlog_format=row; set binlog_format=row;
reset master; reset master;
create database testing_1; create database testing_1;
...@@ -122,6 +166,28 @@ master-bin.000001 # Query # # COMMIT ...@@ -122,6 +166,28 @@ master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tt1` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tt1` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
FLUSH STATUS; FLUSH STATUS;
#
# 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;
show databases; show databases;
Database Database
information_schema information_schema
......
/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -833,12 +833,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -833,12 +833,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
} }
thd->push_internal_handler(&err_handler); thd->push_internal_handler(&err_handler);
if (thd->killed || if (!thd->killed &&
(tables && mysql_rm_table_no_locks(thd, tables, true, false, true, true))) !(tables &&
{ mysql_rm_table_no_locks(thd, tables, true, false, true, true)))
tables= NULL;
}
else
{ {
/* /*
We temporarily disable the binary log while dropping the objects We temporarily disable the binary log while dropping the objects
...@@ -923,7 +920,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -923,7 +920,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
thd->server_status|= SERVER_STATUS_DB_DROPPED; thd->server_status|= SERVER_STATUS_DB_DROPPED;
my_ok(thd, deleted_tables); 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; char *query, *query_pos, *query_end, *query_data_start;
TABLE_LIST *tbl; TABLE_LIST *tbl;
...@@ -938,6 +935,16 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -938,6 +935,16 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
for (tbl= tables; tbl; tbl= tbl->next_local) for (tbl= tables; tbl; tbl= tbl->next_local)
{ {
uint tbl_name_len; 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*/ /* 3 for the quotes and the comma*/
tbl_name_len= strlen(tbl->table_name) + 3; tbl_name_len= strlen(tbl->table_name) + 3;
......
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