summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavi Arnaut <Davi.Arnaut@Sun.COM>2009-02-24 10:49:18 +0100
committerDavi Arnaut <Davi.Arnaut@Sun.COM>2009-02-24 10:49:18 +0100
commit1959c4966ee1ebfacd52935ca58bcd55fe9b931c (patch)
tree43ee155a8a890841554f2f0aaf6bc027d48d57d9
parentd16c7dd1829e7dcfa2ef119fa04d090981936d09 (diff)
parent322a5a39adeb68ef336c1f3d44db4ef41063663c (diff)
downloadmariadb-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.inc26
-rw-r--r--mysql-test/r/handler_innodb.result9
-rw-r--r--mysql-test/r/handler_myisam.result9
-rw-r--r--sql/sql_handler.cc19
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;