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