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-2017, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
18 * src/backend/executor/nodeProjectSet.c
20 *-------------------------------------------------------------------------
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;
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)
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
82 MemoryContextReset(node->argcontext);
85 * Get another input tuple and project SRFs from it.
90 * Retrieve tuples from the outer plan until there are no more.
92 outerPlan = outerPlanState(node);
93 outerTupleSlot = ExecProcNode(outerPlan);
95 if (TupIsNull(outerTupleSlot))
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.
119 /* ----------------------------------------------------------------
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;
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.
170 else if (IsA(elem, SetExprState))
173 * Evaluate SRF - possibly continuing previously started output.
175 *result = ExecMakeFunctionResultSet((SetExprState *) elem,
176 econtext, node->argcontext,
179 if (*isdone != ExprEndResult)
181 if (*isdone == ExprMultipleResult)
182 node->pending_srf_tuples = true;
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 */
199 * If all the SRFs returned EndResult, we consider that as no row being
204 ExecStoreVirtualTuple(resultSlot);
211 /* ----------------------------------------------------------------
214 * Creates the run-time state information for the ProjectSet node
215 * produced by the planner and initializes outer relations
217 * ----------------------------------------------------------------
220 ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
222 ProjectSetState *state;
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 * tuple table initialization
249 ExecInitResultTupleSlot(estate, &state->ps);
251 /* We don't support any qual on ProjectSet nodes */
252 Assert(node->plan.qual == NIL);
255 * initialize child nodes
257 outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
260 * we don't use inner plan
262 Assert(innerPlan(node) == NULL);
265 * initialize tuple type and projection info
267 ExecAssignResultTypeFromTL(&state->ps);
269 /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
270 state->nelems = list_length(node->plan.targetlist);
271 state->elems = (Node **)
272 palloc(sizeof(Node *) * state->nelems);
273 state->elemdone = (ExprDoneCond *)
274 palloc(sizeof(ExprDoneCond) * state->nelems);
277 * Build expressions to evaluate targetlist. We can't use
278 * ExecBuildProjectionInfo here, since that doesn't deal with SRFs.
279 * Instead compile each expression separately, using
280 * ExecInitFunctionResultSet where applicable.
283 foreach(lc, node->plan.targetlist)
285 TargetEntry *te = (TargetEntry *) lfirst(lc);
286 Expr *expr = te->expr;
288 if ((IsA(expr, FuncExpr) &&((FuncExpr *) expr)->funcretset) ||
289 (IsA(expr, OpExpr) &&((OpExpr *) expr)->opretset))
291 state->elems[off] = (Node *)
292 ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
297 Assert(!expression_returns_set((Node *) expr));
298 state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
306 * Create a memory context that ExecMakeFunctionResult can use to evaluate
307 * function arguments in. We can't use the per-tuple context for this
308 * because it gets reset too often; but we don't want to leak evaluation
309 * results into the query-lifespan context either. We use one context for
310 * the arguments of all tSRFs, as they have roughly equivalent lifetimes.
312 state->argcontext = AllocSetContextCreate(CurrentMemoryContext,
313 "tSRF function arguments",
314 ALLOCSET_DEFAULT_SIZES);
319 /* ----------------------------------------------------------------
322 * frees up storage allocated through C routines
323 * ----------------------------------------------------------------
326 ExecEndProjectSet(ProjectSetState *node)
329 * Free the exprcontext
331 ExecFreeExprContext(&node->ps);
334 * clean out the tuple table
336 ExecClearTuple(node->ps.ps_ResultTupleSlot);
341 ExecEndNode(outerPlanState(node));
345 ExecReScanProjectSet(ProjectSetState *node)
347 /* Forget any incompletely-evaluated SRFs */
348 node->pending_srf_tuples = false;
351 * If chgParam of subnode is not null then plan will be re-scanned by
352 * first ExecProcNode.
354 if (node->ps.lefttree->chgParam == NULL)
355 ExecReScan(node->ps.lefttree);