summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/rpl_drop_db.result30
-rw-r--r--mysql-test/t/rpl_drop_db.test39
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sql_db.cc45
-rw-r--r--sql/sql_table.cc20
5 files changed, 129 insertions, 7 deletions
diff --git a/mysql-test/r/rpl_drop_db.result b/mysql-test/r/rpl_drop_db.result
new file mode 100644
index 00000000000..bafbfe3a1ed
--- /dev/null
+++ b/mysql-test/r/rpl_drop_db.result
@@ -0,0 +1,30 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+drop database if exists d1;
+create database d1;
+create table d1.t1 (n int);
+insert into d1.t1 values (1);
+select * from d1.t1 into outfile 'd1/f1.txt';
+create table d1.t2 (n int);
+create table d1.t3 (n int);
+drop database d1;
+ERROR HY000: Error dropping database (can't rmdir './d1/', errno: 17)
+use d1;
+show tables;
+Tables_in_d1
+use test;
+create table t1 (n int);
+insert into t1 values (1234);
+use d1;
+show tables;
+Tables_in_d1
+use test;
+select * from t1;
+n
+1234
+drop table t1;
+stop slave;
diff --git a/mysql-test/t/rpl_drop_db.test b/mysql-test/t/rpl_drop_db.test
new file mode 100644
index 00000000000..ef0ab4be6fd
--- /dev/null
+++ b/mysql-test/t/rpl_drop_db.test
@@ -0,0 +1,39 @@
+# test case for BUG#4680 -- if there are extra files in the db directory
+# dropping the db on the master causes replication problems
+
+-- source include/master-slave.inc
+connection master;
+
+--disable_warnings
+drop database if exists d1;
+--enable_warnings
+create database d1;
+create table d1.t1 (n int);
+insert into d1.t1 values (1);
+select * from d1.t1 into outfile 'd1/f1.txt';
+create table d1.t2 (n int);
+create table d1.t3 (n int);
+--error 1010
+drop database d1;
+use d1;
+show tables;
+use test;
+create table t1 (n int);
+insert into t1 values (1234);
+sync_slave_with_master;
+
+connection slave;
+use d1;
+show tables;
+use test;
+select * from t1;
+
+connection master;
+drop table t1;
+sync_slave_with_master;
+
+#cleanup
+connection slave;
+stop slave;
+system rm -rf var/master-data/d1;
+
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 6969433649f..9d46cc507df 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -441,7 +441,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool log_query);
int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
bool if_exists, bool drop_temporary,
- bool log_query);
+ bool log_query, List<String> *dropped_tables);
int quick_rm_table(enum db_type base,const char *db,
const char *table_name);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index ad6845572e1..0155fca0466 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -31,7 +31,7 @@ static TYPELIB deletable_extentions=
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
const char *db, const char *path,
- uint level);
+ uint level, List<String> *dropped_tables);
/* Database options hash */
static HASH dboptions;
@@ -584,6 +584,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
int error= 0;
char path[FN_REFLEN+16], tmp_db[NAME_LEN+1];
MY_DIR *dirp;
+ List<String> dropped_tables;
uint length;
DBUG_ENTER("mysql_rm_db");
@@ -621,8 +622,10 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
remove_db_from_cache(db);
pthread_mutex_unlock(&LOCK_open);
+
error= -1;
- if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0)) >= 0)
+ if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0,
+ &dropped_tables)) >= 0)
{
ha_drop_database(path);
query_cache_invalidate1(db);
@@ -672,6 +675,37 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
send_ok(thd, (ulong) deleted);
thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
}
+ else if (!dropped_tables.is_empty() && mysql_bin_log.is_open())
+ {
+ List_iterator<String> it(dropped_tables);
+ String* dropped_table;
+ int q_len= 11; /* drop table */
+ int db_len= strlen(db);
+
+ for (;(dropped_table= it++);)
+ {
+ q_len += dropped_table->length() + 2 + db_len;
+ }
+ q_len--; /* no last comma */
+
+ char* query= thd->alloc(q_len);
+ if (!query)
+ goto exit; /* not much else we can do */
+ char* p= strmov(query,"drop table ");
+ it.rewind();
+
+ for (;(dropped_table= it++);)
+ {
+ p= strmov(p,db);
+ *p++ = '.';
+ p= strnmov(p,dropped_table->ptr(),dropped_table->length());
+ *p++ = ',';
+ }
+ *--p= 0;
+ Query_log_event qinfo(thd, query, q_len, 0, 0);
+ qinfo.error_code= 0;
+ mysql_bin_log.write(&qinfo);
+ }
exit:
start_waiting_global_read_lock(thd);
@@ -716,7 +750,7 @@ exit2:
*/
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
- const char *org_path, uint level)
+ const char *org_path, uint level, List<String> *dropped_tables)
{
long deleted=0;
ulong found_other_files=0;
@@ -758,7 +792,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT))))
{
DBUG_PRINT("my",("New subdir found: %s", newpath));
- if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0)
+ if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0)
goto err;
if (!(copy_of_path= thd->memdup(newpath, length+1)) ||
!(dir= new (thd->mem_root) String(copy_of_path, length,
@@ -805,7 +839,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
}
}
if (thd->killed ||
- (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1)))
+ (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0,
+ 1,dropped_tables)))
goto err;
/* Remove RAID directories */
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 87b864c73fa..e948a65f301 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -156,7 +156,8 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
int mysql_rm_table_part2_with_lock(THD *thd,
TABLE_LIST *tables, bool if_exists,
- bool drop_temporary, bool dont_log_query)
+ bool drop_temporary, bool dont_log_query,
+ List<String>* dropped_tables)
{
int error;
thd->mysys_var->current_mutex= &LOCK_open;
@@ -165,6 +166,23 @@ int mysql_rm_table_part2_with_lock(THD *thd,
error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary,
dont_log_query);
+ /*
+ For now we assume that if we got success all the tables in the list
+ were actually dropped, otherwise, assume none were dropped.
+ TODO: fix it to work with a partial drop - extremely rare case, but
+ can happen.
+ */
+ if (!error && dropped_tables)
+ {
+ TABLE_LIST* tbl;
+
+ for (tbl= tables; tbl; tbl= tbl->next)
+ {
+ String *dropped_table= new (thd->mem_root)
+ String(tbl->real_name,&my_charset_latin1);
+ dropped_tables->push_back(dropped_table);
+ }
+ }
pthread_mutex_unlock(&LOCK_open);