PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeResult.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nodeResult.c
4  * support for constant nodes needing special code.
5  *
6  * DESCRIPTION
7  *
8  * Result nodes are used in queries where no relations are scanned.
9  * Examples of such queries are:
10  *
11  * select 1 * 2
12  *
13  * insert into emp values ('mike', 15000)
14  *
15  * (Remember that in an INSERT or UPDATE, we need a plan tree that
16  * generates the new rows.)
17  *
18  * Result nodes are also used to optimise queries with constant
19  * qualifications (ie, quals that do not depend on the scanned data),
20  * such as:
21  *
22  * select * from emp where 2 > 1
23  *
24  * In this case, the plan generated is
25  *
26  * Result (with 2 > 1 qual)
27  * /
28  * SeqScan (emp.*)
29  *
30  * At runtime, the Result node evaluates the constant qual once,
31  * which is shown by EXPLAIN as a One-Time Filter. If it's
32  * false, we can return an empty result set without running the
33  * controlled plan at all. If it's true, we run the controlled
34  * plan normally and pass back the results.
35  *
36  *
37  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
38  * Portions Copyright (c) 1994, Regents of the University of California
39  *
40  * IDENTIFICATION
41  * src/backend/executor/nodeResult.c
42  *
43  *-------------------------------------------------------------------------
44  */
45 
46 #include "postgres.h"
47 
48 #include "executor/executor.h"
49 #include "executor/nodeResult.h"
50 #include "utils/memutils.h"
51 
52 
53 /* ----------------------------------------------------------------
54  * ExecResult(node)
55  *
56  * returns the tuples from the outer plan which satisfy the
57  * qualification clause. Since result nodes with right
58  * subtrees are never planned, we ignore the right subtree
59  * entirely (for now).. -cim 10/7/89
60  *
61  * The qualification containing only constant clauses are
62  * checked first before any processing is done. It always returns
63  * 'nil' if the constant qualification is not satisfied.
64  * ----------------------------------------------------------------
65  */
68 {
69  TupleTableSlot *outerTupleSlot;
70  TupleTableSlot *resultSlot;
72  ExprContext *econtext;
73  ExprDoneCond isDone;
74 
75  econtext = node->ps.ps_ExprContext;
76 
77  /*
78  * check constant qualifications like (2 > 1), if not already done
79  */
80  if (node->rs_checkqual)
81  {
82  bool qualResult = ExecQual((List *) node->resconstantqual,
83  econtext,
84  false);
85 
86  node->rs_checkqual = false;
87  if (!qualResult)
88  {
89  node->rs_done = true;
90  return NULL;
91  }
92  }
93 
94  /*
95  * Check to see if we're still projecting out tuples from a previous scan
96  * tuple (because there is a function-returning-set in the projection
97  * expressions). If so, try to project another one.
98  */
99  if (node->ps.ps_TupFromTlist)
100  {
101  resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
102  if (isDone == ExprMultipleResult)
103  return resultSlot;
104  /* Done with that source tuple... */
105  node->ps.ps_TupFromTlist = false;
106  }
107 
108  /*
109  * Reset per-tuple memory context to free any expression evaluation
110  * storage allocated in the previous tuple cycle. Note this can't happen
111  * until we're done projecting out tuples from a scan tuple.
112  */
113  ResetExprContext(econtext);
114 
115  /*
116  * if rs_done is true then it means that we were asked to return a
117  * constant tuple and we already did the last time ExecResult() was
118  * called, OR that we failed the constant qual check. Either way, now we
119  * are through.
120  */
121  while (!node->rs_done)
122  {
123  outerPlan = outerPlanState(node);
124 
125  if (outerPlan != NULL)
126  {
127  /*
128  * retrieve tuples from the outer plan until there are no more.
129  */
130  outerTupleSlot = ExecProcNode(outerPlan);
131 
132  if (TupIsNull(outerTupleSlot))
133  return NULL;
134 
135  /*
136  * prepare to compute projection expressions, which will expect to
137  * access the input tuples as varno OUTER.
138  */
139  econtext->ecxt_outertuple = outerTupleSlot;
140  }
141  else
142  {
143  /*
144  * if we don't have an outer plan, then we are just generating the
145  * results from a constant target list. Do it only once.
146  */
147  node->rs_done = true;
148  }
149 
150  /*
151  * form the result tuple using ExecProject(), and return it --- unless
152  * the projection produces an empty set, in which case we must loop
153  * back to see if there are more outerPlan tuples.
154  */
155  resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
156 
157  if (isDone != ExprEndResult)
158  {
159  node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
160  return resultSlot;
161  }
162  }
163 
164  return NULL;
165 }
166 
167 /* ----------------------------------------------------------------
168  * ExecResultMarkPos
169  * ----------------------------------------------------------------
170  */
171 void
173 {
175 
176  if (outerPlan != NULL)
177  ExecMarkPos(outerPlan);
178  else
179  elog(DEBUG2, "Result nodes do not support mark/restore");
180 }
181 
182 /* ----------------------------------------------------------------
183  * ExecResultRestrPos
184  * ----------------------------------------------------------------
185  */
186 void
188 {
190 
191  if (outerPlan != NULL)
192  ExecRestrPos(outerPlan);
193  else
194  elog(ERROR, "Result nodes do not support mark/restore");
195 }
196 
197 /* ----------------------------------------------------------------
198  * ExecInitResult
199  *
200  * Creates the run-time state information for the result node
201  * produced by the planner and initializes outer relations
202  * (child nodes).
203  * ----------------------------------------------------------------
204  */
205 ResultState *
206 ExecInitResult(Result *node, EState *estate, int eflags)
207 {
208  ResultState *resstate;
209 
210  /* check for unsupported flags */
211  Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) ||
212  outerPlan(node) != NULL);
213 
214  /*
215  * create state structure
216  */
217  resstate = makeNode(ResultState);
218  resstate->ps.plan = (Plan *) node;
219  resstate->ps.state = estate;
220 
221  resstate->rs_done = false;
222  resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
223 
224  /*
225  * Miscellaneous initialization
226  *
227  * create expression context for node
228  */
229  ExecAssignExprContext(estate, &resstate->ps);
230 
231  resstate->ps.ps_TupFromTlist = false;
232 
233  /*
234  * tuple table initialization
235  */
236  ExecInitResultTupleSlot(estate, &resstate->ps);
237 
238  /*
239  * initialize child expressions
240  */
241  resstate->ps.targetlist = (List *)
242  ExecInitExpr((Expr *) node->plan.targetlist,
243  (PlanState *) resstate);
244  resstate->ps.qual = (List *)
245  ExecInitExpr((Expr *) node->plan.qual,
246  (PlanState *) resstate);
247  resstate->resconstantqual = ExecInitExpr((Expr *) node->resconstantqual,
248  (PlanState *) resstate);
249 
250  /*
251  * initialize child nodes
252  */
253  outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags);
254 
255  /*
256  * we don't use inner plan
257  */
258  Assert(innerPlan(node) == NULL);
259 
260  /*
261  * initialize tuple type and projection info
262  */
263  ExecAssignResultTypeFromTL(&resstate->ps);
264  ExecAssignProjectionInfo(&resstate->ps, NULL);
265 
266  return resstate;
267 }
268 
269 /* ----------------------------------------------------------------
270  * ExecEndResult
271  *
272  * frees up storage allocated through C routines
273  * ----------------------------------------------------------------
274  */
275 void
277 {
278  /*
279  * Free the exprcontext
280  */
281  ExecFreeExprContext(&node->ps);
282 
283  /*
284  * clean out the tuple table
285  */
287 
288  /*
289  * shut down subplans
290  */
292 }
293 
294 void
296 {
297  node->rs_done = false;
298  node->ps.ps_TupFromTlist = false;
299  node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
300 
301  /*
302  * If chgParam of subnode is not null then plan will be re-scanned by
303  * first ExecProcNode.
304  */
305  if (node->ps.lefttree &&
306  node->ps.lefttree->chgParam == NULL)
307  ExecReScan(node->ps.lefttree);
308 }
Plan plan
Definition: plannodes.h:167
List * qual
Definition: plannodes.h:122
bool rs_done
Definition: execnodes.h:1110
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:374
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1059
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:614
Definition: plannodes.h:96
ExprContext * ps_ExprContext
Definition: execnodes.h:1058
void ExecReScan(PlanState *node)
Definition: execAmi.c:73
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:442
List * qual
Definition: execnodes.h:1042
TupleTableSlot * ExecResult(ResultState *node)
Definition: nodeResult.c:67
List * targetlist
Definition: execnodes.h:1041
TupleTableSlot * ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
Definition: execQual.c:5520
EState * state
Definition: execnodes.h:1029
void ExecReScanResult(ResultState *node)
Definition: nodeResult.c:295
void ExecResultRestrPos(ResultState *node)
Definition: nodeResult.c:187
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:696
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:435
struct PlanState * lefttree
Definition: execnodes.h:1043
Node * resconstantqual
Definition: plannodes.h:168
void ExecRestrPos(PlanState *node)
Definition: execAmi.c:344
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1057
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execQual.c:4452
void ExecEndResult(ResultState *node)
Definition: nodeResult.c:276
#define ERROR
Definition: elog.h:43
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:835
ExprState * resconstantqual
Definition: execnodes.h:1109
#define EXEC_FLAG_BACKWARD
Definition: executor.h:59
#define outerPlanState(node)
Definition: execnodes.h:1072
#define innerPlan(node)
Definition: plannodes.h:150
#define DEBUG2
Definition: elog.h:24
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:668
bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
Definition: execQual.c:5246
#define TupIsNull(slot)
Definition: tuptable.h:138
Bitmapset * chgParam
Definition: execnodes.h:1052
#define outerPlan(node)
Definition: plannodes.h:151
bool rs_checkqual
Definition: execnodes.h:1111
ExprDoneCond
Definition: execnodes.h:159
Plan * plan
Definition: execnodes.h:1027
void ExecMarkPos(PlanState *node)
Definition: execAmi.c:295
#define makeNode(_type_)
Definition: nodes.h:539
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:124
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
#define EXEC_FLAG_MARK
Definition: executor.h:60
ResultState * ExecInitResult(Result *node, EState *estate, int eflags)
Definition: nodeResult.c:206
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:413
void ExecResultMarkPos(ResultState *node)
Definition: nodeResult.c:172
List * targetlist
Definition: plannodes.h:121
#define elog
Definition: elog.h:218
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:136
bool ps_TupFromTlist
Definition: execnodes.h:1060
Definition: pg_list.h:45
#define ResetExprContext(econtext)
Definition: executor.h:316
PlanState ps
Definition: execnodes.h:1108