1 /*-------------------------------------------------------------------------
4 * support for constant nodes needing special code.
8 * Result nodes are used in queries where no relations are scanned.
9 * Examples of such queries are:
13 * append emp (name = "mike", salary = 15000)
15 * Result nodes are also used to optimise queries with constant
16 * qualifications (ie, quals that do not depend on the scanned data),
19 * retrieve (emp.all) where 2 > 1
21 * In this case, the plan generated is
23 * Result (with 2 > 1 qual)
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.
33 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
34 * Portions Copyright (c) 1994, Regents of the University of California
37 * $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.28 2004/08/29 04:12:31 momjian Exp $
39 *-------------------------------------------------------------------------
44 #include "executor/executor.h"
45 #include "executor/nodeResult.h"
46 #include "utils/memutils.h"
49 /* ----------------------------------------------------------------
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
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 * ----------------------------------------------------------------
63 ExecResult(ResultState *node)
65 TupleTableSlot *outerTupleSlot;
66 TupleTableSlot *resultSlot;
68 ExprContext *econtext;
71 econtext = node->ps.ps_ExprContext;
74 * check constant qualifications like (2 > 1), if not already done
76 if (node->rs_checkqual)
78 bool qualResult = ExecQual((List *) node->resconstantqual,
82 node->rs_checkqual = false;
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.
95 if (node->ps.ps_TupFromTlist)
97 resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
98 if (isDone == ExprMultipleResult)
100 /* Done with that source tuple... */
101 node->ps.ps_TupFromTlist = false;
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.
109 ResetExprContext(econtext);
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
117 while (!node->rs_done)
119 outerPlan = outerPlanState(node);
121 if (outerPlan != NULL)
124 * retrieve tuples from the outer plan until there are no
127 outerTupleSlot = ExecProcNode(outerPlan);
129 if (TupIsNull(outerTupleSlot))
132 node->ps.ps_OuterTupleSlot = outerTupleSlot;
135 * XXX gross hack. use outer tuple as scan tuple for
138 econtext->ecxt_outertuple = outerTupleSlot;
139 econtext->ecxt_scantuple = outerTupleSlot;
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.
147 node->rs_done = true;
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.
155 resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
157 if (isDone != ExprEndResult)
159 node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
167 /* ----------------------------------------------------------------
170 * Creates the run-time state information for the result node
171 * produced by the planner and initailizes outer relations
173 * ----------------------------------------------------------------
176 ExecInitResult(Result *node, EState *estate)
178 ResultState *resstate;
181 * create state structure
183 resstate = makeNode(ResultState);
184 resstate->ps.plan = (Plan *) node;
185 resstate->ps.state = estate;
187 resstate->rs_done = false;
188 resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
191 * Miscellaneous initialization
193 * create expression context for node
195 ExecAssignExprContext(estate, &resstate->ps);
197 #define RESULT_NSLOTS 1
200 * tuple table initialization
202 ExecInitResultTupleSlot(estate, &resstate->ps);
205 * initialize child expressions
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);
217 * initialize child nodes
219 outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate);
222 * we don't use inner plan
224 Assert(innerPlan(node) == NULL);
227 * initialize tuple type and projection info
229 ExecAssignResultTypeFromTL(&resstate->ps);
230 ExecAssignProjectionInfo(&resstate->ps);
236 ExecCountSlotsResult(Result *node)
238 return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS;
241 /* ----------------------------------------------------------------
244 * frees up storage allocated through C routines
245 * ----------------------------------------------------------------
248 ExecEndResult(ResultState *node)
251 * Free the exprcontext
253 ExecFreeExprContext(&node->ps);
256 * clean out the tuple table
258 ExecClearTuple(node->ps.ps_ResultTupleSlot);
263 ExecEndNode(outerPlanState(node));
267 ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
269 node->rs_done = false;
270 node->ps.ps_TupFromTlist = false;
271 node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
274 * if chgParam of subnode is not null then plan will be re-scanned by
275 * first ExecProcNode.
277 if (((PlanState *) node)->lefttree &&
278 ((PlanState *) node)->lefttree->chgParam == NULL)
279 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);