*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
*/
ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
{
WorkTableScanState *scanstate;
- ParamExecData *prmdata;
/* check for unsupported flags */
Assert(!(eflags & EXEC_FLAG_MARK));
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
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;
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);
}
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)