]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeResult.c
770cc47ccc4f405b80e6f1083e1b35ac6c1c36f7
[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-2000, PostgreSQL, Inc
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.15 2000/07/17 03:04:53 tgl 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         bool            isDone;
71         ProjectionInfo *projInfo;
72
73         /* ----------------
74          *      initialize the result node's state
75          * ----------------
76          */
77         resstate = node->resstate;
78         econtext = resstate->cstate.cs_ExprContext;
79
80         /* ----------------
81          *      Reset per-tuple memory context to free any expression evaluation
82          *      storage allocated in the previous tuple cycle.
83          * ----------------
84          */
85         ResetExprContext(econtext);
86
87         /* ----------------
88          *       check constant qualifications like (2 > 1), if not already done
89          * ----------------
90          */
91         if (resstate->rs_checkqual)
92         {
93                 bool            qualResult = ExecQual((List *) node->resconstantqual,
94                                                                                   econtext,
95                                                                                   false);
96
97                 resstate->rs_checkqual = false;
98                 if (qualResult == false)
99                 {
100                         resstate->rs_done = true;
101                         return NULL;
102                 }
103         }
104
105         /* ----------------
106          *      Check to see if we're still projecting out tuples from a previous
107          *      scan tuple (because there is a function-returning-set in the
108          *      projection expressions).  If so, try to project another one.
109          * ----------------
110          */
111         if (resstate->cstate.cs_TupFromTlist)
112         {
113                 resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
114                 if (!isDone)
115                         return resultSlot;
116                 /* Done with that source tuple... */
117                 resstate->cstate.cs_TupFromTlist = false;
118         }
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         if (!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                  * ----------------
164                  */
165                 projInfo = resstate->cstate.cs_ProjInfo;
166                 resultSlot = ExecProject(projInfo, &isDone);
167                 resstate->cstate.cs_TupFromTlist = !isDone;
168                 return resultSlot;
169         }
170
171         return NULL;
172 }
173
174 /* ----------------------------------------------------------------
175  *              ExecInitResult
176  *
177  *              Creates the run-time state information for the result node
178  *              produced by the planner and initailizes outer relations
179  *              (child nodes).
180  * ----------------------------------------------------------------
181  */
182 bool
183 ExecInitResult(Result *node, EState *estate, Plan *parent)
184 {
185         ResultState *resstate;
186
187         /* ----------------
188          *      assign execution state to node
189          * ----------------
190          */
191         node->plan.state = estate;
192
193         /* ----------------
194          *      create new ResultState for node
195          * ----------------
196          */
197         resstate = makeNode(ResultState);
198         resstate->rs_done = false;
199         resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
200         node->resstate = resstate;
201
202         /* ----------------
203          *      Miscellaneous initialization
204          *
205          *               +      create expression context for node
206          * ----------------
207          */
208         ExecAssignExprContext(estate, &resstate->cstate);
209
210 #define RESULT_NSLOTS 1
211         /* ----------------
212          *      tuple table initialization
213          * ----------------
214          */
215         ExecInitResultTupleSlot(estate, &resstate->cstate);
216
217         /* ----------------
218          *      then initialize children
219          * ----------------
220          */
221         ExecInitNode(outerPlan(node), estate, (Plan *) node);
222
223         /*
224          * we don't use inner plan
225          */
226         Assert(innerPlan(node) == NULL);
227
228         /* ----------------
229          *      initialize tuple type and projection info
230          * ----------------
231          */
232         ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
233         ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
234
235         return TRUE;
236 }
237
238 int
239 ExecCountSlotsResult(Result *node)
240 {
241         return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS;
242 }
243
244 /* ----------------------------------------------------------------
245  *              ExecEndResult
246  *
247  *              frees up storage allocated through C routines
248  * ----------------------------------------------------------------
249  */
250 void
251 ExecEndResult(Result *node)
252 {
253         ResultState *resstate;
254
255         resstate = node->resstate;
256
257         /* ----------------
258          *      Free the projection info
259          *
260          *      Note: we don't ExecFreeResultType(resstate)
261          *                because the rule manager depends on the tupType
262          *                returned by ExecMain().  So for now, this
263          *                is freed at end-transaction time.  -cim 6/2/91
264          * ----------------
265          */
266         ExecFreeProjectionInfo(&resstate->cstate);
267         ExecFreeExprContext(&resstate->cstate);
268
269         /* ----------------
270          *      shut down subplans
271          * ----------------
272          */
273         ExecEndNode(outerPlan(node), (Plan *) node);
274
275         /* ----------------
276          *      clean out the tuple table
277          * ----------------
278          */
279         ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
280         pfree(resstate);
281         node->resstate = NULL;          /* XXX - new for us - er1p */
282 }
283
284 void
285 ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
286 {
287         ResultState *resstate = node->resstate;
288
289         resstate->rs_done = false;
290         resstate->cstate.cs_TupFromTlist = false;
291         resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
292
293         /*
294          * if chgParam of subnode is not null then plan will be re-scanned by
295          * first ExecProcNode.
296          */
297         if (((Plan *) node)->lefttree &&
298                 ((Plan *) node)->lefttree->chgParam == NULL)
299                 ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
300 }