diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2015-06-06 16:13:51 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2015-06-06 16:13:51 +0200 |
commit | 6264451f25143c43e1ad8e045054b720effaf8cb (patch) | |
tree | ab0f44608429ecf9714ed3abf04c4d7574c6bd61 | |
parent | 9a3b975da677e77d63f72f0e6bf0450161b4672d (diff) | |
download | mariadb-git-6264451f25143c43e1ad8e045054b720effaf8cb.tar.gz |
MDEV-8114: server crash on updates with joins still on 10.0.18
Check that leaf table list is really built before storing it.
-rw-r--r-- | mysql-test/r/update_innodb.result | 31 | ||||
-rw-r--r-- | mysql-test/t/update_innodb.test | 39 | ||||
-rw-r--r-- | sql/sql_base.cc | 3 | ||||
-rw-r--r-- | sql/sql_lex.cc | 14 | ||||
-rw-r--r-- | sql/sql_lex.h | 3 |
5 files changed, 86 insertions, 4 deletions
diff --git a/mysql-test/r/update_innodb.result b/mysql-test/r/update_innodb.result new file mode 100644 index 00000000000..88c86c50625 --- /dev/null +++ b/mysql-test/r/update_innodb.result @@ -0,0 +1,31 @@ +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; diff --git a/mysql-test/t/update_innodb.test b/mysql-test/t/update_innodb.test new file mode 100644 index 00000000000..67c356c4e2e --- /dev/null +++ b/mysql-test/t/update_innodb.test @@ -0,0 +1,39 @@ +--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; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 592215da4d0..fcd17b25b2d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8291,9 +8291,10 @@ bool setup_tables(THD *thd, Name_resolution_context *context, if (select_lex->first_cond_optimization) { 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); + select_lex->prep_leaf_list_state= SELECT_LEX::READY; select_lex->leaf_tables_exec.empty(); } else diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a71051e801b..1d62acdbe4b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1882,7 +1882,7 @@ void st_select_lex::init_query() exclude_from_table_unique_test= no_wrap_view_item= FALSE; nest_level= 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)); m_non_agg_field_used= false; m_agg_func_used= false; @@ -4129,12 +4129,22 @@ bool st_select_lex::save_prep_leaf_tables(THD *thd) { List_iterator_fast<TABLE_LIST> li(leaf_tables); 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++)) { if (leaf_tables_prep.push_back(table)) 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 *sl= u->first_select(); sl; sl= sl->next_select()) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 69ee5cc9be0..a0f8e456800 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -789,7 +789,8 @@ public: List<TABLE_LIST> leaf_tables; List<TABLE_LIST> leaf_tables_exec; 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; st_select_lex *merged_into; /* select which this select is merged into */ /* (not 0 only for views/derived tables) */ |