diff options
author | Igor Babaev <igor@askmonty.org> | 2020-11-10 16:02:30 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2020-11-13 08:07:20 -0800 |
commit | 190e8a4c2aeb417b405756b193e135c542d46b34 (patch) | |
tree | 13089ec6e59355967259d1b996f4dc029f083dfb /sql/sql_select.cc | |
parent | 984a06db2ce2b2e3c7c5028245905417f2141cd7 (diff) | |
download | mariadb-git-190e8a4c2aeb417b405756b193e135c542d46b34.tar.gz |
MDEV-23619 MariaDB crash on WITH RECURSIVE UNION ALL (CTE) query
Due to a premature cleanup of the unit that specified a recursive CTE
used in the second operand of union the server fell into an infinite
loop in the reported test case. In other cases this premature cleanup
could cause other problems.
The bug is the result of a not quite correct fix for MDEV-17024. The
unit that specifies a recursive CTE has to be cleaned only after the
cleanup of the last external reference to this CTE. It means that
cleanups of the unit triggered not by the cleanup of a external
reference to the CTE must be blocked.
Usage of local table chains in selects to get external references to
recursive CTEs was not correct either because of possible merges of
some selects.
Also fixed a minor bug in st_select_lex::set_explain_type() that caused
typing 'RECURSIVE UNION' instead of 'UNION' in EXPLAIN output for external
references to a recursive CTE.
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d1076a54f1b..8b4401b1009 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12275,6 +12275,9 @@ void JOIN::join_free() for (tmp_unit= select_lex->first_inner_unit(); tmp_unit; tmp_unit= tmp_unit->next_unit()) + { + if (tmp_unit->with_element && tmp_unit->with_element->is_recursive) + continue; for (sl= tmp_unit->first_select(); sl; sl= sl->next_select()) { Item_subselect *subselect= sl->master_unit()->item; @@ -12292,7 +12295,7 @@ void JOIN::join_free() /* Can't unlock if at least one JOIN is still needed */ can_unlock= can_unlock && full_local; } - + } /* We are not using tables anymore Unlock all tables. We may be in an INSERT .... SELECT statement. |