]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeResult.c
Repair bug #2839: the various ExecReScan functions need to reset
[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-2006, 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.35 2006/12/26 19:26:45 tgl 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                         node->ps.ps_OuterTupleSlot = outerTupleSlot;
136
137                         /*
138                          * XXX gross hack. use outer tuple as scan tuple for projection
139                          */
140                         econtext->ecxt_outertuple = outerTupleSlot;
141                         econtext->ecxt_scantuple = outerTupleSlot;
142                 }
143                 else
144                 {
145                         /*
146                          * if we don't have an outer plan, then we are just generating the
147                          * results from a constant target list.  Do it only once.
148                          */
149                         node->rs_done = true;
150                 }
151
152                 /*
153                  * form the result tuple using ExecProject(), and return it --- unless
154                  * the projection produces an empty set, in which case we must loop
155                  * back to see if there are more outerPlan tuples.
156                  */
157                 resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
158
159                 if (isDone != ExprEndResult)
160                 {
161                         node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
162                         return resultSlot;
163                 }
164         }
165
166         return NULL;
167 }
168
169 /* ----------------------------------------------------------------
170  *              ExecInitResult
171  *
172  *              Creates the run-time state information for the result node
173  *              produced by the planner and initializes outer relations
174  *              (child nodes).
175  * ----------------------------------------------------------------
176  */
177 ResultState *
178 ExecInitResult(Result *node, EState *estate, int eflags)
179 {
180         ResultState *resstate;
181
182         /* check for unsupported flags */
183         Assert(!(eflags & EXEC_FLAG_MARK));
184         Assert(!(eflags & EXEC_FLAG_BACKWARD) || outerPlan(node) != NULL);
185
186         /*
187          * create state structure
188          */
189         resstate = makeNode(ResultState);
190         resstate->ps.plan = (Plan *) node;
191         resstate->ps.state = estate;
192
193         resstate->rs_done = false;
194         resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
195
196         /*
197          * Miscellaneous initialization
198          *
199          * create expression context for node
200          */
201         ExecAssignExprContext(estate, &resstate->ps);
202
203         resstate->ps.ps_TupFromTlist = false;
204
205 #define RESULT_NSLOTS 1
206
207         /*
208          * tuple table initialization
209          */
210         ExecInitResultTupleSlot(estate, &resstate->ps);
211
212         /*
213          * initialize child expressions
214          */
215         resstate->ps.targetlist = (List *)
216                 ExecInitExpr((Expr *) node->plan.targetlist,
217                                          (PlanState *) resstate);
218         resstate->ps.qual = (List *)
219                 ExecInitExpr((Expr *) node->plan.qual,
220                                          (PlanState *) resstate);
221         resstate->resconstantqual = ExecInitExpr((Expr *) node->resconstantqual,
222                                                                                          (PlanState *) resstate);
223
224         /*
225          * initialize child nodes
226          */
227         outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags);
228
229         /*
230          * we don't use inner plan
231          */
232         Assert(innerPlan(node) == NULL);
233
234         /*
235          * initialize tuple type and projection info
236          */
237         ExecAssignResultTypeFromTL(&resstate->ps);
238         ExecAssignProjectionInfo(&resstate->ps);
239
240         return resstate;
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(ResultState *node)
257 {
258         /*
259          * Free the exprcontext
260          */
261         ExecFreeExprContext(&node->ps);
262
263         /*
264          * clean out the tuple table
265          */
266         ExecClearTuple(node->ps.ps_ResultTupleSlot);
267
268         /*
269          * shut down subplans
270          */
271         ExecEndNode(outerPlanState(node));
272 }
273
274 void
275 ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
276 {
277         node->rs_done = false;
278         node->ps.ps_TupFromTlist = false;
279         node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
280
281         /*
282          * if chgParam of subnode is not null then plan will be re-scanned by
283          * first ExecProcNode.
284          */
285         if (((PlanState *) node)->lefttree &&
286                 ((PlanState *) node)->lefttree->chgParam == NULL)
287                 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
288 }