Commit 9e321a44 authored by Igor Babaev's avatar Igor Babaev

MDEV-28615 Crash caused by multi-table UPDATE over derived with hanging CTE

This bug affected only multi-table update statements and in very rare
cases: one of the tables used at the top level of the statement must be
a derived table containg a row construct with a subquery including hanging
CTE.

Before this patch was applied the function prepare_unreferenced() of the
class With_element when invoked for the the hangin CTE did not properly
restored the value of thd->lex->context_analysis_only. As a result it
became 0 after the call of this function.
For a query affected by the bug this function is called when
JOIN::prepare() is called for the subquery with a hanging CTE. This happens
when Item_row::fix_fields() calls fix_fields() for the subquery. Setting
the value of thd->lex->context_analysis_only forces the caller function
Item_row::fix_fields() to invoke the virtual method is_null() for the
subquery that leads to execution of it. It causes an assertion failure
because the call of Item_row::fix_fields() happens during the invocation
of Multiupdate_prelocking_strategy::handle_end() that calls the function
mysql_derived_prepare() for the derived table used by the UPDATE at the
time when proper locks for the statement tables has not been acquired yet.

With this patch the value of thd->lex->context_analysis_only is restored
to CONTEXT_ANALYSIS_ONLY_DERIVED that is set in the function
mysql_multi_update_prepare().

Approved by Oleksandr Byelkin <sanja@mariadb.com>
parent 80ea3590
......@@ -2599,4 +2599,29 @@ src path dest distance population
E FD D 251 80000
drop procedure sp;
drop table distances, city_population;
#
# MDEV-28615: Multi-table UPDATE over derived table containing
# row that uses subquery with hanging CTE
#
CREATE TABLE t1 (a int) ENGINE=MYISAM;
INSERT INTO t1 VALUES (3), (7), (1);
UPDATE
(SELECT (5, (WITH cte AS (SELECT 1) SELECT a FROM t1))) dt
JOIN t1 t
ON t.a=dt.a
SET t.a = 1;
ERROR 21000: Operand should contain 1 column(s)
UPDATE
(SELECT a FROM t1
WHERE (5, (WITH cte AS (SELECT 1) SELECT a FROM t1 WHERE a > 4)) <=
(5,a)) dt
JOIN t1 t
ON t.a=dt.a
SET t.a = 1;
SELECT * FROM t1;
a
3
1
1
DROP TABLE t1;
# End of 10.4 tests
......@@ -1784,8 +1784,6 @@ with data as (select 1 as id)
select id into @myid from data;
set sql_mode= @save_sql_mode;
--echo #
--echo # MDEV-31995 CTE column name specification inconsistency
--echo #
......@@ -1942,4 +1940,31 @@ drop procedure sp;
drop table distances, city_population;
--echo #
--echo # MDEV-28615: Multi-table UPDATE over derived table containing
--echo # row that uses subquery with hanging CTE
--echo #
CREATE TABLE t1 (a int) ENGINE=MYISAM;
INSERT INTO t1 VALUES (3), (7), (1);
--error ER_OPERAND_COLUMNS
UPDATE
(SELECT (5, (WITH cte AS (SELECT 1) SELECT a FROM t1))) dt
JOIN t1 t
ON t.a=dt.a
SET t.a = 1;
UPDATE
(SELECT a FROM t1
WHERE (5, (WITH cte AS (SELECT 1) SELECT a FROM t1 WHERE a > 4)) <=
(5,a)) dt
JOIN t1 t
ON t.a=dt.a
SET t.a = 1;
SELECT * FROM t1;
DROP TABLE t1;
--echo # End of 10.4 tests
......@@ -1241,14 +1241,14 @@ bool With_element::prepare_unreferenced(THD *thd)
sl= sl->next_select())
sl->context.outer_context= 0;
uint8 save_context_analysys_only= thd->lex->context_analysis_only;
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
if (!spec->prepared &&
(spec->prepare(spec->derived, 0, 0) ||
rename_columns_of_derived_unit(thd, spec) ||
check_duplicate_names(thd, first_sl->item_list, 1)))
rc= true;
thd->lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED;
thd->lex->context_analysis_only= save_context_analysys_only;
return rc;
}
......
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