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 "nodes/nodeFuncs.h"
28 #include "utils/memutils.h"
31 static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
34 /* ----------------------------------------------------------------
35 * ExecProjectSet(node)
37 * Return tuples after evaluating the targetlist (which contains set
38 * returning functions).
39 * ----------------------------------------------------------------
42 ExecProjectSet(ProjectSetState *node)
44 TupleTableSlot *outerTupleSlot;
45 TupleTableSlot *resultSlot;
47 ExprContext *econtext;
49 econtext = node->ps.ps_ExprContext;
52 * Check to see if we're still projecting out tuples from a previous scan
53 * tuple (because there is a function-returning-set in the projection
54 * expressions). If so, try to project another one.
56 if (node->pending_srf_tuples)
58 resultSlot = ExecProjectSRF(node, true);
60 if (resultSlot != NULL)
65 * Reset per-tuple memory context to free any expression evaluation
66 * storage allocated in the previous tuple cycle. Note this can't happen
67 * until we're done projecting out tuples from a scan tuple.
69 ResetExprContext(econtext);
72 * Get another input tuple and project SRFs from it.
77 * Retrieve tuples from the outer plan until there are no more.
79 outerPlan = outerPlanState(node);
80 outerTupleSlot = ExecProcNode(outerPlan);
82 if (TupIsNull(outerTupleSlot))
86 * Prepare to compute projection expressions, which will expect to
87 * access the input tuples as varno OUTER.
89 econtext->ecxt_outertuple = outerTupleSlot;
91 /* Evaluate the expressions */
92 resultSlot = ExecProjectSRF(node, false);
95 * Return the tuple unless the projection produced no rows (due to an
96 * empty set), in which case we must loop back to see if there are
97 * more outerPlan tuples.
106 /* ----------------------------------------------------------------
109 * Project a targetlist containing one or more set-returning functions.
111 * 'continuing' indicates whether to continue projecting rows for the
112 * same input tuple; or whether a new input tuple is being projected.
114 * Returns NULL if no output tuple has been produced.
116 * ----------------------------------------------------------------
118 static TupleTableSlot *
119 ExecProjectSRF(ProjectSetState *node, bool continuing)
121 TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
122 ExprContext *econtext = node->ps.ps_ExprContext;
123 bool hassrf PG_USED_FOR_ASSERTS_ONLY;
127 ExecClearTuple(resultSlot);
130 * Assume no further tuples are produced unless an ExprMultipleResult is
131 * encountered from a set returning function.
133 node->pending_srf_tuples = false;
135 hassrf = hasresult = false;
136 for (argno = 0; argno < node->nelems; argno++)
138 Node *elem = node->elems[argno];
139 ExprDoneCond *isdone = &node->elemdone[argno];
140 Datum *result = &resultSlot->tts_values[argno];
141 bool *isnull = &resultSlot->tts_isnull[argno];
143 if (continuing && *isdone == ExprEndResult)
146 * If we're continuing to project output rows from a source tuple,
147 * return NULLs once the SRF has been exhausted.
153 else if (IsA(elem, SetExprState))
156 * Evaluate SRF - possibly continuing previously started output.
158 *result = ExecMakeFunctionResultSet((SetExprState *) elem,
159 econtext, isnull, isdone);
161 if (*isdone != ExprEndResult)
163 if (*isdone == ExprMultipleResult)
164 node->pending_srf_tuples = true;
169 /* Non-SRF tlist expression, just evaluate normally. */
170 *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
171 *isdone = ExprSingleResult;
175 /* ProjectSet should not be used if there's no SRFs */
179 * If all the SRFs returned EndResult, we consider that as no row being
184 ExecStoreVirtualTuple(resultSlot);
191 /* ----------------------------------------------------------------
194 * Creates the run-time state information for the ProjectSet node
195 * produced by the planner and initializes outer relations
197 * ----------------------------------------------------------------
200 ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
202 ProjectSetState *state;
206 /* check for unsupported flags */
207 Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
210 * create state structure
212 state = makeNode(ProjectSetState);
213 state->ps.plan = (Plan *) node;
214 state->ps.state = estate;
216 state->pending_srf_tuples = false;
219 * Miscellaneous initialization
221 * create expression context for node
223 ExecAssignExprContext(estate, &state->ps);
226 * tuple table initialization
228 ExecInitResultTupleSlot(estate, &state->ps);
230 /* We don't support any qual on ProjectSet nodes */
231 Assert(node->plan.qual == NIL);
234 * initialize child nodes
236 outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
239 * we don't use inner plan
241 Assert(innerPlan(node) == NULL);
244 * initialize tuple type and projection info
246 ExecAssignResultTypeFromTL(&state->ps);
248 /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
249 state->nelems = list_length(node->plan.targetlist);
250 state->elems = (Node **)
251 palloc(sizeof(Node *) * state->nelems);
252 state->elemdone = (ExprDoneCond *)
253 palloc(sizeof(ExprDoneCond) * state->nelems);
256 * Build expressions to evaluate targetlist. We can't use
257 * ExecBuildProjectionInfo here, since that doesn't deal with SRFs.
258 * Instead compile each expression separately, using
259 * ExecInitFunctionResultSet where applicable.
262 foreach(lc, node->plan.targetlist)
264 TargetEntry *te = (TargetEntry *) lfirst(lc);
265 Expr *expr = te->expr;
267 if ((IsA(expr, FuncExpr) &&((FuncExpr *) expr)->funcretset) ||
268 (IsA(expr, OpExpr) &&((OpExpr *) expr)->opretset))
270 state->elems[off] = (Node *)
271 ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
276 Assert(!expression_returns_set((Node *) expr));
277 state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
286 /* ----------------------------------------------------------------
289 * frees up storage allocated through C routines
290 * ----------------------------------------------------------------
293 ExecEndProjectSet(ProjectSetState *node)
296 * Free the exprcontext
298 ExecFreeExprContext(&node->ps);
301 * clean out the tuple table
303 ExecClearTuple(node->ps.ps_ResultTupleSlot);
308 ExecEndNode(outerPlanState(node));
312 ExecReScanProjectSet(ProjectSetState *node)
314 /* Forget any incompletely-evaluated SRFs */
315 node->pending_srf_tuples = false;
318 * If chgParam of subnode is not null then plan will be re-scanned by
319 * first ExecProcNode.
321 if (node->ps.lefttree->chgParam == NULL)
322 ExecReScan(node->ps.lefttree);