]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeResult.c
Update some comments to use SQL examples rather than QUEL. From Simon
[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  *              Result nodes are also used to optimise queries with constant
14  *              qualifications (ie, quals that do not depend on the scanned data),
15  *              such as:
16  *
17  *                              select * from emp where 2 > 1
18  *
19  *              In this case, the plan generated is
20  *
21  *                                              Result  (with 2 > 1 qual)
22  *                                              /
23  *                                 SeqScan (emp.all)
24  *
25  *              At runtime, the Result node evaluates the constant qual once,
26  *              which is shown by EXPLAIN as a One-Time Filter.  If it's
27  *              false, we can return an empty result set without running the
28  *              controlled plan at all.  If it's true, we run the controlled
29  *              plan normally and pass back the results.
30  *
31  *
32  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
33  * Portions Copyright (c) 1994, Regents of the University of California
34  *
35  * IDENTIFICATION
36  *        $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.30 2005/04/24 11:46:21 neilc Exp $
37  *
38  *-------------------------------------------------------------------------
39  */
40
41 #include "postgres.h"
42
43 #include "executor/executor.h"
44 #include "executor/nodeResult.h"
45 #include "utils/memutils.h"
46
47
48 /* ----------------------------------------------------------------
49  *              ExecResult(node)
50  *
51  *              returns the tuples from the outer plan which satisfy the
52  *              qualification clause.  Since result nodes with right
53  *              subtrees are never planned, we ignore the right subtree
54  *              entirely (for now).. -cim 10/7/89
55  *
56  *              The qualification containing only constant clauses are
57  *              checked first before any processing is done. It always returns
58  *              'nil' if the constant qualification is not satisfied.
59  * ----------------------------------------------------------------
60  */
61 TupleTableSlot *
62 ExecResult(ResultState *node)
63 {
64         TupleTableSlot *outerTupleSlot;
65         TupleTableSlot *resultSlot;
66         PlanState  *outerPlan;
67         ExprContext *econtext;
68         ExprDoneCond isDone;
69
70         econtext = node->ps.ps_ExprContext;
71
72         /*
73          * check constant qualifications like (2 > 1), if not already done
74          */
75         if (node->rs_checkqual)
76         {
77                 bool            qualResult = ExecQual((List *) node->resconstantqual,
78                                                                                   econtext,
79                                                                                   false);
80
81                 node->rs_checkqual = false;
82                 if (!qualResult)
83                 {
84                         node->rs_done = true;
85                         return NULL;
86                 }
87         }
88
89         /*
90          * Check to see if we're still projecting out tuples from a previous
91          * scan tuple (because there is a function-returning-set in the
92          * projection expressions).  If so, try to project another one.
93          */
94         if (node->ps.ps_TupFromTlist)
95         {
96                 resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
97                 if (isDone == ExprMultipleResult)
98                         return resultSlot;
99                 /* Done with that source tuple... */
100                 node->ps.ps_TupFromTlist = false;
101         }
102
103         /*
104          * Reset per-tuple memory context to free any expression evaluation
105          * storage allocated in the previous tuple cycle.  Note this can't
106          * happen until we're done projecting out tuples from a scan tuple.
107          */
108         ResetExprContext(econtext);
109
110         /*
111          * if rs_done is true then it means that we were asked to return a
112          * constant tuple and we already did the last time ExecResult() was
113          * called, OR that we failed the constant qual check. Either way, now
114          * we are through.
115          */
116         while (!node->rs_done)
117         {
118                 outerPlan = outerPlanState(node);
119
120                 if (outerPlan != NULL)
121                 {
122                         /*
123                          * retrieve tuples from the outer plan until there are no
124                          * more.
125                          */
126                         outerTupleSlot = ExecProcNode(outerPlan);
127
128                         if (TupIsNull(outerTupleSlot))
129                                 return NULL;
130
131                         node->ps.ps_OuterTupleSlot = outerTupleSlot;
132
133                         /*
134                          * XXX gross hack. use outer tuple as scan tuple for
135                          * projection
136                          */
137                         econtext->ecxt_outertuple = outerTupleSlot;
138                         econtext->ecxt_scantuple = outerTupleSlot;
139                 }
140                 else
141                 {
142                         /*
143                          * if we don't have an outer plan, then we are just generating
144                          * the results from a constant target list.  Do it only once.
145                          */
146                         node->rs_done = true;
147                 }
148
149                 /*
150                  * form the result tuple using ExecProject(), and return it ---
151                  * unless the projection produces an empty set, in which case we
152                  * must loop back to see if there are more outerPlan tuples.
153                  */
154                 resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
155
156                 if (isDone != ExprEndResult)
157                 {
158                         node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
159                         return resultSlot;
160                 }
161         }
162
163         return NULL;
164 }
165
166 /* ----------------------------------------------------------------
167  *              ExecInitResult
168  *
169  *              Creates the run-time state information for the result node
170  *              produced by the planner and initailizes outer relations
171  *              (child nodes).
172  * ----------------------------------------------------------------
173  */
174 ResultState *
175 ExecInitResult(Result *node, EState *estate)
176 {
177         ResultState *resstate;
178
179         /*
180          * create state structure
181          */
182         resstate = makeNode(ResultState);
183         resstate->ps.plan = (Plan *) node;
184         resstate->ps.state = estate;
185
186         resstate->rs_done = false;
187         resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
188
189         /*
190          * Miscellaneous initialization
191          *
192          * create expression context for node
193          */
194         ExecAssignExprContext(estate, &resstate->ps);
195
196 #define RESULT_NSLOTS 1
197
198         /*
199          * tuple table initialization
200          */
201         ExecInitResultTupleSlot(estate, &resstate->ps);
202
203         /*
204          * initialize child expressions
205          */
206         resstate->ps.targetlist = (List *)
207                 ExecInitExpr((Expr *) node->plan.targetlist,
208                                          (PlanState *) resstate);
209         resstate->ps.qual = (List *)
210                 ExecInitExpr((Expr *) node->plan.qual,
211                                          (PlanState *) resstate);
212         resstate->resconstantqual = ExecInitExpr((Expr *) node->resconstantqual,
213                                                                                          (PlanState *) resstate);
214
215         /*
216          * initialize child nodes
217          */
218         outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate);
219
220         /*
221          * we don't use inner plan
222          */
223         Assert(innerPlan(node) == NULL);
224
225         /*
226          * initialize tuple type and projection info
227          */
228         ExecAssignResultTypeFromTL(&resstate->ps);
229         ExecAssignProjectionInfo(&resstate->ps);
230
231         return resstate;
232 }
233
234 int
235 ExecCountSlotsResult(Result *node)
236 {
237         return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS;
238 }
239
240 /* ----------------------------------------------------------------
241  *              ExecEndResult
242  *
243  *              frees up storage allocated through C routines
244  * ----------------------------------------------------------------
245  */
246 void
247 ExecEndResult(ResultState *node)
248 {
249         /*
250          * Free the exprcontext
251          */
252         ExecFreeExprContext(&node->ps);
253
254         /*
255          * clean out the tuple table
256          */
257         ExecClearTuple(node->ps.ps_ResultTupleSlot);
258
259         /*
260          * shut down subplans
261          */
262         ExecEndNode(outerPlanState(node));
263 }
264
265 void
266 ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
267 {
268         node->rs_done = false;
269         node->ps.ps_TupFromTlist = false;
270         node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
271
272         /*
273          * if chgParam of subnode is not null then plan will be re-scanned by
274          * first ExecProcNode.
275          */
276         if (((PlanState *) node)->lefttree &&
277                 ((PlanState *) node)->lefttree->chgParam == NULL)
278                 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
279 }