mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
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>
This commit is contained in:
@ -1571,15 +1571,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;
|
||||
@ -1755,6 +1748,7 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
skip all tables of UPDATE SELECT itself
|
||||
*/
|
||||
lex->select_lex.exclude_from_table_unique_test= TRUE;
|
||||
|
||||
/* We only need SELECT privilege for columns in the values list */
|
||||
List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
|
||||
while ((tl= ti++))
|
||||
@ -1805,9 +1799,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);
|
||||
|
||||
if (select_lex->vers_setup_conds(thd, table_list))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
@ -1849,6 +1850,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
|
||||
*/
|
||||
@ -1865,7 +1884,7 @@ int multi_update::prepare(List<Item> ¬_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)
|
||||
|
Reference in New Issue
Block a user