Commit 11b20f27 authored by Davi Arnaut's avatar Davi Arnaut

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.

There is no test case in this change set as the test depends on
a testing feature only available on 5.1 and later.

sql/sql_handler.cc:
  Remove redundant reopen check.
  Set errors even if reopening table.
  Reset TABLE_LIST::table reference when the table is closed.
parent 982f88fc
...@@ -151,6 +151,9 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) ...@@ -151,6 +151,9 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables)
} }
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
} }
/* Mark table as closed, ready for re-open if necessary. */
tables->table= NULL;
} }
/* /*
...@@ -168,8 +171,7 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) ...@@ -168,8 +171,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, '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 'tables' is the pointer to the hashed TABLE_LIST object which has been
saved on the original open. saved on the original open.
'reopen' is also used to suppress the sending of an 'ok' message or 'reopen' is also used to suppress the sending of an 'ok' message.
error messages.
RETURN RETURN
FALSE OK FALSE OK
...@@ -205,8 +207,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) ...@@ -205,8 +207,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
strlen(tables->alias) + 1)) strlen(tables->alias) + 1))
{ {
DBUG_PRINT("info",("duplicate '%s'", tables->alias)); 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; goto err;
} }
} }
...@@ -251,8 +252,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) ...@@ -251,8 +252,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
/* There can be only one table in '*tables'. */ /* There can be only one table in '*tables'. */
if (! (tables->table->file->table_flags() & HA_CAN_SQL_HANDLER)) if (! (tables->table->file->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; goto err;
} }
...@@ -464,8 +464,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ...@@ -464,8 +464,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (need_reopen) if (need_reopen)
{ {
mysql_ha_close_table(thd, tables); mysql_ha_close_table(thd, hash_tables);
hash_tables->table= NULL;
/* /*
The lock might have been aborted, we need to manually reset The lock might have been aborted, we need to manually reset
thd->some_tables_deleted because handler's tables are closed thd->some_tables_deleted because handler's tables are closed
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment