Skip to content

Commit 5da083e

Browse files
author
s.sujatha
committed
Bug#20041860: SLAVE ERROR WHEN DROP DATABASE
Fix: === Backport Bug#11756194 to mysql-5.5. slave breaks if 'drop database' fails on master and mismatched tables on slave. 'DROP TABLE <deleted tables>' was binlogged when 'DROP DATABASE' failed and at least one table was deleted from the database. The log event would lead slave SQL thread stop if some of the tables did not exist on slave. After this patch, It is always binlogged with 'IF EXISTS' option.
1 parent 901ce53 commit 5da083e

File tree

5 files changed

+150
-5
lines changed

5 files changed

+150
-5
lines changed

mysql-test/extra/binlog_tests/database.test

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,47 @@ source include/show_binlog_events.inc;
3131

3232
FLUSH STATUS;
3333

34+
--echo
35+
--echo # 'DROP TABLE IF EXISTS <deleted tables>' is binlogged
36+
--echo # when 'DROP DATABASE' fails and at least one table is deleted
37+
--echo # from the database.
38+
RESET MASTER;
39+
CREATE DATABASE testing_1;
40+
USE testing_1;
41+
CREATE TABLE t1(c1 INT);
42+
CREATE TABLE t2(c1 INT);
43+
44+
let $prefix= `SELECT UUID()`;
45+
--echo # Create a file in the database directory
46+
--replace_result $prefix FAKE_FILE
47+
eval SELECT 'hello' INTO OUTFILE 'fake_file.$prefix';
48+
49+
--echo
50+
--echo # 'DROP DATABASE' will fail if there is any other file in the the
51+
--echo # database directory
52+
53+
# Use '/' instead of '\' in the error message. On windows platform, dir is
54+
# formed with '\'.
55+
--replace_regex /\\testing_1\\*/\/testing_1\//
56+
--error 1010
57+
DROP DATABASE testing_1;
58+
let $wait_binlog_event= DROP TABLE IF EXIST;
59+
source include/wait_for_binlog_event.inc;
60+
let $MYSQLD_DATADIR= `SELECT @@datadir`;
61+
62+
--echo
63+
--echo # Remove the fake file.
64+
--remove_file $MYSQLD_DATADIR/testing_1/fake_file.$prefix
65+
--echo # Now we can drop the database.
66+
DROP DATABASE testing_1;
67+
3468

3569
--echo #
3670
--echo # Bug#11765416 58381: FAILED DROP DATABASE CAN BREAK STATEMENT
3771
--echo # BASED REPLICATION
3872
--echo #
3973

74+
USE test;
4075
--disable_warnings
4176
DROP DATABASE IF EXISTS db1;
4277
DROP TABLE IF EXISTS t3;

mysql-test/suite/binlog/r/binlog_database.result

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,31 @@ master-bin.000001 # Query # # COMMIT
3939
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE `tt1` /* generated by server */
4040
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
4141
FLUSH STATUS;
42+
43+
# 'DROP TABLE IF EXISTS <deleted tables>' is binlogged
44+
# when 'DROP DATABASE' fails and at least one table is deleted
45+
# from the database.
46+
RESET MASTER;
47+
CREATE DATABASE testing_1;
48+
USE testing_1;
49+
CREATE TABLE t1(c1 INT);
50+
CREATE TABLE t2(c1 INT);
51+
# Create a file in the database directory
52+
SELECT 'hello' INTO OUTFILE 'fake_file.FAKE_FILE';
53+
54+
# 'DROP DATABASE' will fail if there is any other file in the the
55+
# database directory
56+
DROP DATABASE testing_1;
57+
ERROR HY000: Error dropping database (can't rmdir './testing_1/', errno: 17)
58+
59+
# Remove the fake file.
60+
# Now we can drop the database.
61+
DROP DATABASE testing_1;
4262
#
4363
# Bug#11765416 58381: FAILED DROP DATABASE CAN BREAK STATEMENT
4464
# BASED REPLICATION
4565
#
66+
USE test;
4667
DROP DATABASE IF EXISTS db1;
4768
DROP TABLE IF EXISTS t3;
4869
CREATE DATABASE db1;
@@ -58,7 +79,7 @@ Tables_in_db1
5879
t2
5980
show binlog events from <binlog_start>;
6081
Log_name Pos Event_type Server_id End_log_pos Info
61-
master-bin.000001 # Query # # use `db1`; DROP TABLE `t1`
82+
master-bin.000001 # Query # # use `db1`; DROP TABLE IF EXISTS `t1`
6283
DROP TABLE t3;
6384
DROP DATABASE db1;
6485
set binlog_format=mixed;
@@ -102,10 +123,31 @@ master-bin.000001 # Query # # COMMIT
102123
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE `tt1` /* generated by server */
103124
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
104125
FLUSH STATUS;
126+
127+
# 'DROP TABLE IF EXISTS <deleted tables>' is binlogged
128+
# when 'DROP DATABASE' fails and at least one table is deleted
129+
# from the database.
130+
RESET MASTER;
131+
CREATE DATABASE testing_1;
132+
USE testing_1;
133+
CREATE TABLE t1(c1 INT);
134+
CREATE TABLE t2(c1 INT);
135+
# Create a file in the database directory
136+
SELECT 'hello' INTO OUTFILE 'fake_file.FAKE_FILE';
137+
138+
# 'DROP DATABASE' will fail if there is any other file in the the
139+
# database directory
140+
DROP DATABASE testing_1;
141+
ERROR HY000: Error dropping database (can't rmdir './testing_1/', errno: 17)
142+
143+
# Remove the fake file.
144+
# Now we can drop the database.
145+
DROP DATABASE testing_1;
105146
#
106147
# Bug#11765416 58381: FAILED DROP DATABASE CAN BREAK STATEMENT
107148
# BASED REPLICATION
108149
#
150+
USE test;
109151
DROP DATABASE IF EXISTS db1;
110152
DROP TABLE IF EXISTS t3;
111153
CREATE DATABASE db1;
@@ -121,7 +163,7 @@ Tables_in_db1
121163
t2
122164
show binlog events from <binlog_start>;
123165
Log_name Pos Event_type Server_id End_log_pos Info
124-
master-bin.000001 # Query # # use `db1`; DROP TABLE `t1`
166+
master-bin.000001 # Query # # use `db1`; DROP TABLE IF EXISTS `t1`
125167
DROP TABLE t3;
126168
DROP DATABASE db1;
127169
set binlog_format=row;
@@ -166,10 +208,31 @@ master-bin.000001 # Query # # COMMIT
166208
master-bin.000001 # Query # # DROP TEMPORARY TABLE IF EXISTS `test`.`tt1` /* generated by server */
167209
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
168210
FLUSH STATUS;
211+
212+
# 'DROP TABLE IF EXISTS <deleted tables>' is binlogged
213+
# when 'DROP DATABASE' fails and at least one table is deleted
214+
# from the database.
215+
RESET MASTER;
216+
CREATE DATABASE testing_1;
217+
USE testing_1;
218+
CREATE TABLE t1(c1 INT);
219+
CREATE TABLE t2(c1 INT);
220+
# Create a file in the database directory
221+
SELECT 'hello' INTO OUTFILE 'fake_file.FAKE_FILE';
222+
223+
# 'DROP DATABASE' will fail if there is any other file in the the
224+
# database directory
225+
DROP DATABASE testing_1;
226+
ERROR HY000: Error dropping database (can't rmdir './testing_1/', errno: 17)
227+
228+
# Remove the fake file.
229+
# Now we can drop the database.
230+
DROP DATABASE testing_1;
169231
#
170232
# Bug#11765416 58381: FAILED DROP DATABASE CAN BREAK STATEMENT
171233
# BASED REPLICATION
172234
#
235+
USE test;
173236
DROP DATABASE IF EXISTS db1;
174237
DROP TABLE IF EXISTS t3;
175238
CREATE DATABASE db1;
@@ -185,7 +248,7 @@ Tables_in_db1
185248
t2
186249
show binlog events from <binlog_start>;
187250
Log_name Pos Event_type Server_id End_log_pos Info
188-
master-bin.000001 # Query # # use `db1`; DROP TABLE `t1`
251+
master-bin.000001 # Query # # use `db1`; DROP TABLE IF EXISTS `t1`
189252
DROP TABLE t3;
190253
DROP DATABASE db1;
191254
show databases;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
include/master-slave.inc
2+
[connection master]
3+
CREATE DATABASE IF NOT EXISTS db1;
4+
CREATE DATABASE IF NOT EXISTS db2;
5+
use db1;
6+
CREATE TABLE a(id INT);
7+
CREATE VIEW v AS SELECT * FROM a;
8+
CREATE TABLE table_father(id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20)) ENGINE=INNODB;
9+
use db2;
10+
CREATE TABLE table_child(id INT PRIMARY KEY, info VARCHAR(20), father_id INT) ENGINE=INNODB;
11+
ALTER TABLE table_child ADD CONSTRAINT aaa FOREIGN KEY (father_id) REFERENCES db1.table_father(id);
12+
DROP DATABASE db1;
13+
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
14+
DROP DATABASE db2;
15+
DROP DATABASE db1;
16+
include/rpl_end.inc
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
###############################################################################
2+
# Bug#20041860: SLAVE ERROR WHEN DROP DATABASE
3+
#
4+
# Test:
5+
# =====
6+
# Create two databases such that one database has a dependency over the other
7+
# database and try to drop the database which has a dependency. This should
8+
# not cause slave to break.
9+
###############################################################################
10+
--source include/master-slave.inc
11+
12+
connection master;
13+
CREATE DATABASE IF NOT EXISTS db1;
14+
CREATE DATABASE IF NOT EXISTS db2;
15+
16+
use db1;
17+
CREATE TABLE a(id INT);
18+
CREATE VIEW v AS SELECT * FROM a;
19+
CREATE TABLE table_father(id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20)) ENGINE=INNODB;
20+
21+
use db2;
22+
CREATE TABLE table_child(id INT PRIMARY KEY, info VARCHAR(20), father_id INT) ENGINE=INNODB;
23+
ALTER TABLE table_child ADD CONSTRAINT aaa FOREIGN KEY (father_id) REFERENCES db1.table_father(id);
24+
25+
--error ER_ROW_IS_REFERENCED
26+
DROP DATABASE db1;
27+
DROP DATABASE db2;
28+
--sync_slave_with_master
29+
--connection master
30+
DROP DATABASE db1;
31+
--source include/rpl_end.inc

sql/sql_db.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -942,7 +942,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
942942

943943
if (!(query= (char*) thd->alloc(MAX_DROP_TABLE_Q_LEN)))
944944
goto exit; /* not much else we can do */
945-
query_pos= query_data_start= strmov(query,"DROP TABLE ");
945+
query_pos= query_data_start= strmov(query,"DROP TABLE IF EXISTS ");
946946
query_end= query + MAX_DROP_TABLE_Q_LEN;
947947
db_len= strlen(db);
948948

0 commit comments

Comments
 (0)