Skip to content

Commit 94e6e4f

Browse files
author
davi@endora.local
committed
Bug#31397 Inconsistent drop table behavior of handler tables.
The problem is that DROP TABLE and other DDL statements failed to automatically close handlers associated with tables that were marked for reopen (FLUSH 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.
1 parent 6223deb commit 94e6e4f

9 files changed

+399
-163
lines changed

mysql-test/include/handler.inc

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,3 +598,97 @@ handler a2 read a last;
598598
handler a2 read a prev;
599599
handler a2 close;
600600
drop table t1;
601+
602+
#
603+
# Bug#31397 Inconsistent drop table behavior of handler tables.
604+
#
605+
606+
--disable_warnings
607+
drop table if exists t1,t2;
608+
--enable_warnings
609+
create table t1 (a int);
610+
handler t1 open as t1_alias;
611+
drop table t1;
612+
create table t1 (a int);
613+
handler t1 open as t1_alias;
614+
flush tables;
615+
drop table t1;
616+
create table t1 (a int);
617+
handler t1 open as t1_alias;
618+
handler t1_alias close;
619+
drop table t1;
620+
create table t1 (a int);
621+
handler t1 open as t1_alias;
622+
handler t1_alias read first;
623+
drop table t1;
624+
--error ER_UNKNOWN_TABLE
625+
handler t1_alias read next;
626+
627+
# Test that temporary tables associated with handlers are properly dropped.
628+
629+
create table t1 (a int);
630+
create temporary table t2 (a int, key(a));
631+
handler t1 open as a1;
632+
handler t2 open as a2;
633+
handler a2 read a first;
634+
drop table t1, t2;
635+
--error ER_UNKNOWN_TABLE
636+
handler a2 read a next;
637+
--error ER_UNKNOWN_TABLE
638+
handler a1 close;
639+
640+
# Alter table drop handlers
641+
642+
create table t1 (a int, key(a));
643+
create table t2 like t1;
644+
handler t1 open as a1;
645+
handler t2 open as a2;
646+
handler a1 read a first;
647+
handler a2 read a first;
648+
alter table t1 add b int;
649+
--error ER_UNKNOWN_TABLE
650+
handler a1 close;
651+
handler a2 close;
652+
drop table t1, t2;
653+
654+
# Rename table drop handlers
655+
656+
create table t1 (a int, key(a));
657+
handler t1 open as a1;
658+
handler a1 read a first;
659+
rename table t1 to t2;
660+
--error ER_UNKNOWN_TABLE
661+
handler a1 read a first;
662+
drop table t2;
663+
664+
# Optimize table drop handlers
665+
666+
create table t1 (a int, key(a));
667+
create table t2 like t1;
668+
handler t1 open as a1;
669+
handler t2 open as a2;
670+
handler a1 read a first;
671+
handler a2 read a first;
672+
optimize table t1;
673+
--error ER_UNKNOWN_TABLE
674+
handler a1 close;
675+
handler a2 close;
676+
drop table t1, t2;
677+
678+
# Flush tables causes handlers reopen
679+
680+
create table t1 (a int, b char(1), key a(a), key b(a,b));
681+
insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
682+
(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j");
683+
handler t1 open;
684+
handler t1 read a first;
685+
handler t1 read a next;
686+
flush tables;
687+
handler t1 read a next;
688+
handler t1 read a next;
689+
flush tables with read lock;
690+
handler t1 read a next;
691+
unlock tables;
692+
drop table t1;
693+
--error ER_UNKNOWN_TABLE
694+
handler t1 read a next;

mysql-test/r/handler_innodb.result

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,3 +637,94 @@ a b
637637
8 i
638638
handler a2 close;
639639
drop table t1;
640+
drop table if exists t1,t2;
641+
create table t1 (a int);
642+
handler t1 open as t1_alias;
643+
drop table t1;
644+
create table t1 (a int);
645+
handler t1 open as t1_alias;
646+
flush tables;
647+
drop table t1;
648+
create table t1 (a int);
649+
handler t1 open as t1_alias;
650+
handler t1_alias close;
651+
drop table t1;
652+
create table t1 (a int);
653+
handler t1 open as t1_alias;
654+
handler t1_alias read first;
655+
a
656+
drop table t1;
657+
handler t1_alias read next;
658+
ERROR 42S02: Unknown table 't1_alias' in HANDLER
659+
create table t1 (a int);
660+
create temporary table t2 (a int, key(a));
661+
handler t1 open as a1;
662+
handler t2 open as a2;
663+
handler a2 read a first;
664+
a
665+
drop table t1, t2;
666+
handler a2 read a next;
667+
ERROR 42S02: Unknown table 'a2' in HANDLER
668+
handler a1 close;
669+
ERROR 42S02: Unknown table 'a1' in HANDLER
670+
create table t1 (a int, key(a));
671+
create table t2 like t1;
672+
handler t1 open as a1;
673+
handler t2 open as a2;
674+
handler a1 read a first;
675+
a
676+
handler a2 read a first;
677+
a
678+
alter table t1 add b int;
679+
handler a1 close;
680+
ERROR 42S02: Unknown table 'a1' in HANDLER
681+
handler a2 close;
682+
drop table t1, t2;
683+
create table t1 (a int, key(a));
684+
handler t1 open as a1;
685+
handler a1 read a first;
686+
a
687+
rename table t1 to t2;
688+
handler a1 read a first;
689+
ERROR 42S02: Unknown table 'a1' in HANDLER
690+
drop table t2;
691+
create table t1 (a int, key(a));
692+
create table t2 like t1;
693+
handler t1 open as a1;
694+
handler t2 open as a2;
695+
handler a1 read a first;
696+
a
697+
handler a2 read a first;
698+
a
699+
optimize table t1;
700+
Table Op Msg_type Msg_text
701+
test.t1 optimize status OK
702+
handler a1 close;
703+
ERROR 42S02: Unknown table 'a1' in HANDLER
704+
handler a2 close;
705+
drop table t1, t2;
706+
create table t1 (a int, b char(1), key a(a), key b(a,b));
707+
insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
708+
(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j");
709+
handler t1 open;
710+
handler t1 read a first;
711+
a b
712+
0 a
713+
handler t1 read a next;
714+
a b
715+
1 b
716+
flush tables;
717+
handler t1 read a next;
718+
a b
719+
0 a
720+
handler t1 read a next;
721+
a b
722+
1 b
723+
flush tables with read lock;
724+
handler t1 read a next;
725+
a b
726+
0 a
727+
unlock tables;
728+
drop table t1;
729+
handler t1 read a next;
730+
ERROR 42S02: Unknown table 't1' in HANDLER

mysql-test/r/handler_myisam.result

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,3 +637,94 @@ a b
637637
8 i
638638
handler a2 close;
639639
drop table t1;
640+
drop table if exists t1,t2;
641+
create table t1 (a int);
642+
handler t1 open as t1_alias;
643+
drop table t1;
644+
create table t1 (a int);
645+
handler t1 open as t1_alias;
646+
flush tables;
647+
drop table t1;
648+
create table t1 (a int);
649+
handler t1 open as t1_alias;
650+
handler t1_alias close;
651+
drop table t1;
652+
create table t1 (a int);
653+
handler t1 open as t1_alias;
654+
handler t1_alias read first;
655+
a
656+
drop table t1;
657+
handler t1_alias read next;
658+
ERROR 42S02: Unknown table 't1_alias' in HANDLER
659+
create table t1 (a int);
660+
create temporary table t2 (a int, key(a));
661+
handler t1 open as a1;
662+
handler t2 open as a2;
663+
handler a2 read a first;
664+
a
665+
drop table t1, t2;
666+
handler a2 read a next;
667+
ERROR 42S02: Unknown table 'a2' in HANDLER
668+
handler a1 close;
669+
ERROR 42S02: Unknown table 'a1' in HANDLER
670+
create table t1 (a int, key(a));
671+
create table t2 like t1;
672+
handler t1 open as a1;
673+
handler t2 open as a2;
674+
handler a1 read a first;
675+
a
676+
handler a2 read a first;
677+
a
678+
alter table t1 add b int;
679+
handler a1 close;
680+
ERROR 42S02: Unknown table 'a1' in HANDLER
681+
handler a2 close;
682+
drop table t1, t2;
683+
create table t1 (a int, key(a));
684+
handler t1 open as a1;
685+
handler a1 read a first;
686+
a
687+
rename table t1 to t2;
688+
handler a1 read a first;
689+
ERROR 42S02: Unknown table 'a1' in HANDLER
690+
drop table t2;
691+
create table t1 (a int, key(a));
692+
create table t2 like t1;
693+
handler t1 open as a1;
694+
handler t2 open as a2;
695+
handler a1 read a first;
696+
a
697+
handler a2 read a first;
698+
a
699+
optimize table t1;
700+
Table Op Msg_type Msg_text
701+
test.t1 optimize status Table is already up to date
702+
handler a1 close;
703+
ERROR 42S02: Unknown table 'a1' in HANDLER
704+
handler a2 close;
705+
drop table t1, t2;
706+
create table t1 (a int, b char(1), key a(a), key b(a,b));
707+
insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
708+
(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j");
709+
handler t1 open;
710+
handler t1 read a first;
711+
a b
712+
0 a
713+
handler t1 read a next;
714+
a b
715+
1 b
716+
flush tables;
717+
handler t1 read a next;
718+
a b
719+
0 a
720+
handler t1 read a next;
721+
a b
722+
1 b
723+
flush tables with read lock;
724+
handler t1 read a next;
725+
a b
726+
0 a
727+
unlock tables;
728+
drop table t1;
729+
handler t1 read a next;
730+
ERROR 42S02: Unknown table 't1' in HANDLER

sql/mysql_priv.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,12 +1289,9 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
12891289
bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
12901290
bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
12911291
List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
1292-
int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags,
1293-
bool is_locked);
1294-
/* mysql_ha_flush mode_flags bits */
1295-
#define MYSQL_HA_CLOSE_FINAL 0x00
1296-
#define MYSQL_HA_REOPEN_ON_USAGE 0x01
1297-
#define MYSQL_HA_FLUSH_ALL 0x02
1292+
void mysql_ha_flush(THD *thd);
1293+
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables);
1294+
void mysql_ha_cleanup(THD *thd);
12981295

12991296
/* sql_base.cc */
13001297
#define TMP_TABLE_KEY_EXTRA 8

sql/sql_base.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -929,8 +929,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
929929
thd->proc_info="Flushing tables";
930930

931931
close_old_data_files(thd,thd->open_tables,1,1);
932-
mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL,
933-
TRUE);
932+
mysql_ha_flush(thd);
933+
934934
bool found=1;
935935
/* Wait until all threads has closed all the tables we had locked */
936936
DBUG_PRINT("info",
@@ -2516,7 +2516,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
25162516
deadlock may occur.
25172517
*/
25182518
if (thd->handler_tables)
2519-
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
2519+
mysql_ha_flush(thd);
25202520

25212521
/*
25222522
Actually try to find the table in the open_cache.
@@ -3136,7 +3136,7 @@ bool wait_for_tables(THD *thd)
31363136
{
31373137
thd->some_tables_deleted=0;
31383138
close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0);
3139-
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
3139+
mysql_ha_flush(thd);
31403140
if (!table_is_used(thd->open_tables,1))
31413141
break;
31423142
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);

sql/sql_class.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -678,9 +678,7 @@ void THD::cleanup(void)
678678
lock=locked_tables; locked_tables=0;
679679
close_thread_tables(this);
680680
}
681-
mysql_ha_flush(this, (TABLE_LIST*) 0,
682-
MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL, FALSE);
683-
hash_free(&handler_tables_hash);
681+
mysql_ha_cleanup(this);
684682
delete_dynamic(&user_var_events);
685683
hash_free(&user_vars);
686684
close_temporary_tables(this);

0 commit comments

Comments
 (0)