diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index bf9108459d7..934085ab796 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2141,4 +2141,24 @@ SELECT * FROM m1; c1 DROP TABLE m1; DROP TABLE t1; +# +# Bug45781 infinite hang/crash in "opening tables" after handler tries to +# open merge table +# +DROP TABLE IF EXISTS m1,t1; +CREATE TABLE t1(a int)engine=myisam; +CREATE TABLE t2(a int)engine=myisam; +CREATE TABLE t3(a int)engine=myisam; +CREATE TABLE t4(a int)engine=myisam; +CREATE TABLE t5(a int)engine=myisam; +CREATE TABLE t6(a int)engine=myisam; +CREATE TABLE t7(a int)engine=myisam; +CREATE TABLE m1(a int)engine=merge union=(t1,t2,t3,t4,t5,t6,t7); +SELECT 1 FROM m1; +1 +HANDLER m1 OPEN; +ERROR HY000: Table storage engine for 'm1' doesn't have this option +DROP TABLE m1,t1,t2,t3,t4,t5,t6,t7; +SELECT 1 FROM m1; +ERROR 42S02: Table 'test.m1' doesn't exist End of 5.1 tests diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 8760876b7ee..0d90468fc8d 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1555,4 +1555,28 @@ SELECT * FROM m1; DROP TABLE m1; DROP TABLE t1; +--echo # +--echo # Bug45781 infinite hang/crash in "opening tables" after handler tries to +--echo # open merge table +--echo # + +--disable_warnings +DROP TABLE IF EXISTS m1,t1; +--enable_warnings + +CREATE TABLE t1(a int)engine=myisam; +CREATE TABLE t2(a int)engine=myisam; +CREATE TABLE t3(a int)engine=myisam; +CREATE TABLE t4(a int)engine=myisam; +CREATE TABLE t5(a int)engine=myisam; +CREATE TABLE t6(a int)engine=myisam; +CREATE TABLE t7(a int)engine=myisam; +CREATE TABLE m1(a int)engine=merge union=(t1,t2,t3,t4,t5,t6,t7); +SELECT 1 FROM m1; +--error ER_ILLEGAL_HA +HANDLER m1 OPEN; +DROP TABLE m1,t1,t2,t3,t4,t5,t6,t7; +--error ER_NO_SUCH_TABLE +SELECT 1 FROM m1; # Should not hang! + --echo End of 5.1 tests diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 16810e29343..1e92d95573a 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -252,14 +252,37 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) /* for now HANDLER can be used only for real TABLES */ tables->required_type= FRMTYPE_TABLE; + /* + We use open_tables() here, rather than, say, + open_ltable() or open_table() because we would like to be able + to open a temporary table. + */ error= open_tables(thd, &tables, &counter, 0); - /* restore the state and merge the opened table into handler_tables list */ if (thd->open_tables) { - thd->open_tables->next= thd->handler_tables; - thd->handler_tables= thd->open_tables; + if (thd->open_tables->next) + { + /* + We opened something that is more than a single table. + This happens with MERGE engine. Don't try to link + this mess into thd->handler_tables list, close it + and report an error. We must do it right away + because mysql_ha_close_table(), called down the road, + can close a single table only. + */ + close_thread_tables(thd); + my_error(ER_ILLEGAL_HA, MYF(0), tables->alias); + error= 1; + } + else + { + /* Merge the opened table into handler_tables list. */ + thd->open_tables->next= thd->handler_tables; + thd->handler_tables= thd->open_tables; + } } + /* Restore the state. */ thd->open_tables= backup_open_tables; if (error)