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-2025, 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 *
8301 tgl@sss.pgh.pa.us 88 :CBC 599377 : 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 : 599377 : 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 : 599377 : oldcontext = MemoryContextSwitchTo(qcontext);
106 : :
107 : 599377 : estate = makeNode(EState);
108 : :
109 : : /*
110 : : * Initialize all fields of the Executor State structure
111 : : */
112 : 599377 : estate->es_direction = ForwardScanDirection;
2999 113 : 599377 : estate->es_snapshot = InvalidSnapshot; /* caller must initialize this */
7665 114 : 599377 : estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */
8301 115 : 599377 : estate->es_range_table = NIL;
2529 116 : 599377 : estate->es_range_table_size = 0;
117 : 599377 : estate->es_relations = NULL;
2525 118 : 599377 : estate->es_rowmarks = NULL;
915 119 : 599377 : estate->es_rteperminfos = NIL;
5794 120 : 599377 : estate->es_plannedstmt = NULL;
219 amitlan@postgresql.o 121 : 599377 : estate->es_part_prune_infos = NIL;
122 : :
5808 tgl@sss.pgh.pa.us 123 : 599377 : estate->es_junkFilter = NULL;
124 : :
6490 125 : 599377 : estate->es_output_cid = (CommandId) 0;
126 : :
8301 127 : 599377 : estate->es_result_relations = NULL;
1789 heikki.linnakangas@i 128 : 599377 : estate->es_opened_result_relations = NIL;
2767 rhaas@postgresql.org 129 : 599377 : estate->es_tuple_routing_result_relations = NIL;
6597 tgl@sss.pgh.pa.us 130 : 599377 : estate->es_trig_target_relations = NIL;
131 : :
1003 efujita@postgresql.o 132 : 599377 : estate->es_insert_pending_result_relations = NIL;
133 : 599377 : estate->es_insert_pending_modifytables = NIL;
134 : :
8301 tgl@sss.pgh.pa.us 135 : 599377 : estate->es_param_list_info = NULL;
136 : 599377 : estate->es_param_exec_vals = NULL;
137 : :
3081 kgrittn@postgresql.o 138 : 599377 : estate->es_queryEnv = NULL;
139 : :
8301 tgl@sss.pgh.pa.us 140 : 599377 : estate->es_query_cxt = qcontext;
141 : :
5823 142 : 599377 : estate->es_tupleTable = NIL;
143 : :
8301 144 : 599377 : estate->es_processed = 0;
884 michael@paquier.xyz 145 : 599377 : estate->es_total_processed = 0;
146 : :
5305 tgl@sss.pgh.pa.us 147 : 599377 : estate->es_top_eflags = 0;
148 : 599377 : estate->es_instrument = 0;
149 : 599377 : estate->es_finished = false;
150 : :
8301 151 : 599377 : estate->es_exprcontexts = NIL;
152 : :
6766 153 : 599377 : estate->es_subplanstates = NIL;
154 : :
5307 155 : 599377 : estate->es_auxmodifytables = NIL;
156 : :
8301 157 : 599377 : estate->es_per_tuple_exprcontext = NULL;
158 : :
3118 rhaas@postgresql.org 159 : 599377 : estate->es_sourceText = NULL;
160 : :
2871 161 : 599377 : estate->es_use_parallel_mode = false;
332 michael@paquier.xyz 162 : 599377 : estate->es_parallel_workers_to_launch = 0;
163 : 599377 : estate->es_parallel_workers_launched = 0;
164 : :
2725 andres@anarazel.de 165 : 599377 : estate->es_jit_flags = 0;
166 : 599377 : estate->es_jit = NULL;
167 : :
168 : : /*
169 : : * Return the executor state structure
170 : : */
8301 tgl@sss.pgh.pa.us 171 : 599377 : MemoryContextSwitchTo(oldcontext);
172 : :
173 : 599377 : return estate;
174 : : }
175 : :
176 : : /* ----------------
177 : : * FreeExecutorState
178 : : *
179 : : * Release an EState along with all remaining working storage.
180 : : *
181 : : * Note: this is not responsible for releasing non-memory resources, such as
182 : : * open relations or buffer pins. But it will shut down any still-active
183 : : * ExprContexts within the EState and deallocate associated JITed expressions.
184 : : * That is sufficient cleanup for situations where the EState has only been
185 : : * used for expression evaluation, and not to run a complete Plan.
186 : : *
187 : : * This can be called in any memory context ... so long as it's not one
188 : : * of the ones to be freed.
189 : : * ----------------
190 : : */
191 : : void
192 : 581718 : FreeExecutorState(EState *estate)
193 : : {
194 : : /*
195 : : * Shut down and free any remaining ExprContexts. We do this explicitly
196 : : * to ensure that any remaining shutdown callbacks get called (since they
197 : : * might need to release resources that aren't simply memory within the
198 : : * per-query memory context).
199 : : */
200 [ + + ]: 1521733 : while (estate->es_exprcontexts)
201 : : {
202 : : /*
203 : : * XXX: seems there ought to be a faster way to implement this than
204 : : * repeated list_delete(), no?
205 : : */
5894 206 : 940015 : FreeExprContext((ExprContext *) linitial(estate->es_exprcontexts),
207 : : true);
208 : : /* FreeExprContext removed the list link for us */
209 : : }
210 : :
211 : : /* release JIT context, if allocated */
2600 andres@anarazel.de 212 [ - + ]: 581718 : if (estate->es_jit)
213 : : {
2600 andres@anarazel.de 214 :UBC 0 : jit_release_context(estate->es_jit);
215 : 0 : estate->es_jit = NULL;
216 : : }
217 : :
218 : : /* release partition directory, if allocated */
2375 rhaas@postgresql.org 219 [ + + ]:CBC 581718 : if (estate->es_partition_directory)
220 : : {
221 : 2488 : DestroyPartitionDirectory(estate->es_partition_directory);
222 : 2488 : estate->es_partition_directory = NULL;
223 : : }
224 : :
225 : : /*
226 : : * Free the per-query memory context, thereby releasing all working
227 : : * memory, including the EState node itself.
228 : : */
6766 tgl@sss.pgh.pa.us 229 : 581718 : MemoryContextDelete(estate->es_query_cxt);
10651 scrappy@hub.org 230 : 581718 : }
231 : :
232 : : /*
233 : : * Internal implementation for CreateExprContext() and CreateWorkExprContext()
234 : : * that allows control over the AllocSet parameters.
235 : : */
236 : : static ExprContext *
1978 jdavis@postgresql.or 237 : 1008591 : CreateExprContextInternal(EState *estate, Size minContextSize,
238 : : Size initBlockSize, Size maxBlockSize)
239 : : {
240 : : ExprContext *econtext;
241 : : MemoryContext oldcontext;
242 : :
243 : : /* Create the ExprContext node within the per-query memory context */
8301 tgl@sss.pgh.pa.us 244 : 1008591 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
245 : :
246 : 1008591 : econtext = makeNode(ExprContext);
247 : :
248 : : /* Initialize fields of ExprContext */
249 : 1008591 : econtext->ecxt_scantuple = NULL;
9187 250 : 1008591 : econtext->ecxt_innertuple = NULL;
251 : 1008591 : econtext->ecxt_outertuple = NULL;
252 : :
8301 253 : 1008591 : econtext->ecxt_per_query_memory = estate->es_query_cxt;
254 : :
255 : : /*
256 : : * Create working memory for expression evaluation in this context.
257 : : */
9187 258 : 1008591 : econtext->ecxt_per_tuple_memory =
8301 259 : 1008591 : AllocSetContextCreate(estate->es_query_cxt,
260 : : "ExprContext",
261 : : minContextSize,
262 : : initBlockSize,
263 : : maxBlockSize);
264 : :
265 : 1008591 : econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
266 : 1008591 : econtext->ecxt_param_list_info = estate->es_param_list_info;
267 : :
9187 268 : 1008591 : econtext->ecxt_aggvalues = NULL;
269 : 1008591 : econtext->ecxt_aggnulls = NULL;
270 : :
7843 271 : 1008591 : econtext->caseValue_datum = (Datum) 0;
272 : 1008591 : econtext->caseValue_isNull = true;
273 : :
8301 274 : 1008591 : econtext->domainValue_datum = (Datum) 0;
275 : 1008591 : econtext->domainValue_isNull = true;
276 : :
277 : 1008591 : econtext->ecxt_estate = estate;
278 : :
8518 279 : 1008591 : econtext->ecxt_callbacks = NULL;
280 : :
281 : : /*
282 : : * Link the ExprContext into the EState to ensure it is shut down when the
283 : : * EState is freed. Because we use lcons(), shutdowns will occur in
284 : : * reverse order of creation, which may not be essential but can't hurt.
285 : : */
8301 286 : 1008591 : estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
287 : :
288 : 1008591 : MemoryContextSwitchTo(oldcontext);
289 : :
9187 290 : 1008591 : return econtext;
291 : : }
292 : :
293 : : /* ----------------
294 : : * CreateExprContext
295 : : *
296 : : * Create a context for expression evaluation within an EState.
297 : : *
298 : : * An executor run may require multiple ExprContexts (we usually make one
299 : : * for each Plan node, and a separate one for per-output-tuple processing
300 : : * such as constraint checking). Each ExprContext has its own "per-tuple"
301 : : * memory context.
302 : : *
303 : : * Note we make no assumption about the caller's memory context.
304 : : * ----------------
305 : : */
306 : : ExprContext *
1978 jdavis@postgresql.or 307 : 1005759 : CreateExprContext(EState *estate)
308 : : {
309 : 1005759 : return CreateExprContextInternal(estate, ALLOCSET_DEFAULT_SIZES);
310 : : }
311 : :
312 : :
313 : : /* ----------------
314 : : * CreateWorkExprContext
315 : : *
316 : : * Like CreateExprContext, but specifies the AllocSet sizes to be reasonable
317 : : * in proportion to work_mem. If the maximum block allocation size is too
318 : : * large, it's easy to skip right past work_mem with a single allocation.
319 : : * ----------------
320 : : */
321 : : ExprContext *
322 : 2832 : CreateWorkExprContext(EState *estate)
323 : : {
1941 tgl@sss.pgh.pa.us 324 : 2832 : Size maxBlockSize = ALLOCSET_DEFAULT_MAXSIZE;
325 : :
166 jdavis@postgresql.or 326 : 2832 : maxBlockSize = pg_prevpower2_size_t(work_mem * (Size) 1024 / 16);
327 : :
328 : : /* But no bigger than ALLOCSET_DEFAULT_MAXSIZE */
329 : 2832 : maxBlockSize = Min(maxBlockSize, ALLOCSET_DEFAULT_MAXSIZE);
330 : :
331 : : /* and no smaller than ALLOCSET_DEFAULT_INITSIZE */
332 : 2832 : maxBlockSize = Max(maxBlockSize, ALLOCSET_DEFAULT_INITSIZE);
333 : :
334 : 2832 : return CreateExprContextInternal(estate, ALLOCSET_DEFAULT_MINSIZE,
335 : : ALLOCSET_DEFAULT_INITSIZE, maxBlockSize);
336 : : }
337 : :
338 : : /* ----------------
339 : : * CreateStandaloneExprContext
340 : : *
341 : : * Create a context for standalone expression evaluation.
342 : : *
343 : : * An ExprContext made this way can be used for evaluation of expressions
344 : : * that contain no Params, subplans, or Var references (it might work to
345 : : * put tuple references into the scantuple field, but it seems unwise).
346 : : *
347 : : * The ExprContext struct is allocated in the caller's current memory
348 : : * context, which also becomes its "per query" context.
349 : : *
350 : : * It is caller's responsibility to free the ExprContext when done,
351 : : * or at least ensure that any shutdown callbacks have been called
352 : : * (ReScanExprContext() is suitable). Otherwise, non-memory resources
353 : : * might be leaked.
354 : : * ----------------
355 : : */
356 : : ExprContext *
6973 tgl@sss.pgh.pa.us 357 : 4454 : CreateStandaloneExprContext(void)
358 : : {
359 : : ExprContext *econtext;
360 : :
361 : : /* Create the ExprContext node within the caller's memory context */
362 : 4454 : econtext = makeNode(ExprContext);
363 : :
364 : : /* Initialize fields of ExprContext */
365 : 4454 : econtext->ecxt_scantuple = NULL;
366 : 4454 : econtext->ecxt_innertuple = NULL;
367 : 4454 : econtext->ecxt_outertuple = NULL;
368 : :
369 : 4454 : econtext->ecxt_per_query_memory = CurrentMemoryContext;
370 : :
371 : : /*
372 : : * Create working memory for expression evaluation in this context.
373 : : */
374 : 4454 : econtext->ecxt_per_tuple_memory =
375 : 4454 : AllocSetContextCreate(CurrentMemoryContext,
376 : : "ExprContext",
377 : : ALLOCSET_DEFAULT_SIZES);
378 : :
379 : 4454 : econtext->ecxt_param_exec_vals = NULL;
380 : 4454 : econtext->ecxt_param_list_info = NULL;
381 : :
382 : 4454 : econtext->ecxt_aggvalues = NULL;
383 : 4454 : econtext->ecxt_aggnulls = NULL;
384 : :
385 : 4454 : econtext->caseValue_datum = (Datum) 0;
386 : 4454 : econtext->caseValue_isNull = true;
387 : :
388 : 4454 : econtext->domainValue_datum = (Datum) 0;
389 : 4454 : econtext->domainValue_isNull = true;
390 : :
391 : 4454 : econtext->ecxt_estate = NULL;
392 : :
393 : 4454 : econtext->ecxt_callbacks = NULL;
394 : :
395 : 4454 : return econtext;
396 : : }
397 : :
398 : : /* ----------------
399 : : * FreeExprContext
400 : : *
401 : : * Free an expression context, including calling any remaining
402 : : * shutdown callbacks.
403 : : *
404 : : * Since we free the temporary context used for expression evaluation,
405 : : * any previously computed pass-by-reference expression result will go away!
406 : : *
407 : : * If isCommit is false, we are being called in error cleanup, and should
408 : : * not call callbacks but only release memory. (It might be better to call
409 : : * the callbacks and pass the isCommit flag to them, but that would require
410 : : * more invasive code changes than currently seems justified.)
411 : : *
412 : : * Note we make no assumption about the caller's memory context.
413 : : * ----------------
414 : : */
415 : : void
5894 416 : 987665 : FreeExprContext(ExprContext *econtext, bool isCommit)
417 : : {
418 : : EState *estate;
419 : :
420 : : /* Call any registered callbacks */
421 : 987665 : ShutdownExprContext(econtext, isCommit);
422 : : /* And clean up the memory used */
9187 423 : 987665 : MemoryContextDelete(econtext->ecxt_per_tuple_memory);
424 : : /* Unlink self from owning EState, if any */
8301 425 : 987665 : estate = econtext->ecxt_estate;
6973 426 [ + - ]: 987665 : if (estate)
427 : 987665 : estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts,
428 : : econtext);
429 : : /* And delete the ExprContext node */
9187 430 : 987665 : pfree(econtext);
10651 scrappy@hub.org 431 : 987665 : }
432 : :
433 : : /*
434 : : * ReScanExprContext
435 : : *
436 : : * Reset an expression context in preparation for a rescan of its
437 : : * plan node. This requires calling any registered shutdown callbacks,
438 : : * since any partially complete set-returning-functions must be canceled.
439 : : *
440 : : * Note we make no assumption about the caller's memory context.
441 : : */
442 : : void
7933 tgl@sss.pgh.pa.us 443 : 2023583 : ReScanExprContext(ExprContext *econtext)
444 : : {
445 : : /* Call any registered callbacks */
5894 446 : 2023583 : ShutdownExprContext(econtext, true);
447 : : /* And clean up the memory used */
7933 448 : 2023583 : MemoryContextReset(econtext->ecxt_per_tuple_memory);
449 : 2023583 : }
450 : :
451 : : /*
452 : : * Build a per-output-tuple ExprContext for an EState.
453 : : *
454 : : * This is normally invoked via GetPerTupleExprContext() macro,
455 : : * not directly.
456 : : */
457 : : ExprContext *
8993 458 : 327540 : MakePerTupleExprContext(EState *estate)
459 : : {
460 [ + - ]: 327540 : if (estate->es_per_tuple_exprcontext == NULL)
8301 461 : 327540 : estate->es_per_tuple_exprcontext = CreateExprContext(estate);
462 : :
8993 463 : 327540 : return estate->es_per_tuple_exprcontext;
464 : : }
465 : :
466 : :
467 : : /* ----------------------------------------------------------------
468 : : * miscellaneous node-init support functions
469 : : *
470 : : * Note: all of these are expected to be called with CurrentMemoryContext
471 : : * equal to the per-query memory context.
472 : : * ----------------------------------------------------------------
473 : : */
474 : :
475 : : /* ----------------
476 : : * ExecAssignExprContext
477 : : *
478 : : * This initializes the ps_ExprContext field. It is only necessary
479 : : * to do this for nodes which use ExecQual or ExecProject
480 : : * because those routines require an econtext. Other nodes that
481 : : * don't have to evaluate expressions don't need to do this.
482 : : * ----------------
483 : : */
484 : : void
8065 bruce@momjian.us 485 : 619353 : ExecAssignExprContext(EState *estate, PlanState *planstate)
486 : : {
8301 tgl@sss.pgh.pa.us 487 : 619353 : planstate->ps_ExprContext = CreateExprContext(estate);
488 : 619353 : }
489 : :
490 : : /* ----------------
491 : : * ExecGetResultType
492 : : * ----------------
493 : : */
494 : : TupleDesc
8065 bruce@momjian.us 495 : 768448 : ExecGetResultType(PlanState *planstate)
496 : : {
2493 andres@anarazel.de 497 : 768448 : return planstate->ps_ResultTupleDesc;
498 : : }
499 : :
500 : : /*
501 : : * ExecGetResultSlotOps - information about node's type of result slot
502 : : */
503 : : const TupleTableSlotOps *
2487 504 : 316574 : ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
505 : : {
506 [ + - + + ]: 316574 : if (planstate->resultopsset && planstate->resultops)
507 : : {
508 [ + + ]: 315786 : if (isfixed)
509 : 289885 : *isfixed = planstate->resultopsfixed;
510 : 315786 : return planstate->resultops;
511 : : }
512 : :
513 [ + + ]: 788 : if (isfixed)
514 : : {
515 [ + - ]: 773 : if (planstate->resultopsset)
516 : 773 : *isfixed = planstate->resultopsfixed;
2487 andres@anarazel.de 517 [ # # ]:UBC 0 : else if (planstate->ps_ResultTupleSlot)
518 : 0 : *isfixed = TTS_FIXED(planstate->ps_ResultTupleSlot);
519 : : else
520 : 0 : *isfixed = false;
521 : : }
522 : :
2487 andres@anarazel.de 523 [ + - ]:CBC 788 : if (!planstate->ps_ResultTupleSlot)
524 : 788 : return &TTSOpsVirtual;
525 : :
2487 andres@anarazel.de 526 :UBC 0 : return planstate->ps_ResultTupleSlot->tts_ops;
527 : : }
528 : :
529 : : /*
530 : : * ExecGetCommonSlotOps - identify common result slot type, if any
531 : : *
532 : : * If all the given PlanState nodes return the same fixed tuple slot type,
533 : : * return the slot ops struct for that slot type. Else, return NULL.
534 : : */
535 : : const TupleTableSlotOps *
261 tgl@sss.pgh.pa.us 536 :CBC 9339 : ExecGetCommonSlotOps(PlanState **planstates, int nplans)
537 : : {
538 : : const TupleTableSlotOps *result;
539 : : bool isfixed;
540 : :
541 [ + + ]: 9339 : if (nplans <= 0)
542 : 51 : return NULL;
543 : 9288 : result = ExecGetResultSlotOps(planstates[0], &isfixed);
544 [ + + ]: 9288 : if (!isfixed)
545 : 55 : return NULL;
546 [ + + ]: 24527 : for (int i = 1; i < nplans; i++)
547 : : {
548 : : const TupleTableSlotOps *thisops;
549 : :
550 : 15798 : thisops = ExecGetResultSlotOps(planstates[i], &isfixed);
551 [ + + ]: 15798 : if (!isfixed)
552 : 21 : return NULL;
553 [ + + ]: 15777 : if (result != thisops)
554 : 483 : return NULL;
555 : : }
556 : 8729 : return result;
557 : : }
558 : :
559 : : /*
560 : : * ExecGetCommonChildSlotOps - as above, for the PlanState's standard children
561 : : */
562 : : const TupleTableSlotOps *
563 : 379 : ExecGetCommonChildSlotOps(PlanState *ps)
564 : : {
565 : : PlanState *planstates[2];
566 : :
567 : 379 : planstates[0] = outerPlanState(ps);
568 : 379 : planstates[1] = innerPlanState(ps);
569 : 379 : return ExecGetCommonSlotOps(planstates, 2);
570 : : }
571 : :
572 : :
573 : : /* ----------------
574 : : * ExecAssignProjectionInfo
575 : : *
576 : : * forms the projection information from the node's targetlist
577 : : *
578 : : * Notes for inputDesc are same as for ExecBuildProjectionInfo: supply it
579 : : * for a relation-scan node, can pass NULL for upper-level nodes
580 : : * ----------------
581 : : */
582 : : void
6791 583 : 350201 : ExecAssignProjectionInfo(PlanState *planstate,
584 : : TupleDesc inputDesc)
585 : : {
8273 586 : 350167 : planstate->ps_ProjInfo =
3098 andres@anarazel.de 587 : 350201 : ExecBuildProjectionInfo(planstate->plan->targetlist,
588 : : planstate->ps_ExprContext,
589 : : planstate->ps_ResultTupleSlot,
590 : : planstate,
591 : : inputDesc);
10651 scrappy@hub.org 592 : 350167 : }
593 : :
594 : :
595 : : /* ----------------
596 : : * ExecConditionalAssignProjectionInfo
597 : : *
598 : : * as ExecAssignProjectionInfo, but store NULL rather than building projection
599 : : * info if no projection is required
600 : : * ----------------
601 : : */
602 : : void
2842 rhaas@postgresql.org 603 : 263391 : ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
604 : : int varno)
605 : : {
606 [ + + ]: 263391 : if (tlist_matches_tupdesc(planstate,
607 : 263391 : planstate->plan->targetlist,
608 : : varno,
609 : : inputDesc))
610 : : {
611 : 141688 : planstate->ps_ProjInfo = NULL;
2487 andres@anarazel.de 612 : 141688 : planstate->resultopsset = planstate->scanopsset;
613 : 141688 : planstate->resultopsfixed = planstate->scanopsfixed;
614 : 141688 : planstate->resultops = planstate->scanops;
615 : : }
616 : : else
617 : : {
2493 618 [ + - ]: 121703 : if (!planstate->ps_ResultTupleSlot)
619 : : {
2487 620 : 121703 : ExecInitResultSlot(planstate, &TTSOpsVirtual);
621 : 121703 : planstate->resultops = &TTSOpsVirtual;
622 : 121703 : planstate->resultopsfixed = true;
623 : 121703 : planstate->resultopsset = true;
624 : : }
2842 rhaas@postgresql.org 625 : 121703 : ExecAssignProjectionInfo(planstate, inputDesc);
626 : : }
627 : 263391 : }
628 : :
629 : : static bool
1452 tgl@sss.pgh.pa.us 630 : 263391 : tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc)
631 : : {
2842 rhaas@postgresql.org 632 : 263391 : int numattrs = tupdesc->natts;
633 : : int attrno;
634 : 263391 : ListCell *tlist_item = list_head(tlist);
635 : :
636 : : /* Check the tlist attributes */
637 [ + + ]: 1879283 : for (attrno = 1; attrno <= numattrs; attrno++)
638 : : {
639 : 1731158 : Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
640 : : Var *var;
641 : :
642 [ + + ]: 1731158 : if (tlist_item == NULL)
643 : 13245 : return false; /* tlist too short */
644 : 1717913 : var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
645 [ + - + + ]: 1717913 : if (!var || !IsA(var, Var))
646 : 32788 : return false; /* tlist item not a Var */
647 : : /* if these Asserts fail, planner messed up */
648 [ - + ]: 1685125 : Assert(var->varno == varno);
649 [ - + ]: 1685125 : Assert(var->varlevelsup == 0);
650 [ + + ]: 1685125 : if (var->varattno != attrno)
651 : 69068 : return false; /* out of order */
652 [ - + ]: 1616057 : if (att_tup->attisdropped)
2842 rhaas@postgresql.org 653 :UBC 0 : return false; /* table contains dropped columns */
2719 andrew@dunslane.net 654 [ + + ]:CBC 1616057 : if (att_tup->atthasmissing)
655 : 162 : return false; /* table contains cols with missing values */
656 : :
657 : : /*
658 : : * Note: usually the Var's type should match the tupdesc exactly, but
659 : : * in situations involving unions of columns that have different
660 : : * typmods, the Var may have come from above the union and hence have
661 : : * typmod -1. This is a legitimate situation since the Var still
662 : : * describes the column, just not as exactly as the tupdesc does. We
663 : : * could change the planner to prevent it, but it'd then insert
664 : : * projection steps just to convert from specific typmod to typmod -1,
665 : : * which is pretty silly.
666 : : */
2842 rhaas@postgresql.org 667 [ + + ]: 1615895 : if (var->vartype != att_tup->atttypid ||
668 [ + + ]: 1615892 : (var->vartypmod != att_tup->atttypmod &&
669 [ - + ]: 3 : var->vartypmod != -1))
670 : 3 : return false; /* type mismatch */
671 : :
2245 tgl@sss.pgh.pa.us 672 : 1615892 : tlist_item = lnext(tlist, tlist_item);
673 : : }
674 : :
2842 rhaas@postgresql.org 675 [ + + ]: 148125 : if (tlist_item)
676 : 6437 : return false; /* tlist too long */
677 : :
678 : 141688 : return true;
679 : : }
680 : :
681 : :
682 : : /* ----------------------------------------------------------------
683 : : * Scan node support
684 : : * ----------------------------------------------------------------
685 : : */
686 : :
687 : : /* ----------------
688 : : * ExecAssignScanType
689 : : * ----------------
690 : : */
691 : : void
7022 tgl@sss.pgh.pa.us 692 : 436 : ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
693 : : {
8311 694 : 436 : TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
695 : :
7022 696 : 436 : ExecSetSlotDescriptor(slot, tupDesc);
10651 scrappy@hub.org 697 : 436 : }
698 : :
699 : : /* ----------------
700 : : * ExecCreateScanSlotFromOuterPlan
701 : : * ----------------
702 : : */
703 : : void
2487 andres@anarazel.de 704 : 66808 : ExecCreateScanSlotFromOuterPlan(EState *estate,
705 : : ScanState *scanstate,
706 : : const TupleTableSlotOps *tts_ops)
707 : : {
708 : : PlanState *outerPlan;
709 : : TupleDesc tupDesc;
710 : :
8311 tgl@sss.pgh.pa.us 711 : 66808 : outerPlan = outerPlanState(scanstate);
8160 712 : 66808 : tupDesc = ExecGetResultType(outerPlan);
713 : :
2487 andres@anarazel.de 714 : 66808 : ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops);
10651 scrappy@hub.org 715 : 66808 : }
716 : :
717 : : /* ----------------------------------------------------------------
718 : : * ExecRelationIsTargetRelation
719 : : *
720 : : * Detect whether a relation (identified by rangetable index)
721 : : * is one of the target relations of the query.
722 : : *
723 : : * Note: This is currently no longer used in core. We keep it around
724 : : * because FDWs may wish to use it to determine if their foreign table
725 : : * is a target relation.
726 : : * ----------------------------------------------------------------
727 : : */
728 : : bool
7217 tgl@sss.pgh.pa.us 729 :UBC 0 : ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
730 : : {
1789 heikki.linnakangas@i 731 : 0 : return list_member_int(estate->es_plannedstmt->resultRelations, scanrelid);
732 : : }
733 : :
734 : : /* ----------------------------------------------------------------
735 : : * ExecOpenScanRelation
736 : : *
737 : : * Open the heap relation to be scanned by a base-level scan plan node.
738 : : * This should be called during the node's ExecInit routine.
739 : : * ----------------------------------------------------------------
740 : : */
741 : : Relation
4515 tgl@sss.pgh.pa.us 742 :CBC 215138 : ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
743 : : {
744 : : Relation rel;
745 : :
746 : : /* Open the relation. */
171 amitlan@postgresql.o 747 : 215138 : rel = ExecGetRangeTableRelation(estate, scanrelid, false);
748 : :
749 : : /*
750 : : * Complain if we're attempting a scan of an unscannable relation, except
751 : : * when the query won't actually be run. This is a slightly klugy place
752 : : * to do this, perhaps, but there is no better place.
753 : : */
4515 tgl@sss.pgh.pa.us 754 [ + + ]: 215138 : if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 &&
755 [ + + ]: 198617 : !RelationIsScannable(rel))
756 [ + - ]: 6 : ereport(ERROR,
757 : : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
758 : : errmsg("materialized view \"%s\" has not been populated",
759 : : RelationGetRelationName(rel)),
760 : : errhint("Use the REFRESH MATERIALIZED VIEW command.")));
761 : :
762 : 215132 : return rel;
763 : : }
764 : :
765 : : /*
766 : : * ExecInitRangeTable
767 : : * Set up executor's range-table-related data
768 : : *
769 : : * In addition to the range table proper, initialize arrays that are
770 : : * indexed by rangetable index.
771 : : */
772 : : void
211 amitlan@postgresql.o 773 : 430598 : ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos,
774 : : Bitmapset *unpruned_relids)
775 : : {
776 : : /* Remember the range table List as-is */
2529 tgl@sss.pgh.pa.us 777 : 430598 : estate->es_range_table = rangeTable;
778 : :
779 : : /* ... and the RTEPermissionInfo List too */
915 780 : 430598 : estate->es_rteperminfos = permInfos;
781 : :
782 : : /* Set size of associated arrays */
2529 783 : 430598 : estate->es_range_table_size = list_length(rangeTable);
784 : :
785 : : /*
786 : : * Initialize the bitmapset of RT indexes (es_unpruned_relids)
787 : : * representing relations that will be scanned during execution. This set
788 : : * is initially populated by the caller and may be extended later by
789 : : * ExecDoInitialPruning() to include RT indexes of unpruned leaf
790 : : * partitions.
791 : : */
211 amitlan@postgresql.o 792 : 430598 : estate->es_unpruned_relids = unpruned_relids;
793 : :
794 : : /*
795 : : * Allocate an array to store an open Relation corresponding to each
796 : : * rangetable entry, and initialize entries to NULL. Relations are opened
797 : : * and stored here as needed.
798 : : */
2529 tgl@sss.pgh.pa.us 799 : 430598 : estate->es_relations = (Relation *)
800 : 430598 : palloc0(estate->es_range_table_size * sizeof(Relation));
801 : :
802 : : /*
803 : : * es_result_relations and es_rowmarks are also parallel to
804 : : * es_range_table, but are allocated only if needed.
805 : : */
1789 heikki.linnakangas@i 806 : 430598 : estate->es_result_relations = NULL;
2525 tgl@sss.pgh.pa.us 807 : 430598 : estate->es_rowmarks = NULL;
2529 808 : 430598 : }
809 : :
810 : : /*
811 : : * ExecGetRangeTableRelation
812 : : * Open the Relation for a range table entry, if not already done
813 : : *
814 : : * The Relations will be closed in ExecEndPlan().
815 : : *
816 : : * If isResultRel is true, the relation is being used as a result relation.
817 : : * Such a relation might have been pruned, which is OK for result relations,
818 : : * but not for scan relations; see the details in ExecInitModifyTable(). If
819 : : * isResultRel is false, the caller must ensure that 'rti' refers to an
820 : : * unpruned relation (i.e., it is a member of estate->es_unpruned_relids)
821 : : * before calling this function. Attempting to open a pruned relation for
822 : : * scanning will result in an error.
823 : : */
824 : : Relation
171 amitlan@postgresql.o 825 : 280400 : ExecGetRangeTableRelation(EState *estate, Index rti, bool isResultRel)
826 : : {
827 : : Relation rel;
828 : :
2529 tgl@sss.pgh.pa.us 829 [ + - - + ]: 280400 : Assert(rti > 0 && rti <= estate->es_range_table_size);
830 : :
171 amitlan@postgresql.o 831 [ + + - + ]: 280400 : if (!isResultRel && !bms_is_member(rti, estate->es_unpruned_relids))
198 amitlan@postgresql.o 832 [ # # ]:UBC 0 : elog(ERROR, "trying to open a pruned relation");
833 : :
2529 tgl@sss.pgh.pa.us 834 :CBC 280400 : rel = estate->es_relations[rti - 1];
835 [ + + ]: 280400 : if (rel == NULL)
836 : : {
837 : : /* First time through, so open the relation */
838 : 259954 : RangeTblEntry *rte = exec_rt_fetch(rti, estate);
839 : :
840 [ - + ]: 259954 : Assert(rte->rtekind == RTE_RELATION);
841 : :
2527 842 [ + + ]: 259954 : if (!IsParallelWorker())
843 : : {
844 : : /*
845 : : * In a normal query, we should already have the appropriate lock,
846 : : * but verify that through an Assert. Since there's already an
847 : : * Assert inside table_open that insists on holding some lock, it
848 : : * seems sufficient to check this only when rellockmode is higher
849 : : * than the minimum.
850 : : */
2420 andres@anarazel.de 851 : 257640 : rel = table_open(rte->relid, NoLock);
2527 tgl@sss.pgh.pa.us 852 [ + + - + ]: 257640 : Assert(rte->rellockmode == AccessShareLock ||
853 : : CheckRelationLockedByMe(rel, rte->rellockmode, false));
854 : : }
855 : : else
856 : : {
857 : : /*
858 : : * If we are a parallel worker, we need to obtain our own local
859 : : * lock on the relation. This ensures sane behavior in case the
860 : : * parent process exits before we do.
861 : : */
2420 andres@anarazel.de 862 : 2314 : rel = table_open(rte->relid, rte->rellockmode);
863 : : }
864 : :
2527 tgl@sss.pgh.pa.us 865 : 259954 : estate->es_relations[rti - 1] = rel;
866 : : }
867 : :
2529 868 : 280400 : return rel;
869 : : }
870 : :
871 : : /*
872 : : * ExecInitResultRelation
873 : : * Open relation given by the passed-in RT index and fill its
874 : : * ResultRelInfo node
875 : : *
876 : : * Here, we also save the ResultRelInfo in estate->es_result_relations array
877 : : * such that it can be accessed later using the RT index.
878 : : */
879 : : void
1789 heikki.linnakangas@i 880 : 59126 : ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
881 : : Index rti)
882 : : {
883 : : Relation resultRelationDesc;
884 : :
171 amitlan@postgresql.o 885 : 59126 : resultRelationDesc = ExecGetRangeTableRelation(estate, rti, true);
1789 heikki.linnakangas@i 886 : 59126 : InitResultRelInfo(resultRelInfo,
887 : : resultRelationDesc,
888 : : rti,
889 : : NULL,
890 : : estate->es_instrument);
891 : :
892 [ + + ]: 59126 : if (estate->es_result_relations == NULL)
893 : 56393 : estate->es_result_relations = (ResultRelInfo **)
894 : 56393 : palloc0(estate->es_range_table_size * sizeof(ResultRelInfo *));
895 : 59126 : estate->es_result_relations[rti - 1] = resultRelInfo;
896 : :
897 : : /*
898 : : * Saving in the list allows to avoid needlessly traversing the whole
899 : : * array when only a few of its entries are possibly non-NULL.
900 : : */
901 : 59126 : estate->es_opened_result_relations =
902 : 59126 : lappend(estate->es_opened_result_relations, resultRelInfo);
903 : 59126 : }
904 : :
905 : : /*
906 : : * UpdateChangedParamSet
907 : : * Add changed parameters to a plan node's chgParam set
908 : : */
909 : : void
8065 bruce@momjian.us 910 : 501175 : UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
911 : : {
912 : : Bitmapset *parmset;
913 : :
914 : : /*
915 : : * The plan node only depends on params listed in its allParam set. Don't
916 : : * include anything else into its chgParam set.
917 : : */
8245 tgl@sss.pgh.pa.us 918 : 501175 : parmset = bms_intersect(node->plan->allParam, newchg);
919 919 : 501175 : node->chgParam = bms_join(node->chgParam, parmset);
10067 vadim4o@yahoo.com 920 : 501175 : }
921 : :
922 : : /*
923 : : * executor_errposition
924 : : * Report an execution-time cursor position, if possible.
925 : : *
926 : : * This is expected to be used within an ereport() call. The return value
927 : : * is a dummy (always 0, in fact).
928 : : *
929 : : * The locations stored in parsetrees are byte offsets into the source string.
930 : : * We have to convert them to 1-based character indexes for reporting to
931 : : * clients. (We do things this way to avoid unnecessary overhead in the
932 : : * normal non-error case: computing character indexes would be much more
933 : : * expensive than storing token offsets.)
934 : : */
935 : : int
3063 tgl@sss.pgh.pa.us 936 :UBC 0 : executor_errposition(EState *estate, int location)
937 : : {
938 : : int pos;
939 : :
940 : : /* No-op if location was not provided */
941 [ # # ]: 0 : if (location < 0)
1991 942 : 0 : return 0;
943 : : /* Can't do anything if source text is not available */
3063 944 [ # # # # ]: 0 : if (estate == NULL || estate->es_sourceText == NULL)
1991 945 : 0 : return 0;
946 : : /* Convert offset to character number */
3063 947 : 0 : pos = pg_mbstrlen_with_len(estate->es_sourceText, location) + 1;
948 : : /* And pass it to the ereport mechanism */
1991 949 : 0 : return errposition(pos);
950 : : }
951 : :
952 : : /*
953 : : * Register a shutdown callback in an ExprContext.
954 : : *
955 : : * Shutdown callbacks will be called (in reverse order of registration)
956 : : * when the ExprContext is deleted or rescanned. This provides a hook
957 : : * for functions called in the context to do any cleanup needed --- it's
958 : : * particularly useful for functions returning sets. Note that the
959 : : * callback will *not* be called in the event that execution is aborted
960 : : * by an error.
961 : : */
962 : : void
8518 tgl@sss.pgh.pa.us 963 :CBC 78582 : RegisterExprContextCallback(ExprContext *econtext,
964 : : ExprContextCallbackFunction function,
965 : : Datum arg)
966 : : {
967 : : ExprContext_CB *ecxt_callback;
968 : :
969 : : /* Save the info in appropriate memory context */
970 : : ecxt_callback = (ExprContext_CB *)
971 : 78582 : MemoryContextAlloc(econtext->ecxt_per_query_memory,
972 : : sizeof(ExprContext_CB));
973 : :
974 : 78582 : ecxt_callback->function = function;
975 : 78582 : ecxt_callback->arg = arg;
976 : :
977 : : /* link to front of list for appropriate execution order */
978 : 78582 : ecxt_callback->next = econtext->ecxt_callbacks;
979 : 78582 : econtext->ecxt_callbacks = ecxt_callback;
980 : 78582 : }
981 : :
982 : : /*
983 : : * Deregister a shutdown callback in an ExprContext.
984 : : *
985 : : * Any list entries matching the function and arg will be removed.
986 : : * This can be used if it's no longer necessary to call the callback.
987 : : */
988 : : void
989 : 67352 : UnregisterExprContextCallback(ExprContext *econtext,
990 : : ExprContextCallbackFunction function,
991 : : Datum arg)
992 : : {
993 : : ExprContext_CB **prev_callback;
994 : : ExprContext_CB *ecxt_callback;
995 : :
996 : 67352 : prev_callback = &econtext->ecxt_callbacks;
997 : :
998 [ + + ]: 191811 : while ((ecxt_callback = *prev_callback) != NULL)
999 : : {
1000 [ + + + + ]: 124459 : if (ecxt_callback->function == function && ecxt_callback->arg == arg)
1001 : : {
1002 : 67352 : *prev_callback = ecxt_callback->next;
1003 : 67352 : pfree(ecxt_callback);
1004 : : }
1005 : : else
1006 : 57107 : prev_callback = &ecxt_callback->next;
1007 : : }
1008 : 67352 : }
1009 : :
1010 : : /*
1011 : : * Call all the shutdown callbacks registered in an ExprContext.
1012 : : *
1013 : : * The callback list is emptied (important in case this is only a rescan
1014 : : * reset, and not deletion of the ExprContext).
1015 : : *
1016 : : * If isCommit is false, just clean the callback list but don't call 'em.
1017 : : * (See comment for FreeExprContext.)
1018 : : */
1019 : : static void
5894 1020 : 3011248 : ShutdownExprContext(ExprContext *econtext, bool isCommit)
1021 : : {
1022 : : ExprContext_CB *ecxt_callback;
1023 : : MemoryContext oldcontext;
1024 : :
1025 : : /* Fast path in normal case where there's nothing to do. */
8301 1026 [ + + ]: 3011248 : if (econtext->ecxt_callbacks == NULL)
1027 : 3001083 : return;
1028 : :
1029 : : /*
1030 : : * Call the callbacks in econtext's per-tuple context. This ensures that
1031 : : * any memory they might leak will get cleaned up.
1032 : : */
1033 : 10165 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
1034 : :
1035 : : /*
1036 : : * Call each callback function in reverse registration order.
1037 : : */
8518 1038 [ + + ]: 20534 : while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
1039 : : {
1040 : 10369 : econtext->ecxt_callbacks = ecxt_callback->next;
5894 1041 [ + - ]: 10369 : if (isCommit)
2921 peter_e@gmx.net 1042 : 10369 : ecxt_callback->function(ecxt_callback->arg);
8518 tgl@sss.pgh.pa.us 1043 : 10369 : pfree(ecxt_callback);
1044 : : }
1045 : :
8301 1046 : 10165 : MemoryContextSwitchTo(oldcontext);
1047 : : }
1048 : :
1049 : : /*
1050 : : * GetAttributeByName
1051 : : * GetAttributeByNum
1052 : : *
1053 : : * These functions return the value of the requested attribute
1054 : : * out of the given tuple Datum.
1055 : : * C functions which take a tuple as an argument are expected
1056 : : * to use these. Ex: overpaid(EMP) might call GetAttributeByNum().
1057 : : * Note: these are actually rather slow because they do a typcache
1058 : : * lookup on each call.
1059 : : */
1060 : : Datum
3098 andres@anarazel.de 1061 : 18 : GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull)
1062 : : {
1063 : : AttrNumber attrno;
1064 : : Datum result;
1065 : : Oid tupType;
1066 : : int32 tupTypmod;
1067 : : TupleDesc tupDesc;
1068 : : HeapTupleData tmptup;
1069 : : int i;
1070 : :
1071 [ - + ]: 18 : if (attname == NULL)
3098 andres@anarazel.de 1072 [ # # ]:UBC 0 : elog(ERROR, "invalid attribute name");
1073 : :
3098 andres@anarazel.de 1074 [ - + ]:CBC 18 : if (isNull == NULL)
3098 andres@anarazel.de 1075 [ # # ]:UBC 0 : elog(ERROR, "a NULL isNull pointer was passed");
1076 : :
3098 andres@anarazel.de 1077 [ - + ]:CBC 18 : if (tuple == NULL)
1078 : : {
1079 : : /* Kinda bogus but compatible with old behavior... */
3098 andres@anarazel.de 1080 :UBC 0 : *isNull = true;
1081 : 0 : return (Datum) 0;
1082 : : }
1083 : :
3098 andres@anarazel.de 1084 :CBC 18 : tupType = HeapTupleHeaderGetTypeId(tuple);
1085 : 18 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
1086 : 18 : tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1087 : :
1088 : 18 : attrno = InvalidAttrNumber;
1089 [ + - ]: 72 : for (i = 0; i < tupDesc->natts; i++)
1090 : : {
2939 1091 : 72 : Form_pg_attribute att = TupleDescAttr(tupDesc, i);
1092 : :
1093 [ + + ]: 72 : if (namestrcmp(&(att->attname), attname) == 0)
1094 : : {
1095 : 18 : attrno = att->attnum;
3098 1096 : 18 : break;
1097 : : }
1098 : : }
1099 : :
1100 [ - + ]: 18 : if (attrno == InvalidAttrNumber)
3098 andres@anarazel.de 1101 [ # # ]:UBC 0 : elog(ERROR, "attribute \"%s\" does not exist", attname);
1102 : :
1103 : : /*
1104 : : * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all
1105 : : * the fields in the struct just in case user tries to inspect system
1106 : : * columns.
1107 : : */
3098 andres@anarazel.de 1108 :CBC 18 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
1109 : 18 : ItemPointerSetInvalid(&(tmptup.t_self));
1110 : 18 : tmptup.t_tableOid = InvalidOid;
1111 : 18 : tmptup.t_data = tuple;
1112 : :
1113 : 18 : result = heap_getattr(&tmptup,
1114 : : attrno,
1115 : : tupDesc,
1116 : : isNull);
1117 : :
1118 [ + - ]: 18 : ReleaseTupleDesc(tupDesc);
1119 : :
1120 : 18 : return result;
1121 : : }
1122 : :
1123 : : Datum
3098 andres@anarazel.de 1124 :UBC 0 : GetAttributeByNum(HeapTupleHeader tuple,
1125 : : AttrNumber attrno,
1126 : : bool *isNull)
1127 : : {
1128 : : Datum result;
1129 : : Oid tupType;
1130 : : int32 tupTypmod;
1131 : : TupleDesc tupDesc;
1132 : : HeapTupleData tmptup;
1133 : :
1134 [ # # ]: 0 : if (!AttributeNumberIsValid(attrno))
1135 [ # # ]: 0 : elog(ERROR, "invalid attribute number %d", attrno);
1136 : :
1137 [ # # ]: 0 : if (isNull == NULL)
1138 [ # # ]: 0 : elog(ERROR, "a NULL isNull pointer was passed");
1139 : :
1140 [ # # ]: 0 : if (tuple == NULL)
1141 : : {
1142 : : /* Kinda bogus but compatible with old behavior... */
1143 : 0 : *isNull = true;
1144 : 0 : return (Datum) 0;
1145 : : }
1146 : :
1147 : 0 : tupType = HeapTupleHeaderGetTypeId(tuple);
1148 : 0 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
1149 : 0 : tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1150 : :
1151 : : /*
1152 : : * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all
1153 : : * the fields in the struct just in case user tries to inspect system
1154 : : * columns.
1155 : : */
1156 : 0 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
1157 : 0 : ItemPointerSetInvalid(&(tmptup.t_self));
1158 : 0 : tmptup.t_tableOid = InvalidOid;
1159 : 0 : tmptup.t_data = tuple;
1160 : :
1161 : 0 : result = heap_getattr(&tmptup,
1162 : : attrno,
1163 : : tupDesc,
1164 : : isNull);
1165 : :
1166 [ # # ]: 0 : ReleaseTupleDesc(tupDesc);
1167 : :
1168 : 0 : return result;
1169 : : }
1170 : :
1171 : : /*
1172 : : * Number of items in a tlist (including any resjunk items!)
1173 : : */
1174 : : int
3098 andres@anarazel.de 1175 :CBC 646428 : ExecTargetListLength(List *targetlist)
1176 : : {
1177 : : /* This used to be more complex, but fjoins are dead */
1178 : 646428 : return list_length(targetlist);
1179 : : }
1180 : :
1181 : : /*
1182 : : * Number of items in a tlist, not including any resjunk items
1183 : : */
1184 : : int
1185 : 72491 : ExecCleanTargetListLength(List *targetlist)
1186 : : {
1187 : 72491 : int len = 0;
1188 : : ListCell *tl;
1189 : :
1190 [ + + + + : 294063 : foreach(tl, targetlist)
+ + ]
1191 : : {
3071 tgl@sss.pgh.pa.us 1192 : 221572 : TargetEntry *curTle = lfirst_node(TargetEntry, tl);
1193 : :
3098 andres@anarazel.de 1194 [ + + ]: 221572 : if (!curTle->resjunk)
1195 : 204912 : len++;
1196 : : }
1197 : 72491 : return len;
1198 : : }
1199 : :
1200 : : /*
1201 : : * Return a relInfo's tuple slot for a trigger's OLD tuples.
1202 : : */
1203 : : TupleTableSlot *
2384 1204 : 11984 : ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
1205 : : {
1206 [ + + ]: 11984 : if (relInfo->ri_TrigOldSlot == NULL)
1207 : : {
1208 : 4928 : Relation rel = relInfo->ri_RelationDesc;
1209 : 4928 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1210 : :
1211 : 4928 : relInfo->ri_TrigOldSlot =
1212 : 4928 : ExecInitExtraTupleSlot(estate,
1213 : : RelationGetDescr(rel),
1214 : : table_slot_callbacks(rel));
1215 : :
1216 : 4928 : MemoryContextSwitchTo(oldcontext);
1217 : : }
1218 : :
1219 : 11984 : return relInfo->ri_TrigOldSlot;
1220 : : }
1221 : :
1222 : : /*
1223 : : * Return a relInfo's tuple slot for a trigger's NEW tuples.
1224 : : */
1225 : : TupleTableSlot *
1226 : 1756 : ExecGetTriggerNewSlot(EState *estate, ResultRelInfo *relInfo)
1227 : : {
1228 [ + + ]: 1756 : if (relInfo->ri_TrigNewSlot == NULL)
1229 : : {
1230 : 1092 : Relation rel = relInfo->ri_RelationDesc;
1231 : 1092 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1232 : :
1233 : 1092 : relInfo->ri_TrigNewSlot =
1234 : 1092 : ExecInitExtraTupleSlot(estate,
1235 : : RelationGetDescr(rel),
1236 : : table_slot_callbacks(rel));
1237 : :
1238 : 1092 : MemoryContextSwitchTo(oldcontext);
1239 : : }
1240 : :
1241 : 1756 : return relInfo->ri_TrigNewSlot;
1242 : : }
1243 : :
1244 : : /*
1245 : : * Return a relInfo's tuple slot for processing returning tuples.
1246 : : */
1247 : : TupleTableSlot *
1248 : 655 : ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
1249 : : {
1250 [ + + ]: 655 : if (relInfo->ri_ReturningSlot == NULL)
1251 : : {
1252 : 340 : Relation rel = relInfo->ri_RelationDesc;
1253 : 340 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1254 : :
1255 : 340 : relInfo->ri_ReturningSlot =
1256 : 340 : ExecInitExtraTupleSlot(estate,
1257 : : RelationGetDescr(rel),
1258 : : table_slot_callbacks(rel));
1259 : :
1260 : 340 : MemoryContextSwitchTo(oldcontext);
1261 : : }
1262 : :
1263 : 655 : return relInfo->ri_ReturningSlot;
1264 : : }
1265 : :
1266 : : /*
1267 : : * Return a relInfo's all-NULL tuple slot for processing returning tuples.
1268 : : *
1269 : : * Note: this slot is intentionally filled with NULLs in every column, and
1270 : : * should be considered read-only --- the caller must not update it.
1271 : : */
1272 : : TupleTableSlot *
233 dean.a.rasheed@gmail 1273 : 156 : ExecGetAllNullSlot(EState *estate, ResultRelInfo *relInfo)
1274 : : {
1275 [ + + ]: 156 : if (relInfo->ri_AllNullSlot == NULL)
1276 : : {
1277 : 106 : Relation rel = relInfo->ri_RelationDesc;
1278 : 106 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1279 : : TupleTableSlot *slot;
1280 : :
1281 : 106 : slot = ExecInitExtraTupleSlot(estate,
1282 : : RelationGetDescr(rel),
1283 : : table_slot_callbacks(rel));
1284 : 106 : ExecStoreAllNullTuple(slot);
1285 : :
1286 : 106 : relInfo->ri_AllNullSlot = slot;
1287 : :
1288 : 106 : MemoryContextSwitchTo(oldcontext);
1289 : : }
1290 : :
1291 : 156 : return relInfo->ri_AllNullSlot;
1292 : : }
1293 : :
1294 : : /*
1295 : : * Return the map needed to convert given child result relation's tuples to
1296 : : * the rowtype of the query's main target ("root") relation. Note that a
1297 : : * NULL result is valid and means that no conversion is needed.
1298 : : */
1299 : : TupleConversionMap *
1614 tgl@sss.pgh.pa.us 1300 : 33946 : ExecGetChildToRootMap(ResultRelInfo *resultRelInfo)
1301 : : {
1302 : : /* If we didn't already do so, compute the map for this child. */
1303 [ + + ]: 33946 : if (!resultRelInfo->ri_ChildToRootMapValid)
1304 : : {
1305 : 837 : ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1306 : :
1307 [ + + ]: 837 : if (rootRelInfo)
1308 : 651 : resultRelInfo->ri_ChildToRootMap =
1309 : 651 : convert_tuples_by_name(RelationGetDescr(resultRelInfo->ri_RelationDesc),
1310 : 651 : RelationGetDescr(rootRelInfo->ri_RelationDesc));
1311 : : else /* this isn't a child result rel */
1312 : 186 : resultRelInfo->ri_ChildToRootMap = NULL;
1313 : :
1314 : 837 : resultRelInfo->ri_ChildToRootMapValid = true;
1315 : : }
1316 : :
1317 : 33946 : return resultRelInfo->ri_ChildToRootMap;
1318 : : }
1319 : :
1320 : : /*
1321 : : * Returns the map needed to convert given root result relation's tuples to
1322 : : * the rowtype of the given child relation. Note that a NULL result is valid
1323 : : * and means that no conversion is needed.
1324 : : */
1325 : : TupleConversionMap *
1009 alvherre@alvh.no-ip. 1326 : 511423 : ExecGetRootToChildMap(ResultRelInfo *resultRelInfo, EState *estate)
1327 : : {
1328 : : /* Mustn't get called for a non-child result relation. */
1329 [ - + ]: 511423 : Assert(resultRelInfo->ri_RootResultRelInfo);
1330 : :
1331 : : /* If we didn't already do so, compute the map for this child. */
1332 [ + + ]: 511423 : if (!resultRelInfo->ri_RootToChildMapValid)
1333 : : {
1334 : 3843 : ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1335 : 3843 : TupleDesc indesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
1336 : 3843 : TupleDesc outdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
1337 : 3843 : Relation childrel = resultRelInfo->ri_RelationDesc;
1338 : : AttrMap *attrMap;
1339 : : MemoryContext oldcontext;
1340 : :
1341 : : /*
1342 : : * When this child table is not a partition (!relispartition), it may
1343 : : * have columns that are not present in the root table, which we ask
1344 : : * to ignore by passing true for missing_ok.
1345 : : */
1346 : 3843 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1347 : 3843 : attrMap = build_attrmap_by_name_if_req(indesc, outdesc,
1348 : 3843 : !childrel->rd_rel->relispartition);
1349 [ + + ]: 3843 : if (attrMap)
1350 : 738 : resultRelInfo->ri_RootToChildMap =
1351 : 738 : convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
1352 : 3843 : MemoryContextSwitchTo(oldcontext);
1353 : 3843 : resultRelInfo->ri_RootToChildMapValid = true;
1354 : : }
1355 : :
1356 : 511423 : return resultRelInfo->ri_RootToChildMap;
1357 : : }
1358 : :
1359 : : /* Return a bitmap representing columns being inserted */
1360 : : Bitmapset *
1671 heikki.linnakangas@i 1361 : 699 : ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
1362 : : {
1005 alvherre@alvh.no-ip. 1363 : 699 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
1364 : :
1365 [ - + ]: 699 : if (perminfo == NULL)
1005 alvherre@alvh.no-ip. 1366 :UBC 0 : return NULL;
1367 : :
1368 : : /* Map the columns to child's attribute numbers if needed. */
1005 alvherre@alvh.no-ip. 1369 [ + + ]:CBC 699 : if (relinfo->ri_RootResultRelInfo)
1370 : : {
1009 1371 : 31 : TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
1372 : :
1005 1373 [ + + ]: 31 : if (map)
1374 : 2 : return execute_attr_map_cols(map->attrMap, perminfo->insertedCols);
1375 : : }
1376 : :
1377 : 697 : return perminfo->insertedCols;
1378 : : }
1379 : :
1380 : : /* Return a bitmap representing columns being updated */
1381 : : Bitmapset *
1671 heikki.linnakangas@i 1382 : 30123 : ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1383 : : {
1005 alvherre@alvh.no-ip. 1384 : 30123 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
1385 : :
1386 [ - + ]: 30123 : if (perminfo == NULL)
1005 alvherre@alvh.no-ip. 1387 :UBC 0 : return NULL;
1388 : :
1389 : : /* Map the columns to child's attribute numbers if needed. */
1005 alvherre@alvh.no-ip. 1390 [ + + ]:CBC 30123 : if (relinfo->ri_RootResultRelInfo)
1391 : : {
1009 1392 : 903 : TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
1393 : :
1005 1394 [ + + ]: 903 : if (map)
1395 : 245 : return execute_attr_map_cols(map->attrMap, perminfo->updatedCols);
1396 : : }
1397 : :
1398 : 29878 : return perminfo->updatedCols;
1399 : : }
1400 : :
1401 : : /* Return a bitmap representing generated columns being updated */
1402 : : Bitmapset *
1671 heikki.linnakangas@i 1403 : 29321 : ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1404 : : {
1405 : : /* Compute the info if we didn't already */
211 peter@eisentraut.org 1406 [ + + ]: 29321 : if (!relinfo->ri_extraUpdatedCols_valid)
1407 : 29222 : ExecInitGenerated(relinfo, estate, CMD_UPDATE);
975 tgl@sss.pgh.pa.us 1408 : 29321 : return relinfo->ri_extraUpdatedCols;
1409 : : }
1410 : :
1411 : : /*
1412 : : * Return columns being updated, including generated columns
1413 : : *
1414 : : * The bitmap is allocated in per-tuple memory context. It's up to the caller to
1415 : : * copy it into a different context with the appropriate lifespan, if needed.
1416 : : */
1417 : : Bitmapset *
1671 heikki.linnakangas@i 1418 : 7351 : ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1419 : : {
1420 : : Bitmapset *ret;
1421 : : MemoryContext oldcxt;
1422 : :
822 tomas.vondra@postgre 1423 [ + + ]: 7351 : oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
1424 : :
1425 : 7351 : ret = bms_union(ExecGetUpdatedCols(relinfo, estate),
1426 : 7351 : ExecGetExtraUpdatedCols(relinfo, estate));
1427 : :
1428 : 7351 : MemoryContextSwitchTo(oldcxt);
1429 : :
1430 : 7351 : return ret;
1431 : : }
1432 : :
1433 : : /*
1434 : : * GetResultRTEPermissionInfo
1435 : : * Looks up RTEPermissionInfo for ExecGet*Cols() routines
1436 : : */
1437 : : static RTEPermissionInfo *
1005 alvherre@alvh.no-ip. 1438 : 31004 : GetResultRTEPermissionInfo(ResultRelInfo *relinfo, EState *estate)
1439 : : {
1440 : : Index rti;
1441 : : RangeTblEntry *rte;
1442 : 31004 : RTEPermissionInfo *perminfo = NULL;
1443 : :
1444 [ + + ]: 31004 : if (relinfo->ri_RootResultRelInfo)
1445 : : {
1446 : : /*
1447 : : * For inheritance child result relations (a partition routing target
1448 : : * of an INSERT or a child UPDATE target), this returns the root
1449 : : * parent's RTE to fetch the RTEPermissionInfo because that's the only
1450 : : * one that has one assigned.
1451 : : */
1452 : 990 : rti = relinfo->ri_RootResultRelInfo->ri_RangeTableIndex;
1453 : : }
1454 [ + - ]: 30014 : else if (relinfo->ri_RangeTableIndex != 0)
1455 : : {
1456 : : /*
1457 : : * Non-child result relation should have their own RTEPermissionInfo.
1458 : : */
1459 : 30014 : rti = relinfo->ri_RangeTableIndex;
1460 : : }
1461 : : else
1462 : : {
1463 : : /*
1464 : : * The relation isn't in the range table and it isn't a partition
1465 : : * routing target. This ResultRelInfo must've been created only for
1466 : : * firing triggers and the relation is not being inserted into. (See
1467 : : * ExecGetTriggerResultRel.)
1468 : : */
1005 alvherre@alvh.no-ip. 1469 :UBC 0 : rti = 0;
1470 : : }
1471 : :
1005 alvherre@alvh.no-ip. 1472 [ + - ]:CBC 31004 : if (rti > 0)
1473 : : {
1474 : 31004 : rte = exec_rt_fetch(rti, estate);
1475 : 31004 : perminfo = getRTEPermissionInfo(estate->es_rteperminfos, rte);
1476 : : }
1477 : :
1478 : 31004 : return perminfo;
1479 : : }
1480 : :
1481 : : /*
1482 : : * ExecGetResultRelCheckAsUser
1483 : : * Returns the user to modify passed-in result relation as
1484 : : *
1485 : : * The user is chosen by looking up the relation's or, if a child table, its
1486 : : * root parent's RTEPermissionInfo.
1487 : : */
1488 : : Oid
1489 : 182 : ExecGetResultRelCheckAsUser(ResultRelInfo *relInfo, EState *estate)
1490 : : {
1491 : 182 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relInfo, estate);
1492 : :
1493 : : /* XXX - maybe ok to return GetUserId() in this case? */
1494 [ - + ]: 182 : if (perminfo == NULL)
1005 alvherre@alvh.no-ip. 1495 [ # # ]:UBC 0 : elog(ERROR, "no RTEPermissionInfo found for result relation with OID %u",
1496 : : RelationGetRelid(relInfo->ri_RelationDesc));
1497 : :
1005 alvherre@alvh.no-ip. 1498 [ + + ]:CBC 182 : return perminfo->checkAsUser ? perminfo->checkAsUser : GetUserId();
1499 : : }
|