summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sanja@askmonty.org>2015-02-11 01:26:50 +0100
committerunknown <sanja@askmonty.org>2015-02-11 01:26:50 +0100
commitc233d6e120e20ea39dc7b9eac4cef264befc3cd0 (patch)
treef3b4f22da053dd507e6cca358e91877211d54acf /sql
parentcfb7d5d78a8aa6a683cd7a2f745d98ecfaca0100 (diff)
downloadmariadb-git-c233d6e120e20ea39dc7b9eac4cef264befc3cd0.tar.gz
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.
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_base.cc3
-rw-r--r--sql/sql_delete.cc5
-rw-r--r--sql/sql_derived.cc3
-rw-r--r--sql/table.h18
4 files changed, 27 insertions, 2 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 90a12eb366d..3c36c2b514a 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2028,6 +2028,9 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
bool check_alias)
{
TABLE_LIST *dup;
+
+ table= table->find_table_for_update();
+
if (table->table && table->table->file->ht->db_type == DB_TYPE_MRG_MYISAM)
{
TABLE_LIST *child;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 97d3d10c21c..055b4858598 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -657,9 +657,10 @@ multi_delete::initialize_tables(JOIN *join)
delete_while_scanning= 1;
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 &&
- 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
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 004cccb41a9..56748fa110d 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -507,6 +507,9 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_RETURN(FALSE);
if (derived->is_materialized_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->single_table_updatable())
diff --git a/sql/table.h b/sql/table.h
index 8e8c2811b71..7a1e380f14c 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1984,6 +1984,24 @@ struct TABLE_LIST
TABLE_LIST *find_underlying_table(TABLE *table);
TABLE_LIST *first_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();
bool is_leaf_for_name_resolution();
inline TABLE_LIST *top_table()