List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:November 2 2007 1:25pm
Subject:bk commit into 5.1 tree (davi:1.2606) BUG#31397
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of davi. When davi does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-11-02 11:25:28-02:00, davi@stripped +5 -0
  Bug#31397 Inconsistent drop table behavior of handler tables.
  
  The current implementation fails to properly discard handlers of
  dropped tables (that were marked for reopen) because it searches
  on the open handler tables list and using the current alias of the
  table being dropped. The problem is that it must not use the open
  handler tables list to search because the table might have been
  closed (marked for reopen) by a flush tables command and also it
  must not use the current table alias at all since multiple different
  aliases may be associated with a single table. This is specially
  visible when a user has two open handlers (using alias) of a same
  table and a flush tables command is issued before the table is
  dropped (see test case). Scanning the handler table list is also
  useless for dropping handlers associated with temporary tables,
  because temporary tables are not kept in the THD::handler_tables
  list.
  
  The solution is to simple scan the handlers hash table searching
  for, and deleting all handlers with matching table names if the
  reopen flag is not passed to the flush function, indicating that
  the handlers should be deleted. All matching handlers are deleted
  even if the associated the table is not open.

  mysql-test/include/handler.inc@stripped, 2007-11-02 11:25:26-02:00, davi@stripped +32 -0
    Add test case for Bug#31397

  mysql-test/r/handler_innodb.result@stripped, 2007-11-02 11:25:26-02:00, davi@stripped +19 -0
    Add test case result for Bug#31397

  mysql-test/r/handler_myisam.result@stripped, 2007-11-02 11:25:26-02:00, davi@stripped +19 -0
    Add test case result for Bug#31397

  sql/sql_handler.cc@stripped, 2007-11-02 11:25:26-02:00, davi@stripped +61 -6
    When dropping tables for a final close, scan the handler's hash table since
    the table might no be in the handlers open table list because the table was
    marked for reopen or because it's a temporary table.

  sql/sql_table.cc@stripped, 2007-11-02 11:25:26-02:00, davi@stripped +1 -6
    Now that temporary tables are properly removed even when opened
    by a SQL HANDLER, enable the assert since this branch can't be taken
    outside of SF/trigger/prelocked mode.

diff -Nrup a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc
--- a/mysql-test/include/handler.inc	2007-11-01 18:52:50 -02:00
+++ b/mysql-test/include/handler.inc	2007-11-02 11:25:26 -02:00
@@ -598,3 +598,35 @@ handler a2 read a last;
 handler a2 read a prev;
 handler a2 close;
 drop table t1;
+
+#
+# Bug#31397 Inconsistent drop table behavior of handler tables.
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a int);
+handler t1 open as t1_alias;
+drop table t1;
+create table t1 (a int);
+handler t1 open as t1_alias;
+flush tables;
+drop table t1;
+create table t1 (a int);
+handler t1 open as t1_alias;
+handler t1_alias close;
+drop table t1;
+
+#
+# Test that temporary tables associated with handlers are properly dropped.
+#
+
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+create table t1 (a int);
+create temporary table t2 (a int, key(a));
+handler t2 open as a2;
+handler a2 read a first;
+drop table t1, t2;
diff -Nrup a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result
--- a/mysql-test/r/handler_innodb.result	2007-11-01 18:52:50 -02:00
+++ b/mysql-test/r/handler_innodb.result	2007-11-02 11:25:26 -02:00
@@ -637,3 +637,22 @@ a	b
 8	i
 handler a2 close;
 drop table t1;
+drop table if exists t1;
+create table t1 (a int);
+handler t1 open as t1_alias;
+drop table t1;
+create table t1 (a int);
+handler t1 open as t1_alias;
+flush tables;
+drop table t1;
+create table t1 (a int);
+handler t1 open as t1_alias;
+handler t1_alias close;
+drop table t1;
+drop table if exists t1, t2;
+create table t1 (a int);
+create temporary table t2 (a int, key(a));
+handler t2 open as a2;
+handler a2 read a first;
+a
+drop table t1, t2;
diff -Nrup a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result
--- a/mysql-test/r/handler_myisam.result	2007-11-01 18:52:50 -02:00
+++ b/mysql-test/r/handler_myisam.result	2007-11-02 11:25:26 -02:00
@@ -637,3 +637,22 @@ a	b
 8	i
 handler a2 close;
 drop table t1;
+drop table if exists t1;
+create table t1 (a int);
+handler t1 open as t1_alias;
+drop table t1;
+create table t1 (a int);
+handler t1 open as t1_alias;
+flush tables;
+drop table t1;
+create table t1 (a int);
+handler t1 open as t1_alias;
+handler t1_alias close;
+drop table t1;
+drop table if exists t1, t2;
+create table t1 (a int);
+create temporary table t2 (a int, key(a));
+handler t2 open as a2;
+handler a2 read a first;
+a
+drop table t1, t2;
diff -Nrup a/sql/sql_handler.cc b/sql/sql_handler.cc
--- a/sql/sql_handler.cc	2007-11-01 18:52:52 -02:00
+++ b/sql/sql_handler.cc	2007-11-02 11:25:26 -02:00
@@ -119,13 +119,15 @@ static void mysql_ha_hash_free(TABLE_LIS
 
   @param thd Thread identifier.
   @param tables A list of tables with the first entry to close.
+  @param is_locked If LOCK_open is locked.
 
   @note Though this function takes a list of tables, only the first list entry
   will be closed.
   @note Broadcasts refresh if it closed the table.
 */
 
-static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables)
+static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
+                                 bool is_locked)
 {
   TABLE **table_ptr;
 
@@ -143,13 +145,15 @@ static void mysql_ha_close_table(THD *th
   if (*table_ptr)
   {
     (*table_ptr)->file->ha_index_or_rnd_end();
-    VOID(pthread_mutex_lock(&LOCK_open));
+    if (! is_locked)
+      VOID(pthread_mutex_lock(&LOCK_open));
     if (close_thread_table(thd, table_ptr))
     {
       /* Tell threads waiting for refresh that something has happened */
       broadcast_refresh();
     }
-    VOID(pthread_mutex_unlock(&LOCK_open));
+    if (! is_locked)
+      VOID(pthread_mutex_unlock(&LOCK_open));
   }
   else if (tables->table)
   {
@@ -305,7 +309,7 @@ err:
   if (hash_tables)
     my_free((char*) hash_tables, MYF(0));
   if (tables->table)
-    mysql_ha_close_table(thd, tables);
+    mysql_ha_close_table(thd, tables, FALSE);
   DBUG_PRINT("exit",("ERROR"));
   DBUG_RETURN(TRUE);
 }
@@ -339,7 +343,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST
                                               (uchar*) tables->alias,
                                               strlen(tables->alias) + 1)))
   {
-    mysql_ha_close_table(thd, hash_tables);
+    mysql_ha_close_table(thd, hash_tables, FALSE);
     hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
   }
   else
@@ -478,7 +482,7 @@ retry:
 
   if (need_reopen)
   {
-    mysql_ha_close_table(thd, tables);
+    mysql_ha_close_table(thd, tables, FALSE);
     hash_tables->table= NULL;
     /*
       The lock might have been aborted, we need to manually reset
@@ -669,6 +673,54 @@ err0:
 }
 
 
+/**
+  Drop a list of HANDLER tables and associated hashes
+
+  @param thd        Thread identifier.
+  @param tables     A list of tables with the first entry to close.
+  @param is_locked  If LOCK_open is locked.
+*/
+
+static int mysql_ha_drop(THD *thd, TABLE_LIST *tables, bool is_locked)
+{
+  TABLE_LIST *hash_tables, *head= NULL, *first= tables;
+  DBUG_ENTER("mysql_ha_drop");
+  DBUG_PRINT("enter", ("tables: %p  is_locked: %d", tables, (int) is_locked));
+
+  /* search for all handler with matching table names */
+  for (uint i= 0; i < thd->handler_tables_hash.records; i++)
+  {
+    hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
+    for (tables= first; tables; tables= tables->next_local)
+    {
+      if (! *tables->db ||
+          ! my_strcasecmp(&my_charset_latin1, hash_tables->db, tables->db) &&
+          ! my_strcasecmp(&my_charset_latin1, hash_tables->table_name,
+                          tables->table_name))
+        break;
+    }
+
+    /* specific drop table or drop-all */
+    if (tables || ! first)
+    {
+      hash_tables->next_local= head;
+      head= hash_tables;
+    }
+  }
+
+  while (head)
+  {
+    hash_tables= head;
+    head= hash_tables->next_local;
+    if (hash_tables->table)
+      mysql_ha_close_table(thd, hash_tables, is_locked);
+    hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
+  }
+
+  DBUG_RETURN(0);
+}
+
+
 /*
   Flush (close) a list of HANDLER tables.
 
@@ -707,6 +759,9 @@ int mysql_ha_flush(THD *thd, TABLE_LIST 
   DBUG_ENTER("mysql_ha_flush");
   DBUG_PRINT("enter", ("tables: 0x%lx  mode_flags: 0x%02x",
                        (long) tables, mode_flags));
+
+  if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE))
+    DBUG_RETURN(mysql_ha_drop(thd, tables, is_locked));
 
   if (tables)
   {
diff -Nrup a/sql/sql_table.cc b/sql/sql_table.cc
--- a/sql/sql_table.cc	2007-11-01 20:48:11 -02:00
+++ b/sql/sql_table.cc	2007-11-02 11:25:26 -02:00
@@ -1573,12 +1573,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
       continue;
     case -1:
       // table already in use
-      /*
-        XXX: This branch should never be taken outside of SF, trigger or
-             prelocked mode.
-
-        DBUG_ASSERT(thd->in_sub_stmt);
-      */
+      DBUG_ASSERT(thd->in_sub_stmt);
       error= 1;
       goto err_with_placeholders;
     default:
Thread
bk commit into 5.1 tree (davi:1.2606) BUG#31397Davi Arnaut2 Nov