/Users/deen/code/yugabyte-db/src/postgres/src/backend/executor/nodeValuesscan.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * nodeValuesscan.c |
4 | | * Support routines for scanning Values lists |
5 | | * ("VALUES (...), (...), ..." in rangetable). |
6 | | * |
7 | | * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group |
8 | | * Portions Copyright (c) 1994, Regents of the University of California |
9 | | * |
10 | | * |
11 | | * IDENTIFICATION |
12 | | * src/backend/executor/nodeValuesscan.c |
13 | | * |
14 | | *------------------------------------------------------------------------- |
15 | | */ |
16 | | /* |
17 | | * INTERFACE ROUTINES |
18 | | * ExecValuesScan scans a values list. |
19 | | * ExecValuesNext retrieve next tuple in sequential order. |
20 | | * ExecInitValuesScan creates and initializes a valuesscan node. |
21 | | * ExecEndValuesScan releases any storage allocated. |
22 | | * ExecReScanValuesScan rescans the values list |
23 | | */ |
24 | | #include "postgres.h" |
25 | | |
26 | | #include "executor/executor.h" |
27 | | #include "executor/nodeValuesscan.h" |
28 | | #include "jit/jit.h" |
29 | | #include "utils/expandeddatum.h" |
30 | | |
31 | | |
32 | | static TupleTableSlot *ValuesNext(ValuesScanState *node); |
33 | | |
34 | | |
35 | | /* ---------------------------------------------------------------- |
36 | | * Scan Support |
37 | | * ---------------------------------------------------------------- |
38 | | */ |
39 | | |
40 | | /* ---------------------------------------------------------------- |
41 | | * ValuesNext |
42 | | * |
43 | | * This is a workhorse for ExecValuesScan |
44 | | * ---------------------------------------------------------------- |
45 | | */ |
46 | | static TupleTableSlot * |
47 | | ValuesNext(ValuesScanState *node) |
48 | 125k | { |
49 | 125k | TupleTableSlot *slot; |
50 | 125k | EState *estate; |
51 | 125k | ExprContext *econtext; |
52 | 125k | ScanDirection direction; |
53 | 125k | List *exprlist; |
54 | | |
55 | | /* |
56 | | * get information from the estate and scan state |
57 | | */ |
58 | 125k | estate = node->ss.ps.state; |
59 | 125k | direction = estate->es_direction; |
60 | 125k | slot = node->ss.ss_ScanTupleSlot; |
61 | 125k | econtext = node->rowcontext; |
62 | | |
63 | | /* |
64 | | * Get the next tuple. Return NULL if no more tuples. |
65 | | */ |
66 | 125k | if (ScanDirectionIsForward(direction)) |
67 | 125k | { |
68 | 125k | if (node->curr_idx < node->array_len) |
69 | 125k | node->curr_idx++; |
70 | 125k | if (node->curr_idx < node->array_len) |
71 | 123k | exprlist = node->exprlists[node->curr_idx]; |
72 | 1.45k | else |
73 | 1.45k | exprlist = NIL; |
74 | 125k | } |
75 | 18.4E | else |
76 | 18.4E | { |
77 | 18.4E | if (node->curr_idx >= 0) |
78 | 0 | node->curr_idx--; |
79 | 18.4E | if (node->curr_idx >= 0) |
80 | 0 | exprlist = node->exprlists[node->curr_idx]; |
81 | 18.4E | else |
82 | 18.4E | exprlist = NIL; |
83 | 18.4E | } |
84 | | |
85 | | /* |
86 | | * Always clear the result slot; this is appropriate if we are at the end |
87 | | * of the data, and if we're not, we still need it as the first step of |
88 | | * the store-virtual-tuple protocol. It seems wise to clear the slot |
89 | | * before we reset the context it might have pointers into. |
90 | | */ |
91 | 125k | ExecClearTuple(slot); |
92 | | |
93 | 125k | if (exprlist) |
94 | 123k | { |
95 | 123k | MemoryContext oldContext; |
96 | 123k | List *oldsubplans; |
97 | 123k | List *exprstatelist; |
98 | 123k | Datum *values; |
99 | 123k | bool *isnull; |
100 | 123k | ListCell *lc; |
101 | 123k | int resind; |
102 | 123k | int saved_jit_flags; |
103 | | |
104 | | /* |
105 | | * Get rid of any prior cycle's leftovers. We use ReScanExprContext |
106 | | * not just ResetExprContext because we want any registered shutdown |
107 | | * callbacks to be called. |
108 | | */ |
109 | 123k | ReScanExprContext(econtext); |
110 | | |
111 | | /* |
112 | | * Build the expression eval state in the econtext's per-tuple memory. |
113 | | * This is a tad unusual, but we want to delete the eval state again |
114 | | * when we move to the next row, to avoid growth of memory |
115 | | * requirements over a long values list. |
116 | | */ |
117 | 123k | oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); |
118 | | |
119 | | /* |
120 | | * The expressions might contain SubPlans (this is currently only |
121 | | * possible if there's a sub-select containing a LATERAL reference, |
122 | | * otherwise sub-selects in a VALUES list should be InitPlans). Those |
123 | | * subplans will want to hook themselves into our subPlan list, which |
124 | | * would result in a corrupted list after we delete the eval state. We |
125 | | * can work around this by saving and restoring the subPlan list. |
126 | | * (There's no need for the functionality that would be enabled by |
127 | | * having the list entries, since the SubPlans aren't going to be |
128 | | * re-executed anyway.) |
129 | | */ |
130 | 123k | oldsubplans = node->ss.ps.subPlan; |
131 | 123k | node->ss.ps.subPlan = NIL; |
132 | | |
133 | | /* |
134 | | * As the expressions are only ever used once, disable JIT for them. |
135 | | * This is worthwhile because it's common to insert significant |
136 | | * amounts of data via VALUES(). |
137 | | */ |
138 | 123k | saved_jit_flags = econtext->ecxt_estate->es_jit_flags; |
139 | 123k | econtext->ecxt_estate->es_jit_flags = PGJIT_NONE; |
140 | 123k | exprstatelist = ExecInitExprList(exprlist, &node->ss.ps); |
141 | 123k | econtext->ecxt_estate->es_jit_flags = saved_jit_flags; |
142 | | |
143 | 123k | node->ss.ps.subPlan = oldsubplans; |
144 | | |
145 | | /* parser should have checked all sublists are the same length */ |
146 | 123k | Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts); |
147 | | |
148 | | /* |
149 | | * Compute the expressions and build a virtual result tuple. We |
150 | | * already did ExecClearTuple(slot). |
151 | | */ |
152 | 123k | values = slot->tts_values; |
153 | 123k | isnull = slot->tts_isnull; |
154 | | |
155 | 123k | resind = 0; |
156 | 123k | foreach(lc, exprstatelist) |
157 | 445k | { |
158 | 445k | ExprState *estate = (ExprState *) lfirst(lc); |
159 | 445k | Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor, |
160 | 445k | resind); |
161 | | |
162 | 445k | values[resind] = ExecEvalExpr(estate, |
163 | 445k | econtext, |
164 | 445k | &isnull[resind]); |
165 | | |
166 | | /* |
167 | | * We must force any R/W expanded datums to read-only state, in |
168 | | * case they are multiply referenced in the plan node's output |
169 | | * expressions, or in case we skip the output projection and the |
170 | | * output column is multiply referenced in higher plan nodes. |
171 | | */ |
172 | 445k | values[resind] = MakeExpandedObjectReadOnly(values[resind], |
173 | 445k | isnull[resind], |
174 | 445k | attr->attlen); |
175 | | |
176 | 445k | resind++; |
177 | 445k | } |
178 | | |
179 | 123k | MemoryContextSwitchTo(oldContext); |
180 | | |
181 | | /* |
182 | | * And return the virtual tuple. |
183 | | */ |
184 | 123k | ExecStoreVirtualTuple(slot); |
185 | 123k | } |
186 | | |
187 | 125k | return slot; |
188 | 125k | } |
189 | | |
190 | | /* |
191 | | * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual |
192 | | */ |
193 | | static bool |
194 | | ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot) |
195 | 0 | { |
196 | | /* nothing to check */ |
197 | 0 | return true; |
198 | 0 | } |
199 | | |
200 | | /* ---------------------------------------------------------------- |
201 | | * ExecValuesScan(node) |
202 | | * |
203 | | * Scans the values lists sequentially and returns the next qualifying |
204 | | * tuple. |
205 | | * We call the ExecScan() routine and pass it the appropriate |
206 | | * access method functions. |
207 | | * ---------------------------------------------------------------- |
208 | | */ |
209 | | static TupleTableSlot * |
210 | | ExecValuesScan(PlanState *pstate) |
211 | 124k | { |
212 | 124k | ValuesScanState *node = castNode(ValuesScanState, pstate); |
213 | | |
214 | 124k | return ExecScan(&node->ss, |
215 | 124k | (ExecScanAccessMtd) ValuesNext, |
216 | 124k | (ExecScanRecheckMtd) ValuesRecheck); |
217 | 124k | } |
218 | | |
219 | | /* ---------------------------------------------------------------- |
220 | | * ExecInitValuesScan |
221 | | * ---------------------------------------------------------------- |
222 | | */ |
223 | | ValuesScanState * |
224 | | ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) |
225 | 2.52k | { |
226 | 2.52k | ValuesScanState *scanstate; |
227 | 2.52k | TupleDesc tupdesc; |
228 | 2.52k | ListCell *vtl; |
229 | 2.52k | int i; |
230 | 2.52k | PlanState *planstate; |
231 | | |
232 | | /* |
233 | | * ValuesScan should not have any children. |
234 | | */ |
235 | 2.52k | Assert(outerPlan(node) == NULL); |
236 | 2.52k | Assert(innerPlan(node) == NULL); |
237 | | |
238 | | /* |
239 | | * create new ScanState for node |
240 | | */ |
241 | 2.52k | scanstate = makeNode(ValuesScanState); |
242 | 0 | scanstate->ss.ps.plan = (Plan *) node; |
243 | 2.52k | scanstate->ss.ps.state = estate; |
244 | 2.52k | scanstate->ss.ps.ExecProcNode = ExecValuesScan; |
245 | | |
246 | | /* |
247 | | * Miscellaneous initialization |
248 | | */ |
249 | 2.52k | planstate = &scanstate->ss.ps; |
250 | | |
251 | | /* |
252 | | * Create expression contexts. We need two, one for per-sublist |
253 | | * processing and one for execScan.c to use for quals and projections. We |
254 | | * cheat a little by using ExecAssignExprContext() to build both. |
255 | | */ |
256 | 2.52k | ExecAssignExprContext(estate, planstate); |
257 | 2.52k | scanstate->rowcontext = planstate->ps_ExprContext; |
258 | 2.52k | ExecAssignExprContext(estate, planstate); |
259 | | |
260 | | /* |
261 | | * Get info about values list, initialize scan slot with it. |
262 | | */ |
263 | 2.52k | tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists)); |
264 | 2.52k | ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc); |
265 | | |
266 | | /* |
267 | | * Initialize result type and projection. |
268 | | */ |
269 | 2.52k | ExecInitResultTypeTL(&scanstate->ss.ps); |
270 | 2.52k | ExecAssignScanProjectionInfo(&scanstate->ss); |
271 | | |
272 | | /* |
273 | | * initialize child expressions |
274 | | */ |
275 | 2.52k | scanstate->ss.ps.qual = |
276 | 2.52k | ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate); |
277 | | |
278 | | /* |
279 | | * Other node-specific setup |
280 | | */ |
281 | 2.52k | scanstate->curr_idx = -1; |
282 | 2.52k | scanstate->array_len = list_length(node->values_lists); |
283 | | |
284 | | /* convert list of sublists into array of sublists for easy addressing */ |
285 | 2.52k | scanstate->exprlists = (List **) |
286 | 2.52k | palloc(scanstate->array_len * sizeof(List *)); |
287 | 2.52k | i = 0; |
288 | 2.52k | foreach(vtl, node->values_lists) |
289 | 124k | { |
290 | 124k | scanstate->exprlists[i++] = (List *) lfirst(vtl); |
291 | 124k | } |
292 | | |
293 | 2.52k | return scanstate; |
294 | 2.52k | } |
295 | | |
296 | | /* ---------------------------------------------------------------- |
297 | | * ExecEndValuesScan |
298 | | * |
299 | | * frees any storage allocated through C routines. |
300 | | * ---------------------------------------------------------------- |
301 | | */ |
302 | | void |
303 | | ExecEndValuesScan(ValuesScanState *node) |
304 | 1.44k | { |
305 | | /* |
306 | | * Free both exprcontexts |
307 | | */ |
308 | 1.44k | ExecFreeExprContext(&node->ss.ps); |
309 | 1.44k | node->ss.ps.ps_ExprContext = node->rowcontext; |
310 | 1.44k | ExecFreeExprContext(&node->ss.ps); |
311 | | |
312 | | /* |
313 | | * clean out the tuple table |
314 | | */ |
315 | 1.44k | if (node->ss.ps.ps_ResultTupleSlot) |
316 | 468 | ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); |
317 | 1.44k | ExecClearTuple(node->ss.ss_ScanTupleSlot); |
318 | 1.44k | } |
319 | | |
320 | | /* ---------------------------------------------------------------- |
321 | | * ExecReScanValuesScan |
322 | | * |
323 | | * Rescans the relation. |
324 | | * ---------------------------------------------------------------- |
325 | | */ |
326 | | void |
327 | | ExecReScanValuesScan(ValuesScanState *node) |
328 | 16 | { |
329 | 16 | if (node->ss.ps.ps_ResultTupleSlot) |
330 | 0 | ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); |
331 | | |
332 | 16 | ExecScanReScan(&node->ss); |
333 | | |
334 | 16 | node->curr_idx = -1; |
335 | 16 | } |