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