1/*-------------------------------------------------------------------------
4 * Routines to handle materialization nodes.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/executor/nodeMaterial.c
13 *-------------------------------------------------------------------------
17 * ExecMaterial - materialize the result of a subplan
18 * ExecInitMaterial - initialize node and subnodes
19 * ExecEndMaterial - shutdown node and subnodes
28/* ----------------------------------------------------------------
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.
36 * ----------------------------------------------------------------
52 * get state info from node
60 * If first time through, and we need a tuplestore, initialize it.
62 if (tuplestorestate == NULL && node->
eflags != 0)
69 * Allocate a second read pointer to serve as the mark. We know it
70 * must have index 1, so needn't store that.
82 * If we are not at the end of the tuplestore, or are going backwards, try
83 * to fetch a tuple from tuplestore.
85 eof_tuplestore = (tuplestorestate == NULL) ||
88 if (!forward && eof_tuplestore)
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
99 return NULL;
/* the tuplestore must be empty */
101 eof_tuplestore =
false;
105 * If we can fetch another tuple from the tuplestore, return it.
113 eof_tuplestore =
true;
117 * If necessary, try to fetch another row from the subplan.
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
130 * We can only get here with forward==true, so no need to worry about
131 * which direction the subplan will go.
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.
159/* ----------------------------------------------------------------
161 * ----------------------------------------------------------------
170 * create state structure
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.
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.
201 * Miscellaneous initialization
203 * Materialization nodes don't need ExprContexts because they never call
204 * ExecQual or ExecProject.
208 * initialize child nodes
210 * We shield the child node from the need to support REWIND, BACKWARD, or
219 * Initialize result type and slot. No need to initialize projection info
220 * because this node doesn't do projections.
222 * material nodes only return tuples from their materialized relation.
228 * initialize tuple type.
235/* ----------------------------------------------------------------
237 * ----------------------------------------------------------------
243 * Release tuplestore resources
250 * shut down the subplan
255/* ----------------------------------------------------------------
256 * ExecMaterialMarkPos
258 * Calls tuplestore to save the current position in the stored file.
259 * ----------------------------------------------------------------
267 * if we haven't materialized yet, just return.
273 * copy the active read pointer to the mark.
278 * since we may have advanced the mark, try to truncate the tuplestore.
283/* ----------------------------------------------------------------
284 * ExecMaterialRestrPos
286 * Calls tuplestore to restore the last saved file position.
287 * ----------------------------------------------------------------
295 * if we haven't materialized yet, just return.
301 * copy the mark to the active read pointer.
306/* ----------------------------------------------------------------
309 * Rescans the materialized relation.
310 * ----------------------------------------------------------------
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.
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.)
336 * Otherwise we can just rewind and rescan the stored output. The
337 * state of the subnode does not change.
353 /* In this case we are just passing on the subquery's output */
356 * if chgParam of subnode is not null then plan will be re-scanned by
357 * first ExecProcNode.
#define PG_USED_FOR_ASSERTS_ONLY
void ExecReScan(PlanState *node)
void ExecEndNode(PlanState *node)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
const TupleTableSlotOps TTSOpsMinimalTuple
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
#define outerPlanState(node)
#define EXEC_FLAG_BACKWARD
static TupleTableSlot * ExecProcNode(PlanState *node)
Assert(PointerIsAligned(start, uint64))
#define CHECK_FOR_INTERRUPTS()
static TupleTableSlot * ExecMaterial(PlanState *pstate)
void ExecReScanMaterial(MaterialState *node)
void ExecMaterialMarkPos(MaterialState *node)
MaterialState * ExecInitMaterial(Material *node, EState *estate, int eflags)
void ExecEndMaterial(MaterialState *node)
void ExecMaterialRestrPos(MaterialState *node)
#define castNode(_type_, nodeptr)
#define ScanDirectionIsForward(direction)
ScanDirection es_direction
Tuplestorestate * tuplestorestate
TupleTableSlot * ps_ResultTupleSlot
ProjectionInfo * ps_ProjInfo
ExecProcNodeMtd ExecProcNode
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
void tuplestore_rescan(Tuplestorestate *state)
int tuplestore_alloc_read_pointer(Tuplestorestate *state, int eflags)
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
void tuplestore_trim(Tuplestorestate *state)
void tuplestore_copy_read_pointer(Tuplestorestate *state, int srcptr, int destptr)
bool tuplestore_advance(Tuplestorestate *state, bool forward)
void tuplestore_end(Tuplestorestate *state)
bool tuplestore_ateof(Tuplestorestate *state)
void tuplestore_set_eflags(Tuplestorestate *state, int eflags)
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)