Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * execUtils.c
4 : : * miscellaneous executor utility routines
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/executor/execUtils.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : /*
16 : : * INTERFACE ROUTINES
17 : : * CreateExecutorState Create/delete executor working state
18 : : * FreeExecutorState
19 : : * CreateExprContext
20 : : * CreateStandaloneExprContext
21 : : * FreeExprContext
22 : : * ReScanExprContext
23 : : *
24 : : * ExecAssignExprContext Common code for plan node init routines.
25 : : * etc
26 : : *
27 : : * ExecOpenScanRelation Common code for scan node init routines.
28 : : *
29 : : * ExecInitRangeTable Set up executor's range-table-related data.
30 : : *
31 : : * ExecGetRangeTableRelation Fetch Relation for a rangetable entry.
32 : : *
33 : : * executor_errposition Report syntactic position of an error.
34 : : *
35 : : * RegisterExprContextCallback Register function shutdown callback
36 : : * UnregisterExprContextCallback Deregister function shutdown callback
37 : : *
38 : : * GetAttributeByName Runtime extraction of columns from tuples.
39 : : * GetAttributeByNum
40 : : *
41 : : * NOTES
42 : : * This file has traditionally been the place to stick misc.
43 : : * executor support stuff that doesn't really go anyplace else.
44 : : */
45 : :
46 : : #include "postgres.h"
47 : :
48 : : #include "access/parallel.h"
49 : : #include "access/table.h"
50 : : #include "access/tableam.h"
51 : : #include "executor/executor.h"
52 : : #include "executor/nodeModifyTable.h"
53 : : #include "jit/jit.h"
54 : : #include "mb/pg_wchar.h"
55 : : #include "miscadmin.h"
56 : : #include "parser/parse_relation.h"
57 : : #include "partitioning/partdesc.h"
58 : : #include "storage/lmgr.h"
59 : : #include "utils/builtins.h"
60 : : #include "utils/memutils.h"
61 : : #include "utils/rel.h"
62 : : #include "utils/typcache.h"
63 : :
64 : :
65 : : static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc);
66 : : static void ShutdownExprContext(ExprContext *econtext, bool isCommit);
67 : : static RTEPermissionInfo *GetResultRTEPermissionInfo(ResultRelInfo *relinfo, EState *estate);
68 : :
69 : :
70 : : /* ----------------------------------------------------------------
71 : : * Executor state and memory management functions
72 : : * ----------------------------------------------------------------
73 : : */
74 : :
75 : : /* ----------------
76 : : * CreateExecutorState
77 : : *
78 : : * Create and initialize an EState node, which is the root of
79 : : * working storage for an entire Executor invocation.
80 : : *
81 : : * Principally, this creates the per-query memory context that will be
82 : : * used to hold all working data that lives till the end of the query.
83 : : * Note that the per-query context will become a child of the caller's
84 : : * CurrentMemoryContext.
85 : : * ----------------
86 : : */
87 : : EState *
7791 tgl@sss.pgh.pa.us 88 :CBC 610451 : CreateExecutorState(void)
89 : : {
90 : : EState *estate;
91 : : MemoryContext qcontext;
92 : : MemoryContext oldcontext;
93 : :
94 : : /*
95 : : * Create the per-query context for this Executor run.
96 : : */
97 : 610451 : qcontext = AllocSetContextCreate(CurrentMemoryContext,
98 : : "ExecutorState",
99 : : ALLOCSET_DEFAULT_SIZES);
100 : :
101 : : /*
102 : : * Make the EState node within the per-query context. This way, we don't
103 : : * need a separate pfree() operation for it at shutdown.
104 : : */
105 : 610451 : oldcontext = MemoryContextSwitchTo(qcontext);
106 : :
107 : 610451 : estate = makeNode(EState);
108 : :
109 : : /*
110 : : * Initialize all fields of the Executor State structure
111 : : */
112 : 610451 : estate->es_direction = ForwardScanDirection;
2489 113 : 610451 : estate->es_snapshot = InvalidSnapshot; /* caller must initialize this */
7155 114 : 610451 : estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */
7791 115 : 610451 : estate->es_range_table = NIL;
2019 116 : 610451 : estate->es_range_table_size = 0;
117 : 610451 : estate->es_relations = NULL;
2015 118 : 610451 : estate->es_rowmarks = NULL;
405 119 : 610451 : estate->es_rteperminfos = NIL;
5284 120 : 610451 : estate->es_plannedstmt = NULL;
121 : :
5298 122 : 610451 : estate->es_junkFilter = NULL;
123 : :
5980 124 : 610451 : estate->es_output_cid = (CommandId) 0;
125 : :
7791 126 : 610451 : estate->es_result_relations = NULL;
1279 heikki.linnakangas@i 127 : 610451 : estate->es_opened_result_relations = NIL;
2257 rhaas@postgresql.org 128 : 610451 : estate->es_tuple_routing_result_relations = NIL;
6087 tgl@sss.pgh.pa.us 129 : 610451 : estate->es_trig_target_relations = NIL;
130 : :
493 efujita@postgresql.o 131 : 610451 : estate->es_insert_pending_result_relations = NIL;
132 : 610451 : estate->es_insert_pending_modifytables = NIL;
133 : :
7791 tgl@sss.pgh.pa.us 134 : 610451 : estate->es_param_list_info = NULL;
135 : 610451 : estate->es_param_exec_vals = NULL;
136 : :
2571 kgrittn@postgresql.o 137 : 610451 : estate->es_queryEnv = NULL;
138 : :
7791 tgl@sss.pgh.pa.us 139 : 610451 : estate->es_query_cxt = qcontext;
140 : :
5313 141 : 610451 : estate->es_tupleTable = NIL;
142 : :
7791 143 : 610451 : estate->es_processed = 0;
374 michael@paquier.xyz 144 : 610451 : estate->es_total_processed = 0;
145 : :
4795 tgl@sss.pgh.pa.us 146 : 610451 : estate->es_top_eflags = 0;
147 : 610451 : estate->es_instrument = 0;
148 : 610451 : estate->es_finished = false;
149 : :
7791 150 : 610451 : estate->es_exprcontexts = NIL;
151 : :
6256 152 : 610451 : estate->es_subplanstates = NIL;
153 : :
4797 154 : 610451 : estate->es_auxmodifytables = NIL;
155 : :
7791 156 : 610451 : estate->es_per_tuple_exprcontext = NULL;
157 : :
2608 rhaas@postgresql.org 158 : 610451 : estate->es_sourceText = NULL;
159 : :
2361 160 : 610451 : estate->es_use_parallel_mode = false;
161 : :
2215 andres@anarazel.de 162 : 610451 : estate->es_jit_flags = 0;
163 : 610451 : estate->es_jit = NULL;
164 : :
165 : : /*
166 : : * Return the executor state structure
167 : : */
7791 tgl@sss.pgh.pa.us 168 : 610451 : MemoryContextSwitchTo(oldcontext);
169 : :
170 : 610451 : return estate;
171 : : }
172 : :
173 : : /* ----------------
174 : : * FreeExecutorState
175 : : *
176 : : * Release an EState along with all remaining working storage.
177 : : *
178 : : * Note: this is not responsible for releasing non-memory resources, such as
179 : : * open relations or buffer pins. But it will shut down any still-active
180 : : * ExprContexts within the EState and deallocate associated JITed expressions.
181 : : * That is sufficient cleanup for situations where the EState has only been
182 : : * used for expression evaluation, and not to run a complete Plan.
183 : : *
184 : : * This can be called in any memory context ... so long as it's not one
185 : : * of the ones to be freed.
186 : : * ----------------
187 : : */
188 : : void
189 : 594090 : FreeExecutorState(EState *estate)
190 : : {
191 : : /*
192 : : * Shut down and free any remaining ExprContexts. We do this explicitly
193 : : * to ensure that any remaining shutdown callbacks get called (since they
194 : : * might need to release resources that aren't simply memory within the
195 : : * per-query memory context).
196 : : */
197 [ + + ]: 1510391 : while (estate->es_exprcontexts)
198 : : {
199 : : /*
200 : : * XXX: seems there ought to be a faster way to implement this than
201 : : * repeated list_delete(), no?
202 : : */
5384 203 : 916301 : FreeExprContext((ExprContext *) linitial(estate->es_exprcontexts),
204 : : true);
205 : : /* FreeExprContext removed the list link for us */
206 : : }
207 : :
208 : : /* release JIT context, if allocated */
2090 andres@anarazel.de 209 [ - + ]: 594090 : if (estate->es_jit)
210 : : {
2090 andres@anarazel.de 211 :UBC 0 : jit_release_context(estate->es_jit);
212 : 0 : estate->es_jit = NULL;
213 : : }
214 : :
215 : : /* release partition directory, if allocated */
1865 rhaas@postgresql.org 216 [ + + ]:CBC 594090 : if (estate->es_partition_directory)
217 : : {
218 : 3800 : DestroyPartitionDirectory(estate->es_partition_directory);
219 : 3800 : estate->es_partition_directory = NULL;
220 : : }
221 : :
222 : : /*
223 : : * Free the per-query memory context, thereby releasing all working
224 : : * memory, including the EState node itself.
225 : : */
6256 tgl@sss.pgh.pa.us 226 : 594090 : MemoryContextDelete(estate->es_query_cxt);
10141 scrappy@hub.org 227 : 594090 : }
228 : :
229 : : /*
230 : : * Internal implementation for CreateExprContext() and CreateWorkExprContext()
231 : : * that allows control over the AllocSet parameters.
232 : : */
233 : : static ExprContext *
1468 jdavis@postgresql.or 234 : 984380 : CreateExprContextInternal(EState *estate, Size minContextSize,
235 : : Size initBlockSize, Size maxBlockSize)
236 : : {
237 : : ExprContext *econtext;
238 : : MemoryContext oldcontext;
239 : :
240 : : /* Create the ExprContext node within the per-query memory context */
7791 tgl@sss.pgh.pa.us 241 : 984380 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
242 : :
243 : 984380 : econtext = makeNode(ExprContext);
244 : :
245 : : /* Initialize fields of ExprContext */
246 : 984380 : econtext->ecxt_scantuple = NULL;
8677 247 : 984380 : econtext->ecxt_innertuple = NULL;
248 : 984380 : econtext->ecxt_outertuple = NULL;
249 : :
7791 250 : 984380 : econtext->ecxt_per_query_memory = estate->es_query_cxt;
251 : :
252 : : /*
253 : : * Create working memory for expression evaluation in this context.
254 : : */
8677 255 : 984380 : econtext->ecxt_per_tuple_memory =
7791 256 : 984380 : AllocSetContextCreate(estate->es_query_cxt,
257 : : "ExprContext",
258 : : minContextSize,
259 : : initBlockSize,
260 : : maxBlockSize);
261 : :
262 : 984380 : econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
263 : 984380 : econtext->ecxt_param_list_info = estate->es_param_list_info;
264 : :
8677 265 : 984380 : econtext->ecxt_aggvalues = NULL;
266 : 984380 : econtext->ecxt_aggnulls = NULL;
267 : :
7333 268 : 984380 : econtext->caseValue_datum = (Datum) 0;
269 : 984380 : econtext->caseValue_isNull = true;
270 : :
7791 271 : 984380 : econtext->domainValue_datum = (Datum) 0;
272 : 984380 : econtext->domainValue_isNull = true;
273 : :
274 : 984380 : econtext->ecxt_estate = estate;
275 : :
8008 276 : 984380 : econtext->ecxt_callbacks = NULL;
277 : :
278 : : /*
279 : : * Link the ExprContext into the EState to ensure it is shut down when the
280 : : * EState is freed. Because we use lcons(), shutdowns will occur in
281 : : * reverse order of creation, which may not be essential but can't hurt.
282 : : */
7791 283 : 984380 : estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
284 : :
285 : 984380 : MemoryContextSwitchTo(oldcontext);
286 : :
8677 287 : 984380 : return econtext;
288 : : }
289 : :
290 : : /* ----------------
291 : : * CreateExprContext
292 : : *
293 : : * Create a context for expression evaluation within an EState.
294 : : *
295 : : * An executor run may require multiple ExprContexts (we usually make one
296 : : * for each Plan node, and a separate one for per-output-tuple processing
297 : : * such as constraint checking). Each ExprContext has its own "per-tuple"
298 : : * memory context.
299 : : *
300 : : * Note we make no assumption about the caller's memory context.
301 : : * ----------------
302 : : */
303 : : ExprContext *
1468 jdavis@postgresql.or 304 : 981810 : CreateExprContext(EState *estate)
305 : : {
306 : 981810 : return CreateExprContextInternal(estate, ALLOCSET_DEFAULT_SIZES);
307 : : }
308 : :
309 : :
310 : : /* ----------------
311 : : * CreateWorkExprContext
312 : : *
313 : : * Like CreateExprContext, but specifies the AllocSet sizes to be reasonable
314 : : * in proportion to work_mem. If the maximum block allocation size is too
315 : : * large, it's easy to skip right past work_mem with a single allocation.
316 : : * ----------------
317 : : */
318 : : ExprContext *
319 : 2570 : CreateWorkExprContext(EState *estate)
320 : : {
1431 tgl@sss.pgh.pa.us 321 : 2570 : Size minContextSize = ALLOCSET_DEFAULT_MINSIZE;
322 : 2570 : Size initBlockSize = ALLOCSET_DEFAULT_INITSIZE;
323 : 2570 : Size maxBlockSize = ALLOCSET_DEFAULT_MAXSIZE;
324 : :
325 : : /* choose the maxBlockSize to be no larger than 1/16 of work_mem */
1468 jdavis@postgresql.or 326 [ + + ]: 15690 : while (16 * maxBlockSize > work_mem * 1024L)
327 : 13120 : maxBlockSize >>= 1;
328 : :
329 [ + + ]: 2570 : if (maxBlockSize < ALLOCSET_DEFAULT_INITSIZE)
330 : 39 : maxBlockSize = ALLOCSET_DEFAULT_INITSIZE;
331 : :
332 : 2570 : return CreateExprContextInternal(estate, minContextSize,
333 : : initBlockSize, maxBlockSize);
334 : : }
335 : :
336 : : /* ----------------
337 : : * CreateStandaloneExprContext
338 : : *
339 : : * Create a context for standalone expression evaluation.
340 : : *
341 : : * An ExprContext made this way can be used for evaluation of expressions
342 : : * that contain no Params, subplans, or Var references (it might work to
343 : : * put tuple references into the scantuple field, but it seems unwise).
344 : : *
345 : : * The ExprContext struct is allocated in the caller's current memory
346 : : * context, which also becomes its "per query" context.
347 : : *
348 : : * It is caller's responsibility to free the ExprContext when done,
349 : : * or at least ensure that any shutdown callbacks have been called
350 : : * (ReScanExprContext() is suitable). Otherwise, non-memory resources
351 : : * might be leaked.
352 : : * ----------------
353 : : */
354 : : ExprContext *
6463 tgl@sss.pgh.pa.us 355 : 4150 : CreateStandaloneExprContext(void)
356 : : {
357 : : ExprContext *econtext;
358 : :
359 : : /* Create the ExprContext node within the caller's memory context */
360 : 4150 : econtext = makeNode(ExprContext);
361 : :
362 : : /* Initialize fields of ExprContext */
363 : 4150 : econtext->ecxt_scantuple = NULL;
364 : 4150 : econtext->ecxt_innertuple = NULL;
365 : 4150 : econtext->ecxt_outertuple = NULL;
366 : :
367 : 4150 : econtext->ecxt_per_query_memory = CurrentMemoryContext;
368 : :
369 : : /*
370 : : * Create working memory for expression evaluation in this context.
371 : : */
372 : 4150 : econtext->ecxt_per_tuple_memory =
373 : 4150 : AllocSetContextCreate(CurrentMemoryContext,
374 : : "ExprContext",
375 : : ALLOCSET_DEFAULT_SIZES);
376 : :
377 : 4150 : econtext->ecxt_param_exec_vals = NULL;
378 : 4150 : econtext->ecxt_param_list_info = NULL;
379 : :
380 : 4150 : econtext->ecxt_aggvalues = NULL;
381 : 4150 : econtext->ecxt_aggnulls = NULL;
382 : :
383 : 4150 : econtext->caseValue_datum = (Datum) 0;
384 : 4150 : econtext->caseValue_isNull = true;
385 : :
386 : 4150 : econtext->domainValue_datum = (Datum) 0;
387 : 4150 : econtext->domainValue_isNull = true;
388 : :
389 : 4150 : econtext->ecxt_estate = NULL;
390 : :
391 : 4150 : econtext->ecxt_callbacks = NULL;
392 : :
393 : 4150 : return econtext;
394 : : }
395 : :
396 : : /* ----------------
397 : : * FreeExprContext
398 : : *
399 : : * Free an expression context, including calling any remaining
400 : : * shutdown callbacks.
401 : : *
402 : : * Since we free the temporary context used for expression evaluation,
403 : : * any previously computed pass-by-reference expression result will go away!
404 : : *
405 : : * If isCommit is false, we are being called in error cleanup, and should
406 : : * not call callbacks but only release memory. (It might be better to call
407 : : * the callbacks and pass the isCommit flag to them, but that would require
408 : : * more invasive code changes than currently seems justified.)
409 : : *
410 : : * Note we make no assumption about the caller's memory context.
411 : : * ----------------
412 : : */
413 : : void
5384 414 : 965214 : FreeExprContext(ExprContext *econtext, bool isCommit)
415 : : {
416 : : EState *estate;
417 : :
418 : : /* Call any registered callbacks */
419 : 965214 : ShutdownExprContext(econtext, isCommit);
420 : : /* And clean up the memory used */
8677 421 : 965214 : MemoryContextDelete(econtext->ecxt_per_tuple_memory);
422 : : /* Unlink self from owning EState, if any */
7791 423 : 965214 : estate = econtext->ecxt_estate;
6463 424 [ + - ]: 965214 : if (estate)
425 : 965214 : estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts,
426 : : econtext);
427 : : /* And delete the ExprContext node */
8677 428 : 965214 : pfree(econtext);
10141 scrappy@hub.org 429 : 965214 : }
430 : :
431 : : /*
432 : : * ReScanExprContext
433 : : *
434 : : * Reset an expression context in preparation for a rescan of its
435 : : * plan node. This requires calling any registered shutdown callbacks,
436 : : * since any partially complete set-returning-functions must be canceled.
437 : : *
438 : : * Note we make no assumption about the caller's memory context.
439 : : */
440 : : void
7423 tgl@sss.pgh.pa.us 441 : 1613339 : ReScanExprContext(ExprContext *econtext)
442 : : {
443 : : /* Call any registered callbacks */
5384 444 : 1613339 : ShutdownExprContext(econtext, true);
445 : : /* And clean up the memory used */
7423 446 : 1613339 : MemoryContextReset(econtext->ecxt_per_tuple_memory);
447 : 1613339 : }
448 : :
449 : : /*
450 : : * Build a per-output-tuple ExprContext for an EState.
451 : : *
452 : : * This is normally invoked via GetPerTupleExprContext() macro,
453 : : * not directly.
454 : : */
455 : : ExprContext *
8483 456 : 319925 : MakePerTupleExprContext(EState *estate)
457 : : {
458 [ + - ]: 319925 : if (estate->es_per_tuple_exprcontext == NULL)
7791 459 : 319925 : estate->es_per_tuple_exprcontext = CreateExprContext(estate);
460 : :
8483 461 : 319925 : return estate->es_per_tuple_exprcontext;
462 : : }
463 : :
464 : :
465 : : /* ----------------------------------------------------------------
466 : : * miscellaneous node-init support functions
467 : : *
468 : : * Note: all of these are expected to be called with CurrentMemoryContext
469 : : * equal to the per-query memory context.
470 : : * ----------------------------------------------------------------
471 : : */
472 : :
473 : : /* ----------------
474 : : * ExecAssignExprContext
475 : : *
476 : : * This initializes the ps_ExprContext field. It is only necessary
477 : : * to do this for nodes which use ExecQual or ExecProject
478 : : * because those routines require an econtext. Other nodes that
479 : : * don't have to evaluate expressions don't need to do this.
480 : : * ----------------
481 : : */
482 : : void
7555 bruce@momjian.us 483 : 604129 : ExecAssignExprContext(EState *estate, PlanState *planstate)
484 : : {
7791 tgl@sss.pgh.pa.us 485 : 604129 : planstate->ps_ExprContext = CreateExprContext(estate);
486 : 604129 : }
487 : :
488 : : /* ----------------
489 : : * ExecGetResultType
490 : : * ----------------
491 : : */
492 : : TupleDesc
7555 bruce@momjian.us 493 : 727207 : ExecGetResultType(PlanState *planstate)
494 : : {
1983 andres@anarazel.de 495 : 727207 : return planstate->ps_ResultTupleDesc;
496 : : }
497 : :
498 : : /*
499 : : * ExecGetResultSlotOps - information about node's type of result slot
500 : : */
501 : : const TupleTableSlotOps *
1977 502 : 266646 : ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
503 : : {
504 [ + - + + ]: 266646 : if (planstate->resultopsset && planstate->resultops)
505 : : {
506 [ + + ]: 265892 : if (isfixed)
507 : 242819 : *isfixed = planstate->resultopsfixed;
508 : 265892 : return planstate->resultops;
509 : : }
510 : :
511 [ + + ]: 754 : if (isfixed)
512 : : {
513 [ + - ]: 736 : if (planstate->resultopsset)
514 : 736 : *isfixed = planstate->resultopsfixed;
1977 andres@anarazel.de 515 [ # # ]:UBC 0 : else if (planstate->ps_ResultTupleSlot)
516 : 0 : *isfixed = TTS_FIXED(planstate->ps_ResultTupleSlot);
517 : : else
518 : 0 : *isfixed = false;
519 : : }
520 : :
1977 andres@anarazel.de 521 [ + - ]:CBC 754 : if (!planstate->ps_ResultTupleSlot)
522 : 754 : return &TTSOpsVirtual;
523 : :
1977 andres@anarazel.de 524 :UBC 0 : return planstate->ps_ResultTupleSlot->tts_ops;
525 : : }
526 : :
527 : :
528 : : /* ----------------
529 : : * ExecAssignProjectionInfo
530 : : *
531 : : * forms the projection information from the node's targetlist
532 : : *
533 : : * Notes for inputDesc are same as for ExecBuildProjectionInfo: supply it
534 : : * for a relation-scan node, can pass NULL for upper-level nodes
535 : : * ----------------
536 : : */
537 : : void
6281 tgl@sss.pgh.pa.us 538 :CBC 361208 : ExecAssignProjectionInfo(PlanState *planstate,
539 : : TupleDesc inputDesc)
540 : : {
7763 541 : 361177 : planstate->ps_ProjInfo =
2588 andres@anarazel.de 542 : 361208 : ExecBuildProjectionInfo(planstate->plan->targetlist,
543 : : planstate->ps_ExprContext,
544 : : planstate->ps_ResultTupleSlot,
545 : : planstate,
546 : : inputDesc);
10141 scrappy@hub.org 547 : 361177 : }
548 : :
549 : :
550 : : /* ----------------
551 : : * ExecConditionalAssignProjectionInfo
552 : : *
553 : : * as ExecAssignProjectionInfo, but store NULL rather than building projection
554 : : * info if no projection is required
555 : : * ----------------
556 : : */
557 : : void
2332 rhaas@postgresql.org 558 : 234276 : ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
559 : : int varno)
560 : : {
561 [ + + ]: 234276 : if (tlist_matches_tupdesc(planstate,
562 : 234276 : planstate->plan->targetlist,
563 : : varno,
564 : : inputDesc))
565 : : {
566 : 126481 : planstate->ps_ProjInfo = NULL;
1977 andres@anarazel.de 567 : 126481 : planstate->resultopsset = planstate->scanopsset;
568 : 126481 : planstate->resultopsfixed = planstate->scanopsfixed;
569 : 126481 : planstate->resultops = planstate->scanops;
570 : : }
571 : : else
572 : : {
1983 573 [ + - ]: 107795 : if (!planstate->ps_ResultTupleSlot)
574 : : {
1977 575 : 107795 : ExecInitResultSlot(planstate, &TTSOpsVirtual);
576 : 107795 : planstate->resultops = &TTSOpsVirtual;
577 : 107795 : planstate->resultopsfixed = true;
578 : 107795 : planstate->resultopsset = true;
579 : : }
2332 rhaas@postgresql.org 580 : 107795 : ExecAssignProjectionInfo(planstate, inputDesc);
581 : : }
582 : 234276 : }
583 : :
584 : : static bool
942 tgl@sss.pgh.pa.us 585 : 234276 : tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc)
586 : : {
2332 rhaas@postgresql.org 587 : 234276 : int numattrs = tupdesc->natts;
588 : : int attrno;
589 : 234276 : ListCell *tlist_item = list_head(tlist);
590 : :
591 : : /* Check the tlist attributes */
592 [ + + ]: 1713401 : for (attrno = 1; attrno <= numattrs; attrno++)
593 : : {
594 : 1579840 : Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
595 : : Var *var;
596 : :
597 [ + + ]: 1579840 : if (tlist_item == NULL)
598 : 12889 : return false; /* tlist too short */
599 : 1566951 : var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
600 [ + - + + ]: 1566951 : if (!var || !IsA(var, Var))
601 : 29393 : return false; /* tlist item not a Var */
602 : : /* if these Asserts fail, planner messed up */
603 [ - + ]: 1537558 : Assert(var->varno == varno);
604 [ - + ]: 1537558 : Assert(var->varlevelsup == 0);
605 [ + + ]: 1537558 : if (var->varattno != attrno)
606 : 58286 : return false; /* out of order */
607 [ - + ]: 1479272 : if (att_tup->attisdropped)
2332 rhaas@postgresql.org 608 :UBC 0 : return false; /* table contains dropped columns */
2209 andrew@dunslane.net 609 [ + + ]:CBC 1479272 : if (att_tup->atthasmissing)
610 : 144 : return false; /* table contains cols with missing values */
611 : :
612 : : /*
613 : : * Note: usually the Var's type should match the tupdesc exactly, but
614 : : * in situations involving unions of columns that have different
615 : : * typmods, the Var may have come from above the union and hence have
616 : : * typmod -1. This is a legitimate situation since the Var still
617 : : * describes the column, just not as exactly as the tupdesc does. We
618 : : * could change the planner to prevent it, but it'd then insert
619 : : * projection steps just to convert from specific typmod to typmod -1,
620 : : * which is pretty silly.
621 : : */
2332 rhaas@postgresql.org 622 [ + + ]: 1479128 : if (var->vartype != att_tup->atttypid ||
623 [ + + ]: 1479125 : (var->vartypmod != att_tup->atttypmod &&
624 [ - + ]: 3 : var->vartypmod != -1))
625 : 3 : return false; /* type mismatch */
626 : :
1735 tgl@sss.pgh.pa.us 627 : 1479125 : tlist_item = lnext(tlist, tlist_item);
628 : : }
629 : :
2332 rhaas@postgresql.org 630 [ + + ]: 133561 : if (tlist_item)
631 : 7080 : return false; /* tlist too long */
632 : :
633 : 126481 : return true;
634 : : }
635 : :
636 : :
637 : : /* ----------------------------------------------------------------
638 : : * Scan node support
639 : : * ----------------------------------------------------------------
640 : : */
641 : :
642 : : /* ----------------
643 : : * ExecAssignScanType
644 : : * ----------------
645 : : */
646 : : void
6512 tgl@sss.pgh.pa.us 647 : 376 : ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
648 : : {
7801 649 : 376 : TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
650 : :
6512 651 : 376 : ExecSetSlotDescriptor(slot, tupDesc);
10141 scrappy@hub.org 652 : 376 : }
653 : :
654 : : /* ----------------
655 : : * ExecCreateScanSlotFromOuterPlan
656 : : * ----------------
657 : : */
658 : : void
1977 andres@anarazel.de 659 : 56686 : ExecCreateScanSlotFromOuterPlan(EState *estate,
660 : : ScanState *scanstate,
661 : : const TupleTableSlotOps *tts_ops)
662 : : {
663 : : PlanState *outerPlan;
664 : : TupleDesc tupDesc;
665 : :
7801 tgl@sss.pgh.pa.us 666 : 56686 : outerPlan = outerPlanState(scanstate);
7650 667 : 56686 : tupDesc = ExecGetResultType(outerPlan);
668 : :
1977 andres@anarazel.de 669 : 56686 : ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops);
10141 scrappy@hub.org 670 : 56686 : }
671 : :
672 : : /* ----------------------------------------------------------------
673 : : * ExecRelationIsTargetRelation
674 : : *
675 : : * Detect whether a relation (identified by rangetable index)
676 : : * is one of the target relations of the query.
677 : : *
678 : : * Note: This is currently no longer used in core. We keep it around
679 : : * because FDWs may wish to use it to determine if their foreign table
680 : : * is a target relation.
681 : : * ----------------------------------------------------------------
682 : : */
683 : : bool
6707 tgl@sss.pgh.pa.us 684 :UBC 0 : ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
685 : : {
1279 heikki.linnakangas@i 686 : 0 : return list_member_int(estate->es_plannedstmt->resultRelations, scanrelid);
687 : : }
688 : :
689 : : /* ----------------------------------------------------------------
690 : : * ExecOpenScanRelation
691 : : *
692 : : * Open the heap relation to be scanned by a base-level scan plan node.
693 : : * This should be called during the node's ExecInit routine.
694 : : * ----------------------------------------------------------------
695 : : */
696 : : Relation
4005 tgl@sss.pgh.pa.us 697 :CBC 189113 : ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
698 : : {
699 : : Relation rel;
700 : :
701 : : /* Open the relation. */
2019 702 : 189113 : rel = ExecGetRangeTableRelation(estate, scanrelid);
703 : :
704 : : /*
705 : : * Complain if we're attempting a scan of an unscannable relation, except
706 : : * when the query won't actually be run. This is a slightly klugy place
707 : : * to do this, perhaps, but there is no better place.
708 : : */
4005 709 [ + + ]: 189113 : if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 &&
710 [ + + ]: 173981 : !RelationIsScannable(rel))
711 [ + - ]: 6 : ereport(ERROR,
712 : : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
713 : : errmsg("materialized view \"%s\" has not been populated",
714 : : RelationGetRelationName(rel)),
715 : : errhint("Use the REFRESH MATERIALIZED VIEW command.")));
716 : :
717 : 189107 : return rel;
718 : : }
719 : :
720 : : /*
721 : : * ExecInitRangeTable
722 : : * Set up executor's range-table-related data
723 : : *
724 : : * In addition to the range table proper, initialize arrays that are
725 : : * indexed by rangetable index.
726 : : */
727 : : void
405 728 : 451094 : ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos)
729 : : {
730 : : /* Remember the range table List as-is */
2019 731 : 451094 : estate->es_range_table = rangeTable;
732 : :
733 : : /* ... and the RTEPermissionInfo List too */
405 734 : 451094 : estate->es_rteperminfos = permInfos;
735 : :
736 : : /* Set size of associated arrays */
2019 737 : 451094 : estate->es_range_table_size = list_length(rangeTable);
738 : :
739 : : /*
740 : : * Allocate an array to store an open Relation corresponding to each
741 : : * rangetable entry, and initialize entries to NULL. Relations are opened
742 : : * and stored here as needed.
743 : : */
744 : 451094 : estate->es_relations = (Relation *)
745 : 451094 : palloc0(estate->es_range_table_size * sizeof(Relation));
746 : :
747 : : /*
748 : : * es_result_relations and es_rowmarks are also parallel to
749 : : * es_range_table, but are allocated only if needed.
750 : : */
1279 heikki.linnakangas@i 751 : 451094 : estate->es_result_relations = NULL;
2015 tgl@sss.pgh.pa.us 752 : 451094 : estate->es_rowmarks = NULL;
2019 753 : 451094 : }
754 : :
755 : : /*
756 : : * ExecGetRangeTableRelation
757 : : * Open the Relation for a range table entry, if not already done
758 : : *
759 : : * The Relations will be closed again in ExecEndPlan().
760 : : */
761 : : Relation
762 : 255790 : ExecGetRangeTableRelation(EState *estate, Index rti)
763 : : {
764 : : Relation rel;
765 : :
766 [ + - - + ]: 255790 : Assert(rti > 0 && rti <= estate->es_range_table_size);
767 : :
768 : 255790 : rel = estate->es_relations[rti - 1];
769 [ + + ]: 255790 : if (rel == NULL)
770 : : {
771 : : /* First time through, so open the relation */
772 : 236207 : RangeTblEntry *rte = exec_rt_fetch(rti, estate);
773 : :
774 [ - + ]: 236207 : Assert(rte->rtekind == RTE_RELATION);
775 : :
2017 776 [ + + ]: 236207 : if (!IsParallelWorker())
777 : : {
778 : : /*
779 : : * In a normal query, we should already have the appropriate lock,
780 : : * but verify that through an Assert. Since there's already an
781 : : * Assert inside table_open that insists on holding some lock, it
782 : : * seems sufficient to check this only when rellockmode is higher
783 : : * than the minimum.
784 : : */
1910 andres@anarazel.de 785 : 233895 : rel = table_open(rte->relid, NoLock);
2017 tgl@sss.pgh.pa.us 786 [ + + - + ]: 233895 : Assert(rte->rellockmode == AccessShareLock ||
787 : : CheckRelationLockedByMe(rel, rte->rellockmode, false));
788 : : }
789 : : else
790 : : {
791 : : /*
792 : : * If we are a parallel worker, we need to obtain our own local
793 : : * lock on the relation. This ensures sane behavior in case the
794 : : * parent process exits before we do.
795 : : */
1910 andres@anarazel.de 796 : 2312 : rel = table_open(rte->relid, rte->rellockmode);
797 : : }
798 : :
2017 tgl@sss.pgh.pa.us 799 : 236207 : estate->es_relations[rti - 1] = rel;
800 : : }
801 : :
2019 802 : 255790 : return rel;
803 : : }
804 : :
805 : : /*
806 : : * ExecInitResultRelation
807 : : * Open relation given by the passed-in RT index and fill its
808 : : * ResultRelInfo node
809 : : *
810 : : * Here, we also save the ResultRelInfo in estate->es_result_relations array
811 : : * such that it can be accessed later using the RT index.
812 : : */
813 : : void
1279 heikki.linnakangas@i 814 : 60881 : ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
815 : : Index rti)
816 : : {
817 : : Relation resultRelationDesc;
818 : :
819 : 60881 : resultRelationDesc = ExecGetRangeTableRelation(estate, rti);
820 : 60881 : InitResultRelInfo(resultRelInfo,
821 : : resultRelationDesc,
822 : : rti,
823 : : NULL,
824 : : estate->es_instrument);
825 : :
826 [ + + ]: 60881 : if (estate->es_result_relations == NULL)
827 : 58394 : estate->es_result_relations = (ResultRelInfo **)
828 : 58394 : palloc0(estate->es_range_table_size * sizeof(ResultRelInfo *));
829 : 60881 : estate->es_result_relations[rti - 1] = resultRelInfo;
830 : :
831 : : /*
832 : : * Saving in the list allows to avoid needlessly traversing the whole
833 : : * array when only a few of its entries are possibly non-NULL.
834 : : */
835 : 60881 : estate->es_opened_result_relations =
836 : 60881 : lappend(estate->es_opened_result_relations, resultRelInfo);
837 : 60881 : }
838 : :
839 : : /*
840 : : * UpdateChangedParamSet
841 : : * Add changed parameters to a plan node's chgParam set
842 : : */
843 : : void
7555 bruce@momjian.us 844 : 331549 : UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
845 : : {
846 : : Bitmapset *parmset;
847 : :
848 : : /*
849 : : * The plan node only depends on params listed in its allParam set. Don't
850 : : * include anything else into its chgParam set.
851 : : */
7735 tgl@sss.pgh.pa.us 852 : 331549 : parmset = bms_intersect(node->plan->allParam, newchg);
409 853 : 331549 : node->chgParam = bms_join(node->chgParam, parmset);
9557 vadim4o@yahoo.com 854 : 331549 : }
855 : :
856 : : /*
857 : : * executor_errposition
858 : : * Report an execution-time cursor position, if possible.
859 : : *
860 : : * This is expected to be used within an ereport() call. The return value
861 : : * is a dummy (always 0, in fact).
862 : : *
863 : : * The locations stored in parsetrees are byte offsets into the source string.
864 : : * We have to convert them to 1-based character indexes for reporting to
865 : : * clients. (We do things this way to avoid unnecessary overhead in the
866 : : * normal non-error case: computing character indexes would be much more
867 : : * expensive than storing token offsets.)
868 : : */
869 : : int
2553 tgl@sss.pgh.pa.us 870 :UBC 0 : executor_errposition(EState *estate, int location)
871 : : {
872 : : int pos;
873 : :
874 : : /* No-op if location was not provided */
875 [ # # ]: 0 : if (location < 0)
1481 876 : 0 : return 0;
877 : : /* Can't do anything if source text is not available */
2553 878 [ # # # # ]: 0 : if (estate == NULL || estate->es_sourceText == NULL)
1481 879 : 0 : return 0;
880 : : /* Convert offset to character number */
2553 881 : 0 : pos = pg_mbstrlen_with_len(estate->es_sourceText, location) + 1;
882 : : /* And pass it to the ereport mechanism */
1481 883 : 0 : return errposition(pos);
884 : : }
885 : :
886 : : /*
887 : : * Register a shutdown callback in an ExprContext.
888 : : *
889 : : * Shutdown callbacks will be called (in reverse order of registration)
890 : : * when the ExprContext is deleted or rescanned. This provides a hook
891 : : * for functions called in the context to do any cleanup needed --- it's
892 : : * particularly useful for functions returning sets. Note that the
893 : : * callback will *not* be called in the event that execution is aborted
894 : : * by an error.
895 : : */
896 : : void
8008 tgl@sss.pgh.pa.us 897 :CBC 68293 : RegisterExprContextCallback(ExprContext *econtext,
898 : : ExprContextCallbackFunction function,
899 : : Datum arg)
900 : : {
901 : : ExprContext_CB *ecxt_callback;
902 : :
903 : : /* Save the info in appropriate memory context */
904 : : ecxt_callback = (ExprContext_CB *)
905 : 68293 : MemoryContextAlloc(econtext->ecxt_per_query_memory,
906 : : sizeof(ExprContext_CB));
907 : :
908 : 68293 : ecxt_callback->function = function;
909 : 68293 : ecxt_callback->arg = arg;
910 : :
911 : : /* link to front of list for appropriate execution order */
912 : 68293 : ecxt_callback->next = econtext->ecxt_callbacks;
913 : 68293 : econtext->ecxt_callbacks = ecxt_callback;
914 : 68293 : }
915 : :
916 : : /*
917 : : * Deregister a shutdown callback in an ExprContext.
918 : : *
919 : : * Any list entries matching the function and arg will be removed.
920 : : * This can be used if it's no longer necessary to call the callback.
921 : : */
922 : : void
923 : 58533 : UnregisterExprContextCallback(ExprContext *econtext,
924 : : ExprContextCallbackFunction function,
925 : : Datum arg)
926 : : {
927 : : ExprContext_CB **prev_callback;
928 : : ExprContext_CB *ecxt_callback;
929 : :
930 : 58533 : prev_callback = &econtext->ecxt_callbacks;
931 : :
932 [ + + ]: 166854 : while ((ecxt_callback = *prev_callback) != NULL)
933 : : {
934 [ + + + + ]: 108321 : if (ecxt_callback->function == function && ecxt_callback->arg == arg)
935 : : {
936 : 58533 : *prev_callback = ecxt_callback->next;
937 : 58533 : pfree(ecxt_callback);
938 : : }
939 : : else
940 : 49788 : prev_callback = &ecxt_callback->next;
941 : : }
942 : 58533 : }
943 : :
944 : : /*
945 : : * Call all the shutdown callbacks registered in an ExprContext.
946 : : *
947 : : * The callback list is emptied (important in case this is only a rescan
948 : : * reset, and not deletion of the ExprContext).
949 : : *
950 : : * If isCommit is false, just clean the callback list but don't call 'em.
951 : : * (See comment for FreeExprContext.)
952 : : */
953 : : static void
5384 954 : 2578553 : ShutdownExprContext(ExprContext *econtext, bool isCommit)
955 : : {
956 : : ExprContext_CB *ecxt_callback;
957 : : MemoryContext oldcontext;
958 : :
959 : : /* Fast path in normal case where there's nothing to do. */
7791 960 [ + + ]: 2578553 : if (econtext->ecxt_callbacks == NULL)
961 : 2569845 : return;
962 : :
963 : : /*
964 : : * Call the callbacks in econtext's per-tuple context. This ensures that
965 : : * any memory they might leak will get cleaned up.
966 : : */
967 : 8708 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
968 : :
969 : : /*
970 : : * Call each callback function in reverse registration order.
971 : : */
8008 972 [ + + ]: 17613 : while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
973 : : {
974 : 8905 : econtext->ecxt_callbacks = ecxt_callback->next;
5384 975 [ + - ]: 8905 : if (isCommit)
2411 peter_e@gmx.net 976 : 8905 : ecxt_callback->function(ecxt_callback->arg);
8008 tgl@sss.pgh.pa.us 977 : 8905 : pfree(ecxt_callback);
978 : : }
979 : :
7791 980 : 8708 : MemoryContextSwitchTo(oldcontext);
981 : : }
982 : :
983 : : /*
984 : : * GetAttributeByName
985 : : * GetAttributeByNum
986 : : *
987 : : * These functions return the value of the requested attribute
988 : : * out of the given tuple Datum.
989 : : * C functions which take a tuple as an argument are expected
990 : : * to use these. Ex: overpaid(EMP) might call GetAttributeByNum().
991 : : * Note: these are actually rather slow because they do a typcache
992 : : * lookup on each call.
993 : : */
994 : : Datum
2588 andres@anarazel.de 995 : 18 : GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull)
996 : : {
997 : : AttrNumber attrno;
998 : : Datum result;
999 : : Oid tupType;
1000 : : int32 tupTypmod;
1001 : : TupleDesc tupDesc;
1002 : : HeapTupleData tmptup;
1003 : : int i;
1004 : :
1005 [ - + ]: 18 : if (attname == NULL)
2588 andres@anarazel.de 1006 [ # # ]:UBC 0 : elog(ERROR, "invalid attribute name");
1007 : :
2588 andres@anarazel.de 1008 [ - + ]:CBC 18 : if (isNull == NULL)
2588 andres@anarazel.de 1009 [ # # ]:UBC 0 : elog(ERROR, "a NULL isNull pointer was passed");
1010 : :
2588 andres@anarazel.de 1011 [ - + ]:CBC 18 : if (tuple == NULL)
1012 : : {
1013 : : /* Kinda bogus but compatible with old behavior... */
2588 andres@anarazel.de 1014 :UBC 0 : *isNull = true;
1015 : 0 : return (Datum) 0;
1016 : : }
1017 : :
2588 andres@anarazel.de 1018 :CBC 18 : tupType = HeapTupleHeaderGetTypeId(tuple);
1019 : 18 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
1020 : 18 : tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1021 : :
1022 : 18 : attrno = InvalidAttrNumber;
1023 [ + - ]: 72 : for (i = 0; i < tupDesc->natts; i++)
1024 : : {
2429 1025 : 72 : Form_pg_attribute att = TupleDescAttr(tupDesc, i);
1026 : :
1027 [ + + ]: 72 : if (namestrcmp(&(att->attname), attname) == 0)
1028 : : {
1029 : 18 : attrno = att->attnum;
2588 1030 : 18 : break;
1031 : : }
1032 : : }
1033 : :
1034 [ - + ]: 18 : if (attrno == InvalidAttrNumber)
2588 andres@anarazel.de 1035 [ # # ]:UBC 0 : elog(ERROR, "attribute \"%s\" does not exist", attname);
1036 : :
1037 : : /*
1038 : : * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all
1039 : : * the fields in the struct just in case user tries to inspect system
1040 : : * columns.
1041 : : */
2588 andres@anarazel.de 1042 :CBC 18 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
1043 : 18 : ItemPointerSetInvalid(&(tmptup.t_self));
1044 : 18 : tmptup.t_tableOid = InvalidOid;
1045 : 18 : tmptup.t_data = tuple;
1046 : :
1047 : 18 : result = heap_getattr(&tmptup,
1048 : : attrno,
1049 : : tupDesc,
1050 : : isNull);
1051 : :
1052 [ + - ]: 18 : ReleaseTupleDesc(tupDesc);
1053 : :
1054 : 18 : return result;
1055 : : }
1056 : :
1057 : : Datum
2588 andres@anarazel.de 1058 :UBC 0 : GetAttributeByNum(HeapTupleHeader tuple,
1059 : : AttrNumber attrno,
1060 : : bool *isNull)
1061 : : {
1062 : : Datum result;
1063 : : Oid tupType;
1064 : : int32 tupTypmod;
1065 : : TupleDesc tupDesc;
1066 : : HeapTupleData tmptup;
1067 : :
1068 [ # # ]: 0 : if (!AttributeNumberIsValid(attrno))
1069 [ # # ]: 0 : elog(ERROR, "invalid attribute number %d", attrno);
1070 : :
1071 [ # # ]: 0 : if (isNull == NULL)
1072 [ # # ]: 0 : elog(ERROR, "a NULL isNull pointer was passed");
1073 : :
1074 [ # # ]: 0 : if (tuple == NULL)
1075 : : {
1076 : : /* Kinda bogus but compatible with old behavior... */
1077 : 0 : *isNull = true;
1078 : 0 : return (Datum) 0;
1079 : : }
1080 : :
1081 : 0 : tupType = HeapTupleHeaderGetTypeId(tuple);
1082 : 0 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
1083 : 0 : tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1084 : :
1085 : : /*
1086 : : * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all
1087 : : * the fields in the struct just in case user tries to inspect system
1088 : : * columns.
1089 : : */
1090 : 0 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
1091 : 0 : ItemPointerSetInvalid(&(tmptup.t_self));
1092 : 0 : tmptup.t_tableOid = InvalidOid;
1093 : 0 : tmptup.t_data = tuple;
1094 : :
1095 : 0 : result = heap_getattr(&tmptup,
1096 : : attrno,
1097 : : tupDesc,
1098 : : isNull);
1099 : :
1100 [ # # ]: 0 : ReleaseTupleDesc(tupDesc);
1101 : :
1102 : 0 : return result;
1103 : : }
1104 : :
1105 : : /*
1106 : : * Number of items in a tlist (including any resjunk items!)
1107 : : */
1108 : : int
2588 andres@anarazel.de 1109 :CBC 626583 : ExecTargetListLength(List *targetlist)
1110 : : {
1111 : : /* This used to be more complex, but fjoins are dead */
1112 : 626583 : return list_length(targetlist);
1113 : : }
1114 : :
1115 : : /*
1116 : : * Number of items in a tlist, not including any resjunk items
1117 : : */
1118 : : int
1119 : 94479 : ExecCleanTargetListLength(List *targetlist)
1120 : : {
1121 : 94479 : int len = 0;
1122 : : ListCell *tl;
1123 : :
1124 [ + + + + : 311407 : foreach(tl, targetlist)
+ + ]
1125 : : {
2561 tgl@sss.pgh.pa.us 1126 : 216928 : TargetEntry *curTle = lfirst_node(TargetEntry, tl);
1127 : :
2588 andres@anarazel.de 1128 [ + + ]: 216928 : if (!curTle->resjunk)
1129 : 201931 : len++;
1130 : : }
1131 : 94479 : return len;
1132 : : }
1133 : :
1134 : : /*
1135 : : * Return a relInfo's tuple slot for a trigger's OLD tuples.
1136 : : */
1137 : : TupleTableSlot *
1874 1138 : 11861 : ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
1139 : : {
1140 [ + + ]: 11861 : if (relInfo->ri_TrigOldSlot == NULL)
1141 : : {
1142 : 4921 : Relation rel = relInfo->ri_RelationDesc;
1143 : 4921 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1144 : :
1145 : 4921 : relInfo->ri_TrigOldSlot =
1146 : 4921 : ExecInitExtraTupleSlot(estate,
1147 : : RelationGetDescr(rel),
1148 : : table_slot_callbacks(rel));
1149 : :
1150 : 4921 : MemoryContextSwitchTo(oldcontext);
1151 : : }
1152 : :
1153 : 11861 : return relInfo->ri_TrigOldSlot;
1154 : : }
1155 : :
1156 : : /*
1157 : : * Return a relInfo's tuple slot for a trigger's NEW tuples.
1158 : : */
1159 : : TupleTableSlot *
1160 : 1713 : ExecGetTriggerNewSlot(EState *estate, ResultRelInfo *relInfo)
1161 : : {
1162 [ + + ]: 1713 : if (relInfo->ri_TrigNewSlot == NULL)
1163 : : {
1164 : 1067 : Relation rel = relInfo->ri_RelationDesc;
1165 : 1067 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1166 : :
1167 : 1067 : relInfo->ri_TrigNewSlot =
1168 : 1067 : ExecInitExtraTupleSlot(estate,
1169 : : RelationGetDescr(rel),
1170 : : table_slot_callbacks(rel));
1171 : :
1172 : 1067 : MemoryContextSwitchTo(oldcontext);
1173 : : }
1174 : :
1175 : 1713 : return relInfo->ri_TrigNewSlot;
1176 : : }
1177 : :
1178 : : /*
1179 : : * Return a relInfo's tuple slot for processing returning tuples.
1180 : : */
1181 : : TupleTableSlot *
1182 : 546 : ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
1183 : : {
1184 [ + + ]: 546 : if (relInfo->ri_ReturningSlot == NULL)
1185 : : {
1186 : 242 : Relation rel = relInfo->ri_RelationDesc;
1187 : 242 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1188 : :
1189 : 242 : relInfo->ri_ReturningSlot =
1190 : 242 : ExecInitExtraTupleSlot(estate,
1191 : : RelationGetDescr(rel),
1192 : : table_slot_callbacks(rel));
1193 : :
1194 : 242 : MemoryContextSwitchTo(oldcontext);
1195 : : }
1196 : :
1197 : 546 : return relInfo->ri_ReturningSlot;
1198 : : }
1199 : :
1200 : : /*
1201 : : * Return the map needed to convert given child result relation's tuples to
1202 : : * the rowtype of the query's main target ("root") relation. Note that a
1203 : : * NULL result is valid and means that no conversion is needed.
1204 : : */
1205 : : TupleConversionMap *
1104 tgl@sss.pgh.pa.us 1206 : 33850 : ExecGetChildToRootMap(ResultRelInfo *resultRelInfo)
1207 : : {
1208 : : /* If we didn't already do so, compute the map for this child. */
1209 [ + + ]: 33850 : if (!resultRelInfo->ri_ChildToRootMapValid)
1210 : : {
1211 : 790 : ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1212 : :
1213 [ + + ]: 790 : if (rootRelInfo)
1214 : 607 : resultRelInfo->ri_ChildToRootMap =
1215 : 607 : convert_tuples_by_name(RelationGetDescr(resultRelInfo->ri_RelationDesc),
1216 : 607 : RelationGetDescr(rootRelInfo->ri_RelationDesc));
1217 : : else /* this isn't a child result rel */
1218 : 183 : resultRelInfo->ri_ChildToRootMap = NULL;
1219 : :
1220 : 790 : resultRelInfo->ri_ChildToRootMapValid = true;
1221 : : }
1222 : :
1223 : 33850 : return resultRelInfo->ri_ChildToRootMap;
1224 : : }
1225 : :
1226 : : /*
1227 : : * Returns the map needed to convert given root result relation's tuples to
1228 : : * the rowtype of the given child relation. Note that a NULL result is valid
1229 : : * and means that no conversion is needed.
1230 : : */
1231 : : TupleConversionMap *
499 alvherre@alvh.no-ip. 1232 : 504563 : ExecGetRootToChildMap(ResultRelInfo *resultRelInfo, EState *estate)
1233 : : {
1234 : : /* Mustn't get called for a non-child result relation. */
1235 [ - + ]: 504563 : Assert(resultRelInfo->ri_RootResultRelInfo);
1236 : :
1237 : : /* If we didn't already do so, compute the map for this child. */
1238 [ + + ]: 504563 : if (!resultRelInfo->ri_RootToChildMapValid)
1239 : : {
1240 : 5129 : ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1241 : 5129 : TupleDesc indesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
1242 : 5129 : TupleDesc outdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
1243 : 5129 : Relation childrel = resultRelInfo->ri_RelationDesc;
1244 : : AttrMap *attrMap;
1245 : : MemoryContext oldcontext;
1246 : :
1247 : : /*
1248 : : * When this child table is not a partition (!relispartition), it may
1249 : : * have columns that are not present in the root table, which we ask
1250 : : * to ignore by passing true for missing_ok.
1251 : : */
1252 : 5129 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1253 : 5129 : attrMap = build_attrmap_by_name_if_req(indesc, outdesc,
1254 : 5129 : !childrel->rd_rel->relispartition);
1255 [ + + ]: 5129 : if (attrMap)
1256 : 718 : resultRelInfo->ri_RootToChildMap =
1257 : 718 : convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
1258 : 5129 : MemoryContextSwitchTo(oldcontext);
1259 : 5129 : resultRelInfo->ri_RootToChildMapValid = true;
1260 : : }
1261 : :
1262 : 504563 : return resultRelInfo->ri_RootToChildMap;
1263 : : }
1264 : :
1265 : : /* Return a bitmap representing columns being inserted */
1266 : : Bitmapset *
1161 heikki.linnakangas@i 1267 : 593 : ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
1268 : : {
495 alvherre@alvh.no-ip. 1269 : 593 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
1270 : :
1271 [ - + ]: 593 : if (perminfo == NULL)
495 alvherre@alvh.no-ip. 1272 :UBC 0 : return NULL;
1273 : :
1274 : : /* Map the columns to child's attribute numbers if needed. */
495 alvherre@alvh.no-ip. 1275 [ - + ]:CBC 593 : if (relinfo->ri_RootResultRelInfo)
1276 : : {
499 alvherre@alvh.no-ip. 1277 :UBC 0 : TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
1278 : :
495 1279 [ # # ]: 0 : if (map)
1280 : 0 : return execute_attr_map_cols(map->attrMap, perminfo->insertedCols);
1281 : : }
1282 : :
495 alvherre@alvh.no-ip. 1283 :CBC 593 : return perminfo->insertedCols;
1284 : : }
1285 : :
1286 : : /* Return a bitmap representing columns being updated */
1287 : : Bitmapset *
1161 heikki.linnakangas@i 1288 : 29837 : ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1289 : : {
495 alvherre@alvh.no-ip. 1290 : 29837 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
1291 : :
1292 [ - + ]: 29837 : if (perminfo == NULL)
495 alvherre@alvh.no-ip. 1293 :UBC 0 : return NULL;
1294 : :
1295 : : /* Map the columns to child's attribute numbers if needed. */
495 alvherre@alvh.no-ip. 1296 [ + + ]:CBC 29837 : if (relinfo->ri_RootResultRelInfo)
1297 : : {
499 1298 : 852 : TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
1299 : :
495 1300 [ + + ]: 852 : if (map)
1301 : 243 : return execute_attr_map_cols(map->attrMap, perminfo->updatedCols);
1302 : : }
1303 : :
1304 : 29594 : return perminfo->updatedCols;
1305 : : }
1306 : :
1307 : : /* Return a bitmap representing generated columns being updated */
1308 : : Bitmapset *
1161 heikki.linnakangas@i 1309 : 29142 : ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1310 : : {
1311 : : /* Compute the info if we didn't already */
405 tgl@sss.pgh.pa.us 1312 [ + + ]: 29142 : if (relinfo->ri_GeneratedExprsU == NULL)
455 1313 : 29082 : ExecInitStoredGenerated(relinfo, estate, CMD_UPDATE);
465 1314 : 29142 : return relinfo->ri_extraUpdatedCols;
1315 : : }
1316 : :
1317 : : /*
1318 : : * Return columns being updated, including generated columns
1319 : : *
1320 : : * The bitmap is allocated in per-tuple memory context. It's up to the caller to
1321 : : * copy it into a different context with the appropriate lifespan, if needed.
1322 : : */
1323 : : Bitmapset *
1161 heikki.linnakangas@i 1324 : 7275 : ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1325 : : {
1326 : : Bitmapset *ret;
1327 : : MemoryContext oldcxt;
1328 : :
312 tomas.vondra@postgre 1329 [ + + ]: 7275 : oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
1330 : :
1331 : 7275 : ret = bms_union(ExecGetUpdatedCols(relinfo, estate),
1332 : 7275 : ExecGetExtraUpdatedCols(relinfo, estate));
1333 : :
1334 : 7275 : MemoryContextSwitchTo(oldcxt);
1335 : :
1336 : 7275 : return ret;
1337 : : }
1338 : :
1339 : : /*
1340 : : * GetResultRTEPermissionInfo
1341 : : * Looks up RTEPermissionInfo for ExecGet*Cols() routines
1342 : : */
1343 : : static RTEPermissionInfo *
495 alvherre@alvh.no-ip. 1344 : 30599 : GetResultRTEPermissionInfo(ResultRelInfo *relinfo, EState *estate)
1345 : : {
1346 : : Index rti;
1347 : : RangeTblEntry *rte;
1348 : 30599 : RTEPermissionInfo *perminfo = NULL;
1349 : :
1350 [ + + ]: 30599 : if (relinfo->ri_RootResultRelInfo)
1351 : : {
1352 : : /*
1353 : : * For inheritance child result relations (a partition routing target
1354 : : * of an INSERT or a child UPDATE target), this returns the root
1355 : : * parent's RTE to fetch the RTEPermissionInfo because that's the only
1356 : : * one that has one assigned.
1357 : : */
1358 : 900 : rti = relinfo->ri_RootResultRelInfo->ri_RangeTableIndex;
1359 : : }
1360 [ + - ]: 29699 : else if (relinfo->ri_RangeTableIndex != 0)
1361 : : {
1362 : : /*
1363 : : * Non-child result relation should have their own RTEPermissionInfo.
1364 : : */
1365 : 29699 : rti = relinfo->ri_RangeTableIndex;
1366 : : }
1367 : : else
1368 : : {
1369 : : /*
1370 : : * The relation isn't in the range table and it isn't a partition
1371 : : * routing target. This ResultRelInfo must've been created only for
1372 : : * firing triggers and the relation is not being inserted into. (See
1373 : : * ExecGetTriggerResultRel.)
1374 : : */
495 alvherre@alvh.no-ip. 1375 :UBC 0 : rti = 0;
1376 : : }
1377 : :
495 alvherre@alvh.no-ip. 1378 [ + - ]:CBC 30599 : if (rti > 0)
1379 : : {
1380 : 30599 : rte = exec_rt_fetch(rti, estate);
1381 : 30599 : perminfo = getRTEPermissionInfo(estate->es_rteperminfos, rte);
1382 : : }
1383 : :
1384 : 30599 : return perminfo;
1385 : : }
1386 : :
1387 : : /*
1388 : : * ExecGetResultRelCheckAsUser
1389 : : * Returns the user to modify passed-in result relation as
1390 : : *
1391 : : * The user is chosen by looking up the relation's or, if a child table, its
1392 : : * root parent's RTEPermissionInfo.
1393 : : */
1394 : : Oid
1395 : 169 : ExecGetResultRelCheckAsUser(ResultRelInfo *relInfo, EState *estate)
1396 : : {
1397 : 169 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relInfo, estate);
1398 : :
1399 : : /* XXX - maybe ok to return GetUserId() in this case? */
1400 [ - + ]: 169 : if (perminfo == NULL)
495 alvherre@alvh.no-ip. 1401 [ # # ]:UBC 0 : elog(ERROR, "no RTEPermissionInfo found for result relation with OID %u",
1402 : : RelationGetRelid(relInfo->ri_RelationDesc));
1403 : :
495 alvherre@alvh.no-ip. 1404 [ + + ]:CBC 169 : return perminfo->checkAsUser ? perminfo->checkAsUser : GetUserId();
1405 : : }
|