Commit ec657e8d authored by unknown's avatar unknown
Browse files

patch for BUG#4680 - drop database breaking replication if there were extra files

in the database directory on the master


mysql-test/r/rpl_drop_db.result:
  New BitKeeper file ``mysql-test/r/rpl_drop_db.result''
mysql-test/t/rpl_drop_db.test:
  New BitKeeper file ``mysql-test/t/rpl_drop_db.test''
parent bbb2bfe1
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
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;
+39 −0
Original line number Diff line number Diff line
# 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;
+1 −1
Original line number Diff line number Diff line
@@ -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);
+40 −5
Original line number Diff line number Diff line
@@ -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 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
*/

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 */
+19 −1
Original line number Diff line number Diff line
@@ -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);