Branch data Line data Source code
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-2026, PostgreSQL Global Development Group
38 : : * Portions Copyright (c) 1994, Regents of the University of California
39 : : *
40 : : * IDENTIFICATION
41 : : * src/backend/executor/nodeResult.c
42 : : *
43 : : *-------------------------------------------------------------------------
44 : : */
45 : :
46 : : #include "postgres.h"
47 : :
48 : : #include "executor/executor.h"
49 : : #include "executor/nodeResult.h"
50 : : #include "miscadmin.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 : : static TupleTableSlot *
67 : 91366 : ExecResult(PlanState *pstate)
68 : : {
69 : 91366 : ResultState *node = castNode(ResultState, pstate);
70 : 91366 : TupleTableSlot *outerTupleSlot;
71 : 91366 : PlanState *outerPlan;
72 : 91366 : ExprContext *econtext;
73 : :
74 [ + + ]: 91366 : CHECK_FOR_INTERRUPTS();
75 : :
76 : 91366 : econtext = node->ps.ps_ExprContext;
77 : :
78 : : /*
79 : : * check constant qualifications like (2 > 1), if not already done
80 : : */
81 [ + + ]: 91366 : if (node->rs_checkqual)
82 : : {
83 : 2704 : bool qualResult = ExecQual(node->resconstantqual, econtext);
84 : :
85 : 2704 : node->rs_checkqual = false;
86 [ + + ]: 2704 : if (!qualResult)
87 : : {
88 : 1538 : node->rs_done = true;
89 : 1538 : return NULL;
90 : : }
91 [ + + ]: 2704 : }
92 : :
93 : : /*
94 : : * Reset per-tuple memory context to free any expression evaluation
95 : : * storage allocated in the previous tuple cycle.
96 : : */
97 : 89828 : ResetExprContext(econtext);
98 : :
99 : : /*
100 : : * if rs_done is true then it means that we were asked to return a
101 : : * constant tuple and we already did the last time ExecResult() was
102 : : * called, OR that we failed the constant qual check. Either way, now we
103 : : * are through.
104 : : */
105 [ + + ]: 89828 : if (!node->rs_done)
106 : : {
107 : 66527 : outerPlan = outerPlanState(node);
108 : :
109 [ + + ]: 66527 : if (outerPlan != NULL)
110 : : {
111 : : /*
112 : : * retrieve tuples from the outer plan until there are no more.
113 : : */
114 : 36476 : outerTupleSlot = ExecProcNode(outerPlan);
115 : :
116 [ + + + + ]: 36476 : if (TupIsNull(outerTupleSlot))
117 : 1256 : return NULL;
118 : :
119 : : /*
120 : : * prepare to compute projection expressions, which will expect to
121 : : * access the input tuples as varno OUTER.
122 : : */
123 : 35220 : econtext->ecxt_outertuple = outerTupleSlot;
124 : 35220 : }
125 : : else
126 : : {
127 : : /*
128 : : * if we don't have an outer plan, then we are just generating the
129 : : * results from a constant target list. Do it only once.
130 : : */
131 : 30051 : node->rs_done = true;
132 : : }
133 : :
134 : : /* form the result tuple using ExecProject(), and return it */
135 : 65271 : return ExecProject(node->ps.ps_ProjInfo);
136 : : }
137 : :
138 : 23301 : return NULL;
139 : 91366 : }
140 : :
141 : : /* ----------------------------------------------------------------
142 : : * ExecResultMarkPos
143 : : * ----------------------------------------------------------------
144 : : */
145 : : void
146 : 0 : ExecResultMarkPos(ResultState *node)
147 : : {
148 : 0 : PlanState *outerPlan = outerPlanState(node);
149 : :
150 [ # # ]: 0 : if (outerPlan != NULL)
151 : 0 : ExecMarkPos(outerPlan);
152 : : else
153 [ # # # # ]: 0 : elog(DEBUG2, "Result nodes do not support mark/restore");
154 : 0 : }
155 : :
156 : : /* ----------------------------------------------------------------
157 : : * ExecResultRestrPos
158 : : * ----------------------------------------------------------------
159 : : */
160 : : void
161 : 0 : ExecResultRestrPos(ResultState *node)
162 : : {
163 : 0 : PlanState *outerPlan = outerPlanState(node);
164 : :
165 [ # # ]: 0 : if (outerPlan != NULL)
166 : 0 : ExecRestrPos(outerPlan);
167 : : else
168 [ # # # # ]: 0 : elog(ERROR, "Result nodes do not support mark/restore");
169 : 0 : }
170 : :
171 : : /* ----------------------------------------------------------------
172 : : * ExecInitResult
173 : : *
174 : : * Creates the run-time state information for the result node
175 : : * produced by the planner and initializes outer relations
176 : : * (child nodes).
177 : : * ----------------------------------------------------------------
178 : : */
179 : : ResultState *
180 : 24618 : ExecInitResult(Result *node, EState *estate, int eflags)
181 : : {
182 : 24618 : ResultState *resstate;
183 : :
184 : : /* check for unsupported flags */
185 [ - + # # ]: 24618 : Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) ||
186 : : outerPlan(node) != NULL);
187 : :
188 : : /*
189 : : * create state structure
190 : : */
191 : 24618 : resstate = makeNode(ResultState);
192 : 24618 : resstate->ps.plan = (Plan *) node;
193 : 24618 : resstate->ps.state = estate;
194 : 24618 : resstate->ps.ExecProcNode = ExecResult;
195 : :
196 : 24618 : resstate->rs_done = false;
197 : 24618 : resstate->rs_checkqual = (node->resconstantqual != NULL);
198 : :
199 : : /*
200 : : * Miscellaneous initialization
201 : : *
202 : : * create expression context for node
203 : : */
204 : 24618 : ExecAssignExprContext(estate, &resstate->ps);
205 : :
206 : : /*
207 : : * initialize child nodes
208 : : */
209 : 24618 : outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags);
210 : :
211 : : /*
212 : : * we don't use inner plan
213 : : */
214 [ + - ]: 24618 : Assert(innerPlan(node) == NULL);
215 : :
216 : : /*
217 : : * Initialize result slot, type and projection.
218 : : */
219 : 24618 : ExecInitResultTupleSlotTL(&resstate->ps, &TTSOpsVirtual);
220 : 24618 : ExecAssignProjectionInfo(&resstate->ps, NULL);
221 : :
222 : : /*
223 : : * initialize child expressions
224 : : */
225 : 24618 : resstate->ps.qual =
226 : 24618 : ExecInitQual(node->plan.qual, (PlanState *) resstate);
227 : 24618 : resstate->resconstantqual =
228 : 24618 : ExecInitQual((List *) node->resconstantqual, (PlanState *) resstate);
229 : :
230 : 49236 : return resstate;
231 : 24618 : }
232 : :
233 : : /* ----------------------------------------------------------------
234 : : * ExecEndResult
235 : : *
236 : : * frees up storage allocated through C routines
237 : : * ----------------------------------------------------------------
238 : : */
239 : : void
240 : 19535 : ExecEndResult(ResultState *node)
241 : : {
242 : : /*
243 : : * shut down subplans
244 : : */
245 : 19535 : ExecEndNode(outerPlanState(node));
246 : 19535 : }
247 : :
248 : : void
249 : 10452 : ExecReScanResult(ResultState *node)
250 : : {
251 : 10452 : PlanState *outerPlan = outerPlanState(node);
252 : :
253 : 10452 : node->rs_done = false;
254 : 10452 : node->rs_checkqual = (node->resconstantqual != NULL);
255 : :
256 : : /*
257 : : * If chgParam of subnode is not null then plan will be re-scanned by
258 : : * first ExecProcNode.
259 : : */
260 [ + + + + ]: 10452 : if (outerPlan && outerPlan->chgParam == NULL)
261 : 19 : ExecReScan(outerPlan);
262 : 10452 : }
|