aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeWorktablescan.c64
-rw-r--r--src/test/regress/expected/with.out83
-rw-r--r--src/test/regress/sql/with.sql21
3 files changed, 144 insertions, 24 deletions
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index 2f09c5e22dd..a597240fe60 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeWorktablescan.c,v 1.1 2008/10/04 21:56:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeWorktablescan.c,v 1.2 2008/10/13 00:41:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -64,6 +64,40 @@ TupleTableSlot *
ExecWorkTableScan(WorkTableScanState *node)
{
/*
+ * On the first call, find the ancestor RecursiveUnion's state
+ * via the Param slot reserved for it. (We can't do this during node
+ * init because there are corner cases where we'll get the init call
+ * before the RecursiveUnion does.)
+ */
+ if (node->rustate == NULL)
+ {
+ WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
+ EState *estate = node->ss.ps.state;
+ ParamExecData *param;
+
+ param = &(estate->es_param_exec_vals[plan->wtParam]);
+ Assert(param->execPlan == NULL);
+ Assert(!param->isnull);
+ node->rustate = (RecursiveUnionState *) DatumGetPointer(param->value);
+ Assert(node->rustate && IsA(node->rustate, RecursiveUnionState));
+
+ /*
+ * The scan tuple type (ie, the rowtype we expect to find in the work
+ * table) is the same as the result rowtype of the ancestor
+ * RecursiveUnion node. Note this depends on the assumption that
+ * RecursiveUnion doesn't allow projection.
+ */
+ ExecAssignScanType(&node->ss,
+ ExecGetResultType(&node->rustate->ps));
+
+ /*
+ * Now we can initialize the projection info. This must be
+ * completed before we can call ExecScan().
+ */
+ ExecAssignScanProjectionInfo(&node->ss);
+ }
+
+ /*
* use WorkTableScanNext as access method
*/
return ExecScan(&node->ss, (ExecScanAccessMtd) WorkTableScanNext);
@@ -78,7 +112,6 @@ WorkTableScanState *
ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
{
WorkTableScanState *scanstate;
- ParamExecData *prmdata;
/* check for unsupported flags */
Assert(!(eflags & EXEC_FLAG_MARK));
@@ -95,16 +128,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
scanstate = makeNode(WorkTableScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
-
- /*
- * Find the ancestor RecursiveUnion's state
- * via the Param slot reserved for it.
- */
- prmdata = &(estate->es_param_exec_vals[node->wtParam]);
- Assert(prmdata->execPlan == NULL);
- Assert(!prmdata->isnull);
- scanstate->rustate = (RecursiveUnionState *) DatumGetPointer(prmdata->value);
- Assert(scanstate->rustate && IsA(scanstate->rustate, RecursiveUnionState));
+ scanstate->rustate = NULL; /* we'll set this later */
/*
* Miscellaneous initialization
@@ -132,19 +156,9 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
ExecInitScanTupleSlot(estate, &scanstate->ss);
/*
- * The scan tuple type (ie, the rowtype we expect to find in the work
- * table) is the same as the result rowtype of the ancestor RecursiveUnion
- * node. Note this depends on the assumption that RecursiveUnion doesn't
- * allow projection.
- */
- ExecAssignScanType(&scanstate->ss,
- ExecGetResultType(&scanstate->rustate->ps));
-
- /*
- * Initialize result tuple type and projection info.
+ * Initialize result tuple type, but not yet projection info.
*/
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
- ExecAssignScanProjectionInfo(&scanstate->ss);
scanstate->ss.ps.ps_TupFromTlist = false;
@@ -190,5 +204,7 @@ void
ExecWorkTableScanReScan(WorkTableScanState *node, ExprContext *exprCtxt)
{
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
- tuplestore_rescan(node->rustate->working_table);
+ /* No need (or way) to rescan if ExecWorkTableScan not called yet */
+ if (node->rustate)
+ tuplestore_rescan(node->rustate->working_table);
}
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index 4760aa9d9fd..fe7561065ed 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -292,6 +292,89 @@ SELECT pg_get_viewdef('vsubdepartment'::regclass, true);
FROM subdepartment;
(1 row)
+-- corner case in which sub-WITH gets initialized first
+with recursive q as (
+ select * from department
+ union all
+ (with x as (select * from q)
+ select * from x)
+ )
+select * from q limit 24;
+ id | parent_department | name
+----+-------------------+------
+ 0 | | ROOT
+ 1 | 0 | A
+ 2 | 1 | B
+ 3 | 2 | C
+ 4 | 2 | D
+ 5 | 0 | E
+ 6 | 4 | F
+ 7 | 5 | G
+ 0 | | ROOT
+ 1 | 0 | A
+ 2 | 1 | B
+ 3 | 2 | C
+ 4 | 2 | D
+ 5 | 0 | E
+ 6 | 4 | F
+ 7 | 5 | G
+ 0 | | ROOT
+ 1 | 0 | A
+ 2 | 1 | B
+ 3 | 2 | C
+ 4 | 2 | D
+ 5 | 0 | E
+ 6 | 4 | F
+ 7 | 5 | G
+(24 rows)
+
+with recursive q as (
+ select * from department
+ union all
+ (with recursive x as (
+ select * from department
+ union all
+ (select * from q union all select * from x)
+ )
+ select * from x)
+ )
+select * from q limit 32;
+ id | parent_department | name
+----+-------------------+------
+ 0 | | ROOT
+ 1 | 0 | A
+ 2 | 1 | B
+ 3 | 2 | C
+ 4 | 2 | D
+ 5 | 0 | E
+ 6 | 4 | F
+ 7 | 5 | G
+ 0 | | ROOT
+ 1 | 0 | A
+ 2 | 1 | B
+ 3 | 2 | C
+ 4 | 2 | D
+ 5 | 0 | E
+ 6 | 4 | F
+ 7 | 5 | G
+ 0 | | ROOT
+ 1 | 0 | A
+ 2 | 1 | B
+ 3 | 2 | C
+ 4 | 2 | D
+ 5 | 0 | E
+ 6 | 4 | F
+ 7 | 5 | G
+ 0 | | ROOT
+ 1 | 0 | A
+ 2 | 1 | B
+ 3 | 2 | C
+ 4 | 2 | D
+ 5 | 0 | E
+ 6 | 4 | F
+ 7 | 5 | G
+(32 rows)
+
-- recursive term has sub-UNION
WITH RECURSIVE t(i,j) AS (
VALUES (1,2)
diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql
index 60c545d0676..54d311101d1 100644
--- a/src/test/regress/sql/with.sql
+++ b/src/test/regress/sql/with.sql
@@ -178,6 +178,27 @@ SELECT * FROM vsubdepartment ORDER BY name;
SELECT pg_get_viewdef('vsubdepartment'::regclass);
SELECT pg_get_viewdef('vsubdepartment'::regclass, true);
+-- corner case in which sub-WITH gets initialized first
+with recursive q as (
+ select * from department
+ union all
+ (with x as (select * from q)
+ select * from x)
+ )
+select * from q limit 24;
+
+with recursive q as (
+ select * from department
+ union all
+ (with recursive x as (
+ select * from department
+ union all
+ (select * from q union all select * from x)
+ )
+ select * from x)
+ )
+select * from q limit 32;
+
-- recursive term has sub-UNION
WITH RECURSIVE t(i,j) AS (
VALUES (1,2)