Commit c233d6e1 authored by unknown's avatar unknown

MDEV-7260: Crash in get_best_combination when executing multi-table UPDATE with nested views

Do not use merge_for_insert for commands which use SELECT because optimizer can't work with such tables.

Fixes which makes multi-delete working with normally merged views.
parent cfb7d5d7
...@@ -5398,6 +5398,19 @@ DROP VIEW v1; ...@@ -5398,6 +5398,19 @@ DROP VIEW v1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
create view v1 as select 1; create view v1 as select 1;
drop view v1; drop view v1;
#
# MDEV-7260: Crash in get_best_combination when executing multi-table
# UPDATE with nested views
#
CREATE TABLE `t1` (`id` bigint(20));
INSERT INTO `t1` VALUES (1),(2);
CREATE TABLE `t2` (`id` bigint(20));
CREATE TABLE `t3` (`id` bigint(20), `flag` tinyint(4));
create view v1 as select id from t1;
create view v2 as select t2.* from (t2 left join v1 using (id));
update t3 left join v2 using (id) set flag=flag+1;
drop view v2, v1;
drop table t1, t2, t3;
# ----------------------------------------------------------------- # -----------------------------------------------------------------
# -- End of 5.5 tests. # -- End of 5.5 tests.
# ----------------------------------------------------------------- # -----------------------------------------------------------------
......
...@@ -5345,6 +5345,28 @@ create view v1 as select 1; ...@@ -5345,6 +5345,28 @@ create view v1 as select 1;
drop view v1; drop view v1;
--echo #
--echo # MDEV-7260: Crash in get_best_combination when executing multi-table
--echo # UPDATE with nested views
--echo #
CREATE TABLE `t1` (`id` bigint(20));
INSERT INTO `t1` VALUES (1),(2);
CREATE TABLE `t2` (`id` bigint(20));
CREATE TABLE `t3` (`id` bigint(20), `flag` tinyint(4));
create view v1 as select id from t1;
create view v2 as select t2.* from (t2 left join v1 using (id));
update t3 left join v2 using (id) set flag=flag+1;
drop view v2, v1;
drop table t1, t2, t3;
--echo # ----------------------------------------------------------------- --echo # -----------------------------------------------------------------
--echo # -- End of 5.5 tests. --echo # -- End of 5.5 tests.
--echo # ----------------------------------------------------------------- --echo # -----------------------------------------------------------------
......
...@@ -2028,6 +2028,9 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, ...@@ -2028,6 +2028,9 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
bool check_alias) bool check_alias)
{ {
TABLE_LIST *dup; TABLE_LIST *dup;
table= table->find_table_for_update();
if (table->table && table->table->file->ht->db_type == DB_TYPE_MRG_MYISAM) if (table->table && table->table->file->ht->db_type == DB_TYPE_MRG_MYISAM)
{ {
TABLE_LIST *child; TABLE_LIST *child;
......
...@@ -657,9 +657,10 @@ multi_delete::initialize_tables(JOIN *join) ...@@ -657,9 +657,10 @@ multi_delete::initialize_tables(JOIN *join)
delete_while_scanning= 1; delete_while_scanning= 1;
for (walk= delete_tables; walk; walk= walk->next_local) for (walk= delete_tables; walk; walk= walk->next_local)
{ {
tables_to_delete_from|= walk->table->map; TABLE_LIST *tbl= walk->correspondent_table->find_table_for_update();
tables_to_delete_from|= tbl->table->map;
if (delete_while_scanning && if (delete_while_scanning &&
unique_table(thd, walk, join->tables_list, false)) unique_table(thd, tbl, join->tables_list, false))
{ {
/* /*
If the table we are going to delete from appears If the table we are going to delete from appears
......
...@@ -507,6 +507,9 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) ...@@ -507,6 +507,9 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
if (derived->is_materialized_derived()) if (derived->is_materialized_derived())
DBUG_RETURN(mysql_derived_prepare(thd, lex, derived)); DBUG_RETURN(mysql_derived_prepare(thd, lex, derived));
if ((thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI))
DBUG_RETURN(FALSE);
if (!derived->is_multitable()) if (!derived->is_multitable())
{ {
if (!derived->single_table_updatable()) if (!derived->single_table_updatable())
......
...@@ -1984,6 +1984,24 @@ struct TABLE_LIST ...@@ -1984,6 +1984,24 @@ struct TABLE_LIST
TABLE_LIST *find_underlying_table(TABLE *table); TABLE_LIST *find_underlying_table(TABLE *table);
TABLE_LIST *first_leaf_for_name_resolution(); TABLE_LIST *first_leaf_for_name_resolution();
TABLE_LIST *last_leaf_for_name_resolution(); TABLE_LIST *last_leaf_for_name_resolution();
/**
@brief
Find the bottom in the chain of embedded table VIEWs.
@detail
This is used for single-table UPDATE/DELETE when they are modifying a
single-table VIEW.
*/
TABLE_LIST *find_table_for_update()
{
TABLE_LIST *tbl= this;
while(!tbl->is_multitable() && tbl->single_table_updatable() &&
tbl->merge_underlying_list)
{
tbl= tbl->merge_underlying_list;
}
return tbl;
}
TABLE *get_real_join_table(); TABLE *get_real_join_table();
bool is_leaf_for_name_resolution(); bool is_leaf_for_name_resolution();
inline TABLE_LIST *top_table() inline TABLE_LIST *top_table()
......
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