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-2019, 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 | #include "utils/memutils.h" |
52 | |
53 | |
54 | /* ---------------------------------------------------------------- |
55 | * ExecResult(node) |
56 | * |
57 | * returns the tuples from the outer plan which satisfy the |
58 | * qualification clause. Since result nodes with right |
59 | * subtrees are never planned, we ignore the right subtree |
60 | * entirely (for now).. -cim 10/7/89 |
61 | * |
62 | * The qualification containing only constant clauses are |
63 | * checked first before any processing is done. It always returns |
64 | * 'nil' if the constant qualification is not satisfied. |
65 | * ---------------------------------------------------------------- |
66 | */ |
67 | static TupleTableSlot * |
68 | ExecResult(PlanState *pstate) |
69 | { |
70 | ResultState *node = castNode(ResultState, pstate); |
71 | TupleTableSlot *outerTupleSlot; |
72 | PlanState *outerPlan; |
73 | ExprContext *econtext; |
74 | |
75 | CHECK_FOR_INTERRUPTS(); |
76 | |
77 | econtext = node->ps.ps_ExprContext; |
78 | |
79 | /* |
80 | * check constant qualifications like (2 > 1), if not already done |
81 | */ |
82 | if (node->rs_checkqual) |
83 | { |
84 | bool qualResult = ExecQual(node->resconstantqual, econtext); |
85 | |
86 | node->rs_checkqual = false; |
87 | if (!qualResult) |
88 | { |
89 | node->rs_done = true; |
90 | return NULL; |
91 | } |
92 | } |
93 | |
94 | /* |
95 | * Reset per-tuple memory context to free any expression evaluation |
96 | * storage allocated in the previous tuple cycle. |
97 | */ |
98 | ResetExprContext(econtext); |
99 | |
100 | /* |
101 | * if rs_done is true then it means that we were asked to return a |
102 | * constant tuple and we already did the last time ExecResult() was |
103 | * called, OR that we failed the constant qual check. Either way, now we |
104 | * are through. |
105 | */ |
106 | while (!node->rs_done) |
107 | { |
108 | outerPlan = outerPlanState(node); |
109 | |
110 | if (outerPlan != NULL) |
111 | { |
112 | /* |
113 | * retrieve tuples from the outer plan until there are no more. |
114 | */ |
115 | outerTupleSlot = ExecProcNode(outerPlan); |
116 | |
117 | if (TupIsNull(outerTupleSlot)) |
118 | return NULL; |
119 | |
120 | /* |
121 | * prepare to compute projection expressions, which will expect to |
122 | * access the input tuples as varno OUTER. |
123 | */ |
124 | econtext->ecxt_outertuple = outerTupleSlot; |
125 | } |
126 | else |
127 | { |
128 | /* |
129 | * if we don't have an outer plan, then we are just generating the |
130 | * results from a constant target list. Do it only once. |
131 | */ |
132 | node->rs_done = true; |
133 | } |
134 | |
135 | /* form the result tuple using ExecProject(), and return it */ |
136 | return ExecProject(node->ps.ps_ProjInfo); |
137 | } |
138 | |
139 | return NULL; |
140 | } |
141 | |
142 | /* ---------------------------------------------------------------- |
143 | * ExecResultMarkPos |
144 | * ---------------------------------------------------------------- |
145 | */ |
146 | void |
147 | ExecResultMarkPos(ResultState *node) |
148 | { |
149 | PlanState *outerPlan = outerPlanState(node); |
150 | |
151 | if (outerPlan != NULL) |
152 | ExecMarkPos(outerPlan); |
153 | else |
154 | elog(DEBUG2, "Result nodes do not support mark/restore" ); |
155 | } |
156 | |
157 | /* ---------------------------------------------------------------- |
158 | * ExecResultRestrPos |
159 | * ---------------------------------------------------------------- |
160 | */ |
161 | void |
162 | ExecResultRestrPos(ResultState *node) |
163 | { |
164 | PlanState *outerPlan = outerPlanState(node); |
165 | |
166 | if (outerPlan != NULL) |
167 | ExecRestrPos(outerPlan); |
168 | else |
169 | elog(ERROR, "Result nodes do not support mark/restore" ); |
170 | } |
171 | |
172 | /* ---------------------------------------------------------------- |
173 | * ExecInitResult |
174 | * |
175 | * Creates the run-time state information for the result node |
176 | * produced by the planner and initializes outer relations |
177 | * (child nodes). |
178 | * ---------------------------------------------------------------- |
179 | */ |
180 | ResultState * |
181 | ExecInitResult(Result *node, EState *estate, int eflags) |
182 | { |
183 | ResultState *resstate; |
184 | |
185 | /* check for unsupported flags */ |
186 | Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) || |
187 | outerPlan(node) != NULL); |
188 | |
189 | /* |
190 | * create state structure |
191 | */ |
192 | resstate = makeNode(ResultState); |
193 | resstate->ps.plan = (Plan *) node; |
194 | resstate->ps.state = estate; |
195 | resstate->ps.ExecProcNode = ExecResult; |
196 | |
197 | resstate->rs_done = false; |
198 | resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true; |
199 | |
200 | /* |
201 | * Miscellaneous initialization |
202 | * |
203 | * create expression context for node |
204 | */ |
205 | ExecAssignExprContext(estate, &resstate->ps); |
206 | |
207 | /* |
208 | * initialize child nodes |
209 | */ |
210 | outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags); |
211 | |
212 | /* |
213 | * we don't use inner plan |
214 | */ |
215 | Assert(innerPlan(node) == NULL); |
216 | |
217 | /* |
218 | * Initialize result slot, type and projection. |
219 | */ |
220 | ExecInitResultTupleSlotTL(&resstate->ps, &TTSOpsVirtual); |
221 | ExecAssignProjectionInfo(&resstate->ps, NULL); |
222 | |
223 | /* |
224 | * initialize child expressions |
225 | */ |
226 | resstate->ps.qual = |
227 | ExecInitQual(node->plan.qual, (PlanState *) resstate); |
228 | resstate->resconstantqual = |
229 | ExecInitQual((List *) node->resconstantqual, (PlanState *) resstate); |
230 | |
231 | return resstate; |
232 | } |
233 | |
234 | /* ---------------------------------------------------------------- |
235 | * ExecEndResult |
236 | * |
237 | * frees up storage allocated through C routines |
238 | * ---------------------------------------------------------------- |
239 | */ |
240 | void |
241 | ExecEndResult(ResultState *node) |
242 | { |
243 | /* |
244 | * Free the exprcontext |
245 | */ |
246 | ExecFreeExprContext(&node->ps); |
247 | |
248 | /* |
249 | * clean out the tuple table |
250 | */ |
251 | ExecClearTuple(node->ps.ps_ResultTupleSlot); |
252 | |
253 | /* |
254 | * shut down subplans |
255 | */ |
256 | ExecEndNode(outerPlanState(node)); |
257 | } |
258 | |
259 | void |
260 | ExecReScanResult(ResultState *node) |
261 | { |
262 | node->rs_done = false; |
263 | node->rs_checkqual = (node->resconstantqual == NULL) ? false : true; |
264 | |
265 | /* |
266 | * If chgParam of subnode is not null then plan will be re-scanned by |
267 | * first ExecProcNode. |
268 | */ |
269 | if (node->ps.lefttree && |
270 | node->ps.lefttree->chgParam == NULL) |
271 | ExecReScan(node->ps.lefttree); |
272 | } |
273 | |