diff options
-rw-r--r-- | mysql-test/r/rpl_drop_db.result | 30 | ||||
-rw-r--r-- | mysql-test/t/rpl_drop_db.test | 39 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/sql_db.cc | 45 | ||||
-rw-r--r-- | sql/sql_table.cc | 20 |
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); |