PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2025, 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"
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 */
38static 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 */
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 */
164ExecInitMaterial(Material *node, EState *estate, int eflags)
165{
166 MaterialState *matstate;
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 |
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 */
239void
241{
242 /*
243 * Release tuplestore resources
244 */
245 if (node->tuplestorestate != NULL)
247 node->tuplestorestate = NULL;
248
249 /*
250 * shut down the subplan
251 */
253}
254
255/* ----------------------------------------------------------------
256 * ExecMaterialMarkPos
257 *
258 * Calls tuplestore to save the current position in the stored file.
259 * ----------------------------------------------------------------
260 */
261void
263{
265
266 /*
267 * if we haven't materialized yet, just return.
268 */
269 if (!node->tuplestorestate)
270 return;
271
272 /*
273 * copy the active read pointer to the mark.
274 */
276
277 /*
278 * since we may have advanced the mark, try to truncate the tuplestore.
279 */
281}
282
283/* ----------------------------------------------------------------
284 * ExecMaterialRestrPos
285 *
286 * Calls tuplestore to restore the last saved file position.
287 * ----------------------------------------------------------------
288 */
289void
291{
293
294 /*
295 * if we haven't materialized yet, just return.
296 */
297 if (!node->tuplestorestate)
298 return;
299
300 /*
301 * copy the mark to the active read pointer.
302 */
304}
305
306/* ----------------------------------------------------------------
307 * ExecReScanMaterial
308 *
309 * Rescans the materialized relation.
310 * ----------------------------------------------------------------
311 */
312void
314{
316
318
319 if (node->eflags != 0)
320 {
321 /*
322 * If we haven't materialized yet, just return. If outerplan's
323 * chgParam is not NULL then it will be re-scanned by ExecProcNode,
324 * else no reason to re-scan it at all.
325 */
326 if (!node->tuplestorestate)
327 return;
328
329 /*
330 * If subnode is to be rescanned then we forget previous stored
331 * results; we have to re-read the subplan and re-store. Also, if we
332 * told tuplestore it needn't support rescan, we lose and must
333 * re-read. (This last should not happen in common cases; else our
334 * caller lied by not passing EXEC_FLAG_REWIND to us.)
335 *
336 * Otherwise we can just rewind and rescan the stored output. The
337 * state of the subnode does not change.
338 */
339 if (outerPlan->chgParam != NULL ||
340 (node->eflags & EXEC_FLAG_REWIND) == 0)
341 {
343 node->tuplestorestate = NULL;
344 if (outerPlan->chgParam == NULL)
346 node->eof_underlying = false;
347 }
348 else
350 }
351 else
352 {
353 /* In this case we are just passing on the subquery's output */
354
355 /*
356 * if chgParam of subnode is not null then plan will be re-scanned by
357 * first ExecProcNode.
358 */
359 if (outerPlan->chgParam == NULL)
361 node->eof_underlying = false;
362 }
363}
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:201
#define Assert(condition)
Definition: c.h:812
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:562
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1986
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:704
#define outerPlanState(node)
Definition: execnodes.h:1222
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
#define EXEC_FLAG_REWIND
Definition: executor.h:67
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:267
#define EXEC_FLAG_MARK
Definition: executor.h:69
int work_mem
Definition: globals.c:130
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static TupleTableSlot * ExecMaterial(PlanState *pstate)
Definition: nodeMaterial.c:39
void ExecReScanMaterial(MaterialState *node)
Definition: nodeMaterial.c:313
void ExecMaterialMarkPos(MaterialState *node)
Definition: nodeMaterial.c:262
MaterialState * ExecInitMaterial(Material *node, EState *estate, int eflags)
Definition: nodeMaterial.c:164
void ExecEndMaterial(MaterialState *node)
Definition: nodeMaterial.c:240
void ExecMaterialRestrPos(MaterialState *node)
Definition: nodeMaterial.c:290
#define makeNode(_type_)
Definition: nodes.h:155
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#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:631
bool eof_underlying
Definition: execnodes.h:2259
Tuplestorestate * tuplestorestate
Definition: execnodes.h:2260
ScanState ss
Definition: execnodes.h:2257
Plan * plan
Definition: execnodes.h:1126
EState * state
Definition: execnodes.h:1128
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1164
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1166
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1132
PlanState ps
Definition: execnodes.h:1573
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1130
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:742
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1285
int tuplestore_alloc_read_pointer(Tuplestorestate *state, int eflags)
Definition: tuplestore.c:395
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:330
void tuplestore_trim(Tuplestorestate *state)
Definition: tuplestore.c:1412
void tuplestore_copy_read_pointer(Tuplestorestate *state, int srcptr, int destptr)
Definition: tuplestore.c:1320
bool tuplestore_advance(Tuplestorestate *state, bool forward)
Definition: tuplestore.c:1162
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:492
bool tuplestore_ateof(Tuplestorestate *state)
Definition: tuplestore.c:591
void tuplestore_set_eflags(Tuplestorestate *state, int eflags)
Definition: tuplestore.c:371
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
#define TupIsNull(slot)
Definition: tuptable.h:306
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:509