Add support for user-defined I/O conversion casts.
[PostgreSQL.git] / src / backend / executor / nodeCtescan.c
blob80de4db699f89642358632057c4a7dee990df3b3
1 /*-------------------------------------------------------------------------
3 * nodeCtescan.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include "executor/execdebug.h"
19 #include "executor/nodeCtescan.h"
20 #include "miscadmin.h"
22 static TupleTableSlot *CteScanNext(CteScanState *node);
24 /* ----------------------------------------------------------------
25 * CteScanNext
27 * This is a workhorse for ExecCteScan
28 * ----------------------------------------------------------------
30 static TupleTableSlot *
31 CteScanNext(CteScanState *node)
33 EState *estate;
34 ScanDirection dir;
35 bool forward;
36 Tuplestorestate *tuplestorestate;
37 bool eof_tuplestore;
38 TupleTableSlot *slot;
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
64 * fetch.
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.
75 if (!eof_tuplestore)
77 if (tuplestore_gettupleslot(tuplestorestate, forward, slot))
78 return slot;
79 if (forward)
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
89 * returned NULL.
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;
103 return NULL;
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
111 * what they want.
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
119 * stable over that.
121 return ExecCopySlot(slot, cteslot);
125 * Nothing left ...
127 return ExecClearTuple(slot);
130 /* ----------------------------------------------------------------
131 * ExecCteScan(node)
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 * ----------------------------------------------------------------
138 TupleTableSlot *
139 ExecCteScan(CteScanState *node)
142 * use CteScanNext as access method
144 return ExecScan(&node->ss, (ExecScanAccessMtd) CteScanNext);
148 /* ----------------------------------------------------------------
149 * ExecInitCteScan
150 * ----------------------------------------------------------------
152 CteScanState *
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;
210 else
212 /* Not the leader */
213 Assert(IsA(scanstate->leader, CteScanState));
214 scanstate->readptr =
215 tuplestore_alloc_read_pointer(scanstate->leader->cte_table,
216 scanstate->eflags);
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;
259 return scanstate;
263 ExecCountSlotsCteScan(CteScan *node)
265 return ExecCountSlotsNode(outerPlan(node)) +
266 ExecCountSlotsNode(innerPlan(node)) +
267 CTESCAN_NSLOTS;
270 /* ----------------------------------------------------------------
271 * ExecEndCteScan
273 * frees any storage allocated through C routines.
274 * ----------------------------------------------------------------
276 void
277 ExecEndCteScan(CteScanState *node)
280 * Free exprcontext
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 /* ----------------------------------------------------------------
298 * ExecCteScanReScan
300 * Rescans the relation.
301 * ----------------------------------------------------------------
303 void
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;
322 else
324 tuplestore_select_read_pointer(tuplestorestate, node->readptr);
325 tuplestore_rescan(tuplestorestate);
328 else
330 /* Not leader, so just rewind my own pointer */
331 tuplestore_select_read_pointer(tuplestorestate, node->readptr);
332 tuplestore_rescan(tuplestorestate);