]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeMaterial.c
Update copyright for 2018
[postgresql] / src / backend / executor / nodeMaterial.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeMaterial.c
4  *        Routines to handle materialization nodes.
5  *
6  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/executor/nodeMaterial.c
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 static TupleTableSlot *                 /* result tuple from subplan */
39 ExecMaterial(PlanState *pstate)
40 {
41         MaterialState *node = castNode(MaterialState, pstate);
42         EState     *estate;
43         ScanDirection dir;
44         bool            forward;
45         Tuplestorestate *tuplestorestate;
46         bool            eof_tuplestore;
47         TupleTableSlot *slot;
48
49         CHECK_FOR_INTERRUPTS();
50
51         /*
52          * get state info from node
53          */
54         estate = node->ss.ps.state;
55         dir = estate->es_direction;
56         forward = ScanDirectionIsForward(dir);
57         tuplestorestate = node->tuplestorestate;
58
59         /*
60          * If first time through, and we need a tuplestore, initialize it.
61          */
62         if (tuplestorestate == NULL && node->eflags != 0)
63         {
64                 tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
65                 tuplestore_set_eflags(tuplestorestate, node->eflags);
66                 if (node->eflags & EXEC_FLAG_MARK)
67                 {
68                         /*
69                          * Allocate a second read pointer to serve as the mark. We know it
70                          * must have index 1, so needn't store that.
71                          */
72                         int                     ptrno PG_USED_FOR_ASSERTS_ONLY;
73
74                         ptrno = tuplestore_alloc_read_pointer(tuplestorestate,
75                                                                                                   node->eflags);
76                         Assert(ptrno == 1);
77                 }
78                 node->tuplestorestate = tuplestorestate;
79         }
80
81         /*
82          * If we are not at the end of the tuplestore, or are going backwards, try
83          * to fetch a tuple from tuplestore.
84          */
85         eof_tuplestore = (tuplestorestate == NULL) ||
86                 tuplestore_ateof(tuplestorestate);
87
88         if (!forward && eof_tuplestore)
89         {
90                 if (!node->eof_underlying)
91                 {
92                         /*
93                          * When reversing direction at tuplestore EOF, the first
94                          * gettupleslot call will fetch the last-added tuple; but we want
95                          * to return the one before that, if possible. So do an extra
96                          * fetch.
97                          */
98                         if (!tuplestore_advance(tuplestorestate, forward))
99                                 return NULL;    /* the tuplestore must be empty */
100                 }
101                 eof_tuplestore = false;
102         }
103
104         /*
105          * If we can fetch another tuple from the tuplestore, return it.
106          */
107         slot = node->ss.ps.ps_ResultTupleSlot;
108         if (!eof_tuplestore)
109         {
110                 if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
111                         return slot;
112                 if (forward)
113                         eof_tuplestore = true;
114         }
115
116         /*
117          * If necessary, try to fetch another row from the subplan.
118          *
119          * Note: the eof_underlying state variable exists to short-circuit further
120          * subplan calls.  It's not optional, unfortunately, because some plan
121          * node types are not robust about being called again when they've already
122          * returned NULL.
123          */
124         if (eof_tuplestore && !node->eof_underlying)
125         {
126                 PlanState  *outerNode;
127                 TupleTableSlot *outerslot;
128
129                 /*
130                  * We can only get here with forward==true, so no need to worry about
131                  * which direction the subplan will go.
132                  */
133                 outerNode = outerPlanState(node);
134                 outerslot = ExecProcNode(outerNode);
135                 if (TupIsNull(outerslot))
136                 {
137                         node->eof_underlying = true;
138                         return NULL;
139                 }
140
141                 /*
142                  * Append a copy of the returned tuple to tuplestore.  NOTE: because
143                  * the tuplestore is certainly in EOF state, its read position will
144                  * move forward over the added tuple.  This is what we want.
145                  */
146                 if (tuplestorestate)
147                         tuplestore_puttupleslot(tuplestorestate, outerslot);
148
149                 /*
150                  * We can just return the subplan's returned tuple, without copying.
151                  */
152                 return outerslot;
153         }
154
155         /*
156          * Nothing left ...
157          */
158         return ExecClearTuple(slot);
159 }
160
161 /* ----------------------------------------------------------------
162  *              ExecInitMaterial
163  * ----------------------------------------------------------------
164  */
165 MaterialState *
166 ExecInitMaterial(Material *node, EState *estate, int eflags)
167 {
168         MaterialState *matstate;
169         Plan       *outerPlan;
170
171         /*
172          * create state structure
173          */
174         matstate = makeNode(MaterialState);
175         matstate->ss.ps.plan = (Plan *) node;
176         matstate->ss.ps.state = estate;
177         matstate->ss.ps.ExecProcNode = ExecMaterial;
178
179         /*
180          * We must have a tuplestore buffering the subplan output to do backward
181          * scan or mark/restore.  We also prefer to materialize the subplan output
182          * if we might be called on to rewind and replay it many times. However,
183          * if none of these cases apply, we can skip storing the data.
184          */
185         matstate->eflags = (eflags & (EXEC_FLAG_REWIND |
186                                                                   EXEC_FLAG_BACKWARD |
187                                                                   EXEC_FLAG_MARK));
188
189         /*
190          * Tuplestore's interpretation of the flag bits is subtly different from
191          * the general executor meaning: it doesn't think BACKWARD necessarily
192          * means "backwards all the way to start".  If told to support BACKWARD we
193          * must include REWIND in the tuplestore eflags, else tuplestore_trim
194          * might throw away too much.
195          */
196         if (eflags & EXEC_FLAG_BACKWARD)
197                 matstate->eflags |= EXEC_FLAG_REWIND;
198
199         matstate->eof_underlying = false;
200         matstate->tuplestorestate = NULL;
201
202         /*
203          * Miscellaneous initialization
204          *
205          * Materialization nodes don't need ExprContexts because they never call
206          * ExecQual or ExecProject.
207          */
208
209         /*
210          * tuple table initialization
211          *
212          * material nodes only return tuples from their materialized relation.
213          */
214         ExecInitResultTupleSlot(estate, &matstate->ss.ps);
215         ExecInitScanTupleSlot(estate, &matstate->ss);
216
217         /*
218          * initialize child nodes
219          *
220          * We shield the child node from the need to support REWIND, BACKWARD, or
221          * MARK/RESTORE.
222          */
223         eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);
224
225         outerPlan = outerPlan(node);
226         outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags);
227
228         /*
229          * initialize tuple type.  no need to initialize projection info because
230          * this node doesn't do projections.
231          */
232         ExecAssignResultTypeFromTL(&matstate->ss.ps);
233         ExecAssignScanTypeFromOuterPlan(&matstate->ss);
234         matstate->ss.ps.ps_ProjInfo = NULL;
235
236         return matstate;
237 }
238
239 /* ----------------------------------------------------------------
240  *              ExecEndMaterial
241  * ----------------------------------------------------------------
242  */
243 void
244 ExecEndMaterial(MaterialState *node)
245 {
246         /*
247          * clean out the tuple table
248          */
249         ExecClearTuple(node->ss.ss_ScanTupleSlot);
250
251         /*
252          * Release tuplestore resources
253          */
254         if (node->tuplestorestate != NULL)
255                 tuplestore_end(node->tuplestorestate);
256         node->tuplestorestate = NULL;
257
258         /*
259          * shut down the subplan
260          */
261         ExecEndNode(outerPlanState(node));
262 }
263
264 /* ----------------------------------------------------------------
265  *              ExecMaterialMarkPos
266  *
267  *              Calls tuplestore to save the current position in the stored file.
268  * ----------------------------------------------------------------
269  */
270 void
271 ExecMaterialMarkPos(MaterialState *node)
272 {
273         Assert(node->eflags & EXEC_FLAG_MARK);
274
275         /*
276          * if we haven't materialized yet, just return.
277          */
278         if (!node->tuplestorestate)
279                 return;
280
281         /*
282          * copy the active read pointer to the mark.
283          */
284         tuplestore_copy_read_pointer(node->tuplestorestate, 0, 1);
285
286         /*
287          * since we may have advanced the mark, try to truncate the tuplestore.
288          */
289         tuplestore_trim(node->tuplestorestate);
290 }
291
292 /* ----------------------------------------------------------------
293  *              ExecMaterialRestrPos
294  *
295  *              Calls tuplestore to restore the last saved file position.
296  * ----------------------------------------------------------------
297  */
298 void
299 ExecMaterialRestrPos(MaterialState *node)
300 {
301         Assert(node->eflags & EXEC_FLAG_MARK);
302
303         /*
304          * if we haven't materialized yet, just return.
305          */
306         if (!node->tuplestorestate)
307                 return;
308
309         /*
310          * copy the mark to the active read pointer.
311          */
312         tuplestore_copy_read_pointer(node->tuplestorestate, 1, 0);
313 }
314
315 /* ----------------------------------------------------------------
316  *              ExecReScanMaterial
317  *
318  *              Rescans the materialized relation.
319  * ----------------------------------------------------------------
320  */
321 void
322 ExecReScanMaterial(MaterialState *node)
323 {
324         PlanState  *outerPlan = outerPlanState(node);
325
326         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
327
328         if (node->eflags != 0)
329         {
330                 /*
331                  * If we haven't materialized yet, just return. If outerplan's
332                  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
333                  * else no reason to re-scan it at all.
334                  */
335                 if (!node->tuplestorestate)
336                         return;
337
338                 /*
339                  * If subnode is to be rescanned then we forget previous stored
340                  * results; we have to re-read the subplan and re-store.  Also, if we
341                  * told tuplestore it needn't support rescan, we lose and must
342                  * re-read.  (This last should not happen in common cases; else our
343                  * caller lied by not passing EXEC_FLAG_REWIND to us.)
344                  *
345                  * Otherwise we can just rewind and rescan the stored output. The
346                  * state of the subnode does not change.
347                  */
348                 if (outerPlan->chgParam != NULL ||
349                         (node->eflags & EXEC_FLAG_REWIND) == 0)
350                 {
351                         tuplestore_end(node->tuplestorestate);
352                         node->tuplestorestate = NULL;
353                         if (outerPlan->chgParam == NULL)
354                                 ExecReScan(outerPlan);
355                         node->eof_underlying = false;
356                 }
357                 else
358                         tuplestore_rescan(node->tuplestorestate);
359         }
360         else
361         {
362                 /* In this case we are just passing on the subquery's output */
363
364                 /*
365                  * if chgParam of subnode is not null then plan will be re-scanned by
366                  * first ExecProcNode.
367                  */
368                 if (outerPlan->chgParam == NULL)
369                         ExecReScan(outerPlan);
370                 node->eof_underlying = false;
371         }
372 }