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