1 /*-------------------------------------------------------------------------
4 * routines to handle CteScan nodes.
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
18 #include "executor/execdebug.h"
19 #include "executor/nodeCtescan.h"
20 #include "miscadmin.h"
22 static TupleTableSlot
*CteScanNext(CteScanState
*node
);
24 /* ----------------------------------------------------------------
27 * This is a workhorse for ExecCteScan
28 * ----------------------------------------------------------------
30 static TupleTableSlot
*
31 CteScanNext(CteScanState
*node
)
36 Tuplestorestate
*tuplestorestate
;
41 * get state info from node
43 estate
= node
->ss
.ps
.state
;
44 dir
= estate
->es_direction
;
45 forward
= ScanDirectionIsForward(dir
);
46 tuplestorestate
= node
->leader
->cte_table
;
47 tuplestore_select_read_pointer(tuplestorestate
, node
->readptr
);
48 slot
= node
->ss
.ss_ScanTupleSlot
;
51 * If we are not at the end of the tuplestore, or are going backwards, try
52 * to fetch a tuple from tuplestore.
54 eof_tuplestore
= tuplestore_ateof(tuplestorestate
);
56 if (!forward
&& eof_tuplestore
)
58 if (!node
->leader
->eof_cte
)
61 * When reversing direction at tuplestore EOF, the first
62 * gettupleslot call will fetch the last-added tuple; but we want
63 * to return the one before that, if possible. So do an extra
66 if (!tuplestore_advance(tuplestorestate
, forward
))
67 return NULL
; /* the tuplestore must be empty */
69 eof_tuplestore
= false;
73 * If we can fetch another tuple from the tuplestore, return it.
77 if (tuplestore_gettupleslot(tuplestorestate
, forward
, slot
))
80 eof_tuplestore
= true;
84 * If necessary, try to fetch another row from the CTE query.
86 * Note: the eof_cte state variable exists to short-circuit further calls
87 * of the CTE plan. It's not optional, unfortunately, because some plan
88 * node types are not robust about being called again when they've already
91 if (eof_tuplestore
&& !node
->leader
->eof_cte
)
93 TupleTableSlot
*cteslot
;
96 * We can only get here with forward==true, so no need to worry about
97 * which direction the subplan will go.
99 cteslot
= ExecProcNode(node
->cteplanstate
);
100 if (TupIsNull(cteslot
))
102 node
->leader
->eof_cte
= true;
107 * Append a copy of the returned tuple to tuplestore. NOTE: because
108 * our read pointer is certainly in EOF state, its read position will
109 * move forward over the added tuple. This is what we want. Also,
110 * any other readers will *not* move past the new tuple, which is
113 tuplestore_puttupleslot(tuplestorestate
, cteslot
);
116 * We MUST copy the CTE query's output tuple into our own slot.
117 * This is because other CteScan nodes might advance the CTE query
118 * before we are called again, and our output tuple must stay
121 return ExecCopySlot(slot
, cteslot
);
127 return ExecClearTuple(slot
);
130 /* ----------------------------------------------------------------
133 * Scans the CTE sequentially and returns the next qualifying tuple.
134 * It calls the ExecScan() routine and passes it the access method
135 * which retrieves tuples sequentially.
136 * ----------------------------------------------------------------
139 ExecCteScan(CteScanState
*node
)
142 * use CteScanNext as access method
144 return ExecScan(&node
->ss
, (ExecScanAccessMtd
) CteScanNext
);
148 /* ----------------------------------------------------------------
150 * ----------------------------------------------------------------
153 ExecInitCteScan(CteScan
*node
, EState
*estate
, int eflags
)
155 CteScanState
*scanstate
;
156 ParamExecData
*prmdata
;
158 /* check for unsupported flags */
159 Assert(!(eflags
& EXEC_FLAG_MARK
));
162 * For the moment we have to force the tuplestore to allow REWIND, because
163 * we might be asked to rescan the CTE even though upper levels didn't
164 * tell us to be prepared to do it efficiently. Annoying, since this
165 * prevents truncation of the tuplestore. XXX FIXME
167 eflags
|= EXEC_FLAG_REWIND
;
170 * CteScan should not have any children.
172 Assert(outerPlan(node
) == NULL
);
173 Assert(innerPlan(node
) == NULL
);
176 * create new CteScanState for node
178 scanstate
= makeNode(CteScanState
);
179 scanstate
->ss
.ps
.plan
= (Plan
*) node
;
180 scanstate
->ss
.ps
.state
= estate
;
181 scanstate
->eflags
= eflags
;
182 scanstate
->cte_table
= NULL
;
183 scanstate
->eof_cte
= false;
186 * Find the already-initialized plan for the CTE query.
188 scanstate
->cteplanstate
= (PlanState
*) list_nth(estate
->es_subplanstates
,
189 node
->ctePlanId
- 1);
192 * The Param slot associated with the CTE query is used to hold a
193 * pointer to the CteState of the first CteScan node that initializes
194 * for this CTE. This node will be the one that holds the shared
195 * state for all the CTEs.
197 prmdata
= &(estate
->es_param_exec_vals
[node
->cteParam
]);
198 Assert(prmdata
->execPlan
== NULL
);
199 Assert(!prmdata
->isnull
);
200 scanstate
->leader
= (CteScanState
*) DatumGetPointer(prmdata
->value
);
201 if (scanstate
->leader
== NULL
)
203 /* I am the leader */
204 prmdata
->value
= PointerGetDatum(scanstate
);
205 scanstate
->leader
= scanstate
;
206 scanstate
->cte_table
= tuplestore_begin_heap(true, false, work_mem
);
207 tuplestore_set_eflags(scanstate
->cte_table
, scanstate
->eflags
);
208 scanstate
->readptr
= 0;
213 Assert(IsA(scanstate
->leader
, CteScanState
));
215 tuplestore_alloc_read_pointer(scanstate
->leader
->cte_table
,
220 * Miscellaneous initialization
222 * create expression context for node
224 ExecAssignExprContext(estate
, &scanstate
->ss
.ps
);
227 * initialize child expressions
229 scanstate
->ss
.ps
.targetlist
= (List
*)
230 ExecInitExpr((Expr
*) node
->scan
.plan
.targetlist
,
231 (PlanState
*) scanstate
);
232 scanstate
->ss
.ps
.qual
= (List
*)
233 ExecInitExpr((Expr
*) node
->scan
.plan
.qual
,
234 (PlanState
*) scanstate
);
236 #define CTESCAN_NSLOTS 2
239 * tuple table initialization
241 ExecInitResultTupleSlot(estate
, &scanstate
->ss
.ps
);
242 ExecInitScanTupleSlot(estate
, &scanstate
->ss
);
245 * The scan tuple type (ie, the rowtype we expect to find in the work
246 * table) is the same as the result rowtype of the CTE query.
248 ExecAssignScanType(&scanstate
->ss
,
249 ExecGetResultType(scanstate
->cteplanstate
));
252 * Initialize result tuple type and projection info.
254 ExecAssignResultTypeFromTL(&scanstate
->ss
.ps
);
255 ExecAssignScanProjectionInfo(&scanstate
->ss
);
257 scanstate
->ss
.ps
.ps_TupFromTlist
= false;
263 ExecCountSlotsCteScan(CteScan
*node
)
265 return ExecCountSlotsNode(outerPlan(node
)) +
266 ExecCountSlotsNode(innerPlan(node
)) +
270 /* ----------------------------------------------------------------
273 * frees any storage allocated through C routines.
274 * ----------------------------------------------------------------
277 ExecEndCteScan(CteScanState
*node
)
282 ExecFreeExprContext(&node
->ss
.ps
);
285 * clean out the tuple table
287 ExecClearTuple(node
->ss
.ps
.ps_ResultTupleSlot
);
288 ExecClearTuple(node
->ss
.ss_ScanTupleSlot
);
291 * If I am the leader, free the tuplestore.
293 if (node
->leader
== node
)
294 tuplestore_end(node
->cte_table
);
297 /* ----------------------------------------------------------------
300 * Rescans the relation.
301 * ----------------------------------------------------------------
304 ExecCteScanReScan(CteScanState
*node
, ExprContext
*exprCtxt
)
306 Tuplestorestate
*tuplestorestate
= node
->leader
->cte_table
;
308 ExecClearTuple(node
->ss
.ps
.ps_ResultTupleSlot
);
309 node
->ss
.ps
.ps_TupFromTlist
= false;
311 if (node
->leader
== node
)
314 * The leader is responsible for clearing the tuplestore if a new
315 * scan of the underlying CTE is required.
317 if (node
->cteplanstate
->chgParam
!= NULL
)
319 tuplestore_clear(tuplestorestate
);
320 node
->eof_cte
= false;
324 tuplestore_select_read_pointer(tuplestorestate
, node
->readptr
);
325 tuplestore_rescan(tuplestorestate
);
330 /* Not leader, so just rewind my own pointer */
331 tuplestore_select_read_pointer(tuplestorestate
, node
->readptr
);
332 tuplestore_rescan(tuplestorestate
);