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