Bug#38499: flush tables and multitable table update with

derived table cause crash

When a multi-UPDATE command fails to lock some table, and
subsequently succeeds, the tables need to be reopened if
they were altered. But the reopening procedure failed for
derived tables.

Extra cleanup has been added.
This commit is contained in:
Gleb Shchepa 2008-10-09 20:24:31 +05:00
parent 453bc6c1aa
commit 0b38c93d6e
4 changed files with 240 additions and 1 deletions

View File

@ -115,3 +115,21 @@ CREATE TABLE t3 SELECT * FROM t1;
# normal mode # normal mode
# PS mode # PS mode
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
CREATE TABLE t1( a INT, b INT );
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4);
# 1. test regular tables
# 1.1. test altering of columns that multiupdate doesn't use
# 1.1.1. normal mode
# 1.1.2. PS mode
# 1.2. test altering of columns that multiupdate uses
# 1.2.1. normal mode
# 1.2.2. PS mode
ALTER TABLE t1 ADD COLUMN a INT;
# 2. test UNIONs
# 2.1. test altering of columns that multiupdate doesn't use
# 2.1.1. normal mode
# 2.1.2. PS mode
# 2.2. test altering of columns that multiupdate uses
# 2.2.1. normal mode
# 2.2.2. PS mode
DROP TABLE t1;

View File

@ -400,4 +400,206 @@ while ($i) {
--connection default --connection default
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
#
# Bug#38499: flush tables and multitable table update with derived table cause
# crash
#
CREATE TABLE t1( a INT, b INT );
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4);
--echo # 1. test regular tables
--echo # 1.1. test altering of columns that multiupdate doesn't use
--echo # 1.1.1. normal mode
--disable_query_log
let $i = 100;
while ($i) {
--dec $i
--connection writer
send UPDATE t1, (SELECT 1 FROM t1 t1i) d SET a = 0 WHERE 1=0;
--connection locker
ALTER TABLE t1 ADD COLUMN (c INT);
ALTER TABLE t1 DROP COLUMN c;
--connection writer
--reap
}
--echo # 1.1.2. PS mode
--connection writer
PREPARE stmt FROM 'UPDATE t1, (SELECT 1 FROM t1 t1i) d SET a = 0 WHERE 1=0';
let $i = 100;
while ($i) {
--dec $i
--connection writer
--send EXECUTE stmt
--connection locker
ALTER TABLE t1 ADD COLUMN (c INT);
ALTER TABLE t1 DROP COLUMN c;
--connection writer
--reap
}
--enable_query_log
--echo # 1.2. test altering of columns that multiupdate uses
--echo # 1.2.1. normal mode
--connection default
--disable_query_log
let $i = 100;
while ($i) {
dec $i;
--connection locker
--error 0,1060
ALTER TABLE t1 ADD COLUMN a int(11) unsigned default NULL;
UPDATE t1 SET a=b;
--connection writer
--send UPDATE t1, (SELECT 1 FROM t1 t1i) d SET a = 0 WHERE 1=0;
--connection locker
--error 0,1091
ALTER TABLE t1 DROP COLUMN a;
--connection writer
--error 0,1054 # unknown column error
--reap
}
--enable_query_log
--echo # 1.2.2. PS mode
--disable_query_log
let $i = 100;
while ($i) {
dec $i;
--connection locker
--error 0,1060
ALTER TABLE t1 ADD COLUMN a INT;
UPDATE t1 SET a=b;
--connection writer
PREPARE stmt FROM 'UPDATE t1, (SELECT 1 FROM t1 t1i) d SET a = 0 WHERE 1=0';
--send EXECUTE stmt
--connection locker
--error 0,1091
ALTER TABLE t1 DROP COLUMN a;
--connection writer
--error 0,1054 # Unknown column 'a' in 'field list'
--reap
}
--enable_query_log
--connection default
ALTER TABLE t1 ADD COLUMN a INT;
--echo # 2. test UNIONs
--echo # 2.1. test altering of columns that multiupdate doesn't use
--echo # 2.1.1. normal mode
--disable_query_log
let $i = 100;
while ($i) {
--dec $i
--connection writer
send UPDATE t1, ((SELECT 1 FROM t1 t1i) UNION (SELECT 2 FROM t1 t1ii)) e SET a = 0 WHERE 1=0;
--connection locker
ALTER TABLE t1 ADD COLUMN (c INT);
ALTER TABLE t1 DROP COLUMN c;
--connection writer
--reap
}
--echo # 2.1.2. PS mode
--connection writer
PREPARE stmt FROM 'UPDATE t1, ((SELECT 1 FROM t1 t1i) UNION (SELECT 2 FROM t1 t1ii)) e SET a = 0 WHERE 1=0';
let $i = 100;
while ($i) {
--dec $i
--connection writer
--send EXECUTE stmt
--connection locker
ALTER TABLE t1 ADD COLUMN (c INT);
ALTER TABLE t1 DROP COLUMN c;
--connection writer
--reap
}
--enable_query_log
--echo # 2.2. test altering of columns that multiupdate uses
--echo # 2.2.1. normal mode
--connection default
--disable_query_log
let $i = 100;
while ($i) {
dec $i;
--connection locker
--error 0,1060
ALTER TABLE t1 ADD COLUMN a int(11) unsigned default NULL;
UPDATE t1 SET a=b;
--connection writer
--send UPDATE t1, ((SELECT 1 FROM t1 t1i) UNION (SELECT 2 FROM t1 t1ii)) e SET a = 0 WHERE 1=0;
--connection locker
--error 0,1091
ALTER TABLE t1 DROP COLUMN a;
--connection writer
--error 0,1054 # Unknown column 'a' in 'field list'
--reap
}
--enable_query_log
--echo # 2.2.2. PS mode
--disable_query_log
let $i = 100;
while ($i) {
dec $i;
--connection locker
--error 0,1060
ALTER TABLE t1 ADD COLUMN a INT;
UPDATE t1 SET a=b;
--connection writer
PREPARE stmt FROM 'UPDATE t1, ((SELECT 1 FROM t1 t1i) UNION (SELECT 2 FROM t1 t1ii)) e SET a = 0 WHERE 1=0';
--send EXECUTE stmt
--connection locker
--error 0,1091
ALTER TABLE t1 DROP COLUMN a;
--connection writer
--error 0,1054 # Unknown column 'a' in 'field list'
--reap
}
--enable_query_log
--connection default
DROP TABLE t1;
# End of 5.0 tests # End of 5.0 tests

View File

@ -399,7 +399,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
} }
else else
{ {
DBUG_ASSERT(!thd->stmt_arena->is_conventional());
/* /*
We're in execution of a prepared statement or stored procedure: We're in execution of a prepared statement or stored procedure:
reset field items to point at fields from the created temporary table. reset field items to point at fields from the created temporary table.

View File

@ -875,6 +875,26 @@ reopen_tables:
for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global)
tbl->cleanup_items(); tbl->cleanup_items();
/*
To not to hog memory (as a result of the
unit->reinit_exec_mechanism() call below):
*/
lex->unit.cleanup();
for (SELECT_LEX *sl= lex->all_selects_list;
sl;
sl= sl->next_select_in_list())
{
SELECT_LEX_UNIT *unit= sl->master_unit();
unit->reinit_exec_mechanism(); // reset unit->prepared flags
/*
Reset 'clean' flag back to force normal execution of
unit->cleanup() in Prepared_statement::cleanup_stmt()
(call to lex->unit.cleanup() above sets this flag to TRUE).
*/
unit->unclean();
}
/* /*
Also we need to cleanup Natural_join_column::table_field items. Also we need to cleanup Natural_join_column::table_field items.
To not to traverse a join tree we will cleanup whole To not to traverse a join tree we will cleanup whole