A fix and a test case for Bug#19399 "res 'Lost Connection' when
dropping/creating tables". The bug could lead to a crash when multi-delete statements were prepared and used with temporary tables. The bug was caused by lack of clean-up of multi-delete tables before re-execution of a prepared statement. In a statement like DELETE t1 FROM t1, t2 WHERE ... the first table list (t1) is moved to lex->auxilliary_table_list and excluded from lex->query_tables or select_lex->tables. Thus it was unaccessible to reinit_stmt_before_use and not cleaned up before re-execution of a prepared statement.
This commit is contained in:
parent
e343c0e214
commit
8e735d2c11
@ -875,3 +875,17 @@ select @@max_prepared_stmt_count, @@prepared_stmt_count;
|
||||
@@max_prepared_stmt_count @@prepared_stmt_count
|
||||
3 0
|
||||
set global max_prepared_stmt_count= @old_max_prepared_stmt_count;
|
||||
drop table if exists t1;
|
||||
create temporary table if not exists t1 (a1 int);
|
||||
prepare stmt from "delete t1 from t1 where (cast(a1/3 as unsigned) * 3) = a1";
|
||||
drop temporary table t1;
|
||||
create temporary table if not exists t1 (a1 int);
|
||||
execute stmt;
|
||||
drop temporary table t1;
|
||||
create temporary table if not exists t1 (a1 int);
|
||||
execute stmt;
|
||||
drop temporary table t1;
|
||||
create temporary table if not exists t1 (a1 int);
|
||||
execute stmt;
|
||||
drop temporary table t1;
|
||||
deallocate prepare stmt;
|
||||
|
@ -926,4 +926,29 @@ select @@max_prepared_stmt_count, @@prepared_stmt_count;
|
||||
set global max_prepared_stmt_count= @old_max_prepared_stmt_count;
|
||||
--enable_ps_protocol
|
||||
|
||||
#
|
||||
# Bug#19399 "Stored Procedures 'Lost Connection' when dropping/creating
|
||||
# tables"
|
||||
# Check that multi-delete tables are also cleaned up before re-execution.
|
||||
#
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
create temporary table if not exists t1 (a1 int);
|
||||
--enable_warnings
|
||||
# exact delete syntax is essential
|
||||
prepare stmt from "delete t1 from t1 where (cast(a1/3 as unsigned) * 3) = a1";
|
||||
drop temporary table t1;
|
||||
create temporary table if not exists t1 (a1 int);
|
||||
# the server crashed on the next statement without the fix
|
||||
execute stmt;
|
||||
drop temporary table t1;
|
||||
create temporary table if not exists t1 (a1 int);
|
||||
# the problem was in memory corruption: repeat the test just in case
|
||||
execute stmt;
|
||||
drop temporary table t1;
|
||||
create temporary table if not exists t1 (a1 int);
|
||||
execute stmt;
|
||||
drop temporary table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
@ -125,6 +125,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
|
||||
lex->value_list.empty();
|
||||
lex->update_list.empty();
|
||||
lex->param_list.empty();
|
||||
lex->auxilliary_table_list.empty();
|
||||
lex->unit.next= lex->unit.master=
|
||||
lex->unit.link_next= lex->unit.return_to= 0;
|
||||
lex->unit.prev= lex->unit.link_prev= 0;
|
||||
|
@ -1727,14 +1727,9 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
|
||||
tables;
|
||||
tables= tables->next)
|
||||
{
|
||||
/*
|
||||
Reset old pointers to TABLEs: they are not valid since the tables
|
||||
were closed in the end of previous prepare or execute call.
|
||||
*/
|
||||
tables->table= 0;
|
||||
tables->table_list= 0;
|
||||
tables->reinit_before_use(thd);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
SELECT_LEX_UNIT *unit= sl->master_unit();
|
||||
unit->unclean();
|
||||
@ -1743,6 +1738,17 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
|
||||
unit->reinit_exec_mechanism();
|
||||
}
|
||||
}
|
||||
/*
|
||||
Cleanup of the special case of DELETE t1, t2 FROM t1, t2, t3 ...
|
||||
(multi-delete). We do a full clean up, although at the moment all we
|
||||
need to clean in the tables of MULTI-DELETE list is 'table' member.
|
||||
*/
|
||||
for (TABLE_LIST *tables= (TABLE_LIST*) lex->auxilliary_table_list.first;
|
||||
tables;
|
||||
tables= tables->next)
|
||||
{
|
||||
tables->reinit_before_use(thd);
|
||||
}
|
||||
lex->current_select= &lex->select_lex;
|
||||
if (lex->result)
|
||||
lex->result->cleanup();
|
||||
|
17
sql/table.cc
17
sql/table.cc
@ -1523,6 +1523,23 @@ db_type get_table_type(const char *name)
|
||||
DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
|
||||
}
|
||||
|
||||
/*
|
||||
Cleanup this table for re-execution.
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::reinit_before_use()
|
||||
*/
|
||||
|
||||
void st_table_list::reinit_before_use(THD * /* thd */)
|
||||
{
|
||||
/*
|
||||
Reset old pointers to TABLEs: they are not valid since the tables
|
||||
were closed in the end of previous prepare or execute call.
|
||||
*/
|
||||
table= 0;
|
||||
table_list= 0;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Instansiate templates
|
||||
|
@ -238,6 +238,11 @@ typedef struct st_table_list
|
||||
bool cacheable_table; /* stop PS caching */
|
||||
/* used in multi-upd privelege check */
|
||||
bool table_in_update_from_clause;
|
||||
/*
|
||||
Cleanup for re-execution in a prepared statement or a stored
|
||||
procedure.
|
||||
*/
|
||||
void reinit_before_use(THD *thd);
|
||||
} TABLE_LIST;
|
||||
|
||||
typedef struct st_changed_table_list
|
||||
|
Loading…
x
Reference in New Issue
Block a user