1/*-------------------------------------------------------------------------
4 * support for evaluating targetlists containing set-returning functions
8 * ProjectSet nodes are inserted by the planner to evaluate set-returning
9 * functions in the targetlist. It's guaranteed that all set-returning
10 * functions are directly at the top level of the targetlist, i.e. they
11 * can't be inside more-complex expressions. If that'd otherwise be
12 * the case, the planner adds additional ProjectSet nodes.
14 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
18 * src/backend/executor/nodeProjectSet.c
20 *-------------------------------------------------------------------------
34/* ----------------------------------------------------------------
35 * ExecProjectSet(node)
37 * Return tuples after evaluating the targetlist (which contains set
38 * returning functions).
39 * ----------------------------------------------------------------
55 * Reset per-tuple context to free expression-evaluation storage allocated
56 * for a potentially previously returned tuple. Note that the SRF argument
57 * context has a different lifetime and is reset below.
62 * Check to see if we're still projecting out tuples from a previous scan
63 * tuple (because there is a function-returning-set in the projection
64 * expressions). If so, try to project another one.
70 if (resultSlot != NULL)
75 * Get another input tuple and project SRFs from it.
80 * Reset argument context to free any expression evaluation storage
81 * allocated in the previous tuple cycle. Note this can't happen
82 * until we're done projecting out tuples from a scan tuple, as
83 * ValuePerCall functions are allowed to reference the arguments for
84 * each returned tuple. However, if we loop around after finding that
85 * no rows are produced from a scan tuple, we should reset, to avoid
86 * leaking memory when many successive scan tuples produce no rows.
91 * Retrieve tuples from the outer plan until there are no more.
100 * Prepare to compute projection expressions, which will expect to
101 * access the input tuples as varno OUTER.
105 /* Evaluate the expressions */
109 * Return the tuple unless the projection produced no rows (due to an
110 * empty set), in which case we must loop back to see if there are
111 * more outerPlan tuples.
117 * When we do loop back, we'd better reset the econtext again, just in
118 * case the SRF leaked some memory there.
126/* ----------------------------------------------------------------
129 * Project a targetlist containing one or more set-returning functions.
131 * 'continuing' indicates whether to continue projecting rows for the
132 * same input tuple; or whether a new input tuple is being projected.
134 * Returns NULL if no output tuple has been produced.
136 * ----------------------------------------------------------------
150 /* Call SRFs, as well as plain expressions, in per-tuple context */
154 * Assume no further tuples are produced unless an ExprMultipleResult is
155 * encountered from a set returning function.
159 hassrf = hasresult =
false;
160 for (argno = 0; argno < node->
nelems; argno++)
165 bool *isnull = &resultSlot->
tts_isnull[argno];
170 * If we're continuing to project output rows from a source tuple,
171 * return NULLs once the SRF has been exhausted.
180 * Evaluate SRF - possibly continuing previously started output.
194 /* Non-SRF tlist expression, just evaluate normally. */
202 /* ProjectSet should not be used if there's no SRFs */
206 * If all the SRFs returned ExprEndResult, we consider that as no row
218/* ----------------------------------------------------------------
221 * Creates the run-time state information for the ProjectSet node
222 * produced by the planner and initializes outer relations
224 * ----------------------------------------------------------------
233 /* check for unsupported flags */
237 * create state structure
241 state->ps.state = estate;
244 state->pending_srf_tuples =
false;
247 * Miscellaneous initialization
249 * create expression context for node
254 * initialize child nodes
259 * we don't use inner plan
264 * tuple table and result type initialization
268 /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
276 * Build expressions to evaluate targetlist. We can't use
277 * ExecBuildProjectionInfo here, since that doesn't deal with SRFs.
278 * Instead compile each expression separately, using
279 * ExecInitFunctionResultSet where applicable.
303 /* We don't support any qual on ProjectSet nodes */
307 * Create a memory context that ExecMakeFunctionResultSet can use to
308 * evaluate function arguments in. We can't use the per-tuple context for
309 * this because it gets reset too often; but we don't want to leak
310 * evaluation results into the query-lifespan context either. We use one
311 * context for the arguments of all tSRFs, as they have roughly equivalent
315 "tSRF function arguments",
321/* ----------------------------------------------------------------
324 * frees up storage allocated through C routines
325 * ----------------------------------------------------------------
341 /* Forget any incompletely-evaluated SRFs */
345 * If chgParam of subnode is not null then plan will be re-scanned by
346 * first ExecProcNode.
#define PG_USED_FOR_ASSERTS_ONLY
void ExecReScan(PlanState *node)
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
void ExecEndNode(PlanState *node)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
SetExprState * ExecInitFunctionResultSet(Expr *expr, ExprContext *econtext, PlanState *parent)
Datum ExecMakeFunctionResultSet(SetExprState *fcache, ExprContext *econtext, MemoryContext argContext, bool *isNull, ExprDoneCond *isDone)
const TupleTableSlotOps TTSOpsVirtual
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
void ExecAssignExprContext(EState *estate, PlanState *planstate)
#define outerPlanState(node)
#define EXEC_FLAG_BACKWARD
#define ResetExprContext(econtext)
static TupleTableSlot * ExecProcNode(PlanState *node)
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Assert(PointerIsAligned(start, uint64))
void MemoryContextReset(MemoryContext context)
MemoryContext CurrentMemoryContext
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define CHECK_FOR_INTERRUPTS()
bool expression_returns_set(Node *clause)
static TupleTableSlot * ExecProjectSet(PlanState *pstate)
ProjectSetState * ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
void ExecReScanProjectSet(ProjectSetState *node)
void ExecEndProjectSet(ProjectSetState *node)
static TupleTableSlot * ExecProjectSRF(ProjectSetState *node, bool continuing)
#define IsA(nodeptr, _type_)
#define castNode(_type_, nodeptr)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
static int list_length(const List *l)
MemoryContext ecxt_per_tuple_memory
TupleTableSlot * ecxt_outertuple
ExprContext * ps_ExprContext
TupleTableSlot * ps_ResultTupleSlot
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)