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