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 1262526 : 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 1262526 : 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 1262526 : oldcontext = MemoryContextSwitchTo(qcontext);
106 :
107 1262526 : estate = makeNode(EState);
108 :
109 : /*
110 : * Initialize all fields of the Executor State structure
111 : */
112 1262526 : estate->es_direction = ForwardScanDirection;
113 1262526 : estate->es_snapshot = InvalidSnapshot; /* caller must initialize this */
114 1262526 : estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */
115 1262526 : estate->es_range_table = NIL;
116 1262526 : estate->es_range_table_size = 0;
117 1262526 : estate->es_relations = NULL;
118 1262526 : estate->es_rowmarks = NULL;
119 1262526 : estate->es_rteperminfos = NIL;
120 1262526 : estate->es_plannedstmt = NULL;
121 :
122 1262526 : estate->es_junkFilter = NULL;
123 :
124 1262526 : estate->es_output_cid = (CommandId) 0;
125 :
126 1262526 : estate->es_result_relations = NULL;
127 1262526 : estate->es_opened_result_relations = NIL;
128 1262526 : estate->es_tuple_routing_result_relations = NIL;
129 1262526 : estate->es_trig_target_relations = NIL;
130 :
131 1262526 : estate->es_insert_pending_result_relations = NIL;
132 1262526 : estate->es_insert_pending_modifytables = NIL;
133 :
134 1262526 : estate->es_param_list_info = NULL;
135 1262526 : estate->es_param_exec_vals = NULL;
136 :
137 1262526 : estate->es_queryEnv = NULL;
138 :
139 1262526 : estate->es_query_cxt = qcontext;
140 :
141 1262526 : estate->es_tupleTable = NIL;
142 :
143 1262526 : estate->es_processed = 0;
144 1262526 : estate->es_total_processed = 0;
145 :
146 1262526 : estate->es_top_eflags = 0;
147 1262526 : estate->es_instrument = 0;
148 1262526 : estate->es_finished = false;
149 :
150 1262526 : estate->es_exprcontexts = NIL;
151 :
152 1262526 : estate->es_subplanstates = NIL;
153 :
154 1262526 : estate->es_auxmodifytables = NIL;
155 :
156 1262526 : estate->es_per_tuple_exprcontext = NULL;
157 :
158 1262526 : estate->es_sourceText = NULL;
159 :
160 1262526 : estate->es_use_parallel_mode = false;
161 1262526 : estate->es_parallel_workers_to_launch = 0;
162 1262526 : estate->es_parallel_workers_launched = 0;
163 :
164 1262526 : estate->es_jit_flags = 0;
165 1262526 : estate->es_jit = NULL;
166 :
167 : /*
168 : * Return the executor state structure
169 : */
170 1262526 : MemoryContextSwitchTo(oldcontext);
171 :
172 1262526 : 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 1229320 : 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 3140162 : 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 1910842 : 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 1229320 : if (estate->es_jit)
212 : {
213 1200 : jit_release_context(estate->es_jit);
214 1200 : estate->es_jit = NULL;
215 : }
216 :
217 : /* release partition directory, if allocated */
218 1229320 : if (estate->es_partition_directory)
219 : {
220 6756 : DestroyPartitionDirectory(estate->es_partition_directory);
221 6756 : 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 1229320 : MemoryContextDelete(estate->es_query_cxt);
229 1229320 : }
230 :
231 : /*
232 : * Internal implementation for CreateExprContext() and CreateWorkExprContext()
233 : * that allows control over the AllocSet parameters.
234 : */
235 : static ExprContext *
236 2048014 : 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 2048014 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
244 :
245 2048014 : econtext = makeNode(ExprContext);
246 :
247 : /* Initialize fields of ExprContext */
248 2048014 : econtext->ecxt_scantuple = NULL;
249 2048014 : econtext->ecxt_innertuple = NULL;
250 2048014 : econtext->ecxt_outertuple = NULL;
251 :
252 2048014 : econtext->ecxt_per_query_memory = estate->es_query_cxt;
253 :
254 : /*
255 : * Create working memory for expression evaluation in this context.
256 : */
257 2048014 : econtext->ecxt_per_tuple_memory =
258 2048014 : AllocSetContextCreate(estate->es_query_cxt,
259 : "ExprContext",
260 : minContextSize,
261 : initBlockSize,
262 : maxBlockSize);
263 :
264 2048014 : econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
265 2048014 : econtext->ecxt_param_list_info = estate->es_param_list_info;
266 :
267 2048014 : econtext->ecxt_aggvalues = NULL;
268 2048014 : econtext->ecxt_aggnulls = NULL;
269 :
270 2048014 : econtext->caseValue_datum = (Datum) 0;
271 2048014 : econtext->caseValue_isNull = true;
272 :
273 2048014 : econtext->domainValue_datum = (Datum) 0;
274 2048014 : econtext->domainValue_isNull = true;
275 :
276 2048014 : econtext->ecxt_estate = estate;
277 :
278 2048014 : 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 2048014 : estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
286 :
287 2048014 : MemoryContextSwitchTo(oldcontext);
288 :
289 2048014 : 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 2042504 : CreateExprContext(EState *estate)
307 : {
308 2042504 : 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 5510 : CreateWorkExprContext(EState *estate)
322 : {
323 5510 : Size minContextSize = ALLOCSET_DEFAULT_MINSIZE;
324 5510 : Size initBlockSize = ALLOCSET_DEFAULT_INITSIZE;
325 5510 : Size maxBlockSize = ALLOCSET_DEFAULT_MAXSIZE;
326 :
327 : /* choose the maxBlockSize to be no larger than 1/16 of work_mem */
328 33606 : while (16 * maxBlockSize > work_mem * 1024L)
329 28096 : maxBlockSize >>= 1;
330 :
331 5510 : if (maxBlockSize < ALLOCSET_DEFAULT_INITSIZE)
332 78 : maxBlockSize = ALLOCSET_DEFAULT_INITSIZE;
333 :
334 5510 : 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 8640 : CreateStandaloneExprContext(void)
358 : {
359 : ExprContext *econtext;
360 :
361 : /* Create the ExprContext node within the caller's memory context */
362 8640 : econtext = makeNode(ExprContext);
363 :
364 : /* Initialize fields of ExprContext */
365 8640 : econtext->ecxt_scantuple = NULL;
366 8640 : econtext->ecxt_innertuple = NULL;
367 8640 : econtext->ecxt_outertuple = NULL;
368 :
369 8640 : econtext->ecxt_per_query_memory = CurrentMemoryContext;
370 :
371 : /*
372 : * Create working memory for expression evaluation in this context.
373 : */
374 8640 : econtext->ecxt_per_tuple_memory =
375 8640 : AllocSetContextCreate(CurrentMemoryContext,
376 : "ExprContext",
377 : ALLOCSET_DEFAULT_SIZES);
378 :
379 8640 : econtext->ecxt_param_exec_vals = NULL;
380 8640 : econtext->ecxt_param_list_info = NULL;
381 :
382 8640 : econtext->ecxt_aggvalues = NULL;
383 8640 : econtext->ecxt_aggnulls = NULL;
384 :
385 8640 : econtext->caseValue_datum = (Datum) 0;
386 8640 : econtext->caseValue_isNull = true;
387 :
388 8640 : econtext->domainValue_datum = (Datum) 0;
389 8640 : econtext->domainValue_isNull = true;
390 :
391 8640 : econtext->ecxt_estate = NULL;
392 :
393 8640 : econtext->ecxt_callbacks = NULL;
394 :
395 8640 : 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 2008812 : FreeExprContext(ExprContext *econtext, bool isCommit)
417 : {
418 : EState *estate;
419 :
420 : /* Call any registered callbacks */
421 2008812 : ShutdownExprContext(econtext, isCommit);
422 : /* And clean up the memory used */
423 2008812 : MemoryContextDelete(econtext->ecxt_per_tuple_memory);
424 : /* Unlink self from owning EState, if any */
425 2008812 : estate = econtext->ecxt_estate;
426 2008812 : if (estate)
427 2008812 : estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts,
428 : econtext);
429 : /* And delete the ExprContext node */
430 2008812 : pfree(econtext);
431 2008812 : }
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 3390342 : ReScanExprContext(ExprContext *econtext)
444 : {
445 : /* Call any registered callbacks */
446 3390342 : ShutdownExprContext(econtext, true);
447 : /* And clean up the memory used */
448 3390342 : MemoryContextReset(econtext->ecxt_per_tuple_memory);
449 3390342 : }
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 652072 : MakePerTupleExprContext(EState *estate)
459 : {
460 652072 : if (estate->es_per_tuple_exprcontext == NULL)
461 652072 : estate->es_per_tuple_exprcontext = CreateExprContext(estate);
462 :
463 652072 : 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 1272332 : ExecAssignExprContext(EState *estate, PlanState *planstate)
486 : {
487 1272332 : planstate->ps_ExprContext = CreateExprContext(estate);
488 1272332 : }
489 :
490 : /* ----------------
491 : * ExecGetResultType
492 : * ----------------
493 : */
494 : TupleDesc
495 1512880 : ExecGetResultType(PlanState *planstate)
496 : {
497 1512880 : return planstate->ps_ResultTupleDesc;
498 : }
499 :
500 : /*
501 : * ExecGetResultSlotOps - information about node's type of result slot
502 : */
503 : const TupleTableSlotOps *
504 536016 : ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
505 : {
506 536016 : if (planstate->resultopsset && planstate->resultops)
507 : {
508 534532 : if (isfixed)
509 484930 : *isfixed = planstate->resultopsfixed;
510 534532 : return planstate->resultops;
511 : }
512 :
513 1484 : if (isfixed)
514 : {
515 1454 : if (planstate->resultopsset)
516 1454 : *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 1484 : if (!planstate->ps_ResultTupleSlot)
524 1484 : return &TTSOpsVirtual;
525 :
526 0 : return planstate->ps_ResultTupleSlot->tts_ops;
527 : }
528 :
529 :
530 : /* ----------------
531 : * ExecAssignProjectionInfo
532 : *
533 : * forms the projection information from the node's targetlist
534 : *
535 : * Notes for inputDesc are same as for ExecBuildProjectionInfo: supply it
536 : * for a relation-scan node, can pass NULL for upper-level nodes
537 : * ----------------
538 : */
539 : void
540 760102 : ExecAssignProjectionInfo(PlanState *planstate,
541 : TupleDesc inputDesc)
542 : {
543 760040 : planstate->ps_ProjInfo =
544 760102 : ExecBuildProjectionInfo(planstate->plan->targetlist,
545 : planstate->ps_ExprContext,
546 : planstate->ps_ResultTupleSlot,
547 : planstate,
548 : inputDesc);
549 760040 : }
550 :
551 :
552 : /* ----------------
553 : * ExecConditionalAssignProjectionInfo
554 : *
555 : * as ExecAssignProjectionInfo, but store NULL rather than building projection
556 : * info if no projection is required
557 : * ----------------
558 : */
559 : void
560 491436 : ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
561 : int varno)
562 : {
563 491436 : if (tlist_matches_tupdesc(planstate,
564 491436 : planstate->plan->targetlist,
565 : varno,
566 : inputDesc))
567 : {
568 263056 : planstate->ps_ProjInfo = NULL;
569 263056 : planstate->resultopsset = planstate->scanopsset;
570 263056 : planstate->resultopsfixed = planstate->scanopsfixed;
571 263056 : planstate->resultops = planstate->scanops;
572 : }
573 : else
574 : {
575 228380 : if (!planstate->ps_ResultTupleSlot)
576 : {
577 228380 : ExecInitResultSlot(planstate, &TTSOpsVirtual);
578 228380 : planstate->resultops = &TTSOpsVirtual;
579 228380 : planstate->resultopsfixed = true;
580 228380 : planstate->resultopsset = true;
581 : }
582 228380 : ExecAssignProjectionInfo(planstate, inputDesc);
583 : }
584 491436 : }
585 :
586 : static bool
587 491436 : tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc)
588 : {
589 491436 : int numattrs = tupdesc->natts;
590 : int attrno;
591 491436 : ListCell *tlist_item = list_head(tlist);
592 :
593 : /* Check the tlist attributes */
594 3394412 : for (attrno = 1; attrno <= numattrs; attrno++)
595 : {
596 3117936 : Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
597 : Var *var;
598 :
599 3117936 : if (tlist_item == NULL)
600 28118 : return false; /* tlist too short */
601 3089818 : var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
602 3089818 : if (!var || !IsA(var, Var))
603 59920 : return false; /* tlist item not a Var */
604 : /* if these Asserts fail, planner messed up */
605 : Assert(var->varno == varno);
606 : Assert(var->varlevelsup == 0);
607 3029898 : if (var->varattno != attrno)
608 126628 : return false; /* out of order */
609 2903270 : if (att_tup->attisdropped)
610 0 : return false; /* table contains dropped columns */
611 2903270 : if (att_tup->atthasmissing)
612 288 : return false; /* table contains cols with missing values */
613 :
614 : /*
615 : * Note: usually the Var's type should match the tupdesc exactly, but
616 : * in situations involving unions of columns that have different
617 : * typmods, the Var may have come from above the union and hence have
618 : * typmod -1. This is a legitimate situation since the Var still
619 : * describes the column, just not as exactly as the tupdesc does. We
620 : * could change the planner to prevent it, but it'd then insert
621 : * projection steps just to convert from specific typmod to typmod -1,
622 : * which is pretty silly.
623 : */
624 2902982 : if (var->vartype != att_tup->atttypid ||
625 2902976 : (var->vartypmod != att_tup->atttypmod &&
626 6 : var->vartypmod != -1))
627 6 : return false; /* type mismatch */
628 :
629 2902976 : tlist_item = lnext(tlist, tlist_item);
630 : }
631 :
632 276476 : if (tlist_item)
633 13420 : return false; /* tlist too long */
634 :
635 263056 : return true;
636 : }
637 :
638 :
639 : /* ----------------------------------------------------------------
640 : * Scan node support
641 : * ----------------------------------------------------------------
642 : */
643 :
644 : /* ----------------
645 : * ExecAssignScanType
646 : * ----------------
647 : */
648 : void
649 752 : ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
650 : {
651 752 : TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
652 :
653 752 : ExecSetSlotDescriptor(slot, tupDesc);
654 752 : }
655 :
656 : /* ----------------
657 : * ExecCreateScanSlotFromOuterPlan
658 : * ----------------
659 : */
660 : void
661 123828 : ExecCreateScanSlotFromOuterPlan(EState *estate,
662 : ScanState *scanstate,
663 : const TupleTableSlotOps *tts_ops)
664 : {
665 : PlanState *outerPlan;
666 : TupleDesc tupDesc;
667 :
668 123828 : outerPlan = outerPlanState(scanstate);
669 123828 : tupDesc = ExecGetResultType(outerPlan);
670 :
671 123828 : ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops);
672 123828 : }
673 :
674 : /* ----------------------------------------------------------------
675 : * ExecRelationIsTargetRelation
676 : *
677 : * Detect whether a relation (identified by rangetable index)
678 : * is one of the target relations of the query.
679 : *
680 : * Note: This is currently no longer used in core. We keep it around
681 : * because FDWs may wish to use it to determine if their foreign table
682 : * is a target relation.
683 : * ----------------------------------------------------------------
684 : */
685 : bool
686 0 : ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
687 : {
688 0 : return list_member_int(estate->es_plannedstmt->resultRelations, scanrelid);
689 : }
690 :
691 : /* ----------------------------------------------------------------
692 : * ExecOpenScanRelation
693 : *
694 : * Open the heap relation to be scanned by a base-level scan plan node.
695 : * This should be called during the node's ExecInit routine.
696 : * ----------------------------------------------------------------
697 : */
698 : Relation
699 400406 : ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
700 : {
701 : Relation rel;
702 :
703 : /* Open the relation. */
704 400406 : rel = ExecGetRangeTableRelation(estate, scanrelid);
705 :
706 : /*
707 : * Complain if we're attempting a scan of an unscannable relation, except
708 : * when the query won't actually be run. This is a slightly klugy place
709 : * to do this, perhaps, but there is no better place.
710 : */
711 400406 : if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 &&
712 370024 : !RelationIsScannable(rel))
713 12 : ereport(ERROR,
714 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
715 : errmsg("materialized view \"%s\" has not been populated",
716 : RelationGetRelationName(rel)),
717 : errhint("Use the REFRESH MATERIALIZED VIEW command.")));
718 :
719 400394 : return rel;
720 : }
721 :
722 : /*
723 : * ExecInitRangeTable
724 : * Set up executor's range-table-related data
725 : *
726 : * In addition to the range table proper, initialize arrays that are
727 : * indexed by rangetable index.
728 : */
729 : void
730 934630 : ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos)
731 : {
732 : /* Remember the range table List as-is */
733 934630 : estate->es_range_table = rangeTable;
734 :
735 : /* ... and the RTEPermissionInfo List too */
736 934630 : estate->es_rteperminfos = permInfos;
737 :
738 : /* Set size of associated arrays */
739 934630 : estate->es_range_table_size = list_length(rangeTable);
740 :
741 : /*
742 : * Allocate an array to store an open Relation corresponding to each
743 : * rangetable entry, and initialize entries to NULL. Relations are opened
744 : * and stored here as needed.
745 : */
746 934630 : estate->es_relations = (Relation *)
747 934630 : palloc0(estate->es_range_table_size * sizeof(Relation));
748 :
749 : /*
750 : * es_result_relations and es_rowmarks are also parallel to
751 : * es_range_table, but are allocated only if needed.
752 : */
753 934630 : estate->es_result_relations = NULL;
754 934630 : estate->es_rowmarks = NULL;
755 934630 : }
756 :
757 : /*
758 : * ExecGetRangeTableRelation
759 : * Open the Relation for a range table entry, if not already done
760 : *
761 : * The Relations will be closed in ExecEndPlan().
762 : */
763 : Relation
764 538230 : ExecGetRangeTableRelation(EState *estate, Index rti)
765 : {
766 : Relation rel;
767 :
768 : Assert(rti > 0 && rti <= estate->es_range_table_size);
769 :
770 538230 : rel = estate->es_relations[rti - 1];
771 538230 : if (rel == NULL)
772 : {
773 : /* First time through, so open the relation */
774 498758 : RangeTblEntry *rte = exec_rt_fetch(rti, estate);
775 :
776 : Assert(rte->rtekind == RTE_RELATION);
777 :
778 498758 : if (!IsParallelWorker())
779 : {
780 : /*
781 : * In a normal query, we should already have the appropriate lock,
782 : * but verify that through an Assert. Since there's already an
783 : * Assert inside table_open that insists on holding some lock, it
784 : * seems sufficient to check this only when rellockmode is higher
785 : * than the minimum.
786 : */
787 494148 : rel = table_open(rte->relid, NoLock);
788 : Assert(rte->rellockmode == AccessShareLock ||
789 : CheckRelationLockedByMe(rel, rte->rellockmode, false));
790 : }
791 : else
792 : {
793 : /*
794 : * If we are a parallel worker, we need to obtain our own local
795 : * lock on the relation. This ensures sane behavior in case the
796 : * parent process exits before we do.
797 : */
798 4610 : rel = table_open(rte->relid, rte->rellockmode);
799 : }
800 :
801 498758 : estate->es_relations[rti - 1] = rel;
802 : }
803 :
804 538230 : return rel;
805 : }
806 :
807 : /*
808 : * ExecInitResultRelation
809 : * Open relation given by the passed-in RT index and fill its
810 : * ResultRelInfo node
811 : *
812 : * Here, we also save the ResultRelInfo in estate->es_result_relations array
813 : * such that it can be accessed later using the RT index.
814 : */
815 : void
816 125814 : ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
817 : Index rti)
818 : {
819 : Relation resultRelationDesc;
820 :
821 125814 : resultRelationDesc = ExecGetRangeTableRelation(estate, rti);
822 125814 : InitResultRelInfo(resultRelInfo,
823 : resultRelationDesc,
824 : rti,
825 : NULL,
826 : estate->es_instrument);
827 :
828 125814 : if (estate->es_result_relations == NULL)
829 120734 : estate->es_result_relations = (ResultRelInfo **)
830 120734 : palloc0(estate->es_range_table_size * sizeof(ResultRelInfo *));
831 125814 : estate->es_result_relations[rti - 1] = resultRelInfo;
832 :
833 : /*
834 : * Saving in the list allows to avoid needlessly traversing the whole
835 : * array when only a few of its entries are possibly non-NULL.
836 : */
837 125814 : estate->es_opened_result_relations =
838 125814 : lappend(estate->es_opened_result_relations, resultRelInfo);
839 125814 : }
840 :
841 : /*
842 : * UpdateChangedParamSet
843 : * Add changed parameters to a plan node's chgParam set
844 : */
845 : void
846 726756 : UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
847 : {
848 : Bitmapset *parmset;
849 :
850 : /*
851 : * The plan node only depends on params listed in its allParam set. Don't
852 : * include anything else into its chgParam set.
853 : */
854 726756 : parmset = bms_intersect(node->plan->allParam, newchg);
855 726756 : node->chgParam = bms_join(node->chgParam, parmset);
856 726756 : }
857 :
858 : /*
859 : * executor_errposition
860 : * Report an execution-time cursor position, if possible.
861 : *
862 : * This is expected to be used within an ereport() call. The return value
863 : * is a dummy (always 0, in fact).
864 : *
865 : * The locations stored in parsetrees are byte offsets into the source string.
866 : * We have to convert them to 1-based character indexes for reporting to
867 : * clients. (We do things this way to avoid unnecessary overhead in the
868 : * normal non-error case: computing character indexes would be much more
869 : * expensive than storing token offsets.)
870 : */
871 : int
872 0 : executor_errposition(EState *estate, int location)
873 : {
874 : int pos;
875 :
876 : /* No-op if location was not provided */
877 0 : if (location < 0)
878 0 : return 0;
879 : /* Can't do anything if source text is not available */
880 0 : if (estate == NULL || estate->es_sourceText == NULL)
881 0 : return 0;
882 : /* Convert offset to character number */
883 0 : pos = pg_mbstrlen_with_len(estate->es_sourceText, location) + 1;
884 : /* And pass it to the ereport mechanism */
885 0 : return errposition(pos);
886 : }
887 :
888 : /*
889 : * Register a shutdown callback in an ExprContext.
890 : *
891 : * Shutdown callbacks will be called (in reverse order of registration)
892 : * when the ExprContext is deleted or rescanned. This provides a hook
893 : * for functions called in the context to do any cleanup needed --- it's
894 : * particularly useful for functions returning sets. Note that the
895 : * callback will *not* be called in the event that execution is aborted
896 : * by an error.
897 : */
898 : void
899 148404 : RegisterExprContextCallback(ExprContext *econtext,
900 : ExprContextCallbackFunction function,
901 : Datum arg)
902 : {
903 : ExprContext_CB *ecxt_callback;
904 :
905 : /* Save the info in appropriate memory context */
906 : ecxt_callback = (ExprContext_CB *)
907 148404 : MemoryContextAlloc(econtext->ecxt_per_query_memory,
908 : sizeof(ExprContext_CB));
909 :
910 148404 : ecxt_callback->function = function;
911 148404 : ecxt_callback->arg = arg;
912 :
913 : /* link to front of list for appropriate execution order */
914 148404 : ecxt_callback->next = econtext->ecxt_callbacks;
915 148404 : econtext->ecxt_callbacks = ecxt_callback;
916 148404 : }
917 :
918 : /*
919 : * Deregister a shutdown callback in an ExprContext.
920 : *
921 : * Any list entries matching the function and arg will be removed.
922 : * This can be used if it's no longer necessary to call the callback.
923 : */
924 : void
925 123860 : UnregisterExprContextCallback(ExprContext *econtext,
926 : ExprContextCallbackFunction function,
927 : Datum arg)
928 : {
929 : ExprContext_CB **prev_callback;
930 : ExprContext_CB *ecxt_callback;
931 :
932 123860 : prev_callback = &econtext->ecxt_callbacks;
933 :
934 353564 : while ((ecxt_callback = *prev_callback) != NULL)
935 : {
936 229704 : if (ecxt_callback->function == function && ecxt_callback->arg == arg)
937 : {
938 123860 : *prev_callback = ecxt_callback->next;
939 123860 : pfree(ecxt_callback);
940 : }
941 : else
942 105844 : prev_callback = &ecxt_callback->next;
943 : }
944 123860 : }
945 :
946 : /*
947 : * Call all the shutdown callbacks registered in an ExprContext.
948 : *
949 : * The callback list is emptied (important in case this is only a rescan
950 : * reset, and not deletion of the ExprContext).
951 : *
952 : * If isCommit is false, just clean the callback list but don't call 'em.
953 : * (See comment for FreeExprContext.)
954 : */
955 : static void
956 5399154 : ShutdownExprContext(ExprContext *econtext, bool isCommit)
957 : {
958 : ExprContext_CB *ecxt_callback;
959 : MemoryContext oldcontext;
960 :
961 : /* Fast path in normal case where there's nothing to do. */
962 5399154 : if (econtext->ecxt_callbacks == NULL)
963 5376732 : return;
964 :
965 : /*
966 : * Call the callbacks in econtext's per-tuple context. This ensures that
967 : * any memory they might leak will get cleaned up.
968 : */
969 22422 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
970 :
971 : /*
972 : * Call each callback function in reverse registration order.
973 : */
974 45244 : while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
975 : {
976 22822 : econtext->ecxt_callbacks = ecxt_callback->next;
977 22822 : if (isCommit)
978 22822 : ecxt_callback->function(ecxt_callback->arg);
979 22822 : pfree(ecxt_callback);
980 : }
981 :
982 22422 : MemoryContextSwitchTo(oldcontext);
983 : }
984 :
985 : /*
986 : * GetAttributeByName
987 : * GetAttributeByNum
988 : *
989 : * These functions return the value of the requested attribute
990 : * out of the given tuple Datum.
991 : * C functions which take a tuple as an argument are expected
992 : * to use these. Ex: overpaid(EMP) might call GetAttributeByNum().
993 : * Note: these are actually rather slow because they do a typcache
994 : * lookup on each call.
995 : */
996 : Datum
997 36 : GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull)
998 : {
999 : AttrNumber attrno;
1000 : Datum result;
1001 : Oid tupType;
1002 : int32 tupTypmod;
1003 : TupleDesc tupDesc;
1004 : HeapTupleData tmptup;
1005 : int i;
1006 :
1007 36 : if (attname == NULL)
1008 0 : elog(ERROR, "invalid attribute name");
1009 :
1010 36 : if (isNull == NULL)
1011 0 : elog(ERROR, "a NULL isNull pointer was passed");
1012 :
1013 36 : if (tuple == NULL)
1014 : {
1015 : /* Kinda bogus but compatible with old behavior... */
1016 0 : *isNull = true;
1017 0 : return (Datum) 0;
1018 : }
1019 :
1020 36 : tupType = HeapTupleHeaderGetTypeId(tuple);
1021 36 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
1022 36 : tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1023 :
1024 36 : attrno = InvalidAttrNumber;
1025 144 : for (i = 0; i < tupDesc->natts; i++)
1026 : {
1027 144 : Form_pg_attribute att = TupleDescAttr(tupDesc, i);
1028 :
1029 144 : if (namestrcmp(&(att->attname), attname) == 0)
1030 : {
1031 36 : attrno = att->attnum;
1032 36 : break;
1033 : }
1034 : }
1035 :
1036 36 : if (attrno == InvalidAttrNumber)
1037 0 : elog(ERROR, "attribute \"%s\" does not exist", attname);
1038 :
1039 : /*
1040 : * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all
1041 : * the fields in the struct just in case user tries to inspect system
1042 : * columns.
1043 : */
1044 36 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
1045 36 : ItemPointerSetInvalid(&(tmptup.t_self));
1046 36 : tmptup.t_tableOid = InvalidOid;
1047 36 : tmptup.t_data = tuple;
1048 :
1049 36 : result = heap_getattr(&tmptup,
1050 : attrno,
1051 : tupDesc,
1052 : isNull);
1053 :
1054 36 : ReleaseTupleDesc(tupDesc);
1055 :
1056 36 : return result;
1057 : }
1058 :
1059 : Datum
1060 0 : GetAttributeByNum(HeapTupleHeader tuple,
1061 : AttrNumber attrno,
1062 : bool *isNull)
1063 : {
1064 : Datum result;
1065 : Oid tupType;
1066 : int32 tupTypmod;
1067 : TupleDesc tupDesc;
1068 : HeapTupleData tmptup;
1069 :
1070 0 : if (!AttributeNumberIsValid(attrno))
1071 0 : elog(ERROR, "invalid attribute number %d", attrno);
1072 :
1073 0 : if (isNull == NULL)
1074 0 : elog(ERROR, "a NULL isNull pointer was passed");
1075 :
1076 0 : if (tuple == NULL)
1077 : {
1078 : /* Kinda bogus but compatible with old behavior... */
1079 0 : *isNull = true;
1080 0 : return (Datum) 0;
1081 : }
1082 :
1083 0 : tupType = HeapTupleHeaderGetTypeId(tuple);
1084 0 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
1085 0 : tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1086 :
1087 : /*
1088 : * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all
1089 : * the fields in the struct just in case user tries to inspect system
1090 : * columns.
1091 : */
1092 0 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
1093 0 : ItemPointerSetInvalid(&(tmptup.t_self));
1094 0 : tmptup.t_tableOid = InvalidOid;
1095 0 : tmptup.t_data = tuple;
1096 :
1097 0 : result = heap_getattr(&tmptup,
1098 : attrno,
1099 : tupDesc,
1100 : isNull);
1101 :
1102 0 : ReleaseTupleDesc(tupDesc);
1103 :
1104 0 : return result;
1105 : }
1106 :
1107 : /*
1108 : * Number of items in a tlist (including any resjunk items!)
1109 : */
1110 : int
1111 1316652 : ExecTargetListLength(List *targetlist)
1112 : {
1113 : /* This used to be more complex, but fjoins are dead */
1114 1316652 : return list_length(targetlist);
1115 : }
1116 :
1117 : /*
1118 : * Number of items in a tlist, not including any resjunk items
1119 : */
1120 : int
1121 195692 : ExecCleanTargetListLength(List *targetlist)
1122 : {
1123 195692 : int len = 0;
1124 : ListCell *tl;
1125 :
1126 651948 : foreach(tl, targetlist)
1127 : {
1128 456256 : TargetEntry *curTle = lfirst_node(TargetEntry, tl);
1129 :
1130 456256 : if (!curTle->resjunk)
1131 424814 : len++;
1132 : }
1133 195692 : return len;
1134 : }
1135 :
1136 : /*
1137 : * Return a relInfo's tuple slot for a trigger's OLD tuples.
1138 : */
1139 : TupleTableSlot *
1140 23928 : ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
1141 : {
1142 23928 : if (relInfo->ri_TrigOldSlot == NULL)
1143 : {
1144 9890 : Relation rel = relInfo->ri_RelationDesc;
1145 9890 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1146 :
1147 9890 : relInfo->ri_TrigOldSlot =
1148 9890 : ExecInitExtraTupleSlot(estate,
1149 : RelationGetDescr(rel),
1150 : table_slot_callbacks(rel));
1151 :
1152 9890 : MemoryContextSwitchTo(oldcontext);
1153 : }
1154 :
1155 23928 : return relInfo->ri_TrigOldSlot;
1156 : }
1157 :
1158 : /*
1159 : * Return a relInfo's tuple slot for a trigger's NEW tuples.
1160 : */
1161 : TupleTableSlot *
1162 3506 : ExecGetTriggerNewSlot(EState *estate, ResultRelInfo *relInfo)
1163 : {
1164 3506 : if (relInfo->ri_TrigNewSlot == NULL)
1165 : {
1166 2190 : Relation rel = relInfo->ri_RelationDesc;
1167 2190 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1168 :
1169 2190 : relInfo->ri_TrigNewSlot =
1170 2190 : ExecInitExtraTupleSlot(estate,
1171 : RelationGetDescr(rel),
1172 : table_slot_callbacks(rel));
1173 :
1174 2190 : MemoryContextSwitchTo(oldcontext);
1175 : }
1176 :
1177 3506 : return relInfo->ri_TrigNewSlot;
1178 : }
1179 :
1180 : /*
1181 : * Return a relInfo's tuple slot for processing returning tuples.
1182 : */
1183 : TupleTableSlot *
1184 1154 : ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
1185 : {
1186 1154 : if (relInfo->ri_ReturningSlot == NULL)
1187 : {
1188 542 : Relation rel = relInfo->ri_RelationDesc;
1189 542 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1190 :
1191 542 : relInfo->ri_ReturningSlot =
1192 542 : ExecInitExtraTupleSlot(estate,
1193 : RelationGetDescr(rel),
1194 : table_slot_callbacks(rel));
1195 :
1196 542 : MemoryContextSwitchTo(oldcontext);
1197 : }
1198 :
1199 1154 : return relInfo->ri_ReturningSlot;
1200 : }
1201 :
1202 : /*
1203 : * Return the map needed to convert given child result relation's tuples to
1204 : * the rowtype of the query's main target ("root") relation. Note that a
1205 : * NULL result is valid and means that no conversion is needed.
1206 : */
1207 : TupleConversionMap *
1208 67772 : ExecGetChildToRootMap(ResultRelInfo *resultRelInfo)
1209 : {
1210 : /* If we didn't already do so, compute the map for this child. */
1211 67772 : if (!resultRelInfo->ri_ChildToRootMapValid)
1212 : {
1213 1604 : ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1214 :
1215 1604 : if (rootRelInfo)
1216 1238 : resultRelInfo->ri_ChildToRootMap =
1217 1238 : convert_tuples_by_name(RelationGetDescr(resultRelInfo->ri_RelationDesc),
1218 1238 : RelationGetDescr(rootRelInfo->ri_RelationDesc));
1219 : else /* this isn't a child result rel */
1220 366 : resultRelInfo->ri_ChildToRootMap = NULL;
1221 :
1222 1604 : resultRelInfo->ri_ChildToRootMapValid = true;
1223 : }
1224 :
1225 67772 : return resultRelInfo->ri_ChildToRootMap;
1226 : }
1227 :
1228 : /*
1229 : * Returns the map needed to convert given root result relation's tuples to
1230 : * the rowtype of the given child relation. Note that a NULL result is valid
1231 : * and means that no conversion is needed.
1232 : */
1233 : TupleConversionMap *
1234 1007618 : ExecGetRootToChildMap(ResultRelInfo *resultRelInfo, EState *estate)
1235 : {
1236 : /* Mustn't get called for a non-child result relation. */
1237 : Assert(resultRelInfo->ri_RootResultRelInfo);
1238 :
1239 : /* If we didn't already do so, compute the map for this child. */
1240 1007618 : if (!resultRelInfo->ri_RootToChildMapValid)
1241 : {
1242 9460 : ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1243 9460 : TupleDesc indesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
1244 9460 : TupleDesc outdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
1245 9460 : Relation childrel = resultRelInfo->ri_RelationDesc;
1246 : AttrMap *attrMap;
1247 : MemoryContext oldcontext;
1248 :
1249 : /*
1250 : * When this child table is not a partition (!relispartition), it may
1251 : * have columns that are not present in the root table, which we ask
1252 : * to ignore by passing true for missing_ok.
1253 : */
1254 9460 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1255 9460 : attrMap = build_attrmap_by_name_if_req(indesc, outdesc,
1256 9460 : !childrel->rd_rel->relispartition);
1257 9460 : if (attrMap)
1258 1428 : resultRelInfo->ri_RootToChildMap =
1259 1428 : convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
1260 9460 : MemoryContextSwitchTo(oldcontext);
1261 9460 : resultRelInfo->ri_RootToChildMapValid = true;
1262 : }
1263 :
1264 1007618 : return resultRelInfo->ri_RootToChildMap;
1265 : }
1266 :
1267 : /* Return a bitmap representing columns being inserted */
1268 : Bitmapset *
1269 1234 : ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
1270 : {
1271 1234 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
1272 :
1273 1234 : if (perminfo == NULL)
1274 0 : return NULL;
1275 :
1276 : /* Map the columns to child's attribute numbers if needed. */
1277 1234 : if (relinfo->ri_RootResultRelInfo)
1278 : {
1279 6 : TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
1280 :
1281 6 : if (map)
1282 4 : return execute_attr_map_cols(map->attrMap, perminfo->insertedCols);
1283 : }
1284 :
1285 1230 : return perminfo->insertedCols;
1286 : }
1287 :
1288 : /* Return a bitmap representing columns being updated */
1289 : Bitmapset *
1290 59376 : ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1291 : {
1292 59376 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
1293 :
1294 59376 : if (perminfo == NULL)
1295 0 : return NULL;
1296 :
1297 : /* Map the columns to child's attribute numbers if needed. */
1298 59376 : if (relinfo->ri_RootResultRelInfo)
1299 : {
1300 1798 : TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
1301 :
1302 1798 : if (map)
1303 490 : return execute_attr_map_cols(map->attrMap, perminfo->updatedCols);
1304 : }
1305 :
1306 58886 : return perminfo->updatedCols;
1307 : }
1308 :
1309 : /* Return a bitmap representing generated columns being updated */
1310 : Bitmapset *
1311 57938 : ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1312 : {
1313 : /* Compute the info if we didn't already */
1314 57938 : if (relinfo->ri_GeneratedExprsU == NULL)
1315 57818 : ExecInitStoredGenerated(relinfo, estate, CMD_UPDATE);
1316 57938 : return relinfo->ri_extraUpdatedCols;
1317 : }
1318 :
1319 : /*
1320 : * Return columns being updated, including generated columns
1321 : *
1322 : * The bitmap is allocated in per-tuple memory context. It's up to the caller to
1323 : * copy it into a different context with the appropriate lifespan, if needed.
1324 : */
1325 : Bitmapset *
1326 14656 : ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1327 : {
1328 : Bitmapset *ret;
1329 : MemoryContext oldcxt;
1330 :
1331 14656 : oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
1332 :
1333 14656 : ret = bms_union(ExecGetUpdatedCols(relinfo, estate),
1334 14656 : ExecGetExtraUpdatedCols(relinfo, estate));
1335 :
1336 14656 : MemoryContextSwitchTo(oldcxt);
1337 :
1338 14656 : return ret;
1339 : }
1340 :
1341 : /*
1342 : * GetResultRTEPermissionInfo
1343 : * Looks up RTEPermissionInfo for ExecGet*Cols() routines
1344 : */
1345 : static RTEPermissionInfo *
1346 60950 : GetResultRTEPermissionInfo(ResultRelInfo *relinfo, EState *estate)
1347 : {
1348 : Index rti;
1349 : RangeTblEntry *rte;
1350 60950 : RTEPermissionInfo *perminfo = NULL;
1351 :
1352 60950 : if (relinfo->ri_RootResultRelInfo)
1353 : {
1354 : /*
1355 : * For inheritance child result relations (a partition routing target
1356 : * of an INSERT or a child UPDATE target), this returns the root
1357 : * parent's RTE to fetch the RTEPermissionInfo because that's the only
1358 : * one that has one assigned.
1359 : */
1360 1900 : rti = relinfo->ri_RootResultRelInfo->ri_RangeTableIndex;
1361 : }
1362 59050 : else if (relinfo->ri_RangeTableIndex != 0)
1363 : {
1364 : /*
1365 : * Non-child result relation should have their own RTEPermissionInfo.
1366 : */
1367 59050 : rti = relinfo->ri_RangeTableIndex;
1368 : }
1369 : else
1370 : {
1371 : /*
1372 : * The relation isn't in the range table and it isn't a partition
1373 : * routing target. This ResultRelInfo must've been created only for
1374 : * firing triggers and the relation is not being inserted into. (See
1375 : * ExecGetTriggerResultRel.)
1376 : */
1377 0 : rti = 0;
1378 : }
1379 :
1380 60950 : if (rti > 0)
1381 : {
1382 60950 : rte = exec_rt_fetch(rti, estate);
1383 60950 : perminfo = getRTEPermissionInfo(estate->es_rteperminfos, rte);
1384 : }
1385 :
1386 60950 : return perminfo;
1387 : }
1388 :
1389 : /*
1390 : * ExecGetResultRelCheckAsUser
1391 : * Returns the user to modify passed-in result relation as
1392 : *
1393 : * The user is chosen by looking up the relation's or, if a child table, its
1394 : * root parent's RTEPermissionInfo.
1395 : */
1396 : Oid
1397 340 : ExecGetResultRelCheckAsUser(ResultRelInfo *relInfo, EState *estate)
1398 : {
1399 340 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relInfo, estate);
1400 :
1401 : /* XXX - maybe ok to return GetUserId() in this case? */
1402 340 : if (perminfo == NULL)
1403 0 : elog(ERROR, "no RTEPermissionInfo found for result relation with OID %u",
1404 : RelationGetRelid(relInfo->ri_RelationDesc));
1405 :
1406 340 : return perminfo->checkAsUser ? perminfo->checkAsUser : GetUserId();
1407 : }
|