PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeProjectSet.c
Go to the documentation of this file.
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"
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  */
43 {
44  TupleTableSlot *outerTupleSlot;
45  TupleTableSlot *resultSlot;
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  */
200 ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
201 {
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  */
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 *)
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
294 {
295  /*
296  * Free the exprcontext
297  */
298  ExecFreeExprContext(&node->ps);
299 
300  /*
301  * clean out the tuple table
302  */
304 
305  /*
306  * shut down subplans
307  */
309 }
310 
311 void
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 }
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:135
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:398
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
PlanState ps
Definition: execnodes.h:896
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:654
ExprContext * ps_ExprContext
Definition: execnodes.h:833
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:670
bool pending_srf_tuples
Definition: execnodes.h:900
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
Definition: nodes.h:509
static TupleTableSlot * ExecProjectSRF(ProjectSetState *node, bool continuing)
Datum * tts_values
Definition: tuptable.h:125
return result
Definition: formatting.c:1618
EState * state
Definition: execnodes.h:805
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:440
struct PlanState * lefttree
Definition: execnodes.h:818
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:832
void ExecReScanProjectSet(ProjectSetState *node)
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
SetExprState * ExecInitFunctionResultSet(Expr *expr, ExprContext *econtext, PlanState *parent)
Definition: execSRF.c:424
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:845
#define innerPlan(node)
Definition: plannodes.h:163
Node ** elems
Definition: execnodes.h:897
bool * tts_isnull
Definition: tuptable.h:126
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
#define TupIsNull(slot)
Definition: tuptable.h:138
Datum ExecMakeFunctionResultSet(SetExprState *fcache, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone)
Definition: execSRF.c:473
TupleTableSlot * ExecProjectSet(ProjectSetState *node)
Bitmapset * chgParam
Definition: execnodes.h:827
#define outerPlan(node)
Definition: plannodes.h:164
ExprDoneCond
Definition: execnodes.h:235
uintptr_t Datum
Definition: postgres.h:372
Plan * plan
Definition: execnodes.h:803
#define makeNode(_type_)
Definition: nodes.h:557
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:61
Definition: regguts.h:298
Expr * expr
Definition: primnodes.h:1367
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:418
static int list_length(const List *l)
Definition: pg_list.h:89
ProjectSetState * ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
List * targetlist
Definition: plannodes.h:134
void * palloc(Size size)
Definition: mcxt.c:849
ExprDoneCond * elemdone
Definition: execnodes.h:898
void ExecEndProjectSet(ProjectSetState *node)
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:990
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:140
#define ResetExprContext(econtext)
Definition: executor.h:449
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
Plan plan
Definition: plannodes.h:192