]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeResult.c
pgindent run. Make it all clean.
[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-2001, PostgreSQL Global Development Group
34  * Portions Copyright (c) 1994, Regents of the University of California
35  *
36  * IDENTIFICATION
37  *        $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.18 2001/03/22 03:59:29 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(Result *node)
64 {
65         ResultState *resstate;
66         TupleTableSlot *outerTupleSlot;
67         TupleTableSlot *resultSlot;
68         Plan       *outerPlan;
69         ExprContext *econtext;
70         ExprDoneCond isDone;
71
72         /* ----------------
73          *      initialize the result node's state
74          * ----------------
75          */
76         resstate = node->resstate;
77         econtext = resstate->cstate.cs_ExprContext;
78
79         /* ----------------
80          *       check constant qualifications like (2 > 1), if not already done
81          * ----------------
82          */
83         if (resstate->rs_checkqual)
84         {
85                 bool            qualResult = ExecQual((List *) node->resconstantqual,
86                                                                                   econtext,
87                                                                                   false);
88
89                 resstate->rs_checkqual = false;
90                 if (qualResult == false)
91                 {
92                         resstate->rs_done = true;
93                         return NULL;
94                 }
95         }
96
97         /* ----------------
98          *      Check to see if we're still projecting out tuples from a previous
99          *      scan tuple (because there is a function-returning-set in the
100          *      projection expressions).  If so, try to project another one.
101          * ----------------
102          */
103         if (resstate->cstate.cs_TupFromTlist)
104         {
105                 resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
106                 if (isDone == ExprMultipleResult)
107                         return resultSlot;
108                 /* Done with that source tuple... */
109                 resstate->cstate.cs_TupFromTlist = false;
110         }
111
112         /* ----------------
113          *      Reset per-tuple memory context to free any expression evaluation
114          *      storage allocated in the previous tuple cycle.  Note this can't
115          *      happen until we're done projecting out tuples from a scan tuple.
116          * ----------------
117          */
118         ResetExprContext(econtext);
119
120         /* ----------------
121          *      if rs_done is true then it means that we were asked to return
122          *      a constant tuple and we already did the last time ExecResult()
123          *      was called, OR that we failed the constant qual check.
124          *      Either way, now we are through.
125          * ----------------
126          */
127         while (!resstate->rs_done)
128         {
129                 outerPlan = outerPlan(node);
130
131                 if (outerPlan != NULL)
132                 {
133                         /* ----------------
134                          *      retrieve tuples from the outer plan until there are no more.
135                          * ----------------
136                          */
137                         outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
138
139                         if (TupIsNull(outerTupleSlot))
140                                 return NULL;
141
142                         resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
143
144                         /* ----------------
145                          *       XXX gross hack. use outer tuple as scan tuple for projection
146                          * ----------------
147                          */
148                         econtext->ecxt_outertuple = outerTupleSlot;
149                         econtext->ecxt_scantuple = outerTupleSlot;
150                 }
151                 else
152                 {
153                         /* ----------------
154                          *      if we don't have an outer plan, then we are just generating
155                          *      the results from a constant target list.  Do it only once.
156                          * ----------------
157                          */
158                         resstate->rs_done = true;
159                 }
160
161                 /* ----------------
162                  *       form the result tuple using ExecProject(), and return it
163                  *       --- unless the projection produces an empty set, in which case
164                  *       we must loop back to see if there are more outerPlan tuples.
165                  * ----------------
166                  */
167                 resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
168
169                 if (isDone != ExprEndResult)
170                 {
171                         resstate->cstate.cs_TupFromTlist = (isDone == ExprMultipleResult);
172                         return resultSlot;
173                 }
174         }
175
176         return NULL;
177 }
178
179 /* ----------------------------------------------------------------
180  *              ExecInitResult
181  *
182  *              Creates the run-time state information for the result node
183  *              produced by the planner and initailizes outer relations
184  *              (child nodes).
185  * ----------------------------------------------------------------
186  */
187 bool
188 ExecInitResult(Result *node, EState *estate, Plan *parent)
189 {
190         ResultState *resstate;
191
192         /* ----------------
193          *      assign execution state to node
194          * ----------------
195          */
196         node->plan.state = estate;
197
198         /* ----------------
199          *      create new ResultState for node
200          * ----------------
201          */
202         resstate = makeNode(ResultState);
203         resstate->rs_done = false;
204         resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
205         node->resstate = resstate;
206
207         /* ----------------
208          *      Miscellaneous initialization
209          *
210          *               +      create expression context for node
211          * ----------------
212          */
213         ExecAssignExprContext(estate, &resstate->cstate);
214
215 #define RESULT_NSLOTS 1
216         /* ----------------
217          *      tuple table initialization
218          * ----------------
219          */
220         ExecInitResultTupleSlot(estate, &resstate->cstate);
221
222         /* ----------------
223          *      then initialize children
224          * ----------------
225          */
226         ExecInitNode(outerPlan(node), estate, (Plan *) node);
227
228         /*
229          * we don't use inner plan
230          */
231         Assert(innerPlan(node) == NULL);
232
233         /* ----------------
234          *      initialize tuple type and projection info
235          * ----------------
236          */
237         ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
238         ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
239
240         return TRUE;
241 }
242
243 int
244 ExecCountSlotsResult(Result *node)
245 {
246         return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS;
247 }
248
249 /* ----------------------------------------------------------------
250  *              ExecEndResult
251  *
252  *              frees up storage allocated through C routines
253  * ----------------------------------------------------------------
254  */
255 void
256 ExecEndResult(Result *node)
257 {
258         ResultState *resstate;
259
260         resstate = node->resstate;
261
262         /* ----------------
263          *      Free the projection info
264          *
265          *      Note: we don't ExecFreeResultType(resstate)
266          *                because the rule manager depends on the tupType
267          *                returned by ExecMain().  So for now, this
268          *                is freed at end-transaction time.  -cim 6/2/91
269          * ----------------
270          */
271         ExecFreeProjectionInfo(&resstate->cstate);
272         ExecFreeExprContext(&resstate->cstate);
273
274         /* ----------------
275          *      shut down subplans
276          * ----------------
277          */
278         ExecEndNode(outerPlan(node), (Plan *) node);
279
280         /* ----------------
281          *      clean out the tuple table
282          * ----------------
283          */
284         ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
285         pfree(resstate);
286         node->resstate = NULL;          /* XXX - new for us - er1p */
287 }
288
289 void
290 ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
291 {
292         ResultState *resstate = node->resstate;
293
294         resstate->rs_done = false;
295         resstate->cstate.cs_TupFromTlist = false;
296         resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
297
298         /*
299          * if chgParam of subnode is not null then plan will be re-scanned by
300          * first ExecProcNode.
301          */
302         if (((Plan *) node)->lefttree &&
303                 ((Plan *) node)->lefttree->chgParam == NULL)
304                 ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
305 }