Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeProjectSet.c
4 : * support for evaluating targetlists containing set-returning functions
5 : *
6 : * DESCRIPTION
7 : *
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.
13 : *
14 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
15 : * Portions Copyright (c) 1994, Regents of the University of California
16 : *
17 : * IDENTIFICATION
18 : * src/backend/executor/nodeProjectSet.c
19 : *
20 : *-------------------------------------------------------------------------
21 : */
22 :
23 : #include "postgres.h"
24 :
25 : #include "executor/executor.h"
26 : #include "executor/nodeProjectSet.h"
27 : #include "miscadmin.h"
28 : #include "nodes/nodeFuncs.h"
29 : #include "utils/memutils.h"
30 :
31 :
32 : static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
33 :
34 :
35 : /* ----------------------------------------------------------------
36 : * ExecProjectSet(node)
37 : *
38 : * Return tuples after evaluating the targetlist (which contains set
39 : * returning functions).
40 : * ----------------------------------------------------------------
41 : */
42 : static TupleTableSlot *
43 17345 : ExecProjectSet(PlanState *pstate)
44 : {
45 17345 : ProjectSetState *node = castNode(ProjectSetState, pstate);
46 : TupleTableSlot *outerTupleSlot;
47 : TupleTableSlot *resultSlot;
48 : PlanState *outerPlan;
49 : ExprContext *econtext;
50 :
51 17345 : CHECK_FOR_INTERRUPTS();
52 :
53 17345 : econtext = node->ps.ps_ExprContext;
54 :
55 : /*
56 : * Check to see if we're still projecting out tuples from a previous scan
57 : * tuple (because there is a function-returning-set in the projection
58 : * expressions). If so, try to project another one.
59 : */
60 17345 : if (node->pending_srf_tuples)
61 : {
62 16935 : resultSlot = ExecProjectSRF(node, true);
63 :
64 16935 : if (resultSlot != NULL)
65 13820 : return resultSlot;
66 : }
67 :
68 : /*
69 : * Reset per-tuple memory context to free any expression evaluation
70 : * storage allocated in the previous tuple cycle. Note this can't happen
71 : * until we're done projecting out tuples from a scan tuple.
72 : */
73 3525 : ResetExprContext(econtext);
74 :
75 : /*
76 : * Get another input tuple and project SRFs from it.
77 : */
78 : for (;;)
79 : {
80 : /*
81 : * Retrieve tuples from the outer plan until there are no more.
82 : */
83 7067 : outerPlan = outerPlanState(node);
84 7067 : outerTupleSlot = ExecProcNode(outerPlan);
85 :
86 7067 : if (TupIsNull(outerTupleSlot))
87 392 : return NULL;
88 :
89 : /*
90 : * Prepare to compute projection expressions, which will expect to
91 : * access the input tuples as varno OUTER.
92 : */
93 6675 : econtext->ecxt_outertuple = outerTupleSlot;
94 :
95 : /* Evaluate the expressions */
96 6675 : resultSlot = ExecProjectSRF(node, false);
97 :
98 : /*
99 : * Return the tuple unless the projection produced no rows (due to an
100 : * empty set), in which case we must loop back to see if there are
101 : * more outerPlan tuples.
102 : */
103 6668 : if (resultSlot)
104 3126 : return resultSlot;
105 3542 : }
106 :
107 : return NULL;
108 : }
109 :
110 : /* ----------------------------------------------------------------
111 : * ExecProjectSRF
112 : *
113 : * Project a targetlist containing one or more set-returning functions.
114 : *
115 : * 'continuing' indicates whether to continue projecting rows for the
116 : * same input tuple; or whether a new input tuple is being projected.
117 : *
118 : * Returns NULL if no output tuple has been produced.
119 : *
120 : * ----------------------------------------------------------------
121 : */
122 : static TupleTableSlot *
123 23610 : ExecProjectSRF(ProjectSetState *node, bool continuing)
124 : {
125 23610 : TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
126 23610 : ExprContext *econtext = node->ps.ps_ExprContext;
127 : bool hassrf PG_USED_FOR_ASSERTS_ONLY;
128 : bool hasresult;
129 : int argno;
130 :
131 23610 : ExecClearTuple(resultSlot);
132 :
133 : /*
134 : * Assume no further tuples are produced unless an ExprMultipleResult is
135 : * encountered from a set returning function.
136 : */
137 23610 : node->pending_srf_tuples = false;
138 :
139 23610 : hassrf = hasresult = false;
140 57586 : for (argno = 0; argno < node->nelems; argno++)
141 : {
142 33983 : Node *elem = node->elems[argno];
143 33983 : ExprDoneCond *isdone = &node->elemdone[argno];
144 33983 : Datum *result = &resultSlot->tts_values[argno];
145 33983 : bool *isnull = &resultSlot->tts_isnull[argno];
146 :
147 33983 : if (continuing && *isdone == ExprEndResult)
148 : {
149 : /*
150 : * If we're continuing to project output rows from a source tuple,
151 : * return NULLs once the SRF has been exhausted.
152 : */
153 3 : *result = (Datum) 0;
154 3 : *isnull = true;
155 3 : hassrf = true;
156 : }
157 33980 : else if (IsA(elem, SetExprState))
158 : {
159 : /*
160 : * Evaluate SRF - possibly continuing previously started output.
161 : */
162 25559 : *result = ExecMakeFunctionResultSet((SetExprState *) elem,
163 : econtext, isnull, isdone);
164 :
165 25552 : if (*isdone != ExprEndResult)
166 18176 : hasresult = true;
167 25552 : if (*isdone == ExprMultipleResult)
168 18176 : node->pending_srf_tuples = true;
169 25552 : hassrf = true;
170 : }
171 : else
172 : {
173 : /* Non-SRF tlist expression, just evaluate normally. */
174 8421 : *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
175 8421 : *isdone = ExprSingleResult;
176 : }
177 : }
178 :
179 : /* ProjectSet should not be used if there's no SRFs */
180 23603 : Assert(hassrf);
181 :
182 : /*
183 : * If all the SRFs returned EndResult, we consider that as no row being
184 : * produced.
185 : */
186 23603 : if (hasresult)
187 : {
188 16946 : ExecStoreVirtualTuple(resultSlot);
189 16946 : return resultSlot;
190 : }
191 :
192 6657 : return NULL;
193 : }
194 :
195 : /* ----------------------------------------------------------------
196 : * ExecInitProjectSet
197 : *
198 : * Creates the run-time state information for the ProjectSet node
199 : * produced by the planner and initializes outer relations
200 : * (child nodes).
201 : * ----------------------------------------------------------------
202 : */
203 : ProjectSetState *
204 227 : ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
205 : {
206 : ProjectSetState *state;
207 : ListCell *lc;
208 : int off;
209 :
210 : /* check for unsupported flags */
211 227 : Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
212 :
213 : /*
214 : * create state structure
215 : */
216 227 : state = makeNode(ProjectSetState);
217 227 : state->ps.plan = (Plan *) node;
218 227 : state->ps.state = estate;
219 227 : state->ps.ExecProcNode = ExecProjectSet;
220 :
221 227 : state->pending_srf_tuples = false;
222 :
223 : /*
224 : * Miscellaneous initialization
225 : *
226 : * create expression context for node
227 : */
228 227 : ExecAssignExprContext(estate, &state->ps);
229 :
230 : /*
231 : * tuple table initialization
232 : */
233 227 : ExecInitResultTupleSlot(estate, &state->ps);
234 :
235 : /* We don't support any qual on ProjectSet nodes */
236 227 : Assert(node->plan.qual == NIL);
237 :
238 : /*
239 : * initialize child nodes
240 : */
241 227 : outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
242 :
243 : /*
244 : * we don't use inner plan
245 : */
246 227 : Assert(innerPlan(node) == NULL);
247 :
248 : /*
249 : * initialize tuple type and projection info
250 : */
251 227 : ExecAssignResultTypeFromTL(&state->ps);
252 :
253 : /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
254 227 : state->nelems = list_length(node->plan.targetlist);
255 227 : state->elems = (Node **)
256 227 : palloc(sizeof(Node *) * state->nelems);
257 227 : state->elemdone = (ExprDoneCond *)
258 227 : palloc(sizeof(ExprDoneCond) * state->nelems);
259 :
260 : /*
261 : * Build expressions to evaluate targetlist. We can't use
262 : * ExecBuildProjectionInfo here, since that doesn't deal with SRFs.
263 : * Instead compile each expression separately, using
264 : * ExecInitFunctionResultSet where applicable.
265 : */
266 227 : off = 0;
267 635 : foreach(lc, node->plan.targetlist)
268 : {
269 408 : TargetEntry *te = (TargetEntry *) lfirst(lc);
270 408 : Expr *expr = te->expr;
271 :
272 574 : if ((IsA(expr, FuncExpr) &&((FuncExpr *) expr)->funcretset) ||
273 167 : (IsA(expr, OpExpr) &&((OpExpr *) expr)->opretset))
274 : {
275 486 : state->elems[off] = (Node *)
276 243 : ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
277 : &state->ps);
278 : }
279 : else
280 : {
281 165 : Assert(!expression_returns_set((Node *) expr));
282 165 : state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
283 : }
284 :
285 408 : off++;
286 : }
287 :
288 227 : return state;
289 : }
290 :
291 : /* ----------------------------------------------------------------
292 : * ExecEndProjectSet
293 : *
294 : * frees up storage allocated through C routines
295 : * ----------------------------------------------------------------
296 : */
297 : void
298 219 : ExecEndProjectSet(ProjectSetState *node)
299 : {
300 : /*
301 : * Free the exprcontext
302 : */
303 219 : ExecFreeExprContext(&node->ps);
304 :
305 : /*
306 : * clean out the tuple table
307 : */
308 219 : ExecClearTuple(node->ps.ps_ResultTupleSlot);
309 :
310 : /*
311 : * shut down subplans
312 : */
313 219 : ExecEndNode(outerPlanState(node));
314 219 : }
315 :
316 : void
317 214 : ExecReScanProjectSet(ProjectSetState *node)
318 : {
319 : /* Forget any incompletely-evaluated SRFs */
320 214 : node->pending_srf_tuples = false;
321 :
322 : /*
323 : * If chgParam of subnode is not null then plan will be re-scanned by
324 : * first ExecProcNode.
325 : */
326 214 : if (node->ps.lefttree->chgParam == NULL)
327 214 : ExecReScan(node->ps.lefttree);
328 214 : }
|