[Commits] 7563d4c: MDEV-26135 Assertion failure when executing PS with a hanging recursive CTE

IgorBabaev igor at mariadb.com
Sat Jul 17 08:46:50 EEST 2021


revision-id: 7563d4c9270ebb789ca645266d34dc83fb6bd784 (mariadb-10.2.31-1059-g7563d4c)
parent(s): c47e4aab62c65e1a1d431f9888ba1bc6b9841687
author: Igor Babaev
committer: Igor Babaev
timestamp: 2021-07-16 22:46:50 -0700
message:

MDEV-26135 Assertion failure when executing PS with a hanging recursive CTE

The bug affected execution of queries with With clauses containing so-called
hanging recursive CTEs in PREPARE mode. A CTE is hanging if it's not used
in the query. Preparation of a prepared statement from a query with a
hanging CTE caused a leak in the server and execution of this prepared
statement led to an assert failure of the server built in the debug mode.
This happened because the units specifying recursive CTEs erroneously were
not cleaned up if those CTEs were hanging.
The patch enforces cleanup of hanging recursive CTEs in the same way as
other hanging CTEs.

Approved by dmitry.shulga at mariadb.com

---
 mysql-test/r/cte_recursive.result | 27 +++++++++++++++++++++++++++
 mysql-test/t/cte_recursive.test   | 21 +++++++++++++++++++++
 sql/sql_union.cc                  |  6 ++++--
 3 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result
index 3e92652..a4d821e 100644
--- a/mysql-test/r/cte_recursive.result
+++ b/mysql-test/r/cte_recursive.result
@@ -4454,5 +4454,32 @@ deallocate prepare stmt;
 drop table folks;
 set big_tables=@save_big_tables;
 #
+# MDEV-26135: execution of PS for query with hanging recursive CTE
+#
+create table t1 (a int);
+insert into t1 values (5), (7);
+create table t2 (b int);
+insert into t2 values (3), (7), (1);
+with recursive r as (select a from t1 union select a+1 from r where a < 10)
+select * from t2;
+b
+3
+7
+1
+prepare stmt from "with recursive r as (select a from t1 union select a+1 from r where a < 10)
+select * from t2";
+execute stmt;
+b
+3
+7
+1
+execute stmt;
+b
+3
+7
+1
+deallocate prepare stmt;
+drop table t1,t2;
+#
 # End of 10.2 tests
 #
diff --git a/mysql-test/t/cte_recursive.test b/mysql-test/t/cte_recursive.test
index 849e76b..49f9c1f 100644
--- a/mysql-test/t/cte_recursive.test
+++ b/mysql-test/t/cte_recursive.test
@@ -2820,5 +2820,26 @@ drop table folks;
 set big_tables=@save_big_tables;
 
 --echo #
+--echo # MDEV-26135: execution of PS for query with hanging recursive CTE
+--echo #
+
+create table t1 (a int);
+insert into t1 values (5), (7);
+create table t2 (b int);
+insert into t2 values (3), (7), (1);
+
+let $q=
+with recursive r as (select a from t1 union select a+1 from r where a < 10)
+select * from t2;
+
+eval $q;
+eval prepare stmt from "$q";
+execute stmt;
+execute stmt;
+deallocate prepare stmt;
+
+drop table t1,t2;
+
+--echo #
 --echo # End of 10.2 tests
 --echo #
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 7baedfb..e5648e6 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -1382,7 +1382,8 @@ bool st_select_lex_unit::cleanup()
   {
     DBUG_RETURN(FALSE);
   }
-  if (with_element && with_element->is_recursive && union_result)
+  if (with_element && with_element->is_recursive && union_result &&
+      with_element->rec_outer_references)
   {
     select_union_recursive *result= with_element->rec_result;
     if (++result->cleanup_count == with_element->rec_outer_references)
@@ -1584,7 +1585,8 @@ bool st_select_lex::cleanup()
   for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
        lex_unit= lex_unit->next_unit())
   {
-    if (lex_unit->with_element && lex_unit->with_element->is_recursive)
+    if (lex_unit->with_element && lex_unit->with_element->is_recursive &&
+        lex_unit->with_element->rec_outer_references)
       continue;
     error= (bool) ((uint) error | (uint) lex_unit->cleanup());
   }


More information about the commits mailing list