List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:November 8 2010 3:04pm
Subject:bzr commit into mysql-5.5-runtime branch (jon.hauglid:3179) Bug#57663
View as plain text  
#At file:///export/home/x/mysql-5.5-runtime-refactor/ based on revid:jon.hauglid@stripped

 3179 Jon Olav Hauglid	2010-11-08
      Bug #57663 Concurrent statement using stored function and DROP DATABASE
                 breaks SBR
      
      This is a preliminary version of the patch.
      
      The problem was that DROP DATABASE ignores any metadata locks on stored
      functions and procedures held by other connections. This makes it
      possible for DROP DATABASE to drop functions/procedures that are in use
      by other connections and therefore break statement based replication.
      (DROP DATABASE can appear in the binlog before a statement using a
      dropped function/procedure.)
      
      This problem was an issue left unresolved by the patch for Bug#30977
      where metadata locks for stored functions/procedures were introduced.
      
      This patch fixes the problem by making sure DROP DATABASE takes
      exclusive metadata locks on all stored functions/procedures to be
      dropped.
      
      Test case added to sp-lock.test.

    modified:
      mysql-test/r/sp-lock.result
      mysql-test/t/sp-lock.test
      sql/sql_db.cc
      sql/sql_table.cc
=== modified file 'mysql-test/r/sp-lock.result'
--- a/mysql-test/r/sp-lock.result	2010-08-06 11:29:37 +0000
+++ b/mysql-test/r/sp-lock.result	2010-11-08 15:04:43 +0000
@@ -735,5 +735,91 @@ END	latin1	latin1_swedish_ci	latin1_swed
 # Connection default;
 DROP PROCEDURE p1;
 #
+# Bug#57663 Concurrent statement using stored function and DROP DATABASE
+#           breaks SBR
+#
+DROP DATABASE IF EXISTS db1;
+DROP FUNCTION IF EXISTS f1;
+# Test 1: Check that DROP DATABASE block if a function is used
+#         by an active transaction.
+# Connection default
+CREATE DATABASE db1;
+CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1;
+START TRANSACTION;
+SELECT db1.f1();
+db1.f1()
+1
+# Connection con1
+# Sending:
+DROP DATABASE db1;
+# Connection default
+COMMIT;
+# Connection con1
+# Reaping: DROP DATABASE db1
+# Test 2: Check that DROP DATABASE blocks if a procedure is
+#         used by an active transaction.
+# Connection default
+CREATE DATABASE db1;
+CREATE PROCEDURE db1.p1() BEGIN END;
+CREATE FUNCTION f1() RETURNS INTEGER
+BEGIN
+CALL db1.p1();
+RETURN 1;
+END|
+START TRANSACTION;
+SELECT f1();
+f1()
+1
+# Connection con1
+# Sending:
+DROP DATABASE db1;
+# Connection default
+COMMIT;
+# Connection con1
+# Reaping: DROP DATABASE db1
+# Test 3: Check that DROP DATABASE is not selected as a victim if a
+#         deadlock is discovered with DML statements.
+# Connection default
+CREATE DATABASE db1;
+CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1;
+CREATE FUNCTION db1.f2() RETURNS INTEGER RETURN 1;
+START TRANSACTION;
+SELECT db1.f2();
+db1.f2()
+1
+# Connection con1
+# Sending:
+DROP DATABASE db1;
+# Connection default
+SELECT db1.f1();
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+COMMIT;
+# Connection con1
+# Reaping: DROP DATABASE db1
+# Test 4: Check that active DROP DATABASE blocks stored routine DDL.
+# Connection default
+CREATE DATABASE db1;
+CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1;
+CREATE FUNCTION db1.f2() RETURNS INTEGER RETURN 2;
+START TRANSACTION;
+SELECT db1.f2();
+db1.f2()
+2
+# Connection con1
+# Sending:
+DROP DATABASE db1;
+# Connection con2
+# Sending:
+ALTER FUNCTION db1.f1 COMMENT "test";
+# Connection default
+COMMIT;
+# Connection con1
+# Reaping: DROP DATABASE db1
+# Connection con2
+# Reaping: ALTER FUNCTION f1 COMMENT 'test'
+ERROR 42000: FUNCTION db1.f1 does not exist
+# Connection default
+DROP FUNCTION f1;
+#
 # End of 5.5 tests
 #

=== modified file 'mysql-test/t/sp-lock.test'
--- a/mysql-test/t/sp-lock.test	2010-08-06 11:29:37 +0000
+++ b/mysql-test/t/sp-lock.test	2010-11-08 15:04:43 +0000
@@ -972,5 +972,165 @@ DROP PROCEDURE p1;
 
 
 --echo #
+--echo # Bug#57663 Concurrent statement using stored function and DROP DATABASE
+--echo #           breaks SBR
+--echo #
+
+--disable_warnings
+DROP DATABASE IF EXISTS db1;
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+connect(con1, localhost, root);
+connect(con2, localhost, root);
+
+--echo # Test 1: Check that DROP DATABASE block if a function is used
+--echo #         by an active transaction.
+
+--echo # Connection default
+connection default;
+CREATE DATABASE db1;
+CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1;
+START TRANSACTION;
+SELECT db1.f1();
+
+--echo # Connection con1
+connection con1;
+--echo # Sending:
+--send DROP DATABASE db1
+
+--echo # Connection default
+connection default;
+let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
+  WHERE state= 'Waiting for stored function metadata lock'
+  AND info='DROP DATABASE db1';
+--source include/wait_condition.inc
+COMMIT;
+
+--echo # Connection con1
+connection con1;
+--echo # Reaping: DROP DATABASE db1
+--reap
+
+--echo # Test 2: Check that DROP DATABASE blocks if a procedure is
+--echo #         used by an active transaction.
+
+--echo # Connection default
+connection default;
+CREATE DATABASE db1;
+CREATE PROCEDURE db1.p1() BEGIN END;
+delimiter |;
+CREATE FUNCTION f1() RETURNS INTEGER
+BEGIN
+  CALL db1.p1();
+  RETURN 1;
+END|
+delimiter ;|
+START TRANSACTION;
+SELECT f1();
+
+--echo # Connection con1
+connection con1;
+--echo # Sending:
+--send DROP DATABASE db1
+
+--echo # Connection default
+connection default;
+let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
+  WHERE state= 'Waiting for stored procedure metadata lock'
+  AND info='DROP DATABASE db1';
+--source include/wait_condition.inc
+COMMIT;
+
+--echo # Connection con1
+connection con1;
+--echo # Reaping: DROP DATABASE db1
+--reap
+
+--echo # Test 3: Check that DROP DATABASE is not selected as a victim if a
+--echo #         deadlock is discovered with DML statements.
+
+--echo # Connection default
+connection default;
+CREATE DATABASE db1;
+CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1;
+CREATE FUNCTION db1.f2() RETURNS INTEGER RETURN 1;
+START TRANSACTION;
+# DROP DATABASE will try to lock f2 before f1
+SELECT db1.f2();
+
+--echo # Connection con1
+connection con1;
+--echo # Sending:
+--send DROP DATABASE db1
+
+--echo # Connection default
+connection default;
+let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
+  WHERE state= 'Waiting for stored function metadata lock'
+  AND info='DROP DATABASE db1';
+--source include/wait_condition.inc
+--error ER_LOCK_DEADLOCK
+SELECT db1.f1();
+COMMIT;
+
+--echo # Connection con1
+connection con1;
+--echo # Reaping: DROP DATABASE db1
+--reap
+
+--echo # Test 4: Check that active DROP DATABASE blocks stored routine DDL.
+
+--echo # Connection default
+connection default;
+CREATE DATABASE db1;
+CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1;
+CREATE FUNCTION db1.f2() RETURNS INTEGER RETURN 2;
+START TRANSACTION;
+SELECT db1.f2();
+
+--echo # Connection con1
+connection con1;
+--echo # Sending:
+--send DROP DATABASE db1
+
+--echo # Connection con2
+connection con2;
+let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
+  WHERE state= 'Waiting for stored function metadata lock'
+  AND info='DROP DATABASE db1';
+--source include/wait_condition.inc
+--echo # Sending:
+--send ALTER FUNCTION db1.f1 COMMENT "test"
+
+--echo # Connection default
+connection default;
+let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
+  WHERE state= 'Waiting for schema metadata lock'
+  AND info='ALTER FUNCTION db1.f1 COMMENT "test"';
+--source include/wait_condition.inc
+COMMIT;
+
+--echo # Connection con1
+connection con1;
+--echo # Reaping: DROP DATABASE db1
+--reap
+disconnect con1;
+--source include/wait_until_disconnected.inc
+
+--echo # Connection con2
+connection con2;
+--echo # Reaping: ALTER FUNCTION f1 COMMENT 'test'
+--error ER_SP_DOES_NOT_EXIST
+--reap
+disconnect con2;
+--source include/wait_until_disconnected.inc
+
+--echo # Connection default
+connection default;
+DROP FUNCTION f1;
+
+
+--echo #
 --echo # End of 5.5 tests
 --echo #

=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc	2010-10-19 10:29:21 +0000
+++ b/sql/sql_db.cc	2010-11-08 15:04:43 +0000
@@ -30,6 +30,9 @@
 #include "log_event.h"                   // Query_log_event
 #include <mysys_err.h>
 #include "sp.h"
+#include "sp_head.h"                     // TYPE_ENUM_FUNCTION
+#include "sql_base.h"                    // lock_table_names,close_system_tables
+#include "sql_handler.h"                 // mysql_ha_rm_tables
 #include "events.h"
 #include <my_dir.h>
 #include <m_ctype.h>
@@ -44,8 +47,12 @@ const char *del_exts[]= {".frm", ".BAK",
 static TYPELIB deletable_extentions=
 {array_elements(del_exts)-1,"del_exts", del_exts, NULL};
 
-static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
-				 const char *db, const char *path, uint level, 
+static bool lock_db_routines(THD *thd, char *db);
+static long find_db_tables(THD *thd, MY_DIR *dirp, const char *db,
+                           const char *path, TABLE_LIST **tables,
+                           ulong *found_other_files);
+static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *path,
+                                 ulong found_other_files,
                                  TABLE_LIST **dropped_tables);
          
 long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path);
@@ -787,10 +794,27 @@ bool mysql_rm_db(THD *thd,char *db,bool
   }
   else
   {
+    ulong found_other_files= 0;
     Drop_table_error_handler err_handler;
     thd->push_internal_handler(&err_handler);
 
     error= -1;
+
+    /* Lock all tables and stored routines about to be dropped. */
+    if (find_db_tables(thd, dirp, db, path, &dropped_tables,
+                       &found_other_files) ||
+        lock_table_names(thd, dropped_tables, NULL,
+                         thd->variables.lock_wait_timeout,
+                         MYSQL_OPEN_SKIP_TEMPORARY) ||
+        lock_db_routines(thd, db))
+    {
+      thd->pop_internal_handler();
+      goto exit;
+    }
+
+    if (dropped_tables)
+      mysql_ha_rm_tables(thd, dropped_tables);
+
     /*
       We temporarily disable the binary log while dropping the objects
       in the database. Since the DROP DATABASE statement is always
@@ -809,7 +833,7 @@ bool mysql_rm_db(THD *thd,char *db,bool
       as disabled and will not log the drop database statement on any
       other connected server.
      */
-    if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0,
+    if ((deleted= mysql_rm_known_files(thd, dirp, path, found_other_files,
                                        &dropped_tables)) >= 0)
     {
       ha_drop_database(path);
@@ -932,23 +956,67 @@ exit:
   DBUG_RETURN(error);
 }
 
-/*
-  Removes files with known extensions plus all found subdirectories that
-  are 2 hex digits (raid directories).
-  thd MUST be set when calling this function!
-*/
 
-static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
-				 const char *org_path, uint level,
-                                 TABLE_LIST **dropped_tables)
+static bool lock_db_routines(THD *thd, char *db)
+{
+  TABLE *table;
+  uint key_len;
+  int nxtres= 0;
+  Open_tables_backup open_tables_state_backup;
+  MDL_request_list mdl_requests;
+  DBUG_ENTER("find_db_routine");
+
+  table = open_proc_table_for_read(thd, &open_tables_state_backup);
+  if (!table)
+  {
+    /*
+      mysql.proc will be re-opened during deletion, so we don't need to
+      report errors here. Also, DROP DB should not fail even if mysql.proc
+      can't be opened.
+    */
+    thd->warning_info->clear_warning_info(thd->query_id);
+    thd->clear_error();
+    DBUG_RETURN(FALSE);
+  }
+
+  table->field[MYSQL_PROC_FIELD_DB]->store(db, strlen(db), system_charset_info);
+  key_len= table->key_info->key_part[0].store_length;
+  table->file->ha_index_init(0, 1);
+
+  if (! table->file->index_read_map(table->record[0],
+                                    table->field[MYSQL_PROC_FIELD_DB]->ptr,
+                                    (key_part_map)1, HA_READ_KEY_EXACT))
+  {
+    do
+    {
+      char *sp_name= get_field(thd->mem_root,
+                               table->field[MYSQL_PROC_FIELD_NAME]);
+      longlong sp_type= table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
+      MDL_request *mdl_request= new (thd->mem_root) MDL_request;
+      mdl_request->init(sp_type == TYPE_ENUM_FUNCTION ?
+                        MDL_key::FUNCTION : MDL_key::PROCEDURE,
+                        db, sp_name, MDL_EXCLUSIVE);
+      mdl_requests.push_front(mdl_request);
+    } while (! (nxtres= table->file->index_next_same(table->record[0],
+                                         table->field[MYSQL_PROC_FIELD_DB]->ptr,
+						     key_len)));
+  }
+  table->file->ha_index_end();
+  close_system_tables(thd, &open_tables_state_backup);
+  if (nxtres != 0 && nxtres != HA_ERR_END_OF_FILE)
+    DBUG_RETURN(TRUE);
+  DBUG_RETURN(thd->mdl_context.acquire_locks(&mdl_requests,
+                                             thd->variables.lock_wait_timeout));
+}
+
+
+static long find_db_tables(THD *thd, MY_DIR *dirp, const char *db,
+                           const char *path, TABLE_LIST **tables,
+                           ulong *found_other_files)
 {
-  long deleted=0;
-  ulong found_other_files=0;
   char filePath[FN_REFLEN];
   TABLE_LIST *tot_list=0, **tot_list_next_local, **tot_list_next_global;
-  List<String> raid_dirs;
-  DBUG_ENTER("mysql_rm_known_files");
-  DBUG_PRINT("enter",("path: %s", org_path));
+  DBUG_ENTER("find_db_tables");
 
   tot_list_next_local= tot_list_next_global= &tot_list;
 
@@ -965,37 +1033,8 @@ static long mysql_rm_known_files(THD *th
        (file->name[1] == '.' &&  !file->name[2])))
       continue;
 
-    /* Check if file is a raid directory */
-    if ((my_isdigit(system_charset_info, file->name[0]) ||
-	 (file->name[0] >= 'a' && file->name[0] <= 'f')) &&
-	(my_isdigit(system_charset_info, file->name[1]) ||
-	 (file->name[1] >= 'a' && file->name[1] <= 'f')) &&
-	!file->name[2] && !level)
-    {
-      char newpath[FN_REFLEN], *copy_of_path;
-      MY_DIR *new_dirp;
-      String *dir;
-      uint length;
-
-      strxmov(newpath,org_path,"/",file->name,NullS);
-      length= unpack_filename(newpath,newpath);
-      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)) < 0)
-	  goto err;
-	if (!(copy_of_path= (char*) thd->memdup(newpath, length+1)) ||
-	    !(dir= new (thd->mem_root) String(copy_of_path, length,
-					       &my_charset_bin)) ||
-	    raid_dirs.push_back(dir))
-	  goto err;
-	continue;
-      }
-      found_other_files++;
-      continue;
-    }
-    else if (file->name[0] == 'a' && file->name[1] == 'r' &&
-             file->name[2] == 'c' && file->name[3] == '\0')
+    if (file->name[0] == 'a' && file->name[1] == 'r' &&
+        file->name[2] == 'c' && file->name[3] == '\0')
     {
       /* .frm archive:
         Those archives are obsolete, but following code should
@@ -1003,16 +1042,16 @@ static long mysql_rm_known_files(THD *th
       */
       char newpath[FN_REFLEN];
       MY_DIR *new_dirp;
-      strxmov(newpath, org_path, "/", "arc", NullS);
+      strxmov(newpath, path, "/", "arc", NullS);
       (void) unpack_filename(newpath, newpath);
       if ((new_dirp = my_dir(newpath, MYF(MY_DONT_SORT))))
       {
 	DBUG_PRINT("my",("Archive subdir found: %s", newpath));
 	if ((mysql_rm_arc_files(thd, new_dirp, newpath)) < 0)
-	  goto err;
+	  DBUG_RETURN(TRUE);
 	continue;
       }
-      found_other_files++;
+      (*found_other_files)++;
       continue;
     }
     if (!(extension= strrchr(file->name, '.')))
@@ -1020,7 +1059,7 @@ static long mysql_rm_known_files(THD *th
     if (find_type(extension, &deletable_extentions,1+2) <= 0)
     {
       if (find_type(extension, ha_known_exts(),1+2) <= 0)
-	found_other_files++;
+	(*found_other_files)++;
       continue;
     }
     /* just for safety we use files_charset_info */
@@ -1036,7 +1075,7 @@ static long mysql_rm_known_files(THD *th
                                           strlen(file->name) + 1);
 
       if (!table_list)
-        goto err;
+        DBUG_RETURN(TRUE);
       table_list->db= (char*) (table_list+1);
       table_list->db_length= strmov(table_list->db, db) - table_list->db;
       table_list->table_name= table_list->db + table_list->db_length + 1;
@@ -1060,47 +1099,60 @@ static long mysql_rm_known_files(THD *th
       (*tot_list_next_global)= table_list;
       tot_list_next_local= &table_list->next_local;
       tot_list_next_global= &table_list->next_global;
-      deleted++;
     }
     else
     {
-      strxmov(filePath, org_path, "/", file->name, NullS);
+      strxmov(filePath, path, "/", file->name, NullS);
       if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME)))
-      {
-	goto err;
-      }
+	DBUG_RETURN(TRUE);
     }
   }
-  if (thd->killed ||
-      (tot_list && mysql_rm_table_part2(thd, tot_list, 1, 0, 1, 1)))
-    goto err;
+  *tables= tot_list;
+  DBUG_RETURN(FALSE);
+}
+
 
-  /* Remove RAID directories */
+/*
+  Removes files with known extensions.
+  thd MUST be set when calling this function!
+*/
+
+static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *path,
+                                 ulong found_other_files,
+                                 TABLE_LIST **dropped_tables)
+{
+  long deleted=0;
+  TABLE_LIST *table;
+  DBUG_ENTER("mysql_rm_known_files");
+  DBUG_PRINT("enter",("path: %s", path));
+
+  for (table= *dropped_tables; table; table= table->next_local)
   {
-    List_iterator<String> it(raid_dirs);
-    String *dir;
-    while ((dir= it++))
-      if (rmdir(dir->c_ptr()) < 0)
-	found_other_files++;
+    tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
+                     FALSE);
+    deleted++;
   }
+
+  if (thd->killed ||
+      (dropped_tables &&
+       mysql_rm_table_part2(thd, *dropped_tables, 1, 0, 1, 1)))
+    goto err;
+
   my_dirend(dirp);  
   
-  if (dropped_tables)
-    *dropped_tables= tot_list;
-  
   /*
     If the directory is a symbolic link, remove the link first, then
     remove the directory the symbolic link pointed at
   */
   if (found_other_files)
   {
-    my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, EEXIST);
+    my_error(ER_DB_DROP_RMDIR, MYF(0), path, EEXIST);
     DBUG_RETURN(-1);
   }
   else
   {
     /* Don't give errors if we can't delete 'RAID' directory */
-    if (rm_dir_w_symlink(org_path, level == 0))
+    if (rm_dir_w_symlink(path, TRUE))
       DBUG_RETURN(-1);
   }
 
@@ -1108,6 +1160,7 @@ static long mysql_rm_known_files(THD *th
 
 err:
   my_dirend(dirp);
+  *dropped_tables= NULL;
   DBUG_RETURN(-1);
 }
 

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-10-19 10:29:21 +0000
+++ b/sql/sql_table.cc	2010-11-08 15:04:43 +0000
@@ -1851,11 +1851,23 @@ bool mysql_rm_table(THD *thd,TABLE_LIST
 {
   bool error;
   Drop_table_error_handler err_handler;
+  TABLE_LIST *table;
 
   DBUG_ENTER("mysql_rm_table");
 
   /* mark for close and remove all cached entries */
 
+  /* Disable drop of enabled log tables, must be done before name locking */
+  for (table= tables; table; table= table->next_local)
+  {
+    if (check_if_log_table(table->db_length, table->db,
+                           table->table_name_length, table->table_name, 1))
+    {
+      my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
+      DBUG_RETURN(TRUE);
+    }
+  }
+
   if (!drop_temporary)
   {
     if (!thd->locked_tables_mode &&
@@ -1863,10 +1875,69 @@ bool mysql_rm_table(THD *thd,TABLE_LIST
       DBUG_RETURN(TRUE);
   }
 
+  mysql_ha_rm_tables(thd, tables);
+
+  if (!drop_temporary)
+  {
+    if (!thd->locked_tables_mode)
+    {
+      if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
+                           MYSQL_OPEN_SKIP_TEMPORARY))
+      {
+        error= TRUE;
+        goto end;
+      }
+      for (table= tables; table; table= table->next_local)
+        tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
+                         FALSE);
+    }
+    else
+    {
+      for (table= tables; table; table= table->next_local)
+        if (table->open_type != OT_BASE_ONLY &&
+	    find_temporary_table(thd, table))
+        {
+          /*
+            A temporary table.
+
+            Don't try to find a corresponding MDL lock or assign it
+            to table->mdl_request.ticket. There can't be metadata
+            locks for temporary tables: they are local to the session.
+
+            Later in this function we release the MDL lock only if
+            table->mdl_requeset.ticket is not NULL. Thus here we
+            ensure that we won't release the metadata lock on the base
+            table locked with LOCK TABLES as a side effect of temporary
+            table drop.
+          */
+          DBUG_ASSERT(table->mdl_request.ticket == NULL);
+        }
+        else
+        {
+          /*
+            Not a temporary table.
+
+            Since 'tables' list can't contain duplicates (this is ensured
+            by parser) it is safe to cache pointer to the TABLE instances
+            in its elements.
+          */
+          table->table= find_table_for_mdl_upgrade(thd->open_tables, table->db,
+                                                   table->table_name, FALSE);
+          if (!table->table)
+          {
+            error= TRUE;
+            goto end;
+          }
+          table->mdl_request.ticket= table->table->mdl_ticket;
+        }
+    }
+  }
+
   thd->push_internal_handler(&err_handler);
   error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0);
   thd->pop_internal_handler();
 
+end:
   if (thd->global_read_lock.has_protection())
     thd->global_read_lock.start_waiting_global_read_lock(thd);
 
@@ -1976,71 +2047,6 @@ int mysql_rm_table_part2(THD *thd, TABLE
     }
   }
 
-  mysql_ha_rm_tables(thd, tables);
-
-  /* Disable drop of enabled log tables, must be done before name locking */
-  for (table= tables; table; table= table->next_local)
-  {
-    if (check_if_log_table(table->db_length, table->db,
-                           table->table_name_length, table->table_name, 1))
-    {
-      my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
-      DBUG_RETURN(1);
-    }
-  }
-
-  if (!drop_temporary)
-  {
-    if (!thd->locked_tables_mode)
-    {
-      if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
-                           MYSQL_OPEN_SKIP_TEMPORARY))
-        DBUG_RETURN(1);
-      for (table= tables; table; table= table->next_local)
-      {
-        tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
-                         FALSE);
-      }
-    }
-    else
-    {
-      for (table= tables; table; table= table->next_local)
-        if (table->open_type != OT_BASE_ONLY &&
-	    find_temporary_table(thd, table))
-        {
-          /*
-            A temporary table.
-
-            Don't try to find a corresponding MDL lock or assign it
-            to table->mdl_request.ticket. There can't be metadata
-            locks for temporary tables: they are local to the session.
-
-            Later in this function we release the MDL lock only if
-            table->mdl_requeset.ticket is not NULL. Thus here we
-            ensure that we won't release the metadata lock on the base
-            table locked with LOCK TABLES as a side effect of temporary
-            table drop.
-          */
-          DBUG_ASSERT(table->mdl_request.ticket == NULL);
-        }
-        else
-        {
-          /*
-            Not a temporary table.
-
-            Since 'tables' list can't contain duplicates (this is ensured
-            by parser) it is safe to cache pointer to the TABLE instances
-            in its elements.
-          */
-          table->table= find_table_for_mdl_upgrade(thd->open_tables, table->db,
-                                                   table->table_name, FALSE);
-          if (!table->table)
-            DBUG_RETURN(1);
-          table->mdl_request.ticket= table->table->mdl_ticket;
-        }
-    }
-  }
-
   for (table= tables; table; table= table->next_local)
   {
     bool is_trans;


Attachment: [text/bzr-bundle] bzr/jon.hauglid@oracle.com-20101108150443-rj3fhe0pgpnonx2s.bundle
Thread
bzr commit into mysql-5.5-runtime branch (jon.hauglid:3179) Bug#57663Jon Olav Hauglid8 Nov