]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeProjectSet.c
Initial pgindent run with pg_bsd_indent version 2.0.
[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-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 "nodes/nodeFuncs.h"
28 #include "utils/memutils.h"
29
30
31 static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
32
33
34 /* ----------------------------------------------------------------
35  *              ExecProjectSet(node)
36  *
37  *              Return tuples after evaluating the targetlist (which contains set
38  *              returning functions).
39  * ----------------------------------------------------------------
40  */
41 TupleTableSlot *
42 ExecProjectSet(ProjectSetState *node)
43 {
44         TupleTableSlot *outerTupleSlot;
45         TupleTableSlot *resultSlot;
46         PlanState  *outerPlan;
47         ExprContext *econtext;
48
49         econtext = node->ps.ps_ExprContext;
50
51         /*
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.
55          */
56         if (node->pending_srf_tuples)
57         {
58                 resultSlot = ExecProjectSRF(node, true);
59
60                 if (resultSlot != NULL)
61                         return resultSlot;
62         }
63
64         /*
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.
68          */
69         ResetExprContext(econtext);
70
71         /*
72          * Get another input tuple and project SRFs from it.
73          */
74         for (;;)
75         {
76                 /*
77                  * Retrieve tuples from the outer plan until there are no more.
78                  */
79                 outerPlan = outerPlanState(node);
80                 outerTupleSlot = ExecProcNode(outerPlan);
81
82                 if (TupIsNull(outerTupleSlot))
83                         return NULL;
84
85                 /*
86                  * Prepare to compute projection expressions, which will expect to
87                  * access the input tuples as varno OUTER.
88                  */
89                 econtext->ecxt_outertuple = outerTupleSlot;
90
91                 /* Evaluate the expressions */
92                 resultSlot = ExecProjectSRF(node, false);
93
94                 /*
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.
98                  */
99                 if (resultSlot)
100                         return resultSlot;
101         }
102
103         return NULL;
104 }
105
106 /* ----------------------------------------------------------------
107  *              ExecProjectSRF
108  *
109  *              Project a targetlist containing one or more set-returning functions.
110  *
111  *              'continuing' indicates whether to continue projecting rows for the
112  *              same input tuple; or whether a new input tuple is being projected.
113  *
114  *              Returns NULL if no output tuple has been produced.
115  *
116  * ----------------------------------------------------------------
117  */
118 static TupleTableSlot *
119 ExecProjectSRF(ProjectSetState *node, bool continuing)
120 {
121         TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
122         ExprContext *econtext = node->ps.ps_ExprContext;
123         bool            hassrf PG_USED_FOR_ASSERTS_ONLY;
124         bool            hasresult;
125         int                     argno;
126
127         ExecClearTuple(resultSlot);
128
129         /*
130          * Assume no further tuples are produced unless an ExprMultipleResult is
131          * encountered from a set returning function.
132          */
133         node->pending_srf_tuples = false;
134
135         hassrf = hasresult = false;
136         for (argno = 0; argno < node->nelems; argno++)
137         {
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];
142
143                 if (continuing && *isdone == ExprEndResult)
144                 {
145                         /*
146                          * If we're continuing to project output rows from a source tuple,
147                          * return NULLs once the SRF has been exhausted.
148                          */
149                         *result = (Datum) 0;
150                         *isnull = true;
151                         hassrf = true;
152                 }
153                 else if (IsA(elem, SetExprState))
154                 {
155                         /*
156                          * Evaluate SRF - possibly continuing previously started output.
157                          */
158                         *result = ExecMakeFunctionResultSet((SetExprState *) elem,
159                                                                                                 econtext, isnull, isdone);
160
161                         if (*isdone != ExprEndResult)
162                                 hasresult = true;
163                         if (*isdone == ExprMultipleResult)
164                                 node->pending_srf_tuples = true;
165                         hassrf = true;
166                 }
167                 else
168                 {
169                         /* Non-SRF tlist expression, just evaluate normally. */
170                         *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
171                         *isdone = ExprSingleResult;
172                 }
173         }
174
175         /* ProjectSet should not be used if there's no SRFs */
176         Assert(hassrf);
177
178         /*
179          * If all the SRFs returned EndResult, we consider that as no row being
180          * produced.
181          */
182         if (hasresult)
183         {
184                 ExecStoreVirtualTuple(resultSlot);
185                 return resultSlot;
186         }
187
188         return NULL;
189 }
190
191 /* ----------------------------------------------------------------
192  *              ExecInitProjectSet
193  *
194  *              Creates the run-time state information for the ProjectSet node
195  *              produced by the planner and initializes outer relations
196  *              (child nodes).
197  * ----------------------------------------------------------------
198  */
199 ProjectSetState *
200 ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
201 {
202         ProjectSetState *state;
203         ListCell   *lc;
204         int                     off;
205
206         /* check for unsupported flags */
207         Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
208
209         /*
210          * create state structure
211          */
212         state = makeNode(ProjectSetState);
213         state->ps.plan = (Plan *) node;
214         state->ps.state = estate;
215
216         state->pending_srf_tuples = false;
217
218         /*
219          * Miscellaneous initialization
220          *
221          * create expression context for node
222          */
223         ExecAssignExprContext(estate, &state->ps);
224
225         /*
226          * tuple table initialization
227          */
228         ExecInitResultTupleSlot(estate, &state->ps);
229
230         /* We don't support any qual on ProjectSet nodes */
231         Assert(node->plan.qual == NIL);
232
233         /*
234          * initialize child nodes
235          */
236         outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
237
238         /*
239          * we don't use inner plan
240          */
241         Assert(innerPlan(node) == NULL);
242
243         /*
244          * initialize tuple type and projection info
245          */
246         ExecAssignResultTypeFromTL(&state->ps);
247
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);
254
255         /*
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.
260          */
261         off = 0;
262         foreach(lc, node->plan.targetlist)
263         {
264                 TargetEntry *te = (TargetEntry *) lfirst(lc);
265                 Expr       *expr = te->expr;
266
267                 if ((IsA(expr, FuncExpr) &&((FuncExpr *) expr)->funcretset) ||
268                         (IsA(expr, OpExpr) &&((OpExpr *) expr)->opretset))
269                 {
270                         state->elems[off] = (Node *)
271                                 ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
272                                                                                   &state->ps);
273                 }
274                 else
275                 {
276                         Assert(!expression_returns_set((Node *) expr));
277                         state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
278                 }
279
280                 off++;
281         }
282
283         return state;
284 }
285
286 /* ----------------------------------------------------------------
287  *              ExecEndProjectSet
288  *
289  *              frees up storage allocated through C routines
290  * ----------------------------------------------------------------
291  */
292 void
293 ExecEndProjectSet(ProjectSetState *node)
294 {
295         /*
296          * Free the exprcontext
297          */
298         ExecFreeExprContext(&node->ps);
299
300         /*
301          * clean out the tuple table
302          */
303         ExecClearTuple(node->ps.ps_ResultTupleSlot);
304
305         /*
306          * shut down subplans
307          */
308         ExecEndNode(outerPlanState(node));
309 }
310
311 void
312 ExecReScanProjectSet(ProjectSetState *node)
313 {
314         /* Forget any incompletely-evaluated SRFs */
315         node->pending_srf_tuples = false;
316
317         /*
318          * If chgParam of subnode is not null then plan will be re-scanned by
319          * first ExecProcNode.
320          */
321         if (node->ps.lefttree->chgParam == NULL)
322                 ExecReScan(node->ps.lefttree);
323 }