Skip to content

Commit 9e321a4

Browse files
committed
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>
1 parent 80ea359 commit 9e321a4

File tree

3 files changed

+54
-4
lines changed

3 files changed

+54
-4
lines changed

mysql-test/main/cte_nonrecursive.result

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2599,4 +2599,29 @@ src path dest distance population
25992599
E FD D 251 80000
26002600
drop procedure sp;
26012601
drop table distances, city_population;
2602+
#
2603+
# MDEV-28615: Multi-table UPDATE over derived table containing
2604+
# row that uses subquery with hanging CTE
2605+
#
2606+
CREATE TABLE t1 (a int) ENGINE=MYISAM;
2607+
INSERT INTO t1 VALUES (3), (7), (1);
2608+
UPDATE
2609+
(SELECT (5, (WITH cte AS (SELECT 1) SELECT a FROM t1))) dt
2610+
JOIN t1 t
2611+
ON t.a=dt.a
2612+
SET t.a = 1;
2613+
ERROR 21000: Operand should contain 1 column(s)
2614+
UPDATE
2615+
(SELECT a FROM t1
2616+
WHERE (5, (WITH cte AS (SELECT 1) SELECT a FROM t1 WHERE a > 4)) <=
2617+
(5,a)) dt
2618+
JOIN t1 t
2619+
ON t.a=dt.a
2620+
SET t.a = 1;
2621+
SELECT * FROM t1;
2622+
a
2623+
3
2624+
1
2625+
1
2626+
DROP TABLE t1;
26022627
# End of 10.4 tests

mysql-test/main/cte_nonrecursive.test

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,8 +1784,6 @@ with data as (select 1 as id)
17841784
select id into @myid from data;
17851785
set sql_mode= @save_sql_mode;
17861786

1787-
1788-
17891787
--echo #
17901788
--echo # MDEV-31995 CTE column name specification inconsistency
17911789
--echo #
@@ -1942,4 +1940,31 @@ drop procedure sp;
19421940

19431941
drop table distances, city_population;
19441942

1943+
--echo #
1944+
--echo # MDEV-28615: Multi-table UPDATE over derived table containing
1945+
--echo # row that uses subquery with hanging CTE
1946+
--echo #
1947+
1948+
CREATE TABLE t1 (a int) ENGINE=MYISAM;
1949+
INSERT INTO t1 VALUES (3), (7), (1);
1950+
1951+
--error ER_OPERAND_COLUMNS
1952+
UPDATE
1953+
(SELECT (5, (WITH cte AS (SELECT 1) SELECT a FROM t1))) dt
1954+
JOIN t1 t
1955+
ON t.a=dt.a
1956+
SET t.a = 1;
1957+
1958+
UPDATE
1959+
(SELECT a FROM t1
1960+
WHERE (5, (WITH cte AS (SELECT 1) SELECT a FROM t1 WHERE a > 4)) <=
1961+
(5,a)) dt
1962+
JOIN t1 t
1963+
ON t.a=dt.a
1964+
SET t.a = 1;
1965+
1966+
SELECT * FROM t1;
1967+
1968+
DROP TABLE t1;
1969+
19451970
--echo # End of 10.4 tests

sql/sql_cte.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,14 +1241,14 @@ bool With_element::prepare_unreferenced(THD *thd)
12411241
sl= sl->next_select())
12421242
sl->context.outer_context= 0;
12431243

1244+
uint8 save_context_analysys_only= thd->lex->context_analysis_only;
12441245
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
12451246
if (!spec->prepared &&
12461247
(spec->prepare(spec->derived, 0, 0) ||
12471248
rename_columns_of_derived_unit(thd, spec) ||
12481249
check_duplicate_names(thd, first_sl->item_list, 1)))
12491250
rc= true;
1250-
1251-
thd->lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED;
1251+
thd->lex->context_analysis_only= save_context_analysys_only;
12521252
return rc;
12531253
}
12541254

0 commit comments

Comments
 (0)