diff --git a/mysql-test/r/cte_nonrecursive.result b/mysql-test/r/cte_nonrecursive.result index 453f1319ccb..36982d3673b 100644 --- a/mysql-test/r/cte_nonrecursive.result +++ b/mysql-test/r/cte_nonrecursive.result @@ -1079,3 +1079,52 @@ id select_type table type possible_keys key key_len ref rows Extra 3 DERIVED t2 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL DROP TABLE t1,t2; +# +# MDEV-13780: tower of embedding CTEs with multiple usage of them +# +create table t1 (a int); +insert into t1 values (3), (2), (4), (7), (1), (2), (5); +with cte_e as +( +with cte_o as +( +with cte_i as (select * from t1 where a < 7) +select * from cte_i where a > 1 +) +select * from cte_o as cto_o1 where a < 3 +union +select * from cte_o as cto_o2 where a > 4 +) +select * from cte_e as cte_e1 where a > 1 +union +select * from cte_e as cte_e2; +a +2 +5 +explain extended with cte_e as +( +with cte_o as +( +with cte_i as (select * from t1 where a < 7) +select * from cte_i where a > 1 +) +select * from cte_o as cto_o1 where a < 3 +union +select * from cte_o as cto_o2 where a > 4 +) +select * from cte_e as cte_e1 where a > 1 +union +select * from cte_e as cte_e2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY ALL NULL NULL NULL NULL 14 100.00 Using where +2 DERIVED t1 ALL NULL NULL NULL NULL 7 100.00 Using where +5 UNION t1 ALL NULL NULL NULL NULL 7 100.00 Using where +NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL +6 UNION ALL NULL NULL NULL NULL 14 100.00 +9 DERIVED t1 ALL NULL NULL NULL NULL 7 100.00 Using where +12 UNION t1 ALL NULL NULL NULL NULL 7 100.00 Using where +NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL +NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1003 with cte_e as (with cte_o as (with cte_i as (select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` < 7)select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` > 1)select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` < 3 and `test`.`t1`.`a` > 1 and `test`.`t1`.`a` < 7 and `test`.`t1`.`a` > 1 union select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` > 4 and `test`.`t1`.`a` > 1 and `test`.`t1`.`a` < 7 and `test`.`t1`.`a` > 1)select `cte_e1`.`a` AS `a` from `cte_e` `cte_e1` where `cte_e1`.`a` > 1 union select `cte_e2`.`a` AS `a` from `cte_e` `cte_e2` +drop table t1; diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result index 057e3fe034c..b744f24bb57 100644 --- a/mysql-test/r/cte_recursive.result +++ b/mysql-test/r/cte_recursive.result @@ -2875,3 +2875,25 @@ f 2 set standard_compliant_cte=default; DROP TABLE t; +# +# mdev-14184: recursive CTE embedded into CTE with multiple references +# +WITH +cte1 AS ( +SELECT n FROM ( +WITH RECURSIVE rec_cte(n) AS ( +SELECT 1 as n1 +UNION ALL +SELECT n+1 as n2 FROM rec_cte WHERE n < 3 +) SELECT n FROM rec_cte +) AS X +), +cte2 as ( +SELECT 2 FROM cte1 +) +SELECT * +FROM cte1; +n +1 +2 +3 diff --git a/mysql-test/t/cte_nonrecursive.test b/mysql-test/t/cte_nonrecursive.test index 57b7ae1658f..c9639f50a19 100644 --- a/mysql-test/t/cte_nonrecursive.test +++ b/mysql-test/t/cte_nonrecursive.test @@ -743,3 +743,31 @@ eval $q; eval explain $q; DROP TABLE t1,t2; + +--echo # +--echo # MDEV-13780: tower of embedding CTEs with multiple usage of them +--echo # + +create table t1 (a int); +insert into t1 values (3), (2), (4), (7), (1), (2), (5); + +let $q= +with cte_e as +( + with cte_o as + ( + with cte_i as (select * from t1 where a < 7) + select * from cte_i where a > 1 + ) + select * from cte_o as cto_o1 where a < 3 + union + select * from cte_o as cto_o2 where a > 4 +) +select * from cte_e as cte_e1 where a > 1 +union +select * from cte_e as cte_e2; + +eval $q; +eval explain extended $q; + +drop table t1; diff --git a/mysql-test/t/cte_recursive.test b/mysql-test/t/cte_recursive.test index 5701ee896cb..36d948251c3 100644 --- a/mysql-test/t/cte_recursive.test +++ b/mysql-test/t/cte_recursive.test @@ -1928,3 +1928,22 @@ set standard_compliant_cte=default; DROP TABLE t; +--echo # +--echo # mdev-14184: recursive CTE embedded into CTE with multiple references +--echo # + +WITH +cte1 AS ( + SELECT n FROM ( + WITH RECURSIVE rec_cte(n) AS ( + SELECT 1 as n1 + UNION ALL + SELECT n+1 as n2 FROM rec_cte WHERE n < 3 + ) SELECT n FROM rec_cte + ) AS X +), +cte2 as ( + SELECT 2 FROM cte1 +) +SELECT * +FROM cte1; diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index e1af30123f6..6fe08e3c0ed 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -349,7 +349,10 @@ void With_element::check_dependencies_in_select(st_select_lex *sl, /* Now look for the dependencies in the subqueries of sl */ st_select_lex_unit *inner_unit= sl->first_inner_unit(); for (; inner_unit; inner_unit= inner_unit->next_unit()) - check_dependencies_in_unit(inner_unit, ctxt, in_subq, dep_map); + { + if (!inner_unit->with_element) + check_dependencies_in_unit(inner_unit, ctxt, in_subq, dep_map); + } } @@ -838,7 +841,6 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd, with_table->next_global= spec_tables; } res= &lex->unit; - res->set_with_clause(owner); lex->unit.include_down(with_table->select_lex); lex->unit.set_slave(with_select); @@ -847,6 +849,8 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd, insert_chain_before( (st_select_lex_node **) &(old_lex->all_selects_list), with_select)); + if (check_dependencies_in_with_clauses(lex->with_clauses_list)) + res= NULL; lex_end(lex); err: if (arena) @@ -990,14 +994,18 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) and it was unsuccesful. Yet for units cloned from the spec it has not been done yet. */ - if (with_elem && sl->master_unit() == with_elem->spec) + With_clause *attached_with_clause=sl->get_with_clause(); + if (attached_with_clause && + (found= attached_with_clause->find_table_def(table, NULL))) break; - With_clause *with_clause=sl->get_with_clause(); - if (with_clause) + if (with_elem) { - With_element *barrier= with_clause->with_recursive ? NULL : with_elem; - if ((found= with_clause->find_table_def(table, barrier))) + With_clause *containing_with_clause= with_elem->get_owner(); + With_element *barrier= containing_with_clause->with_recursive ? + NULL : with_elem; + if ((found= containing_with_clause->find_table_def(table, barrier))) break; + sl= sl->master_unit()->outer_select(); } master_unit= sl->master_unit(); /* Do not look for the table's definition beyond the scope of the view */