1 /*-------------------------------------------------------------------------
4 * Routines to handle materialization nodes.
6 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.60 2007/11/15 21:14:34 momjian Exp $
13 *-------------------------------------------------------------------------
17 * ExecMaterial - materialize the result of a subplan
18 * ExecInitMaterial - initialize node and subnodes
19 * ExecEndMaterial - shutdown node and subnodes
24 #include "executor/executor.h"
25 #include "executor/nodeMaterial.h"
26 #include "miscadmin.h"
28 /* ----------------------------------------------------------------
31 * As long as we are at the end of the data collected in the tuplestore,
32 * we collect one new row from the subplan on each call, and stash it
33 * aside in the tuplestore before returning it. The tuplestore is
34 * only read if we are asked to scan backwards, rescan, or mark/restore.
36 * ----------------------------------------------------------------
38 TupleTableSlot * /* result tuple from subplan */
39 ExecMaterial(MaterialState *node)
44 Tuplestorestate *tuplestorestate;
49 * get state info from node
51 estate = node->ss.ps.state;
52 dir = estate->es_direction;
53 forward = ScanDirectionIsForward(dir);
54 tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
57 * If first time through, and we need a tuplestore, initialize it.
59 if (tuplestorestate == NULL && node->eflags != 0)
61 tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
62 tuplestore_set_eflags(tuplestorestate, node->eflags);
63 node->tuplestorestate = (void *) tuplestorestate;
67 * If we are not at the end of the tuplestore, or are going backwards, try
68 * to fetch a tuple from tuplestore.
70 eof_tuplestore = (tuplestorestate == NULL) ||
71 tuplestore_ateof(tuplestorestate);
73 if (!forward && eof_tuplestore)
75 if (!node->eof_underlying)
78 * When reversing direction at tuplestore EOF, the first
79 * gettupleslot call will fetch the last-added tuple; but we want
80 * to return the one before that, if possible. So do an extra
83 if (!tuplestore_advance(tuplestorestate, forward))
84 return NULL; /* the tuplestore must be empty */
86 eof_tuplestore = false;
90 * If we can fetch another tuple from the tuplestore, return it.
92 slot = node->ss.ps.ps_ResultTupleSlot;
95 if (tuplestore_gettupleslot(tuplestorestate, forward, slot))
98 eof_tuplestore = true;
102 * If necessary, try to fetch another row from the subplan.
104 * Note: the eof_underlying state variable exists to short-circuit further
105 * subplan calls. It's not optional, unfortunately, because some plan
106 * node types are not robust about being called again when they've already
109 if (eof_tuplestore && !node->eof_underlying)
111 PlanState *outerNode;
112 TupleTableSlot *outerslot;
115 * We can only get here with forward==true, so no need to worry about
116 * which direction the subplan will go.
118 outerNode = outerPlanState(node);
119 outerslot = ExecProcNode(outerNode);
120 if (TupIsNull(outerslot))
122 node->eof_underlying = true;
127 * Append returned tuple to tuplestore. NOTE: because the tuplestore
128 * is certainly in EOF state, its read position will move forward over
129 * the added tuple. This is what we want.
132 tuplestore_puttupleslot(tuplestorestate, outerslot);
135 * And return a copy of the tuple. (XXX couldn't we just return the
138 return ExecCopySlot(slot, outerslot);
144 return ExecClearTuple(slot);
147 /* ----------------------------------------------------------------
149 * ----------------------------------------------------------------
152 ExecInitMaterial(Material *node, EState *estate, int eflags)
154 MaterialState *matstate;
158 * create state structure
160 matstate = makeNode(MaterialState);
161 matstate->ss.ps.plan = (Plan *) node;
162 matstate->ss.ps.state = estate;
165 * We must have a tuplestore buffering the subplan output to do backward
166 * scan or mark/restore. We also prefer to materialize the subplan output
167 * if we might be called on to rewind and replay it many times. However,
168 * if none of these cases apply, we can skip storing the data.
170 matstate->eflags = (eflags & (EXEC_FLAG_REWIND |
174 matstate->eof_underlying = false;
175 matstate->tuplestorestate = NULL;
178 * Miscellaneous initialization
180 * Materialization nodes don't need ExprContexts because they never call
181 * ExecQual or ExecProject.
184 #define MATERIAL_NSLOTS 2
187 * tuple table initialization
189 * material nodes only return tuples from their materialized relation.
191 ExecInitResultTupleSlot(estate, &matstate->ss.ps);
192 ExecInitScanTupleSlot(estate, &matstate->ss);
195 * initialize child nodes
197 * We shield the child node from the need to support REWIND, BACKWARD, or
200 eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);
202 outerPlan = outerPlan(node);
203 outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags);
206 * initialize tuple type. no need to initialize projection info because
207 * this node doesn't do projections.
209 ExecAssignResultTypeFromTL(&matstate->ss.ps);
210 ExecAssignScanTypeFromOuterPlan(&matstate->ss);
211 matstate->ss.ps.ps_ProjInfo = NULL;
217 ExecCountSlotsMaterial(Material *node)
219 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
220 ExecCountSlotsNode(innerPlan((Plan *) node)) +
224 /* ----------------------------------------------------------------
226 * ----------------------------------------------------------------
229 ExecEndMaterial(MaterialState *node)
232 * clean out the tuple table
234 ExecClearTuple(node->ss.ss_ScanTupleSlot);
237 * Release tuplestore resources
239 if (node->tuplestorestate != NULL)
240 tuplestore_end((Tuplestorestate *) node->tuplestorestate);
241 node->tuplestorestate = NULL;
244 * shut down the subplan
246 ExecEndNode(outerPlanState(node));
249 /* ----------------------------------------------------------------
250 * ExecMaterialMarkPos
252 * Calls tuplestore to save the current position in the stored file.
253 * ----------------------------------------------------------------
256 ExecMaterialMarkPos(MaterialState *node)
258 Assert(node->eflags & EXEC_FLAG_MARK);
261 * if we haven't materialized yet, just return.
263 if (!node->tuplestorestate)
266 tuplestore_markpos((Tuplestorestate *) node->tuplestorestate);
269 /* ----------------------------------------------------------------
270 * ExecMaterialRestrPos
272 * Calls tuplestore to restore the last saved file position.
273 * ----------------------------------------------------------------
276 ExecMaterialRestrPos(MaterialState *node)
278 Assert(node->eflags & EXEC_FLAG_MARK);
281 * if we haven't materialized yet, just return.
283 if (!node->tuplestorestate)
287 * restore the scan to the previously marked position
289 tuplestore_restorepos((Tuplestorestate *) node->tuplestorestate);
292 /* ----------------------------------------------------------------
295 * Rescans the materialized relation.
296 * ----------------------------------------------------------------
299 ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
301 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
303 if (node->eflags != 0)
306 * If we haven't materialized yet, just return. If outerplan' chgParam
307 * is not NULL then it will be re-scanned by ExecProcNode, else - no
308 * reason to re-scan it at all.
310 if (!node->tuplestorestate)
314 * If subnode is to be rescanned then we forget previous stored
315 * results; we have to re-read the subplan and re-store. Also, if we
316 * told tuplestore it needn't support rescan, we lose and must
317 * re-read. (This last should not happen in common cases; else our
318 * caller lied by not passing EXEC_FLAG_REWIND to us.)
320 * Otherwise we can just rewind and rescan the stored output. The
321 * state of the subnode does not change.
323 if (((PlanState *) node)->lefttree->chgParam != NULL ||
324 (node->eflags & EXEC_FLAG_REWIND) == 0)
326 tuplestore_end((Tuplestorestate *) node->tuplestorestate);
327 node->tuplestorestate = NULL;
328 if (((PlanState *) node)->lefttree->chgParam == NULL)
329 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
330 node->eof_underlying = false;
333 tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
337 /* In this case we are just passing on the subquery's output */
340 * if chgParam of subnode is not null then plan will be re-scanned by
341 * first ExecProcNode.
343 if (((PlanState *) node)->lefttree->chgParam == NULL)
344 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
345 node->eof_underlying = false;