]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeResult.c
pgindent run for 8.3.
[postgresql] / src / backend / executor / nodeResult.c
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-2007, PostgreSQL Global Development Group
38  * Portions Copyright (c) 1994, Regents of the University of California
39  *
40  * IDENTIFICATION
41  *        $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.41 2007/11/15 21:14:35 momjian Exp $
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  */
66 TupleTableSlot *
67 ExecResult(ResultState *node)
68 {
69         TupleTableSlot *outerTupleSlot;
70         TupleTableSlot *resultSlot;
71         PlanState  *outerPlan;
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
172 ExecResultMarkPos(ResultState *node)
173 {
174         PlanState  *outerPlan = outerPlanState(node);
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
187 ExecResultRestrPos(ResultState *node)
188 {
189         PlanState  *outerPlan = outerPlanState(node);
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 #define RESULT_NSLOTS 1
234
235         /*
236          * tuple table initialization
237          */
238         ExecInitResultTupleSlot(estate, &resstate->ps);
239
240         /*
241          * initialize child expressions
242          */
243         resstate->ps.targetlist = (List *)
244                 ExecInitExpr((Expr *) node->plan.targetlist,
245                                          (PlanState *) resstate);
246         resstate->ps.qual = (List *)
247                 ExecInitExpr((Expr *) node->plan.qual,
248                                          (PlanState *) resstate);
249         resstate->resconstantqual = ExecInitExpr((Expr *) node->resconstantqual,
250                                                                                          (PlanState *) resstate);
251
252         /*
253          * initialize child nodes
254          */
255         outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags);
256
257         /*
258          * we don't use inner plan
259          */
260         Assert(innerPlan(node) == NULL);
261
262         /*
263          * initialize tuple type and projection info
264          */
265         ExecAssignResultTypeFromTL(&resstate->ps);
266         ExecAssignProjectionInfo(&resstate->ps, NULL);
267
268         return resstate;
269 }
270
271 int
272 ExecCountSlotsResult(Result *node)
273 {
274         return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS;
275 }
276
277 /* ----------------------------------------------------------------
278  *              ExecEndResult
279  *
280  *              frees up storage allocated through C routines
281  * ----------------------------------------------------------------
282  */
283 void
284 ExecEndResult(ResultState *node)
285 {
286         /*
287          * Free the exprcontext
288          */
289         ExecFreeExprContext(&node->ps);
290
291         /*
292          * clean out the tuple table
293          */
294         ExecClearTuple(node->ps.ps_ResultTupleSlot);
295
296         /*
297          * shut down subplans
298          */
299         ExecEndNode(outerPlanState(node));
300 }
301
302 void
303 ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
304 {
305         node->rs_done = false;
306         node->ps.ps_TupFromTlist = false;
307         node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
308
309         /*
310          * If chgParam of subnode is not null then plan will be re-scanned by
311          * first ExecProcNode.  However, if caller is passing us an exprCtxt then
312          * forcibly rescan the subnode now, so that we can pass the exprCtxt down
313          * to the subnode (needed for gated indexscan).
314          */
315         if (node->ps.lefttree &&
316                 (node->ps.lefttree->chgParam == NULL || exprCtxt != NULL))
317                 ExecReScan(node->ps.lefttree, exprCtxt);
318 }