diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2015-11-03 09:31:20 +0100 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2015-11-05 17:50:59 +0100 |
commit | 5041de97e15e4af05003a8c6c14bfff106da570b (patch) | |
tree | 4937735c3ae99e1df7732ffa9f12c94d18f2910e | |
parent | d9119710c44d0cd785447080c43bf3c2ba2e4cac (diff) | |
download | mariadb-git-5041de97e15e4af05003a8c6c14bfff106da570b.tar.gz |
MDEV-8701 Crash on derived query
Make unique table check after setup_fields of update because unique table can materialize table and we do not need field resolving after materialization.
-rw-r--r-- | mysql-test/r/update.result | 35 | ||||
-rw-r--r-- | mysql-test/t/update.test | 41 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 3 | ||||
-rw-r--r-- | sql/sql_update.cc | 32 | ||||
-rw-r--r-- | sql/sql_update.h | 1 |
5 files changed, 102 insertions, 10 deletions
diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index db7c2380398..2e883aa5680 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -644,4 +644,39 @@ Handler_read_rnd 2 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 drop table t1, t2; +# +#MDEV-8701: Crash on derived query +# +CREATE TABLE t1 ( +data_exit_entry_id int(11) NOT NULL, +data_entry_id int(11) NOT NULL, +data_entry_exit_id int(11) NOT NULL, +data_exit_entry_quantity double NOT NULL +) DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( +data_entry_id int(11) NOT NULL, +data_entry_cost double NOT NULL, +data_entry_quantity double NOT NULL +) DEFAULT CHARSET=utf8; +create algorithm=temptable view v1 as SELECT data_entry_exit_id, data_exit_entry_quantity, data_entry_cost +FROM t1 INNER JOIN t2 as dt ON dt.data_entry_id = t1.data_entry_id; +UPDATE t2 +SET data_entry_cost += ( ( SELECT SUM(data_exit_entry_quantity * data_entry_cost) +FROM +v1 AS query +WHERE data_entry_exit_id = t2.data_entry_id +) +); +UPDATE t2 +SET data_entry_cost += ( ( SELECT SUM(data_exit_entry_quantity * data_entry_cost) +FROM +( SELECT data_entry_exit_id, data_exit_entry_quantity, data_entry_cost +FROM t1 INNER JOIN t2 as dt ON dt.data_entry_id = t1.data_entry_id) AS query +WHERE data_entry_exit_id = t2.data_entry_id +) +); +drop view v1; +drop table t1, t2; # End of MariaDB 10.0 tests diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 05f9ce39bec..c0334a75bff 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -580,4 +580,45 @@ show status like 'Handler_read%'; drop table t1, t2; +--echo # +--echo #MDEV-8701: Crash on derived query +--echo # + +CREATE TABLE t1 ( + data_exit_entry_id int(11) NOT NULL, + data_entry_id int(11) NOT NULL, + data_entry_exit_id int(11) NOT NULL, + data_exit_entry_quantity double NOT NULL +) DEFAULT CHARSET=utf8; + +CREATE TABLE t2 ( + data_entry_id int(11) NOT NULL, + data_entry_cost double NOT NULL, + data_entry_quantity double NOT NULL +) DEFAULT CHARSET=utf8; + +create algorithm=temptable view v1 as SELECT data_entry_exit_id, data_exit_entry_quantity, data_entry_cost + FROM t1 INNER JOIN t2 as dt ON dt.data_entry_id = t1.data_entry_id; + +UPDATE t2 +SET data_entry_cost + = ( ( SELECT SUM(data_exit_entry_quantity * data_entry_cost) + FROM + v1 AS query + WHERE data_entry_exit_id = t2.data_entry_id + ) + ); + +UPDATE t2 +SET data_entry_cost + = ( ( SELECT SUM(data_exit_entry_quantity * data_entry_cost) + FROM + ( SELECT data_entry_exit_id, data_exit_entry_quantity, data_entry_cost + FROM t1 INNER JOIN t2 as dt ON dt.data_entry_id = t1.data_entry_id) AS query + WHERE data_entry_exit_id = t2.data_entry_id + ) + ); + +drop view v1; +drop table t1, t2; --echo # End of MariaDB 10.0 tests diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 1790b972724..8a3c55cbfda 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1420,7 +1420,8 @@ static int mysql_test_update(Prepared_statement *stmt, (SELECT_ACL & ~table_list->table->grant.privilege); table_list->register_want_access(SELECT_ACL); #endif - if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0)) + if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0) || + check_unique_table(thd, table_list)) goto error; /* TODO: here we should send types of placeholders to the client. */ DBUG_RETURN(0); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d3d222620a8..0f7b28cd9d9 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -364,6 +364,9 @@ int mysql_update(THD *thd, DBUG_RETURN(1); /* purecov: inspected */ } + if (check_unique_table(thd, table_list)) + DBUG_RETURN(TRUE); + /* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */ if (select_lex->optimize_unflattened_subqueries(false)) DBUG_RETURN(TRUE); @@ -1095,19 +1098,30 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); - /* Check that we are not using table that we are updating in a sub select */ - { - TABLE_LIST *duplicate; - if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0))) - { - update_non_unique_table_error(table_list, "UPDATE", duplicate); - DBUG_RETURN(TRUE); - } - } select_lex->fix_prepare_information(thd, conds, &fake_conds); DBUG_RETURN(FALSE); } +/** + Check that we are not using table that we are updating in a sub select + + @param thd Thread handle + @param table_list List of table with first to check + + @retval TRUE Error + @retval FALSE OK +*/ +bool check_unique_table(THD *thd, TABLE_LIST *table_list) +{ + TABLE_LIST *duplicate; + DBUG_ENTER("check_unique_table"); + if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0))) + { + update_non_unique_table_error(table_list, "UPDATE", duplicate); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} /*************************************************************************** Update multiple tables from join diff --git a/sql/sql_update.h b/sql/sql_update.h index 64029c5d634..4c6f89d8468 100644 --- a/sql/sql_update.h +++ b/sql/sql_update.h @@ -27,6 +27,7 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT; bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, Item **conds, uint order_num, ORDER *order); +bool check_unique_table(THD *thd, TABLE_LIST *table_list); int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, List<Item> &values,COND *conds, uint order_num, ORDER *order, ha_rows limit, |