mirror of
https://github.com/MariaDB/server.git
synced 2025-06-13 13:01:51 +03:00
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.
This commit is contained in:
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,7 +216,6 @@ 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);
|
||||
goto err;
|
||||
}
|
||||
@ -259,7 +260,6 @@ 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);
|
||||
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;
|
||||
|
Reference in New Issue
Block a user