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

Generated by: LCOV version 1.14