1
/*-------------------------------------------------------------------------
4
* Routines to handle materialization nodes.
6
* Portions Copyright (c) 1996-2005, 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.48 2004-12-31 21:59:45 pgsql Exp $
13
*-------------------------------------------------------------------------
17
* ExecMaterial - materialize the result of a subplan
18
* ExecInitMaterial - initialize node and subnodes
19
* ExecEndMaterial - shutdown node and subnodes
24
#include "access/heapam.h"
25
#include "executor/executor.h"
26
#include "executor/nodeMaterial.h"
27
#include "miscadmin.h"
28
#include "utils/tuplestore.h"
30
/* ----------------------------------------------------------------
33
* As long as we are at the end of the data collected in the tuplestore,
34
* we collect one new row from the subplan on each call, and stash it
35
* aside in the tuplestore before returning it. The tuplestore is
36
* only read if we are asked to scan backwards, rescan, or mark/restore.
38
* ----------------------------------------------------------------
40
TupleTableSlot * /* result tuple from subplan */
41
ExecMaterial(MaterialState *node)
46
Tuplestorestate *tuplestorestate;
47
HeapTuple heapTuple = NULL;
48
bool should_free = false;
53
* get state info from node
55
estate = node->ss.ps.state;
56
dir = estate->es_direction;
57
forward = ScanDirectionIsForward(dir);
58
tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
61
* If first time through, initialize the tuplestore.
63
if (tuplestorestate == NULL)
65
tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
67
node->tuplestorestate = (void *) tuplestorestate;
71
* If we are not at the end of the tuplestore, or are going backwards,
72
* try to fetch a tuple from tuplestore.
74
eof_tuplestore = tuplestore_ateof(tuplestorestate);
76
if (!forward && eof_tuplestore)
78
if (!node->eof_underlying)
81
* When reversing direction at tuplestore EOF, the first
82
* getheaptuple call will fetch the last-added tuple; but we
83
* want to return the one before that, if possible. So do an
86
heapTuple = tuplestore_getheaptuple(tuplestorestate,
89
if (heapTuple == NULL)
90
return NULL; /* the tuplestore must be empty */
92
heap_freetuple(heapTuple);
94
eof_tuplestore = false;
99
heapTuple = tuplestore_getheaptuple(tuplestorestate,
102
if (heapTuple == NULL && forward)
103
eof_tuplestore = true;
107
* If necessary, try to fetch another row from the subplan.
109
* Note: the eof_underlying state variable exists to short-circuit
110
* further subplan calls. It's not optional, unfortunately, because
111
* some plan node types are not robust about being called again when
112
* they've already returned NULL.
114
if (eof_tuplestore && !node->eof_underlying)
116
PlanState *outerNode;
117
TupleTableSlot *outerslot;
120
* We can only get here with forward==true, so no need to worry
121
* about which direction the subplan will go.
123
outerNode = outerPlanState(node);
124
outerslot = ExecProcNode(outerNode);
125
if (TupIsNull(outerslot))
127
node->eof_underlying = true;
130
heapTuple = outerslot->val;
134
* Append returned tuple to tuplestore, too. NOTE: because the
135
* tuplestore is certainly in EOF state, its read position will
136
* move forward over the added tuple. This is what we want.
138
tuplestore_puttuple(tuplestorestate, (void *) heapTuple);
142
* Return the obtained tuple.
144
slot = (TupleTableSlot *) node->ss.ps.ps_ResultTupleSlot;
145
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
148
/* ----------------------------------------------------------------
150
* ----------------------------------------------------------------
153
ExecInitMaterial(Material *node, EState *estate)
155
MaterialState *matstate;
159
* create state structure
161
matstate = makeNode(MaterialState);
162
matstate->ss.ps.plan = (Plan *) node;
163
matstate->ss.ps.state = estate;
165
matstate->tuplestorestate = NULL;
166
matstate->eof_underlying = false;
169
* Miscellaneous initialization
171
* Materialization nodes don't need ExprContexts because they never call
172
* ExecQual or ExecProject.
175
#define MATERIAL_NSLOTS 2
178
* tuple table initialization
180
* material nodes only return tuples from their materialized relation.
182
ExecInitResultTupleSlot(estate, &matstate->ss.ps);
183
ExecInitScanTupleSlot(estate, &matstate->ss);
186
* initializes child nodes
188
outerPlan = outerPlan(node);
189
outerPlanState(matstate) = ExecInitNode(outerPlan, estate);
192
* initialize tuple type. no need to initialize projection info
193
* because this node doesn't do projections.
195
ExecAssignResultTypeFromOuterPlan(&matstate->ss.ps);
196
ExecAssignScanTypeFromOuterPlan(&matstate->ss);
197
matstate->ss.ps.ps_ProjInfo = NULL;
203
ExecCountSlotsMaterial(Material *node)
205
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
206
ExecCountSlotsNode(innerPlan((Plan *) node)) +
210
/* ----------------------------------------------------------------
212
* ----------------------------------------------------------------
215
ExecEndMaterial(MaterialState *node)
218
* clean out the tuple table
220
ExecClearTuple(node->ss.ss_ScanTupleSlot);
223
* Release tuplestore resources
225
if (node->tuplestorestate != NULL)
226
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
227
node->tuplestorestate = NULL;
230
* shut down the subplan
232
ExecEndNode(outerPlanState(node));
235
/* ----------------------------------------------------------------
236
* ExecMaterialMarkPos
238
* Calls tuplestore to save the current position in the stored file.
239
* ----------------------------------------------------------------
242
ExecMaterialMarkPos(MaterialState *node)
245
* if we haven't materialized yet, just return.
247
if (!node->tuplestorestate)
250
tuplestore_markpos((Tuplestorestate *) node->tuplestorestate);
253
/* ----------------------------------------------------------------
254
* ExecMaterialRestrPos
256
* Calls tuplestore to restore the last saved file position.
257
* ----------------------------------------------------------------
260
ExecMaterialRestrPos(MaterialState *node)
263
* if we haven't materialized yet, just return.
265
if (!node->tuplestorestate)
269
* restore the scan to the previously marked position
271
tuplestore_restorepos((Tuplestorestate *) node->tuplestorestate);
274
/* ----------------------------------------------------------------
277
* Rescans the materialized relation.
278
* ----------------------------------------------------------------
281
ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
284
* If we haven't materialized yet, just return. If outerplan' chgParam
285
* is not NULL then it will be re-scanned by ExecProcNode, else - no
286
* reason to re-scan it at all.
288
if (!node->tuplestorestate)
291
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
294
* If subnode is to be rescanned then we forget previous stored
295
* results; we have to re-read the subplan and re-store.
297
* Otherwise we can just rewind and rescan the stored output. The state
298
* of the subnode does not change.
300
if (((PlanState *) node)->lefttree->chgParam != NULL)
302
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
303
node->tuplestorestate = NULL;
304
node->eof_underlying = false;
307
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);