PostgreSQL Source Code  git master
nodeMaterial.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nodeMaterial.c
4  * Routines to handle materialization nodes.
5  *
6  * Portions Copyright (c) 1996-2023, 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 */
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 
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  ExecCopySlot(slot, outerslot);
150  return slot;
151  }
152 
153  /*
154  * Nothing left ...
155  */
156  return ExecClearTuple(slot);
157 }
158 
159 /* ----------------------------------------------------------------
160  * ExecInitMaterial
161  * ----------------------------------------------------------------
162  */
164 ExecInitMaterial(Material *node, EState *estate, int eflags)
165 {
166  MaterialState *matstate;
167  Plan *outerPlan;
168 
169  /*
170  * create state structure
171  */
172  matstate = makeNode(MaterialState);
173  matstate->ss.ps.plan = (Plan *) node;
174  matstate->ss.ps.state = estate;
175  matstate->ss.ps.ExecProcNode = ExecMaterial;
176 
177  /*
178  * We must have a tuplestore buffering the subplan output to do backward
179  * scan or mark/restore. We also prefer to materialize the subplan output
180  * if we might be called on to rewind and replay it many times. However,
181  * if none of these cases apply, we can skip storing the data.
182  */
183  matstate->eflags = (eflags & (EXEC_FLAG_REWIND |
185  EXEC_FLAG_MARK));
186 
187  /*
188  * Tuplestore's interpretation of the flag bits is subtly different from
189  * the general executor meaning: it doesn't think BACKWARD necessarily
190  * means "backwards all the way to start". If told to support BACKWARD we
191  * must include REWIND in the tuplestore eflags, else tuplestore_trim
192  * might throw away too much.
193  */
194  if (eflags & EXEC_FLAG_BACKWARD)
195  matstate->eflags |= EXEC_FLAG_REWIND;
196 
197  matstate->eof_underlying = false;
198  matstate->tuplestorestate = NULL;
199 
200  /*
201  * Miscellaneous initialization
202  *
203  * Materialization nodes don't need ExprContexts because they never call
204  * ExecQual or ExecProject.
205  */
206 
207  /*
208  * initialize child nodes
209  *
210  * We shield the child node from the need to support REWIND, BACKWARD, or
211  * MARK/RESTORE.
212  */
214 
215  outerPlan = outerPlan(node);
216  outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags);
217 
218  /*
219  * Initialize result type and slot. No need to initialize projection info
220  * because this node doesn't do projections.
221  *
222  * material nodes only return tuples from their materialized relation.
223  */
225  matstate->ss.ps.ps_ProjInfo = NULL;
226 
227  /*
228  * initialize tuple type.
229  */
231 
232  return matstate;
233 }
234 
235 /* ----------------------------------------------------------------
236  * ExecEndMaterial
237  * ----------------------------------------------------------------
238  */
239 void
241 {
242  /*
243  * clean out the tuple table
244  */
246 
247  /*
248  * Release tuplestore resources
249  */
250  if (node->tuplestorestate != NULL)
252  node->tuplestorestate = NULL;
253 
254  /*
255  * shut down the subplan
256  */
258 }
259 
260 /* ----------------------------------------------------------------
261  * ExecMaterialMarkPos
262  *
263  * Calls tuplestore to save the current position in the stored file.
264  * ----------------------------------------------------------------
265  */
266 void
268 {
269  Assert(node->eflags & EXEC_FLAG_MARK);
270 
271  /*
272  * if we haven't materialized yet, just return.
273  */
274  if (!node->tuplestorestate)
275  return;
276 
277  /*
278  * copy the active read pointer to the mark.
279  */
281 
282  /*
283  * since we may have advanced the mark, try to truncate the tuplestore.
284  */
286 }
287 
288 /* ----------------------------------------------------------------
289  * ExecMaterialRestrPos
290  *
291  * Calls tuplestore to restore the last saved file position.
292  * ----------------------------------------------------------------
293  */
294 void
296 {
297  Assert(node->eflags & EXEC_FLAG_MARK);
298 
299  /*
300  * if we haven't materialized yet, just return.
301  */
302  if (!node->tuplestorestate)
303  return;
304 
305  /*
306  * copy the mark to the active read pointer.
307  */
309 }
310 
311 /* ----------------------------------------------------------------
312  * ExecReScanMaterial
313  *
314  * Rescans the materialized relation.
315  * ----------------------------------------------------------------
316  */
317 void
319 {
321 
323 
324  if (node->eflags != 0)
325  {
326  /*
327  * If we haven't materialized yet, just return. If outerplan's
328  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
329  * else no reason to re-scan it at all.
330  */
331  if (!node->tuplestorestate)
332  return;
333 
334  /*
335  * If subnode is to be rescanned then we forget previous stored
336  * results; we have to re-read the subplan and re-store. Also, if we
337  * told tuplestore it needn't support rescan, we lose and must
338  * re-read. (This last should not happen in common cases; else our
339  * caller lied by not passing EXEC_FLAG_REWIND to us.)
340  *
341  * Otherwise we can just rewind and rescan the stored output. The
342  * state of the subnode does not change.
343  */
344  if (outerPlan->chgParam != NULL ||
345  (node->eflags & EXEC_FLAG_REWIND) == 0)
346  {
348  node->tuplestorestate = NULL;
349  if (outerPlan->chgParam == NULL)
351  node->eof_underlying = false;
352  }
353  else
355  }
356  else
357  {
358  /* In this case we are just passing on the subquery's output */
359 
360  /*
361  * if chgParam of subnode is not null then plan will be re-scanned by
362  * first ExecProcNode.
363  */
364  if (outerPlan->chgParam == NULL)
366  node->eof_underlying = false;
367  }
368 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:166
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1800
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:690
#define outerPlanState(node)
Definition: execnodes.h:1133
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
#define EXEC_FLAG_REWIND
Definition: executor.h:67
#define EXEC_FLAG_MARK
Definition: executor.h:69
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:268
int work_mem
Definition: globals.c:125
Assert(fmt[strlen(fmt) - 1] !='\n')
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
MaterialState * ExecInitMaterial(Material *node, EState *estate, int eflags)
Definition: nodeMaterial.c:164
void ExecReScanMaterial(MaterialState *node)
Definition: nodeMaterial.c:318
void ExecMaterialMarkPos(MaterialState *node)
Definition: nodeMaterial.c:267
static TupleTableSlot * ExecMaterial(PlanState *pstate)
Definition: nodeMaterial.c:39
void ExecEndMaterial(MaterialState *node)
Definition: nodeMaterial.c:240
void ExecMaterialRestrPos(MaterialState *node)
Definition: nodeMaterial.c:295
#define makeNode(_type_)
Definition: nodes.h:176
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
#define outerPlan(node)
Definition: plannodes.h:183
#define ScanDirectionIsForward(direction)
Definition: sdir.h:64
ScanDirection
Definition: sdir.h:25
ScanDirection es_direction
Definition: execnodes.h:615
bool eof_underlying
Definition: execnodes.h:2144
Tuplestorestate * tuplestorestate
Definition: execnodes.h:2145
ScanState ss
Definition: execnodes.h:2142
Plan * plan
Definition: execnodes.h:1037
EState * state
Definition: execnodes.h:1039
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1075
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1077
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1043
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1477
PlanState ps
Definition: execnodes.h:1474
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:708
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1233
int tuplestore_alloc_read_pointer(Tuplestorestate *state, int eflags)
Definition: tuplestore.c:383
void tuplestore_trim(Tuplestorestate *state)
Definition: tuplestore.c:1360
void tuplestore_copy_read_pointer(Tuplestorestate *state, int srcptr, int destptr)
Definition: tuplestore.c:1268
bool tuplestore_advance(Tuplestorestate *state, bool forward)
Definition: tuplestore.c:1110
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
bool tuplestore_ateof(Tuplestorestate *state)
Definition: tuplestore.c:557
void tuplestore_set_eflags(Tuplestorestate *state, int eflags)
Definition: tuplestore.c:359
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:433
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:483
#define TupIsNull(slot)
Definition: tuptable.h:300