Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * nodeValuesscan.c
4 : : * Support routines for scanning Values lists
5 : : * ("VALUES (...), (...), ..." in rangetable).
6 : : *
7 : : * Portions Copyright (c) 1996-2024, 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 "optimizer/clauses.h"
30 : : #include "utils/expandeddatum.h"
31 : :
32 : :
33 : : static TupleTableSlot *ValuesNext(ValuesScanState *node);
34 : :
35 : :
36 : : /* ----------------------------------------------------------------
37 : : * Scan Support
38 : : * ----------------------------------------------------------------
39 : : */
40 : :
41 : : /* ----------------------------------------------------------------
42 : : * ValuesNext
43 : : *
44 : : * This is a workhorse for ExecValuesScan
45 : : * ----------------------------------------------------------------
46 : : */
47 : : static TupleTableSlot *
6465 mail@joeconway.com 48 :CBC 110930 : ValuesNext(ValuesScanState *node)
49 : : {
50 : : TupleTableSlot *slot;
51 : : EState *estate;
52 : : ExprContext *econtext;
53 : : ScanDirection direction;
54 : : int curr_idx;
55 : :
56 : : /*
57 : : * get information from the estate and scan state
58 : : */
59 : 110930 : estate = node->ss.ps.state;
60 : 110930 : direction = estate->es_direction;
61 : 110930 : slot = node->ss.ss_ScanTupleSlot;
tgl@sss.pgh.pa.us 62 : 110930 : econtext = node->rowcontext;
63 : :
64 : : /*
65 : : * Get the next tuple. Return NULL if no more tuples.
66 : : */
mail@joeconway.com 67 [ + - ]: 110930 : if (ScanDirectionIsForward(direction))
68 : : {
69 [ + - ]: 110930 : if (node->curr_idx < node->array_len)
70 : 110930 : node->curr_idx++;
71 : : }
72 : : else
73 : : {
6465 mail@joeconway.com 74 [ # # ]:UBC 0 : if (node->curr_idx >= 0)
75 : 0 : node->curr_idx--;
76 : : }
77 : :
78 : : /*
79 : : * Always clear the result slot; this is appropriate if we are at the end
80 : : * of the data, and if we're not, we still need it as the first step of
81 : : * the store-virtual-tuple protocol. It seems wise to clear the slot
82 : : * before we reset the context it might have pointers into.
83 : : */
6465 mail@joeconway.com 84 :CBC 110930 : ExecClearTuple(slot);
85 : :
1549 tgl@sss.pgh.pa.us 86 : 110930 : curr_idx = node->curr_idx;
87 [ + - + + ]: 110930 : if (curr_idx >= 0 && curr_idx < node->array_len)
88 : : {
89 : 76818 : List *exprlist = node->exprlists[curr_idx];
90 : 76818 : List *exprstatelist = node->exprstatelists[curr_idx];
91 : : MemoryContext oldContext;
92 : : Datum *values;
93 : : bool *isnull;
94 : : ListCell *lc;
95 : : int resind;
96 : :
97 : : /*
98 : : * Get rid of any prior cycle's leftovers. We use ReScanExprContext
99 : : * not just ResetExprContext because we want any registered shutdown
100 : : * callbacks to be called.
101 : : */
6465 102 : 76818 : ReScanExprContext(econtext);
103 : :
104 : : /*
105 : : * Do per-VALUES-row work in the per-tuple context.
106 : : */
107 : 76818 : oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
108 : :
109 : : /*
110 : : * Unless we already made the expression eval state for this row,
111 : : * build it in the econtext's per-tuple memory. This is a tad
112 : : * unusual, but we want to delete the eval state again when we move to
113 : : * the next row, to avoid growth of memory requirements over a long
114 : : * values list. For rows in which that won't work, we already built
115 : : * the eval state at plan startup.
116 : : */
1549 117 [ + + ]: 76818 : if (exprstatelist == NIL)
118 : : {
119 : : /*
120 : : * Pass parent as NULL, not my plan node, because we don't want
121 : : * anything in this transient state linking into permanent state.
122 : : * The only expression type that might wish to do so is a SubPlan,
123 : : * and we already checked that there aren't any.
124 : : *
125 : : * Note that passing parent = NULL also disables JIT compilation
126 : : * of the expressions, which is a win, because they're only going
127 : : * to be used once under normal circumstances.
128 : : */
129 : 76788 : exprstatelist = ExecInitExprList(exprlist, NULL);
130 : : }
131 : :
132 : : /* parser should have checked all sublists are the same length */
6465 133 [ - + ]: 76818 : Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);
134 : :
135 : : /*
136 : : * Compute the expressions and build a virtual result tuple. We
137 : : * already did ExecClearTuple(slot).
138 : : */
139 : 76818 : values = slot->tts_values;
140 : 76818 : isnull = slot->tts_isnull;
141 : :
142 : 76818 : resind = 0;
143 [ + - + + : 165208 : foreach(lc, exprstatelist)
+ + ]
144 : : {
6402 bruce@momjian.us 145 : 88390 : ExprState *estate = (ExprState *) lfirst(lc);
2429 andres@anarazel.de 146 : 88390 : Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor,
147 : : resind);
148 : :
6465 tgl@sss.pgh.pa.us 149 : 88390 : values[resind] = ExecEvalExpr(estate,
150 : : econtext,
151 : : &isnull[resind]);
152 : :
153 : : /*
154 : : * We must force any R/W expanded datums to read-only state, in
155 : : * case they are multiply referenced in the plan node's output
156 : : * expressions, or in case we skip the output projection and the
157 : : * output column is multiply referenced in higher plan nodes.
158 : : */
2872 159 [ + + + + ]: 88390 : values[resind] = MakeExpandedObjectReadOnly(values[resind],
160 : : isnull[resind],
161 : : attr->attlen);
162 : :
6465 163 : 88390 : resind++;
164 : : }
165 : :
166 : 76818 : MemoryContextSwitchTo(oldContext);
167 : :
168 : : /*
169 : : * And return the virtual tuple.
170 : : */
171 : 76818 : ExecStoreVirtualTuple(slot);
172 : : }
173 : :
174 : 110930 : return slot;
175 : : }
176 : :
177 : : /*
178 : : * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
179 : : */
180 : : static bool
5284 181 : 2 : ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
182 : : {
183 : : /* nothing to check */
184 : 2 : return true;
185 : : }
186 : :
187 : : /* ----------------------------------------------------------------
188 : : * ExecValuesScan(node)
189 : : *
190 : : * Scans the values lists sequentially and returns the next qualifying
191 : : * tuple.
192 : : * We call the ExecScan() routine and pass it the appropriate
193 : : * access method functions.
194 : : * ----------------------------------------------------------------
195 : : */
196 : : static TupleTableSlot *
2463 andres@anarazel.de 197 : 110450 : ExecValuesScan(PlanState *pstate)
198 : : {
199 : 110450 : ValuesScanState *node = castNode(ValuesScanState, pstate);
200 : :
5284 tgl@sss.pgh.pa.us 201 : 110450 : return ExecScan(&node->ss,
202 : : (ExecScanAccessMtd) ValuesNext,
203 : : (ExecScanRecheckMtd) ValuesRecheck);
204 : : }
205 : :
206 : : /* ----------------------------------------------------------------
207 : : * ExecInitValuesScan
208 : : * ----------------------------------------------------------------
209 : : */
210 : : ValuesScanState *
6465 mail@joeconway.com 211 : 4266 : ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
212 : : {
213 : : ValuesScanState *scanstate;
214 : : TupleDesc tupdesc;
215 : : ListCell *vtl;
216 : : int i;
217 : : PlanState *planstate;
218 : :
219 : : /*
220 : : * ValuesScan should not have any children.
221 : : */
222 [ - + ]: 4266 : Assert(outerPlan(node) == NULL);
223 [ - + ]: 4266 : Assert(innerPlan(node) == NULL);
224 : :
225 : : /*
226 : : * create new ScanState for node
227 : : */
228 : 4266 : scanstate = makeNode(ValuesScanState);
229 : 4266 : scanstate->ss.ps.plan = (Plan *) node;
230 : 4266 : scanstate->ss.ps.state = estate;
2463 andres@anarazel.de 231 : 4266 : scanstate->ss.ps.ExecProcNode = ExecValuesScan;
232 : :
233 : : /*
234 : : * Miscellaneous initialization
235 : : */
6465 mail@joeconway.com 236 : 4266 : planstate = &scanstate->ss.ps;
237 : :
238 : : /*
239 : : * Create expression contexts. We need two, one for per-sublist
240 : : * processing and one for execScan.c to use for quals and projections. We
241 : : * cheat a little by using ExecAssignExprContext() to build both.
242 : : */
tgl@sss.pgh.pa.us 243 : 4266 : ExecAssignExprContext(estate, planstate);
244 : 4266 : scanstate->rowcontext = planstate->ps_ExprContext;
mail@joeconway.com 245 : 4266 : ExecAssignExprContext(estate, planstate);
246 : :
247 : : /*
248 : : * Get info about values list, initialize scan slot with it.
249 : : */
2249 andres@anarazel.de 250 : 4266 : tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
1977 251 : 4266 : ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
252 : :
253 : : /*
254 : : * Initialize result type and projection.
255 : : */
1983 256 : 4266 : ExecInitResultTypeTL(&scanstate->ss.ps);
2249 257 : 4266 : ExecAssignScanProjectionInfo(&scanstate->ss);
258 : :
259 : : /*
260 : : * initialize child expressions
261 : : */
262 : 4266 : scanstate->ss.ps.qual =
263 : 4266 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
264 : :
265 : : /*
266 : : * Other node-specific setup
267 : : */
6465 mail@joeconway.com 268 : 4266 : scanstate->curr_idx = -1;
6264 tgl@sss.pgh.pa.us 269 : 4266 : scanstate->array_len = list_length(node->values_lists);
270 : :
271 : : /*
272 : : * Convert the list of expression sublists into an array for easier
273 : : * addressing at runtime. Also, detect whether any sublists contain
274 : : * SubPlans; for just those sublists, go ahead and do expression
275 : : * initialization. (This avoids problems with SubPlans wanting to connect
276 : : * themselves up to the outer plan tree. Notably, EXPLAIN won't see the
277 : : * subplans otherwise; also we will have troubles with dangling pointers
278 : : * and/or leaked resources if we try to handle SubPlans the same as
279 : : * simpler expressions.)
280 : : */
6465 mail@joeconway.com 281 : 4266 : scanstate->exprlists = (List **)
282 : 4266 : palloc(scanstate->array_len * sizeof(List *));
1549 tgl@sss.pgh.pa.us 283 : 4266 : scanstate->exprstatelists = (List **)
284 : 4266 : palloc0(scanstate->array_len * sizeof(List *));
6465 mail@joeconway.com 285 : 4266 : i = 0;
6264 tgl@sss.pgh.pa.us 286 [ + - + + : 21366 : foreach(vtl, node->values_lists)
+ + ]
287 : : {
1000 peter@eisentraut.org 288 : 17100 : List *exprs = lfirst_node(List, vtl);
289 : :
1549 tgl@sss.pgh.pa.us 290 : 17100 : scanstate->exprlists[i] = exprs;
291 : :
292 : : /*
293 : : * We can avoid the cost of a contain_subplans() scan in the simple
294 : : * case where there are no SubPlans anywhere.
295 : : */
296 [ + + + + ]: 17304 : if (estate->es_subplanstates &&
297 : 204 : contain_subplans((Node *) exprs))
298 : : {
299 : : int saved_jit_flags;
300 : :
301 : : /*
302 : : * As these expressions are only used once, disable JIT for them.
303 : : * This is worthwhile because it's common to insert significant
304 : : * amounts of data via VALUES(). Note that this doesn't prevent
305 : : * use of JIT *within* a subplan, since that's initialized
306 : : * separately; this just affects the upper-level subexpressions.
307 : : */
308 : 9 : saved_jit_flags = estate->es_jit_flags;
309 : 9 : estate->es_jit_flags = PGJIT_NONE;
310 : :
311 : 9 : scanstate->exprstatelists[i] = ExecInitExprList(exprs,
312 : : &scanstate->ss.ps);
313 : :
314 : 9 : estate->es_jit_flags = saved_jit_flags;
315 : : }
316 : 17100 : i++;
317 : : }
318 : :
6465 mail@joeconway.com 319 : 4266 : return scanstate;
320 : : }
321 : :
322 : : /* ----------------------------------------------------------------
323 : : * ExecReScanValuesScan
324 : : *
325 : : * Rescans the relation.
326 : : * ----------------------------------------------------------------
327 : : */
328 : : void
5025 tgl@sss.pgh.pa.us 329 : 30199 : ExecReScanValuesScan(ValuesScanState *node)
330 : : {
1983 andres@anarazel.de 331 [ + + ]: 30199 : if (node->ss.ps.ps_ResultTupleSlot)
1983 andres@anarazel.de 332 :GBC 6 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
333 : :
5284 tgl@sss.pgh.pa.us 334 :CBC 30199 : ExecScanReScan(&node->ss);
335 : :
6465 mail@joeconway.com 336 : 30199 : node->curr_idx = -1;
337 : 30199 : }
|