From 08142504743bc79feb233f42ae24246273102813 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 5 Oct 2008 22:20:17 +0000 Subject: [PATCH] Fix markTargetListOrigin() to not fail on a simple-Var reference to a recursive CTE that we're still in progress of analyzing. Add a similar guard to the similar code in expandRecordVariable(), and tweak regression tests to cover this case. Per report from Dickson S. Guedes. --- src/backend/parser/parse_target.c | 17 +++++++++++++---- src/test/regress/expected/with.out | 18 +++++++++--------- src/test/regress/sql/with.sql | 4 ++-- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 3ead26194e..ed54abe703 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.165 2008/10/04 21:56:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.166 2008/10/05 22:20:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -297,8 +297,16 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle, /* not a simple relation, leave it unmarked */ break; case RTE_CTE: - /* CTE reference: copy up from the subquery */ - if (attnum != InvalidAttrNumber) + /* + * CTE reference: copy up from the subquery, if possible. + * If the RTE is a recursive self-reference then we can't do + * anything because we haven't finished analyzing it yet. + * However, it's no big loss because we must be down inside + * the recursive term of a recursive CTE, and so any markings + * on the current targetlist are not going to affect the results + * anyway. + */ + if (attnum != InvalidAttrNumber && !rte->self_reference) { CommonTableExpr *cte = GetCTEForRTE(pstate, rte); TargetEntry *ste; @@ -1195,8 +1203,9 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) */ break; case RTE_CTE: + /* CTE reference: examine subquery's output expr */ + if (!rte->self_reference) { - /* CTE reference: examine subquery's output expr */ CommonTableExpr *cte = GetCTEForRTE(pstate, rte); TargetEntry *ste; diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index ac91642c7b..65afc1a0c6 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -96,20 +96,20 @@ INSERT INTO department VALUES (7, 5, 'G'); WITH RECURSIVE subdepartment AS ( -- non recursive term - SELECT * FROM department WHERE name = 'A' + SELECT name as root_name, * FROM department WHERE name = 'A' UNION ALL -- recursive term - SELECT d.* FROM department AS d, subdepartment AS sd + SELECT sd.root_name, d.* FROM department AS d, subdepartment AS sd WHERE d.parent_department = sd.id ) SELECT * FROM subdepartment ORDER BY name; - id | parent_department | name -----+-------------------+------ - 1 | 0 | A - 2 | 1 | B - 3 | 2 | C - 4 | 2 | D - 6 | 4 | F + root_name | id | parent_department | name +-----------+----+-------------------+------ + A | 1 | 0 | A + A | 2 | 1 | B + A | 3 | 2 | C + A | 4 | 2 | D + A | 6 | 4 | F (5 rows) -- extract all departments under 'A' with "level" number diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql index 0ad59abdc9..cd8831f4b1 100644 --- a/src/test/regress/sql/with.sql +++ b/src/test/regress/sql/with.sql @@ -68,12 +68,12 @@ INSERT INTO department VALUES (7, 5, 'G'); WITH RECURSIVE subdepartment AS ( -- non recursive term - SELECT * FROM department WHERE name = 'A' + SELECT name as root_name, * FROM department WHERE name = 'A' UNION ALL -- recursive term - SELECT d.* FROM department AS d, subdepartment AS sd + SELECT sd.root_name, d.* FROM department AS d, subdepartment AS sd WHERE d.parent_department = sd.id ) SELECT * FROM subdepartment ORDER BY name;