mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-28965 Assertion failure when preparing UPDATE with derived table in WHERE
This patch fixes not only the assertion failure in the function Field_iterator_table_ref::set_field_iterator() but also: - fixes the problem of forced materialization of derived tables used in subqueries contained in WHERE clauses of single-table and multi-table UPDATE and DELETE statements - fixes the problem of MDEV-17954 that prevented execution of multi-table DELETE statements if they use in their WHERE clauses references to the tables that are updated. The patch must be considered a complement to the patch for MDEV-28883. Approved by Oleksandr Byelkin <sanja@mariadb.com>
This commit is contained in:
@@ -30,6 +30,8 @@
|
||||
#include "sql_base.h"
|
||||
#include "sql_const.h"
|
||||
#include "sql_select.h"
|
||||
#include "sql_update.h" // class Sql_cmd_update
|
||||
#include "sql_delete.h" // class Sql_cmd_delete
|
||||
#include "filesort.h"
|
||||
#include "opt_subselect.h"
|
||||
#include "sql_test.h"
|
||||
@@ -534,6 +536,48 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Check whether an IN subquery must be excluded from conversion to SJ
|
||||
|
||||
@param thd global context the processed statement
|
||||
@returns true if the IN subquery must be excluded from conversion to SJ
|
||||
|
||||
@note
|
||||
Currently a top level IN subquery of an delete statement is not converted
|
||||
to SJ if the statement contains ORDER BY ... LIMIT or contains RETURNING.
|
||||
|
||||
@todo
|
||||
The disjunctive members
|
||||
!((Sql_cmd_update *) cmd)->is_multitable()
|
||||
!((Sql_cmd_delete *) cmd)->is_multitable()
|
||||
will be removed when conversions of IN predicands to semi-joins are
|
||||
fully supported for single-table UPDATE/DELETE statements.
|
||||
*/
|
||||
|
||||
bool SELECT_LEX::is_sj_conversion_prohibited(THD *thd)
|
||||
{
|
||||
DBUG_ASSERT(master_unit()->item->substype() == Item_subselect::IN_SUBS);
|
||||
|
||||
SELECT_LEX *outer_sl= outer_select();
|
||||
if (outer_sl->outer_select())
|
||||
return false;
|
||||
|
||||
Sql_cmd *cmd= thd->lex->m_sql_cmd;
|
||||
|
||||
switch (thd->lex->sql_command) {
|
||||
case SQLCOM_UPDATE:
|
||||
return
|
||||
!((Sql_cmd_update *) cmd)->is_multitable() ||
|
||||
((Sql_cmd_update *) cmd)->processing_as_multitable_update_prohibited(thd);
|
||||
case SQLCOM_DELETE:
|
||||
return
|
||||
!((Sql_cmd_delete *) cmd)->is_multitable() ||
|
||||
((Sql_cmd_delete *) cmd)->processing_as_multitable_delete_prohibited(thd);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check if we need JOIN::prepare()-phase subquery rewrites and if yes, do them
|
||||
@@ -677,9 +721,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
3. Subquery does not have GROUP BY or ORDER BY
|
||||
4. Subquery does not use aggregate functions or HAVING
|
||||
5. Subquery predicate is at the AND-top-level of ON/WHERE clause
|
||||
6. We are not in a subquery of a single table UPDATE/DELETE that
|
||||
doesn't have a JOIN (TODO: We should handle this at some
|
||||
point by switching to multi-table UPDATE/DELETE)
|
||||
6. We are not in a subquery of a single-table UPDATE/DELETE that
|
||||
does not allow conversion to multi-table UPDATE/DELETE
|
||||
7. We're not in a table-less subquery like "SELECT 1"
|
||||
8. No execution method was already chosen (by a prepared statement)
|
||||
9. Parent select is not a table-less select
|
||||
@@ -698,9 +741,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
!select_lex->group_list.elements && !join->order && // 3
|
||||
!join->having && !select_lex->with_sum_func && // 4
|
||||
in_subs->emb_on_expr_nest && // 5
|
||||
select_lex->outer_select()->join && // 6
|
||||
(!thd->lex->m_sql_cmd ||
|
||||
thd->lex->m_sql_cmd->sql_command_code() == SQLCOM_UPDATE_MULTI) &&
|
||||
!select_lex->is_sj_conversion_prohibited(thd) && // 6
|
||||
parent_unit->first_select()->leaf_tables.elements && // 7
|
||||
!in_subs->has_strategy() && // 8
|
||||
select_lex->outer_select()->table_list.first && // 9
|
||||
@@ -760,7 +801,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
*/
|
||||
if (in_subs && !in_subs->has_strategy())
|
||||
{
|
||||
if (is_materialization_applicable(thd, in_subs, select_lex))
|
||||
if (!select_lex->is_sj_conversion_prohibited(thd) &&
|
||||
is_materialization_applicable(thd, in_subs, select_lex))
|
||||
{
|
||||
in_subs->add_strategy(SUBS_MATERIALIZATION);
|
||||
|
||||
|
Reference in New Issue
Block a user