Harmonize parameter names in ecpg code.
[pgsql.git] / src / backend / executor / nodeProjectSet.c
blobadabfa2882dedf7e18690c1ad6739c1e481d2050
1 /*-------------------------------------------------------------------------
3 * nodeProjectSet.c
4 * support for evaluating targetlists containing set-returning functions
6 * DESCRIPTION
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-2022, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
17 * IDENTIFICATION
18 * src/backend/executor/nodeProjectSet.c
20 *-------------------------------------------------------------------------
23 #include "postgres.h"
25 #include "executor/executor.h"
26 #include "executor/nodeProjectSet.h"
27 #include "miscadmin.h"
28 #include "nodes/nodeFuncs.h"
29 #include "utils/memutils.h"
32 static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
35 /* ----------------------------------------------------------------
36 * ExecProjectSet(node)
38 * Return tuples after evaluating the targetlist (which contains set
39 * returning functions).
40 * ----------------------------------------------------------------
42 static TupleTableSlot *
43 ExecProjectSet(PlanState *pstate)
45 ProjectSetState *node = castNode(ProjectSetState, pstate);
46 TupleTableSlot *outerTupleSlot;
47 TupleTableSlot *resultSlot;
48 PlanState *outerPlan;
49 ExprContext *econtext;
51 CHECK_FOR_INTERRUPTS();
53 econtext = node->ps.ps_ExprContext;
56 * Reset per-tuple context to free expression-evaluation storage allocated
57 * for a potentially previously returned tuple. Note that the SRF argument
58 * context has a different lifetime and is reset below.
60 ResetExprContext(econtext);
63 * Check to see if we're still projecting out tuples from a previous scan
64 * tuple (because there is a function-returning-set in the projection
65 * expressions). If so, try to project another one.
67 if (node->pending_srf_tuples)
69 resultSlot = ExecProjectSRF(node, true);
71 if (resultSlot != NULL)
72 return resultSlot;
76 * Reset argument context to free any expression evaluation storage
77 * allocated in the previous tuple cycle. Note this can't happen until
78 * we're done projecting out tuples from a scan tuple, as ValuePerCall
79 * functions are allowed to reference the arguments for each returned
80 * tuple.
82 MemoryContextReset(node->argcontext);
85 * Get another input tuple and project SRFs from it.
87 for (;;)
90 * Retrieve tuples from the outer plan until there are no more.
92 outerPlan = outerPlanState(node);
93 outerTupleSlot = ExecProcNode(outerPlan);
95 if (TupIsNull(outerTupleSlot))
96 return NULL;
99 * Prepare to compute projection expressions, which will expect to
100 * access the input tuples as varno OUTER.
102 econtext->ecxt_outertuple = outerTupleSlot;
104 /* Evaluate the expressions */
105 resultSlot = ExecProjectSRF(node, false);
108 * Return the tuple unless the projection produced no rows (due to an
109 * empty set), in which case we must loop back to see if there are
110 * more outerPlan tuples.
112 if (resultSlot)
113 return resultSlot;
116 return NULL;
119 /* ----------------------------------------------------------------
120 * ExecProjectSRF
122 * Project a targetlist containing one or more set-returning functions.
124 * 'continuing' indicates whether to continue projecting rows for the
125 * same input tuple; or whether a new input tuple is being projected.
127 * Returns NULL if no output tuple has been produced.
129 * ----------------------------------------------------------------
131 static TupleTableSlot *
132 ExecProjectSRF(ProjectSetState *node, bool continuing)
134 TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
135 ExprContext *econtext = node->ps.ps_ExprContext;
136 MemoryContext oldcontext;
137 bool hassrf PG_USED_FOR_ASSERTS_ONLY;
138 bool hasresult;
139 int argno;
141 ExecClearTuple(resultSlot);
143 /* Call SRFs, as well as plain expressions, in per-tuple context */
144 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
147 * Assume no further tuples are produced unless an ExprMultipleResult is
148 * encountered from a set returning function.
150 node->pending_srf_tuples = false;
152 hassrf = hasresult = false;
153 for (argno = 0; argno < node->nelems; argno++)
155 Node *elem = node->elems[argno];
156 ExprDoneCond *isdone = &node->elemdone[argno];
157 Datum *result = &resultSlot->tts_values[argno];
158 bool *isnull = &resultSlot->tts_isnull[argno];
160 if (continuing && *isdone == ExprEndResult)
163 * If we're continuing to project output rows from a source tuple,
164 * return NULLs once the SRF has been exhausted.
166 *result = (Datum) 0;
167 *isnull = true;
168 hassrf = true;
170 else if (IsA(elem, SetExprState))
173 * Evaluate SRF - possibly continuing previously started output.
175 *result = ExecMakeFunctionResultSet((SetExprState *) elem,
176 econtext, node->argcontext,
177 isnull, isdone);
179 if (*isdone != ExprEndResult)
180 hasresult = true;
181 if (*isdone == ExprMultipleResult)
182 node->pending_srf_tuples = true;
183 hassrf = true;
185 else
187 /* Non-SRF tlist expression, just evaluate normally. */
188 *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
189 *isdone = ExprSingleResult;
193 MemoryContextSwitchTo(oldcontext);
195 /* ProjectSet should not be used if there's no SRFs */
196 Assert(hassrf);
199 * If all the SRFs returned ExprEndResult, we consider that as no row
200 * being produced.
202 if (hasresult)
204 ExecStoreVirtualTuple(resultSlot);
205 return resultSlot;
208 return NULL;
211 /* ----------------------------------------------------------------
212 * ExecInitProjectSet
214 * Creates the run-time state information for the ProjectSet node
215 * produced by the planner and initializes outer relations
216 * (child nodes).
217 * ----------------------------------------------------------------
219 ProjectSetState *
220 ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
222 ProjectSetState *state;
223 ListCell *lc;
224 int off;
226 /* check for unsupported flags */
227 Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
230 * create state structure
232 state = makeNode(ProjectSetState);
233 state->ps.plan = (Plan *) node;
234 state->ps.state = estate;
235 state->ps.ExecProcNode = ExecProjectSet;
237 state->pending_srf_tuples = false;
240 * Miscellaneous initialization
242 * create expression context for node
244 ExecAssignExprContext(estate, &state->ps);
247 * initialize child nodes
249 outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
252 * we don't use inner plan
254 Assert(innerPlan(node) == NULL);
257 * tuple table and result type initialization
259 ExecInitResultTupleSlotTL(&state->ps, &TTSOpsVirtual);
261 /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
262 state->nelems = list_length(node->plan.targetlist);
263 state->elems = (Node **)
264 palloc(sizeof(Node *) * state->nelems);
265 state->elemdone = (ExprDoneCond *)
266 palloc(sizeof(ExprDoneCond) * state->nelems);
269 * Build expressions to evaluate targetlist. We can't use
270 * ExecBuildProjectionInfo here, since that doesn't deal with SRFs.
271 * Instead compile each expression separately, using
272 * ExecInitFunctionResultSet where applicable.
274 off = 0;
275 foreach(lc, node->plan.targetlist)
277 TargetEntry *te = (TargetEntry *) lfirst(lc);
278 Expr *expr = te->expr;
280 if ((IsA(expr, FuncExpr) && ((FuncExpr *) expr)->funcretset) ||
281 (IsA(expr, OpExpr) && ((OpExpr *) expr)->opretset))
283 state->elems[off] = (Node *)
284 ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
285 &state->ps);
287 else
289 Assert(!expression_returns_set((Node *) expr));
290 state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
293 off++;
296 /* We don't support any qual on ProjectSet nodes */
297 Assert(node->plan.qual == NIL);
300 * Create a memory context that ExecMakeFunctionResultSet can use to
301 * evaluate function arguments in. We can't use the per-tuple context for
302 * this because it gets reset too often; but we don't want to leak
303 * evaluation results into the query-lifespan context either. We use one
304 * context for the arguments of all tSRFs, as they have roughly equivalent
305 * lifetimes.
307 state->argcontext = AllocSetContextCreate(CurrentMemoryContext,
308 "tSRF function arguments",
309 ALLOCSET_DEFAULT_SIZES);
311 return state;
314 /* ----------------------------------------------------------------
315 * ExecEndProjectSet
317 * frees up storage allocated through C routines
318 * ----------------------------------------------------------------
320 void
321 ExecEndProjectSet(ProjectSetState *node)
324 * Free the exprcontext
326 ExecFreeExprContext(&node->ps);
329 * clean out the tuple table
331 ExecClearTuple(node->ps.ps_ResultTupleSlot);
334 * shut down subplans
336 ExecEndNode(outerPlanState(node));
339 void
340 ExecReScanProjectSet(ProjectSetState *node)
342 PlanState *outerPlan = outerPlanState(node);
344 /* Forget any incompletely-evaluated SRFs */
345 node->pending_srf_tuples = false;
348 * If chgParam of subnode is not null then plan will be re-scanned by
349 * first ExecProcNode.
351 if (outerPlan->chgParam == NULL)
352 ExecReScan(outerPlan);