summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2015-06-06 16:13:51 +0200
committerOleksandr Byelkin <sanja@mariadb.com>2015-06-06 16:13:51 +0200
commit6264451f25143c43e1ad8e045054b720effaf8cb (patch)
treeab0f44608429ecf9714ed3abf04c4d7574c6bd61
parent9a3b975da677e77d63f72f0e6bf0450161b4672d (diff)
downloadmariadb-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.result31
-rw-r--r--mysql-test/t/update_innodb.test39
-rw-r--r--sql/sql_base.cc3
-rw-r--r--sql/sql_lex.cc14
-rw-r--r--sql/sql_lex.h3
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) */