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-2025, 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 *
6975 mail@joeconway.com 47 :CBC 111716 : 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 : 111716 : estate = node->ss.ps.state;
59 : 111716 : direction = estate->es_direction;
60 : 111716 : slot = node->ss.ss_ScanTupleSlot;
tgl@sss.pgh.pa.us 61 : 111716 : econtext = node->rowcontext;
62 : :
63 : : /*
64 : : * Get the next tuple. Return NULL if no more tuples.
65 : : */
mail@joeconway.com 66 [ + - ]: 111716 : if (ScanDirectionIsForward(direction))
67 : : {
68 [ + - ]: 111716 : if (node->curr_idx < node->array_len)
69 : 111716 : node->curr_idx++;
70 : : }
71 : : else
72 : : {
6975 mail@joeconway.com 73 [ # # ]:UBC 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 : : */
6975 mail@joeconway.com 83 :CBC 111716 : ExecClearTuple(slot);
84 : :
2059 tgl@sss.pgh.pa.us 85 : 111716 : curr_idx = node->curr_idx;
86 [ + - + + ]: 111716 : if (curr_idx >= 0 && curr_idx < node->array_len)
87 : : {
88 : 77400 : List *exprlist = node->exprlists[curr_idx];
89 : 77400 : 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 : : */
6975 101 : 77400 : ReScanExprContext(econtext);
102 : :
103 : : /*
104 : : * Do per-VALUES-row work in the per-tuple context.
105 : : */
106 : 77400 : 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 : : */
2059 116 [ + + ]: 77400 : 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 : 77370 : exprstatelist = ExecInitExprList(exprlist, NULL);
129 : : }
130 : :
131 : : /* parser should have checked all sublists are the same length */
6975 132 [ - + ]: 77400 : 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 : 77400 : values = slot->tts_values;
139 : 77400 : isnull = slot->tts_isnull;
140 : :
141 : 77400 : resind = 0;
142 [ + - + + : 166947 : foreach(lc, exprstatelist)
+ + ]
143 : : {
6912 bruce@momjian.us 144 : 89547 : ExprState *estate = (ExprState *) lfirst(lc);
260 drowley@postgresql.o 145 : 89547 : CompactAttribute *attr = TupleDescCompactAttr(slot->tts_tupleDescriptor,
146 : : resind);
147 : :
6975 tgl@sss.pgh.pa.us 148 : 89547 : 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 : : */
3382 158 [ + + + + ]: 89547 : values[resind] = MakeExpandedObjectReadOnly(values[resind],
159 : : isnull[resind],
160 : : attr->attlen);
161 : :
6975 162 : 89547 : resind++;
163 : : }
164 : :
165 : 77400 : MemoryContextSwitchTo(oldContext);
166 : :
167 : : /*
168 : : * And return the virtual tuple.
169 : : */
170 : 77400 : ExecStoreVirtualTuple(slot);
171 : : }
172 : :
173 : 111716 : return slot;
174 : : }
175 : :
176 : : /*
177 : : * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
178 : : */
179 : : static bool
5794 tgl@sss.pgh.pa.us 180 :UBC 0 : ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
181 : : {
182 : : /* nothing to check */
183 : 0 : 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 *
2973 andres@anarazel.de 196 :CBC 111233 : ExecValuesScan(PlanState *pstate)
197 : : {
198 : 111233 : ValuesScanState *node = castNode(ValuesScanState, pstate);
199 : :
5794 tgl@sss.pgh.pa.us 200 : 111233 : return ExecScan(&node->ss,
201 : : (ExecScanAccessMtd) ValuesNext,
202 : : (ExecScanRecheckMtd) ValuesRecheck);
203 : : }
204 : :
205 : : /* ----------------------------------------------------------------
206 : : * ExecInitValuesScan
207 : : * ----------------------------------------------------------------
208 : : */
209 : : ValuesScanState *
6975 mail@joeconway.com 210 : 4538 : 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 [ - + ]: 4538 : Assert(outerPlan(node) == NULL);
222 [ - + ]: 4538 : Assert(innerPlan(node) == NULL);
223 : :
224 : : /*
225 : : * create new ScanState for node
226 : : */
227 : 4538 : scanstate = makeNode(ValuesScanState);
228 : 4538 : scanstate->ss.ps.plan = (Plan *) node;
229 : 4538 : scanstate->ss.ps.state = estate;
2973 andres@anarazel.de 230 : 4538 : scanstate->ss.ps.ExecProcNode = ExecValuesScan;
231 : :
232 : : /*
233 : : * Miscellaneous initialization
234 : : */
6975 mail@joeconway.com 235 : 4538 : 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 : : */
tgl@sss.pgh.pa.us 242 : 4538 : ExecAssignExprContext(estate, planstate);
243 : 4538 : scanstate->rowcontext = planstate->ps_ExprContext;
mail@joeconway.com 244 : 4538 : ExecAssignExprContext(estate, planstate);
245 : :
246 : : /*
247 : : * Get info about values list, initialize scan slot with it.
248 : : */
2759 andres@anarazel.de 249 : 4538 : tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
2487 250 : 4538 : ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
251 : :
252 : : /*
253 : : * Initialize result type and projection.
254 : : */
2493 255 : 4538 : ExecInitResultTypeTL(&scanstate->ss.ps);
2759 256 : 4538 : ExecAssignScanProjectionInfo(&scanstate->ss);
257 : :
258 : : /*
259 : : * initialize child expressions
260 : : */
261 : 4538 : scanstate->ss.ps.qual =
262 : 4538 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
263 : :
264 : : /*
265 : : * Other node-specific setup
266 : : */
6975 mail@joeconway.com 267 : 4538 : scanstate->curr_idx = -1;
6774 tgl@sss.pgh.pa.us 268 : 4538 : 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 : : */
6975 mail@joeconway.com 280 : 4538 : scanstate->exprlists = (List **)
281 : 4538 : palloc(scanstate->array_len * sizeof(List *));
2059 tgl@sss.pgh.pa.us 282 : 4538 : scanstate->exprstatelists = (List **)
283 : 4538 : palloc0(scanstate->array_len * sizeof(List *));
6975 mail@joeconway.com 284 : 4538 : i = 0;
6774 tgl@sss.pgh.pa.us 285 [ + - + + : 22357 : foreach(vtl, node->values_lists)
+ + ]
286 : : {
1510 peter@eisentraut.org 287 : 17819 : List *exprs = lfirst_node(List, vtl);
288 : :
2059 tgl@sss.pgh.pa.us 289 : 17819 : scanstate->exprlists[i] = exprs;
290 : :
291 : : /*
292 : : * We can avoid the cost of a contain_subplans() scan in the simple
293 : : * case where there are no SubPlans anywhere.
294 : : */
295 [ + + + + ]: 18083 : if (estate->es_subplanstates &&
296 : 264 : contain_subplans((Node *) exprs))
297 : : {
298 : : int saved_jit_flags;
299 : :
300 : : /*
301 : : * As these expressions are only used once, disable JIT for them.
302 : : * This is worthwhile because it's common to insert significant
303 : : * amounts of data via VALUES(). Note that this doesn't prevent
304 : : * use of JIT *within* a subplan, since that's initialized
305 : : * separately; this just affects the upper-level subexpressions.
306 : : */
307 : 18 : saved_jit_flags = estate->es_jit_flags;
308 : 18 : estate->es_jit_flags = PGJIT_NONE;
309 : :
310 : 18 : scanstate->exprstatelists[i] = ExecInitExprList(exprs,
311 : : &scanstate->ss.ps);
312 : :
313 : 18 : estate->es_jit_flags = saved_jit_flags;
314 : : }
315 : 17819 : i++;
316 : : }
317 : :
6975 mail@joeconway.com 318 : 4538 : return scanstate;
319 : : }
320 : :
321 : : /* ----------------------------------------------------------------
322 : : * ExecReScanValuesScan
323 : : *
324 : : * Rescans the relation.
325 : : * ----------------------------------------------------------------
326 : : */
327 : : void
5535 tgl@sss.pgh.pa.us 328 : 30189 : ExecReScanValuesScan(ValuesScanState *node)
329 : : {
2493 andres@anarazel.de 330 [ + + ]: 30189 : if (node->ss.ps.ps_ResultTupleSlot)
331 : 6 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
332 : :
5794 tgl@sss.pgh.pa.us 333 : 30189 : ExecScanReScan(&node->ss);
334 : :
6975 mail@joeconway.com 335 : 30189 : node->curr_idx = -1;
336 : 30189 : }
|