From: Date: October 8 2007 1:44pm Subject: bk commit into 5.0 tree (davi:1.2524) BUG#31397 List-Archive: http://lists.mysql.com/commits/35092 X-Bug: 31397 Message-Id: <20071008114419.2ED1C4CA2CA@moksha.local> Below is the list of changes that have just been committed into a local 5.0 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-10-08 08:44:14-03:00, davi@stripped +3 -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). 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/r/handler.result@stripped, 2007-10-08 08:44:11-03:00, davi@stripped +12 -0 Add test case result for Bug#3 mysql-test/t/handler.test@stripped, 2007-10-08 08:44:11-03:00, davi@stripped +19 -0 Add test case for Bug#3 sql/sql_handler.cc@stripped, 2007-10-08 08:44:11-03:00, davi@stripped +58 -3 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. diff -Nrup a/mysql-test/r/handler.result b/mysql-test/r/handler.result --- a/mysql-test/r/handler.result 2007-08-27 10:37:10 -03:00 +++ b/mysql-test/r/handler.result 2007-10-08 08:44:11 -03:00 @@ -502,3 +502,15 @@ handler t1_alias READ a next where inexi ERROR 42S22: Unknown column 'inexistent' in 'field list' handler t1_alias 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; diff -Nrup a/mysql-test/t/handler.test b/mysql-test/t/handler.test --- a/mysql-test/t/handler.test 2007-08-27 10:37:10 -03:00 +++ b/mysql-test/t/handler.test 2007-10-08 08:44:11 -03:00 @@ -460,3 +460,22 @@ handler t1_alias read a next; handler t1_alias READ a next where inexistent > 0; handler t1_alias 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; diff -Nrup a/sql/sql_handler.cc b/sql/sql_handler.cc --- a/sql/sql_handler.cc 2007-08-27 10:37:10 -03:00 +++ b/sql/sql_handler.cc 2007-10-08 08:44:11 -03:00 @@ -124,13 +124,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= false) { TABLE **table_ptr; @@ -148,13 +150,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)); } } @@ -602,6 +606,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, (byte*) hash_tables); + } + + DBUG_RETURN(0); +} + + /* Flush (close) a list of HANDLER tables. @@ -639,6 +691,9 @@ int mysql_ha_flush(THD *thd, TABLE_LIST bool did_lock= FALSE; DBUG_ENTER("mysql_ha_flush"); DBUG_PRINT("enter", ("tables: %p mode_flags: 0x%02x", tables, mode_flags)); + + if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE)) + DBUG_RETURN(mysql_ha_drop(thd, tables, is_locked)); if (tables) {