1/*-------------------------------------------------------------------------
4 * routines to handle CteScan 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/nodeCtescan.c
13 *-------------------------------------------------------------------------
24/* ----------------------------------------------------------------
27 * This is a workhorse for ExecCteScan
28 * ----------------------------------------------------------------
41 * get state info from node
51 * If we are not at the end of the tuplestore, or are going backwards, try
52 * to fetch a tuple from tuplestore.
56 if (!forward && eof_tuplestore)
61 * When reversing direction at tuplestore EOF, the first
62 * gettupleslot call will fetch the last-added tuple; but we want
63 * to return the one before that, if possible. So do an extra
67 return NULL;
/* the tuplestore must be empty */
69 eof_tuplestore =
false;
73 * If we can fetch another tuple from the tuplestore, return it.
75 * Note: we have to use copy=true in the tuplestore_gettupleslot call,
76 * because we are sharing the tuplestore with other nodes that might write
77 * into the tuplestore before we get called again.
84 eof_tuplestore =
true;
88 * If necessary, try to fetch another row from the CTE query.
90 * Note: the eof_cte state variable exists to short-circuit further calls
91 * of the CTE plan. It's not optional, unfortunately, because some plan
92 * node types are not robust about being called again when they've already
100 * We can only get here with forward==true, so no need to worry about
101 * which direction the subplan will go.
111 * There are corner cases where the subplan could change which
112 * tuplestore read pointer is active, so be sure to reselect ours
113 * before storing the tuple we got.
118 * Append a copy of the returned tuple to tuplestore. NOTE: because
119 * our read pointer is certainly in EOF state, its read position will
120 * move forward over the added tuple. This is what we want. Also,
121 * any other readers will *not* move past the new tuple, which is what
127 * We MUST copy the CTE query's output tuple into our own slot. This
128 * is because other CteScan nodes might advance the CTE query before
129 * we are called again, and our output tuple must stay stable over
142 * CteScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
147 /* nothing to check */
151/* ----------------------------------------------------------------
154 * Scans the CTE sequentially and returns the next qualifying tuple.
155 * We call the ExecScan() routine and pass it the appropriate
156 * access method functions.
157 * ----------------------------------------------------------------
170/* ----------------------------------------------------------------
172 * ----------------------------------------------------------------
180 /* check for unsupported flags */
184 * For the moment we have to force the tuplestore to allow REWIND, because
185 * we might be asked to rescan the CTE even though upper levels didn't
186 * tell us to be prepared to do it efficiently. Annoying, since this
187 * prevents truncation of the tuplestore. XXX FIXME
189 * Note: if we are in an EPQ recheck plan tree, it's likely that no access
190 * to the tuplestore is needed at all, making this even more annoying.
191 * It's not worth improving that as long as all the read pointers would
192 * have REWIND anyway, but if we ever improve this logic then that aspect
193 * should be considered too.
198 * CteScan should not have any children.
204 * create new CteScanState for node
210 scanstate->
eflags = eflags;
215 * Find the already-initialized plan for the CTE query.
221 * The Param slot associated with the CTE query is used to hold a pointer
222 * to the CteState of the first CteScan node that initializes for this
223 * CTE. This node will be the one that holds the shared state for all the
224 * CTEs, particularly the shared tuplestore.
230 if (scanstate->
leader == NULL)
232 /* I am the leader */
234 scanstate->
leader = scanstate;
242 /* Create my own read pointer, and ensure it is at start */
252 * Miscellaneous initialization
254 * create expression context for node
259 * The scan tuple type (ie, the rowtype we expect to find in the work
260 * table) is the same as the result rowtype of the CTE query.
267 * Initialize result type and projection.
273 * initialize child expressions
281/* ----------------------------------------------------------------
284 * frees any storage allocated through C routines.
285 * ----------------------------------------------------------------
291 * If I am the leader, free the tuplestore.
300/* ----------------------------------------------------------------
303 * Rescans the relation.
304 * ----------------------------------------------------------------
317 * Clear the tuplestore if a new scan of the underlying CTE is required.
318 * This implicitly resets all the tuplestore's read pointers. Note that
319 * multiple CTE nodes might redundantly clear the tuplestore; that's OK,
320 * and not unduly expensive. We'll stop taking this path as soon as
321 * somebody has attempted to read something from the underlying CTE
322 * (thereby causing its chgParam to be cleared).
332 * Else, just rewind my own pointer. Either the underlying CTE
333 * doesn't need a rescan (and we can re-read what's in the tuplestore
334 * now), or somebody else already took care of it.
ExprState * ExecInitQual(List *qual, PlanState *parent)
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
void ExecAssignScanProjectionInfo(ScanState *node)
void ExecScanReScan(ScanState *node)
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
void ExecInitResultTypeTL(PlanState *planstate)
const TupleTableSlotOps TTSOpsMinimalTuple
TupleDesc ExecGetResultType(PlanState *planstate)
void ExecAssignExprContext(EState *estate, PlanState *planstate)
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
static TupleTableSlot * ExecProcNode(PlanState *node)
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Assert(PointerIsAligned(start, uint64))
static TupleTableSlot * ExecCteScan(PlanState *pstate)
CteScanState * ExecInitCteScan(CteScan *node, EState *estate, int eflags)
void ExecReScanCteScan(CteScanState *node)
static bool CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
void ExecEndCteScan(CteScanState *node)
static TupleTableSlot * CteScanNext(CteScanState *node)
#define castNode(_type_, nodeptr)
static void * list_nth(const List *list, int n)
static Datum PointerGetDatum(const void *X)
static Pointer DatumGetPointer(Datum X)
#define ScanDirectionIsForward(direction)
Tuplestorestate * cte_table
struct CteScanState * leader
ParamExecData * es_param_exec_vals
ScanDirection es_direction
TupleTableSlot * ps_ResultTupleSlot
ExecProcNodeMtd ExecProcNode
TupleTableSlot * ss_ScanTupleSlot
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
void tuplestore_clear(Tuplestorestate *state)
void tuplestore_rescan(Tuplestorestate *state)
int tuplestore_alloc_read_pointer(Tuplestorestate *state, int eflags)
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
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)