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 "utils/memutils.h"
28 
29 
30 static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
31 
32 
33 /* ----------------------------------------------------------------
34  * ExecProjectSet(node)
35  *
36  * Return tuples after evaluating the targetlist (which contains set
37  * returning functions).
38  * ----------------------------------------------------------------
39  */
42 {
43  TupleTableSlot *outerTupleSlot;
44  TupleTableSlot *resultSlot;
46  ExprContext *econtext;
47 
48  econtext = node->ps.ps_ExprContext;
49 
50  /*
51  * Check to see if we're still projecting out tuples from a previous scan
52  * tuple (because there is a function-returning-set in the projection
53  * expressions). If so, try to project another one.
54  */
55  if (node->pending_srf_tuples)
56  {
57  resultSlot = ExecProjectSRF(node, true);
58 
59  if (resultSlot != NULL)
60  return resultSlot;
61  }
62 
63  /*
64  * Reset per-tuple memory context to free any expression evaluation
65  * storage allocated in the previous tuple cycle. Note this can't happen
66  * until we're done projecting out tuples from a scan tuple.
67  */
68  ResetExprContext(econtext);
69 
70  /*
71  * Get another input tuple and project SRFs from it.
72  */
73  for (;;)
74  {
75  /*
76  * Retrieve tuples from the outer plan until there are no more.
77  */
78  outerPlan = outerPlanState(node);
79  outerTupleSlot = ExecProcNode(outerPlan);
80 
81  if (TupIsNull(outerTupleSlot))
82  return NULL;
83 
84  /*
85  * Prepare to compute projection expressions, which will expect to
86  * access the input tuples as varno OUTER.
87  */
88  econtext->ecxt_outertuple = outerTupleSlot;
89 
90  /* Evaluate the expressions */
91  resultSlot = ExecProjectSRF(node, false);
92 
93  /*
94  * Return the tuple unless the projection produced no rows (due to an
95  * empty set), in which case we must loop back to see if there are
96  * more outerPlan tuples.
97  */
98  if (resultSlot)
99  return resultSlot;
100  }
101 
102  return NULL;
103 }
104 
105 /* ----------------------------------------------------------------
106  * ExecProjectSRF
107  *
108  * Project a targetlist containing one or more set-returning functions.
109  *
110  * 'continuing' indicates whether to continue projecting rows for the
111  * same input tuple; or whether a new input tuple is being projected.
112  *
113  * Returns NULL if no output tuple has been produced.
114  *
115  * ----------------------------------------------------------------
116  */
117 static TupleTableSlot *
118 ExecProjectSRF(ProjectSetState *node, bool continuing)
119 {
120  TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
121  ExprContext *econtext = node->ps.ps_ExprContext;
122  bool hassrf PG_USED_FOR_ASSERTS_ONLY = false;
123  bool hasresult;
124  int argno;
125  ListCell *lc;
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  hasresult = false;
136  argno = 0;
137  foreach(lc, node->ps.targetlist)
138  {
139  GenericExprState *gstate = (GenericExprState *) lfirst(lc);
140  ExprDoneCond *isdone = &node->elemdone[argno];
141  Datum *result = &resultSlot->tts_values[argno];
142  bool *isnull = &resultSlot->tts_isnull[argno];
143 
144  if (continuing && *isdone == ExprEndResult)
145  {
146  /*
147  * If we're continuing to project output rows from a source tuple,
148  * return NULLs once the SRF has been exhausted.
149  */
150  *result = (Datum) 0;
151  *isnull = true;
152  hassrf = true;
153  }
154  else if (IsA(gstate->arg, FuncExprState) &&
155  ((FuncExprState *) gstate->arg)->funcReturnsSet)
156  {
157  /*
158  * Evaluate SRF - possibly continuing previously started output.
159  */
160  *result = ExecMakeFunctionResultSet((FuncExprState *) gstate->arg,
161  econtext, isnull, isdone);
162 
163  if (*isdone != ExprEndResult)
164  hasresult = true;
165  if (*isdone == ExprMultipleResult)
166  node->pending_srf_tuples = true;
167  hassrf = true;
168  }
169  else
170  {
171  /* Non-SRF tlist expression, just evaluate normally. */
172  *result = ExecEvalExpr(gstate->arg, econtext, isnull);
173  *isdone = ExprSingleResult;
174  }
175 
176  argno++;
177  }
178 
179  /* ProjectSet should not be used if there's no SRFs */
180  Assert(hassrf);
181 
182  /*
183  * If all the SRFs returned EndResult, we consider that as no row being
184  * produced.
185  */
186  if (hasresult)
187  {
188  ExecStoreVirtualTuple(resultSlot);
189  return resultSlot;
190  }
191 
192  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  */
204 ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
205 {
207 
208  /* check for unsupported flags */
209  Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
210 
211  /*
212  * create state structure
213  */
214  state = makeNode(ProjectSetState);
215  state->ps.plan = (Plan *) node;
216  state->ps.state = estate;
217 
218  state->pending_srf_tuples = false;
219 
220  /*
221  * Miscellaneous initialization
222  *
223  * create expression context for node
224  */
225  ExecAssignExprContext(estate, &state->ps);
226 
227  /*
228  * tuple table initialization
229  */
230  ExecInitResultTupleSlot(estate, &state->ps);
231 
232  /*
233  * initialize child expressions
234  */
235  state->ps.targetlist = (List *)
236  ExecInitExpr((Expr *) node->plan.targetlist,
237  (PlanState *) state);
238  Assert(node->plan.qual == NIL);
239 
240  /*
241  * initialize child nodes
242  */
243  outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
244 
245  /*
246  * we don't use inner plan
247  */
248  Assert(innerPlan(node) == NULL);
249 
250  /*
251  * initialize tuple type and projection info
252  */
254 
255  /* Create workspace for per-SRF is-done state */
256  state->nelems = list_length(node->plan.targetlist);
257  state->elemdone = (ExprDoneCond *)
258  palloc(sizeof(ExprDoneCond) * state->nelems);
259 
260  return state;
261 }
262 
263 /* ----------------------------------------------------------------
264  * ExecEndProjectSet
265  *
266  * frees up storage allocated through C routines
267  * ----------------------------------------------------------------
268  */
269 void
271 {
272  /*
273  * Free the exprcontext
274  */
275  ExecFreeExprContext(&node->ps);
276 
277  /*
278  * clean out the tuple table
279  */
281 
282  /*
283  * shut down subplans
284  */
286 }
287 
288 void
290 {
291  /* Forget any incompletely-evaluated SRFs */
292  node->pending_srf_tuples = false;
293 
294  /*
295  * If chgParam of subnode is not null then plan will be re-scanned by
296  * first ExecProcNode.
297  */
298  if (node->ps.lefttree->chgParam == NULL)
299  ExecReScan(node->ps.lefttree);
300 }
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:130
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:380
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
PlanState ps
Definition: execnodes.h:1138
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:624
ExprContext * ps_ExprContext
Definition: execnodes.h:1078
void ExecReScan(PlanState *node)
Definition: execAmi.c:73
bool pending_srf_tuples
Definition: execnodes.h:1141
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
static TupleTableSlot * ExecProjectSRF(ProjectSetState *node, bool continuing)
List * targetlist
Definition: execnodes.h:1061
Datum * tts_values
Definition: tuptable.h:125
EState * state
Definition: execnodes.h:1049
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:685
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:430
struct PlanState * lefttree
Definition: execnodes.h:1063
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1077
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execQual.c:4266
void ExecReScanProjectSet(ProjectSetState *node)
#define ExecEvalExpr(expr, econtext, isNull)
Definition: executor.h:73
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:1090
#define innerPlan(node)
Definition: plannodes.h:158
bool * tts_isnull
Definition: tuptable.h:126
Datum ExecMakeFunctionResultSet(FuncExprState *fcache, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone)
Definition: execQual.c:1614
#define TupIsNull(slot)
Definition: tuptable.h:138
TupleTableSlot * ExecProjectSet(ProjectSetState *node)
Bitmapset * chgParam
Definition: execnodes.h:1072
#define outerPlan(node)
Definition: plannodes.h:159
ExprState * arg
Definition: execnodes.h:612
ExprDoneCond
Definition: execnodes.h:166
uintptr_t Datum
Definition: postgres.h:374
Plan * plan
Definition: execnodes.h:1047
#define makeNode(_type_)
Definition: nodes.h:557
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:130
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:61
Definition: regguts.h:298
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:408
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:129
void * palloc(Size size)
Definition: mcxt.c:891
ExprDoneCond * elemdone
Definition: execnodes.h:1139
void ExecEndProjectSet(ProjectSetState *node)
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:986
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:137
Definition: pg_list.h:45
#define ResetExprContext(econtext)
Definition: executor.h:332
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
Plan plan
Definition: plannodes.h:187