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