OSDN Git Service

pgindent run for 8.3.
[pg-rex/syncrep.git] / src / backend / executor / nodeMaterial.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeMaterial.c
4  *        Routines to handle materialization nodes.
5  *
6  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.60 2007/11/15 21:14:34 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *              ExecMaterial                    - materialize the result of a subplan
18  *              ExecInitMaterial                - initialize node and subnodes
19  *              ExecEndMaterial                 - shutdown node and subnodes
20  *
21  */
22 #include "postgres.h"
23
24 #include "executor/executor.h"
25 #include "executor/nodeMaterial.h"
26 #include "miscadmin.h"
27
28 /* ----------------------------------------------------------------
29  *              ExecMaterial
30  *
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.
35  *
36  * ----------------------------------------------------------------
37  */
38 TupleTableSlot *                                /* result tuple from subplan */
39 ExecMaterial(MaterialState *node)
40 {
41         EState     *estate;
42         ScanDirection dir;
43         bool            forward;
44         Tuplestorestate *tuplestorestate;
45         bool            eof_tuplestore;
46         TupleTableSlot *slot;
47
48         /*
49          * get state info from node
50          */
51         estate = node->ss.ps.state;
52         dir = estate->es_direction;
53         forward = ScanDirectionIsForward(dir);
54         tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
55
56         /*
57          * If first time through, and we need a tuplestore, initialize it.
58          */
59         if (tuplestorestate == NULL && node->eflags != 0)
60         {
61                 tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
62                 tuplestore_set_eflags(tuplestorestate, node->eflags);
63                 node->tuplestorestate = (void *) tuplestorestate;
64         }
65
66         /*
67          * If we are not at the end of the tuplestore, or are going backwards, try
68          * to fetch a tuple from tuplestore.
69          */
70         eof_tuplestore = (tuplestorestate == NULL) ||
71                 tuplestore_ateof(tuplestorestate);
72
73         if (!forward && eof_tuplestore)
74         {
75                 if (!node->eof_underlying)
76                 {
77                         /*
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
81                          * fetch.
82                          */
83                         if (!tuplestore_advance(tuplestorestate, forward))
84                                 return NULL;    /* the tuplestore must be empty */
85                 }
86                 eof_tuplestore = false;
87         }
88
89         /*
90          * If we can fetch another tuple from the tuplestore, return it.
91          */
92         slot = node->ss.ps.ps_ResultTupleSlot;
93         if (!eof_tuplestore)
94         {
95                 if (tuplestore_gettupleslot(tuplestorestate, forward, slot))
96                         return slot;
97                 if (forward)
98                         eof_tuplestore = true;
99         }
100
101         /*
102          * If necessary, try to fetch another row from the subplan.
103          *
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
107          * returned NULL.
108          */
109         if (eof_tuplestore && !node->eof_underlying)
110         {
111                 PlanState  *outerNode;
112                 TupleTableSlot *outerslot;
113
114                 /*
115                  * We can only get here with forward==true, so no need to worry about
116                  * which direction the subplan will go.
117                  */
118                 outerNode = outerPlanState(node);
119                 outerslot = ExecProcNode(outerNode);
120                 if (TupIsNull(outerslot))
121                 {
122                         node->eof_underlying = true;
123                         return NULL;
124                 }
125
126                 /*
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.
130                  */
131                 if (tuplestorestate)
132                         tuplestore_puttupleslot(tuplestorestate, outerslot);
133
134                 /*
135                  * And return a copy of the tuple.      (XXX couldn't we just return the
136                  * outerslot?)
137                  */
138                 return ExecCopySlot(slot, outerslot);
139         }
140
141         /*
142          * Nothing left ...
143          */
144         return ExecClearTuple(slot);
145 }
146
147 /* ----------------------------------------------------------------
148  *              ExecInitMaterial
149  * ----------------------------------------------------------------
150  */
151 MaterialState *
152 ExecInitMaterial(Material *node, EState *estate, int eflags)
153 {
154         MaterialState *matstate;
155         Plan       *outerPlan;
156
157         /*
158          * create state structure
159          */
160         matstate = makeNode(MaterialState);
161         matstate->ss.ps.plan = (Plan *) node;
162         matstate->ss.ps.state = estate;
163
164         /*
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.
169          */
170         matstate->eflags = (eflags & (EXEC_FLAG_REWIND |
171                                                                   EXEC_FLAG_BACKWARD |
172                                                                   EXEC_FLAG_MARK));
173
174         matstate->eof_underlying = false;
175         matstate->tuplestorestate = NULL;
176
177         /*
178          * Miscellaneous initialization
179          *
180          * Materialization nodes don't need ExprContexts because they never call
181          * ExecQual or ExecProject.
182          */
183
184 #define MATERIAL_NSLOTS 2
185
186         /*
187          * tuple table initialization
188          *
189          * material nodes only return tuples from their materialized relation.
190          */
191         ExecInitResultTupleSlot(estate, &matstate->ss.ps);
192         ExecInitScanTupleSlot(estate, &matstate->ss);
193
194         /*
195          * initialize child nodes
196          *
197          * We shield the child node from the need to support REWIND, BACKWARD, or
198          * MARK/RESTORE.
199          */
200         eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);
201
202         outerPlan = outerPlan(node);
203         outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags);
204
205         /*
206          * initialize tuple type.  no need to initialize projection info because
207          * this node doesn't do projections.
208          */
209         ExecAssignResultTypeFromTL(&matstate->ss.ps);
210         ExecAssignScanTypeFromOuterPlan(&matstate->ss);
211         matstate->ss.ps.ps_ProjInfo = NULL;
212
213         return matstate;
214 }
215
216 int
217 ExecCountSlotsMaterial(Material *node)
218 {
219         return ExecCountSlotsNode(outerPlan((Plan *) node)) +
220                 ExecCountSlotsNode(innerPlan((Plan *) node)) +
221                 MATERIAL_NSLOTS;
222 }
223
224 /* ----------------------------------------------------------------
225  *              ExecEndMaterial
226  * ----------------------------------------------------------------
227  */
228 void
229 ExecEndMaterial(MaterialState *node)
230 {
231         /*
232          * clean out the tuple table
233          */
234         ExecClearTuple(node->ss.ss_ScanTupleSlot);
235
236         /*
237          * Release tuplestore resources
238          */
239         if (node->tuplestorestate != NULL)
240                 tuplestore_end((Tuplestorestate *) node->tuplestorestate);
241         node->tuplestorestate = NULL;
242
243         /*
244          * shut down the subplan
245          */
246         ExecEndNode(outerPlanState(node));
247 }
248
249 /* ----------------------------------------------------------------
250  *              ExecMaterialMarkPos
251  *
252  *              Calls tuplestore to save the current position in the stored file.
253  * ----------------------------------------------------------------
254  */
255 void
256 ExecMaterialMarkPos(MaterialState *node)
257 {
258         Assert(node->eflags & EXEC_FLAG_MARK);
259
260         /*
261          * if we haven't materialized yet, just return.
262          */
263         if (!node->tuplestorestate)
264                 return;
265
266         tuplestore_markpos((Tuplestorestate *) node->tuplestorestate);
267 }
268
269 /* ----------------------------------------------------------------
270  *              ExecMaterialRestrPos
271  *
272  *              Calls tuplestore to restore the last saved file position.
273  * ----------------------------------------------------------------
274  */
275 void
276 ExecMaterialRestrPos(MaterialState *node)
277 {
278         Assert(node->eflags & EXEC_FLAG_MARK);
279
280         /*
281          * if we haven't materialized yet, just return.
282          */
283         if (!node->tuplestorestate)
284                 return;
285
286         /*
287          * restore the scan to the previously marked position
288          */
289         tuplestore_restorepos((Tuplestorestate *) node->tuplestorestate);
290 }
291
292 /* ----------------------------------------------------------------
293  *              ExecMaterialReScan
294  *
295  *              Rescans the materialized relation.
296  * ----------------------------------------------------------------
297  */
298 void
299 ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
300 {
301         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
302
303         if (node->eflags != 0)
304         {
305                 /*
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.
309                  */
310                 if (!node->tuplestorestate)
311                         return;
312
313                 /*
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.)
319                  *
320                  * Otherwise we can just rewind and rescan the stored output. The
321                  * state of the subnode does not change.
322                  */
323                 if (((PlanState *) node)->lefttree->chgParam != NULL ||
324                         (node->eflags & EXEC_FLAG_REWIND) == 0)
325                 {
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;
331                 }
332                 else
333                         tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
334         }
335         else
336         {
337                 /* In this case we are just passing on the subquery's output */
338
339                 /*
340                  * if chgParam of subnode is not null then plan will be re-scanned by
341                  * first ExecProcNode.
342                  */
343                 if (((PlanState *) node)->lefttree->chgParam == NULL)
344                         ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
345                 node->eof_underlying = false;
346         }
347 }