mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-07-19 19:39:38 +02:00
Fix list-manipulation bug in WITH RECURSIVE processing.
makeDependencyGraphWalker and checkWellFormedRecursionWalker
thought they could hold onto a pointer to a list's first
cons cell while the list was modified by recursive calls.
That was okay when the cons cell was actually separately
palloc'd ... but since commit 1cff1b95a
, it's quite unsafe,
leading to core dumps or incorrect complaints of faulty
WITH nesting.
In the field this'd require at least a seven-deep WITH nest
to cause an issue, but enabling DEBUG_LIST_MEMORY_USAGE
allows the bug to be seen with lesser nesting depths.
Per bug #16801 from Alexander Lakhin. Back-patch to v13.
Michael Paquier and Tom Lane
Discussion: https://postgr.es/m/16801-393c7922143eaa4d@postgresql.org
This commit is contained in:
parent
1f56ae3229
commit
49076fd3ba
@ -537,15 +537,15 @@ makeDependencyGraphWalker(Node *node, CteState *cstate)
|
|||||||
* In the non-RECURSIVE case, query names are visible to the
|
* In the non-RECURSIVE case, query names are visible to the
|
||||||
* WITH items after them and to the main query.
|
* WITH items after them and to the main query.
|
||||||
*/
|
*/
|
||||||
ListCell *cell1;
|
|
||||||
|
|
||||||
cstate->innerwiths = lcons(NIL, cstate->innerwiths);
|
cstate->innerwiths = lcons(NIL, cstate->innerwiths);
|
||||||
cell1 = list_head(cstate->innerwiths);
|
|
||||||
foreach(lc, stmt->withClause->ctes)
|
foreach(lc, stmt->withClause->ctes)
|
||||||
{
|
{
|
||||||
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
||||||
|
ListCell *cell1;
|
||||||
|
|
||||||
(void) makeDependencyGraphWalker(cte->ctequery, cstate);
|
(void) makeDependencyGraphWalker(cte->ctequery, cstate);
|
||||||
|
/* note that recursion could mutate innerwiths list */
|
||||||
|
cell1 = list_head(cstate->innerwiths);
|
||||||
lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
|
lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
|
||||||
}
|
}
|
||||||
(void) raw_expression_tree_walker(node,
|
(void) raw_expression_tree_walker(node,
|
||||||
@ -813,15 +813,15 @@ checkWellFormedRecursionWalker(Node *node, CteState *cstate)
|
|||||||
* In the non-RECURSIVE case, query names are visible to the
|
* In the non-RECURSIVE case, query names are visible to the
|
||||||
* WITH items after them and to the main query.
|
* WITH items after them and to the main query.
|
||||||
*/
|
*/
|
||||||
ListCell *cell1;
|
|
||||||
|
|
||||||
cstate->innerwiths = lcons(NIL, cstate->innerwiths);
|
cstate->innerwiths = lcons(NIL, cstate->innerwiths);
|
||||||
cell1 = list_head(cstate->innerwiths);
|
|
||||||
foreach(lc, stmt->withClause->ctes)
|
foreach(lc, stmt->withClause->ctes)
|
||||||
{
|
{
|
||||||
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
||||||
|
ListCell *cell1;
|
||||||
|
|
||||||
(void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
|
(void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
|
||||||
|
/* note that recursion could mutate innerwiths list */
|
||||||
|
cell1 = list_head(cstate->innerwiths);
|
||||||
lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
|
lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
|
||||||
}
|
}
|
||||||
checkWellFormedSelectStmt(stmt, cstate);
|
checkWellFormedSelectStmt(stmt, cstate);
|
||||||
|
@ -167,6 +167,65 @@ ERROR: operator does not exist: text + integer
|
|||||||
LINE 4: SELECT n+1 FROM t WHERE n < 10
|
LINE 4: SELECT n+1 FROM t WHERE n < 10
|
||||||
^
|
^
|
||||||
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
|
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
|
||||||
|
-- Deeply nested WITH caused a list-munging problem in v13
|
||||||
|
-- Detection of cross-references and self-references
|
||||||
|
WITH RECURSIVE w1(c1) AS
|
||||||
|
(WITH w2(c2) AS
|
||||||
|
(WITH w3(c3) AS
|
||||||
|
(WITH w4(c4) AS
|
||||||
|
(WITH w5(c5) AS
|
||||||
|
(WITH RECURSIVE w6(c6) AS
|
||||||
|
(WITH w6(c6) AS
|
||||||
|
(WITH w8(c8) AS
|
||||||
|
(SELECT 1)
|
||||||
|
SELECT * FROM w8)
|
||||||
|
SELECT * FROM w6)
|
||||||
|
SELECT * FROM w6)
|
||||||
|
SELECT * FROM w5)
|
||||||
|
SELECT * FROM w4)
|
||||||
|
SELECT * FROM w3)
|
||||||
|
SELECT * FROM w2)
|
||||||
|
SELECT * FROM w1;
|
||||||
|
c1
|
||||||
|
----
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Detection of invalid self-references
|
||||||
|
WITH RECURSIVE outermost(x) AS (
|
||||||
|
SELECT 1
|
||||||
|
UNION (WITH innermost1 AS (
|
||||||
|
SELECT 2
|
||||||
|
UNION (WITH innermost2 AS (
|
||||||
|
SELECT 3
|
||||||
|
UNION (WITH innermost3 AS (
|
||||||
|
SELECT 4
|
||||||
|
UNION (WITH innermost4 AS (
|
||||||
|
SELECT 5
|
||||||
|
UNION (WITH innermost5 AS (
|
||||||
|
SELECT 6
|
||||||
|
UNION (WITH innermost6 AS
|
||||||
|
(SELECT 7)
|
||||||
|
SELECT * FROM innermost6))
|
||||||
|
SELECT * FROM innermost5))
|
||||||
|
SELECT * FROM innermost4))
|
||||||
|
SELECT * FROM innermost3))
|
||||||
|
SELECT * FROM innermost2))
|
||||||
|
SELECT * FROM outermost
|
||||||
|
UNION SELECT * FROM innermost1)
|
||||||
|
)
|
||||||
|
SELECT * FROM outermost ORDER BY 1;
|
||||||
|
x
|
||||||
|
---
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Some examples with a tree
|
-- Some examples with a tree
|
||||||
--
|
--
|
||||||
|
@ -87,6 +87,50 @@ UNION ALL
|
|||||||
)
|
)
|
||||||
SELECT n, n IS OF (int) AS is_int FROM t;
|
SELECT n, n IS OF (int) AS is_int FROM t;
|
||||||
|
|
||||||
|
-- Deeply nested WITH caused a list-munging problem in v13
|
||||||
|
-- Detection of cross-references and self-references
|
||||||
|
WITH RECURSIVE w1(c1) AS
|
||||||
|
(WITH w2(c2) AS
|
||||||
|
(WITH w3(c3) AS
|
||||||
|
(WITH w4(c4) AS
|
||||||
|
(WITH w5(c5) AS
|
||||||
|
(WITH RECURSIVE w6(c6) AS
|
||||||
|
(WITH w6(c6) AS
|
||||||
|
(WITH w8(c8) AS
|
||||||
|
(SELECT 1)
|
||||||
|
SELECT * FROM w8)
|
||||||
|
SELECT * FROM w6)
|
||||||
|
SELECT * FROM w6)
|
||||||
|
SELECT * FROM w5)
|
||||||
|
SELECT * FROM w4)
|
||||||
|
SELECT * FROM w3)
|
||||||
|
SELECT * FROM w2)
|
||||||
|
SELECT * FROM w1;
|
||||||
|
-- Detection of invalid self-references
|
||||||
|
WITH RECURSIVE outermost(x) AS (
|
||||||
|
SELECT 1
|
||||||
|
UNION (WITH innermost1 AS (
|
||||||
|
SELECT 2
|
||||||
|
UNION (WITH innermost2 AS (
|
||||||
|
SELECT 3
|
||||||
|
UNION (WITH innermost3 AS (
|
||||||
|
SELECT 4
|
||||||
|
UNION (WITH innermost4 AS (
|
||||||
|
SELECT 5
|
||||||
|
UNION (WITH innermost5 AS (
|
||||||
|
SELECT 6
|
||||||
|
UNION (WITH innermost6 AS
|
||||||
|
(SELECT 7)
|
||||||
|
SELECT * FROM innermost6))
|
||||||
|
SELECT * FROM innermost5))
|
||||||
|
SELECT * FROM innermost4))
|
||||||
|
SELECT * FROM innermost3))
|
||||||
|
SELECT * FROM innermost2))
|
||||||
|
SELECT * FROM outermost
|
||||||
|
UNION SELECT * FROM innermost1)
|
||||||
|
)
|
||||||
|
SELECT * FROM outermost ORDER BY 1;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Some examples with a tree
|
-- Some examples with a tree
|
||||||
--
|
--
|
||||||
|
Loading…
Reference in New Issue
Block a user