Commit 6264451f authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-8114: server crash on updates with joins still on 10.0.18

Check that leaf table list is really built before storing it.
parent 9a3b975d
CREATE TABLE `t1` (
`c1` int(11) NOT NULL,
`c2` datetime DEFAULT NULL,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `t2` (
`c0` varchar(10) NOT NULL,
`c1` int(11) NOT NULL,
`c2` int(11) NOT NULL,
PRIMARY KEY (`c0`,`c1`),
KEY `c1` (`c1`),
KEY `c2` (`c2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `t3` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`c1` datetime NOT NULL,
`c2` bigint(20) NOT NULL,
`c3` int(4) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `c2` (`c2`),
KEY `c3` (`c3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `t4` (
`c1` int(11) NOT NULL,
`c2` bigint(20) DEFAULT NULL,
`c3` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE ALGORITHM=UNDEFINED VIEW `v1` AS select `t4`.`c1` AS `c1`,`t4`.`c2` AS `c2`,`t4`.`c3` AS `c3` from `t4`;
UPDATE t1 a JOIN t2 b ON a.c1 = b.c1 JOIN v1 vw ON b.c2 = vw.c1 JOIN t3 del ON vw.c2 = del.c2 SET a.c2 = ( SELECT max(t.c1) FROM t3 t, v1 i WHERE del.c2 = t.c2 AND vw.c3 = i.c3 AND t.c3 = 4 ) WHERE a.c2 IS NULL OR a.c2 < '2011-05-01';
drop view v1;
drop table t1,t2,t3,t4;
--source include/have_innodb.inc
CREATE TABLE `t1` (
`c1` int(11) NOT NULL,
`c2` datetime DEFAULT NULL,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `t2` (
`c0` varchar(10) NOT NULL,
`c1` int(11) NOT NULL,
`c2` int(11) NOT NULL,
PRIMARY KEY (`c0`,`c1`),
KEY `c1` (`c1`),
KEY `c2` (`c2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `t3` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`c1` datetime NOT NULL,
`c2` bigint(20) NOT NULL,
`c3` int(4) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `c2` (`c2`),
KEY `c3` (`c3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `t4` (
`c1` int(11) NOT NULL,
`c2` bigint(20) DEFAULT NULL,
`c3` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE ALGORITHM=UNDEFINED VIEW `v1` AS select `t4`.`c1` AS `c1`,`t4`.`c2` AS `c2`,`t4`.`c3` AS `c3` from `t4`;
UPDATE t1 a JOIN t2 b ON a.c1 = b.c1 JOIN v1 vw ON b.c2 = vw.c1 JOIN t3 del ON vw.c2 = del.c2 SET a.c2 = ( SELECT max(t.c1) FROM t3 t, v1 i WHERE del.c2 = t.c2 AND vw.c3 = i.c3 AND t.c3 = 4 ) WHERE a.c2 IS NULL OR a.c2 < '2011-05-01';
drop view v1;
drop table t1,t2,t3,t4;
...@@ -8291,9 +8291,10 @@ bool setup_tables(THD *thd, Name_resolution_context *context, ...@@ -8291,9 +8291,10 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
if (select_lex->first_cond_optimization) if (select_lex->first_cond_optimization)
{ {
leaves.empty(); leaves.empty();
if (!select_lex->is_prep_leaf_list_saved) if (select_lex->prep_leaf_list_state != SELECT_LEX::SAVED)
{ {
make_leaves_list(leaves, tables, full_table_list, first_select_table); make_leaves_list(leaves, tables, full_table_list, first_select_table);
select_lex->prep_leaf_list_state= SELECT_LEX::READY;
select_lex->leaf_tables_exec.empty(); select_lex->leaf_tables_exec.empty();
} }
else else
......
...@@ -1882,7 +1882,7 @@ void st_select_lex::init_query() ...@@ -1882,7 +1882,7 @@ void st_select_lex::init_query()
exclude_from_table_unique_test= no_wrap_view_item= FALSE; exclude_from_table_unique_test= no_wrap_view_item= FALSE;
nest_level= 0; nest_level= 0;
link_next= 0; link_next= 0;
is_prep_leaf_list_saved= FALSE; prep_leaf_list_state= UNINIT;
bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used)); bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used));
m_non_agg_field_used= false; m_non_agg_field_used= false;
m_agg_func_used= false; m_agg_func_used= false;
...@@ -4129,12 +4129,22 @@ bool st_select_lex::save_prep_leaf_tables(THD *thd) ...@@ -4129,12 +4129,22 @@ bool st_select_lex::save_prep_leaf_tables(THD *thd)
{ {
List_iterator_fast<TABLE_LIST> li(leaf_tables); List_iterator_fast<TABLE_LIST> li(leaf_tables);
TABLE_LIST *table; TABLE_LIST *table;
/*
Check that the SELECT_LEX was really prepared and so tables are setup.
It can be subquery in SET clause of UPDATE which was not prepared yet, so
its tables are not yet setup and ready for storing.
*/
if (prep_leaf_list_state != READY)
return FALSE;
while ((table= li++)) while ((table= li++))
{ {
if (leaf_tables_prep.push_back(table)) if (leaf_tables_prep.push_back(table))
return TRUE; return TRUE;
} }
is_prep_leaf_list_saved= TRUE; prep_leaf_list_state= SAVED;
for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit()) for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit())
{ {
for (SELECT_LEX *sl= u->first_select(); sl; sl= sl->next_select()) for (SELECT_LEX *sl= u->first_select(); sl; sl= sl->next_select())
......
...@@ -789,7 +789,8 @@ class st_select_lex: public st_select_lex_node ...@@ -789,7 +789,8 @@ class st_select_lex: public st_select_lex_node
List<TABLE_LIST> leaf_tables; List<TABLE_LIST> leaf_tables;
List<TABLE_LIST> leaf_tables_exec; List<TABLE_LIST> leaf_tables_exec;
List<TABLE_LIST> leaf_tables_prep; List<TABLE_LIST> leaf_tables_prep;
bool is_prep_leaf_list_saved; enum leaf_list_state {UNINIT, READY, SAVED};
enum leaf_list_state prep_leaf_list_state;
uint insert_tables; uint insert_tables;
st_select_lex *merged_into; /* select which this select is merged into */ st_select_lex *merged_into; /* select which this select is merged into */
/* (not 0 only for views/derived tables) */ /* (not 0 only for views/derived tables) */
......
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