From 977e840d66be2c9238117f14055141e7e41d9d8c Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Sat, 20 Jun 2026 19:55:35 +0700 Subject: [PATCH] MDEV-32326 Recursive CTE reference in a scalar subquery must be rejected A recursive reference to a WITH RECURSIVE table that is reachable only through a scalar subquery (in particular through a WITH clause nested inside such a subquery) was not recognized as a subquery reference. As a result the recursive CTE was wrongly accepted as standard-compliant instead of being rejected with ER_NOT_STANDARD_COMPLIANT_RECURSIVE, and execution later dereferenced an uninitialized join_tab for that reference in st_select_lex_unit::exec_recursive(), crashing the server. The cause was in With_element::check_dependencies_in_unit(). The flag marking that we are inside a subquery (in_subq) was updated only after the unit's own WITH clause had already been analyzed. Hence dependencies discovered while descending into a WITH clause attached to a scalar subquery were recorded in top_level_dep_map instead of sq_dep_map, so contains_sq_with_recursive_reference() failed to report the violation. The fix: set in_subq from unit->item before processing the unit's WITH clause, so that dependencies found in nested WITH clauses of a scalar subquery are correctly attributed to the subquery context. The expected error for the MDEV-32299 cases in cte_recursive.test changes accordingly from ER_BAD_FIELD_ERROR to ER_NOT_STANDARD_COMPLIANT_RECURSIVE: the query is now rejected at dependency analysis for its non-compliant recursive reference rather than failing later during name resolution. The test still verifies that no crash occurs. --- mysql-test/main/cte_recursive.result | 13 +++++++++++-- mysql-test/main/cte_recursive.test | 15 +++++++++++++-- sql/sql_cte.cc | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/cte_recursive.result b/mysql-test/main/cte_recursive.result index a84a99ca3605e..2c319d4072a23 100644 --- a/mysql-test/main/cte_recursive.result +++ b/mysql-test/main/cte_recursive.result @@ -5979,7 +5979,7 @@ ERROR 42S22: Unknown column 'x' in 'SELECT' # MDEV-32299 Segfault when preparing unreferenced select in recursive CTE # SELECT ( WITH RECURSIVE x AS ( SELECT * FROM ( SELECT UTC_TIMESTAMP FROM ( SELECT ( WITH x AS ( WITH x AS ( SELECT * FROM x ) SELECT 1 ) SELECT 1 ) ) x ) x UNION SELECT NULL ) ( SELECT x FROM x ) ) ; -ERROR 42S22: Unknown column 'x' in 'SELECT' +ERROR HY000: Restrictions imposed on recursive definitions are violated for table 'x' select ( with recursive x as ( select * from ( @@ -6001,7 +6001,7 @@ select null ) (select x from x) ); -ERROR 42S22: Unknown column 'x' in 'SELECT' +ERROR HY000: Restrictions imposed on recursive definitions are violated for table 'x' select ( with recursive r as ( select * from ( @@ -6153,4 +6153,13 @@ y 2 2 4 +# +# MDEV-32326: Recursive reference in scalar subquery should be rejected +# +WITH RECURSIVE x AS ( +SELECT 1 +UNION +SELECT 1 > ( WITH cte AS ( SELECT 1 FROM x ) SELECT 1 FROM cte ) ) +SELECT 1 FROM x; +ERROR HY000: Restrictions imposed on recursive definitions are violated for table 'x' # End of 10.11 tests diff --git a/mysql-test/main/cte_recursive.test b/mysql-test/main/cte_recursive.test index d6fb2a47884ed..906118898b9e8 100644 --- a/mysql-test/main/cte_recursive.test +++ b/mysql-test/main/cte_recursive.test @@ -4071,12 +4071,12 @@ SELECT ( WITH RECURSIVE x AS ( WITH x AS ( SELECT 1 FROM t14 ) SELECT x ) , t14 --echo # # As in bug report ---error ER_BAD_FIELD_ERROR +--error ER_NOT_STANDARD_COMPLIANT_RECURSIVE SELECT ( WITH RECURSIVE x AS ( SELECT * FROM ( SELECT UTC_TIMESTAMP FROM ( SELECT ( WITH x AS ( WITH x AS ( SELECT * FROM x ) SELECT 1 ) SELECT 1 ) ) x ) x UNION SELECT NULL ) ( SELECT x FROM x ) ) ; #0 0x00005555569dff7b in TABLE_LIST::reset_const_table (this=0x7fffe0019938) at ../src/sql/table.cc:9615 #1 0x00005555569dffd4 in TABLE_LIST::reset_const_table (this=0x7fffe001a8c0) at ../src/sql/table.cc:9622 ---error ER_BAD_FIELD_ERROR +--error ER_NOT_STANDARD_COMPLIANT_RECURSIVE select ( with recursive x as ( select * from ( @@ -4240,4 +4240,15 @@ with recursive r (y) as ( select z * 2 from r where z < 10) select y from r; +--echo # +--echo # MDEV-32326: Recursive reference in scalar subquery should be rejected +--echo # + +--ERROR ER_NOT_STANDARD_COMPLIANT_RECURSIVE +WITH RECURSIVE x AS ( + SELECT 1 + UNION + SELECT 1 > ( WITH cte AS ( SELECT 1 FROM x ) SELECT 1 FROM cte ) ) + SELECT 1 FROM x; + --echo # End of 10.11 tests diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 8f819a7a94420..4c4887d4d70b4 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -653,13 +653,13 @@ void With_element::check_dependencies_in_unit(st_select_lex_unit *unit, table_map *dep_map) { st_unit_ctxt_elem unit_ctxt_elem= {ctxt, unit}; + in_subq |= unit->item != NULL; if (unit->with_clause) { (void) unit->with_clause->check_dependencies(); check_dependencies_in_with_clause(unit->with_clause, &unit_ctxt_elem, in_subq, dep_map); } - in_subq |= unit->item != NULL; st_select_lex *sl= unit->first_select(); for (; sl; sl= sl->next_select()) {