LCOV - code coverage report
Current view: top level - src/backend/executor - execExprInterp.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 1371 1466 93.5 %
Date: 2020-06-05 19:06:29 Functions: 64 66 97.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * execExprInterp.c
       4             :  *    Interpreted evaluation of an expression step list.
       5             :  *
       6             :  * This file provides either a "direct threaded" (for gcc, clang and
       7             :  * compatible) or a "switch threaded" (for all compilers) implementation of
       8             :  * expression evaluation.  The former is amongst the fastest known methods
       9             :  * of interpreting programs without resorting to assembly level work, or
      10             :  * just-in-time compilation, but it requires support for computed gotos.
      11             :  * The latter is amongst the fastest approaches doable in standard C.
      12             :  *
      13             :  * In either case we use ExprEvalStep->opcode to dispatch to the code block
      14             :  * within ExecInterpExpr() that implements the specific opcode type.
      15             :  *
      16             :  * Switch-threading uses a plain switch() statement to perform the
      17             :  * dispatch.  This has the advantages of being plain C and allowing the
      18             :  * compiler to warn if implementation of a specific opcode has been forgotten.
      19             :  * The disadvantage is that dispatches will, as commonly implemented by
      20             :  * compilers, happen from a single location, requiring more jumps and causing
      21             :  * bad branch prediction.
      22             :  *
      23             :  * In direct threading, we use gcc's label-as-values extension - also adopted
      24             :  * by some other compilers - to replace ExprEvalStep->opcode with the address
      25             :  * of the block implementing the instruction. Dispatch to the next instruction
      26             :  * is done by a "computed goto".  This allows for better branch prediction
      27             :  * (as the jumps are happening from different locations) and fewer jumps
      28             :  * (as no preparatory jump to a common dispatch location is needed).
      29             :  *
      30             :  * When using direct threading, ExecReadyInterpretedExpr will replace
      31             :  * each step's opcode field with the address of the relevant code block and
      32             :  * ExprState->flags will contain EEO_FLAG_DIRECT_THREADED to remember that
      33             :  * that's been done.
      34             :  *
      35             :  * For very simple instructions the overhead of the full interpreter
      36             :  * "startup", as minimal as it is, is noticeable.  Therefore
      37             :  * ExecReadyInterpretedExpr will choose to implement certain simple
      38             :  * opcode patterns using special fast-path routines (ExecJust*).
      39             :  *
      40             :  * Complex or uncommon instructions are not implemented in-line in
      41             :  * ExecInterpExpr(), rather we call out to a helper function appearing later
      42             :  * in this file.  For one reason, there'd not be a noticeable performance
      43             :  * benefit, but more importantly those complex routines are intended to be
      44             :  * shared between different expression evaluation approaches.  For instance
      45             :  * a JIT compiler would generate calls to them.  (This is why they are
      46             :  * exported rather than being "static" in this file.)
      47             :  *
      48             :  *
      49             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
      50             :  * Portions Copyright (c) 1994, Regents of the University of California
      51             :  *
      52             :  * IDENTIFICATION
      53             :  *    src/backend/executor/execExprInterp.c
      54             :  *
      55             :  *-------------------------------------------------------------------------
      56             :  */
      57             : #include "postgres.h"
      58             : 
      59             : #include "access/heaptoast.h"
      60             : #include "catalog/pg_type.h"
      61             : #include "commands/sequence.h"
      62             : #include "executor/execExpr.h"
      63             : #include "executor/nodeSubplan.h"
      64             : #include "funcapi.h"
      65             : #include "miscadmin.h"
      66             : #include "nodes/nodeFuncs.h"
      67             : #include "parser/parsetree.h"
      68             : #include "pgstat.h"
      69             : #include "utils/array.h"
      70             : #include "utils/builtins.h"
      71             : #include "utils/date.h"
      72             : #include "utils/datum.h"
      73             : #include "utils/expandedrecord.h"
      74             : #include "utils/lsyscache.h"
      75             : #include "utils/memutils.h"
      76             : #include "utils/timestamp.h"
      77             : #include "utils/typcache.h"
      78             : #include "utils/xml.h"
      79             : 
      80             : /*
      81             :  * Use computed-goto-based opcode dispatch when computed gotos are available.
      82             :  * But use a separate symbol so that it's easy to adjust locally in this file
      83             :  * for development and testing.
      84             :  */
      85             : #ifdef HAVE_COMPUTED_GOTO
      86             : #define EEO_USE_COMPUTED_GOTO
      87             : #endif                          /* HAVE_COMPUTED_GOTO */
      88             : 
      89             : /*
      90             :  * Macros for opcode dispatch.
      91             :  *
      92             :  * EEO_SWITCH - just hides the switch if not in use.
      93             :  * EEO_CASE - labels the implementation of named expression step type.
      94             :  * EEO_DISPATCH - jump to the implementation of the step type for 'op'.
      95             :  * EEO_OPCODE - compute opcode required by used expression evaluation method.
      96             :  * EEO_NEXT - increment 'op' and jump to correct next step type.
      97             :  * EEO_JUMP - jump to the specified step number within the current expression.
      98             :  */
      99             : #if defined(EEO_USE_COMPUTED_GOTO)
     100             : 
     101             : /* struct for jump target -> opcode lookup table */
     102             : typedef struct ExprEvalOpLookup
     103             : {
     104             :     const void *opcode;
     105             :     ExprEvalOp  op;
     106             : } ExprEvalOpLookup;
     107             : 
     108             : /* to make dispatch_table accessible outside ExecInterpExpr() */
     109             : static const void **dispatch_table = NULL;
     110             : 
     111             : /* jump target -> opcode lookup table */
     112             : static ExprEvalOpLookup reverse_dispatch_table[EEOP_LAST];
     113             : 
     114             : #define EEO_SWITCH()
     115             : #define EEO_CASE(name)      CASE_##name:
     116             : #define EEO_DISPATCH()      goto *((void *) op->opcode)
     117             : #define EEO_OPCODE(opcode)  ((intptr_t) dispatch_table[opcode])
     118             : 
     119             : #else                           /* !EEO_USE_COMPUTED_GOTO */
     120             : 
     121             : #define EEO_SWITCH()        starteval: switch ((ExprEvalOp) op->opcode)
     122             : #define EEO_CASE(name)      case name:
     123             : #define EEO_DISPATCH()      goto starteval
     124             : #define EEO_OPCODE(opcode)  (opcode)
     125             : 
     126             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     127             : 
     128             : #define EEO_NEXT() \
     129             :     do { \
     130             :         op++; \
     131             :         EEO_DISPATCH(); \
     132             :     } while (0)
     133             : 
     134             : #define EEO_JUMP(stepno) \
     135             :     do { \
     136             :         op = &state->steps[stepno]; \
     137             :         EEO_DISPATCH(); \
     138             :     } while (0)
     139             : 
     140             : 
     141             : static Datum ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull);
     142             : static void ExecInitInterpreter(void);
     143             : 
     144             : /* support functions */
     145             : static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype);
     146             : static void CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot);
     147             : static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
     148             :                                     TupleDesc *cache_field, ExprContext *econtext);
     149             : static void ShutdownTupleDescRef(Datum arg);
     150             : static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
     151             :                                ExprContext *econtext, bool checkisnull);
     152             : 
     153             : /* fast-path evaluation functions */
     154             : static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
     155             : static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
     156             : static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
     157             : static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
     158             : static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
     159             : static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
     160             : static Datum ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull);
     161             : static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull);
     162             : static Datum ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     163             : static Datum ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     164             : static Datum ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     165             : static Datum ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     166             : static Datum ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     167             : static Datum ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     168             : 
     169             : /* execution helper functions */
     170             : static pg_attribute_always_inline void ExecAggPlainTransByVal(AggState *aggstate,
     171             :                                                               AggStatePerTrans pertrans,
     172             :                                                               AggStatePerGroup pergroup,
     173             :                                                               ExprContext *aggcontext,
     174             :                                                               int setno);
     175             : static pg_attribute_always_inline void ExecAggPlainTransByRef(AggState *aggstate,
     176             :                                                               AggStatePerTrans pertrans,
     177             :                                                               AggStatePerGroup pergroup,
     178             :                                                               ExprContext *aggcontext,
     179             :                                                               int setno);
     180             : 
     181             : /*
     182             :  * Prepare ExprState for interpreted execution.
     183             :  */
     184             : void
     185     1263548 : ExecReadyInterpretedExpr(ExprState *state)
     186             : {
     187             :     /* Ensure one-time interpreter setup has been done */
     188     1263548 :     ExecInitInterpreter();
     189             : 
     190             :     /* Simple validity checks on expression */
     191             :     Assert(state->steps_len >= 1);
     192             :     Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE);
     193             : 
     194             :     /*
     195             :      * Don't perform redundant initialization. This is unreachable in current
     196             :      * cases, but might be hit if there's additional expression evaluation
     197             :      * methods that rely on interpreted execution to work.
     198             :      */
     199     1263548 :     if (state->flags & EEO_FLAG_INTERPRETER_INITIALIZED)
     200           0 :         return;
     201             : 
     202             :     /*
     203             :      * First time through, check whether attribute matches Var.  Might not be
     204             :      * ok anymore, due to schema changes. We do that by setting up a callback
     205             :      * that does checking on the first call, which then sets the evalfunc
     206             :      * callback to the actual method of execution.
     207             :      */
     208     1263548 :     state->evalfunc = ExecInterpExprStillValid;
     209             : 
     210             :     /* DIRECT_THREADED should not already be set */
     211             :     Assert((state->flags & EEO_FLAG_DIRECT_THREADED) == 0);
     212             : 
     213             :     /*
     214             :      * There shouldn't be any errors before the expression is fully
     215             :      * initialized, and even if so, it'd lead to the expression being
     216             :      * abandoned.  So we can set the flag now and save some code.
     217             :      */
     218     1263548 :     state->flags |= EEO_FLAG_INTERPRETER_INITIALIZED;
     219             : 
     220             :     /*
     221             :      * Select fast-path evalfuncs for very simple expressions.  "Starting up"
     222             :      * the full interpreter is a measurable overhead for these, and these
     223             :      * patterns occur often enough to be worth optimizing.
     224             :      */
     225     1263548 :     if (state->steps_len == 3)
     226             :     {
     227      299302 :         ExprEvalOp  step0 = state->steps[0].opcode;
     228      299302 :         ExprEvalOp  step1 = state->steps[1].opcode;
     229             : 
     230      299302 :         if (step0 == EEOP_INNER_FETCHSOME &&
     231             :             step1 == EEOP_INNER_VAR)
     232             :         {
     233        9798 :             state->evalfunc_private = (void *) ExecJustInnerVar;
     234        9798 :             return;
     235             :         }
     236      289504 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     237             :                  step1 == EEOP_OUTER_VAR)
     238             :         {
     239       44956 :             state->evalfunc_private = (void *) ExecJustOuterVar;
     240       44956 :             return;
     241             :         }
     242      244548 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     243             :                  step1 == EEOP_SCAN_VAR)
     244             :         {
     245       22248 :             state->evalfunc_private = (void *) ExecJustScanVar;
     246       22248 :             return;
     247             :         }
     248      222300 :         else if (step0 == EEOP_INNER_FETCHSOME &&
     249             :                  step1 == EEOP_ASSIGN_INNER_VAR)
     250             :         {
     251         570 :             state->evalfunc_private = (void *) ExecJustAssignInnerVar;
     252         570 :             return;
     253             :         }
     254      221730 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     255             :                  step1 == EEOP_ASSIGN_OUTER_VAR)
     256             :         {
     257        7098 :             state->evalfunc_private = (void *) ExecJustAssignOuterVar;
     258        7098 :             return;
     259             :         }
     260      214632 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     261             :                  step1 == EEOP_ASSIGN_SCAN_VAR)
     262             :         {
     263       35100 :             state->evalfunc_private = (void *) ExecJustAssignScanVar;
     264       35100 :             return;
     265             :         }
     266      179532 :         else if (step0 == EEOP_CASE_TESTVAL &&
     267        1004 :                  step1 == EEOP_FUNCEXPR_STRICT &&
     268        1004 :                  state->steps[0].d.casetest.value)
     269             :         {
     270         218 :             state->evalfunc_private = (void *) ExecJustApplyFuncToCase;
     271         218 :             return;
     272             :         }
     273             :     }
     274      964246 :     else if (state->steps_len == 2)
     275             :     {
     276      357446 :         ExprEvalOp  step0 = state->steps[0].opcode;
     277             : 
     278      357446 :         if (step0 == EEOP_CONST)
     279             :         {
     280      121196 :             state->evalfunc_private = (void *) ExecJustConst;
     281      121196 :             return;
     282             :         }
     283      236250 :         else if (step0 == EEOP_INNER_VAR)
     284             :         {
     285         232 :             state->evalfunc_private = (void *) ExecJustInnerVarVirt;
     286         232 :             return;
     287             :         }
     288      236018 :         else if (step0 == EEOP_OUTER_VAR)
     289             :         {
     290       46728 :             state->evalfunc_private = (void *) ExecJustOuterVarVirt;
     291       46728 :             return;
     292             :         }
     293      189290 :         else if (step0 == EEOP_SCAN_VAR)
     294             :         {
     295          48 :             state->evalfunc_private = (void *) ExecJustScanVarVirt;
     296          48 :             return;
     297             :         }
     298      189242 :         else if (step0 == EEOP_ASSIGN_INNER_VAR)
     299             :         {
     300          52 :             state->evalfunc_private = (void *) ExecJustAssignInnerVarVirt;
     301          52 :             return;
     302             :         }
     303      189190 :         else if (step0 == EEOP_ASSIGN_OUTER_VAR)
     304             :         {
     305         650 :             state->evalfunc_private = (void *) ExecJustAssignOuterVarVirt;
     306         650 :             return;
     307             :         }
     308      188540 :         else if (step0 == EEOP_ASSIGN_SCAN_VAR)
     309             :         {
     310        3352 :             state->evalfunc_private = (void *) ExecJustAssignScanVarVirt;
     311        3352 :             return;
     312             :         }
     313             :     }
     314             : 
     315             : #if defined(EEO_USE_COMPUTED_GOTO)
     316             : 
     317             :     /*
     318             :      * In the direct-threaded implementation, replace each opcode with the
     319             :      * address to jump to.  (Use ExecEvalStepOp() to get back the opcode.)
     320             :      */
     321     6743674 :     for (int off = 0; off < state->steps_len; off++)
     322             :     {
     323     5772372 :         ExprEvalStep *op = &state->steps[off];
     324             : 
     325     5772372 :         op->opcode = EEO_OPCODE(op->opcode);
     326             :     }
     327             : 
     328      971302 :     state->flags |= EEO_FLAG_DIRECT_THREADED;
     329             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     330             : 
     331      971302 :     state->evalfunc_private = (void *) ExecInterpExpr;
     332             : }
     333             : 
     334             : 
     335             : /*
     336             :  * Evaluate expression identified by "state" in the execution context
     337             :  * given by "econtext".  *isnull is set to the is-null flag for the result,
     338             :  * and the Datum value is the function result.
     339             :  *
     340             :  * As a special case, return the dispatch table's address if state is NULL.
     341             :  * This is used by ExecInitInterpreter to set up the dispatch_table global.
     342             :  * (Only applies when EEO_USE_COMPUTED_GOTO is defined.)
     343             :  */
     344             : static Datum
     345   100477006 : ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
     346             : {
     347             :     ExprEvalStep *op;
     348             :     TupleTableSlot *resultslot;
     349             :     TupleTableSlot *innerslot;
     350             :     TupleTableSlot *outerslot;
     351             :     TupleTableSlot *scanslot;
     352             : 
     353             :     /*
     354             :      * This array has to be in the same order as enum ExprEvalOp.
     355             :      */
     356             : #if defined(EEO_USE_COMPUTED_GOTO)
     357             :     static const void *const dispatch_table[] = {
     358             :         &&CASE_EEOP_DONE,
     359             :         &&CASE_EEOP_INNER_FETCHSOME,
     360             :         &&CASE_EEOP_OUTER_FETCHSOME,
     361             :         &&CASE_EEOP_SCAN_FETCHSOME,
     362             :         &&CASE_EEOP_INNER_VAR,
     363             :         &&CASE_EEOP_OUTER_VAR,
     364             :         &&CASE_EEOP_SCAN_VAR,
     365             :         &&CASE_EEOP_INNER_SYSVAR,
     366             :         &&CASE_EEOP_OUTER_SYSVAR,
     367             :         &&CASE_EEOP_SCAN_SYSVAR,
     368             :         &&CASE_EEOP_WHOLEROW,
     369             :         &&CASE_EEOP_ASSIGN_INNER_VAR,
     370             :         &&CASE_EEOP_ASSIGN_OUTER_VAR,
     371             :         &&CASE_EEOP_ASSIGN_SCAN_VAR,
     372             :         &&CASE_EEOP_ASSIGN_TMP,
     373             :         &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
     374             :         &&CASE_EEOP_CONST,
     375             :         &&CASE_EEOP_FUNCEXPR,
     376             :         &&CASE_EEOP_FUNCEXPR_STRICT,
     377             :         &&CASE_EEOP_FUNCEXPR_FUSAGE,
     378             :         &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
     379             :         &&CASE_EEOP_BOOL_AND_STEP_FIRST,
     380             :         &&CASE_EEOP_BOOL_AND_STEP,
     381             :         &&CASE_EEOP_BOOL_AND_STEP_LAST,
     382             :         &&CASE_EEOP_BOOL_OR_STEP_FIRST,
     383             :         &&CASE_EEOP_BOOL_OR_STEP,
     384             :         &&CASE_EEOP_BOOL_OR_STEP_LAST,
     385             :         &&CASE_EEOP_BOOL_NOT_STEP,
     386             :         &&CASE_EEOP_QUAL,
     387             :         &&CASE_EEOP_JUMP,
     388             :         &&CASE_EEOP_JUMP_IF_NULL,
     389             :         &&CASE_EEOP_JUMP_IF_NOT_NULL,
     390             :         &&CASE_EEOP_JUMP_IF_NOT_TRUE,
     391             :         &&CASE_EEOP_NULLTEST_ISNULL,
     392             :         &&CASE_EEOP_NULLTEST_ISNOTNULL,
     393             :         &&CASE_EEOP_NULLTEST_ROWISNULL,
     394             :         &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
     395             :         &&CASE_EEOP_BOOLTEST_IS_TRUE,
     396             :         &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
     397             :         &&CASE_EEOP_BOOLTEST_IS_FALSE,
     398             :         &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
     399             :         &&CASE_EEOP_PARAM_EXEC,
     400             :         &&CASE_EEOP_PARAM_EXTERN,
     401             :         &&CASE_EEOP_PARAM_CALLBACK,
     402             :         &&CASE_EEOP_CASE_TESTVAL,
     403             :         &&CASE_EEOP_MAKE_READONLY,
     404             :         &&CASE_EEOP_IOCOERCE,
     405             :         &&CASE_EEOP_DISTINCT,
     406             :         &&CASE_EEOP_NOT_DISTINCT,
     407             :         &&CASE_EEOP_NULLIF,
     408             :         &&CASE_EEOP_SQLVALUEFUNCTION,
     409             :         &&CASE_EEOP_CURRENTOFEXPR,
     410             :         &&CASE_EEOP_NEXTVALUEEXPR,
     411             :         &&CASE_EEOP_ARRAYEXPR,
     412             :         &&CASE_EEOP_ARRAYCOERCE,
     413             :         &&CASE_EEOP_ROW,
     414             :         &&CASE_EEOP_ROWCOMPARE_STEP,
     415             :         &&CASE_EEOP_ROWCOMPARE_FINAL,
     416             :         &&CASE_EEOP_MINMAX,
     417             :         &&CASE_EEOP_FIELDSELECT,
     418             :         &&CASE_EEOP_FIELDSTORE_DEFORM,
     419             :         &&CASE_EEOP_FIELDSTORE_FORM,
     420             :         &&CASE_EEOP_SBSREF_SUBSCRIPT,
     421             :         &&CASE_EEOP_SBSREF_OLD,
     422             :         &&CASE_EEOP_SBSREF_ASSIGN,
     423             :         &&CASE_EEOP_SBSREF_FETCH,
     424             :         &&CASE_EEOP_DOMAIN_TESTVAL,
     425             :         &&CASE_EEOP_DOMAIN_NOTNULL,
     426             :         &&CASE_EEOP_DOMAIN_CHECK,
     427             :         &&CASE_EEOP_CONVERT_ROWTYPE,
     428             :         &&CASE_EEOP_SCALARARRAYOP,
     429             :         &&CASE_EEOP_XMLEXPR,
     430             :         &&CASE_EEOP_AGGREF,
     431             :         &&CASE_EEOP_GROUPING_FUNC,
     432             :         &&CASE_EEOP_WINDOW_FUNC,
     433             :         &&CASE_EEOP_SUBPLAN,
     434             :         &&CASE_EEOP_ALTERNATIVE_SUBPLAN,
     435             :         &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
     436             :         &&CASE_EEOP_AGG_DESERIALIZE,
     437             :         &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
     438             :         &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
     439             :         &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
     440             :         &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
     441             :         &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
     442             :         &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
     443             :         &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
     444             :         &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
     445             :         &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
     446             :         &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
     447             :         &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
     448             :         &&CASE_EEOP_LAST
     449             :     };
     450             : 
     451             :     StaticAssertStmt(EEOP_LAST + 1 == lengthof(dispatch_table),
     452             :                      "dispatch_table out of whack with ExprEvalOp");
     453             : 
     454   100477006 :     if (unlikely(state == NULL))
     455        6884 :         return PointerGetDatum(dispatch_table);
     456             : #else
     457             :     Assert(state != NULL);
     458             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     459             : 
     460             :     /* setup state */
     461   100470122 :     op = state->steps;
     462   100470122 :     resultslot = state->resultslot;
     463   100470122 :     innerslot = econtext->ecxt_innertuple;
     464   100470122 :     outerslot = econtext->ecxt_outertuple;
     465   100470122 :     scanslot = econtext->ecxt_scantuple;
     466             : 
     467             : #if defined(EEO_USE_COMPUTED_GOTO)
     468   100470122 :     EEO_DISPATCH();
     469             : #endif
     470             : 
     471             :     EEO_SWITCH()
     472             :     {
     473   100459454 :         EEO_CASE(EEOP_DONE)
     474             :         {
     475   100459454 :             goto out;
     476             :         }
     477             : 
     478    22091902 :         EEO_CASE(EEOP_INNER_FETCHSOME)
     479             :         {
     480    22091902 :             CheckOpSlotCompatibility(op, innerslot);
     481             : 
     482    22091902 :             slot_getsomeattrs(innerslot, op->d.fetch.last_var);
     483             : 
     484    22091902 :             EEO_NEXT();
     485             :         }
     486             : 
     487    16172446 :         EEO_CASE(EEOP_OUTER_FETCHSOME)
     488             :         {
     489    16172446 :             CheckOpSlotCompatibility(op, outerslot);
     490             : 
     491    16172446 :             slot_getsomeattrs(outerslot, op->d.fetch.last_var);
     492             : 
     493    16172446 :             EEO_NEXT();
     494             :         }
     495             : 
     496    50223434 :         EEO_CASE(EEOP_SCAN_FETCHSOME)
     497             :         {
     498    50223434 :             CheckOpSlotCompatibility(op, scanslot);
     499             : 
     500    50223434 :             slot_getsomeattrs(scanslot, op->d.fetch.last_var);
     501             : 
     502    50223434 :             EEO_NEXT();
     503             :         }
     504             : 
     505    20869728 :         EEO_CASE(EEOP_INNER_VAR)
     506             :         {
     507    20869728 :             int         attnum = op->d.var.attnum;
     508             : 
     509             :             /*
     510             :              * Since we already extracted all referenced columns from the
     511             :              * tuple with a FETCHSOME step, we can just grab the value
     512             :              * directly out of the slot's decomposed-data arrays.  But let's
     513             :              * have an Assert to check that that did happen.
     514             :              */
     515             :             Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
     516    20869728 :             *op->resvalue = innerslot->tts_values[attnum];
     517    20869728 :             *op->resnull = innerslot->tts_isnull[attnum];
     518             : 
     519    20869728 :             EEO_NEXT();
     520             :         }
     521             : 
     522    30320220 :         EEO_CASE(EEOP_OUTER_VAR)
     523             :         {
     524    30320220 :             int         attnum = op->d.var.attnum;
     525             : 
     526             :             /* See EEOP_INNER_VAR comments */
     527             : 
     528             :             Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
     529    30320220 :             *op->resvalue = outerslot->tts_values[attnum];
     530    30320220 :             *op->resnull = outerslot->tts_isnull[attnum];
     531             : 
     532    30320220 :             EEO_NEXT();
     533             :         }
     534             : 
     535    46684948 :         EEO_CASE(EEOP_SCAN_VAR)
     536             :         {
     537    46684948 :             int         attnum = op->d.var.attnum;
     538             : 
     539             :             /* See EEOP_INNER_VAR comments */
     540             : 
     541             :             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
     542    46684948 :             *op->resvalue = scanslot->tts_values[attnum];
     543    46684948 :             *op->resnull = scanslot->tts_isnull[attnum];
     544             : 
     545    46684948 :             EEO_NEXT();
     546             :         }
     547             : 
     548           4 :         EEO_CASE(EEOP_INNER_SYSVAR)
     549             :         {
     550           4 :             ExecEvalSysVar(state, op, econtext, innerslot);
     551           4 :             EEO_NEXT();
     552             :         }
     553             : 
     554           8 :         EEO_CASE(EEOP_OUTER_SYSVAR)
     555             :         {
     556           8 :             ExecEvalSysVar(state, op, econtext, outerslot);
     557           8 :             EEO_NEXT();
     558             :         }
     559             : 
     560     5373328 :         EEO_CASE(EEOP_SCAN_SYSVAR)
     561             :         {
     562     5373328 :             ExecEvalSysVar(state, op, econtext, scanslot);
     563     5373328 :             EEO_NEXT();
     564             :         }
     565             : 
     566       31160 :         EEO_CASE(EEOP_WHOLEROW)
     567             :         {
     568             :             /* too complex for an inline implementation */
     569       31160 :             ExecEvalWholeRowVar(state, op, econtext);
     570             : 
     571       31160 :             EEO_NEXT();
     572             :         }
     573             : 
     574     4473536 :         EEO_CASE(EEOP_ASSIGN_INNER_VAR)
     575             :         {
     576     4473536 :             int         resultnum = op->d.assign_var.resultnum;
     577     4473536 :             int         attnum = op->d.assign_var.attnum;
     578             : 
     579             :             /*
     580             :              * We do not need CheckVarSlotCompatibility here; that was taken
     581             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     582             :              */
     583             :             Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
     584     4473536 :             resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
     585     4473536 :             resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
     586             : 
     587     4473536 :             EEO_NEXT();
     588             :         }
     589             : 
     590    11301330 :         EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
     591             :         {
     592    11301330 :             int         resultnum = op->d.assign_var.resultnum;
     593    11301330 :             int         attnum = op->d.assign_var.attnum;
     594             : 
     595             :             /*
     596             :              * We do not need CheckVarSlotCompatibility here; that was taken
     597             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     598             :              */
     599             :             Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
     600    11301330 :             resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
     601    11301330 :             resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
     602             : 
     603    11301330 :             EEO_NEXT();
     604             :         }
     605             : 
     606    35779614 :         EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
     607             :         {
     608    35779614 :             int         resultnum = op->d.assign_var.resultnum;
     609    35779614 :             int         attnum = op->d.assign_var.attnum;
     610             : 
     611             :             /*
     612             :              * We do not need CheckVarSlotCompatibility here; that was taken
     613             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     614             :              */
     615             :             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
     616    35779614 :             resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
     617    35779614 :             resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
     618             : 
     619    35779614 :             EEO_NEXT();
     620             :         }
     621             : 
     622    29708066 :         EEO_CASE(EEOP_ASSIGN_TMP)
     623             :         {
     624    29708066 :             int         resultnum = op->d.assign_tmp.resultnum;
     625             : 
     626    29708066 :             resultslot->tts_values[resultnum] = state->resvalue;
     627    29708066 :             resultslot->tts_isnull[resultnum] = state->resnull;
     628             : 
     629    29708066 :             EEO_NEXT();
     630             :         }
     631             : 
     632     8863470 :         EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
     633             :         {
     634     8863470 :             int         resultnum = op->d.assign_tmp.resultnum;
     635             : 
     636     8863470 :             resultslot->tts_isnull[resultnum] = state->resnull;
     637     8863470 :             if (!resultslot->tts_isnull[resultnum])
     638     4622020 :                 resultslot->tts_values[resultnum] =
     639     4622020 :                     MakeExpandedObjectReadOnlyInternal(state->resvalue);
     640             :             else
     641     4241450 :                 resultslot->tts_values[resultnum] = state->resvalue;
     642             : 
     643     8863470 :             EEO_NEXT();
     644             :         }
     645             : 
     646    26043808 :         EEO_CASE(EEOP_CONST)
     647             :         {
     648    26043808 :             *op->resnull = op->d.constval.isnull;
     649    26043808 :             *op->resvalue = op->d.constval.value;
     650             : 
     651    26043808 :             EEO_NEXT();
     652             :         }
     653             : 
     654             :         /*
     655             :          * Function-call implementations. Arguments have previously been
     656             :          * evaluated directly into fcinfo->args.
     657             :          *
     658             :          * As both STRICT checks and function-usage are noticeable performance
     659             :          * wise, and function calls are a very hot-path (they also back
     660             :          * operators!), it's worth having so many separate opcodes.
     661             :          *
     662             :          * Note: the reason for using a temporary variable "d", here and in
     663             :          * other places, is that some compilers think "*op->resvalue = f();"
     664             :          * requires them to evaluate op->resvalue into a register before
     665             :          * calling f(), just in case f() is able to modify op->resvalue
     666             :          * somehow.  The extra line of code can save a useless register spill
     667             :          * and reload across the function call.
     668             :          */
     669      909796 :         EEO_CASE(EEOP_FUNCEXPR)
     670             :         {
     671      909796 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     672             :             Datum       d;
     673             : 
     674      909796 :             fcinfo->isnull = false;
     675      909796 :             d = op->d.func.fn_addr(fcinfo);
     676      902762 :             *op->resvalue = d;
     677      902762 :             *op->resnull = fcinfo->isnull;
     678             : 
     679      902762 :             EEO_NEXT();
     680             :         }
     681             : 
     682    65979854 :         EEO_CASE(EEOP_FUNCEXPR_STRICT)
     683             :         {
     684    65979854 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     685    65979854 :             NullableDatum *args = fcinfo->args;
     686    65979854 :             int         nargs = op->d.func.nargs;
     687             :             Datum       d;
     688             : 
     689             :             /* strict function, so check for NULL args */
     690   189578666 :             for (int argno = 0; argno < nargs; argno++)
     691             :             {
     692   124328948 :                 if (args[argno].isnull)
     693             :                 {
     694      730136 :                     *op->resnull = true;
     695      730136 :                     goto strictfail;
     696             :                 }
     697             :             }
     698    65249718 :             fcinfo->isnull = false;
     699    65249718 :             d = op->d.func.fn_addr(fcinfo);
     700    65246594 :             *op->resvalue = d;
     701    65246594 :             *op->resnull = fcinfo->isnull;
     702             : 
     703    65976730 :     strictfail:
     704    65976730 :             EEO_NEXT();
     705             :         }
     706             : 
     707           0 :         EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
     708             :         {
     709             :             /* not common enough to inline */
     710           0 :             ExecEvalFuncExprFusage(state, op, econtext);
     711             : 
     712           0 :             EEO_NEXT();
     713             :         }
     714             : 
     715           0 :         EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
     716             :         {
     717             :             /* not common enough to inline */
     718           0 :             ExecEvalFuncExprStrictFusage(state, op, econtext);
     719             : 
     720           0 :             EEO_NEXT();
     721             :         }
     722             : 
     723             :         /*
     724             :          * If any of its clauses is FALSE, an AND's result is FALSE regardless
     725             :          * of the states of the rest of the clauses, so we can stop evaluating
     726             :          * and return FALSE immediately.  If none are FALSE and one or more is
     727             :          * NULL, we return NULL; otherwise we return TRUE.  This makes sense
     728             :          * when you interpret NULL as "don't know": perhaps one of the "don't
     729             :          * knows" would have been FALSE if we'd known its value.  Only when
     730             :          * all the inputs are known to be TRUE can we state confidently that
     731             :          * the AND's result is TRUE.
     732             :          */
     733      320626 :         EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
     734             :         {
     735      320626 :             *op->d.boolexpr.anynull = false;
     736             : 
     737             :             /*
     738             :              * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the
     739             :              * same as EEOP_BOOL_AND_STEP - so fall through to that.
     740             :              */
     741             : 
     742             :             /* FALL THROUGH */
     743             :         }
     744             : 
     745      354584 :         EEO_CASE(EEOP_BOOL_AND_STEP)
     746             :         {
     747      354584 :             if (*op->resnull)
     748             :             {
     749        1204 :                 *op->d.boolexpr.anynull = true;
     750             :             }
     751      353380 :             else if (!DatumGetBool(*op->resvalue))
     752             :             {
     753             :                 /* result is already set to FALSE, need not change it */
     754             :                 /* bail out early */
     755      213194 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
     756             :             }
     757             : 
     758      141390 :             EEO_NEXT();
     759             :         }
     760             : 
     761      107432 :         EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
     762             :         {
     763      107432 :             if (*op->resnull)
     764             :             {
     765             :                 /* result is already set to NULL, need not change it */
     766             :             }
     767      106586 :             else if (!DatumGetBool(*op->resvalue))
     768             :             {
     769             :                 /* result is already set to FALSE, need not change it */
     770             : 
     771             :                 /*
     772             :                  * No point jumping early to jumpdone - would be same target
     773             :                  * (as this is the last argument to the AND expression),
     774             :                  * except more expensive.
     775             :                  */
     776             :             }
     777       39028 :             else if (*op->d.boolexpr.anynull)
     778             :             {
     779         372 :                 *op->resvalue = (Datum) 0;
     780         372 :                 *op->resnull = true;
     781             :             }
     782             :             else
     783             :             {
     784             :                 /* result is already set to TRUE, need not change it */
     785             :             }
     786             : 
     787      107432 :             EEO_NEXT();
     788             :         }
     789             : 
     790             :         /*
     791             :          * If any of its clauses is TRUE, an OR's result is TRUE regardless of
     792             :          * the states of the rest of the clauses, so we can stop evaluating
     793             :          * and return TRUE immediately.  If none are TRUE and one or more is
     794             :          * NULL, we return NULL; otherwise we return FALSE.  This makes sense
     795             :          * when you interpret NULL as "don't know": perhaps one of the "don't
     796             :          * knows" would have been TRUE if we'd known its value.  Only when all
     797             :          * the inputs are known to be FALSE can we state confidently that the
     798             :          * OR's result is FALSE.
     799             :          */
     800     2055230 :         EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
     801             :         {
     802     2055230 :             *op->d.boolexpr.anynull = false;
     803             : 
     804             :             /*
     805             :              * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same
     806             :              * as EEOP_BOOL_OR_STEP - so fall through to that.
     807             :              */
     808             : 
     809             :             /* FALL THROUGH */
     810             :         }
     811             : 
     812     3794290 :         EEO_CASE(EEOP_BOOL_OR_STEP)
     813             :         {
     814     3794290 :             if (*op->resnull)
     815             :             {
     816      102212 :                 *op->d.boolexpr.anynull = true;
     817             :             }
     818     3692078 :             else if (DatumGetBool(*op->resvalue))
     819             :             {
     820             :                 /* result is already set to TRUE, need not change it */
     821             :                 /* bail out early */
     822      291202 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
     823             :             }
     824             : 
     825     3503088 :             EEO_NEXT();
     826             :         }
     827             : 
     828     1764028 :         EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
     829             :         {
     830     1764028 :             if (*op->resnull)
     831             :             {
     832             :                 /* result is already set to NULL, need not change it */
     833             :             }
     834     1701880 :             else if (DatumGetBool(*op->resvalue))
     835             :             {
     836             :                 /* result is already set to TRUE, need not change it */
     837             : 
     838             :                 /*
     839             :                  * No point jumping to jumpdone - would be same target (as
     840             :                  * this is the last argument to the AND expression), except
     841             :                  * more expensive.
     842             :                  */
     843             :             }
     844     1681570 :             else if (*op->d.boolexpr.anynull)
     845             :             {
     846         962 :                 *op->resvalue = (Datum) 0;
     847         962 :                 *op->resnull = true;
     848             :             }
     849             :             else
     850             :             {
     851             :                 /* result is already set to FALSE, need not change it */
     852             :             }
     853             : 
     854     1764028 :             EEO_NEXT();
     855             :         }
     856             : 
     857      535510 :         EEO_CASE(EEOP_BOOL_NOT_STEP)
     858             :         {
     859             :             /*
     860             :              * Evaluation of 'not' is simple... if expr is false, then return
     861             :              * 'true' and vice versa.  It's safe to do this even on a
     862             :              * nominally null value, so we ignore resnull; that means that
     863             :              * NULL in produces NULL out, which is what we want.
     864             :              */
     865      535510 :             *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
     866             : 
     867      535510 :             EEO_NEXT();
     868             :         }
     869             : 
     870    55539852 :         EEO_CASE(EEOP_QUAL)
     871             :         {
     872             :             /* simplified version of BOOL_AND_STEP for use by ExecQual() */
     873             : 
     874             :             /* If argument (also result) is false or null ... */
     875    55539852 :             if (*op->resnull ||
     876    55066488 :                 !DatumGetBool(*op->resvalue))
     877             :             {
     878             :                 /* ... bail out early, returning FALSE */
     879    34599974 :                 *op->resnull = false;
     880    34599974 :                 *op->resvalue = BoolGetDatum(false);
     881    34599974 :                 EEO_JUMP(op->d.qualexpr.jumpdone);
     882             :             }
     883             : 
     884             :             /*
     885             :              * Otherwise, leave the TRUE value in place, in case this is the
     886             :              * last qual.  Then, TRUE is the correct answer.
     887             :              */
     888             : 
     889    20939878 :             EEO_NEXT();
     890             :         }
     891             : 
     892      110758 :         EEO_CASE(EEOP_JUMP)
     893             :         {
     894             :             /* Unconditionally jump to target step */
     895      110758 :             EEO_JUMP(op->d.jump.jumpdone);
     896             :         }
     897             : 
     898      457516 :         EEO_CASE(EEOP_JUMP_IF_NULL)
     899             :         {
     900             :             /* Transfer control if current result is null */
     901      457516 :             if (*op->resnull)
     902        2346 :                 EEO_JUMP(op->d.jump.jumpdone);
     903             : 
     904      455170 :             EEO_NEXT();
     905             :         }
     906             : 
     907     2706896 :         EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
     908             :         {
     909             :             /* Transfer control if current result is non-null */
     910     2706896 :             if (!*op->resnull)
     911     1429274 :                 EEO_JUMP(op->d.jump.jumpdone);
     912             : 
     913     1277622 :             EEO_NEXT();
     914             :         }
     915             : 
     916     1059950 :         EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
     917             :         {
     918             :             /* Transfer control if current result is null or false */
     919     1059950 :             if (*op->resnull || !DatumGetBool(*op->resvalue))
     920      872470 :                 EEO_JUMP(op->d.jump.jumpdone);
     921             : 
     922      187480 :             EEO_NEXT();
     923             :         }
     924             : 
     925      404738 :         EEO_CASE(EEOP_NULLTEST_ISNULL)
     926             :         {
     927      404738 :             *op->resvalue = BoolGetDatum(*op->resnull);
     928      404738 :             *op->resnull = false;
     929             : 
     930      404738 :             EEO_NEXT();
     931             :         }
     932             : 
     933     4119920 :         EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
     934             :         {
     935     4119920 :             *op->resvalue = BoolGetDatum(!*op->resnull);
     936     4119920 :             *op->resnull = false;
     937             : 
     938     4119920 :             EEO_NEXT();
     939             :         }
     940             : 
     941         388 :         EEO_CASE(EEOP_NULLTEST_ROWISNULL)
     942             :         {
     943             :             /* out of line implementation: too large */
     944         388 :             ExecEvalRowNull(state, op, econtext);
     945             : 
     946         388 :             EEO_NEXT();
     947             :         }
     948             : 
     949         216 :         EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
     950             :         {
     951             :             /* out of line implementation: too large */
     952         216 :             ExecEvalRowNotNull(state, op, econtext);
     953             : 
     954         216 :             EEO_NEXT();
     955             :         }
     956             : 
     957             :         /* BooleanTest implementations for all booltesttypes */
     958             : 
     959          86 :         EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
     960             :         {
     961          86 :             if (*op->resnull)
     962             :             {
     963           8 :                 *op->resvalue = BoolGetDatum(false);
     964           8 :                 *op->resnull = false;
     965             :             }
     966             :             /* else, input value is the correct output as well */
     967             : 
     968          86 :             EEO_NEXT();
     969             :         }
     970             : 
     971        1582 :         EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE)
     972             :         {
     973        1582 :             if (*op->resnull)
     974             :             {
     975         112 :                 *op->resvalue = BoolGetDatum(true);
     976         112 :                 *op->resnull = false;
     977             :             }
     978             :             else
     979        1470 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
     980             : 
     981        1582 :             EEO_NEXT();
     982             :         }
     983             : 
     984         780 :         EEO_CASE(EEOP_BOOLTEST_IS_FALSE)
     985             :         {
     986         780 :             if (*op->resnull)
     987             :             {
     988         158 :                 *op->resvalue = BoolGetDatum(false);
     989         158 :                 *op->resnull = false;
     990             :             }
     991             :             else
     992         622 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
     993             : 
     994         780 :             EEO_NEXT();
     995             :         }
     996             : 
     997         308 :         EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE)
     998             :         {
     999         308 :             if (*op->resnull)
    1000             :             {
    1001           4 :                 *op->resvalue = BoolGetDatum(true);
    1002           4 :                 *op->resnull = false;
    1003             :             }
    1004             :             /* else, input value is the correct output as well */
    1005             : 
    1006         308 :             EEO_NEXT();
    1007             :         }
    1008             : 
    1009    14382420 :         EEO_CASE(EEOP_PARAM_EXEC)
    1010             :         {
    1011             :             /* out of line implementation: too large */
    1012    14382420 :             ExecEvalParamExec(state, op, econtext);
    1013             : 
    1014    14382410 :             EEO_NEXT();
    1015             :         }
    1016             : 
    1017      142448 :         EEO_CASE(EEOP_PARAM_EXTERN)
    1018             :         {
    1019             :             /* out of line implementation: too large */
    1020      142448 :             ExecEvalParamExtern(state, op, econtext);
    1021      142448 :             EEO_NEXT();
    1022             :         }
    1023             : 
    1024      798324 :         EEO_CASE(EEOP_PARAM_CALLBACK)
    1025             :         {
    1026             :             /* allow an extension module to supply a PARAM_EXTERN value */
    1027      798324 :             op->d.cparam.paramfunc(state, op, econtext);
    1028      798316 :             EEO_NEXT();
    1029             :         }
    1030             : 
    1031        8600 :         EEO_CASE(EEOP_CASE_TESTVAL)
    1032             :         {
    1033             :             /*
    1034             :              * Normally upper parts of the expression tree have setup the
    1035             :              * values to be returned here, but some parts of the system
    1036             :              * currently misuse {caseValue,domainValue}_{datum,isNull} to set
    1037             :              * run-time data.  So if no values have been set-up, use
    1038             :              * ExprContext's.  This isn't pretty, but also not *that* ugly,
    1039             :              * and this is unlikely to be performance sensitive enough to
    1040             :              * worry about an extra branch.
    1041             :              */
    1042        8600 :             if (op->d.casetest.value)
    1043             :             {
    1044        4018 :                 *op->resvalue = *op->d.casetest.value;
    1045        4018 :                 *op->resnull = *op->d.casetest.isnull;
    1046             :             }
    1047             :             else
    1048             :             {
    1049        4582 :                 *op->resvalue = econtext->caseValue_datum;
    1050        4582 :                 *op->resnull = econtext->caseValue_isNull;
    1051             :             }
    1052             : 
    1053        8600 :             EEO_NEXT();
    1054             :         }
    1055             : 
    1056      289370 :         EEO_CASE(EEOP_DOMAIN_TESTVAL)
    1057             :         {
    1058             :             /*
    1059             :              * See EEOP_CASE_TESTVAL comment.
    1060             :              */
    1061      289370 :             if (op->d.casetest.value)
    1062             :             {
    1063       31976 :                 *op->resvalue = *op->d.casetest.value;
    1064       31976 :                 *op->resnull = *op->d.casetest.isnull;
    1065             :             }
    1066             :             else
    1067             :             {
    1068      257394 :                 *op->resvalue = econtext->domainValue_datum;
    1069      257394 :                 *op->resnull = econtext->domainValue_isNull;
    1070             :             }
    1071             : 
    1072      289370 :             EEO_NEXT();
    1073             :         }
    1074             : 
    1075        6628 :         EEO_CASE(EEOP_MAKE_READONLY)
    1076             :         {
    1077             :             /*
    1078             :              * Force a varlena value that might be read multiple times to R/O
    1079             :              */
    1080        6628 :             if (!*op->d.make_readonly.isnull)
    1081        6590 :                 *op->resvalue =
    1082        6590 :                     MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
    1083        6628 :             *op->resnull = *op->d.make_readonly.isnull;
    1084             : 
    1085        6628 :             EEO_NEXT();
    1086             :         }
    1087             : 
    1088     2486688 :         EEO_CASE(EEOP_IOCOERCE)
    1089             :         {
    1090             :             /*
    1091             :              * Evaluate a CoerceViaIO node.  This can be quite a hot path, so
    1092             :              * inline as much work as possible.  The source value is in our
    1093             :              * result variable.
    1094             :              */
    1095             :             char       *str;
    1096             : 
    1097             :             /* call output function (similar to OutputFunctionCall) */
    1098     2486688 :             if (*op->resnull)
    1099             :             {
    1100             :                 /* output functions are not called on nulls */
    1101         792 :                 str = NULL;
    1102             :             }
    1103             :             else
    1104             :             {
    1105             :                 FunctionCallInfo fcinfo_out;
    1106             : 
    1107     2485896 :                 fcinfo_out = op->d.iocoerce.fcinfo_data_out;
    1108     2485896 :                 fcinfo_out->args[0].value = *op->resvalue;
    1109     2485896 :                 fcinfo_out->args[0].isnull = false;
    1110             : 
    1111     2485896 :                 fcinfo_out->isnull = false;
    1112     2485896 :                 str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
    1113             : 
    1114             :                 /* OutputFunctionCall assumes result isn't null */
    1115             :                 Assert(!fcinfo_out->isnull);
    1116             :             }
    1117             : 
    1118             :             /* call input function (similar to InputFunctionCall) */
    1119     2486688 :             if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
    1120             :             {
    1121             :                 FunctionCallInfo fcinfo_in;
    1122             :                 Datum       d;
    1123             : 
    1124     2485974 :                 fcinfo_in = op->d.iocoerce.fcinfo_data_in;
    1125     2485974 :                 fcinfo_in->args[0].value = PointerGetDatum(str);
    1126     2485974 :                 fcinfo_in->args[0].isnull = *op->resnull;
    1127             :                 /* second and third arguments are already set up */
    1128             : 
    1129     2485974 :                 fcinfo_in->isnull = false;
    1130     2485974 :                 d = FunctionCallInvoke(fcinfo_in);
    1131     2485936 :                 *op->resvalue = d;
    1132             : 
    1133             :                 /* Should get null result if and only if str is NULL */
    1134             :                 if (str == NULL)
    1135             :                 {
    1136             :                     Assert(*op->resnull);
    1137             :                     Assert(fcinfo_in->isnull);
    1138             :                 }
    1139             :                 else
    1140             :                 {
    1141             :                     Assert(!*op->resnull);
    1142             :                     Assert(!fcinfo_in->isnull);
    1143             :                 }
    1144             :             }
    1145             : 
    1146     2486650 :             EEO_NEXT();
    1147             :         }
    1148             : 
    1149      509822 :         EEO_CASE(EEOP_DISTINCT)
    1150             :         {
    1151             :             /*
    1152             :              * IS DISTINCT FROM must evaluate arguments (already done into
    1153             :              * fcinfo->args) to determine whether they are NULL; if either is
    1154             :              * NULL then the result is determined.  If neither is NULL, then
    1155             :              * proceed to evaluate the comparison function, which is just the
    1156             :              * type's standard equality operator.  We need not care whether
    1157             :              * that function is strict.  Because the handling of nulls is
    1158             :              * different, we can't just reuse EEOP_FUNCEXPR.
    1159             :              */
    1160      509822 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1161             : 
    1162             :             /* check function arguments for NULLness */
    1163      509822 :             if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
    1164             :             {
    1165             :                 /* Both NULL? Then is not distinct... */
    1166      477188 :                 *op->resvalue = BoolGetDatum(false);
    1167      477188 :                 *op->resnull = false;
    1168             :             }
    1169       32634 :             else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
    1170             :             {
    1171             :                 /* Only one is NULL? Then is distinct... */
    1172         182 :                 *op->resvalue = BoolGetDatum(true);
    1173         182 :                 *op->resnull = false;
    1174             :             }
    1175             :             else
    1176             :             {
    1177             :                 /* Neither null, so apply the equality function */
    1178             :                 Datum       eqresult;
    1179             : 
    1180       32452 :                 fcinfo->isnull = false;
    1181       32452 :                 eqresult = op->d.func.fn_addr(fcinfo);
    1182             :                 /* Must invert result of "="; safe to do even if null */
    1183       32452 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
    1184       32452 :                 *op->resnull = fcinfo->isnull;
    1185             :             }
    1186             : 
    1187      509822 :             EEO_NEXT();
    1188             :         }
    1189             : 
    1190             :         /* see EEOP_DISTINCT for comments, this is just inverted */
    1191     6871730 :         EEO_CASE(EEOP_NOT_DISTINCT)
    1192             :         {
    1193     6871730 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1194             : 
    1195     6871730 :             if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
    1196             :             {
    1197       99306 :                 *op->resvalue = BoolGetDatum(true);
    1198       99306 :                 *op->resnull = false;
    1199             :             }
    1200     6772424 :             else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
    1201             :             {
    1202         194 :                 *op->resvalue = BoolGetDatum(false);
    1203         194 :                 *op->resnull = false;
    1204             :             }
    1205             :             else
    1206             :             {
    1207             :                 Datum       eqresult;
    1208             : 
    1209     6772230 :                 fcinfo->isnull = false;
    1210     6772230 :                 eqresult = op->d.func.fn_addr(fcinfo);
    1211     6772230 :                 *op->resvalue = eqresult;
    1212     6772230 :                 *op->resnull = fcinfo->isnull;
    1213             :             }
    1214             : 
    1215     6871730 :             EEO_NEXT();
    1216             :         }
    1217             : 
    1218        4396 :         EEO_CASE(EEOP_NULLIF)
    1219             :         {
    1220             :             /*
    1221             :              * The arguments are already evaluated into fcinfo->args.
    1222             :              */
    1223        4396 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1224             : 
    1225             :             /* if either argument is NULL they can't be equal */
    1226        4396 :             if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull)
    1227             :             {
    1228             :                 Datum       result;
    1229             : 
    1230        4360 :                 fcinfo->isnull = false;
    1231        4360 :                 result = op->d.func.fn_addr(fcinfo);
    1232             : 
    1233             :                 /* if the arguments are equal return null */
    1234        4360 :                 if (!fcinfo->isnull && DatumGetBool(result))
    1235             :                 {
    1236          60 :                     *op->resvalue = (Datum) 0;
    1237          60 :                     *op->resnull = true;
    1238             : 
    1239          60 :                     EEO_NEXT();
    1240             :                 }
    1241             :             }
    1242             : 
    1243             :             /* Arguments aren't equal, so return the first one */
    1244        4336 :             *op->resvalue = fcinfo->args[0].value;
    1245        4336 :             *op->resnull = fcinfo->args[0].isnull;
    1246             : 
    1247        4336 :             EEO_NEXT();
    1248             :         }
    1249             : 
    1250        4364 :         EEO_CASE(EEOP_SQLVALUEFUNCTION)
    1251             :         {
    1252             :             /*
    1253             :              * Doesn't seem worthwhile to have an inline implementation
    1254             :              * efficiency-wise.
    1255             :              */
    1256        4364 :             ExecEvalSQLValueFunction(state, op);
    1257             : 
    1258        4364 :             EEO_NEXT();
    1259             :         }
    1260             : 
    1261           0 :         EEO_CASE(EEOP_CURRENTOFEXPR)
    1262             :         {
    1263             :             /* error invocation uses space, and shouldn't ever occur */
    1264           0 :             ExecEvalCurrentOfExpr(state, op);
    1265             : 
    1266           0 :             EEO_NEXT();
    1267             :         }
    1268             : 
    1269         224 :         EEO_CASE(EEOP_NEXTVALUEEXPR)
    1270             :         {
    1271             :             /*
    1272             :              * Doesn't seem worthwhile to have an inline implementation
    1273             :              * efficiency-wise.
    1274             :              */
    1275         224 :             ExecEvalNextValueExpr(state, op);
    1276             : 
    1277         224 :             EEO_NEXT();
    1278             :         }
    1279             : 
    1280      263194 :         EEO_CASE(EEOP_ARRAYEXPR)
    1281             :         {
    1282             :             /* too complex for an inline implementation */
    1283      263194 :             ExecEvalArrayExpr(state, op);
    1284             : 
    1285      263194 :             EEO_NEXT();
    1286             :         }
    1287             : 
    1288       38874 :         EEO_CASE(EEOP_ARRAYCOERCE)
    1289             :         {
    1290             :             /* too complex for an inline implementation */
    1291       38874 :             ExecEvalArrayCoerce(state, op, econtext);
    1292             : 
    1293       38856 :             EEO_NEXT();
    1294             :         }
    1295             : 
    1296       20888 :         EEO_CASE(EEOP_ROW)
    1297             :         {
    1298             :             /* too complex for an inline implementation */
    1299       20888 :             ExecEvalRow(state, op);
    1300             : 
    1301       20888 :             EEO_NEXT();
    1302             :         }
    1303             : 
    1304      139128 :         EEO_CASE(EEOP_ROWCOMPARE_STEP)
    1305             :         {
    1306      139128 :             FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
    1307             :             Datum       d;
    1308             : 
    1309             :             /* force NULL result if strict fn and NULL input */
    1310      139128 :             if (op->d.rowcompare_step.finfo->fn_strict &&
    1311      139128 :                 (fcinfo->args[0].isnull || fcinfo->args[1].isnull))
    1312             :             {
    1313          12 :                 *op->resnull = true;
    1314          12 :                 EEO_JUMP(op->d.rowcompare_step.jumpnull);
    1315             :             }
    1316             : 
    1317             :             /* Apply comparison function */
    1318      139116 :             fcinfo->isnull = false;
    1319      139116 :             d = op->d.rowcompare_step.fn_addr(fcinfo);
    1320      139116 :             *op->resvalue = d;
    1321             : 
    1322             :             /* force NULL result if NULL function result */
    1323      139116 :             if (fcinfo->isnull)
    1324             :             {
    1325           0 :                 *op->resnull = true;
    1326           0 :                 EEO_JUMP(op->d.rowcompare_step.jumpnull);
    1327             :             }
    1328      139116 :             *op->resnull = false;
    1329             : 
    1330             :             /* If unequal, no need to compare remaining columns */
    1331      139116 :             if (DatumGetInt32(*op->resvalue) != 0)
    1332             :             {
    1333       63008 :                 EEO_JUMP(op->d.rowcompare_step.jumpdone);
    1334             :             }
    1335             : 
    1336       76108 :             EEO_NEXT();
    1337             :         }
    1338             : 
    1339       63008 :         EEO_CASE(EEOP_ROWCOMPARE_FINAL)
    1340             :         {
    1341       63008 :             int32       cmpresult = DatumGetInt32(*op->resvalue);
    1342       63008 :             RowCompareType rctype = op->d.rowcompare_final.rctype;
    1343             : 
    1344       63008 :             *op->resnull = false;
    1345       63008 :             switch (rctype)
    1346             :             {
    1347             :                     /* EQ and NE cases aren't allowed here */
    1348       22936 :                 case ROWCOMPARE_LT:
    1349       22936 :                     *op->resvalue = BoolGetDatum(cmpresult < 0);
    1350       22936 :                     break;
    1351       40000 :                 case ROWCOMPARE_LE:
    1352       40000 :                     *op->resvalue = BoolGetDatum(cmpresult <= 0);
    1353       40000 :                     break;
    1354           4 :                 case ROWCOMPARE_GE:
    1355           4 :                     *op->resvalue = BoolGetDatum(cmpresult >= 0);
    1356           4 :                     break;
    1357          68 :                 case ROWCOMPARE_GT:
    1358          68 :                     *op->resvalue = BoolGetDatum(cmpresult > 0);
    1359          68 :                     break;
    1360           0 :                 default:
    1361             :                     Assert(false);
    1362           0 :                     break;
    1363             :             }
    1364             : 
    1365       63008 :             EEO_NEXT();
    1366             :         }
    1367             : 
    1368        2668 :         EEO_CASE(EEOP_MINMAX)
    1369             :         {
    1370             :             /* too complex for an inline implementation */
    1371        2668 :             ExecEvalMinMax(state, op);
    1372             : 
    1373        2668 :             EEO_NEXT();
    1374             :         }
    1375             : 
    1376       54276 :         EEO_CASE(EEOP_FIELDSELECT)
    1377             :         {
    1378             :             /* too complex for an inline implementation */
    1379       54276 :             ExecEvalFieldSelect(state, op, econtext);
    1380             : 
    1381       54276 :             EEO_NEXT();
    1382             :         }
    1383             : 
    1384         224 :         EEO_CASE(EEOP_FIELDSTORE_DEFORM)
    1385             :         {
    1386             :             /* too complex for an inline implementation */
    1387         224 :             ExecEvalFieldStoreDeForm(state, op, econtext);
    1388             : 
    1389         224 :             EEO_NEXT();
    1390             :         }
    1391             : 
    1392         224 :         EEO_CASE(EEOP_FIELDSTORE_FORM)
    1393             :         {
    1394             :             /* too complex for an inline implementation */
    1395         224 :             ExecEvalFieldStoreForm(state, op, econtext);
    1396             : 
    1397         224 :             EEO_NEXT();
    1398             :         }
    1399             : 
    1400      456512 :         EEO_CASE(EEOP_SBSREF_SUBSCRIPT)
    1401             :         {
    1402             :             /* Process an array subscript */
    1403             : 
    1404             :             /* too complex for an inline implementation */
    1405      456512 :             if (ExecEvalSubscriptingRef(state, op))
    1406             :             {
    1407      456488 :                 EEO_NEXT();
    1408             :             }
    1409             :             else
    1410             :             {
    1411             :                 /* Subscript is null, short-circuit SubscriptingRef to NULL */
    1412          12 :                 EEO_JUMP(op->d.sbsref_subscript.jumpdone);
    1413             :             }
    1414             :         }
    1415             : 
    1416         132 :         EEO_CASE(EEOP_SBSREF_OLD)
    1417             :         {
    1418             :             /*
    1419             :              * Fetch the old value in an sbsref assignment, in case it's
    1420             :              * referenced (via a CaseTestExpr) inside the assignment
    1421             :              * expression.
    1422             :              */
    1423             : 
    1424             :             /* too complex for an inline implementation */
    1425         132 :             ExecEvalSubscriptingRefOld(state, op);
    1426             : 
    1427         132 :             EEO_NEXT();
    1428             :         }
    1429             : 
    1430             :         /*
    1431             :          * Perform SubscriptingRef assignment
    1432             :          */
    1433         618 :         EEO_CASE(EEOP_SBSREF_ASSIGN)
    1434             :         {
    1435             :             /* too complex for an inline implementation */
    1436         618 :             ExecEvalSubscriptingRefAssign(state, op);
    1437             : 
    1438         602 :             EEO_NEXT();
    1439             :         }
    1440             : 
    1441             :         /*
    1442             :          * Fetch subset of an array.
    1443             :          */
    1444      455158 :         EEO_CASE(EEOP_SBSREF_FETCH)
    1445             :         {
    1446             :             /* too complex for an inline implementation */
    1447      455158 :             ExecEvalSubscriptingRefFetch(state, op);
    1448             : 
    1449      455142 :             EEO_NEXT();
    1450             :         }
    1451             : 
    1452       10054 :         EEO_CASE(EEOP_CONVERT_ROWTYPE)
    1453             :         {
    1454             :             /* too complex for an inline implementation */
    1455       10054 :             ExecEvalConvertRowtype(state, op, econtext);
    1456             : 
    1457       10054 :             EEO_NEXT();
    1458             :         }
    1459             : 
    1460     3145074 :         EEO_CASE(EEOP_SCALARARRAYOP)
    1461             :         {
    1462             :             /* too complex for an inline implementation */
    1463     3145074 :             ExecEvalScalarArrayOp(state, op);
    1464             : 
    1465     3145074 :             EEO_NEXT();
    1466             :         }
    1467             : 
    1468         250 :         EEO_CASE(EEOP_DOMAIN_NOTNULL)
    1469             :         {
    1470             :             /* too complex for an inline implementation */
    1471         250 :             ExecEvalConstraintNotNull(state, op);
    1472             : 
    1473         186 :             EEO_NEXT();
    1474             :         }
    1475             : 
    1476       31632 :         EEO_CASE(EEOP_DOMAIN_CHECK)
    1477             :         {
    1478             :             /* too complex for an inline implementation */
    1479       31632 :             ExecEvalConstraintCheck(state, op);
    1480             : 
    1481       31388 :             EEO_NEXT();
    1482             :         }
    1483             : 
    1484       26428 :         EEO_CASE(EEOP_XMLEXPR)
    1485             :         {
    1486             :             /* too complex for an inline implementation */
    1487       26428 :             ExecEvalXmlExpr(state, op);
    1488             : 
    1489       26376 :             EEO_NEXT();
    1490             :         }
    1491             : 
    1492     1430172 :         EEO_CASE(EEOP_AGGREF)
    1493             :         {
    1494             :             /*
    1495             :              * Returns a Datum whose value is the precomputed aggregate value
    1496             :              * found in the given expression context.
    1497             :              */
    1498     1430172 :             AggrefExprState *aggref = op->d.aggref.astate;
    1499             : 
    1500             :             Assert(econtext->ecxt_aggvalues != NULL);
    1501             : 
    1502     1430172 :             *op->resvalue = econtext->ecxt_aggvalues[aggref->aggno];
    1503     1430172 :             *op->resnull = econtext->ecxt_aggnulls[aggref->aggno];
    1504             : 
    1505     1430172 :             EEO_NEXT();
    1506             :         }
    1507             : 
    1508        1094 :         EEO_CASE(EEOP_GROUPING_FUNC)
    1509             :         {
    1510             :             /* too complex/uncommon for an inline implementation */
    1511        1094 :             ExecEvalGroupingFunc(state, op);
    1512             : 
    1513        1094 :             EEO_NEXT();
    1514             :         }
    1515             : 
    1516      638616 :         EEO_CASE(EEOP_WINDOW_FUNC)
    1517             :         {
    1518             :             /*
    1519             :              * Like Aggref, just return a precomputed value from the econtext.
    1520             :              */
    1521      638616 :             WindowFuncExprState *wfunc = op->d.window_func.wfstate;
    1522             : 
    1523             :             Assert(econtext->ecxt_aggvalues != NULL);
    1524             : 
    1525      638616 :             *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];
    1526      638616 :             *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];
    1527             : 
    1528      638616 :             EEO_NEXT();
    1529             :         }
    1530             : 
    1531     2375948 :         EEO_CASE(EEOP_SUBPLAN)
    1532             :         {
    1533             :             /* too complex for an inline implementation */
    1534     2375948 :             ExecEvalSubPlan(state, op, econtext);
    1535             : 
    1536     2375944 :             EEO_NEXT();
    1537             :         }
    1538             : 
    1539      511298 :         EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN)
    1540             :         {
    1541             :             /* too complex for an inline implementation */
    1542      511298 :             ExecEvalAlternativeSubPlan(state, op, econtext);
    1543             : 
    1544      511298 :             EEO_NEXT();
    1545             :         }
    1546             : 
    1547             :         /* evaluate a strict aggregate deserialization function */
    1548          60 :         EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
    1549             :         {
    1550             :             /* Don't call a strict deserialization function with NULL input */
    1551          60 :             if (op->d.agg_deserialize.fcinfo_data->args[0].isnull)
    1552          48 :                 EEO_JUMP(op->d.agg_deserialize.jumpnull);
    1553             : 
    1554             :             /* fallthrough */
    1555             :         }
    1556             : 
    1557             :         /* evaluate aggregate deserialization function (non-strict portion) */
    1558          12 :         EEO_CASE(EEOP_AGG_DESERIALIZE)
    1559             :         {
    1560          12 :             FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
    1561          12 :             AggState   *aggstate = castNode(AggState, state->parent);
    1562             :             MemoryContext oldContext;
    1563             : 
    1564             :             /*
    1565             :              * We run the deserialization functions in per-input-tuple memory
    1566             :              * context.
    1567             :              */
    1568          12 :             oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    1569          12 :             fcinfo->isnull = false;
    1570          12 :             *op->resvalue = FunctionCallInvoke(fcinfo);
    1571          12 :             *op->resnull = fcinfo->isnull;
    1572          12 :             MemoryContextSwitchTo(oldContext);
    1573             : 
    1574          12 :             EEO_NEXT();
    1575             :         }
    1576             : 
    1577             :         /*
    1578             :          * Check that a strict aggregate transition / combination function's
    1579             :          * input is not NULL.
    1580             :          */
    1581             : 
    1582     2558680 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
    1583             :         {
    1584     2558680 :             NullableDatum *args = op->d.agg_strict_input_check.args;
    1585     2558680 :             int         nargs = op->d.agg_strict_input_check.nargs;
    1586             : 
    1587     5156898 :             for (int argno = 0; argno < nargs; argno++)
    1588             :             {
    1589     2598960 :                 if (args[argno].isnull)
    1590         742 :                     EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    1591             :             }
    1592     2557938 :             EEO_NEXT();
    1593             :         }
    1594             : 
    1595      188572 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
    1596             :         {
    1597      188572 :             bool       *nulls = op->d.agg_strict_input_check.nulls;
    1598      188572 :             int         nargs = op->d.agg_strict_input_check.nargs;
    1599             : 
    1600      377288 :             for (int argno = 0; argno < nargs; argno++)
    1601             :             {
    1602      188740 :                 if (nulls[argno])
    1603          24 :                     EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    1604             :             }
    1605      188548 :             EEO_NEXT();
    1606             :         }
    1607             : 
    1608             :         /*
    1609             :          * Check for a NULL pointer to the per-group states.
    1610             :          */
    1611             : 
    1612       53056 :         EEO_CASE(EEOP_AGG_PLAIN_PERGROUP_NULLCHECK)
    1613             :         {
    1614       53056 :             AggState   *aggstate = castNode(AggState, state->parent);
    1615       53056 :             AggStatePerGroup pergroup_allaggs =
    1616       53056 :             aggstate->all_pergroups[op->d.agg_plain_pergroup_nullcheck.setoff];
    1617             : 
    1618       53056 :             if (pergroup_allaggs == NULL)
    1619       26512 :                 EEO_JUMP(op->d.agg_plain_pergroup_nullcheck.jumpnull);
    1620             : 
    1621       26544 :             EEO_NEXT();
    1622             :         }
    1623             : 
    1624             :         /*
    1625             :          * Different types of aggregate transition functions are implemented
    1626             :          * as different types of steps, to avoid incurring unnecessary
    1627             :          * overhead.  There's a step type for each valid combination of having
    1628             :          * a by value / by reference transition type, [not] needing to the
    1629             :          * initialize the transition value for the first row in a group from
    1630             :          * input, and [not] strict transition function.
    1631             :          *
    1632             :          * Could optimize further by splitting off by-reference for
    1633             :          * fixed-length types, but currently that doesn't seem worth it.
    1634             :          */
    1635             : 
    1636      258936 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
    1637             :         {
    1638      258936 :             AggState   *aggstate = castNode(AggState, state->parent);
    1639      258936 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1640      258936 :             AggStatePerGroup pergroup =
    1641      258936 :             &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1642             : 
    1643             :             Assert(pertrans->transtypeByVal);
    1644             : 
    1645      258936 :             if (pergroup->noTransValue)
    1646             :             {
    1647             :                 /* If transValue has not yet been initialized, do so now. */
    1648        5668 :                 ExecAggInitGroup(aggstate, pertrans, pergroup,
    1649             :                                  op->d.agg_trans.aggcontext);
    1650             :                 /* copied trans value from input, done this round */
    1651             :             }
    1652      253268 :             else if (likely(!pergroup->transValueIsNull))
    1653             :             {
    1654             :                 /* invoke transition function, unless prevented by strictness */
    1655      253268 :                 ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    1656             :                                        op->d.agg_trans.aggcontext,
    1657             :                                        op->d.agg_trans.setno);
    1658             :             }
    1659             : 
    1660      258936 :             EEO_NEXT();
    1661             :         }
    1662             : 
    1663             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    1664     9786294 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL)
    1665             :         {
    1666     9786294 :             AggState   *aggstate = castNode(AggState, state->parent);
    1667     9786294 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1668     9786294 :             AggStatePerGroup pergroup =
    1669     9786294 :             &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1670             : 
    1671             :             Assert(pertrans->transtypeByVal);
    1672             : 
    1673     9786294 :             if (likely(!pergroup->transValueIsNull))
    1674     9746282 :                 ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    1675             :                                        op->d.agg_trans.aggcontext,
    1676             :                                        op->d.agg_trans.setno);
    1677             : 
    1678     9786294 :             EEO_NEXT();
    1679             :         }
    1680             : 
    1681             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    1682     5079888 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)
    1683             :         {
    1684     5079888 :             AggState   *aggstate = castNode(AggState, state->parent);
    1685     5079888 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1686     5079888 :             AggStatePerGroup pergroup =
    1687     5079888 :             &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1688             : 
    1689             :             Assert(pertrans->transtypeByVal);
    1690             : 
    1691     5079888 :             ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    1692             :                                    op->d.agg_trans.aggcontext,
    1693             :                                    op->d.agg_trans.setno);
    1694             : 
    1695     5079864 :             EEO_NEXT();
    1696             :         }
    1697             : 
    1698             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    1699       85168 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
    1700             :         {
    1701       85168 :             AggState   *aggstate = castNode(AggState, state->parent);
    1702       85168 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1703       85168 :             AggStatePerGroup pergroup =
    1704       85168 :             &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1705             : 
    1706             :             Assert(!pertrans->transtypeByVal);
    1707             : 
    1708       85168 :             if (pergroup->noTransValue)
    1709         302 :                 ExecAggInitGroup(aggstate, pertrans, pergroup,
    1710             :                                  op->d.agg_trans.aggcontext);
    1711       84866 :             else if (likely(!pergroup->transValueIsNull))
    1712       84866 :                 ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    1713             :                                        op->d.agg_trans.aggcontext,
    1714             :                                        op->d.agg_trans.setno);
    1715             : 
    1716       85164 :             EEO_NEXT();
    1717             :         }
    1718             : 
    1719             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    1720     1714036 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
    1721             :         {
    1722     1714036 :             AggState   *aggstate = castNode(AggState, state->parent);
    1723     1714036 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1724     1714036 :             AggStatePerGroup pergroup =
    1725     1714036 :             &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1726             : 
    1727             :             Assert(!pertrans->transtypeByVal);
    1728             : 
    1729     1714036 :             if (likely(!pergroup->transValueIsNull))
    1730     1714036 :                 ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    1731             :                                        op->d.agg_trans.aggcontext,
    1732             :                                        op->d.agg_trans.setno);
    1733     1714036 :             EEO_NEXT();
    1734             :         }
    1735             : 
    1736             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    1737       14080 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF)
    1738             :         {
    1739       14080 :             AggState   *aggstate = castNode(AggState, state->parent);
    1740       14080 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1741       14080 :             AggStatePerGroup pergroup =
    1742       14080 :             &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1743             : 
    1744             :             Assert(!pertrans->transtypeByVal);
    1745             : 
    1746       14080 :             ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    1747             :                                    op->d.agg_trans.aggcontext,
    1748             :                                    op->d.agg_trans.setno);
    1749             : 
    1750       14080 :             EEO_NEXT();
    1751             :         }
    1752             : 
    1753             :         /* process single-column ordered aggregate datum */
    1754      809636 :         EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM)
    1755             :         {
    1756             :             /* too complex for an inline implementation */
    1757      809636 :             ExecEvalAggOrderedTransDatum(state, op, econtext);
    1758             : 
    1759      809636 :             EEO_NEXT();
    1760             :         }
    1761             : 
    1762             :         /* process multi-column ordered aggregate tuple */
    1763       15328 :         EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE)
    1764             :         {
    1765             :             /* too complex for an inline implementation */
    1766       15328 :             ExecEvalAggOrderedTransTuple(state, op, econtext);
    1767             : 
    1768       15328 :             EEO_NEXT();
    1769             :         }
    1770             : 
    1771           0 :         EEO_CASE(EEOP_LAST)
    1772             :         {
    1773             :             /* unreachable */
    1774             :             Assert(false);
    1775           0 :             goto out;
    1776             :         }
    1777             :     }
    1778             : 
    1779   100459454 : out:
    1780   100459454 :     *isnull = state->resnull;
    1781   100459454 :     return state->resvalue;
    1782             : }
    1783             : 
    1784             : /*
    1785             :  * Expression evaluation callback that performs extra checks before executing
    1786             :  * the expression. Declared extern so other methods of execution can use it
    1787             :  * too.
    1788             :  */
    1789             : Datum
    1790      916470 : ExecInterpExprStillValid(ExprState *state, ExprContext *econtext, bool *isNull)
    1791             : {
    1792             :     /*
    1793             :      * First time through, check whether attribute matches Var.  Might not be
    1794             :      * ok anymore, due to schema changes.
    1795             :      */
    1796      916470 :     CheckExprStillValid(state, econtext);
    1797             : 
    1798             :     /* skip the check during further executions */
    1799      916454 :     state->evalfunc = (ExprStateEvalFunc) state->evalfunc_private;
    1800             : 
    1801             :     /* and actually execute */
    1802      916454 :     return state->evalfunc(state, econtext, isNull);
    1803             : }
    1804             : 
    1805             : /*
    1806             :  * Check that an expression is still valid in the face of potential schema
    1807             :  * changes since the plan has been created.
    1808             :  */
    1809             : void
    1810      919568 : CheckExprStillValid(ExprState *state, ExprContext *econtext)
    1811             : {
    1812             :     TupleTableSlot *innerslot;
    1813             :     TupleTableSlot *outerslot;
    1814             :     TupleTableSlot *scanslot;
    1815             : 
    1816      919568 :     innerslot = econtext->ecxt_innertuple;
    1817      919568 :     outerslot = econtext->ecxt_outertuple;
    1818      919568 :     scanslot = econtext->ecxt_scantuple;
    1819             : 
    1820     5392192 :     for (int i = 0; i < state->steps_len; i++)
    1821             :     {
    1822     4472640 :         ExprEvalStep *op = &state->steps[i];
    1823             : 
    1824     4472640 :         switch (ExecEvalStepOp(state, op))
    1825             :         {
    1826       63754 :             case EEOP_INNER_VAR:
    1827             :                 {
    1828       63754 :                     int         attnum = op->d.var.attnum;
    1829             : 
    1830       63754 :                     CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
    1831       63754 :                     break;
    1832             :                 }
    1833             : 
    1834      154724 :             case EEOP_OUTER_VAR:
    1835             :                 {
    1836      154724 :                     int         attnum = op->d.var.attnum;
    1837             : 
    1838      154724 :                     CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
    1839      154724 :                     break;
    1840             :                 }
    1841             : 
    1842      152832 :             case EEOP_SCAN_VAR:
    1843             :                 {
    1844      152832 :                     int         attnum = op->d.var.attnum;
    1845             : 
    1846      152832 :                     CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
    1847      152816 :                     break;
    1848             :                 }
    1849     4101330 :             default:
    1850     4101330 :                 break;
    1851             :         }
    1852             :     }
    1853      919552 : }
    1854             : 
    1855             : /*
    1856             :  * Check whether a user attribute in a slot can be referenced by a Var
    1857             :  * expression.  This should succeed unless there have been schema changes
    1858             :  * since the expression tree has been created.
    1859             :  */
    1860             : static void
    1861      371310 : CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
    1862             : {
    1863             :     /*
    1864             :      * What we have to check for here is the possibility of an attribute
    1865             :      * having been dropped or changed in type since the plan tree was created.
    1866             :      * Ideally the plan will get invalidated and not re-used, but just in
    1867             :      * case, we keep these defenses.  Fortunately it's sufficient to check
    1868             :      * once on the first time through.
    1869             :      *
    1870             :      * Note: ideally we'd check typmod as well as typid, but that seems
    1871             :      * impractical at the moment: in many cases the tupdesc will have been
    1872             :      * generated by ExecTypeFromTL(), and that can't guarantee to generate an
    1873             :      * accurate typmod in all cases, because some expression node types don't
    1874             :      * carry typmod.  Fortunately, for precisely that reason, there should be
    1875             :      * no places with a critical dependency on the typmod of a value.
    1876             :      *
    1877             :      * System attributes don't require checking since their types never
    1878             :      * change.
    1879             :      */
    1880      371310 :     if (attnum > 0)
    1881             :     {
    1882      371310 :         TupleDesc   slot_tupdesc = slot->tts_tupleDescriptor;
    1883             :         Form_pg_attribute attr;
    1884             : 
    1885      371310 :         if (attnum > slot_tupdesc->natts) /* should never happen */
    1886           0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    1887             :                  attnum, slot_tupdesc->natts);
    1888             : 
    1889      371310 :         attr = TupleDescAttr(slot_tupdesc, attnum - 1);
    1890             : 
    1891      371310 :         if (attr->attisdropped)
    1892           8 :             ereport(ERROR,
    1893             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    1894             :                      errmsg("attribute %d of type %s has been dropped",
    1895             :                             attnum, format_type_be(slot_tupdesc->tdtypeid))));
    1896             : 
    1897      371302 :         if (vartype != attr->atttypid)
    1898           8 :             ereport(ERROR,
    1899             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    1900             :                      errmsg("attribute %d of type %s has wrong type",
    1901             :                             attnum, format_type_be(slot_tupdesc->tdtypeid)),
    1902             :                      errdetail("Table has type %s, but query expects %s.",
    1903             :                                format_type_be(attr->atttypid),
    1904             :                                format_type_be(vartype))));
    1905             :     }
    1906      371294 : }
    1907             : 
    1908             : /*
    1909             :  * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
    1910             :  */
    1911             : static void
    1912   108246554 : CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot)
    1913             : {
    1914             : #ifdef USE_ASSERT_CHECKING
    1915             :     /* there's nothing to check */
    1916             :     if (!op->d.fetch.fixed)
    1917             :         return;
    1918             : 
    1919             :     /*
    1920             :      * Should probably fixed at some point, but for now it's easier to allow
    1921             :      * buffer and heap tuples to be used interchangeably.
    1922             :      */
    1923             :     if (slot->tts_ops == &TTSOpsBufferHeapTuple &&
    1924             :         op->d.fetch.kind == &TTSOpsHeapTuple)
    1925             :         return;
    1926             :     if (slot->tts_ops == &TTSOpsHeapTuple &&
    1927             :         op->d.fetch.kind == &TTSOpsBufferHeapTuple)
    1928             :         return;
    1929             : 
    1930             :     /*
    1931             :      * At the moment we consider it OK if a virtual slot is used instead of a
    1932             :      * specific type of slot, as a virtual slot never needs to be deformed.
    1933             :      */
    1934             :     if (slot->tts_ops == &TTSOpsVirtual)
    1935             :         return;
    1936             : 
    1937             :     Assert(op->d.fetch.kind == slot->tts_ops);
    1938             : #endif
    1939   108246554 : }
    1940             : 
    1941             : /*
    1942             :  * get_cached_rowtype: utility function to lookup a rowtype tupdesc
    1943             :  *
    1944             :  * type_id, typmod: identity of the rowtype
    1945             :  * cache_field: where to cache the TupleDesc pointer in expression state node
    1946             :  *      (field must be initialized to NULL)
    1947             :  * econtext: expression context we are executing in
    1948             :  *
    1949             :  * NOTE: because the shutdown callback will be called during plan rescan,
    1950             :  * must be prepared to re-do this during any node execution; cannot call
    1951             :  * just once during expression initialization.
    1952             :  */
    1953             : static TupleDesc
    1954       74288 : get_cached_rowtype(Oid type_id, int32 typmod,
    1955             :                    TupleDesc *cache_field, ExprContext *econtext)
    1956             : {
    1957       74288 :     TupleDesc   tupDesc = *cache_field;
    1958             : 
    1959             :     /* Do lookup if no cached value or if requested type changed */
    1960       74288 :     if (tupDesc == NULL ||
    1961       70142 :         type_id != tupDesc->tdtypeid ||
    1962       70142 :         typmod != tupDesc->tdtypmod)
    1963             :     {
    1964        4146 :         tupDesc = lookup_rowtype_tupdesc(type_id, typmod);
    1965             : 
    1966        4146 :         if (*cache_field)
    1967             :         {
    1968             :             /* Release old tupdesc; but callback is already registered */
    1969           0 :             ReleaseTupleDesc(*cache_field);
    1970             :         }
    1971             :         else
    1972             :         {
    1973             :             /* Need to register shutdown callback to release tupdesc */
    1974        4146 :             RegisterExprContextCallback(econtext,
    1975             :                                         ShutdownTupleDescRef,
    1976             :                                         PointerGetDatum(cache_field));
    1977             :         }
    1978        4146 :         *cache_field = tupDesc;
    1979             :     }
    1980       74288 :     return tupDesc;
    1981             : }
    1982             : 
    1983             : /*
    1984             :  * Callback function to release a tupdesc refcount at econtext shutdown
    1985             :  */
    1986             : static void
    1987        3872 : ShutdownTupleDescRef(Datum arg)
    1988             : {
    1989        3872 :     TupleDesc  *cache_field = (TupleDesc *) DatumGetPointer(arg);
    1990             : 
    1991        3872 :     if (*cache_field)
    1992        3872 :         ReleaseTupleDesc(*cache_field);
    1993        3872 :     *cache_field = NULL;
    1994        3872 : }
    1995             : 
    1996             : /*
    1997             :  * Fast-path functions, for very simple expressions
    1998             :  */
    1999             : 
    2000             : /* implementation of ExecJust(Inner|Outer|Scan)Var */
    2001             : static pg_attribute_always_inline Datum
    2002    12615890 : ExecJustVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2003             : {
    2004    12615890 :     ExprEvalStep *op = &state->steps[1];
    2005    12615890 :     int         attnum = op->d.var.attnum + 1;
    2006             : 
    2007    12615890 :     CheckOpSlotCompatibility(&state->steps[0], slot);
    2008             : 
    2009             :     /*
    2010             :      * Since we use slot_getattr(), we don't need to implement the FETCHSOME
    2011             :      * step explicitly, and we also needn't Assert that the attnum is in range
    2012             :      * --- slot_getattr() will take care of any problems.
    2013             :      */
    2014    12615890 :     return slot_getattr(slot, attnum, isnull);
    2015             : }
    2016             : 
    2017             : /* Simple reference to inner Var */
    2018             : static Datum
    2019     4025050 : ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2020             : {
    2021     4025050 :     return ExecJustVarImpl(state, econtext->ecxt_innertuple, isnull);
    2022             : }
    2023             : 
    2024             : /* Simple reference to outer Var */
    2025             : static Datum
    2026     8325288 : ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2027             : {
    2028     8325288 :     return ExecJustVarImpl(state, econtext->ecxt_outertuple, isnull);
    2029             : }
    2030             : 
    2031             : /* Simple reference to scan Var */
    2032             : static Datum
    2033      265552 : ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2034             : {
    2035      265552 :     return ExecJustVarImpl(state, econtext->ecxt_scantuple, isnull);
    2036             : }
    2037             : 
    2038             : /* implementation of ExecJustAssign(Inner|Outer|Scan)Var */
    2039             : static pg_attribute_always_inline Datum
    2040     7142882 : ExecJustAssignVarImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
    2041             : {
    2042     7142882 :     ExprEvalStep *op = &state->steps[1];
    2043     7142882 :     int         attnum = op->d.assign_var.attnum + 1;
    2044     7142882 :     int         resultnum = op->d.assign_var.resultnum;
    2045     7142882 :     TupleTableSlot *outslot = state->resultslot;
    2046             : 
    2047     7142882 :     CheckOpSlotCompatibility(&state->steps[0], inslot);
    2048             : 
    2049             :     /*
    2050             :      * We do not need CheckVarSlotCompatibility here; that was taken care of
    2051             :      * at compilation time.
    2052             :      *
    2053             :      * Since we use slot_getattr(), we don't need to implement the FETCHSOME
    2054             :      * step explicitly, and we also needn't Assert that the attnum is in range
    2055             :      * --- slot_getattr() will take care of any problems.
    2056             :      */
    2057    14285764 :     outslot->tts_values[resultnum] =
    2058     7142882 :         slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
    2059     7142882 :     return 0;
    2060             : }
    2061             : 
    2062             : /* Evaluate inner Var and assign to appropriate column of result tuple */
    2063             : static Datum
    2064        4602 : ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2065             : {
    2066        4602 :     return ExecJustAssignVarImpl(state, econtext->ecxt_innertuple, isnull);
    2067             : }
    2068             : 
    2069             : /* Evaluate outer Var and assign to appropriate column of result tuple */
    2070             : static Datum
    2071      263166 : ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2072             : {
    2073      263166 :     return ExecJustAssignVarImpl(state, econtext->ecxt_outertuple, isnull);
    2074             : }
    2075             : 
    2076             : /* Evaluate scan Var and assign to appropriate column of result tuple */
    2077             : static Datum
    2078     6875114 : ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2079             : {
    2080     6875114 :     return ExecJustAssignVarImpl(state, econtext->ecxt_scantuple, isnull);
    2081             : }
    2082             : 
    2083             : /* Evaluate CASE_TESTVAL and apply a strict function to it */
    2084             : static Datum
    2085        2350 : ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
    2086             : {
    2087        2350 :     ExprEvalStep *op = &state->steps[0];
    2088             :     FunctionCallInfo fcinfo;
    2089             :     NullableDatum *args;
    2090             :     int         nargs;
    2091             :     Datum       d;
    2092             : 
    2093             :     /*
    2094             :      * XXX with some redesign of the CaseTestExpr mechanism, maybe we could
    2095             :      * get rid of this data shuffling?
    2096             :      */
    2097        2350 :     *op->resvalue = *op->d.casetest.value;
    2098        2350 :     *op->resnull = *op->d.casetest.isnull;
    2099             : 
    2100        2350 :     op++;
    2101             : 
    2102        2350 :     nargs = op->d.func.nargs;
    2103        2350 :     fcinfo = op->d.func.fcinfo_data;
    2104        2350 :     args = fcinfo->args;
    2105             : 
    2106             :     /* strict function, so check for NULL args */
    2107        4908 :     for (int argno = 0; argno < nargs; argno++)
    2108             :     {
    2109        2566 :         if (args[argno].isnull)
    2110             :         {
    2111           8 :             *isnull = true;
    2112           8 :             return (Datum) 0;
    2113             :         }
    2114             :     }
    2115        2342 :     fcinfo->isnull = false;
    2116        2342 :     d = op->d.func.fn_addr(fcinfo);
    2117        2330 :     *isnull = fcinfo->isnull;
    2118        2330 :     return d;
    2119             : }
    2120             : 
    2121             : /* Simple Const expression */
    2122             : static Datum
    2123     1169554 : ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
    2124             : {
    2125     1169554 :     ExprEvalStep *op = &state->steps[0];
    2126             : 
    2127     1169554 :     *isnull = op->d.constval.isnull;
    2128     1169554 :     return op->d.constval.value;
    2129             : }
    2130             : 
    2131             : /* implementation of ExecJust(Inner|Outer|Scan)VarVirt */
    2132             : static pg_attribute_always_inline Datum
    2133    10382230 : ExecJustVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2134             : {
    2135    10382230 :     ExprEvalStep *op = &state->steps[0];
    2136    10382230 :     int         attnum = op->d.var.attnum;
    2137             : 
    2138             :     /*
    2139             :      * As it is guaranteed that a virtual slot is used, there never is a need
    2140             :      * to perform tuple deforming (nor would it be possible). Therefore
    2141             :      * execExpr.c has not emitted an EEOP_*_FETCHSOME step. Verify, as much as
    2142             :      * possible, that that determination was accurate.
    2143             :      */
    2144             :     Assert(TTS_IS_VIRTUAL(slot));
    2145             :     Assert(TTS_FIXED(slot));
    2146             :     Assert(attnum >= 0 && attnum < slot->tts_nvalid);
    2147             : 
    2148    10382230 :     *isnull = slot->tts_isnull[attnum];
    2149             : 
    2150    10382230 :     return slot->tts_values[attnum];
    2151             : }
    2152             : 
    2153             : /* Like ExecJustInnerVar, optimized for virtual slots */
    2154             : static Datum
    2155      381592 : ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2156             : {
    2157      381592 :     return ExecJustVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2158             : }
    2159             : 
    2160             : /* Like ExecJustOuterVar, optimized for virtual slots */
    2161             : static Datum
    2162    10000514 : ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2163             : {
    2164    10000514 :     return ExecJustVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
    2165             : }
    2166             : 
    2167             : /* Like ExecJustScanVar, optimized for virtual slots */
    2168             : static Datum
    2169         124 : ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2170             : {
    2171         124 :     return ExecJustVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
    2172             : }
    2173             : 
    2174             : /* implementation of ExecJustAssign(Inner|Outer|Scan)VarVirt */
    2175             : static pg_attribute_always_inline Datum
    2176      491382 : ExecJustAssignVarVirtImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
    2177             : {
    2178      491382 :     ExprEvalStep *op = &state->steps[0];
    2179      491382 :     int         attnum = op->d.assign_var.attnum;
    2180      491382 :     int         resultnum = op->d.assign_var.resultnum;
    2181      491382 :     TupleTableSlot *outslot = state->resultslot;
    2182             : 
    2183             :     /* see ExecJustVarVirtImpl for comments */
    2184             : 
    2185             :     Assert(TTS_IS_VIRTUAL(inslot));
    2186             :     Assert(TTS_FIXED(inslot));
    2187             :     Assert(attnum >= 0 && attnum < inslot->tts_nvalid);
    2188             : 
    2189      491382 :     outslot->tts_values[resultnum] = inslot->tts_values[attnum];
    2190      491382 :     outslot->tts_isnull[resultnum] = inslot->tts_isnull[attnum];
    2191             : 
    2192      491382 :     return 0;
    2193             : }
    2194             : 
    2195             : /* Like ExecJustAssignInnerVar, optimized for virtual slots */
    2196             : static Datum
    2197       80752 : ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2198             : {
    2199       80752 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2200             : }
    2201             : 
    2202             : /* Like ExecJustAssignOuterVar, optimized for virtual slots */
    2203             : static Datum
    2204      287234 : ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2205             : {
    2206      287234 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
    2207             : }
    2208             : 
    2209             : /* Like ExecJustAssignScanVar, optimized for virtual slots */
    2210             : static Datum
    2211      123396 : ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2212             : {
    2213      123396 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
    2214             : }
    2215             : 
    2216             : #if defined(EEO_USE_COMPUTED_GOTO)
    2217             : /*
    2218             :  * Comparator used when building address->opcode lookup table for
    2219             :  * ExecEvalStepOp() in the threaded dispatch case.
    2220             :  */
    2221             : static int
    2222    28297436 : dispatch_compare_ptr(const void *a, const void *b)
    2223             : {
    2224    28297436 :     const ExprEvalOpLookup *la = (const ExprEvalOpLookup *) a;
    2225    28297436 :     const ExprEvalOpLookup *lb = (const ExprEvalOpLookup *) b;
    2226             : 
    2227    28297436 :     if (la->opcode < lb->opcode)
    2228    18025310 :         return -1;
    2229    10272126 :     else if (la->opcode > lb->opcode)
    2230     6324752 :         return 1;
    2231     3947374 :     return 0;
    2232             : }
    2233             : #endif
    2234             : 
    2235             : /*
    2236             :  * Do one-time initialization of interpretation machinery.
    2237             :  */
    2238             : static void
    2239     1263548 : ExecInitInterpreter(void)
    2240             : {
    2241             : #if defined(EEO_USE_COMPUTED_GOTO)
    2242             :     /* Set up externally-visible pointer to dispatch table */
    2243     1263548 :     if (dispatch_table == NULL)
    2244             :     {
    2245        6884 :         dispatch_table = (const void **)
    2246        6884 :             DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
    2247             : 
    2248             :         /* build reverse lookup table */
    2249      626444 :         for (int i = 0; i < EEOP_LAST; i++)
    2250             :         {
    2251      619560 :             reverse_dispatch_table[i].opcode = dispatch_table[i];
    2252      619560 :             reverse_dispatch_table[i].op = (ExprEvalOp) i;
    2253             :         }
    2254             : 
    2255             :         /* make it bsearch()able */
    2256        6884 :         qsort(reverse_dispatch_table,
    2257             :               EEOP_LAST /* nmembers */ ,
    2258             :               sizeof(ExprEvalOpLookup),
    2259             :               dispatch_compare_ptr);
    2260             :     }
    2261             : #endif
    2262     1263548 : }
    2263             : 
    2264             : /*
    2265             :  * Function to return the opcode of an expression step.
    2266             :  *
    2267             :  * When direct-threading is in use, ExprState->opcode isn't easily
    2268             :  * decipherable. This function returns the appropriate enum member.
    2269             :  */
    2270             : ExprEvalOp
    2271     4495730 : ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
    2272             : {
    2273             : #if defined(EEO_USE_COMPUTED_GOTO)
    2274     4495730 :     if (state->flags & EEO_FLAG_DIRECT_THREADED)
    2275             :     {
    2276             :         ExprEvalOpLookup key;
    2277             :         ExprEvalOpLookup *res;
    2278             : 
    2279     3947374 :         key.opcode = (void *) op->opcode;
    2280     3947374 :         res = bsearch(&key,
    2281             :                       reverse_dispatch_table,
    2282             :                       EEOP_LAST /* nmembers */ ,
    2283             :                       sizeof(ExprEvalOpLookup),
    2284             :                       dispatch_compare_ptr);
    2285             :         Assert(res);            /* unknown ops shouldn't get looked up */
    2286     3947374 :         return res->op;
    2287             :     }
    2288             : #endif
    2289      548356 :     return (ExprEvalOp) op->opcode;
    2290             : }
    2291             : 
    2292             : 
    2293             : /*
    2294             :  * Out-of-line helper functions for complex instructions.
    2295             :  */
    2296             : 
    2297             : /*
    2298             :  * Evaluate EEOP_FUNCEXPR_FUSAGE
    2299             :  */
    2300             : void
    2301           0 : ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op,
    2302             :                        ExprContext *econtext)
    2303             : {
    2304           0 :     FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    2305             :     PgStat_FunctionCallUsage fcusage;
    2306             :     Datum       d;
    2307             : 
    2308           0 :     pgstat_init_function_usage(fcinfo, &fcusage);
    2309             : 
    2310           0 :     fcinfo->isnull = false;
    2311           0 :     d = op->d.func.fn_addr(fcinfo);
    2312           0 :     *op->resvalue = d;
    2313           0 :     *op->resnull = fcinfo->isnull;
    2314             : 
    2315           0 :     pgstat_end_function_usage(&fcusage, true);
    2316           0 : }
    2317             : 
    2318             : /*
    2319             :  * Evaluate EEOP_FUNCEXPR_STRICT_FUSAGE
    2320             :  */
    2321             : void
    2322           0 : ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
    2323             :                              ExprContext *econtext)
    2324             : {
    2325             : 
    2326           0 :     FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    2327             :     PgStat_FunctionCallUsage fcusage;
    2328           0 :     NullableDatum *args = fcinfo->args;
    2329           0 :     int         nargs = op->d.func.nargs;
    2330             :     Datum       d;
    2331             : 
    2332             :     /* strict function, so check for NULL args */
    2333           0 :     for (int argno = 0; argno < nargs; argno++)
    2334             :     {
    2335           0 :         if (args[argno].isnull)
    2336             :         {
    2337           0 :             *op->resnull = true;
    2338           0 :             return;
    2339             :         }
    2340             :     }
    2341             : 
    2342           0 :     pgstat_init_function_usage(fcinfo, &fcusage);
    2343             : 
    2344           0 :     fcinfo->isnull = false;
    2345           0 :     d = op->d.func.fn_addr(fcinfo);
    2346           0 :     *op->resvalue = d;
    2347           0 :     *op->resnull = fcinfo->isnull;
    2348             : 
    2349           0 :     pgstat_end_function_usage(&fcusage, true);
    2350             : }
    2351             : 
    2352             : /*
    2353             :  * Evaluate a PARAM_EXEC parameter.
    2354             :  *
    2355             :  * PARAM_EXEC params (internal executor parameters) are stored in the
    2356             :  * ecxt_param_exec_vals array, and can be accessed by array index.
    2357             :  */
    2358             : void
    2359    14470544 : ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2360             : {
    2361             :     ParamExecData *prm;
    2362             : 
    2363    14470544 :     prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
    2364    14470544 :     if (unlikely(prm->execPlan != NULL))
    2365             :     {
    2366             :         /* Parameter not evaluated yet, so go do it */
    2367       10524 :         ExecSetParamPlan(prm->execPlan, econtext);
    2368             :         /* ExecSetParamPlan should have processed this param... */
    2369             :         Assert(prm->execPlan == NULL);
    2370             :     }
    2371    14470534 :     *op->resvalue = prm->value;
    2372    14470534 :     *op->resnull = prm->isnull;
    2373    14470534 : }
    2374             : 
    2375             : /*
    2376             :  * Evaluate a PARAM_EXTERN parameter.
    2377             :  *
    2378             :  * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
    2379             :  */
    2380             : void
    2381      142448 : ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2382             : {
    2383      142448 :     ParamListInfo paramInfo = econtext->ecxt_param_list_info;
    2384      142448 :     int         paramId = op->d.param.paramid;
    2385             : 
    2386      142448 :     if (likely(paramInfo &&
    2387             :                paramId > 0 && paramId <= paramInfo->numParams))
    2388             :     {
    2389             :         ParamExternData *prm;
    2390             :         ParamExternData prmdata;
    2391             : 
    2392             :         /* give hook a chance in case parameter is dynamic */
    2393      142448 :         if (paramInfo->paramFetch != NULL)
    2394         132 :             prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata);
    2395             :         else
    2396      142316 :             prm = &paramInfo->params[paramId - 1];
    2397             : 
    2398      142448 :         if (likely(OidIsValid(prm->ptype)))
    2399             :         {
    2400             :             /* safety check in case hook did something unexpected */
    2401      142448 :             if (unlikely(prm->ptype != op->d.param.paramtype))
    2402           0 :                 ereport(ERROR,
    2403             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    2404             :                          errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    2405             :                                 paramId,
    2406             :                                 format_type_be(prm->ptype),
    2407             :                                 format_type_be(op->d.param.paramtype))));
    2408      142448 :             *op->resvalue = prm->value;
    2409      142448 :             *op->resnull = prm->isnull;
    2410      142448 :             return;
    2411             :         }
    2412             :     }
    2413             : 
    2414           0 :     ereport(ERROR,
    2415             :             (errcode(ERRCODE_UNDEFINED_OBJECT),
    2416             :              errmsg("no value found for parameter %d", paramId)));
    2417             : }
    2418             : 
    2419             : /*
    2420             :  * Evaluate a SQLValueFunction expression.
    2421             :  */
    2422             : void
    2423        4364 : ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
    2424             : {
    2425        4364 :     LOCAL_FCINFO(fcinfo, 0);
    2426        4364 :     SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
    2427             : 
    2428        4364 :     *op->resnull = false;
    2429             : 
    2430             :     /*
    2431             :      * Note: current_schema() can return NULL.  current_user() etc currently
    2432             :      * cannot, but might as well code those cases the same way for safety.
    2433             :      */
    2434        4364 :     switch (svf->op)
    2435             :     {
    2436          18 :         case SVFOP_CURRENT_DATE:
    2437          18 :             *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
    2438          18 :             break;
    2439           8 :         case SVFOP_CURRENT_TIME:
    2440             :         case SVFOP_CURRENT_TIME_N:
    2441           8 :             *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
    2442           8 :             break;
    2443         252 :         case SVFOP_CURRENT_TIMESTAMP:
    2444             :         case SVFOP_CURRENT_TIMESTAMP_N:
    2445         252 :             *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
    2446         252 :             break;
    2447           8 :         case SVFOP_LOCALTIME:
    2448             :         case SVFOP_LOCALTIME_N:
    2449           8 :             *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
    2450           8 :             break;
    2451          36 :         case SVFOP_LOCALTIMESTAMP:
    2452             :         case SVFOP_LOCALTIMESTAMP_N:
    2453          36 :             *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
    2454          36 :             break;
    2455        3974 :         case SVFOP_CURRENT_ROLE:
    2456             :         case SVFOP_CURRENT_USER:
    2457             :         case SVFOP_USER:
    2458        3974 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    2459        3974 :             *op->resvalue = current_user(fcinfo);
    2460        3974 :             *op->resnull = fcinfo->isnull;
    2461        3974 :             break;
    2462          52 :         case SVFOP_SESSION_USER:
    2463          52 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    2464          52 :             *op->resvalue = session_user(fcinfo);
    2465          52 :             *op->resnull = fcinfo->isnull;
    2466          52 :             break;
    2467           4 :         case SVFOP_CURRENT_CATALOG:
    2468           4 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    2469           4 :             *op->resvalue = current_database(fcinfo);
    2470           4 :             *op->resnull = fcinfo->isnull;
    2471           4 :             break;
    2472          12 :         case SVFOP_CURRENT_SCHEMA:
    2473          12 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    2474          12 :             *op->resvalue = current_schema(fcinfo);
    2475          12 :             *op->resnull = fcinfo->isnull;
    2476          12 :             break;
    2477             :     }
    2478        4364 : }
    2479             : 
    2480             : /*
    2481             :  * Raise error if a CURRENT OF expression is evaluated.
    2482             :  *
    2483             :  * The planner should convert CURRENT OF into a TidScan qualification, or some
    2484             :  * other special handling in a ForeignScan node.  So we have to be able to do
    2485             :  * ExecInitExpr on a CurrentOfExpr, but we shouldn't ever actually execute it.
    2486             :  * If we get here, we suppose we must be dealing with CURRENT OF on a foreign
    2487             :  * table whose FDW doesn't handle it, and complain accordingly.
    2488             :  */
    2489             : void
    2490           2 : ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
    2491             : {
    2492           2 :     ereport(ERROR,
    2493             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2494             :              errmsg("WHERE CURRENT OF is not supported for this table type")));
    2495             : }
    2496             : 
    2497             : /*
    2498             :  * Evaluate NextValueExpr.
    2499             :  */
    2500             : void
    2501         224 : ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
    2502             : {
    2503         224 :     int64       newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
    2504             : 
    2505         224 :     switch (op->d.nextvalueexpr.seqtypid)
    2506             :     {
    2507          20 :         case INT2OID:
    2508          20 :             *op->resvalue = Int16GetDatum((int16) newval);
    2509          20 :             break;
    2510         172 :         case INT4OID:
    2511         172 :             *op->resvalue = Int32GetDatum((int32) newval);
    2512         172 :             break;
    2513          32 :         case INT8OID:
    2514          32 :             *op->resvalue = Int64GetDatum((int64) newval);
    2515          32 :             break;
    2516           0 :         default:
    2517           0 :             elog(ERROR, "unsupported sequence type %u",
    2518             :                  op->d.nextvalueexpr.seqtypid);
    2519             :     }
    2520         224 :     *op->resnull = false;
    2521         224 : }
    2522             : 
    2523             : /*
    2524             :  * Evaluate NullTest / IS NULL for rows.
    2525             :  */
    2526             : void
    2527         388 : ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2528             : {
    2529         388 :     ExecEvalRowNullInt(state, op, econtext, true);
    2530         388 : }
    2531             : 
    2532             : /*
    2533             :  * Evaluate NullTest / IS NOT NULL for rows.
    2534             :  */
    2535             : void
    2536         216 : ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2537             : {
    2538         216 :     ExecEvalRowNullInt(state, op, econtext, false);
    2539         216 : }
    2540             : 
    2541             : /* Common code for IS [NOT] NULL on a row value */
    2542             : static void
    2543         604 : ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
    2544             :                    ExprContext *econtext, bool checkisnull)
    2545             : {
    2546         604 :     Datum       value = *op->resvalue;
    2547         604 :     bool        isnull = *op->resnull;
    2548             :     HeapTupleHeader tuple;
    2549             :     Oid         tupType;
    2550             :     int32       tupTypmod;
    2551             :     TupleDesc   tupDesc;
    2552             :     HeapTupleData tmptup;
    2553             : 
    2554         604 :     *op->resnull = false;
    2555             : 
    2556             :     /* NULL row variables are treated just as NULL scalar columns */
    2557         604 :     if (isnull)
    2558             :     {
    2559          78 :         *op->resvalue = BoolGetDatum(checkisnull);
    2560         404 :         return;
    2561             :     }
    2562             : 
    2563             :     /*
    2564             :      * The SQL standard defines IS [NOT] NULL for a non-null rowtype argument
    2565             :      * as:
    2566             :      *
    2567             :      * "R IS NULL" is true if every field is the null value.
    2568             :      *
    2569             :      * "R IS NOT NULL" is true if no field is the null value.
    2570             :      *
    2571             :      * This definition is (apparently intentionally) not recursive; so our
    2572             :      * tests on the fields are primitive attisnull tests, not recursive checks
    2573             :      * to see if they are all-nulls or no-nulls rowtypes.
    2574             :      *
    2575             :      * The standard does not consider the possibility of zero-field rows, but
    2576             :      * here we consider them to vacuously satisfy both predicates.
    2577             :      */
    2578             : 
    2579         526 :     tuple = DatumGetHeapTupleHeader(value);
    2580             : 
    2581         526 :     tupType = HeapTupleHeaderGetTypeId(tuple);
    2582         526 :     tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    2583             : 
    2584             :     /* Lookup tupdesc if first time through or if type changes */
    2585         526 :     tupDesc = get_cached_rowtype(tupType, tupTypmod,
    2586             :                                  &op->d.nulltest_row.argdesc,
    2587             :                                  econtext);
    2588             : 
    2589             :     /*
    2590             :      * heap_attisnull needs a HeapTuple not a bare HeapTupleHeader.
    2591             :      */
    2592         526 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    2593         526 :     tmptup.t_data = tuple;
    2594             : 
    2595         962 :     for (int att = 1; att <= tupDesc->natts; att++)
    2596             :     {
    2597             :         /* ignore dropped columns */
    2598         762 :         if (TupleDescAttr(tupDesc, att - 1)->attisdropped)
    2599           0 :             continue;
    2600         762 :         if (heap_attisnull(&tmptup, att, tupDesc))
    2601             :         {
    2602             :             /* null field disproves IS NOT NULL */
    2603          40 :             if (!checkisnull)
    2604             :             {
    2605          24 :                 *op->resvalue = BoolGetDatum(false);
    2606          24 :                 return;
    2607             :             }
    2608             :         }
    2609             :         else
    2610             :         {
    2611             :             /* non-null field disproves IS NULL */
    2612         722 :             if (checkisnull)
    2613             :             {
    2614         302 :                 *op->resvalue = BoolGetDatum(false);
    2615         302 :                 return;
    2616             :             }
    2617             :         }
    2618             :     }
    2619             : 
    2620         200 :     *op->resvalue = BoolGetDatum(true);
    2621             : }
    2622             : 
    2623             : /*
    2624             :  * Evaluate an ARRAY[] expression.
    2625             :  *
    2626             :  * The individual array elements (or subarrays) have already been evaluated
    2627             :  * into op->d.arrayexpr.elemvalues[]/elemnulls[].
    2628             :  */
    2629             : void
    2630      263194 : ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
    2631             : {
    2632             :     ArrayType  *result;
    2633      263194 :     Oid         element_type = op->d.arrayexpr.elemtype;
    2634      263194 :     int         nelems = op->d.arrayexpr.nelems;
    2635      263194 :     int         ndims = 0;
    2636             :     int         dims[MAXDIM];
    2637             :     int         lbs[MAXDIM];
    2638             : 
    2639             :     /* Set non-null as default */
    2640      263194 :     *op->resnull = false;
    2641             : 
    2642      263194 :     if (!op->d.arrayexpr.multidims)
    2643             :     {
    2644             :         /* Elements are presumably of scalar type */
    2645      262842 :         Datum      *dvalues = op->d.arrayexpr.elemvalues;
    2646      262842 :         bool       *dnulls = op->d.arrayexpr.elemnulls;
    2647             : 
    2648             :         /* setup for 1-D array of the given length */
    2649      262842 :         ndims = 1;
    2650      262842 :         dims[0] = nelems;
    2651      262842 :         lbs[0] = 1;
    2652             : 
    2653      788526 :         result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
    2654             :                                     element_type,
    2655      262842 :                                     op->d.arrayexpr.elemlength,
    2656      262842 :                                     op->d.arrayexpr.elembyval,
    2657      262842 :                                     op->d.arrayexpr.elemalign);
    2658             :     }
    2659             :     else
    2660             :     {
    2661             :         /* Must be nested array expressions */
    2662         352 :         int         nbytes = 0;
    2663         352 :         int         nitems = 0;
    2664         352 :         int         outer_nelems = 0;
    2665         352 :         int         elem_ndims = 0;
    2666         352 :         int        *elem_dims = NULL;
    2667         352 :         int        *elem_lbs = NULL;
    2668         352 :         bool        firstone = true;
    2669         352 :         bool        havenulls = false;
    2670         352 :         bool        haveempty = false;
    2671             :         char      **subdata;
    2672             :         bits8     **subbitmaps;
    2673             :         int        *subbytes;
    2674             :         int        *subnitems;
    2675             :         int32       dataoffset;
    2676             :         char       *dat;
    2677             :         int         iitem;
    2678             : 
    2679         352 :         subdata = (char **) palloc(nelems * sizeof(char *));
    2680         352 :         subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *));
    2681         352 :         subbytes = (int *) palloc(nelems * sizeof(int));
    2682         352 :         subnitems = (int *) palloc(nelems * sizeof(int));
    2683             : 
    2684             :         /* loop through and get data area from each element */
    2685         992 :         for (int elemoff = 0; elemoff < nelems; elemoff++)
    2686             :         {
    2687             :             Datum       arraydatum;
    2688             :             bool        eisnull;
    2689             :             ArrayType  *array;
    2690             :             int         this_ndims;
    2691             : 
    2692         640 :             arraydatum = op->d.arrayexpr.elemvalues[elemoff];
    2693         640 :             eisnull = op->d.arrayexpr.elemnulls[elemoff];
    2694             : 
    2695             :             /* temporarily ignore null subarrays */
    2696         640 :             if (eisnull)
    2697             :             {
    2698           0 :                 haveempty = true;
    2699           0 :                 continue;
    2700             :             }
    2701             : 
    2702         640 :             array = DatumGetArrayTypeP(arraydatum);
    2703             : 
    2704             :             /* run-time double-check on element type */
    2705         640 :             if (element_type != ARR_ELEMTYPE(array))
    2706           0 :                 ereport(ERROR,
    2707             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    2708             :                          errmsg("cannot merge incompatible arrays"),
    2709             :                          errdetail("Array with element type %s cannot be "
    2710             :                                    "included in ARRAY construct with element type %s.",
    2711             :                                    format_type_be(ARR_ELEMTYPE(array)),
    2712             :                                    format_type_be(element_type))));
    2713             : 
    2714         640 :             this_ndims = ARR_NDIM(array);
    2715             :             /* temporarily ignore zero-dimensional subarrays */
    2716         640 :             if (this_ndims <= 0)
    2717             :             {
    2718           0 :                 haveempty = true;
    2719           0 :                 continue;
    2720             :             }
    2721             : 
    2722         640 :             if (firstone)
    2723             :             {
    2724             :                 /* Get sub-array details from first member */
    2725         352 :                 elem_ndims = this_ndims;
    2726         352 :                 ndims = elem_ndims + 1;
    2727         352 :                 if (ndims <= 0 || ndims > MAXDIM)
    2728           0 :                     ereport(ERROR,
    2729             :                             (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2730             :                              errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
    2731             :                                     ndims, MAXDIM)));
    2732             : 
    2733         352 :                 elem_dims = (int *) palloc(elem_ndims * sizeof(int));
    2734         352 :                 memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
    2735         352 :                 elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
    2736         352 :                 memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
    2737             : 
    2738         352 :                 firstone = false;
    2739             :             }
    2740             :             else
    2741             :             {
    2742             :                 /* Check other sub-arrays are compatible */
    2743         288 :                 if (elem_ndims != this_ndims ||
    2744         288 :                     memcmp(elem_dims, ARR_DIMS(array),
    2745         288 :                            elem_ndims * sizeof(int)) != 0 ||
    2746         288 :                     memcmp(elem_lbs, ARR_LBOUND(array),
    2747             :                            elem_ndims * sizeof(int)) != 0)
    2748           0 :                     ereport(ERROR,
    2749             :                             (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2750             :                              errmsg("multidimensional arrays must have array "
    2751             :                                     "expressions with matching dimensions")));
    2752             :             }
    2753             : 
    2754         640 :             subdata[outer_nelems] = ARR_DATA_PTR(array);
    2755         640 :             subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
    2756         640 :             subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
    2757         640 :             nbytes += subbytes[outer_nelems];
    2758         640 :             subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
    2759             :                                                      ARR_DIMS(array));
    2760         640 :             nitems += subnitems[outer_nelems];
    2761         640 :             havenulls |= ARR_HASNULL(array);
    2762         640 :             outer_nelems++;
    2763             :         }
    2764             : 
    2765             :         /*
    2766             :          * If all items were null or empty arrays, return an empty array;
    2767             :          * otherwise, if some were and some weren't, raise error.  (Note: we
    2768             :          * must special-case this somehow to avoid trying to generate a 1-D
    2769             :          * array formed from empty arrays.  It's not ideal...)
    2770             :          */
    2771         352 :         if (haveempty)
    2772             :         {
    2773           0 :             if (ndims == 0)     /* didn't find any nonempty array */
    2774             :             {
    2775           0 :                 *op->resvalue = PointerGetDatum(construct_empty_array(element_type));
    2776           0 :                 return;
    2777             :             }
    2778           0 :             ereport(ERROR,
    2779             :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2780             :                      errmsg("multidimensional arrays must have array "
    2781             :                             "expressions with matching dimensions")));
    2782             :         }
    2783             : 
    2784             :         /* setup for multi-D array */
    2785         352 :         dims[0] = outer_nelems;
    2786         352 :         lbs[0] = 1;
    2787         880 :         for (int i = 1; i < ndims; i++)
    2788             :         {
    2789         528 :             dims[i] = elem_dims[i - 1];
    2790         528 :             lbs[i] = elem_lbs[i - 1];
    2791             :         }
    2792             : 
    2793         352 :         if (havenulls)
    2794             :         {
    2795          28 :             dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
    2796          28 :             nbytes += dataoffset;
    2797             :         }
    2798             :         else
    2799             :         {
    2800         324 :             dataoffset = 0;     /* marker for no null bitmap */
    2801         324 :             nbytes += ARR_OVERHEAD_NONULLS(ndims);
    2802             :         }
    2803             : 
    2804         352 :         result = (ArrayType *) palloc(nbytes);
    2805         352 :         SET_VARSIZE(result, nbytes);
    2806         352 :         result->ndim = ndims;
    2807         352 :         result->dataoffset = dataoffset;
    2808         352 :         result->elemtype = element_type;
    2809         352 :         memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
    2810         352 :         memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
    2811             : 
    2812         352 :         dat = ARR_DATA_PTR(result);
    2813         352 :         iitem = 0;
    2814         992 :         for (int i = 0; i < outer_nelems; i++)
    2815             :         {
    2816         640 :             memcpy(dat, subdata[i], subbytes[i]);
    2817         640 :             dat += subbytes[i];
    2818         640 :             if (havenulls)
    2819          56 :                 array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
    2820          56 :                                   subbitmaps[i], 0,
    2821          56 :                                   subnitems[i]);
    2822         640 :             iitem += subnitems[i];
    2823             :         }
    2824             :     }
    2825             : 
    2826      263194 :     *op->resvalue = PointerGetDatum(result);
    2827             : }
    2828             : 
    2829             : /*
    2830             :  * Evaluate an ArrayCoerceExpr expression.
    2831             :  *
    2832             :  * Source array is in step's result variable.
    2833             :  */
    2834             : void
    2835       38874 : ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2836             : {
    2837             :     Datum       arraydatum;
    2838             : 
    2839             :     /* NULL array -> NULL result */
    2840       38874 :     if (*op->resnull)
    2841          46 :         return;
    2842             : 
    2843       38828 :     arraydatum = *op->resvalue;
    2844             : 
    2845             :     /*
    2846             :      * If it's binary-compatible, modify the element type in the array header,
    2847             :      * but otherwise leave the array as we received it.
    2848             :      */
    2849       38828 :     if (op->d.arraycoerce.elemexprstate == NULL)
    2850             :     {
    2851             :         /* Detoast input array if necessary, and copy in any case */
    2852       38582 :         ArrayType  *array = DatumGetArrayTypePCopy(arraydatum);
    2853             : 
    2854       38582 :         ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
    2855       38582 :         *op->resvalue = PointerGetDatum(array);
    2856       38582 :         return;
    2857             :     }
    2858             : 
    2859             :     /*
    2860             :      * Use array_map to apply the sub-expression to each array element.
    2861             :      */
    2862         228 :     *op->resvalue = array_map(arraydatum,
    2863         246 :                               op->d.arraycoerce.elemexprstate,
    2864             :                               econtext,
    2865             :                               op->d.arraycoerce.resultelemtype,
    2866         246 :                               op->d.arraycoerce.amstate);
    2867             : }
    2868             : 
    2869             : /*
    2870             :  * Evaluate a ROW() expression.
    2871             :  *
    2872             :  * The individual columns have already been evaluated into
    2873             :  * op->d.row.elemvalues[]/elemnulls[].
    2874             :  */
    2875             : void
    2876       20888 : ExecEvalRow(ExprState *state, ExprEvalStep *op)
    2877             : {
    2878             :     HeapTuple   tuple;
    2879             : 
    2880             :     /* build tuple from evaluated field values */
    2881       20888 :     tuple = heap_form_tuple(op->d.row.tupdesc,
    2882             :                             op->d.row.elemvalues,
    2883             :                             op->d.row.elemnulls);
    2884             : 
    2885       20888 :     *op->resvalue = HeapTupleGetDatum(tuple);
    2886       20888 :     *op->resnull = false;
    2887       20888 : }
    2888             : 
    2889             : /*
    2890             :  * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()).
    2891             :  *
    2892             :  * All of the to-be-compared expressions have already been evaluated into
    2893             :  * op->d.minmax.values[]/nulls[].
    2894             :  */
    2895             : void
    2896        2668 : ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
    2897             : {
    2898        2668 :     Datum      *values = op->d.minmax.values;
    2899        2668 :     bool       *nulls = op->d.minmax.nulls;
    2900        2668 :     FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
    2901        2668 :     MinMaxOp    operator = op->d.minmax.op;
    2902             : 
    2903             :     /* set at initialization */
    2904             :     Assert(fcinfo->args[0].isnull == false);
    2905             :     Assert(fcinfo->args[1].isnull == false);
    2906             : 
    2907             :     /* default to null result */
    2908        2668 :     *op->resnull = true;
    2909             : 
    2910        8200 :     for (int off = 0; off < op->d.minmax.nelems; off++)
    2911             :     {
    2912             :         /* ignore NULL inputs */
    2913        5532 :         if (nulls[off])
    2914         106 :             continue;
    2915             : 
    2916        5426 :         if (*op->resnull)
    2917             :         {
    2918             :             /* first nonnull input, adopt value */
    2919        2668 :             *op->resvalue = values[off];
    2920        2668 :             *op->resnull = false;
    2921             :         }
    2922             :         else
    2923             :         {
    2924             :             int         cmpresult;
    2925             : 
    2926             :             /* apply comparison function */
    2927        2758 :             fcinfo->args[0].value = *op->resvalue;
    2928        2758 :             fcinfo->args[1].value = values[off];
    2929             : 
    2930        2758 :             fcinfo->isnull = false;
    2931        2758 :             cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
    2932        2758 :             if (fcinfo->isnull) /* probably should not happen */
    2933           0 :                 continue;
    2934             : 
    2935        2758 :             if (cmpresult > 0 && operator == IS_LEAST)
    2936         198 :                 *op->resvalue = values[off];
    2937        2560 :             else if (cmpresult < 0 && operator == IS_GREATEST)
    2938          76 :                 *op->resvalue = values[off];
    2939             :         }
    2940             :     }
    2941        2668 : }
    2942             : 
    2943             : /*
    2944             :  * Evaluate a FieldSelect node.
    2945             :  *
    2946             :  * Source record is in step's result variable.
    2947             :  */
    2948             : void
    2949       73640 : ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2950             : {
    2951       73640 :     AttrNumber  fieldnum = op->d.fieldselect.fieldnum;
    2952             :     Datum       tupDatum;
    2953             :     HeapTupleHeader tuple;
    2954             :     Oid         tupType;
    2955             :     int32       tupTypmod;
    2956             :     TupleDesc   tupDesc;
    2957             :     Form_pg_attribute attr;
    2958             :     HeapTupleData tmptup;
    2959             : 
    2960             :     /* NULL record -> NULL result */
    2961       73640 :     if (*op->resnull)
    2962         130 :         return;
    2963             : 
    2964       73510 :     tupDatum = *op->resvalue;
    2965             : 
    2966             :     /* We can special-case expanded records for speed */
    2967       73510 :     if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(tupDatum)))
    2968         480 :     {
    2969         480 :         ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(tupDatum);
    2970             : 
    2971             :         Assert(erh->er_magic == ER_MAGIC);
    2972             : 
    2973             :         /* Extract record's TupleDesc */
    2974         480 :         tupDesc = expanded_record_get_tupdesc(erh);
    2975             : 
    2976             :         /*
    2977             :          * Find field's attr record.  Note we don't support system columns
    2978             :          * here: a datum tuple doesn't have valid values for most of the
    2979             :          * interesting system columns anyway.
    2980             :          */
    2981         480 :         if (fieldnum <= 0)       /* should never happen */
    2982           0 :             elog(ERROR, "unsupported reference to system column %d in FieldSelect",
    2983             :                  fieldnum);
    2984         480 :         if (fieldnum > tupDesc->natts)    /* should never happen */
    2985           0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    2986             :                  fieldnum, tupDesc->natts);
    2987         480 :         attr = TupleDescAttr(tupDesc, fieldnum - 1);
    2988             : 
    2989             :         /* Check for dropped column, and force a NULL result if so */
    2990         480 :         if (attr->attisdropped)
    2991             :         {
    2992           0 :             *op->resnull = true;
    2993           0 :             return;
    2994             :         }
    2995             : 
    2996             :         /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
    2997             :         /* As in CheckVarSlotCompatibility, we should but can't check typmod */
    2998         480 :         if (op->d.fieldselect.resulttype != attr->atttypid)
    2999           0 :             ereport(ERROR,
    3000             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3001             :                      errmsg("attribute %d has wrong type", fieldnum),
    3002             :                      errdetail("Table has type %s, but query expects %s.",
    3003             :                                format_type_be(attr->atttypid),
    3004             :                                format_type_be(op->d.fieldselect.resulttype))));
    3005             : 
    3006             :         /* extract the field */
    3007         480 :         *op->resvalue = expanded_record_get_field(erh, fieldnum,
    3008             :                                                   op->resnull);
    3009             :     }
    3010             :     else
    3011             :     {
    3012             :         /* Get the composite datum and extract its type fields */
    3013       73030 :         tuple = DatumGetHeapTupleHeader(tupDatum);
    3014             : 
    3015       73030 :         tupType = HeapTupleHeaderGetTypeId(tuple);
    3016       73030 :         tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    3017             : 
    3018             :         /* Lookup tupdesc if first time through or if type changes */
    3019       73030 :         tupDesc = get_cached_rowtype(tupType, tupTypmod,
    3020             :                                      &op->d.fieldselect.argdesc,
    3021             :                                      econtext);
    3022             : 
    3023             :         /*
    3024             :          * Find field's attr record.  Note we don't support system columns
    3025             :          * here: a datum tuple doesn't have valid values for most of the
    3026             :          * interesting system columns anyway.
    3027             :          */
    3028       73030 :         if (fieldnum <= 0)       /* should never happen */
    3029           0 :             elog(ERROR, "unsupported reference to system column %d in FieldSelect",
    3030             :                  fieldnum);
    3031       73030 :         if (fieldnum > tupDesc->natts)    /* should never happen */
    3032           0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    3033             :                  fieldnum, tupDesc->natts);
    3034       73030 :         attr = TupleDescAttr(tupDesc, fieldnum - 1);
    3035             : 
    3036             :         /* Check for dropped column, and force a NULL result if so */
    3037       73030 :         if (attr->attisdropped)
    3038             :         {
    3039           0 :             *op->resnull = true;
    3040           0 :             return;
    3041             :         }
    3042             : 
    3043             :         /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
    3044             :         /* As in CheckVarSlotCompatibility, we should but can't check typmod */
    3045       73030 :         if (op->d.fieldselect.resulttype != attr->atttypid)
    3046           0 :             ereport(ERROR,
    3047             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3048             :                      errmsg("attribute %d has wrong type", fieldnum),
    3049             :                      errdetail("Table has type %s, but query expects %s.",
    3050             :                                format_type_be(attr->atttypid),
    3051             :                                format_type_be(op->d.fieldselect.resulttype))));
    3052             : 
    3053             :         /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */
    3054       73030 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3055       73030 :         tmptup.t_data = tuple;
    3056             : 
    3057             :         /* extract the field */
    3058       73030 :         *op->resvalue = heap_getattr(&tmptup,
    3059             :                                      fieldnum,
    3060             :                                      tupDesc,
    3061             :                                      op->resnull);
    3062             :     }
    3063             : }
    3064             : 
    3065             : /*
    3066             :  * Deform source tuple, filling in the step's values/nulls arrays, before
    3067             :  * evaluating individual new values as part of a FieldStore expression.
    3068             :  * Subsequent steps will overwrite individual elements of the values/nulls
    3069             :  * arrays with the new field values, and then FIELDSTORE_FORM will build the
    3070             :  * new tuple value.
    3071             :  *
    3072             :  * Source record is in step's result variable.
    3073             :  */
    3074             : void
    3075         224 : ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3076             : {
    3077             :     TupleDesc   tupDesc;
    3078             : 
    3079             :     /* Lookup tupdesc if first time through or after rescan */
    3080         224 :     tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
    3081             :                                  op->d.fieldstore.argdesc, econtext);
    3082             : 
    3083             :     /* Check that current tupdesc doesn't have more fields than we allocated */
    3084         224 :     if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns))
    3085           0 :         elog(ERROR, "too many columns in composite type %u",
    3086             :              op->d.fieldstore.fstore->resulttype);
    3087             : 
    3088         224 :     if (*op->resnull)
    3089             :     {
    3090             :         /* Convert null input tuple into an all-nulls row */
    3091          96 :         memset(op->d.fieldstore.nulls, true,
    3092          96 :                op->d.fieldstore.ncolumns * sizeof(bool));
    3093             :     }
    3094             :     else
    3095             :     {
    3096             :         /*
    3097             :          * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We
    3098             :          * set all the fields in the struct just in case.
    3099             :          */
    3100         128 :         Datum       tupDatum = *op->resvalue;
    3101             :         HeapTupleHeader tuphdr;
    3102             :         HeapTupleData tmptup;
    3103             : 
    3104         128 :         tuphdr = DatumGetHeapTupleHeader(tupDatum);
    3105         128 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
    3106         128 :         ItemPointerSetInvalid(&(tmptup.t_self));
    3107         128 :         tmptup.t_tableOid = InvalidOid;
    3108         128 :         tmptup.t_data = tuphdr;
    3109             : 
    3110         128 :         heap_deform_tuple(&tmptup, tupDesc,
    3111             :                           op->d.fieldstore.values,
    3112             :                           op->d.fieldstore.nulls);
    3113             :     }
    3114         224 : }
    3115             : 
    3116             : /*
    3117             :  * Compute the new composite datum after each individual field value of a
    3118             :  * FieldStore expression has been evaluated.
    3119             :  */
    3120             : void
    3121         224 : ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3122             : {
    3123             :     HeapTuple   tuple;
    3124             : 
    3125             :     /* argdesc should already be valid from the DeForm step */
    3126         224 :     tuple = heap_form_tuple(*op->d.fieldstore.argdesc,
    3127             :                             op->d.fieldstore.values,
    3128             :                             op->d.fieldstore.nulls);
    3129             : 
    3130         224 :     *op->resvalue = HeapTupleGetDatum(tuple);
    3131         224 :     *op->resnull = false;
    3132         224 : }
    3133             : 
    3134             : /*
    3135             :  * Process a subscript in a SubscriptingRef expression.
    3136             :  *
    3137             :  * If subscript is NULL, throw error in assignment case, or in fetch case
    3138             :  * set result to NULL and return false (instructing caller to skip the rest
    3139             :  * of the SubscriptingRef sequence).
    3140             :  *
    3141             :  * Subscript expression result is in subscriptvalue/subscriptnull.
    3142             :  * On success, integer subscript value has been saved in upperindex[] or
    3143             :  * lowerindex[] for use later.
    3144             :  */
    3145             : bool
    3146      456724 : ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op)
    3147             : {
    3148      456724 :     SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
    3149             :     int        *indexes;
    3150             :     int         off;
    3151             : 
    3152             :     /* If any index expr yields NULL, result is NULL or error */
    3153      456724 :     if (sbsrefstate->subscriptnull)
    3154             :     {
    3155          24 :         if (sbsrefstate->isassignment)
    3156          12 :             ereport(ERROR,
    3157             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    3158             :                      errmsg("array subscript in assignment must not be null")));
    3159          12 :         *op->resnull = true;
    3160          12 :         return false;
    3161             :     }
    3162             : 
    3163             :     /* Convert datum to int, save in appropriate place */
    3164      456700 :     if (op->d.sbsref_subscript.isupper)
    3165      456212 :         indexes = sbsrefstate->upperindex;
    3166             :     else
    3167         488 :         indexes = sbsrefstate->lowerindex;
    3168      456700 :     off = op->d.sbsref_subscript.off;
    3169             : 
    3170      456700 :     indexes[off] = DatumGetInt32(sbsrefstate->subscriptvalue);
    3171             : 
    3172      456700 :     return true;
    3173             : }
    3174             : 
    3175             : /*
    3176             :  * Evaluate SubscriptingRef fetch.
    3177             :  *
    3178             :  * Source container is in step's result variable.
    3179             :  */
    3180             : void
    3181      455370 : ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op)
    3182             : {
    3183      455370 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
    3184             : 
    3185             :     /* Should not get here if source container (or any subscript) is null */
    3186             :     Assert(!(*op->resnull));
    3187             : 
    3188      455370 :     if (sbsrefstate->numlower == 0)
    3189             :     {
    3190             :         /* Scalar case */
    3191      455134 :         *op->resvalue = array_get_element(*op->resvalue,
    3192             :                                           sbsrefstate->numupper,
    3193      455134 :                                           sbsrefstate->upperindex,
    3194      455134 :                                           sbsrefstate->refattrlength,
    3195      455134 :                                           sbsrefstate->refelemlength,
    3196      455134 :                                           sbsrefstate->refelembyval,
    3197      455134 :                                           sbsrefstate->refelemalign,
    3198             :                                           op->resnull);
    3199             :     }
    3200             :     else
    3201             :     {
    3202             :         /* Slice case */
    3203         220 :         *op->resvalue = array_get_slice(*op->resvalue,
    3204             :                                         sbsrefstate->numupper,
    3205         236 :                                         sbsrefstate->upperindex,
    3206         236 :                                         sbsrefstate->lowerindex,
    3207         236 :                                         sbsrefstate->upperprovided,
    3208         236 :                                         sbsrefstate->lowerprovided,
    3209         236 :                                         sbsrefstate->refattrlength,
    3210         236 :                                         sbsrefstate->refelemlength,
    3211         236 :                                         sbsrefstate->refelembyval,
    3212         236 :                                         sbsrefstate->refelemalign);
    3213             :     }
    3214      455354 : }
    3215             : 
    3216             : /*
    3217             :  * Compute old container element/slice value for a SubscriptingRef assignment
    3218             :  * expression. Will only be generated if the new-value subexpression
    3219             :  * contains SubscriptingRef or FieldStore. The value is stored into the
    3220             :  * SubscriptingRefState's prevvalue/prevnull fields.
    3221             :  */
    3222             : void
    3223         132 : ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op)
    3224             : {
    3225         132 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
    3226             : 
    3227         132 :     if (*op->resnull)
    3228             :     {
    3229             :         /* whole array is null, so any element or slice is too */
    3230          36 :         sbsrefstate->prevvalue = (Datum) 0;
    3231          36 :         sbsrefstate->prevnull = true;
    3232             :     }
    3233          96 :     else if (sbsrefstate->numlower == 0)
    3234             :     {
    3235             :         /* Scalar case */
    3236          96 :         sbsrefstate->prevvalue = array_get_element(*op->resvalue,
    3237             :                                                    sbsrefstate->numupper,
    3238          96 :                                                    sbsrefstate->upperindex,
    3239          96 :                                                    sbsrefstate->refattrlength,
    3240          96 :                                                    sbsrefstate->refelemlength,
    3241          96 :                                                    sbsrefstate->refelembyval,
    3242          96 :                                                    sbsrefstate->refelemalign,
    3243             :                                                    &sbsrefstate->prevnull);
    3244             :     }
    3245             :     else
    3246             :     {
    3247             :         /* Slice case */
    3248             :         /* this is currently unreachable */
    3249           0 :         sbsrefstate->prevvalue = array_get_slice(*op->resvalue,
    3250             :                                                  sbsrefstate->numupper,
    3251           0 :                                                  sbsrefstate->upperindex,
    3252           0 :                                                  sbsrefstate->lowerindex,
    3253           0 :                                                  sbsrefstate->upperprovided,
    3254           0 :                                                  sbsrefstate->lowerprovided,
    3255           0 :                                                  sbsrefstate->refattrlength,
    3256           0 :                                                  sbsrefstate->refelemlength,
    3257           0 :                                                  sbsrefstate->refelembyval,
    3258           0 :                                                  sbsrefstate->refelemalign);
    3259           0 :         sbsrefstate->prevnull = false;
    3260             :     }
    3261         132 : }
    3262             : 
    3263             : /*
    3264             :  * Evaluate SubscriptingRef assignment.
    3265             :  *
    3266             :  * Input container (possibly null) is in result area, replacement value is in
    3267             :  * SubscriptingRefState's replacevalue/replacenull.
    3268             :  */
    3269             : void
    3270         618 : ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op)
    3271             : {
    3272         618 :     SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
    3273             : 
    3274             :     /*
    3275             :      * For an assignment to a fixed-length container type, both the original
    3276             :      * container and the value to be assigned into it must be non-NULL, else
    3277             :      * we punt and return the original container.
    3278             :      */
    3279         618 :     if (sbsrefstate->refattrlength > 0)
    3280             :     {
    3281          24 :         if (*op->resnull || sbsrefstate->replacenull)
    3282          12 :             return;
    3283             :     }
    3284             : 
    3285             :     /*
    3286             :      * For assignment to varlena arrays, we handle a NULL original array by
    3287             :      * substituting an empty (zero-dimensional) array; insertion of the new
    3288             :      * element will result in a singleton array value.  It does not matter
    3289             :      * whether the new element is NULL.
    3290             :      */
    3291         606 :     if (*op->resnull)
    3292             :     {
    3293         136 :         *op->resvalue = PointerGetDatum(construct_empty_array(sbsrefstate->refelemtype));
    3294         136 :         *op->resnull = false;
    3295             :     }
    3296             : 
    3297         606 :     if (sbsrefstate->numlower == 0)
    3298             :     {
    3299             :         /* Scalar case */
    3300         438 :         *op->resvalue = array_set_element(*op->resvalue,
    3301             :                                           sbsrefstate->numupper,
    3302         446 :                                           sbsrefstate->upperindex,
    3303             :                                           sbsrefstate->replacevalue,
    3304         446 :                                           sbsrefstate->replacenull,
    3305         446 :                                           sbsrefstate->refattrlength,
    3306         446 :                                           sbsrefstate->refelemlength,
    3307         446 :                                           sbsrefstate->refelembyval,
    3308         446 :                                           sbsrefstate->refelemalign);
    3309             :     }
    3310             :     else
    3311             :     {
    3312             :         /* Slice case */
    3313         152 :         *op->resvalue = array_set_slice(*op->resvalue,
    3314             :                                         sbsrefstate->numupper,
    3315         160 :                                         sbsrefstate->upperindex,
    3316         160 :                                         sbsrefstate->lowerindex,
    3317         160 :                                         sbsrefstate->upperprovided,
    3318         160 :                                         sbsrefstate->lowerprovided,
    3319             :                                         sbsrefstate->replacevalue,
    3320         160 :                                         sbsrefstate->replacenull,
    3321         160 :                                         sbsrefstate->refattrlength,
    3322         160 :                                         sbsrefstate->refelemlength,
    3323         160 :                                         sbsrefstate->refelembyval,
    3324         160 :                                         sbsrefstate->refelemalign);
    3325             :     }
    3326             : }
    3327             : 
    3328             : /*
    3329             :  * Evaluate a rowtype coercion operation.
    3330             :  * This may require rearranging field positions.
    3331             :  *
    3332             :  * Source record is in step's result variable.
    3333             :  */
    3334             : void
    3335       10150 : ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3336             : {
    3337       10150 :     ConvertRowtypeExpr *convert = op->d.convert_rowtype.convert;
    3338             :     HeapTuple   result;
    3339             :     Datum       tupDatum;
    3340             :     HeapTupleHeader tuple;
    3341             :     HeapTupleData tmptup;
    3342             :     TupleDesc   indesc,
    3343             :                 outdesc;
    3344             : 
    3345             :     /* NULL in -> NULL out */
    3346       10150 :     if (*op->resnull)
    3347           4 :         return;
    3348             : 
    3349       10146 :     tupDatum = *op->resvalue;
    3350       10146 :     tuple = DatumGetHeapTupleHeader(tupDatum);
    3351             : 
    3352             :     /* Lookup tupdescs if first time through or after rescan */
    3353       10146 :     if (op->d.convert_rowtype.indesc == NULL)
    3354             :     {
    3355         254 :         get_cached_rowtype(exprType((Node *) convert->arg), -1,
    3356             :                            &op->d.convert_rowtype.indesc,
    3357             :                            econtext);
    3358         254 :         op->d.convert_rowtype.initialized = false;
    3359             :     }
    3360       10146 :     if (op->d.convert_rowtype.outdesc == NULL)
    3361             :     {
    3362         254 :         get_cached_rowtype(convert->resulttype, -1,
    3363             :                            &op->d.convert_rowtype.outdesc,
    3364             :                            econtext);
    3365         254 :         op->d.convert_rowtype.initialized = false;
    3366             :     }
    3367             : 
    3368       10146 :     indesc = op->d.convert_rowtype.indesc;
    3369       10146 :     outdesc = op->d.convert_rowtype.outdesc;
    3370             : 
    3371             :     /*
    3372             :      * We used to be able to assert that incoming tuples are marked with
    3373             :      * exactly the rowtype of indesc.  However, now that ExecEvalWholeRowVar
    3374             :      * might change the tuples' marking to plain RECORD due to inserting
    3375             :      * aliases, we can only make this weak test:
    3376             :      */
    3377             :     Assert(HeapTupleHeaderGetTypeId(tuple) == indesc->tdtypeid ||
    3378             :            HeapTupleHeaderGetTypeId(tuple) == RECORDOID);
    3379             : 
    3380             :     /* if first time through, initialize conversion map */
    3381       10146 :     if (!op->d.convert_rowtype.initialized)
    3382             :     {
    3383             :         MemoryContext old_cxt;
    3384             : 
    3385             :         /* allocate map in long-lived memory context */
    3386         254 :         old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    3387             : 
    3388             :         /* prepare map from old to new attribute numbers */
    3389         254 :         op->d.convert_rowtype.map = convert_tuples_by_name(indesc, outdesc);
    3390         254 :         op->d.convert_rowtype.initialized = true;
    3391             : 
    3392         254 :         MemoryContextSwitchTo(old_cxt);
    3393             :     }
    3394             : 
    3395             :     /* Following steps need a HeapTuple not a bare HeapTupleHeader */
    3396       10146 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3397       10146 :     tmptup.t_data = tuple;
    3398             : 
    3399       10146 :     if (op->d.convert_rowtype.map != NULL)
    3400             :     {
    3401             :         /* Full conversion with attribute rearrangement needed */
    3402         448 :         result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
    3403             :         /* Result already has appropriate composite-datum header fields */
    3404         448 :         *op->resvalue = HeapTupleGetDatum(result);
    3405             :     }
    3406             :     else
    3407             :     {
    3408             :         /*
    3409             :          * The tuple is physically compatible as-is, but we need to insert the
    3410             :          * destination rowtype OID in its composite-datum header field, so we
    3411             :          * have to copy it anyway.  heap_copy_tuple_as_datum() is convenient
    3412             :          * for this since it will both make the physical copy and insert the
    3413             :          * correct composite header fields.  Note that we aren't expecting to
    3414             :          * have to flatten any toasted fields: the input was a composite
    3415             :          * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
    3416             :          * is overkill here, but its check for external fields is cheap.
    3417             :          */
    3418        9698 :         *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
    3419             :     }
    3420             : }
    3421             : 
    3422             : /*
    3423             :  * Evaluate "scalar op ANY/ALL (array)".
    3424             :  *
    3425             :  * Source array is in our result area, scalar arg is already evaluated into
    3426             :  * fcinfo->args[0].
    3427             :  *
    3428             :  * The operator always yields boolean, and we combine the results across all
    3429             :  * array elements using OR and AND (for ANY and ALL respectively).  Of course
    3430             :  * we short-circuit as soon as the result is known.
    3431             :  */
    3432             : void
    3433     3151106 : ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
    3434             : {
    3435     3151106 :     FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
    3436     3151106 :     bool        useOr = op->d.scalararrayop.useOr;
    3437     3151106 :     bool        strictfunc = op->d.scalararrayop.finfo->fn_strict;
    3438             :     ArrayType  *arr;
    3439             :     int         nitems;
    3440             :     Datum       result;
    3441             :     bool        resultnull;
    3442             :     int16       typlen;
    3443             :     bool        typbyval;
    3444             :     char        typalign;
    3445             :     char       *s;
    3446             :     bits8      *bitmap;
    3447             :     int         bitmask;
    3448             : 
    3449             :     /*
    3450             :      * If the array is NULL then we return NULL --- it's not very meaningful
    3451             :      * to do anything else, even if the operator isn't strict.
    3452             :      */
    3453     3151106 :     if (*op->resnull)
    3454       74026 :         return;
    3455             : 
    3456             :     /* Else okay to fetch and detoast the array */
    3457     3077080 :     arr = DatumGetArrayTypeP(*op->resvalue);
    3458             : 
    3459             :     /*
    3460             :      * If the array is empty, we return either FALSE or TRUE per the useOr
    3461             :      * flag.  This is correct even if the scalar is NULL; since we would
    3462             :      * evaluate the operator zero times, it matters not whether it would want
    3463             :      * to return NULL.
    3464             :      */
    3465     3077080 :     nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    3466     3077080 :     if (nitems <= 0)
    3467             :     {
    3468        2540 :         *op->resvalue = BoolGetDatum(!useOr);
    3469        2540 :         *op->resnull = false;
    3470        2540 :         return;
    3471             :     }
    3472             : 
    3473             :     /*
    3474             :      * If the scalar is NULL, and the function is strict, return NULL; no
    3475             :      * point in iterating the loop.
    3476             :      */
    3477     3074540 :     if (fcinfo->args[0].isnull && strictfunc)
    3478             :     {
    3479         804 :         *op->resnull = true;
    3480         804 :         return;
    3481             :     }
    3482             : 
    3483             :     /*
    3484             :      * We arrange to look up info about the element type only once per series
    3485             :      * of calls, assuming the element type doesn't change underneath us.
    3486             :      */
    3487     3073736 :     if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
    3488             :     {
    3489       10970 :         get_typlenbyvalalign(ARR_ELEMTYPE(arr),
    3490             :                              &op->d.scalararrayop.typlen,
    3491             :                              &op->d.scalararrayop.typbyval,
    3492             :                              &op->d.scalararrayop.typalign);
    3493       10970 :         op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
    3494             :     }
    3495             : 
    3496     3073736 :     typlen = op->d.scalararrayop.typlen;
    3497     3073736 :     typbyval = op->d.scalararrayop.typbyval;
    3498     3073736 :     typalign = op->d.scalararrayop.typalign;
    3499             : 
    3500             :     /* Initialize result appropriately depending on useOr */
    3501     3073736 :     result = BoolGetDatum(!useOr);
    3502     3073736 :     resultnull = false;
    3503             : 
    3504             :     /* Loop over the array elements */
    3505     3073736 :     s = (char *) ARR_DATA_PTR(arr);
    3506     3073736 :     bitmap = ARR_NULLBITMAP(arr);
    3507     3073736 :     bitmask = 1;
    3508             : 
    3509     8419584 :     for (int i = 0; i < nitems; i++)
    3510             :     {
    3511             :         Datum       elt;
    3512             :         Datum       thisresult;
    3513             : 
    3514             :         /* Get array element, checking for NULL */
    3515     6453438 :         if (bitmap && (*bitmap & bitmask) == 0)
    3516             :         {
    3517      120832 :             fcinfo->args[1].value = (Datum) 0;
    3518      120832 :             fcinfo->args[1].isnull = true;
    3519             :         }
    3520             :         else
    3521             :         {
    3522     6332606 :             elt = fetch_att(s, typbyval, typlen);
    3523     6332606 :             s = att_addlength_pointer(s, typlen, s);
    3524     6332606 :             s = (char *) att_align_nominal(s, typalign);
    3525     6332606 :             fcinfo->args[1].value = elt;
    3526     6332606 :             fcinfo->args[1].isnull = false;
    3527             :         }
    3528             : 
    3529             :         /* Call comparison function */
    3530     6453438 :         if (fcinfo->args[1].isnull && strictfunc)
    3531             :         {
    3532      120832 :             fcinfo->isnull = true;
    3533      120832 :             thisresult = (Datum) 0;
    3534             :         }
    3535             :         else
    3536             :         {
    3537     6332606 :             fcinfo->isnull = false;
    3538     6332606 :             thisresult = op->d.scalararrayop.fn_addr(fcinfo);
    3539             :         }
    3540             : 
    3541             :         /* Combine results per OR or AND semantics */
    3542     6453438 :         if (fcinfo->isnull)
    3543      120832 :             resultnull = true;
    3544     6332606 :         else if (useOr)
    3545             :         {
    3546     5728368 :             if (DatumGetBool(thisresult))
    3547             :             {
    3548      737192 :                 result = BoolGetDatum(true);
    3549      737192 :                 resultnull = false;
    3550      737192 :                 break;          /* needn't look at any more elements */
    3551             :             }
    3552             :         }
    3553             :         else
    3554             :         {
    3555      604238 :             if (!DatumGetBool(thisresult))
    3556             :             {
    3557      370398 :                 result = BoolGetDatum(false);
    3558      370398 :                 resultnull = false;
    3559      370398 :                 break;          /* needn't look at any more elements */
    3560             :             }
    3561             :         }
    3562             : 
    3563             :         /* advance bitmap pointer if any */
    3564     5345848 :         if (bitmap)
    3565             :         {
    3566      411146 :             bitmask <<= 1;
    3567      411146 :             if (bitmask == 0x100)
    3568             :             {
    3569         526 :                 bitmap++;
    3570         526 :                 bitmask = 1;
    3571             :             }
    3572             :         }
    3573             :     }
    3574             : 
    3575     3073736 :     *op->resvalue = result;
    3576     3073736 :     *op->resnull = resultnull;
    3577             : }
    3578             : 
    3579             : /*
    3580             :  * Evaluate a NOT NULL domain constraint.
    3581             :  */
    3582             : void
    3583         250 : ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
    3584             : {
    3585         250 :     if (*op->resnull)
    3586          64 :         ereport(ERROR,
    3587             :                 (errcode(ERRCODE_NOT_NULL_VIOLATION),
    3588             :                  errmsg("domain %s does not allow null values",
    3589             :                         format_type_be(op->d.domaincheck.resulttype)),
    3590             :                  errdatatype(op->d.domaincheck.resulttype)));
    3591         186 : }
    3592             : 
    3593             : /*
    3594             :  * Evaluate a CHECK domain constraint.
    3595             :  */
    3596             : void
    3597       31632 : ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
    3598             : {
    3599       31632 :     if (!*op->d.domaincheck.checknull &&
    3600       27630 :         !DatumGetBool(*op->d.domaincheck.checkvalue))
    3601         244 :         ereport(ERROR,
    3602             :                 (errcode(ERRCODE_CHECK_VIOLATION),
    3603             :                  errmsg("value for domain %s violates check constraint \"%s\"",
    3604             :                         format_type_be(op->d.domaincheck.resulttype),
    3605             :                         op->d.domaincheck.constraintname),
    3606             :                  errdomainconstraint(op->d.domaincheck.resulttype,
    3607             :                                      op->d.domaincheck.constraintname)));
    3608       31388 : }
    3609             : 
    3610             : /*
    3611             :  * Evaluate the various forms of XmlExpr.
    3612             :  *
    3613             :  * Arguments have been evaluated into named_argvalue/named_argnull
    3614             :  * and/or argvalue/argnull arrays.
    3615             :  */
    3616             : void
    3617       26428 : ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
    3618             : {
    3619       26428 :     XmlExpr    *xexpr = op->d.xmlexpr.xexpr;
    3620             :     Datum       value;
    3621             : 
    3622       26428 :     *op->resnull = true;     /* until we get a result */
    3623       26428 :     *op->resvalue = (Datum) 0;
    3624             : 
    3625       26428 :     switch (xexpr->op)
    3626             :     {
    3627          36 :         case IS_XMLCONCAT:
    3628           8 :             {
    3629          36 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3630          36 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3631          36 :                 List       *values = NIL;
    3632             : 
    3633         116 :                 for (int i = 0; i < list_length(xexpr->args); i++)
    3634             :                 {
    3635          80 :                     if (!argnull[i])
    3636          60 :                         values = lappend(values, DatumGetPointer(argvalue[i]));
    3637             :                 }
    3638             : 
    3639          36 :                 if (values != NIL)
    3640             :                 {
    3641          28 :                     *op->resvalue = PointerGetDatum(xmlconcat(values));
    3642          28 :                     *op->resnull = false;
    3643             :                 }
    3644             :             }
    3645          36 :             break;
    3646             : 
    3647       13040 :         case IS_XMLFOREST:
    3648       13040 :             {
    3649       13040 :                 Datum      *argvalue = op->d.xmlexpr.named_argvalue;
    3650       13040 :                 bool       *argnull = op->d.xmlexpr.named_argnull;
    3651             :                 StringInfoData buf;
    3652             :                 ListCell   *lc;
    3653             :                 ListCell   *lc2;
    3654             :                 int         i;
    3655             : 
    3656       13040 :                 initStringInfo(&buf);
    3657             : 
    3658       13040 :                 i = 0;
    3659       91200 :                 forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
    3660             :                 {
    3661       78160 :                     Expr       *e = (Expr *) lfirst(lc);
    3662       78160 :                     char       *argname = strVal(lfirst(lc2));
    3663             : 
    3664       78160 :                     if (!argnull[i])
    3665             :                     {
    3666       65088 :                         value = argvalue[i];
    3667       65088 :                         appendStringInfo(&buf, "<%s>%s</%s>",
    3668             :                                          argname,
    3669             :                                          map_sql_value_to_xml_value(value,
    3670             :                                                                     exprType((Node *) e), true),
    3671             :                                          argname);
    3672       65088 :                         *op->resnull = false;
    3673             :                     }
    3674       78160 :                     i++;
    3675             :                 }
    3676             : 
    3677       13040 :                 if (!*op->resnull)
    3678             :                 {
    3679             :                     text       *result;
    3680             : 
    3681       13040 :                     result = cstring_to_text_with_len(buf.data, buf.len);
    3682       13040 :                     *op->resvalue = PointerGetDatum(result);
    3683             :                 }
    3684             : 
    3685       13040 :                 pfree(buf.data);
    3686             :             }
    3687       13040 :             break;
    3688             : 
    3689       13144 :         case IS_XMLELEMENT:
    3690       13144 :             *op->resvalue = PointerGetDatum(xmlelement(xexpr,
    3691             :                                                        op->d.xmlexpr.named_argvalue,
    3692             :                                                        op->d.xmlexpr.named_argnull,
    3693             :                                                        op->d.xmlexpr.argvalue,
    3694             :                                                        op->d.xmlexpr.argnull));
    3695       13140 :             *op->resnull = false;
    3696       13140 :             break;
    3697             : 
    3698          88 :         case IS_XMLPARSE:
    3699             :             {
    3700          88 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3701          88 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3702             :                 text       *data;
    3703             :                 bool        preserve_whitespace;
    3704             : 
    3705             :                 /* arguments are known to be text, bool */
    3706             :                 Assert(list_length(xexpr->args) == 2);
    3707             : 
    3708          88 :                 if (argnull[0])
    3709           0 :                     return;
    3710          88 :                 value = argvalue[0];
    3711          88 :                 data = DatumGetTextPP(value);
    3712             : 
    3713          88 :                 if (argnull[1]) /* probably can't happen */
    3714           0 :                     return;
    3715          88 :                 value = argvalue[1];
    3716          88 :                 preserve_whitespace = DatumGetBool(value);
    3717             : 
    3718          88 :                 *op->resvalue = PointerGetDatum(xmlparse(data,
    3719             :                                                          xexpr->xmloption,
    3720             :                                                          preserve_whitespace));
    3721          56 :                 *op->resnull = false;
    3722             :             }
    3723          56 :             break;
    3724             : 
    3725          48 :         case IS_XMLPI:
    3726             :             {
    3727             :                 text       *arg;
    3728             :                 bool        isnull;
    3729             : 
    3730             :                 /* optional argument is known to be text */
    3731             :                 Assert(list_length(xexpr->args) <= 1);
    3732             : 
    3733          48 :                 if (xexpr->args)
    3734             :                 {
    3735          28 :                     isnull = op->d.xmlexpr.argnull[0];
    3736          28 :                     if (isnull)
    3737          12 :                         arg = NULL;
    3738             :                     else
    3739          16 :                         arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]);
    3740             :                 }
    3741             :                 else
    3742             :                 {
    3743          20 :                     arg = NULL;
    3744          20 :                     isnull = false;
    3745             :                 }
    3746             : 
    3747          48 :                 *op->resvalue = PointerGetDatum(xmlpi(xexpr->name,
    3748             :                                                       arg,
    3749             :                                                       isnull,
    3750             :                                                       op->resnull));
    3751             :             }
    3752          36 :             break;
    3753             : 
    3754          40 :         case IS_XMLROOT:
    3755             :             {
    3756          40 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3757          40 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3758             :                 xmltype    *data;
    3759             :                 text       *version;
    3760             :                 int         standalone;
    3761             : 
    3762             :                 /* arguments are known to be xml, text, int */
    3763             :                 Assert(list_length(xexpr->args) == 3);
    3764             : 
    3765          40 :                 if (argnull[0])
    3766           0 :                     return;
    3767          40 :                 data = DatumGetXmlP(argvalue[0]);
    3768             : 
    3769          40 :                 if (argnull[1])
    3770          24 :                     version = NULL;
    3771             :                 else
    3772          16 :                     version = DatumGetTextPP(argvalue[1]);
    3773             : 
    3774             :                 Assert(!argnull[2]);    /* always present */
    3775          40 :                 standalone = DatumGetInt32(argvalue[2]);
    3776             : 
    3777          40 :                 *op->resvalue = PointerGetDatum(xmlroot(data,
    3778             :                                                         version,
    3779             :                                                         standalone));
    3780          40 :                 *op->resnull = false;
    3781             :             }
    3782          40 :             break;
    3783             : 
    3784          16 :         case IS_XMLSERIALIZE:
    3785             :             {
    3786          16 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3787          16 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3788             : 
    3789             :                 /* argument type is known to be xml */
    3790             :                 Assert(list_length(xexpr->args) == 1);
    3791             : 
    3792          16 :                 if (argnull[0])
    3793           0 :                     return;
    3794          16 :                 value = argvalue[0];
    3795             : 
    3796          16 :                 *op->resvalue = PointerGetDatum(xmltotext_with_xmloption(DatumGetXmlP(value),
    3797             :                                                                          xexpr->xmloption));
    3798          12 :                 *op->resnull = false;
    3799             :             }
    3800          12 :             break;
    3801             : 
    3802          16 :         case IS_DOCUMENT:
    3803             :             {
    3804          16 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3805          16 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3806             : 
    3807             :                 /* optional argument is known to be xml */
    3808             :                 Assert(list_length(xexpr->args) == 1);
    3809             : 
    3810          16 :                 if (argnull[0])
    3811           0 :                     return;
    3812          16 :                 value = argvalue[0];
    3813             : 
    3814          16 :                 *op->resvalue =
    3815          16 :                     BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
    3816          16 :                 *op->resnull = false;
    3817             :             }
    3818          16 :             break;
    3819             : 
    3820           0 :         default:
    3821           0 :             elog(ERROR, "unrecognized XML operation");
    3822             :             break;
    3823             :     }
    3824             : }
    3825             : 
    3826             : /*
    3827             :  * ExecEvalGroupingFunc
    3828             :  *
    3829             :  * Computes a bitmask with a bit for each (unevaluated) argument expression
    3830             :  * (rightmost arg is least significant bit).
    3831             :  *
    3832             :  * A bit is set if the corresponding expression is NOT part of the set of
    3833             :  * grouping expressions in the current grouping set.
    3834             :  */
    3835             : void
    3836        1094 : ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
    3837             : {
    3838        1094 :     AggState   *aggstate = castNode(AggState, state->parent);
    3839        1094 :     int         result = 0;
    3840        1094 :     Bitmapset  *grouped_cols = aggstate->grouped_cols;
    3841             :     ListCell   *lc;
    3842             : 
    3843        2738 :     foreach(lc, op->d.grouping_func.clauses)
    3844             :     {
    3845        1644 :         int         attnum = lfirst_int(lc);
    3846             : 
    3847        1644 :         result <<= 1;
    3848             : 
    3849        1644 :         if (!bms_is_member(attnum, grouped_cols))
    3850         640 :             result |= 1;
    3851             :     }
    3852             : 
    3853        1094 :     *op->resvalue = Int32GetDatum(result);
    3854        1094 :     *op->resnull = false;
    3855        1094 : }
    3856             : 
    3857             : /*
    3858             :  * Hand off evaluation of a subplan to nodeSubplan.c
    3859             :  */
    3860             : void
    3861     2375980 : ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3862             : {
    3863     2375980 :     SubPlanState *sstate = op->d.subplan.sstate;
    3864             : 
    3865             :     /* could potentially be nested, so make sure there's enough stack */
    3866     2375980 :     check_stack_depth();
    3867             : 
    3868     2375980 :     *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
    3869     2375976 : }
    3870             : 
    3871             : /*
    3872             :  * Hand off evaluation of an alternative subplan to nodeSubplan.c
    3873             :  */
    3874             : void
    3875      511298 : ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3876             : {
    3877      511298 :     AlternativeSubPlanState *asstate = op->d.alternative_subplan.asstate;
    3878             : 
    3879             :     /* could potentially be nested, so make sure there's enough stack */
    3880      511298 :     check_stack_depth();
    3881             : 
    3882      511298 :     *op->resvalue = ExecAlternativeSubPlan(asstate, econtext, op->resnull);
    3883      511298 : }
    3884             : 
    3885             : /*
    3886             :  * Evaluate a wholerow Var expression.
    3887             :  *
    3888             :  * Returns a Datum whose value is the value of a whole-row range variable
    3889             :  * with respect to given expression context.
    3890             :  */
    3891             : void
    3892       32494 : ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3893             : {
    3894       32494 :     Var        *variable = op->d.wholerow.var;
    3895             :     TupleTableSlot *slot;
    3896             :     TupleDesc   output_tupdesc;
    3897             :     MemoryContext oldcontext;
    3898             :     HeapTupleHeader dtuple;
    3899             :     HeapTuple   tuple;
    3900             : 
    3901             :     /* This was checked by ExecInitExpr */
    3902             :     Assert(variable->varattno == InvalidAttrNumber);
    3903             : 
    3904             :     /* Get the input slot we want */
    3905       32494 :     switch (variable->varno)
    3906             :     {
    3907          60 :         case INNER_VAR:
    3908             :             /* get the tuple from the inner node */
    3909          60 :             slot = econtext->ecxt_innertuple;
    3910          60 :             break;
    3911             : 
    3912          12 :         case OUTER_VAR:
    3913             :             /* get the tuple from the outer node */
    3914          12 :             slot = econtext->ecxt_outertuple;
    3915          12 :             break;
    3916             : 
    3917             :             /* INDEX_VAR is handled by default case */
    3918             : 
    3919       32422 :         default:
    3920             :             /* get the tuple from the relation being scanned */
    3921       32422 :             slot = econtext->ecxt_scantuple;
    3922       32422 :             break;
    3923             :     }
    3924             : 
    3925             :     /* Apply the junkfilter if any */
    3926       32494 :     if (op->d.wholerow.junkFilter != NULL)
    3927          40 :         slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
    3928             : 
    3929             :     /*
    3930             :      * If first time through, obtain tuple descriptor and check compatibility.
    3931             :      *
    3932             :      * XXX: It'd be great if this could be moved to the expression
    3933             :      * initialization phase, but due to using slots that's currently not
    3934             :      * feasible.
    3935             :      */
    3936       32494 :     if (op->d.wholerow.first)
    3937             :     {
    3938             :         /* optimistically assume we don't need slow path */
    3939        1430 :         op->d.wholerow.slow = false;
    3940             : 
    3941             :         /*
    3942             :          * If the Var identifies a named composite type, we must check that
    3943             :          * the actual tuple type is compatible with it.
    3944             :          */
    3945        1430 :         if (variable->vartype != RECORDOID)
    3946             :         {
    3947             :             TupleDesc   var_tupdesc;
    3948             :             TupleDesc   slot_tupdesc;
    3949             : 
    3950             :             /*
    3951             :              * We really only care about numbers of attributes and data types.
    3952             :              * Also, we can ignore type mismatch on columns that are dropped
    3953             :              * in the destination type, so long as (1) the physical storage
    3954             :              * matches or (2) the actual column value is NULL.  Case (1) is
    3955             :              * helpful in some cases involving out-of-date cached plans, while
    3956             :              * case (2) is expected behavior in situations such as an INSERT
    3957             :              * into a table with dropped columns (the planner typically
    3958             :              * generates an INT4 NULL regardless of the dropped column type).
    3959             :              * If we find a dropped column and cannot verify that case (1)
    3960             :              * holds, we have to use the slow path to check (2) for each row.
    3961             :              *
    3962             :              * If vartype is a domain over composite, just look through that
    3963             :              * to the base composite type.
    3964             :              */
    3965         924 :             var_tupdesc = lookup_rowtype_tupdesc_domain(variable->vartype,
    3966             :                                                         -1, false);
    3967             : 
    3968         924 :             slot_tupdesc = slot->tts_tupleDescriptor;
    3969             : 
    3970         924 :             if (var_tupdesc->natts != slot_tupdesc->natts)
    3971           0 :                 ereport(ERROR,
    3972             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3973             :                          errmsg("table row type and query-specified row type do not match"),
    3974             :                          errdetail_plural("Table row contains %d attribute, but query expects %d.",
    3975             :                                           "Table row contains %d attributes, but query expects %d.",
    3976             :                                           slot_tupdesc->natts,
    3977             :                                           slot_tupdesc->natts,
    3978             :                                           var_tupdesc->natts)));
    3979             : 
    3980        3792 :             for (int i = 0; i < var_tupdesc->natts; i++)
    3981             :             {
    3982        2868 :                 Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
    3983        2868 :                 Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
    3984             : 
    3985        2868 :                 if (vattr->atttypid == sattr->atttypid)
    3986        2856 :                     continue;   /* no worries */
    3987          12 :                 if (!vattr->attisdropped)
    3988           0 :                     ereport(ERROR,
    3989             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    3990             :                              errmsg("table row type and query-specified row type do not match"),
    3991             :                              errdetail("Table has type %s at ordinal position %d, but query expects %s.",
    3992             :                                        format_type_be(sattr->atttypid),
    3993             :                                        i + 1,
    3994             :                                        format_type_be(vattr->atttypid))));
    3995             : 
    3996          12 :                 if (vattr->attlen != sattr->attlen ||
    3997           0 :                     vattr->attalign != sattr->attalign)
    3998          12 :                     op->d.wholerow.slow = true; /* need to check for nulls */
    3999             :             }
    4000             : 
    4001             :             /*
    4002             :              * Use the variable's declared rowtype as the descriptor for the
    4003             :              * output values, modulo possibly assigning new column names
    4004             :              * below. In particular, we *must* absorb any attisdropped
    4005             :              * markings.
    4006             :              */
    4007         924 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    4008         924 :             output_tupdesc = CreateTupleDescCopy(var_tupdesc);
    4009         924 :             MemoryContextSwitchTo(oldcontext);
    4010             : 
    4011         924 :             ReleaseTupleDesc(var_tupdesc);
    4012             :         }
    4013             :         else
    4014             :         {
    4015             :             /*
    4016             :              * In the RECORD case, we use the input slot's rowtype as the
    4017             :              * descriptor for the output values, modulo possibly assigning new
    4018             :              * column names below.
    4019             :              */
    4020         506 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    4021         506 :             output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
    4022         506 :             MemoryContextSwitchTo(oldcontext);
    4023             :         }
    4024             : 
    4025             :         /*
    4026             :          * Construct a tuple descriptor for the composite values we'll
    4027             :          * produce, and make sure its record type is "blessed".  The main
    4028             :          * reason to do this is to be sure that operations such as
    4029             :          * row_to_json() will see the desired column names when they look up
    4030             :          * the descriptor from the type information embedded in the composite
    4031             :          * values.
    4032             :          *
    4033             :          * We already got the correct physical datatype info above, but now we
    4034             :          * should try to find the source RTE and adopt its column aliases, in
    4035             :          * case they are different from the original rowtype's names.  For
    4036             :          * example, in "SELECT foo(t) FROM tab t(x,y)", the first two columns
    4037             :          * in the composite output should be named "x" and "y" regardless of
    4038             :          * tab's column names.
    4039             :          *
    4040             :          * If we can't locate the RTE, assume the column names we've got are
    4041             :          * OK.  (As of this writing, the only cases where we can't locate the
    4042             :          * RTE are in execution of trigger WHEN clauses, and then the Var will
    4043             :          * have the trigger's relation's rowtype, so its names are fine.)
    4044             :          * Also, if the creator of the RTE didn't bother to fill in an eref
    4045             :          * field, assume our column names are OK.  (This happens in COPY, and
    4046             :          * perhaps other places.)
    4047             :          */
    4048        1430 :         if (econtext->ecxt_estate &&
    4049        1430 :             variable->varno <= econtext->ecxt_estate->es_range_table_size)
    4050             :         {
    4051        1374 :             RangeTblEntry *rte = exec_rt_fetch(variable->varno,
    4052        1374 :                                                econtext->ecxt_estate);
    4053             : 
    4054        1374 :             if (rte->eref)
    4055        1374 :                 ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
    4056             :         }
    4057             : 
    4058             :         /* Bless the tupdesc if needed, and save it in the execution state */
    4059        1430 :         op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
    4060             : 
    4061        1430 :         op->d.wholerow.first = false;
    4062             :     }
    4063             : 
    4064             :     /*
    4065             :      * Make sure all columns of the slot are accessible in the slot's
    4066             :      * Datum/isnull arrays.
    4067             :      */
    4068       32494 :     slot_getallattrs(slot);
    4069             : 
    4070       32494 :     if (op->d.wholerow.slow)
    4071             :     {
    4072             :         /* Check to see if any dropped attributes are non-null */
    4073          20 :         TupleDesc   tupleDesc = slot->tts_tupleDescriptor;
    4074          20 :         TupleDesc   var_tupdesc = op->d.wholerow.tupdesc;
    4075             : 
    4076             :         Assert(var_tupdesc->natts == tupleDesc->natts);
    4077             : 
    4078         100 :         for (int i = 0; i < var_tupdesc->natts; i++)
    4079             :         {
    4080          80 :             Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
    4081          80 :             Form_pg_attribute sattr = TupleDescAttr(tupleDesc, i);
    4082             : 
    4083          80 :             if (!vattr->attisdropped)
    4084          60 :                 continue;       /* already checked non-dropped cols */
    4085          20 :             if (slot->tts_isnull[i])
    4086          20 :                 continue;       /* null is always okay */
    4087           0 :             if (vattr->attlen != sattr->attlen ||
    4088           0 :                 vattr->attalign != sattr->attalign)
    4089           0 :                 ereport(ERROR,
    4090             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    4091             :                          errmsg("table row type and query-specified row type do not match"),
    4092             :                          errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
    4093             :                                    i + 1)));
    4094             :         }
    4095             :     }
    4096             : 
    4097             :     /*
    4098             :      * Build a composite datum, making sure any toasted fields get detoasted.
    4099             :      *
    4100             :      * (Note: it is critical that we not change the slot's state here.)
    4101             :      */
    4102       32494 :     tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
    4103             :                                         slot->tts_values,
    4104             :                                         slot->tts_isnull);
    4105       32494 :     dtuple = tuple->t_data;
    4106             : 
    4107             :     /*
    4108             :      * Label the datum with the composite type info we identified before.
    4109             :      *
    4110             :      * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
    4111             :      * the tuple build step; but that seems a tad risky so let's not.)
    4112             :      */
    4113       32494 :     HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
    4114       32494 :     HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
    4115             : 
    4116       32494 :     *op->resvalue = PointerGetDatum(dtuple);
    4117       32494 :     *op->resnull = false;
    4118       32494 : }
    4119             : 
    4120             : void
    4121     5373360 : ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
    4122             :                TupleTableSlot *slot)
    4123             : {
    4124             :     Datum       d;
    4125             : 
    4126             :     /* slot_getsysattr has sufficient defenses against bad attnums */
    4127     5373360 :     d = slot_getsysattr(slot,
    4128             :                         op->d.var.attnum,
    4129             :                         op->resnull);
    4130     5373360 :     *op->resvalue = d;
    4131             :     /* this ought to be unreachable, but it's cheap enough to check */
    4132     5373360 :     if (unlikely(*op->resnull))
    4133           0 :         elog(ERROR, "failed to fetch attribute from slot");
    4134     5373360 : }
    4135             : 
    4136             : /*
    4137             :  * Transition value has not been initialized. This is the first non-NULL input
    4138             :  * value for a group. We use it as the initial value for transValue.
    4139             :  */
    4140             : void
    4141       39658 : ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
    4142             :                  ExprContext *aggcontext)
    4143             : {
    4144       39658 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    4145             :     MemoryContext oldContext;
    4146             : 
    4147             :     /*
    4148             :      * We must copy the datum into aggcontext if it is pass-by-ref. We do not
    4149             :      * need to pfree the old transValue, since it's NULL.  (We already checked
    4150             :      * that the agg's input type is binary-compatible with its transtype, so
    4151             :      * straight copy here is OK.)
    4152             :      */
    4153       39658 :     oldContext = MemoryContextSwitchTo(aggcontext->ecxt_per_tuple_memory);
    4154      118974 :     pergroup->transValue = datumCopy(fcinfo->args[1].value,
    4155       39658 :                                      pertrans->transtypeByVal,
    4156       39658 :                                      pertrans->transtypeLen);
    4157       39658 :     pergroup->transValueIsNull = false;
    4158       39658 :     pergroup->noTransValue = false;
    4159       39658 :     MemoryContextSwitchTo(oldContext);
    4160       39658 : }
    4161             : 
    4162             : /*
    4163             :  * Ensure that the current transition value is a child of the aggcontext,
    4164             :  * rather than the per-tuple context.
    4165             :  *
    4166             :  * NB: This can change the current memory context.
    4167             :  */
    4168             : Datum
    4169       42160 : ExecAggTransReparent(AggState *aggstate, AggStatePerTrans pertrans,
    4170             :                      Datum newValue, bool newValueIsNull,
    4171             :                      Datum oldValue, bool oldValueIsNull)
    4172             : {
    4173             :     Assert(newValue != oldValue);
    4174             : 
    4175       42160 :     if (!newValueIsNull)
    4176             :     {
    4177       42160 :         MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
    4178       42276 :         if (DatumIsReadWriteExpandedObject(newValue,
    4179             :                                            false,
    4180       42164 :                                            pertrans->transtypeLen) &&
    4181         116 :             MemoryContextGetParent(DatumGetEOHP(newValue)->eoh_context) == CurrentMemoryContext)
    4182             :              /* do nothing */ ;
    4183             :         else
    4184       84304 :             newValue = datumCopy(newValue,
    4185       42152 :                                  pertrans->transtypeByVal,
    4186       42152 :                                  pertrans->transtypeLen);
    4187             :     }
    4188             :     else
    4189             :     {
    4190             :         /*
    4191             :          * Ensure that AggStatePerGroup->transValue ends up being 0, so
    4192             :          * callers can safely compare newValue/oldValue without having to
    4193             :          * check their respective nullness.
    4194             :          */
    4195           0 :         newValue = (Datum) 0;
    4196             :     }
    4197             : 
    4198       42160 :     if (!oldValueIsNull)
    4199             :     {
    4200       42088 :         if (DatumIsReadWriteExpandedObject(oldValue,
    4201             :                                            false,
    4202             :                                            pertrans->transtypeLen))
    4203           0 :             DeleteExpandedObject(oldValue);
    4204             :         else
    4205       42088 :             pfree(DatumGetPointer(oldValue));
    4206             :     }
    4207             : 
    4208       42160 :     return newValue;
    4209             : }
    4210             : 
    4211             : /*
    4212             :  * Invoke ordered transition function, with a datum argument.
    4213             :  */
    4214             : void
    4215      809636 : ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op,
    4216             :                              ExprContext *econtext)
    4217             : {
    4218      809636 :     AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    4219      809636 :     int         setno = op->d.agg_trans.setno;
    4220             : 
    4221     1619272 :     tuplesort_putdatum(pertrans->sortstates[setno],
    4222      809636 :                        *op->resvalue, *op->resnull);
    4223      809636 : }
    4224             : 
    4225             : /*
    4226             :  * Invoke ordered transition function, with a tuple argument.
    4227             :  */
    4228             : void
    4229       15328 : ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
    4230             :                              ExprContext *econtext)
    4231             : {
    4232       15328 :     AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    4233       15328 :     int         setno = op->d.agg_trans.setno;
    4234             : 
    4235       15328 :     ExecClearTuple(pertrans->sortslot);
    4236       15328 :     pertrans->sortslot->tts_nvalid = pertrans->numInputs;
    4237       15328 :     ExecStoreVirtualTuple(pertrans->sortslot);
    4238       15328 :     tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
    4239       15328 : }
    4240             : 
    4241             : /* implementation of transition function invocation for byval types */
    4242             : static pg_attribute_always_inline void
    4243    15079438 : ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
    4244             :                        AggStatePerGroup pergroup,
    4245             :                        ExprContext *aggcontext, int setno)
    4246             : {
    4247    15079438 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    4248             :     MemoryContext oldContext;
    4249             :     Datum       newVal;
    4250             : 
    4251             :     /* cf. select_current_set() */
    4252    15079438 :     aggstate->curaggcontext = aggcontext;
    4253    15079438 :     aggstate->current_set = setno;
    4254             : 
    4255             :     /* set up aggstate->curpertrans for AggGetAggref() */
    4256    15079438 :     aggstate->curpertrans = pertrans;
    4257             : 
    4258             :     /* invoke transition function in per-tuple context */
    4259    15079438 :     oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    4260             : 
    4261    15079438 :     fcinfo->args[0].value = pergroup->transValue;
    4262    15079438 :     fcinfo->args[0].isnull = pergroup->transValueIsNull;
    4263    15079438 :     fcinfo->isnull = false;      /* just in case transfn doesn't set it */
    4264             : 
    4265    15079438 :     newVal = FunctionCallInvoke(fcinfo);
    4266             : 
    4267    15079414 :     pergroup->transValue = newVal;
    4268    15079414 :     pergroup->transValueIsNull = fcinfo->isnull;
    4269             : 
    4270    15079414 :     MemoryContextSwitchTo(oldContext);
    4271    15079414 : }
    4272             : 
    4273             : /* implementation of transition function invocation for byref types */
    4274             : static pg_attribute_always_inline void
    4275     1812982 : ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
    4276             :                        AggStatePerGroup pergroup,
    4277             :                        ExprContext *aggcontext, int setno)
    4278             : {
    4279     1812982 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    4280             :     MemoryContext oldContext;
    4281             :     Datum       newVal;
    4282             : 
    4283             :     /* cf. select_current_set() */
    4284     1812982 :     aggstate->curaggcontext = aggcontext;
    4285     1812982 :     aggstate->current_set = setno;
    4286             : 
    4287             :     /* set up aggstate->curpertrans for AggGetAggref() */
    4288     1812982 :     aggstate->curpertrans = pertrans;
    4289             : 
    4290             :     /* invoke transition function in per-tuple context */
    4291     1812982 :     oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    4292             : 
    4293     1812982 :     fcinfo->args[0].value = pergroup->transValue;
    4294     1812982 :     fcinfo->args[0].isnull = pergroup->transValueIsNull;
    4295     1812982 :     fcinfo->isnull = false;      /* just in case transfn doesn't set it */
    4296             : 
    4297     1812982 :     newVal = FunctionCallInvoke(fcinfo);
    4298             : 
    4299             :     /*
    4300             :      * For pass-by-ref datatype, must copy the new value into aggcontext and
    4301             :      * free the prior transValue.  But if transfn returned a pointer to its
    4302             :      * first input, we don't need to do anything.  Also, if transfn returned a
    4303             :      * pointer to a R/W expanded object that is already a child of the
    4304             :      * aggcontext, assume we can adopt that value without copying it.
    4305             :      *
    4306             :      * It's safe to compare newVal with pergroup->transValue without regard
    4307             :      * for either being NULL, because ExecAggTransReparent() takes care to set
    4308             :      * transValue to 0 when NULL. Otherwise we could end up accidentally not
    4309             :      * reparenting, when the transValue has the same numerical value as
    4310             :      * newValue, despite being NULL.  This is a somewhat hot path, making it
    4311             :      * undesirable to instead solve this with another branch for the common
    4312             :      * case of the transition function returning its (modified) input
    4313             :      * argument.
    4314             :      */
    4315     1812978 :     if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
    4316       53104 :         newVal = ExecAggTransReparent(aggstate, pertrans,
    4317       26552 :                                       newVal, fcinfo->isnull,
    4318             :                                       pergroup->transValue,
    4319       26552 :                                       pergroup->transValueIsNull);
    4320             : 
    4321     1812978 :     pergroup->transValue = newVal;
    4322     1812978 :     pergroup->transValueIsNull = fcinfo->isnull;
    4323             : 
    4324     1812978 :     MemoryContextSwitchTo(oldContext);
    4325     1812978 : }

Generated by: LCOV version 1.13