LCOV - code coverage report
Current view: top level - src/backend/executor - execUtils.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 292 333 87.7 %
Date: 2019-06-18 07:06:57 Functions: 29 32 90.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * execUtils.c
       4             :  *    miscellaneous executor utility routines
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, 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 "jit/jit.h"
      55             : #include "mb/pg_wchar.h"
      56             : #include "nodes/nodeFuncs.h"
      57             : #include "parser/parsetree.h"
      58             : #include "partitioning/partdesc.h"
      59             : #include "storage/lmgr.h"
      60             : #include "utils/builtins.h"
      61             : #include "utils/memutils.h"
      62             : #include "utils/rel.h"
      63             : #include "utils/typcache.h"
      64             : 
      65             : 
      66             : static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
      67             : static void ShutdownExprContext(ExprContext *econtext, bool isCommit);
      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      520592 : 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      520592 :     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      520592 :     oldcontext = MemoryContextSwitchTo(qcontext);
     106             : 
     107      520592 :     estate = makeNode(EState);
     108             : 
     109             :     /*
     110             :      * Initialize all fields of the Executor State structure
     111             :      */
     112      520592 :     estate->es_direction = ForwardScanDirection;
     113      520592 :     estate->es_snapshot = InvalidSnapshot;   /* caller must initialize this */
     114      520592 :     estate->es_crosscheck_snapshot = InvalidSnapshot;    /* no crosscheck */
     115      520592 :     estate->es_range_table = NIL;
     116      520592 :     estate->es_range_table_array = NULL;
     117      520592 :     estate->es_range_table_size = 0;
     118      520592 :     estate->es_relations = NULL;
     119      520592 :     estate->es_rowmarks = NULL;
     120      520592 :     estate->es_plannedstmt = NULL;
     121             : 
     122      520592 :     estate->es_junkFilter = NULL;
     123             : 
     124      520592 :     estate->es_output_cid = (CommandId) 0;
     125             : 
     126      520592 :     estate->es_result_relations = NULL;
     127      520592 :     estate->es_num_result_relations = 0;
     128      520592 :     estate->es_result_relation_info = NULL;
     129             : 
     130      520592 :     estate->es_root_result_relations = NULL;
     131      520592 :     estate->es_num_root_result_relations = 0;
     132             : 
     133      520592 :     estate->es_tuple_routing_result_relations = NIL;
     134             : 
     135      520592 :     estate->es_trig_target_relations = NIL;
     136             : 
     137      520592 :     estate->es_param_list_info = NULL;
     138      520592 :     estate->es_param_exec_vals = NULL;
     139             : 
     140      520592 :     estate->es_queryEnv = NULL;
     141             : 
     142      520592 :     estate->es_query_cxt = qcontext;
     143             : 
     144      520592 :     estate->es_tupleTable = NIL;
     145             : 
     146      520592 :     estate->es_processed = 0;
     147             : 
     148      520592 :     estate->es_top_eflags = 0;
     149      520592 :     estate->es_instrument = 0;
     150      520592 :     estate->es_finished = false;
     151             : 
     152      520592 :     estate->es_exprcontexts = NIL;
     153             : 
     154      520592 :     estate->es_subplanstates = NIL;
     155             : 
     156      520592 :     estate->es_auxmodifytables = NIL;
     157             : 
     158      520592 :     estate->es_per_tuple_exprcontext = NULL;
     159             : 
     160      520592 :     estate->es_epqTupleSlot = NULL;
     161      520592 :     estate->es_epqScanDone = NULL;
     162      520592 :     estate->es_sourceText = NULL;
     163             : 
     164      520592 :     estate->es_use_parallel_mode = false;
     165             : 
     166      520592 :     estate->es_jit_flags = 0;
     167      520592 :     estate->es_jit = NULL;
     168             : 
     169             :     /*
     170             :      * Return the executor state structure
     171             :      */
     172      520592 :     MemoryContextSwitchTo(oldcontext);
     173             : 
     174      520592 :     return estate;
     175             : }
     176             : 
     177             : /* ----------------
     178             :  *      FreeExecutorState
     179             :  *
     180             :  *      Release an EState along with all remaining working storage.
     181             :  *
     182             :  * Note: this is not responsible for releasing non-memory resources, such as
     183             :  * open relations or buffer pins.  But it will shut down any still-active
     184             :  * ExprContexts within the EState and deallocate associated JITed expressions.
     185             :  * That is sufficient cleanup for situations where the EState has only been
     186             :  * used for expression evaluation, and not to run a complete Plan.
     187             :  *
     188             :  * This can be called in any memory context ... so long as it's not one
     189             :  * of the ones to be freed.
     190             :  * ----------------
     191             :  */
     192             : void
     193      505072 : FreeExecutorState(EState *estate)
     194             : {
     195             :     /*
     196             :      * Shut down and free any remaining ExprContexts.  We do this explicitly
     197             :      * to ensure that any remaining shutdown callbacks get called (since they
     198             :      * might need to release resources that aren't simply memory within the
     199             :      * per-query memory context).
     200             :      */
     201     1895184 :     while (estate->es_exprcontexts)
     202             :     {
     203             :         /*
     204             :          * XXX: seems there ought to be a faster way to implement this than
     205             :          * repeated list_delete(), no?
     206             :          */
     207      885040 :         FreeExprContext((ExprContext *) linitial(estate->es_exprcontexts),
     208             :                         true);
     209             :         /* FreeExprContext removed the list link for us */
     210             :     }
     211             : 
     212             :     /* release JIT context, if allocated */
     213      505072 :     if (estate->es_jit)
     214             :     {
     215         834 :         jit_release_context(estate->es_jit);
     216         834 :         estate->es_jit = NULL;
     217             :     }
     218             : 
     219             :     /* release partition directory, if allocated */
     220      505072 :     if (estate->es_partition_directory)
     221             :     {
     222        1898 :         DestroyPartitionDirectory(estate->es_partition_directory);
     223        1898 :         estate->es_partition_directory = NULL;
     224             :     }
     225             : 
     226             :     /*
     227             :      * Free the per-query memory context, thereby releasing all working
     228             :      * memory, including the EState node itself.
     229             :      */
     230      505072 :     MemoryContextDelete(estate->es_query_cxt);
     231      505072 : }
     232             : 
     233             : /* ----------------
     234             :  *      CreateExprContext
     235             :  *
     236             :  *      Create a context for expression evaluation within an EState.
     237             :  *
     238             :  * An executor run may require multiple ExprContexts (we usually make one
     239             :  * for each Plan node, and a separate one for per-output-tuple processing
     240             :  * such as constraint checking).  Each ExprContext has its own "per-tuple"
     241             :  * memory context.
     242             :  *
     243             :  * Note we make no assumption about the caller's memory context.
     244             :  * ----------------
     245             :  */
     246             : ExprContext *
     247      971488 : CreateExprContext(EState *estate)
     248             : {
     249             :     ExprContext *econtext;
     250             :     MemoryContext oldcontext;
     251             : 
     252             :     /* Create the ExprContext node within the per-query memory context */
     253      971488 :     oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
     254             : 
     255      971488 :     econtext = makeNode(ExprContext);
     256             : 
     257             :     /* Initialize fields of ExprContext */
     258      971488 :     econtext->ecxt_scantuple = NULL;
     259      971488 :     econtext->ecxt_innertuple = NULL;
     260      971488 :     econtext->ecxt_outertuple = NULL;
     261             : 
     262      971488 :     econtext->ecxt_per_query_memory = estate->es_query_cxt;
     263             : 
     264             :     /*
     265             :      * Create working memory for expression evaluation in this context.
     266             :      */
     267      971488 :     econtext->ecxt_per_tuple_memory =
     268      971488 :         AllocSetContextCreate(estate->es_query_cxt,
     269             :                               "ExprContext",
     270             :                               ALLOCSET_DEFAULT_SIZES);
     271             : 
     272      971488 :     econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
     273      971488 :     econtext->ecxt_param_list_info = estate->es_param_list_info;
     274             : 
     275      971488 :     econtext->ecxt_aggvalues = NULL;
     276      971488 :     econtext->ecxt_aggnulls = NULL;
     277             : 
     278      971488 :     econtext->caseValue_datum = (Datum) 0;
     279      971488 :     econtext->caseValue_isNull = true;
     280             : 
     281      971488 :     econtext->domainValue_datum = (Datum) 0;
     282      971488 :     econtext->domainValue_isNull = true;
     283             : 
     284      971488 :     econtext->ecxt_estate = estate;
     285             : 
     286      971488 :     econtext->ecxt_callbacks = NULL;
     287             : 
     288             :     /*
     289             :      * Link the ExprContext into the EState to ensure it is shut down when the
     290             :      * EState is freed.  Because we use lcons(), shutdowns will occur in
     291             :      * reverse order of creation, which may not be essential but can't hurt.
     292             :      */
     293      971488 :     estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
     294             : 
     295      971488 :     MemoryContextSwitchTo(oldcontext);
     296             : 
     297      971488 :     return econtext;
     298             : }
     299             : 
     300             : /* ----------------
     301             :  *      CreateStandaloneExprContext
     302             :  *
     303             :  *      Create a context for standalone expression evaluation.
     304             :  *
     305             :  * An ExprContext made this way can be used for evaluation of expressions
     306             :  * that contain no Params, subplans, or Var references (it might work to
     307             :  * put tuple references into the scantuple field, but it seems unwise).
     308             :  *
     309             :  * The ExprContext struct is allocated in the caller's current memory
     310             :  * context, which also becomes its "per query" context.
     311             :  *
     312             :  * It is caller's responsibility to free the ExprContext when done,
     313             :  * or at least ensure that any shutdown callbacks have been called
     314             :  * (ReScanExprContext() is suitable).  Otherwise, non-memory resources
     315             :  * might be leaked.
     316             :  * ----------------
     317             :  */
     318             : ExprContext *
     319        5668 : CreateStandaloneExprContext(void)
     320             : {
     321             :     ExprContext *econtext;
     322             : 
     323             :     /* Create the ExprContext node within the caller's memory context */
     324        5668 :     econtext = makeNode(ExprContext);
     325             : 
     326             :     /* Initialize fields of ExprContext */
     327        5668 :     econtext->ecxt_scantuple = NULL;
     328        5668 :     econtext->ecxt_innertuple = NULL;
     329        5668 :     econtext->ecxt_outertuple = NULL;
     330             : 
     331        5668 :     econtext->ecxt_per_query_memory = CurrentMemoryContext;
     332             : 
     333             :     /*
     334             :      * Create working memory for expression evaluation in this context.
     335             :      */
     336        5668 :     econtext->ecxt_per_tuple_memory =
     337        5668 :         AllocSetContextCreate(CurrentMemoryContext,
     338             :                               "ExprContext",
     339             :                               ALLOCSET_DEFAULT_SIZES);
     340             : 
     341        5668 :     econtext->ecxt_param_exec_vals = NULL;
     342        5668 :     econtext->ecxt_param_list_info = NULL;
     343             : 
     344        5668 :     econtext->ecxt_aggvalues = NULL;
     345        5668 :     econtext->ecxt_aggnulls = NULL;
     346             : 
     347        5668 :     econtext->caseValue_datum = (Datum) 0;
     348        5668 :     econtext->caseValue_isNull = true;
     349             : 
     350        5668 :     econtext->domainValue_datum = (Datum) 0;
     351        5668 :     econtext->domainValue_isNull = true;
     352             : 
     353        5668 :     econtext->ecxt_estate = NULL;
     354             : 
     355        5668 :     econtext->ecxt_callbacks = NULL;
     356             : 
     357        5668 :     return econtext;
     358             : }
     359             : 
     360             : /* ----------------
     361             :  *      FreeExprContext
     362             :  *
     363             :  *      Free an expression context, including calling any remaining
     364             :  *      shutdown callbacks.
     365             :  *
     366             :  * Since we free the temporary context used for expression evaluation,
     367             :  * any previously computed pass-by-reference expression result will go away!
     368             :  *
     369             :  * If isCommit is false, we are being called in error cleanup, and should
     370             :  * not call callbacks but only release memory.  (It might be better to call
     371             :  * the callbacks and pass the isCommit flag to them, but that would require
     372             :  * more invasive code changes than currently seems justified.)
     373             :  *
     374             :  * Note we make no assumption about the caller's memory context.
     375             :  * ----------------
     376             :  */
     377             : void
     378      953400 : FreeExprContext(ExprContext *econtext, bool isCommit)
     379             : {
     380             :     EState     *estate;
     381             : 
     382             :     /* Call any registered callbacks */
     383      953400 :     ShutdownExprContext(econtext, isCommit);
     384             :     /* And clean up the memory used */
     385      953400 :     MemoryContextDelete(econtext->ecxt_per_tuple_memory);
     386             :     /* Unlink self from owning EState, if any */
     387      953400 :     estate = econtext->ecxt_estate;
     388      953400 :     if (estate)
     389      953400 :         estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts,
     390             :                                                   econtext);
     391             :     /* And delete the ExprContext node */
     392      953400 :     pfree(econtext);
     393      953400 : }
     394             : 
     395             : /*
     396             :  * ReScanExprContext
     397             :  *
     398             :  *      Reset an expression context in preparation for a rescan of its
     399             :  *      plan node.  This requires calling any registered shutdown callbacks,
     400             :  *      since any partially complete set-returning-functions must be canceled.
     401             :  *
     402             :  * Note we make no assumption about the caller's memory context.
     403             :  */
     404             : void
     405     9261236 : ReScanExprContext(ExprContext *econtext)
     406             : {
     407             :     /* Call any registered callbacks */
     408     9261236 :     ShutdownExprContext(econtext, true);
     409             :     /* And clean up the memory used */
     410     9261236 :     MemoryContextReset(econtext->ecxt_per_tuple_memory);
     411     9261236 : }
     412             : 
     413             : /*
     414             :  * Build a per-output-tuple ExprContext for an EState.
     415             :  *
     416             :  * This is normally invoked via GetPerTupleExprContext() macro,
     417             :  * not directly.
     418             :  */
     419             : ExprContext *
     420      264684 : MakePerTupleExprContext(EState *estate)
     421             : {
     422      264684 :     if (estate->es_per_tuple_exprcontext == NULL)
     423      264684 :         estate->es_per_tuple_exprcontext = CreateExprContext(estate);
     424             : 
     425      264684 :     return estate->es_per_tuple_exprcontext;
     426             : }
     427             : 
     428             : 
     429             : /* ----------------------------------------------------------------
     430             :  *               miscellaneous node-init support functions
     431             :  *
     432             :  * Note: all of these are expected to be called with CurrentMemoryContext
     433             :  * equal to the per-query memory context.
     434             :  * ----------------------------------------------------------------
     435             :  */
     436             : 
     437             : /* ----------------
     438             :  *      ExecAssignExprContext
     439             :  *
     440             :  *      This initializes the ps_ExprContext field.  It is only necessary
     441             :  *      to do this for nodes which use ExecQual or ExecProject
     442             :  *      because those routines require an econtext. Other nodes that
     443             :  *      don't have to evaluate expressions don't need to do this.
     444             :  * ----------------
     445             :  */
     446             : void
     447      628366 : ExecAssignExprContext(EState *estate, PlanState *planstate)
     448             : {
     449      628366 :     planstate->ps_ExprContext = CreateExprContext(estate);
     450      628366 : }
     451             : 
     452             : /* ----------------
     453             :  *      ExecGetResultType
     454             :  * ----------------
     455             :  */
     456             : TupleDesc
     457      838022 : ExecGetResultType(PlanState *planstate)
     458             : {
     459      838022 :     return planstate->ps_ResultTupleDesc;
     460             : }
     461             : 
     462             : /*
     463             :  * ExecGetResultSlotOps - information about node's type of result slot
     464             :  */
     465             : const TupleTableSlotOps *
     466      374232 : ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
     467             : {
     468      374232 :     if (planstate->resultopsset && planstate->resultops)
     469             :     {
     470      372980 :         if (isfixed)
     471      313460 :             *isfixed = planstate->resultopsfixed;
     472      372980 :         return planstate->resultops;
     473             :     }
     474             : 
     475        1252 :     if (isfixed)
     476             :     {
     477         744 :         if (planstate->resultopsset)
     478         744 :             *isfixed = planstate->resultopsfixed;
     479           0 :         else if (planstate->ps_ResultTupleSlot)
     480           0 :             *isfixed = TTS_FIXED(planstate->ps_ResultTupleSlot);
     481             :         else
     482           0 :             *isfixed = false;
     483             :     }
     484             : 
     485        1252 :     if (!planstate->ps_ResultTupleSlot)
     486        1252 :         return &TTSOpsVirtual;
     487             : 
     488           0 :     return planstate->ps_ResultTupleSlot->tts_ops;
     489             : }
     490             : 
     491             : 
     492             : /* ----------------
     493             :  *      ExecAssignProjectionInfo
     494             :  *
     495             :  * forms the projection information from the node's targetlist
     496             :  *
     497             :  * Notes for inputDesc are same as for ExecBuildProjectionInfo: supply it
     498             :  * for a relation-scan node, can pass NULL for upper-level nodes
     499             :  * ----------------
     500             :  */
     501             : void
     502      374570 : ExecAssignProjectionInfo(PlanState *planstate,
     503             :                          TupleDesc inputDesc)
     504             : {
     505      374540 :     planstate->ps_ProjInfo =
     506      374570 :         ExecBuildProjectionInfo(planstate->plan->targetlist,
     507             :                                 planstate->ps_ExprContext,
     508             :                                 planstate->ps_ResultTupleSlot,
     509             :                                 planstate,
     510             :                                 inputDesc);
     511      374540 : }
     512             : 
     513             : 
     514             : /* ----------------
     515             :  *      ExecConditionalAssignProjectionInfo
     516             :  *
     517             :  * as ExecAssignProjectionInfo, but store NULL rather than building projection
     518             :  * info if no projection is required
     519             :  * ----------------
     520             :  */
     521             : void
     522      273030 : ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
     523             :                                     Index varno)
     524             : {
     525      273030 :     if (tlist_matches_tupdesc(planstate,
     526      273030 :                               planstate->plan->targetlist,
     527             :                               varno,
     528             :                               inputDesc))
     529             :     {
     530      119494 :         planstate->ps_ProjInfo = NULL;
     531      119494 :         planstate->resultopsset = planstate->scanopsset;
     532      119494 :         planstate->resultopsfixed = planstate->scanopsfixed;
     533      119494 :         planstate->resultops = planstate->scanops;
     534             :     }
     535             :     else
     536             :     {
     537      153536 :         if (!planstate->ps_ResultTupleSlot)
     538             :         {
     539      153536 :             ExecInitResultSlot(planstate, &TTSOpsVirtual);
     540      153536 :             planstate->resultops = &TTSOpsVirtual;
     541      153536 :             planstate->resultopsfixed = true;
     542      153536 :             planstate->resultopsset = true;
     543             :         }
     544      153536 :         ExecAssignProjectionInfo(planstate, inputDesc);
     545             :     }
     546      273030 : }
     547             : 
     548             : static bool
     549      273030 : tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
     550             : {
     551      273030 :     int         numattrs = tupdesc->natts;
     552             :     int         attrno;
     553      273030 :     ListCell   *tlist_item = list_head(tlist);
     554             : 
     555             :     /* Check the tlist attributes */
     556     1724046 :     for (attrno = 1; attrno <= numattrs; attrno++)
     557             :     {
     558     1598248 :         Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
     559             :         Var        *var;
     560             : 
     561     1598248 :         if (tlist_item == NULL)
     562       24706 :             return false;       /* tlist too short */
     563     1573542 :         var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
     564     1573542 :         if (!var || !IsA(var, Var))
     565       49980 :             return false;       /* tlist item not a Var */
     566             :         /* if these Asserts fail, planner messed up */
     567             :         Assert(var->varno == varno);
     568             :         Assert(var->varlevelsup == 0);
     569     1523562 :         if (var->varattno != attrno)
     570       72346 :             return false;       /* out of order */
     571     1451216 :         if (att_tup->attisdropped)
     572           0 :             return false;       /* table contains dropped columns */
     573     1451216 :         if (att_tup->atthasmissing)
     574         196 :             return false;       /* table contains cols with missing values */
     575             : 
     576             :         /*
     577             :          * Note: usually the Var's type should match the tupdesc exactly, but
     578             :          * in situations involving unions of columns that have different
     579             :          * typmods, the Var may have come from above the union and hence have
     580             :          * typmod -1.  This is a legitimate situation since the Var still
     581             :          * describes the column, just not as exactly as the tupdesc does. We
     582             :          * could change the planner to prevent it, but it'd then insert
     583             :          * projection steps just to convert from specific typmod to typmod -1,
     584             :          * which is pretty silly.
     585             :          */
     586     2902036 :         if (var->vartype != att_tup->atttypid ||
     587     1451020 :             (var->vartypmod != att_tup->atttypmod &&
     588           4 :              var->vartypmod != -1))
     589           4 :             return false;       /* type mismatch */
     590             : 
     591     1451016 :         tlist_item = lnext(tlist_item);
     592             :     }
     593             : 
     594      125798 :     if (tlist_item)
     595        6304 :         return false;           /* tlist too long */
     596             : 
     597      119494 :     return true;
     598             : }
     599             : 
     600             : /* ----------------
     601             :  *      ExecFreeExprContext
     602             :  *
     603             :  * A plan node's ExprContext should be freed explicitly during executor
     604             :  * shutdown because there may be shutdown callbacks to call.  (Other resources
     605             :  * made by the above routines, such as projection info, don't need to be freed
     606             :  * explicitly because they're just memory in the per-query memory context.)
     607             :  *
     608             :  * However ... there is no particular need to do it during ExecEndNode,
     609             :  * because FreeExecutorState will free any remaining ExprContexts within
     610             :  * the EState.  Letting FreeExecutorState do it allows the ExprContexts to
     611             :  * be freed in reverse order of creation, rather than order of creation as
     612             :  * will happen if we delete them here, which saves O(N^2) work in the list
     613             :  * cleanup inside FreeExprContext.
     614             :  * ----------------
     615             :  */
     616             : void
     617      507290 : ExecFreeExprContext(PlanState *planstate)
     618             : {
     619             :     /*
     620             :      * Per above discussion, don't actually delete the ExprContext. We do
     621             :      * unlink it from the plan node, though.
     622             :      */
     623      507290 :     planstate->ps_ExprContext = NULL;
     624      507290 : }
     625             : 
     626             : 
     627             : /* ----------------------------------------------------------------
     628             :  *                Scan node support
     629             :  * ----------------------------------------------------------------
     630             :  */
     631             : 
     632             : /* ----------------
     633             :  *      ExecAssignScanType
     634             :  * ----------------
     635             :  */
     636             : void
     637         318 : ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
     638             : {
     639         318 :     TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
     640             : 
     641         318 :     ExecSetSlotDescriptor(slot, tupDesc);
     642         318 : }
     643             : 
     644             : /* ----------------
     645             :  *      ExecCreateScanSlotFromOuterPlan
     646             :  * ----------------
     647             :  */
     648             : void
     649       64058 : ExecCreateScanSlotFromOuterPlan(EState *estate,
     650             :                                 ScanState *scanstate,
     651             :                                 const TupleTableSlotOps *tts_ops)
     652             : {
     653             :     PlanState  *outerPlan;
     654             :     TupleDesc   tupDesc;
     655             : 
     656       64058 :     outerPlan = outerPlanState(scanstate);
     657       64058 :     tupDesc = ExecGetResultType(outerPlan);
     658             : 
     659       64058 :     ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops);
     660       64058 : }
     661             : 
     662             : /* ----------------------------------------------------------------
     663             :  *      ExecRelationIsTargetRelation
     664             :  *
     665             :  *      Detect whether a relation (identified by rangetable index)
     666             :  *      is one of the target relations of the query.
     667             :  *
     668             :  * Note: This is currently no longer used in core.  We keep it around
     669             :  * because FDWs may wish to use it to determine if their foreign table
     670             :  * is a target relation.
     671             :  * ----------------------------------------------------------------
     672             :  */
     673             : bool
     674           0 : ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
     675             : {
     676             :     ResultRelInfo *resultRelInfos;
     677             :     int         i;
     678             : 
     679           0 :     resultRelInfos = estate->es_result_relations;
     680           0 :     for (i = 0; i < estate->es_num_result_relations; i++)
     681             :     {
     682           0 :         if (resultRelInfos[i].ri_RangeTableIndex == scanrelid)
     683           0 :             return true;
     684             :     }
     685           0 :     return false;
     686             : }
     687             : 
     688             : /* ----------------------------------------------------------------
     689             :  *      ExecOpenScanRelation
     690             :  *
     691             :  *      Open the heap relation to be scanned by a base-level scan plan node.
     692             :  *      This should be called during the node's ExecInit routine.
     693             :  * ----------------------------------------------------------------
     694             :  */
     695             : Relation
     696      232276 : ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
     697             : {
     698             :     Relation    rel;
     699             : 
     700             :     /* Open the relation. */
     701      232276 :     rel = ExecGetRangeTableRelation(estate, scanrelid);
     702             : 
     703             :     /*
     704             :      * Complain if we're attempting a scan of an unscannable relation, except
     705             :      * when the query won't actually be run.  This is a slightly klugy place
     706             :      * to do this, perhaps, but there is no better place.
     707             :      */
     708      450978 :     if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 &&
     709      218702 :         !RelationIsScannable(rel))
     710           8 :         ereport(ERROR,
     711             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     712             :                  errmsg("materialized view \"%s\" has not been populated",
     713             :                         RelationGetRelationName(rel)),
     714             :                  errhint("Use the REFRESH MATERIALIZED VIEW command.")));
     715             : 
     716      232268 :     return rel;
     717             : }
     718             : 
     719             : /*
     720             :  * ExecInitRangeTable
     721             :  *      Set up executor's range-table-related data
     722             :  *
     723             :  * We build an array from the range table list to allow faster lookup by RTI.
     724             :  * (The es_range_table field is now somewhat redundant, but we keep it to
     725             :  * avoid breaking external code unnecessarily.)
     726             :  * This is also a convenient place to set up the parallel es_relations array.
     727             :  */
     728             : void
     729      273886 : ExecInitRangeTable(EState *estate, List *rangeTable)
     730             : {
     731             :     Index       rti;
     732             :     ListCell   *lc;
     733             : 
     734             :     /* Remember the range table List as-is */
     735      273886 :     estate->es_range_table = rangeTable;
     736             : 
     737             :     /* Set up the equivalent array representation */
     738      273886 :     estate->es_range_table_size = list_length(rangeTable);
     739      273886 :     estate->es_range_table_array = (RangeTblEntry **)
     740      273886 :         palloc(estate->es_range_table_size * sizeof(RangeTblEntry *));
     741      273886 :     rti = 0;
     742      887724 :     foreach(lc, rangeTable)
     743             :     {
     744      613838 :         estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, lc);
     745             :     }
     746             : 
     747             :     /*
     748             :      * Allocate an array to store an open Relation corresponding to each
     749             :      * rangetable entry, and initialize entries to NULL.  Relations are opened
     750             :      * and stored here as needed.
     751             :      */
     752      273886 :     estate->es_relations = (Relation *)
     753      273886 :         palloc0(estate->es_range_table_size * sizeof(Relation));
     754             : 
     755             :     /*
     756             :      * es_rowmarks is also parallel to the es_range_table_array, but it's
     757             :      * allocated only if needed.
     758             :      */
     759      273886 :     estate->es_rowmarks = NULL;
     760      273886 : }
     761             : 
     762             : /*
     763             :  * ExecGetRangeTableRelation
     764             :  *      Open the Relation for a range table entry, if not already done
     765             :  *
     766             :  * The Relations will be closed again in ExecEndPlan().
     767             :  */
     768             : Relation
     769      319128 : ExecGetRangeTableRelation(EState *estate, Index rti)
     770             : {
     771             :     Relation    rel;
     772             : 
     773             :     Assert(rti > 0 && rti <= estate->es_range_table_size);
     774             : 
     775      319128 :     rel = estate->es_relations[rti - 1];
     776      319128 :     if (rel == NULL)
     777             :     {
     778             :         /* First time through, so open the relation */
     779      294298 :         RangeTblEntry *rte = exec_rt_fetch(rti, estate);
     780             : 
     781             :         Assert(rte->rtekind == RTE_RELATION);
     782             : 
     783      294298 :         if (!IsParallelWorker())
     784             :         {
     785             :             /*
     786             :              * In a normal query, we should already have the appropriate lock,
     787             :              * but verify that through an Assert.  Since there's already an
     788             :              * Assert inside table_open that insists on holding some lock, it
     789             :              * seems sufficient to check this only when rellockmode is higher
     790             :              * than the minimum.
     791             :              */
     792      290848 :             rel = table_open(rte->relid, NoLock);
     793             :             Assert(rte->rellockmode == AccessShareLock ||
     794             :                    CheckRelationLockedByMe(rel, rte->rellockmode, false));
     795             :         }
     796             :         else
     797             :         {
     798             :             /*
     799             :              * If we are a parallel worker, we need to obtain our own local
     800             :              * lock on the relation.  This ensures sane behavior in case the
     801             :              * parent process exits before we do.
     802             :              */
     803        3450 :             rel = table_open(rte->relid, rte->rellockmode);
     804             :         }
     805             : 
     806      294298 :         estate->es_relations[rti - 1] = rel;
     807             :     }
     808             : 
     809      319128 :     return rel;
     810             : }
     811             : 
     812             : /*
     813             :  * UpdateChangedParamSet
     814             :  *      Add changed parameters to a plan node's chgParam set
     815             :  */
     816             : void
     817     3990868 : UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
     818             : {
     819             :     Bitmapset  *parmset;
     820             : 
     821             :     /*
     822             :      * The plan node only depends on params listed in its allParam set. Don't
     823             :      * include anything else into its chgParam set.
     824             :      */
     825     3990868 :     parmset = bms_intersect(node->plan->allParam, newchg);
     826             : 
     827             :     /*
     828             :      * Keep node->chgParam == NULL if there's not actually any members; this
     829             :      * allows the simplest possible tests in executor node files.
     830             :      */
     831     3990868 :     if (!bms_is_empty(parmset))
     832     3914074 :         node->chgParam = bms_join(node->chgParam, parmset);
     833             :     else
     834       76794 :         bms_free(parmset);
     835     3990868 : }
     836             : 
     837             : /*
     838             :  * executor_errposition
     839             :  *      Report an execution-time cursor position, if possible.
     840             :  *
     841             :  * This is expected to be used within an ereport() call.  The return value
     842             :  * is a dummy (always 0, in fact).
     843             :  *
     844             :  * The locations stored in parsetrees are byte offsets into the source string.
     845             :  * We have to convert them to 1-based character indexes for reporting to
     846             :  * clients.  (We do things this way to avoid unnecessary overhead in the
     847             :  * normal non-error case: computing character indexes would be much more
     848             :  * expensive than storing token offsets.)
     849             :  */
     850             : int
     851           0 : executor_errposition(EState *estate, int location)
     852             : {
     853             :     int         pos;
     854             : 
     855             :     /* No-op if location was not provided */
     856           0 :     if (location < 0)
     857           0 :         return 0;
     858             :     /* Can't do anything if source text is not available */
     859           0 :     if (estate == NULL || estate->es_sourceText == NULL)
     860           0 :         return 0;
     861             :     /* Convert offset to character number */
     862           0 :     pos = pg_mbstrlen_with_len(estate->es_sourceText, location) + 1;
     863             :     /* And pass it to the ereport mechanism */
     864           0 :     return errposition(pos);
     865             : }
     866             : 
     867             : /*
     868             :  * Register a shutdown callback in an ExprContext.
     869             :  *
     870             :  * Shutdown callbacks will be called (in reverse order of registration)
     871             :  * when the ExprContext is deleted or rescanned.  This provides a hook
     872             :  * for functions called in the context to do any cleanup needed --- it's
     873             :  * particularly useful for functions returning sets.  Note that the
     874             :  * callback will *not* be called in the event that execution is aborted
     875             :  * by an error.
     876             :  */
     877             : void
     878     1495010 : RegisterExprContextCallback(ExprContext *econtext,
     879             :                             ExprContextCallbackFunction function,
     880             :                             Datum arg)
     881             : {
     882             :     ExprContext_CB *ecxt_callback;
     883             : 
     884             :     /* Save the info in appropriate memory context */
     885     1495010 :     ecxt_callback = (ExprContext_CB *)
     886     1495010 :         MemoryContextAlloc(econtext->ecxt_per_query_memory,
     887             :                            sizeof(ExprContext_CB));
     888             : 
     889     1495010 :     ecxt_callback->function = function;
     890     1495010 :     ecxt_callback->arg = arg;
     891             : 
     892             :     /* link to front of list for appropriate execution order */
     893     1495010 :     ecxt_callback->next = econtext->ecxt_callbacks;
     894     1495010 :     econtext->ecxt_callbacks = ecxt_callback;
     895     1495010 : }
     896             : 
     897             : /*
     898             :  * Deregister a shutdown callback in an ExprContext.
     899             :  *
     900             :  * Any list entries matching the function and arg will be removed.
     901             :  * This can be used if it's no longer necessary to call the callback.
     902             :  */
     903             : void
     904     1449496 : UnregisterExprContextCallback(ExprContext *econtext,
     905             :                               ExprContextCallbackFunction function,
     906             :                               Datum arg)
     907             : {
     908             :     ExprContext_CB **prev_callback;
     909             :     ExprContext_CB *ecxt_callback;
     910             : 
     911     1449496 :     prev_callback = &econtext->ecxt_callbacks;
     912             : 
     913     4414826 :     while ((ecxt_callback = *prev_callback) != NULL)
     914             :     {
     915     1515834 :         if (ecxt_callback->function == function && ecxt_callback->arg == arg)
     916             :         {
     917     1449496 :             *prev_callback = ecxt_callback->next;
     918     1449496 :             pfree(ecxt_callback);
     919             :         }
     920             :         else
     921       66338 :             prev_callback = &ecxt_callback->next;
     922             :     }
     923     1449496 : }
     924             : 
     925             : /*
     926             :  * Call all the shutdown callbacks registered in an ExprContext.
     927             :  *
     928             :  * The callback list is emptied (important in case this is only a rescan
     929             :  * reset, and not deletion of the ExprContext).
     930             :  *
     931             :  * If isCommit is false, just clean the callback list but don't call 'em.
     932             :  * (See comment for FreeExprContext.)
     933             :  */
     934             : static void
     935    10214636 : ShutdownExprContext(ExprContext *econtext, bool isCommit)
     936             : {
     937             :     ExprContext_CB *ecxt_callback;
     938             :     MemoryContext oldcontext;
     939             : 
     940             :     /* Fast path in normal case where there's nothing to do. */
     941    10214636 :     if (econtext->ecxt_callbacks == NULL)
     942    10170758 :         return;
     943             : 
     944             :     /*
     945             :      * Call the callbacks in econtext's per-tuple context.  This ensures that
     946             :      * any memory they might leak will get cleaned up.
     947             :      */
     948       43878 :     oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
     949             : 
     950             :     /*
     951             :      * Call each callback function in reverse registration order.
     952             :      */
     953      132762 :     while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
     954             :     {
     955       45006 :         econtext->ecxt_callbacks = ecxt_callback->next;
     956       45006 :         if (isCommit)
     957       45006 :             ecxt_callback->function(ecxt_callback->arg);
     958       45006 :         pfree(ecxt_callback);
     959             :     }
     960             : 
     961       43878 :     MemoryContextSwitchTo(oldcontext);
     962             : }
     963             : 
     964             : /*
     965             :  *      GetAttributeByName
     966             :  *      GetAttributeByNum
     967             :  *
     968             :  *      These functions return the value of the requested attribute
     969             :  *      out of the given tuple Datum.
     970             :  *      C functions which take a tuple as an argument are expected
     971             :  *      to use these.  Ex: overpaid(EMP) might call GetAttributeByNum().
     972             :  *      Note: these are actually rather slow because they do a typcache
     973             :  *      lookup on each call.
     974             :  */
     975             : Datum
     976          24 : GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull)
     977             : {
     978             :     AttrNumber  attrno;
     979             :     Datum       result;
     980             :     Oid         tupType;
     981             :     int32       tupTypmod;
     982             :     TupleDesc   tupDesc;
     983             :     HeapTupleData tmptup;
     984             :     int         i;
     985             : 
     986          24 :     if (attname == NULL)
     987           0 :         elog(ERROR, "invalid attribute name");
     988             : 
     989          24 :     if (isNull == NULL)
     990           0 :         elog(ERROR, "a NULL isNull pointer was passed");
     991             : 
     992          24 :     if (tuple == NULL)
     993             :     {
     994             :         /* Kinda bogus but compatible with old behavior... */
     995           0 :         *isNull = true;
     996           0 :         return (Datum) 0;
     997             :     }
     998             : 
     999          24 :     tupType = HeapTupleHeaderGetTypeId(tuple);
    1000          24 :     tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    1001          24 :     tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    1002             : 
    1003          24 :     attrno = InvalidAttrNumber;
    1004          96 :     for (i = 0; i < tupDesc->natts; i++)
    1005             :     {
    1006          96 :         Form_pg_attribute att = TupleDescAttr(tupDesc, i);
    1007             : 
    1008          96 :         if (namestrcmp(&(att->attname), attname) == 0)
    1009             :         {
    1010          24 :             attrno = att->attnum;
    1011          24 :             break;
    1012             :         }
    1013             :     }
    1014             : 
    1015          24 :     if (attrno == InvalidAttrNumber)
    1016           0 :         elog(ERROR, "attribute \"%s\" does not exist", attname);
    1017             : 
    1018             :     /*
    1019             :      * heap_getattr needs a HeapTuple not a bare HeapTupleHeader.  We set all
    1020             :      * the fields in the struct just in case user tries to inspect system
    1021             :      * columns.
    1022             :      */
    1023          24 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    1024          24 :     ItemPointerSetInvalid(&(tmptup.t_self));
    1025          24 :     tmptup.t_tableOid = InvalidOid;
    1026          24 :     tmptup.t_data = tuple;
    1027             : 
    1028          24 :     result = heap_getattr(&tmptup,
    1029             :                           attrno,
    1030             :                           tupDesc,
    1031             :                           isNull);
    1032             : 
    1033          24 :     ReleaseTupleDesc(tupDesc);
    1034             : 
    1035          24 :     return result;
    1036             : }
    1037             : 
    1038             : Datum
    1039           0 : GetAttributeByNum(HeapTupleHeader tuple,
    1040             :                   AttrNumber attrno,
    1041             :                   bool *isNull)
    1042             : {
    1043             :     Datum       result;
    1044             :     Oid         tupType;
    1045             :     int32       tupTypmod;
    1046             :     TupleDesc   tupDesc;
    1047             :     HeapTupleData tmptup;
    1048             : 
    1049           0 :     if (!AttributeNumberIsValid(attrno))
    1050           0 :         elog(ERROR, "invalid attribute number %d", attrno);
    1051             : 
    1052           0 :     if (isNull == NULL)
    1053           0 :         elog(ERROR, "a NULL isNull pointer was passed");
    1054             : 
    1055           0 :     if (tuple == NULL)
    1056             :     {
    1057             :         /* Kinda bogus but compatible with old behavior... */
    1058           0 :         *isNull = true;
    1059           0 :         return (Datum) 0;
    1060             :     }
    1061             : 
    1062           0 :     tupType = HeapTupleHeaderGetTypeId(tuple);
    1063           0 :     tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    1064           0 :     tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    1065             : 
    1066             :     /*
    1067             :      * heap_getattr needs a HeapTuple not a bare HeapTupleHeader.  We set all
    1068             :      * the fields in the struct just in case user tries to inspect system
    1069             :      * columns.
    1070             :      */
    1071           0 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    1072           0 :     ItemPointerSetInvalid(&(tmptup.t_self));
    1073           0 :     tmptup.t_tableOid = InvalidOid;
    1074           0 :     tmptup.t_data = tuple;
    1075             : 
    1076           0 :     result = heap_getattr(&tmptup,
    1077             :                           attrno,
    1078             :                           tupDesc,
    1079             :                           isNull);
    1080             : 
    1081           0 :     ReleaseTupleDesc(tupDesc);
    1082             : 
    1083           0 :     return result;
    1084             : }
    1085             : 
    1086             : /*
    1087             :  * Number of items in a tlist (including any resjunk items!)
    1088             :  */
    1089             : int
    1090      675564 : ExecTargetListLength(List *targetlist)
    1091             : {
    1092             :     /* This used to be more complex, but fjoins are dead */
    1093      675564 :     return list_length(targetlist);
    1094             : }
    1095             : 
    1096             : /*
    1097             :  * Number of items in a tlist, not including any resjunk items
    1098             :  */
    1099             : int
    1100       84444 : ExecCleanTargetListLength(List *targetlist)
    1101             : {
    1102       84444 :     int         len = 0;
    1103             :     ListCell   *tl;
    1104             : 
    1105      326646 :     foreach(tl, targetlist)
    1106             :     {
    1107      242202 :         TargetEntry *curTle = lfirst_node(TargetEntry, tl);
    1108             : 
    1109      242202 :         if (!curTle->resjunk)
    1110      213484 :             len++;
    1111             :     }
    1112       84444 :     return len;
    1113             : }
    1114             : 
    1115             : /*
    1116             :  * Return a relInfo's tuple slot for a trigger's OLD tuples.
    1117             :  */
    1118             : TupleTableSlot *
    1119      956164 : ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
    1120             : {
    1121      956164 :     if (relInfo->ri_TrigOldSlot == NULL)
    1122             :     {
    1123       14562 :         Relation    rel = relInfo->ri_RelationDesc;
    1124       14562 :         MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
    1125             : 
    1126       14562 :         relInfo->ri_TrigOldSlot =
    1127       14562 :             ExecInitExtraTupleSlot(estate,
    1128             :                                    RelationGetDescr(rel),
    1129             :                                    table_slot_callbacks(rel));
    1130             : 
    1131       14562 :         MemoryContextSwitchTo(oldcontext);
    1132             :     }
    1133             : 
    1134      956164 :     return relInfo->ri_TrigOldSlot;
    1135             : }
    1136             : 
    1137             : /*
    1138             :  * Return a relInfo's tuple slot for a trigger's NEW tuples.
    1139             :  */
    1140             : TupleTableSlot *
    1141        1566 : ExecGetTriggerNewSlot(EState *estate, ResultRelInfo *relInfo)
    1142             : {
    1143        1566 :     if (relInfo->ri_TrigNewSlot == NULL)
    1144             :     {
    1145         902 :         Relation    rel = relInfo->ri_RelationDesc;
    1146         902 :         MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
    1147             : 
    1148         902 :         relInfo->ri_TrigNewSlot =
    1149         902 :             ExecInitExtraTupleSlot(estate,
    1150             :                                    RelationGetDescr(rel),
    1151             :                                    table_slot_callbacks(rel));
    1152             : 
    1153         902 :         MemoryContextSwitchTo(oldcontext);
    1154             :     }
    1155             : 
    1156        1566 :     return relInfo->ri_TrigNewSlot;
    1157             : }
    1158             : 
    1159             : /*
    1160             :  * Return a relInfo's tuple slot for processing returning tuples.
    1161             :  */
    1162             : TupleTableSlot *
    1163         770 : ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
    1164             : {
    1165         770 :     if (relInfo->ri_ReturningSlot == NULL)
    1166             :     {
    1167         288 :         Relation    rel = relInfo->ri_RelationDesc;
    1168         288 :         MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
    1169             : 
    1170         288 :         relInfo->ri_ReturningSlot =
    1171         288 :             ExecInitExtraTupleSlot(estate,
    1172             :                                    RelationGetDescr(rel),
    1173             :                                    table_slot_callbacks(rel));
    1174             : 
    1175         288 :         MemoryContextSwitchTo(oldcontext);
    1176             :     }
    1177             : 
    1178         770 :     return relInfo->ri_ReturningSlot;
    1179             : }

Generated by: LCOV version 1.13