summaryrefslogtreecommitdiff
path: root/sql/sql_update.cc
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2021-04-19 19:52:06 -0700
committerIgor Babaev <igor@askmonty.org>2021-04-22 13:56:50 -0700
commitb3b5d57e78f835473d13d383caacb7320b5938d5 (patch)
tree944f0e6eb27dbbd781d8f27618e4dce10986256c /sql/sql_update.cc
parent5c5d24c772d4596b0c28f2267477afe448d6e7f7 (diff)
downloadmariadb-git-b3b5d57e78f835473d13d383caacb7320b5938d5.tar.gz
MDEV-24823 Crash with invalid multi-table update of view in 2nd execution of SP
Before this patch mergeable derived tables / view used in a multi-table update / delete were merged before the preparation stage. When the merge of a derived table / view is performed the on expression attached to it is fixed and ANDed with the where condition of the select S containing this derived table / view. It happens after the specification of the derived table / view has been merged into S. If the ON expression refers to a non existing field an error is reported and some other mergeable derived tables / views remain unmerged. It's not a problem if the multi-table update / delete statement is standalone. Yet if it is used in a stored procedure the select with incompletely merged derived tables / views may cause a problem for the second call of the procedure. This does not happen for select queries using derived tables / views, because in this case their specifications are merged after the preparation stage at which all ON expressions are fixed. This patch makes sure that merging of the derived tables / views used in a multi-table update / delete statement is performed after the preparation stage. Approved by Oleksandr Byelkin <sanja@mariadb.com>
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r--sql/sql_update.cc41
1 files changed, 30 insertions, 11 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 01743a6751e..e8b973c03bd 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1390,15 +1390,8 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
call in setup_tables()).
*/
- if (setup_tables_and_check_access(thd, &select_lex->context,
- &select_lex->top_join_list, table_list, select_lex->leaf_tables,
- FALSE, UPDATE_ACL, SELECT_ACL, FALSE))
- DBUG_RETURN(1);
-
- if (select_lex->handle_derived(thd->lex, DT_MERGE))
- DBUG_RETURN(1);
-
- if (thd->lex->save_prep_leaf_tables())
+ if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
+ table_list, select_lex->leaf_tables, FALSE, TRUE))
DBUG_RETURN(1);
List<Item> *fields= &lex->select_lex.item_list;
@@ -1574,7 +1567,8 @@ int mysql_multi_update_prepare(THD *thd)
Check that we are not using table that we are updating, but we should
skip all tables of UPDATE SELECT itself
*/
- lex->select_lex.exclude_from_table_unique_test= TRUE;
+ lex->select_lex.set_unique_exclude();
+
/* We only need SELECT privilege for columns in the values list */
List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
while ((tl= ti++))
@@ -1635,9 +1629,16 @@ bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields,
DBUG_RETURN(TRUE);
}
+ if ((*result)->init(thd))
+ DBUG_RETURN(1);
+
thd->abort_on_warning= !ignore && thd->is_strict_mode();
List<Item> total_list;
+ if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
+ table_list, select_lex->leaf_tables, FALSE, FALSE))
+ DBUG_RETURN(1);
+
res= mysql_select(thd,
table_list, select_lex->with_wild, total_list,
conds, 0, NULL, NULL, NULL, NULL,
@@ -1673,6 +1674,24 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
{}
+bool multi_update::init(THD *thd)
+{
+ table_map tables_to_update= get_table_map(fields);
+ List_iterator_fast<TABLE_LIST> li(*leaves);
+ TABLE_LIST *tbl;
+ while ((tbl =li++))
+ {
+ if (tbl->is_jtbm())
+ continue;
+ if (!(tbl->table->map & tables_to_update))
+ continue;
+ if (updated_leaves.push_back(tbl, thd->mem_root))
+ return true;
+ }
+ return false;
+}
+
+
/*
Connect fields with tables and create list of tables that are updated
*/
@@ -1689,7 +1708,7 @@ int multi_update::prepare(List<Item> &not_used_values,
List_iterator_fast<Item> value_it(*values);
uint i, max_fields;
uint leaf_table_count= 0;
- List_iterator<TABLE_LIST> ti(*leaves);
+ List_iterator<TABLE_LIST> ti(updated_leaves);
DBUG_ENTER("multi_update::prepare");
if (prepared)