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