]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeProjectSet.c
Fix inconsistencies in the code
[postgresql] / src / backend / executor / nodeProjectSet.c
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-2019, 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 ExecProjectSet(PlanState *pstate)
44 {
45         ProjectSetState *node = castNode(ProjectSetState, pstate);
46         TupleTableSlot *outerTupleSlot;
47         TupleTableSlot *resultSlot;
48         PlanState  *outerPlan;
49         ExprContext *econtext;
50
51         CHECK_FOR_INTERRUPTS();
52
53         econtext = node->ps.ps_ExprContext;
54
55         /*
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.
59          */
60         ResetExprContext(econtext);
61
62         /*
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.
66          */
67         if (node->pending_srf_tuples)
68         {
69                 resultSlot = ExecProjectSRF(node, true);
70
71                 if (resultSlot != NULL)
72                         return resultSlot;
73         }
74
75         /*
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.
81          */
82         MemoryContextReset(node->argcontext);
83
84         /*
85          * Get another input tuple and project SRFs from it.
86          */
87         for (;;)
88         {
89                 /*
90                  * Retrieve tuples from the outer plan until there are no more.
91                  */
92                 outerPlan = outerPlanState(node);
93                 outerTupleSlot = ExecProcNode(outerPlan);
94
95                 if (TupIsNull(outerTupleSlot))
96                         return NULL;
97
98                 /*
99                  * Prepare to compute projection expressions, which will expect to
100                  * access the input tuples as varno OUTER.
101                  */
102                 econtext->ecxt_outertuple = outerTupleSlot;
103
104                 /* Evaluate the expressions */
105                 resultSlot = ExecProjectSRF(node, false);
106
107                 /*
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.
111                  */
112                 if (resultSlot)
113                         return resultSlot;
114         }
115
116         return NULL;
117 }
118
119 /* ----------------------------------------------------------------
120  *              ExecProjectSRF
121  *
122  *              Project a targetlist containing one or more set-returning functions.
123  *
124  *              'continuing' indicates whether to continue projecting rows for the
125  *              same input tuple; or whether a new input tuple is being projected.
126  *
127  *              Returns NULL if no output tuple has been produced.
128  *
129  * ----------------------------------------------------------------
130  */
131 static TupleTableSlot *
132 ExecProjectSRF(ProjectSetState *node, bool continuing)
133 {
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;
140
141         ExecClearTuple(resultSlot);
142
143         /* Call SRFs, as well as plain expressions, in per-tuple context */
144         oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
145
146         /*
147          * Assume no further tuples are produced unless an ExprMultipleResult is
148          * encountered from a set returning function.
149          */
150         node->pending_srf_tuples = false;
151
152         hassrf = hasresult = false;
153         for (argno = 0; argno < node->nelems; argno++)
154         {
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];
159
160                 if (continuing && *isdone == ExprEndResult)
161                 {
162                         /*
163                          * If we're continuing to project output rows from a source tuple,
164                          * return NULLs once the SRF has been exhausted.
165                          */
166                         *result = (Datum) 0;
167                         *isnull = true;
168                         hassrf = true;
169                 }
170                 else if (IsA(elem, SetExprState))
171                 {
172                         /*
173                          * Evaluate SRF - possibly continuing previously started output.
174                          */
175                         *result = ExecMakeFunctionResultSet((SetExprState *) elem,
176                                                                                                 econtext, node->argcontext,
177                                                                                                 isnull, isdone);
178
179                         if (*isdone != ExprEndResult)
180                                 hasresult = true;
181                         if (*isdone == ExprMultipleResult)
182                                 node->pending_srf_tuples = true;
183                         hassrf = true;
184                 }
185                 else
186                 {
187                         /* Non-SRF tlist expression, just evaluate normally. */
188                         *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
189                         *isdone = ExprSingleResult;
190                 }
191         }
192
193         MemoryContextSwitchTo(oldcontext);
194
195         /* ProjectSet should not be used if there's no SRFs */
196         Assert(hassrf);
197
198         /*
199          * If all the SRFs returned ExprEndResult, we consider that as no row
200          * being produced.
201          */
202         if (hasresult)
203         {
204                 ExecStoreVirtualTuple(resultSlot);
205                 return resultSlot;
206         }
207
208         return NULL;
209 }
210
211 /* ----------------------------------------------------------------
212  *              ExecInitProjectSet
213  *
214  *              Creates the run-time state information for the ProjectSet node
215  *              produced by the planner and initializes outer relations
216  *              (child nodes).
217  * ----------------------------------------------------------------
218  */
219 ProjectSetState *
220 ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
221 {
222         ProjectSetState *state;
223         ListCell   *lc;
224         int                     off;
225
226         /* check for unsupported flags */
227         Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
228
229         /*
230          * create state structure
231          */
232         state = makeNode(ProjectSetState);
233         state->ps.plan = (Plan *) node;
234         state->ps.state = estate;
235         state->ps.ExecProcNode = ExecProjectSet;
236
237         state->pending_srf_tuples = false;
238
239         /*
240          * Miscellaneous initialization
241          *
242          * create expression context for node
243          */
244         ExecAssignExprContext(estate, &state->ps);
245
246         /*
247          * initialize child nodes
248          */
249         outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
250
251         /*
252          * we don't use inner plan
253          */
254         Assert(innerPlan(node) == NULL);
255
256         /*
257          * tuple table and result type initialization
258          */
259         ExecInitResultTupleSlotTL(&state->ps, &TTSOpsVirtual);
260
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);
267
268         /*
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.
273          */
274         off = 0;
275         foreach(lc, node->plan.targetlist)
276         {
277                 TargetEntry *te = (TargetEntry *) lfirst(lc);
278                 Expr       *expr = te->expr;
279
280                 if ((IsA(expr, FuncExpr) &&((FuncExpr *) expr)->funcretset) ||
281                         (IsA(expr, OpExpr) &&((OpExpr *) expr)->opretset))
282                 {
283                         state->elems[off] = (Node *)
284                                 ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
285                                                                                   &state->ps);
286                 }
287                 else
288                 {
289                         Assert(!expression_returns_set((Node *) expr));
290                         state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
291                 }
292
293                 off++;
294         }
295
296         /* We don't support any qual on ProjectSet nodes */
297         Assert(node->plan.qual == NIL);
298
299         /*
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.
306          */
307         state->argcontext = AllocSetContextCreate(CurrentMemoryContext,
308                                                                                           "tSRF function arguments",
309                                                                                           ALLOCSET_DEFAULT_SIZES);
310
311         return state;
312 }
313
314 /* ----------------------------------------------------------------
315  *              ExecEndProjectSet
316  *
317  *              frees up storage allocated through C routines
318  * ----------------------------------------------------------------
319  */
320 void
321 ExecEndProjectSet(ProjectSetState *node)
322 {
323         /*
324          * Free the exprcontext
325          */
326         ExecFreeExprContext(&node->ps);
327
328         /*
329          * clean out the tuple table
330          */
331         ExecClearTuple(node->ps.ps_ResultTupleSlot);
332
333         /*
334          * shut down subplans
335          */
336         ExecEndNode(outerPlanState(node));
337 }
338
339 void
340 ExecReScanProjectSet(ProjectSetState *node)
341 {
342         /* Forget any incompletely-evaluated SRFs */
343         node->pending_srf_tuples = false;
344
345         /*
346          * If chgParam of subnode is not null then plan will be re-scanned by
347          * first ExecProcNode.
348          */
349         if (node->ps.lefttree->chgParam == NULL)
350                 ExecReScan(node->ps.lefttree);
351 }