diff options
author | Davi Arnaut <Davi.Arnaut@Sun.COM> | 2009-02-24 10:49:18 +0100 |
---|---|---|
committer | Davi Arnaut <Davi.Arnaut@Sun.COM> | 2009-02-24 10:49:18 +0100 |
commit | 1959c4966ee1ebfacd52935ca58bcd55fe9b931c (patch) | |
tree | 43ee155a8a890841554f2f0aaf6bc027d48d57d9 | |
parent | d16c7dd1829e7dcfa2ef119fa04d090981936d09 (diff) | |
parent | 322a5a39adeb68ef336c1f3d44db4ef41063663c (diff) | |
download | mariadb-git-1959c4966ee1ebfacd52935ca58bcd55fe9b931c.tar.gz |
Bug#41110: crash with handler command when used concurrently with alter table
Bug#41112: crash in mysql_ha_close_table/get_lock_data with alter table
The problem is that the server wasn't handling robustly failures
to re-open a table during a HANDLER .. READ statement. If the
table needed to be re-opened due to it's storage engine being
altered to one that doesn't support HANDLER, a reference (dangling
pointer) to a closed table could be left in place and accessed in
later attempts to fetch from the table using the handler. Also,
if the server failed to set a error message if the re-open
failed. These problems could lead to server crashes or hangs.
The solution is to remove any references to a closed table and
to set a error if reopening a table during a HANDLER .. READ
statement fails.
-rw-r--r-- | mysql-test/include/handler.inc | 26 | ||||
-rw-r--r-- | mysql-test/r/handler_innodb.result | 9 | ||||
-rw-r--r-- | mysql-test/r/handler_myisam.result | 9 | ||||
-rw-r--r-- | sql/sql_handler.cc | 19 |
4 files changed, 51 insertions, 12 deletions
diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc index 485b2e881d3..04f4cac831d 100644 --- a/mysql-test/include/handler.inc +++ b/mysql-test/include/handler.inc @@ -692,3 +692,29 @@ unlock tables; drop table t1; --error ER_UNKNOWN_TABLE handler t1 read a next; + +# +# Bug#41110: crash with handler command when used concurrently with alter table +# Bug#41112: crash in mysql_ha_close_table/get_lock_data with alter table +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +insert into t1 values (1); +handler t1 open; +connect(con1,localhost,root,,); +send alter table t1 engine=memory; +connection default; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "rename result table" and info = "alter table t1 engine=memory"; +--source include/wait_condition.inc +--error ER_ILLEGAL_HA +handler t1 read a next; +handler t1 close; +connection con1; +--reap +drop table t1; +connection default; diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index 3e4cef99480..59a46cabe5f 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -730,3 +730,12 @@ unlock tables; drop table t1; handler t1 read a next; ERROR 42S02: Unknown table 't1' in HANDLER +drop table if exists t1; +create table t1 (a int); +insert into t1 values (1); +handler t1 open; +alter table t1 engine=memory; +handler t1 read a next; +ERROR HY000: Table storage engine for 't1' doesn't have this option +handler t1 close; +drop table t1; diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index 0b27b07c4d2..afbf2d9fb6d 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -728,3 +728,12 @@ unlock tables; drop table t1; handler t1 read a next; ERROR 42S02: Unknown table 't1' in HANDLER +drop table if exists t1; +create table t1 (a int); +insert into t1 values (1); +handler t1 open; +alter table t1 engine=memory; +handler t1 read a next; +ERROR HY000: Table storage engine for 't1' doesn't have this option +handler t1 close; +drop table t1; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 28a9fb5c78e..9c8bba6208c 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -160,6 +160,9 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables, table->query_id= thd->query_id; table->open_by_handler= 0; } + + /* Mark table as closed, ready for re-open if necessary. */ + tables->table= NULL; } /* @@ -177,8 +180,7 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables, 'reopen' is set when a handler table is to be re-opened. In this case, 'tables' is the pointer to the hashed TABLE_LIST object which has been saved on the original open. - 'reopen' is also used to suppress the sending of an 'ok' message or - error messages. + 'reopen' is also used to suppress the sending of an 'ok' message. RETURN FALSE OK @@ -214,8 +216,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) strlen(tables->alias) + 1)) { DBUG_PRINT("info",("duplicate '%s'", tables->alias)); - if (! reopen) - my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias); + my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias); goto err; } } @@ -259,8 +260,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) /* There can be only one table in '*tables'. */ if (! (tables->table->file->ha_table_flags() & HA_CAN_SQL_HANDLER)) { - if (! reopen) - my_error(ER_ILLEGAL_HA, MYF(0), tables->alias); + my_error(ER_ILLEGAL_HA, MYF(0), tables->alias); goto err; } @@ -479,8 +479,7 @@ retry: if (need_reopen) { - mysql_ha_close_table(thd, tables, FALSE); - hash_tables->table= NULL; + mysql_ha_close_table(thd, hash_tables, FALSE); /* The lock might have been aborted, we need to manually reset thd->some_tables_deleted because handler's tables are closed @@ -761,11 +760,7 @@ void mysql_ha_flush(THD *thd) { hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i); if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock()) - { mysql_ha_close_table(thd, hash_tables, TRUE); - /* Mark table as closed, ready for re-open. */ - hash_tables->table= NULL; - } } DBUG_VOID_RETURN; |