LCOV - code coverage report
Current view: top level - src/backend/executor - execExprInterp.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 1941 2073 93.6 %
Date: 2025-04-01 14:15:22 Functions: 81 83 97.6 %
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-2025, 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/miscnodes.h"
      67             : #include "nodes/nodeFuncs.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/json.h"
      75             : #include "utils/jsonfuncs.h"
      76             : #include "utils/jsonpath.h"
      77             : #include "utils/lsyscache.h"
      78             : #include "utils/memutils.h"
      79             : #include "utils/timestamp.h"
      80             : #include "utils/typcache.h"
      81             : #include "utils/xml.h"
      82             : 
      83             : /*
      84             :  * Use computed-goto-based opcode dispatch when computed gotos are available.
      85             :  * But use a separate symbol so that it's easy to adjust locally in this file
      86             :  * for development and testing.
      87             :  */
      88             : #ifdef HAVE_COMPUTED_GOTO
      89             : #define EEO_USE_COMPUTED_GOTO
      90             : #endif                          /* HAVE_COMPUTED_GOTO */
      91             : 
      92             : /*
      93             :  * Macros for opcode dispatch.
      94             :  *
      95             :  * EEO_SWITCH - just hides the switch if not in use.
      96             :  * EEO_CASE - labels the implementation of named expression step type.
      97             :  * EEO_DISPATCH - jump to the implementation of the step type for 'op'.
      98             :  * EEO_OPCODE - compute opcode required by used expression evaluation method.
      99             :  * EEO_NEXT - increment 'op' and jump to correct next step type.
     100             :  * EEO_JUMP - jump to the specified step number within the current expression.
     101             :  */
     102             : #if defined(EEO_USE_COMPUTED_GOTO)
     103             : 
     104             : /* struct for jump target -> opcode lookup table */
     105             : typedef struct ExprEvalOpLookup
     106             : {
     107             :     const void *opcode;
     108             :     ExprEvalOp  op;
     109             : } ExprEvalOpLookup;
     110             : 
     111             : /* to make dispatch_table accessible outside ExecInterpExpr() */
     112             : static const void **dispatch_table = NULL;
     113             : 
     114             : /* jump target -> opcode lookup table */
     115             : static ExprEvalOpLookup reverse_dispatch_table[EEOP_LAST];
     116             : 
     117             : #define EEO_SWITCH()
     118             : #define EEO_CASE(name)      CASE_##name:
     119             : #define EEO_DISPATCH()      goto *((void *) op->opcode)
     120             : #define EEO_OPCODE(opcode)  ((intptr_t) dispatch_table[opcode])
     121             : 
     122             : #else                           /* !EEO_USE_COMPUTED_GOTO */
     123             : 
     124             : #define EEO_SWITCH()        starteval: switch ((ExprEvalOp) op->opcode)
     125             : #define EEO_CASE(name)      case name:
     126             : #define EEO_DISPATCH()      goto starteval
     127             : #define EEO_OPCODE(opcode)  (opcode)
     128             : 
     129             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     130             : 
     131             : #define EEO_NEXT() \
     132             :     do { \
     133             :         op++; \
     134             :         EEO_DISPATCH(); \
     135             :     } while (0)
     136             : 
     137             : #define EEO_JUMP(stepno) \
     138             :     do { \
     139             :         op = &state->steps[stepno]; \
     140             :         EEO_DISPATCH(); \
     141             :     } while (0)
     142             : 
     143             : 
     144             : static Datum ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull);
     145             : static void ExecInitInterpreter(void);
     146             : 
     147             : /* support functions */
     148             : static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype);
     149             : static void CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot);
     150             : static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
     151             :                                     ExprEvalRowtypeCache *rowcache,
     152             :                                     bool *changed);
     153             : static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
     154             :                                ExprContext *econtext, bool checkisnull);
     155             : 
     156             : /* fast-path evaluation functions */
     157             : static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
     158             : static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
     159             : static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
     160             : static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
     161             : static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
     162             : static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
     163             : static Datum ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull);
     164             : static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull);
     165             : static Datum ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     166             : static Datum ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     167             : static Datum ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     168             : static Datum ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     169             : static Datum ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     170             : static Datum ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     171             : static Datum ExecJustHashInnerVarWithIV(ExprState *state, ExprContext *econtext, bool *isnull);
     172             : static Datum ExecJustHashOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
     173             : static Datum ExecJustHashInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
     174             : static Datum ExecJustHashOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     175             : static Datum ExecJustHashInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
     176             : static Datum ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext, bool *isnull);
     177             : 
     178             : /* execution helper functions */
     179             : static pg_attribute_always_inline void ExecAggPlainTransByVal(AggState *aggstate,
     180             :                                                               AggStatePerTrans pertrans,
     181             :                                                               AggStatePerGroup pergroup,
     182             :                                                               ExprContext *aggcontext,
     183             :                                                               int setno);
     184             : static pg_attribute_always_inline void ExecAggPlainTransByRef(AggState *aggstate,
     185             :                                                               AggStatePerTrans pertrans,
     186             :                                                               AggStatePerGroup pergroup,
     187             :                                                               ExprContext *aggcontext,
     188             :                                                               int setno);
     189             : static char *ExecGetJsonValueItemString(JsonbValue *item, bool *resnull);
     190             : 
     191             : /*
     192             :  * ScalarArrayOpExprHashEntry
     193             :  *      Hash table entry type used during EEOP_HASHED_SCALARARRAYOP
     194             :  */
     195             : typedef struct ScalarArrayOpExprHashEntry
     196             : {
     197             :     Datum       key;
     198             :     uint32      status;         /* hash status */
     199             :     uint32      hash;           /* hash value (cached) */
     200             : } ScalarArrayOpExprHashEntry;
     201             : 
     202             : #define SH_PREFIX saophash
     203             : #define SH_ELEMENT_TYPE ScalarArrayOpExprHashEntry
     204             : #define SH_KEY_TYPE Datum
     205             : #define SH_SCOPE static inline
     206             : #define SH_DECLARE
     207             : #include "lib/simplehash.h"
     208             : 
     209             : static bool saop_hash_element_match(struct saophash_hash *tb, Datum key1,
     210             :                                     Datum key2);
     211             : static uint32 saop_element_hash(struct saophash_hash *tb, Datum key);
     212             : 
     213             : /*
     214             :  * ScalarArrayOpExprHashTable
     215             :  *      Hash table for EEOP_HASHED_SCALARARRAYOP
     216             :  */
     217             : typedef struct ScalarArrayOpExprHashTable
     218             : {
     219             :     saophash_hash *hashtab;     /* underlying hash table */
     220             :     struct ExprEvalStep *op;
     221             :     FmgrInfo    hash_finfo;     /* function's lookup data */
     222             :     FunctionCallInfoBaseData hash_fcinfo_data;  /* arguments etc */
     223             : } ScalarArrayOpExprHashTable;
     224             : 
     225             : /* Define parameters for ScalarArrayOpExpr hash table code generation. */
     226             : #define SH_PREFIX saophash
     227             : #define SH_ELEMENT_TYPE ScalarArrayOpExprHashEntry
     228             : #define SH_KEY_TYPE Datum
     229             : #define SH_KEY key
     230             : #define SH_HASH_KEY(tb, key) saop_element_hash(tb, key)
     231             : #define SH_EQUAL(tb, a, b) saop_hash_element_match(tb, a, b)
     232             : #define SH_SCOPE static inline
     233             : #define SH_STORE_HASH
     234             : #define SH_GET_HASH(tb, a) a->hash
     235             : #define SH_DEFINE
     236             : #include "lib/simplehash.h"
     237             : 
     238             : /*
     239             :  * Prepare ExprState for interpreted execution.
     240             :  */
     241             : void
     242     2628502 : ExecReadyInterpretedExpr(ExprState *state)
     243             : {
     244             :     /* Ensure one-time interpreter setup has been done */
     245     2628502 :     ExecInitInterpreter();
     246             : 
     247             :     /* Simple validity checks on expression */
     248             :     Assert(state->steps_len >= 1);
     249             :     Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE_RETURN ||
     250             :            state->steps[state->steps_len - 1].opcode == EEOP_DONE_NO_RETURN);
     251             : 
     252             :     /*
     253             :      * Don't perform redundant initialization. This is unreachable in current
     254             :      * cases, but might be hit if there's additional expression evaluation
     255             :      * methods that rely on interpreted execution to work.
     256             :      */
     257     2628502 :     if (state->flags & EEO_FLAG_INTERPRETER_INITIALIZED)
     258           0 :         return;
     259             : 
     260             :     /*
     261             :      * First time through, check whether attribute matches Var.  Might not be
     262             :      * ok anymore, due to schema changes. We do that by setting up a callback
     263             :      * that does checking on the first call, which then sets the evalfunc
     264             :      * callback to the actual method of execution.
     265             :      */
     266     2628502 :     state->evalfunc = ExecInterpExprStillValid;
     267             : 
     268             :     /* DIRECT_THREADED should not already be set */
     269             :     Assert((state->flags & EEO_FLAG_DIRECT_THREADED) == 0);
     270             : 
     271             :     /*
     272             :      * There shouldn't be any errors before the expression is fully
     273             :      * initialized, and even if so, it'd lead to the expression being
     274             :      * abandoned.  So we can set the flag now and save some code.
     275             :      */
     276     2628502 :     state->flags |= EEO_FLAG_INTERPRETER_INITIALIZED;
     277             : 
     278             :     /*
     279             :      * Select fast-path evalfuncs for very simple expressions.  "Starting up"
     280             :      * the full interpreter is a measurable overhead for these, and these
     281             :      * patterns occur often enough to be worth optimizing.
     282             :      */
     283     2628502 :     if (state->steps_len == 5)
     284             :     {
     285      334784 :         ExprEvalOp  step0 = state->steps[0].opcode;
     286      334784 :         ExprEvalOp  step1 = state->steps[1].opcode;
     287      334784 :         ExprEvalOp  step2 = state->steps[2].opcode;
     288      334784 :         ExprEvalOp  step3 = state->steps[3].opcode;
     289             : 
     290      334784 :         if (step0 == EEOP_INNER_FETCHSOME &&
     291         534 :             step1 == EEOP_HASHDATUM_SET_INITVAL &&
     292         534 :             step2 == EEOP_INNER_VAR &&
     293             :             step3 == EEOP_HASHDATUM_NEXT32)
     294             :         {
     295         534 :             state->evalfunc_private = (void *) ExecJustHashInnerVarWithIV;
     296         534 :             return;
     297             :         }
     298             :     }
     299     2293718 :     else if (state->steps_len == 4)
     300             :     {
     301      133532 :         ExprEvalOp  step0 = state->steps[0].opcode;
     302      133532 :         ExprEvalOp  step1 = state->steps[1].opcode;
     303      133532 :         ExprEvalOp  step2 = state->steps[2].opcode;
     304             : 
     305      133532 :         if (step0 == EEOP_OUTER_FETCHSOME &&
     306       24312 :             step1 == EEOP_OUTER_VAR &&
     307             :             step2 == EEOP_HASHDATUM_FIRST)
     308             :         {
     309        1976 :             state->evalfunc_private = (void *) ExecJustHashOuterVar;
     310        1976 :             return;
     311             :         }
     312      131556 :         else if (step0 == EEOP_INNER_FETCHSOME &&
     313        2524 :                  step1 == EEOP_INNER_VAR &&
     314             :                  step2 == EEOP_HASHDATUM_FIRST)
     315             :         {
     316        2494 :             state->evalfunc_private = (void *) ExecJustHashInnerVar;
     317        2494 :             return;
     318             :         }
     319      129062 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     320       22336 :                  step1 == EEOP_OUTER_VAR &&
     321             :                  step2 == EEOP_HASHDATUM_FIRST_STRICT)
     322             :         {
     323       17944 :             state->evalfunc_private = (void *) ExecJustHashOuterVarStrict;
     324       17944 :             return;
     325             :         }
     326             :     }
     327     2160186 :     else if (state->steps_len == 3)
     328             :     {
     329      420592 :         ExprEvalOp  step0 = state->steps[0].opcode;
     330      420592 :         ExprEvalOp  step1 = state->steps[1].opcode;
     331             : 
     332      420592 :         if (step0 == EEOP_INNER_FETCHSOME &&
     333             :             step1 == EEOP_INNER_VAR)
     334             :         {
     335        7950 :             state->evalfunc_private = ExecJustInnerVar;
     336        7950 :             return;
     337             :         }
     338      412642 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     339             :                  step1 == EEOP_OUTER_VAR)
     340             :         {
     341       10080 :             state->evalfunc_private = ExecJustOuterVar;
     342       10080 :             return;
     343             :         }
     344      402562 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     345             :                  step1 == EEOP_SCAN_VAR)
     346             :         {
     347          30 :             state->evalfunc_private = ExecJustScanVar;
     348          30 :             return;
     349             :         }
     350      402532 :         else if (step0 == EEOP_INNER_FETCHSOME &&
     351             :                  step1 == EEOP_ASSIGN_INNER_VAR)
     352             :         {
     353        7114 :             state->evalfunc_private = ExecJustAssignInnerVar;
     354        7114 :             return;
     355             :         }
     356      395418 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     357             :                  step1 == EEOP_ASSIGN_OUTER_VAR)
     358             :         {
     359       10786 :             state->evalfunc_private = ExecJustAssignOuterVar;
     360       10786 :             return;
     361             :         }
     362      384632 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     363             :                  step1 == EEOP_ASSIGN_SCAN_VAR)
     364             :         {
     365       42084 :             state->evalfunc_private = ExecJustAssignScanVar;
     366       42084 :             return;
     367             :         }
     368      342548 :         else if (step0 == EEOP_CASE_TESTVAL &&
     369         318 :                  (step1 == EEOP_FUNCEXPR_STRICT ||
     370          38 :                   step1 == EEOP_FUNCEXPR_STRICT_1 ||
     371             :                   step1 == EEOP_FUNCEXPR_STRICT_2))
     372             :         {
     373         364 :             state->evalfunc_private = ExecJustApplyFuncToCase;
     374         364 :             return;
     375             :         }
     376      342184 :         else if (step0 == EEOP_INNER_VAR &&
     377             :                  step1 == EEOP_HASHDATUM_FIRST)
     378             :         {
     379        2094 :             state->evalfunc_private = (void *) ExecJustHashInnerVarVirt;
     380        2094 :             return;
     381             :         }
     382      340090 :         else if (step0 == EEOP_OUTER_VAR &&
     383             :                  step1 == EEOP_HASHDATUM_FIRST)
     384             :         {
     385        7964 :             state->evalfunc_private = (void *) ExecJustHashOuterVarVirt;
     386        7964 :             return;
     387             :         }
     388             :     }
     389     1739594 :     else if (state->steps_len == 2)
     390             :     {
     391      972926 :         ExprEvalOp  step0 = state->steps[0].opcode;
     392             : 
     393      972926 :         if (step0 == EEOP_CONST)
     394             :         {
     395      435232 :             state->evalfunc_private = ExecJustConst;
     396      435232 :             return;
     397             :         }
     398      537694 :         else if (step0 == EEOP_INNER_VAR)
     399             :         {
     400         278 :             state->evalfunc_private = ExecJustInnerVarVirt;
     401         278 :             return;
     402             :         }
     403      537416 :         else if (step0 == EEOP_OUTER_VAR)
     404             :         {
     405        2686 :             state->evalfunc_private = ExecJustOuterVarVirt;
     406        2686 :             return;
     407             :         }
     408      534730 :         else if (step0 == EEOP_SCAN_VAR)
     409             :         {
     410           0 :             state->evalfunc_private = ExecJustScanVarVirt;
     411           0 :             return;
     412             :         }
     413      534730 :         else if (step0 == EEOP_ASSIGN_INNER_VAR)
     414             :         {
     415         392 :             state->evalfunc_private = ExecJustAssignInnerVarVirt;
     416         392 :             return;
     417             :         }
     418      534338 :         else if (step0 == EEOP_ASSIGN_OUTER_VAR)
     419             :         {
     420        4092 :             state->evalfunc_private = ExecJustAssignOuterVarVirt;
     421        4092 :             return;
     422             :         }
     423      530246 :         else if (step0 == EEOP_ASSIGN_SCAN_VAR)
     424             :         {
     425        4214 :             state->evalfunc_private = ExecJustAssignScanVarVirt;
     426        4214 :             return;
     427             :         }
     428             :     }
     429             : 
     430             : #if defined(EEO_USE_COMPUTED_GOTO)
     431             : 
     432             :     /*
     433             :      * In the direct-threaded implementation, replace each opcode with the
     434             :      * address to jump to.  (Use ExecEvalStepOp() to get back the opcode.)
     435             :      */
     436    18154548 :     for (int off = 0; off < state->steps_len; off++)
     437             :     {
     438    16084354 :         ExprEvalStep *op = &state->steps[off];
     439             : 
     440    16084354 :         op->opcode = EEO_OPCODE(op->opcode);
     441             :     }
     442             : 
     443     2070194 :     state->flags |= EEO_FLAG_DIRECT_THREADED;
     444             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     445             : 
     446     2070194 :     state->evalfunc_private = ExecInterpExpr;
     447             : }
     448             : 
     449             : 
     450             : /*
     451             :  * Evaluate expression identified by "state" in the execution context
     452             :  * given by "econtext".  *isnull is set to the is-null flag for the result,
     453             :  * and the Datum value is the function result.
     454             :  *
     455             :  * As a special case, return the dispatch table's address if state is NULL.
     456             :  * This is used by ExecInitInterpreter to set up the dispatch_table global.
     457             :  * (Only applies when EEO_USE_COMPUTED_GOTO is defined.)
     458             :  */
     459             : static Datum
     460   171279370 : ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
     461             : {
     462             :     ExprEvalStep *op;
     463             :     TupleTableSlot *resultslot;
     464             :     TupleTableSlot *innerslot;
     465             :     TupleTableSlot *outerslot;
     466             :     TupleTableSlot *scanslot;
     467             :     TupleTableSlot *oldslot;
     468             :     TupleTableSlot *newslot;
     469             : 
     470             :     /*
     471             :      * This array has to be in the same order as enum ExprEvalOp.
     472             :      */
     473             : #if defined(EEO_USE_COMPUTED_GOTO)
     474             :     static const void *const dispatch_table[] = {
     475             :         &&CASE_EEOP_DONE_RETURN,
     476             :         &&CASE_EEOP_DONE_NO_RETURN,
     477             :         &&CASE_EEOP_INNER_FETCHSOME,
     478             :         &&CASE_EEOP_OUTER_FETCHSOME,
     479             :         &&CASE_EEOP_SCAN_FETCHSOME,
     480             :         &&CASE_EEOP_OLD_FETCHSOME,
     481             :         &&CASE_EEOP_NEW_FETCHSOME,
     482             :         &&CASE_EEOP_INNER_VAR,
     483             :         &&CASE_EEOP_OUTER_VAR,
     484             :         &&CASE_EEOP_SCAN_VAR,
     485             :         &&CASE_EEOP_OLD_VAR,
     486             :         &&CASE_EEOP_NEW_VAR,
     487             :         &&CASE_EEOP_INNER_SYSVAR,
     488             :         &&CASE_EEOP_OUTER_SYSVAR,
     489             :         &&CASE_EEOP_SCAN_SYSVAR,
     490             :         &&CASE_EEOP_OLD_SYSVAR,
     491             :         &&CASE_EEOP_NEW_SYSVAR,
     492             :         &&CASE_EEOP_WHOLEROW,
     493             :         &&CASE_EEOP_ASSIGN_INNER_VAR,
     494             :         &&CASE_EEOP_ASSIGN_OUTER_VAR,
     495             :         &&CASE_EEOP_ASSIGN_SCAN_VAR,
     496             :         &&CASE_EEOP_ASSIGN_OLD_VAR,
     497             :         &&CASE_EEOP_ASSIGN_NEW_VAR,
     498             :         &&CASE_EEOP_ASSIGN_TMP,
     499             :         &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
     500             :         &&CASE_EEOP_CONST,
     501             :         &&CASE_EEOP_FUNCEXPR,
     502             :         &&CASE_EEOP_FUNCEXPR_STRICT,
     503             :         &&CASE_EEOP_FUNCEXPR_STRICT_1,
     504             :         &&CASE_EEOP_FUNCEXPR_STRICT_2,
     505             :         &&CASE_EEOP_FUNCEXPR_FUSAGE,
     506             :         &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
     507             :         &&CASE_EEOP_BOOL_AND_STEP_FIRST,
     508             :         &&CASE_EEOP_BOOL_AND_STEP,
     509             :         &&CASE_EEOP_BOOL_AND_STEP_LAST,
     510             :         &&CASE_EEOP_BOOL_OR_STEP_FIRST,
     511             :         &&CASE_EEOP_BOOL_OR_STEP,
     512             :         &&CASE_EEOP_BOOL_OR_STEP_LAST,
     513             :         &&CASE_EEOP_BOOL_NOT_STEP,
     514             :         &&CASE_EEOP_QUAL,
     515             :         &&CASE_EEOP_JUMP,
     516             :         &&CASE_EEOP_JUMP_IF_NULL,
     517             :         &&CASE_EEOP_JUMP_IF_NOT_NULL,
     518             :         &&CASE_EEOP_JUMP_IF_NOT_TRUE,
     519             :         &&CASE_EEOP_NULLTEST_ISNULL,
     520             :         &&CASE_EEOP_NULLTEST_ISNOTNULL,
     521             :         &&CASE_EEOP_NULLTEST_ROWISNULL,
     522             :         &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
     523             :         &&CASE_EEOP_BOOLTEST_IS_TRUE,
     524             :         &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
     525             :         &&CASE_EEOP_BOOLTEST_IS_FALSE,
     526             :         &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
     527             :         &&CASE_EEOP_PARAM_EXEC,
     528             :         &&CASE_EEOP_PARAM_EXTERN,
     529             :         &&CASE_EEOP_PARAM_CALLBACK,
     530             :         &&CASE_EEOP_PARAM_SET,
     531             :         &&CASE_EEOP_CASE_TESTVAL,
     532             :         &&CASE_EEOP_CASE_TESTVAL_EXT,
     533             :         &&CASE_EEOP_MAKE_READONLY,
     534             :         &&CASE_EEOP_IOCOERCE,
     535             :         &&CASE_EEOP_IOCOERCE_SAFE,
     536             :         &&CASE_EEOP_DISTINCT,
     537             :         &&CASE_EEOP_NOT_DISTINCT,
     538             :         &&CASE_EEOP_NULLIF,
     539             :         &&CASE_EEOP_SQLVALUEFUNCTION,
     540             :         &&CASE_EEOP_CURRENTOFEXPR,
     541             :         &&CASE_EEOP_NEXTVALUEEXPR,
     542             :         &&CASE_EEOP_RETURNINGEXPR,
     543             :         &&CASE_EEOP_ARRAYEXPR,
     544             :         &&CASE_EEOP_ARRAYCOERCE,
     545             :         &&CASE_EEOP_ROW,
     546             :         &&CASE_EEOP_ROWCOMPARE_STEP,
     547             :         &&CASE_EEOP_ROWCOMPARE_FINAL,
     548             :         &&CASE_EEOP_MINMAX,
     549             :         &&CASE_EEOP_FIELDSELECT,
     550             :         &&CASE_EEOP_FIELDSTORE_DEFORM,
     551             :         &&CASE_EEOP_FIELDSTORE_FORM,
     552             :         &&CASE_EEOP_SBSREF_SUBSCRIPTS,
     553             :         &&CASE_EEOP_SBSREF_OLD,
     554             :         &&CASE_EEOP_SBSREF_ASSIGN,
     555             :         &&CASE_EEOP_SBSREF_FETCH,
     556             :         &&CASE_EEOP_DOMAIN_TESTVAL,
     557             :         &&CASE_EEOP_DOMAIN_TESTVAL_EXT,
     558             :         &&CASE_EEOP_DOMAIN_NOTNULL,
     559             :         &&CASE_EEOP_DOMAIN_CHECK,
     560             :         &&CASE_EEOP_HASHDATUM_SET_INITVAL,
     561             :         &&CASE_EEOP_HASHDATUM_FIRST,
     562             :         &&CASE_EEOP_HASHDATUM_FIRST_STRICT,
     563             :         &&CASE_EEOP_HASHDATUM_NEXT32,
     564             :         &&CASE_EEOP_HASHDATUM_NEXT32_STRICT,
     565             :         &&CASE_EEOP_CONVERT_ROWTYPE,
     566             :         &&CASE_EEOP_SCALARARRAYOP,
     567             :         &&CASE_EEOP_HASHED_SCALARARRAYOP,
     568             :         &&CASE_EEOP_XMLEXPR,
     569             :         &&CASE_EEOP_JSON_CONSTRUCTOR,
     570             :         &&CASE_EEOP_IS_JSON,
     571             :         &&CASE_EEOP_JSONEXPR_PATH,
     572             :         &&CASE_EEOP_JSONEXPR_COERCION,
     573             :         &&CASE_EEOP_JSONEXPR_COERCION_FINISH,
     574             :         &&CASE_EEOP_AGGREF,
     575             :         &&CASE_EEOP_GROUPING_FUNC,
     576             :         &&CASE_EEOP_WINDOW_FUNC,
     577             :         &&CASE_EEOP_MERGE_SUPPORT_FUNC,
     578             :         &&CASE_EEOP_SUBPLAN,
     579             :         &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
     580             :         &&CASE_EEOP_AGG_DESERIALIZE,
     581             :         &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
     582             :         &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1,
     583             :         &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
     584             :         &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
     585             :         &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
     586             :         &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
     587             :         &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
     588             :         &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
     589             :         &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
     590             :         &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
     591             :         &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
     592             :         &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
     593             :         &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
     594             :         &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
     595             :         &&CASE_EEOP_LAST
     596             :     };
     597             : 
     598             :     StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST + 1,
     599             :                      "dispatch_table out of whack with ExprEvalOp");
     600             : 
     601   171279370 :     if (unlikely(state == NULL))
     602       23438 :         return PointerGetDatum(dispatch_table);
     603             : #else
     604             :     Assert(state != NULL);
     605             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     606             : 
     607             :     /* setup state */
     608   171255932 :     op = state->steps;
     609   171255932 :     resultslot = state->resultslot;
     610   171255932 :     innerslot = econtext->ecxt_innertuple;
     611   171255932 :     outerslot = econtext->ecxt_outertuple;
     612   171255932 :     scanslot = econtext->ecxt_scantuple;
     613   171255932 :     oldslot = econtext->ecxt_oldtuple;
     614   171255932 :     newslot = econtext->ecxt_newtuple;
     615             : 
     616             : #if defined(EEO_USE_COMPUTED_GOTO)
     617   171255932 :     EEO_DISPATCH();
     618             : #endif
     619             : 
     620             :     EEO_SWITCH()
     621             :     {
     622    93885734 :         EEO_CASE(EEOP_DONE_RETURN)
     623             :         {
     624    93885734 :             *isnull = state->resnull;
     625    93885734 :             return state->resvalue;
     626             :         }
     627             : 
     628    77352806 :         EEO_CASE(EEOP_DONE_NO_RETURN)
     629             :         {
     630             :             Assert(isnull == NULL);
     631    77352806 :             return (Datum) 0;
     632             :         }
     633             : 
     634    32804248 :         EEO_CASE(EEOP_INNER_FETCHSOME)
     635             :         {
     636    32804248 :             CheckOpSlotCompatibility(op, innerslot);
     637             : 
     638    32804248 :             slot_getsomeattrs(innerslot, op->d.fetch.last_var);
     639             : 
     640    32804248 :             EEO_NEXT();
     641             :         }
     642             : 
     643    29521078 :         EEO_CASE(EEOP_OUTER_FETCHSOME)
     644             :         {
     645    29521078 :             CheckOpSlotCompatibility(op, outerslot);
     646             : 
     647    29521078 :             slot_getsomeattrs(outerslot, op->d.fetch.last_var);
     648             : 
     649    29521078 :             EEO_NEXT();
     650             :         }
     651             : 
     652    78352614 :         EEO_CASE(EEOP_SCAN_FETCHSOME)
     653             :         {
     654    78352614 :             CheckOpSlotCompatibility(op, scanslot);
     655             : 
     656    78352614 :             slot_getsomeattrs(scanslot, op->d.fetch.last_var);
     657             : 
     658    78352614 :             EEO_NEXT();
     659             :         }
     660             : 
     661         370 :         EEO_CASE(EEOP_OLD_FETCHSOME)
     662             :         {
     663         370 :             CheckOpSlotCompatibility(op, oldslot);
     664             : 
     665         370 :             slot_getsomeattrs(oldslot, op->d.fetch.last_var);
     666             : 
     667         370 :             EEO_NEXT();
     668             :         }
     669             : 
     670         368 :         EEO_CASE(EEOP_NEW_FETCHSOME)
     671             :         {
     672         368 :             CheckOpSlotCompatibility(op, newslot);
     673             : 
     674         368 :             slot_getsomeattrs(newslot, op->d.fetch.last_var);
     675             : 
     676         368 :             EEO_NEXT();
     677             :         }
     678             : 
     679    34586952 :         EEO_CASE(EEOP_INNER_VAR)
     680             :         {
     681    34586952 :             int         attnum = op->d.var.attnum;
     682             : 
     683             :             /*
     684             :              * Since we already extracted all referenced columns from the
     685             :              * tuple with a FETCHSOME step, we can just grab the value
     686             :              * directly out of the slot's decomposed-data arrays.  But let's
     687             :              * have an Assert to check that that did happen.
     688             :              */
     689             :             Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
     690    34586952 :             *op->resvalue = innerslot->tts_values[attnum];
     691    34586952 :             *op->resnull = innerslot->tts_isnull[attnum];
     692             : 
     693    34586952 :             EEO_NEXT();
     694             :         }
     695             : 
     696    62599942 :         EEO_CASE(EEOP_OUTER_VAR)
     697             :         {
     698    62599942 :             int         attnum = op->d.var.attnum;
     699             : 
     700             :             /* See EEOP_INNER_VAR comments */
     701             : 
     702             :             Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
     703    62599942 :             *op->resvalue = outerslot->tts_values[attnum];
     704    62599942 :             *op->resnull = outerslot->tts_isnull[attnum];
     705             : 
     706    62599942 :             EEO_NEXT();
     707             :         }
     708             : 
     709    82272938 :         EEO_CASE(EEOP_SCAN_VAR)
     710             :         {
     711    82272938 :             int         attnum = op->d.var.attnum;
     712             : 
     713             :             /* See EEOP_INNER_VAR comments */
     714             : 
     715             :             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
     716    82272938 :             *op->resvalue = scanslot->tts_values[attnum];
     717    82272938 :             *op->resnull = scanslot->tts_isnull[attnum];
     718             : 
     719    82272938 :             EEO_NEXT();
     720             :         }
     721             : 
     722         282 :         EEO_CASE(EEOP_OLD_VAR)
     723             :         {
     724         282 :             int         attnum = op->d.var.attnum;
     725             : 
     726             :             /* See EEOP_INNER_VAR comments */
     727             : 
     728             :             Assert(attnum >= 0 && attnum < oldslot->tts_nvalid);
     729         282 :             *op->resvalue = oldslot->tts_values[attnum];
     730         282 :             *op->resnull = oldslot->tts_isnull[attnum];
     731             : 
     732         282 :             EEO_NEXT();
     733             :         }
     734             : 
     735         288 :         EEO_CASE(EEOP_NEW_VAR)
     736             :         {
     737         288 :             int         attnum = op->d.var.attnum;
     738             : 
     739             :             /* See EEOP_INNER_VAR comments */
     740             : 
     741             :             Assert(attnum >= 0 && attnum < newslot->tts_nvalid);
     742         288 :             *op->resvalue = newslot->tts_values[attnum];
     743         288 :             *op->resnull = newslot->tts_isnull[attnum];
     744             : 
     745         288 :             EEO_NEXT();
     746             :         }
     747             : 
     748           6 :         EEO_CASE(EEOP_INNER_SYSVAR)
     749             :         {
     750           6 :             ExecEvalSysVar(state, op, econtext, innerslot);
     751           6 :             EEO_NEXT();
     752             :         }
     753             : 
     754          12 :         EEO_CASE(EEOP_OUTER_SYSVAR)
     755             :         {
     756          12 :             ExecEvalSysVar(state, op, econtext, outerslot);
     757          12 :             EEO_NEXT();
     758             :         }
     759             : 
     760     7162238 :         EEO_CASE(EEOP_SCAN_SYSVAR)
     761             :         {
     762     7162238 :             ExecEvalSysVar(state, op, econtext, scanslot);
     763     7162226 :             EEO_NEXT();
     764             :         }
     765             : 
     766         228 :         EEO_CASE(EEOP_OLD_SYSVAR)
     767             :         {
     768         228 :             ExecEvalSysVar(state, op, econtext, oldslot);
     769         228 :             EEO_NEXT();
     770             :         }
     771             : 
     772         228 :         EEO_CASE(EEOP_NEW_SYSVAR)
     773             :         {
     774         228 :             ExecEvalSysVar(state, op, econtext, newslot);
     775         228 :             EEO_NEXT();
     776             :         }
     777             : 
     778       43974 :         EEO_CASE(EEOP_WHOLEROW)
     779             :         {
     780             :             /* too complex for an inline implementation */
     781       43974 :             ExecEvalWholeRowVar(state, op, econtext);
     782             : 
     783       43974 :             EEO_NEXT();
     784             :         }
     785             : 
     786     9213068 :         EEO_CASE(EEOP_ASSIGN_INNER_VAR)
     787             :         {
     788     9213068 :             int         resultnum = op->d.assign_var.resultnum;
     789     9213068 :             int         attnum = op->d.assign_var.attnum;
     790             : 
     791             :             /*
     792             :              * We do not need CheckVarSlotCompatibility here; that was taken
     793             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     794             :              */
     795             :             Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
     796             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     797     9213068 :             resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
     798     9213068 :             resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
     799             : 
     800     9213068 :             EEO_NEXT();
     801             :         }
     802             : 
     803    29010024 :         EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
     804             :         {
     805    29010024 :             int         resultnum = op->d.assign_var.resultnum;
     806    29010024 :             int         attnum = op->d.assign_var.attnum;
     807             : 
     808             :             /*
     809             :              * We do not need CheckVarSlotCompatibility here; that was taken
     810             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     811             :              */
     812             :             Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
     813             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     814    29010024 :             resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
     815    29010024 :             resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
     816             : 
     817    29010024 :             EEO_NEXT();
     818             :         }
     819             : 
     820    62825386 :         EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
     821             :         {
     822    62825386 :             int         resultnum = op->d.assign_var.resultnum;
     823    62825386 :             int         attnum = op->d.assign_var.attnum;
     824             : 
     825             :             /*
     826             :              * We do not need CheckVarSlotCompatibility here; that was taken
     827             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     828             :              */
     829             :             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
     830             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     831    62825386 :             resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
     832    62825386 :             resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
     833             : 
     834    62825386 :             EEO_NEXT();
     835             :         }
     836             : 
     837         852 :         EEO_CASE(EEOP_ASSIGN_OLD_VAR)
     838             :         {
     839         852 :             int         resultnum = op->d.assign_var.resultnum;
     840         852 :             int         attnum = op->d.assign_var.attnum;
     841             : 
     842             :             /*
     843             :              * We do not need CheckVarSlotCompatibility here; that was taken
     844             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     845             :              */
     846             :             Assert(attnum >= 0 && attnum < oldslot->tts_nvalid);
     847             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     848         852 :             resultslot->tts_values[resultnum] = oldslot->tts_values[attnum];
     849         852 :             resultslot->tts_isnull[resultnum] = oldslot->tts_isnull[attnum];
     850             : 
     851         852 :             EEO_NEXT();
     852             :         }
     853             : 
     854         850 :         EEO_CASE(EEOP_ASSIGN_NEW_VAR)
     855             :         {
     856         850 :             int         resultnum = op->d.assign_var.resultnum;
     857         850 :             int         attnum = op->d.assign_var.attnum;
     858             : 
     859             :             /*
     860             :              * We do not need CheckVarSlotCompatibility here; that was taken
     861             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     862             :              */
     863             :             Assert(attnum >= 0 && attnum < newslot->tts_nvalid);
     864             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     865         850 :             resultslot->tts_values[resultnum] = newslot->tts_values[attnum];
     866         850 :             resultslot->tts_isnull[resultnum] = newslot->tts_isnull[attnum];
     867             : 
     868         850 :             EEO_NEXT();
     869             :         }
     870             : 
     871    27318590 :         EEO_CASE(EEOP_ASSIGN_TMP)
     872             :         {
     873    27318590 :             int         resultnum = op->d.assign_tmp.resultnum;
     874             : 
     875             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     876    27318590 :             resultslot->tts_values[resultnum] = state->resvalue;
     877    27318590 :             resultslot->tts_isnull[resultnum] = state->resnull;
     878             : 
     879    27318590 :             EEO_NEXT();
     880             :         }
     881             : 
     882    11356452 :         EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
     883             :         {
     884    11356452 :             int         resultnum = op->d.assign_tmp.resultnum;
     885             : 
     886             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     887    11356452 :             resultslot->tts_isnull[resultnum] = state->resnull;
     888    11356452 :             if (!resultslot->tts_isnull[resultnum])
     889     8166738 :                 resultslot->tts_values[resultnum] =
     890     8166738 :                     MakeExpandedObjectReadOnlyInternal(state->resvalue);
     891             :             else
     892     3189714 :                 resultslot->tts_values[resultnum] = state->resvalue;
     893             : 
     894    11356452 :             EEO_NEXT();
     895             :         }
     896             : 
     897    19655392 :         EEO_CASE(EEOP_CONST)
     898             :         {
     899    19655392 :             *op->resnull = op->d.constval.isnull;
     900    19655392 :             *op->resvalue = op->d.constval.value;
     901             : 
     902    19655392 :             EEO_NEXT();
     903             :         }
     904             : 
     905             :         /*
     906             :          * Function-call implementations. Arguments have previously been
     907             :          * evaluated directly into fcinfo->args.
     908             :          *
     909             :          * As both STRICT checks and function-usage are noticeable performance
     910             :          * wise, and function calls are a very hot-path (they also back
     911             :          * operators!), it's worth having so many separate opcodes.
     912             :          *
     913             :          * Note: the reason for using a temporary variable "d", here and in
     914             :          * other places, is that some compilers think "*op->resvalue = f();"
     915             :          * requires them to evaluate op->resvalue into a register before
     916             :          * calling f(), just in case f() is able to modify op->resvalue
     917             :          * somehow.  The extra line of code can save a useless register spill
     918             :          * and reload across the function call.
     919             :          */
     920     3073120 :         EEO_CASE(EEOP_FUNCEXPR)
     921             :         {
     922     3073120 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     923             :             Datum       d;
     924             : 
     925     3073120 :             fcinfo->isnull = false;
     926     3073120 :             d = op->d.func.fn_addr(fcinfo);
     927     3064072 :             *op->resvalue = d;
     928     3064072 :             *op->resnull = fcinfo->isnull;
     929             : 
     930     3064072 :             EEO_NEXT();
     931             :         }
     932             : 
     933             :         /* strict function call with more than two arguments */
     934      809030 :         EEO_CASE(EEOP_FUNCEXPR_STRICT)
     935             :         {
     936      809030 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     937      809030 :             NullableDatum *args = fcinfo->args;
     938      809030 :             int         nargs = op->d.func.nargs;
     939             :             Datum       d;
     940             : 
     941             :             Assert(nargs > 2);
     942             : 
     943             :             /* strict function, so check for NULL args */
     944     3114312 :             for (int argno = 0; argno < nargs; argno++)
     945             :             {
     946     2351848 :                 if (args[argno].isnull)
     947             :                 {
     948       46566 :                     *op->resnull = true;
     949       46566 :                     goto strictfail;
     950             :                 }
     951             :             }
     952      762464 :             fcinfo->isnull = false;
     953      762464 :             d = op->d.func.fn_addr(fcinfo);
     954      759904 :             *op->resvalue = d;
     955      759904 :             *op->resnull = fcinfo->isnull;
     956             : 
     957      806470 :     strictfail:
     958      806470 :             EEO_NEXT();
     959             :         }
     960             : 
     961             :         /* strict function call with one argument */
     962    14138626 :         EEO_CASE(EEOP_FUNCEXPR_STRICT_1)
     963             :         {
     964    14138626 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     965    14138626 :             NullableDatum *args = fcinfo->args;
     966             : 
     967             :             Assert(op->d.func.nargs == 1);
     968             : 
     969             :             /* strict function, so check for NULL args */
     970    14138626 :             if (args[0].isnull)
     971       46348 :                 *op->resnull = true;
     972             :             else
     973             :             {
     974             :                 Datum       d;
     975             : 
     976    14092278 :                 fcinfo->isnull = false;
     977    14092278 :                 d = op->d.func.fn_addr(fcinfo);
     978    14090978 :                 *op->resvalue = d;
     979    14090978 :                 *op->resnull = fcinfo->isnull;
     980             :             }
     981             : 
     982    14137326 :             EEO_NEXT();
     983             :         }
     984             : 
     985             :         /* strict function call with two arguments */
     986    94139878 :         EEO_CASE(EEOP_FUNCEXPR_STRICT_2)
     987             :         {
     988    94139878 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     989    94139878 :             NullableDatum *args = fcinfo->args;
     990             : 
     991             :             Assert(op->d.func.nargs == 2);
     992             : 
     993             :             /* strict function, so check for NULL args */
     994    94139878 :             if (args[0].isnull || args[1].isnull)
     995     1106710 :                 *op->resnull = true;
     996             :             else
     997             :             {
     998             :                 Datum       d;
     999             : 
    1000    93033168 :                 fcinfo->isnull = false;
    1001    93033168 :                 d = op->d.func.fn_addr(fcinfo);
    1002    93030176 :                 *op->resvalue = d;
    1003    93030176 :                 *op->resnull = fcinfo->isnull;
    1004             :             }
    1005             : 
    1006    94136886 :             EEO_NEXT();
    1007             :         }
    1008             : 
    1009         208 :         EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
    1010             :         {
    1011             :             /* not common enough to inline */
    1012         208 :             ExecEvalFuncExprFusage(state, op, econtext);
    1013             : 
    1014         208 :             EEO_NEXT();
    1015             :         }
    1016             : 
    1017           6 :         EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
    1018             :         {
    1019             :             /* not common enough to inline */
    1020           6 :             ExecEvalFuncExprStrictFusage(state, op, econtext);
    1021             : 
    1022           6 :             EEO_NEXT();
    1023             :         }
    1024             : 
    1025             :         /*
    1026             :          * If any of its clauses is FALSE, an AND's result is FALSE regardless
    1027             :          * of the states of the rest of the clauses, so we can stop evaluating
    1028             :          * and return FALSE immediately.  If none are FALSE and one or more is
    1029             :          * NULL, we return NULL; otherwise we return TRUE.  This makes sense
    1030             :          * when you interpret NULL as "don't know": perhaps one of the "don't
    1031             :          * knows" would have been FALSE if we'd known its value.  Only when
    1032             :          * all the inputs are known to be TRUE can we state confidently that
    1033             :          * the AND's result is TRUE.
    1034             :          */
    1035     1076092 :         EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
    1036             :         {
    1037     1076092 :             *op->d.boolexpr.anynull = false;
    1038             : 
    1039             :             /*
    1040             :              * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the
    1041             :              * same as EEOP_BOOL_AND_STEP - so fall through to that.
    1042             :              */
    1043             : 
    1044             :             /* FALL THROUGH */
    1045             :         }
    1046             : 
    1047     1229674 :         EEO_CASE(EEOP_BOOL_AND_STEP)
    1048             :         {
    1049     1229674 :             if (*op->resnull)
    1050             :             {
    1051        1216 :                 *op->d.boolexpr.anynull = true;
    1052             :             }
    1053     1228458 :             else if (!DatumGetBool(*op->resvalue))
    1054             :             {
    1055             :                 /* result is already set to FALSE, need not change it */
    1056             :                 /* bail out early */
    1057      807278 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
    1058             :             }
    1059             : 
    1060      422396 :             EEO_NEXT();
    1061             :         }
    1062             : 
    1063      268814 :         EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
    1064             :         {
    1065      268814 :             if (*op->resnull)
    1066             :             {
    1067             :                 /* result is already set to NULL, need not change it */
    1068             :             }
    1069      267936 :             else if (!DatumGetBool(*op->resvalue))
    1070             :             {
    1071             :                 /* result is already set to FALSE, need not change it */
    1072             : 
    1073             :                 /*
    1074             :                  * No point jumping early to jumpdone - would be same target
    1075             :                  * (as this is the last argument to the AND expression),
    1076             :                  * except more expensive.
    1077             :                  */
    1078             :             }
    1079      200362 :             else if (*op->d.boolexpr.anynull)
    1080             :             {
    1081         372 :                 *op->resvalue = (Datum) 0;
    1082         372 :                 *op->resnull = true;
    1083             :             }
    1084             :             else
    1085             :             {
    1086             :                 /* result is already set to TRUE, need not change it */
    1087             :             }
    1088             : 
    1089      268814 :             EEO_NEXT();
    1090             :         }
    1091             : 
    1092             :         /*
    1093             :          * If any of its clauses is TRUE, an OR's result is TRUE regardless of
    1094             :          * the states of the rest of the clauses, so we can stop evaluating
    1095             :          * and return TRUE immediately.  If none are TRUE and one or more is
    1096             :          * NULL, we return NULL; otherwise we return FALSE.  This makes sense
    1097             :          * when you interpret NULL as "don't know": perhaps one of the "don't
    1098             :          * knows" would have been TRUE if we'd known its value.  Only when all
    1099             :          * the inputs are known to be FALSE can we state confidently that the
    1100             :          * OR's result is FALSE.
    1101             :          */
    1102     3910274 :         EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
    1103             :         {
    1104     3910274 :             *op->d.boolexpr.anynull = false;
    1105             : 
    1106             :             /*
    1107             :              * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same
    1108             :              * as EEOP_BOOL_OR_STEP - so fall through to that.
    1109             :              */
    1110             : 
    1111             :             /* FALL THROUGH */
    1112             :         }
    1113             : 
    1114     7765994 :         EEO_CASE(EEOP_BOOL_OR_STEP)
    1115             :         {
    1116     7765994 :             if (*op->resnull)
    1117             :             {
    1118      163384 :                 *op->d.boolexpr.anynull = true;
    1119             :             }
    1120     7602610 :             else if (DatumGetBool(*op->resvalue))
    1121             :             {
    1122             :                 /* result is already set to TRUE, need not change it */
    1123             :                 /* bail out early */
    1124      469590 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
    1125             :             }
    1126             : 
    1127     7296404 :             EEO_NEXT();
    1128             :         }
    1129             : 
    1130     3440684 :         EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
    1131             :         {
    1132     3440684 :             if (*op->resnull)
    1133             :             {
    1134             :                 /* result is already set to NULL, need not change it */
    1135             :             }
    1136     3289396 :             else if (DatumGetBool(*op->resvalue))
    1137             :             {
    1138             :                 /* result is already set to TRUE, need not change it */
    1139             : 
    1140             :                 /*
    1141             :                  * No point jumping to jumpdone - would be same target (as
    1142             :                  * this is the last argument to the AND expression), except
    1143             :                  * more expensive.
    1144             :                  */
    1145             :             }
    1146     3219986 :             else if (*op->d.boolexpr.anynull)
    1147             :             {
    1148        6634 :                 *op->resvalue = (Datum) 0;
    1149        6634 :                 *op->resnull = true;
    1150             :             }
    1151             :             else
    1152             :             {
    1153             :                 /* result is already set to FALSE, need not change it */
    1154             :             }
    1155             : 
    1156     3440684 :             EEO_NEXT();
    1157             :         }
    1158             : 
    1159     2705476 :         EEO_CASE(EEOP_BOOL_NOT_STEP)
    1160             :         {
    1161             :             /*
    1162             :              * Evaluation of 'not' is simple... if expr is false, then return
    1163             :              * 'true' and vice versa.  It's safe to do this even on a
    1164             :              * nominally null value, so we ignore resnull; that means that
    1165             :              * NULL in produces NULL out, which is what we want.
    1166             :              */
    1167     2705476 :             *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
    1168             : 
    1169     2705476 :             EEO_NEXT();
    1170             :         }
    1171             : 
    1172    85809976 :         EEO_CASE(EEOP_QUAL)
    1173             :         {
    1174             :             /* simplified version of BOOL_AND_STEP for use by ExecQual() */
    1175             : 
    1176             :             /* If argument (also result) is false or null ... */
    1177    85809976 :             if (*op->resnull ||
    1178    84876346 :                 !DatumGetBool(*op->resvalue))
    1179             :             {
    1180             :                 /* ... bail out early, returning FALSE */
    1181    42197412 :                 *op->resnull = false;
    1182    42197412 :                 *op->resvalue = BoolGetDatum(false);
    1183    42197412 :                 EEO_JUMP(op->d.qualexpr.jumpdone);
    1184             :             }
    1185             : 
    1186             :             /*
    1187             :              * Otherwise, leave the TRUE value in place, in case this is the
    1188             :              * last qual.  Then, TRUE is the correct answer.
    1189             :              */
    1190             : 
    1191    43612564 :             EEO_NEXT();
    1192             :         }
    1193             : 
    1194      369766 :         EEO_CASE(EEOP_JUMP)
    1195             :         {
    1196             :             /* Unconditionally jump to target step */
    1197      369766 :             EEO_JUMP(op->d.jump.jumpdone);
    1198             :         }
    1199             : 
    1200      712186 :         EEO_CASE(EEOP_JUMP_IF_NULL)
    1201             :         {
    1202             :             /* Transfer control if current result is null */
    1203      712186 :             if (*op->resnull)
    1204        3276 :                 EEO_JUMP(op->d.jump.jumpdone);
    1205             : 
    1206      708910 :             EEO_NEXT();
    1207             :         }
    1208             : 
    1209      278470 :         EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
    1210             :         {
    1211             :             /* Transfer control if current result is non-null */
    1212      278470 :             if (!*op->resnull)
    1213      201696 :                 EEO_JUMP(op->d.jump.jumpdone);
    1214             : 
    1215       76774 :             EEO_NEXT();
    1216             :         }
    1217             : 
    1218     2284940 :         EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
    1219             :         {
    1220             :             /* Transfer control if current result is null or false */
    1221     2284940 :             if (*op->resnull || !DatumGetBool(*op->resvalue))
    1222     1798334 :                 EEO_JUMP(op->d.jump.jumpdone);
    1223             : 
    1224      486606 :             EEO_NEXT();
    1225             :         }
    1226             : 
    1227      992882 :         EEO_CASE(EEOP_NULLTEST_ISNULL)
    1228             :         {
    1229      992882 :             *op->resvalue = BoolGetDatum(*op->resnull);
    1230      992882 :             *op->resnull = false;
    1231             : 
    1232      992882 :             EEO_NEXT();
    1233             :         }
    1234             : 
    1235     3314792 :         EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
    1236             :         {
    1237     3314792 :             *op->resvalue = BoolGetDatum(!*op->resnull);
    1238     3314792 :             *op->resnull = false;
    1239             : 
    1240     3314792 :             EEO_NEXT();
    1241             :         }
    1242             : 
    1243         696 :         EEO_CASE(EEOP_NULLTEST_ROWISNULL)
    1244             :         {
    1245             :             /* out of line implementation: too large */
    1246         696 :             ExecEvalRowNull(state, op, econtext);
    1247             : 
    1248         696 :             EEO_NEXT();
    1249             :         }
    1250             : 
    1251         566 :         EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
    1252             :         {
    1253             :             /* out of line implementation: too large */
    1254         566 :             ExecEvalRowNotNull(state, op, econtext);
    1255             : 
    1256         566 :             EEO_NEXT();
    1257             :         }
    1258             : 
    1259             :         /* BooleanTest implementations for all booltesttypes */
    1260             : 
    1261       92432 :         EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
    1262             :         {
    1263       92432 :             if (*op->resnull)
    1264             :             {
    1265       91452 :                 *op->resvalue = BoolGetDatum(false);
    1266       91452 :                 *op->resnull = false;
    1267             :             }
    1268             :             /* else, input value is the correct output as well */
    1269             : 
    1270       92432 :             EEO_NEXT();
    1271             :         }
    1272             : 
    1273        1052 :         EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE)
    1274             :         {
    1275        1052 :             if (*op->resnull)
    1276             :             {
    1277         174 :                 *op->resvalue = BoolGetDatum(true);
    1278         174 :                 *op->resnull = false;
    1279             :             }
    1280             :             else
    1281         878 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
    1282             : 
    1283        1052 :             EEO_NEXT();
    1284             :         }
    1285             : 
    1286         826 :         EEO_CASE(EEOP_BOOLTEST_IS_FALSE)
    1287             :         {
    1288         826 :             if (*op->resnull)
    1289             :             {
    1290         162 :                 *op->resvalue = BoolGetDatum(false);
    1291         162 :                 *op->resnull = false;
    1292             :             }
    1293             :             else
    1294         664 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
    1295             : 
    1296         826 :             EEO_NEXT();
    1297             :         }
    1298             : 
    1299         542 :         EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE)
    1300             :         {
    1301         542 :             if (*op->resnull)
    1302             :             {
    1303          42 :                 *op->resvalue = BoolGetDatum(true);
    1304          42 :                 *op->resnull = false;
    1305             :             }
    1306             :             /* else, input value is the correct output as well */
    1307             : 
    1308         542 :             EEO_NEXT();
    1309             :         }
    1310             : 
    1311     7497346 :         EEO_CASE(EEOP_PARAM_EXEC)
    1312             :         {
    1313             :             /* out of line implementation: too large */
    1314     7497346 :             ExecEvalParamExec(state, op, econtext);
    1315             : 
    1316     7497328 :             EEO_NEXT();
    1317             :         }
    1318             : 
    1319      785228 :         EEO_CASE(EEOP_PARAM_EXTERN)
    1320             :         {
    1321             :             /* out of line implementation: too large */
    1322      785228 :             ExecEvalParamExtern(state, op, econtext);
    1323      785228 :             EEO_NEXT();
    1324             :         }
    1325             : 
    1326      416192 :         EEO_CASE(EEOP_PARAM_CALLBACK)
    1327             :         {
    1328             :             /* allow an extension module to supply a PARAM_EXTERN value */
    1329      416192 :             op->d.cparam.paramfunc(state, op, econtext);
    1330      416186 :             EEO_NEXT();
    1331             :         }
    1332             : 
    1333     1631076 :         EEO_CASE(EEOP_PARAM_SET)
    1334             :         {
    1335             :             /* out of line, unlikely to matter performance-wise */
    1336     1631076 :             ExecEvalParamSet(state, op, econtext);
    1337     1631076 :             EEO_NEXT();
    1338             :         }
    1339             : 
    1340       43806 :         EEO_CASE(EEOP_CASE_TESTVAL)
    1341             :         {
    1342       43806 :             *op->resvalue = *op->d.casetest.value;
    1343       43806 :             *op->resnull = *op->d.casetest.isnull;
    1344             : 
    1345       43806 :             EEO_NEXT();
    1346             :         }
    1347             : 
    1348        6474 :         EEO_CASE(EEOP_CASE_TESTVAL_EXT)
    1349             :         {
    1350        6474 :             *op->resvalue = econtext->caseValue_datum;
    1351        6474 :             *op->resnull = econtext->caseValue_isNull;
    1352             : 
    1353        6474 :             EEO_NEXT();
    1354             :         }
    1355             : 
    1356        4872 :         EEO_CASE(EEOP_MAKE_READONLY)
    1357             :         {
    1358             :             /*
    1359             :              * Force a varlena value that might be read multiple times to R/O
    1360             :              */
    1361        4872 :             if (!*op->d.make_readonly.isnull)
    1362        4808 :                 *op->resvalue =
    1363        4808 :                     MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
    1364        4872 :             *op->resnull = *op->d.make_readonly.isnull;
    1365             : 
    1366        4872 :             EEO_NEXT();
    1367             :         }
    1368             : 
    1369     7430072 :         EEO_CASE(EEOP_IOCOERCE)
    1370             :         {
    1371             :             /*
    1372             :              * Evaluate a CoerceViaIO node.  This can be quite a hot path, so
    1373             :              * inline as much work as possible.  The source value is in our
    1374             :              * result variable.
    1375             :              *
    1376             :              * Also look at ExecEvalCoerceViaIOSafe() if you change anything
    1377             :              * here.
    1378             :              */
    1379             :             char       *str;
    1380             : 
    1381             :             /* call output function (similar to OutputFunctionCall) */
    1382     7430072 :             if (*op->resnull)
    1383             :             {
    1384             :                 /* output functions are not called on nulls */
    1385       61986 :                 str = NULL;
    1386             :             }
    1387             :             else
    1388             :             {
    1389             :                 FunctionCallInfo fcinfo_out;
    1390             : 
    1391     7368086 :                 fcinfo_out = op->d.iocoerce.fcinfo_data_out;
    1392     7368086 :                 fcinfo_out->args[0].value = *op->resvalue;
    1393     7368086 :                 fcinfo_out->args[0].isnull = false;
    1394             : 
    1395     7368086 :                 fcinfo_out->isnull = false;
    1396     7368086 :                 str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
    1397             : 
    1398             :                 /* OutputFunctionCall assumes result isn't null */
    1399             :                 Assert(!fcinfo_out->isnull);
    1400             :             }
    1401             : 
    1402             :             /* call input function (similar to InputFunctionCall) */
    1403     7430072 :             if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
    1404             :             {
    1405             :                 FunctionCallInfo fcinfo_in;
    1406             :                 Datum       d;
    1407             : 
    1408     7368202 :                 fcinfo_in = op->d.iocoerce.fcinfo_data_in;
    1409     7368202 :                 fcinfo_in->args[0].value = PointerGetDatum(str);
    1410     7368202 :                 fcinfo_in->args[0].isnull = *op->resnull;
    1411             :                 /* second and third arguments are already set up */
    1412             : 
    1413     7368202 :                 fcinfo_in->isnull = false;
    1414     7368202 :                 d = FunctionCallInvoke(fcinfo_in);
    1415     7368162 :                 *op->resvalue = d;
    1416             : 
    1417             :                 /* Should get null result if and only if str is NULL */
    1418             :                 if (str == NULL)
    1419             :                 {
    1420             :                     Assert(*op->resnull);
    1421             :                     Assert(fcinfo_in->isnull);
    1422             :                 }
    1423             :                 else
    1424             :                 {
    1425             :                     Assert(!*op->resnull);
    1426             :                     Assert(!fcinfo_in->isnull);
    1427             :                 }
    1428             :             }
    1429             : 
    1430     7430032 :             EEO_NEXT();
    1431             :         }
    1432             : 
    1433           0 :         EEO_CASE(EEOP_IOCOERCE_SAFE)
    1434             :         {
    1435           0 :             ExecEvalCoerceViaIOSafe(state, op);
    1436           0 :             EEO_NEXT();
    1437             :         }
    1438             : 
    1439     1512828 :         EEO_CASE(EEOP_DISTINCT)
    1440             :         {
    1441             :             /*
    1442             :              * IS DISTINCT FROM must evaluate arguments (already done into
    1443             :              * fcinfo->args) to determine whether they are NULL; if either is
    1444             :              * NULL then the result is determined.  If neither is NULL, then
    1445             :              * proceed to evaluate the comparison function, which is just the
    1446             :              * type's standard equality operator.  We need not care whether
    1447             :              * that function is strict.  Because the handling of nulls is
    1448             :              * different, we can't just reuse EEOP_FUNCEXPR.
    1449             :              */
    1450     1512828 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1451             : 
    1452             :             /* check function arguments for NULLness */
    1453     1512828 :             if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
    1454             :             {
    1455             :                 /* Both NULL? Then is not distinct... */
    1456     1169046 :                 *op->resvalue = BoolGetDatum(false);
    1457     1169046 :                 *op->resnull = false;
    1458             :             }
    1459      343782 :             else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
    1460             :             {
    1461             :                 /* Only one is NULL? Then is distinct... */
    1462         360 :                 *op->resvalue = BoolGetDatum(true);
    1463         360 :                 *op->resnull = false;
    1464             :             }
    1465             :             else
    1466             :             {
    1467             :                 /* Neither null, so apply the equality function */
    1468             :                 Datum       eqresult;
    1469             : 
    1470      343422 :                 fcinfo->isnull = false;
    1471      343422 :                 eqresult = op->d.func.fn_addr(fcinfo);
    1472             :                 /* Must invert result of "="; safe to do even if null */
    1473      343422 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
    1474      343422 :                 *op->resnull = fcinfo->isnull;
    1475             :             }
    1476             : 
    1477     1512828 :             EEO_NEXT();
    1478             :         }
    1479             : 
    1480             :         /* see EEOP_DISTINCT for comments, this is just inverted */
    1481    12401476 :         EEO_CASE(EEOP_NOT_DISTINCT)
    1482             :         {
    1483    12401476 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1484             : 
    1485    12401476 :             if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
    1486             :             {
    1487       73344 :                 *op->resvalue = BoolGetDatum(true);
    1488       73344 :                 *op->resnull = false;
    1489             :             }
    1490    12328132 :             else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
    1491             :             {
    1492         292 :                 *op->resvalue = BoolGetDatum(false);
    1493         292 :                 *op->resnull = false;
    1494             :             }
    1495             :             else
    1496             :             {
    1497             :                 Datum       eqresult;
    1498             : 
    1499    12327840 :                 fcinfo->isnull = false;
    1500    12327840 :                 eqresult = op->d.func.fn_addr(fcinfo);
    1501    12327840 :                 *op->resvalue = eqresult;
    1502    12327840 :                 *op->resnull = fcinfo->isnull;
    1503             :             }
    1504             : 
    1505    12401476 :             EEO_NEXT();
    1506             :         }
    1507             : 
    1508        7130 :         EEO_CASE(EEOP_NULLIF)
    1509             :         {
    1510             :             /*
    1511             :              * The arguments are already evaluated into fcinfo->args.
    1512             :              */
    1513        7130 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1514        7130 :             Datum       save_arg0 = fcinfo->args[0].value;
    1515             : 
    1516             :             /* if either argument is NULL they can't be equal */
    1517        7130 :             if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull)
    1518             :             {
    1519             :                 Datum       result;
    1520             : 
    1521             :                 /*
    1522             :                  * If first argument is of varlena type, it might be an
    1523             :                  * expanded datum.  We need to ensure that the value passed to
    1524             :                  * the comparison function is a read-only pointer.  However,
    1525             :                  * if we end by returning the first argument, that will be the
    1526             :                  * original read-write pointer if it was read-write.
    1527             :                  */
    1528        7070 :                 if (op->d.func.make_ro)
    1529         242 :                     fcinfo->args[0].value =
    1530         242 :                         MakeExpandedObjectReadOnlyInternal(save_arg0);
    1531             : 
    1532        7070 :                 fcinfo->isnull = false;
    1533        7070 :                 result = op->d.func.fn_addr(fcinfo);
    1534             : 
    1535             :                 /* if the arguments are equal return null */
    1536        7070 :                 if (!fcinfo->isnull && DatumGetBool(result))
    1537             :                 {
    1538         198 :                     *op->resvalue = (Datum) 0;
    1539         198 :                     *op->resnull = true;
    1540             : 
    1541         198 :                     EEO_NEXT();
    1542             :                 }
    1543             :             }
    1544             : 
    1545             :             /* Arguments aren't equal, so return the first one */
    1546        6932 :             *op->resvalue = save_arg0;
    1547        6932 :             *op->resnull = fcinfo->args[0].isnull;
    1548             : 
    1549        6932 :             EEO_NEXT();
    1550             :         }
    1551             : 
    1552       19046 :         EEO_CASE(EEOP_SQLVALUEFUNCTION)
    1553             :         {
    1554             :             /*
    1555             :              * Doesn't seem worthwhile to have an inline implementation
    1556             :              * efficiency-wise.
    1557             :              */
    1558       19046 :             ExecEvalSQLValueFunction(state, op);
    1559             : 
    1560       19046 :             EEO_NEXT();
    1561             :         }
    1562             : 
    1563           2 :         EEO_CASE(EEOP_CURRENTOFEXPR)
    1564             :         {
    1565             :             /* error invocation uses space, and shouldn't ever occur */
    1566           2 :             ExecEvalCurrentOfExpr(state, op);
    1567             : 
    1568           0 :             EEO_NEXT();
    1569             :         }
    1570             : 
    1571         912 :         EEO_CASE(EEOP_NEXTVALUEEXPR)
    1572             :         {
    1573             :             /*
    1574             :              * Doesn't seem worthwhile to have an inline implementation
    1575             :              * efficiency-wise.
    1576             :              */
    1577         912 :             ExecEvalNextValueExpr(state, op);
    1578             : 
    1579         912 :             EEO_NEXT();
    1580             :         }
    1581             : 
    1582         702 :         EEO_CASE(EEOP_RETURNINGEXPR)
    1583             :         {
    1584             :             /*
    1585             :              * The next op actually evaluates the expression.  If the OLD/NEW
    1586             :              * row doesn't exist, skip that and return NULL.
    1587             :              */
    1588         702 :             if (state->flags & op->d.returningexpr.nullflag)
    1589             :             {
    1590         132 :                 *op->resvalue = (Datum) 0;
    1591         132 :                 *op->resnull = true;
    1592             : 
    1593         132 :                 EEO_JUMP(op->d.returningexpr.jumpdone);
    1594             :             }
    1595             : 
    1596         570 :             EEO_NEXT();
    1597             :         }
    1598             : 
    1599      833992 :         EEO_CASE(EEOP_ARRAYEXPR)
    1600             :         {
    1601             :             /* too complex for an inline implementation */
    1602      833992 :             ExecEvalArrayExpr(state, op);
    1603             : 
    1604      833992 :             EEO_NEXT();
    1605             :         }
    1606             : 
    1607      108332 :         EEO_CASE(EEOP_ARRAYCOERCE)
    1608             :         {
    1609             :             /* too complex for an inline implementation */
    1610      108332 :             ExecEvalArrayCoerce(state, op, econtext);
    1611             : 
    1612      108300 :             EEO_NEXT();
    1613             :         }
    1614             : 
    1615       57712 :         EEO_CASE(EEOP_ROW)
    1616             :         {
    1617             :             /* too complex for an inline implementation */
    1618       57712 :             ExecEvalRow(state, op);
    1619             : 
    1620       57712 :             EEO_NEXT();
    1621             :         }
    1622             : 
    1623      208692 :         EEO_CASE(EEOP_ROWCOMPARE_STEP)
    1624             :         {
    1625      208692 :             FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
    1626             :             Datum       d;
    1627             : 
    1628             :             /* force NULL result if strict fn and NULL input */
    1629      208692 :             if (op->d.rowcompare_step.finfo->fn_strict &&
    1630      208692 :                 (fcinfo->args[0].isnull || fcinfo->args[1].isnull))
    1631             :             {
    1632          18 :                 *op->resnull = true;
    1633          18 :                 EEO_JUMP(op->d.rowcompare_step.jumpnull);
    1634             :             }
    1635             : 
    1636             :             /* Apply comparison function */
    1637      208674 :             fcinfo->isnull = false;
    1638      208674 :             d = op->d.rowcompare_step.fn_addr(fcinfo);
    1639      208674 :             *op->resvalue = d;
    1640             : 
    1641             :             /* force NULL result if NULL function result */
    1642      208674 :             if (fcinfo->isnull)
    1643             :             {
    1644           0 :                 *op->resnull = true;
    1645           0 :                 EEO_JUMP(op->d.rowcompare_step.jumpnull);
    1646             :             }
    1647      208674 :             *op->resnull = false;
    1648             : 
    1649             :             /* If unequal, no need to compare remaining columns */
    1650      208674 :             if (DatumGetInt32(*op->resvalue) != 0)
    1651             :             {
    1652       94512 :                 EEO_JUMP(op->d.rowcompare_step.jumpdone);
    1653             :             }
    1654             : 
    1655      114162 :             EEO_NEXT();
    1656             :         }
    1657             : 
    1658       94512 :         EEO_CASE(EEOP_ROWCOMPARE_FINAL)
    1659             :         {
    1660       94512 :             int32       cmpresult = DatumGetInt32(*op->resvalue);
    1661       94512 :             CompareType cmptype = op->d.rowcompare_final.cmptype;
    1662             : 
    1663       94512 :             *op->resnull = false;
    1664       94512 :             switch (cmptype)
    1665             :             {
    1666             :                     /* EQ and NE cases aren't allowed here */
    1667       34404 :                 case COMPARE_LT:
    1668       34404 :                     *op->resvalue = BoolGetDatum(cmpresult < 0);
    1669       34404 :                     break;
    1670       60000 :                 case COMPARE_LE:
    1671       60000 :                     *op->resvalue = BoolGetDatum(cmpresult <= 0);
    1672       60000 :                     break;
    1673           6 :                 case COMPARE_GE:
    1674           6 :                     *op->resvalue = BoolGetDatum(cmpresult >= 0);
    1675           6 :                     break;
    1676         102 :                 case COMPARE_GT:
    1677         102 :                     *op->resvalue = BoolGetDatum(cmpresult > 0);
    1678         102 :                     break;
    1679           0 :                 default:
    1680             :                     Assert(false);
    1681           0 :                     break;
    1682             :             }
    1683             : 
    1684       94512 :             EEO_NEXT();
    1685             :         }
    1686             : 
    1687       23276 :         EEO_CASE(EEOP_MINMAX)
    1688             :         {
    1689             :             /* too complex for an inline implementation */
    1690       23276 :             ExecEvalMinMax(state, op);
    1691             : 
    1692       23276 :             EEO_NEXT();
    1693             :         }
    1694             : 
    1695      402230 :         EEO_CASE(EEOP_FIELDSELECT)
    1696             :         {
    1697             :             /* too complex for an inline implementation */
    1698      402230 :             ExecEvalFieldSelect(state, op, econtext);
    1699             : 
    1700      402230 :             EEO_NEXT();
    1701             :         }
    1702             : 
    1703         520 :         EEO_CASE(EEOP_FIELDSTORE_DEFORM)
    1704             :         {
    1705             :             /* too complex for an inline implementation */
    1706         520 :             ExecEvalFieldStoreDeForm(state, op, econtext);
    1707             : 
    1708         520 :             EEO_NEXT();
    1709             :         }
    1710             : 
    1711         520 :         EEO_CASE(EEOP_FIELDSTORE_FORM)
    1712             :         {
    1713             :             /* too complex for an inline implementation */
    1714         520 :             ExecEvalFieldStoreForm(state, op, econtext);
    1715             : 
    1716         520 :             EEO_NEXT();
    1717             :         }
    1718             : 
    1719      700000 :         EEO_CASE(EEOP_SBSREF_SUBSCRIPTS)
    1720             :         {
    1721             :             /* Precheck SubscriptingRef subscript(s) */
    1722      700000 :             if (op->d.sbsref_subscript.subscriptfunc(state, op, econtext))
    1723             :             {
    1724      699946 :                 EEO_NEXT();
    1725             :             }
    1726             :             else
    1727             :             {
    1728             :                 /* Subscript is null, short-circuit SubscriptingRef to NULL */
    1729          30 :                 EEO_JUMP(op->d.sbsref_subscript.jumpdone);
    1730             :             }
    1731             :         }
    1732             : 
    1733         276 :         EEO_CASE(EEOP_SBSREF_OLD)
    1734        1902 :             EEO_CASE(EEOP_SBSREF_ASSIGN)
    1735      700218 :             EEO_CASE(EEOP_SBSREF_FETCH)
    1736             :         {
    1737             :             /* Perform a SubscriptingRef fetch or assignment */
    1738      700218 :             op->d.sbsref.subscriptfunc(state, op, econtext);
    1739             : 
    1740      700092 :             EEO_NEXT();
    1741             :         }
    1742             : 
    1743       12116 :         EEO_CASE(EEOP_CONVERT_ROWTYPE)
    1744             :         {
    1745             :             /* too complex for an inline implementation */
    1746       12116 :             ExecEvalConvertRowtype(state, op, econtext);
    1747             : 
    1748       12116 :             EEO_NEXT();
    1749             :         }
    1750             : 
    1751     4429900 :         EEO_CASE(EEOP_SCALARARRAYOP)
    1752             :         {
    1753             :             /* too complex for an inline implementation */
    1754     4429900 :             ExecEvalScalarArrayOp(state, op);
    1755             : 
    1756     4429900 :             EEO_NEXT();
    1757             :         }
    1758             : 
    1759        4806 :         EEO_CASE(EEOP_HASHED_SCALARARRAYOP)
    1760             :         {
    1761             :             /* too complex for an inline implementation */
    1762        4806 :             ExecEvalHashedScalarArrayOp(state, op, econtext);
    1763             : 
    1764        4806 :             EEO_NEXT();
    1765             :         }
    1766             : 
    1767       13688 :         EEO_CASE(EEOP_DOMAIN_TESTVAL)
    1768             :         {
    1769       13688 :             *op->resvalue = *op->d.casetest.value;
    1770       13688 :             *op->resnull = *op->d.casetest.isnull;
    1771             : 
    1772       13688 :             EEO_NEXT();
    1773             :         }
    1774             : 
    1775       68636 :         EEO_CASE(EEOP_DOMAIN_TESTVAL_EXT)
    1776             :         {
    1777       68636 :             *op->resvalue = econtext->domainValue_datum;
    1778       68636 :             *op->resnull = econtext->domainValue_isNull;
    1779             : 
    1780       68636 :             EEO_NEXT();
    1781             :         }
    1782             : 
    1783         378 :         EEO_CASE(EEOP_DOMAIN_NOTNULL)
    1784             :         {
    1785             :             /* too complex for an inline implementation */
    1786         378 :             ExecEvalConstraintNotNull(state, op);
    1787             : 
    1788         272 :             EEO_NEXT();
    1789             :         }
    1790             : 
    1791       13144 :         EEO_CASE(EEOP_DOMAIN_CHECK)
    1792             :         {
    1793             :             /* too complex for an inline implementation */
    1794       13144 :             ExecEvalConstraintCheck(state, op);
    1795             : 
    1796       12716 :             EEO_NEXT();
    1797             :         }
    1798             : 
    1799           0 :         EEO_CASE(EEOP_HASHDATUM_SET_INITVAL)
    1800             :         {
    1801           0 :             *op->resvalue = op->d.hashdatum_initvalue.init_value;
    1802           0 :             *op->resnull = false;
    1803             : 
    1804           0 :             EEO_NEXT();
    1805             :         }
    1806             : 
    1807     2727686 :         EEO_CASE(EEOP_HASHDATUM_FIRST)
    1808             :         {
    1809     2727686 :             FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
    1810             : 
    1811             :             /*
    1812             :              * Save the Datum on non-null inputs, otherwise store 0 so that
    1813             :              * subsequent NEXT32 operations combine with an initialized value.
    1814             :              */
    1815     2727686 :             if (!fcinfo->args[0].isnull)
    1816     2716794 :                 *op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
    1817             :             else
    1818       10892 :                 *op->resvalue = (Datum) 0;
    1819             : 
    1820     2727680 :             *op->resnull = false;
    1821             : 
    1822     2727680 :             EEO_NEXT();
    1823             :         }
    1824             : 
    1825    10901878 :         EEO_CASE(EEOP_HASHDATUM_FIRST_STRICT)
    1826             :         {
    1827    10901878 :             FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
    1828             : 
    1829    10901878 :             if (fcinfo->args[0].isnull)
    1830             :             {
    1831             :                 /*
    1832             :                  * With strict we have the expression return NULL instead of
    1833             :                  * ignoring NULL input values.  We've nothing more to do after
    1834             :                  * finding a NULL.
    1835             :                  */
    1836         522 :                 *op->resnull = true;
    1837         522 :                 *op->resvalue = (Datum) 0;
    1838         522 :                 EEO_JUMP(op->d.hashdatum.jumpdone);
    1839             :             }
    1840             : 
    1841             :             /* execute the hash function and save the resulting value */
    1842    10901356 :             *op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
    1843    10901356 :             *op->resnull = false;
    1844             : 
    1845    10901356 :             EEO_NEXT();
    1846             :         }
    1847             : 
    1848     4019050 :         EEO_CASE(EEOP_HASHDATUM_NEXT32)
    1849             :         {
    1850     4019050 :             FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
    1851             :             uint32      existinghash;
    1852             : 
    1853     4019050 :             existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value);
    1854             :             /* combine successive hash values by rotating */
    1855     4019050 :             existinghash = pg_rotate_left32(existinghash, 1);
    1856             : 
    1857             :             /* leave the hash value alone on NULL inputs */
    1858     4019050 :             if (!fcinfo->args[0].isnull)
    1859             :             {
    1860             :                 uint32      hashvalue;
    1861             : 
    1862             :                 /* execute hash func and combine with previous hash value */
    1863     3913576 :                 hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo));
    1864     3913576 :                 existinghash = existinghash ^ hashvalue;
    1865             :             }
    1866             : 
    1867     4019050 :             *op->resvalue = UInt32GetDatum(existinghash);
    1868     4019050 :             *op->resnull = false;
    1869             : 
    1870     4019050 :             EEO_NEXT();
    1871             :         }
    1872             : 
    1873     1516440 :         EEO_CASE(EEOP_HASHDATUM_NEXT32_STRICT)
    1874             :         {
    1875     1516440 :             FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
    1876             : 
    1877     1516440 :             if (fcinfo->args[0].isnull)
    1878             :             {
    1879             :                 /*
    1880             :                  * With strict we have the expression return NULL instead of
    1881             :                  * ignoring NULL input values.  We've nothing more to do after
    1882             :                  * finding a NULL.
    1883             :                  */
    1884          42 :                 *op->resnull = true;
    1885          42 :                 *op->resvalue = (Datum) 0;
    1886          42 :                 EEO_JUMP(op->d.hashdatum.jumpdone);
    1887             :             }
    1888             :             else
    1889             :             {
    1890             :                 uint32      existinghash;
    1891             :                 uint32      hashvalue;
    1892             : 
    1893     1516398 :                 existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value);
    1894             :                 /* combine successive hash values by rotating */
    1895     1516398 :                 existinghash = pg_rotate_left32(existinghash, 1);
    1896             : 
    1897             :                 /* execute hash func and combine with previous hash value */
    1898     1516398 :                 hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo));
    1899     1516398 :                 *op->resvalue = UInt32GetDatum(existinghash ^ hashvalue);
    1900     1516398 :                 *op->resnull = false;
    1901             :             }
    1902             : 
    1903     1516398 :             EEO_NEXT();
    1904             :         }
    1905             : 
    1906       45230 :         EEO_CASE(EEOP_XMLEXPR)
    1907             :         {
    1908             :             /* too complex for an inline implementation */
    1909       45230 :             ExecEvalXmlExpr(state, op);
    1910             : 
    1911       45128 :             EEO_NEXT();
    1912             :         }
    1913             : 
    1914         702 :         EEO_CASE(EEOP_JSON_CONSTRUCTOR)
    1915             :         {
    1916             :             /* too complex for an inline implementation */
    1917         702 :             ExecEvalJsonConstructor(state, op, econtext);
    1918         616 :             EEO_NEXT();
    1919             :         }
    1920             : 
    1921        2750 :         EEO_CASE(EEOP_IS_JSON)
    1922             :         {
    1923             :             /* too complex for an inline implementation */
    1924        2750 :             ExecEvalJsonIsPredicate(state, op);
    1925             : 
    1926        2750 :             EEO_NEXT();
    1927             :         }
    1928             : 
    1929        5282 :         EEO_CASE(EEOP_JSONEXPR_PATH)
    1930             :         {
    1931             :             /* too complex for an inline implementation */
    1932        5282 :             EEO_JUMP(ExecEvalJsonExprPath(state, op, econtext));
    1933             :         }
    1934             : 
    1935        1806 :         EEO_CASE(EEOP_JSONEXPR_COERCION)
    1936             :         {
    1937             :             /* too complex for an inline implementation */
    1938        1806 :             ExecEvalJsonCoercion(state, op, econtext);
    1939             : 
    1940        1650 :             EEO_NEXT();
    1941             :         }
    1942             : 
    1943        1698 :         EEO_CASE(EEOP_JSONEXPR_COERCION_FINISH)
    1944             :         {
    1945             :             /* too complex for an inline implementation */
    1946        1698 :             ExecEvalJsonCoercionFinish(state, op);
    1947             : 
    1948        1620 :             EEO_NEXT();
    1949             :         }
    1950             : 
    1951      563170 :         EEO_CASE(EEOP_AGGREF)
    1952             :         {
    1953             :             /*
    1954             :              * Returns a Datum whose value is the precomputed aggregate value
    1955             :              * found in the given expression context.
    1956             :              */
    1957      563170 :             int         aggno = op->d.aggref.aggno;
    1958             : 
    1959             :             Assert(econtext->ecxt_aggvalues != NULL);
    1960             : 
    1961      563170 :             *op->resvalue = econtext->ecxt_aggvalues[aggno];
    1962      563170 :             *op->resnull = econtext->ecxt_aggnulls[aggno];
    1963             : 
    1964      563170 :             EEO_NEXT();
    1965             :         }
    1966             : 
    1967        1670 :         EEO_CASE(EEOP_GROUPING_FUNC)
    1968             :         {
    1969             :             /* too complex/uncommon for an inline implementation */
    1970        1670 :             ExecEvalGroupingFunc(state, op);
    1971             : 
    1972        1670 :             EEO_NEXT();
    1973             :         }
    1974             : 
    1975     1090436 :         EEO_CASE(EEOP_WINDOW_FUNC)
    1976             :         {
    1977             :             /*
    1978             :              * Like Aggref, just return a precomputed value from the econtext.
    1979             :              */
    1980     1090436 :             WindowFuncExprState *wfunc = op->d.window_func.wfstate;
    1981             : 
    1982             :             Assert(econtext->ecxt_aggvalues != NULL);
    1983             : 
    1984     1090436 :             *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];
    1985     1090436 :             *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];
    1986             : 
    1987     1090436 :             EEO_NEXT();
    1988             :         }
    1989             : 
    1990         440 :         EEO_CASE(EEOP_MERGE_SUPPORT_FUNC)
    1991             :         {
    1992             :             /* too complex/uncommon for an inline implementation */
    1993         440 :             ExecEvalMergeSupportFunc(state, op, econtext);
    1994             : 
    1995         440 :             EEO_NEXT();
    1996             :         }
    1997             : 
    1998     3375234 :         EEO_CASE(EEOP_SUBPLAN)
    1999             :         {
    2000             :             /* too complex for an inline implementation */
    2001     3375234 :             ExecEvalSubPlan(state, op, econtext);
    2002             : 
    2003     3375228 :             EEO_NEXT();
    2004             :         }
    2005             : 
    2006             :         /* evaluate a strict aggregate deserialization function */
    2007         426 :         EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
    2008             :         {
    2009             :             /* Don't call a strict deserialization function with NULL input */
    2010         426 :             if (op->d.agg_deserialize.fcinfo_data->args[0].isnull)
    2011         120 :                 EEO_JUMP(op->d.agg_deserialize.jumpnull);
    2012             : 
    2013             :             /* fallthrough */
    2014             :         }
    2015             : 
    2016             :         /* evaluate aggregate deserialization function (non-strict portion) */
    2017         306 :         EEO_CASE(EEOP_AGG_DESERIALIZE)
    2018             :         {
    2019         306 :             FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
    2020         306 :             AggState   *aggstate = castNode(AggState, state->parent);
    2021             :             MemoryContext oldContext;
    2022             : 
    2023             :             /*
    2024             :              * We run the deserialization functions in per-input-tuple memory
    2025             :              * context.
    2026             :              */
    2027         306 :             oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    2028         306 :             fcinfo->isnull = false;
    2029         306 :             *op->resvalue = FunctionCallInvoke(fcinfo);
    2030         306 :             *op->resnull = fcinfo->isnull;
    2031         306 :             MemoryContextSwitchTo(oldContext);
    2032             : 
    2033         306 :             EEO_NEXT();
    2034             :         }
    2035             : 
    2036             :         /*
    2037             :          * Check that a strict aggregate transition / combination function's
    2038             :          * input is not NULL.
    2039             :          */
    2040             : 
    2041             :         /* when checking more than one argument */
    2042      240582 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
    2043             :         {
    2044      240582 :             NullableDatum *args = op->d.agg_strict_input_check.args;
    2045      240582 :             int         nargs = op->d.agg_strict_input_check.nargs;
    2046             : 
    2047             :             Assert(nargs > 1);
    2048             : 
    2049      721830 :             for (int argno = 0; argno < nargs; argno++)
    2050             :             {
    2051      481290 :                 if (args[argno].isnull)
    2052          42 :                     EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    2053             :             }
    2054      240540 :             EEO_NEXT();
    2055             :         }
    2056             : 
    2057             :         /* special case for just one argument */
    2058     5655424 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1)
    2059             :         {
    2060     5655424 :             NullableDatum *args = op->d.agg_strict_input_check.args;
    2061     5655424 :             PG_USED_FOR_ASSERTS_ONLY int nargs = op->d.agg_strict_input_check.nargs;
    2062             : 
    2063             :             Assert(nargs == 1);
    2064             : 
    2065     5655424 :             if (args[0].isnull)
    2066      158424 :                 EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    2067     5497000 :             EEO_NEXT();
    2068             :         }
    2069             : 
    2070      376704 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
    2071             :         {
    2072      376704 :             bool       *nulls = op->d.agg_strict_input_check.nulls;
    2073      376704 :             int         nargs = op->d.agg_strict_input_check.nargs;
    2074             : 
    2075      708408 :             for (int argno = 0; argno < nargs; argno++)
    2076             :             {
    2077      376704 :                 if (nulls[argno])
    2078       45000 :                     EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    2079             :             }
    2080      331704 :             EEO_NEXT();
    2081             :         }
    2082             : 
    2083             :         /*
    2084             :          * Check for a NULL pointer to the per-group states.
    2085             :          */
    2086             : 
    2087     1192848 :         EEO_CASE(EEOP_AGG_PLAIN_PERGROUP_NULLCHECK)
    2088             :         {
    2089     1192848 :             AggState   *aggstate = castNode(AggState, state->parent);
    2090     1192848 :             AggStatePerGroup pergroup_allaggs =
    2091     1192848 :                 aggstate->all_pergroups[op->d.agg_plain_pergroup_nullcheck.setoff];
    2092             : 
    2093     1192848 :             if (pergroup_allaggs == NULL)
    2094      570120 :                 EEO_JUMP(op->d.agg_plain_pergroup_nullcheck.jumpnull);
    2095             : 
    2096      622728 :             EEO_NEXT();
    2097             :         }
    2098             : 
    2099             :         /*
    2100             :          * Different types of aggregate transition functions are implemented
    2101             :          * as different types of steps, to avoid incurring unnecessary
    2102             :          * overhead.  There's a step type for each valid combination of having
    2103             :          * a by value / by reference transition type, [not] needing to the
    2104             :          * initialize the transition value for the first row in a group from
    2105             :          * input, and [not] strict transition function.
    2106             :          *
    2107             :          * Could optimize further by splitting off by-reference for
    2108             :          * fixed-length types, but currently that doesn't seem worth it.
    2109             :          */
    2110             : 
    2111     1572178 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
    2112             :         {
    2113     1572178 :             AggState   *aggstate = castNode(AggState, state->parent);
    2114     1572178 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2115     1572178 :             AggStatePerGroup pergroup =
    2116     1572178 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2117             : 
    2118             :             Assert(pertrans->transtypeByVal);
    2119             : 
    2120     1572178 :             if (pergroup->noTransValue)
    2121             :             {
    2122             :                 /* If transValue has not yet been initialized, do so now. */
    2123        8876 :                 ExecAggInitGroup(aggstate, pertrans, pergroup,
    2124             :                                  op->d.agg_trans.aggcontext);
    2125             :                 /* copied trans value from input, done this round */
    2126             :             }
    2127     1563302 :             else if (likely(!pergroup->transValueIsNull))
    2128             :             {
    2129             :                 /* invoke transition function, unless prevented by strictness */
    2130     1563302 :                 ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    2131             :                                        op->d.agg_trans.aggcontext,
    2132             :                                        op->d.agg_trans.setno);
    2133             :             }
    2134             : 
    2135     1572178 :             EEO_NEXT();
    2136             :         }
    2137             : 
    2138             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2139    18515980 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL)
    2140             :         {
    2141    18515980 :             AggState   *aggstate = castNode(AggState, state->parent);
    2142    18515980 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2143    18515980 :             AggStatePerGroup pergroup =
    2144    18515980 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2145             : 
    2146             :             Assert(pertrans->transtypeByVal);
    2147             : 
    2148    18515980 :             if (likely(!pergroup->transValueIsNull))
    2149    18455962 :                 ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    2150             :                                        op->d.agg_trans.aggcontext,
    2151             :                                        op->d.agg_trans.setno);
    2152             : 
    2153    18515980 :             EEO_NEXT();
    2154             :         }
    2155             : 
    2156             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2157    10538290 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)
    2158             :         {
    2159    10538290 :             AggState   *aggstate = castNode(AggState, state->parent);
    2160    10538290 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2161    10538290 :             AggStatePerGroup pergroup =
    2162    10538290 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2163             : 
    2164             :             Assert(pertrans->transtypeByVal);
    2165             : 
    2166    10538290 :             ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    2167             :                                    op->d.agg_trans.aggcontext,
    2168             :                                    op->d.agg_trans.setno);
    2169             : 
    2170    10538218 :             EEO_NEXT();
    2171             :         }
    2172             : 
    2173             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2174      195656 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
    2175             :         {
    2176      195656 :             AggState   *aggstate = castNode(AggState, state->parent);
    2177      195656 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2178      195656 :             AggStatePerGroup pergroup =
    2179      195656 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2180             : 
    2181             :             Assert(!pertrans->transtypeByVal);
    2182             : 
    2183      195656 :             if (pergroup->noTransValue)
    2184         878 :                 ExecAggInitGroup(aggstate, pertrans, pergroup,
    2185             :                                  op->d.agg_trans.aggcontext);
    2186      194778 :             else if (likely(!pergroup->transValueIsNull))
    2187      194778 :                 ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    2188             :                                        op->d.agg_trans.aggcontext,
    2189             :                                        op->d.agg_trans.setno);
    2190             : 
    2191      195650 :             EEO_NEXT();
    2192             :         }
    2193             : 
    2194             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2195     2617500 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
    2196             :         {
    2197     2617500 :             AggState   *aggstate = castNode(AggState, state->parent);
    2198     2617500 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2199     2617500 :             AggStatePerGroup pergroup =
    2200     2617500 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2201             : 
    2202             :             Assert(!pertrans->transtypeByVal);
    2203             : 
    2204     2617500 :             if (likely(!pergroup->transValueIsNull))
    2205     2617500 :                 ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    2206             :                                        op->d.agg_trans.aggcontext,
    2207             :                                        op->d.agg_trans.setno);
    2208     2617500 :             EEO_NEXT();
    2209             :         }
    2210             : 
    2211             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2212       24126 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF)
    2213             :         {
    2214       24126 :             AggState   *aggstate = castNode(AggState, state->parent);
    2215       24126 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2216       24126 :             AggStatePerGroup pergroup =
    2217       24126 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2218             : 
    2219             :             Assert(!pertrans->transtypeByVal);
    2220             : 
    2221       24126 :             ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    2222             :                                    op->d.agg_trans.aggcontext,
    2223             :                                    op->d.agg_trans.setno);
    2224             : 
    2225       24126 :             EEO_NEXT();
    2226             :         }
    2227             : 
    2228      365850 :         EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_SINGLE)
    2229             :         {
    2230      365850 :             AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
    2231      365850 :             AggState   *aggstate = castNode(AggState, state->parent);
    2232             : 
    2233      365850 :             if (ExecEvalPreOrderedDistinctSingle(aggstate, pertrans))
    2234      101956 :                 EEO_NEXT();
    2235             :             else
    2236      263894 :                 EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
    2237             :         }
    2238             : 
    2239         720 :         EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_MULTI)
    2240             :         {
    2241         720 :             AggState   *aggstate = castNode(AggState, state->parent);
    2242         720 :             AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
    2243             : 
    2244         720 :             if (ExecEvalPreOrderedDistinctMulti(aggstate, pertrans))
    2245         312 :                 EEO_NEXT();
    2246             :             else
    2247         408 :                 EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
    2248             :         }
    2249             : 
    2250             :         /* process single-column ordered aggregate datum */
    2251      844384 :         EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM)
    2252             :         {
    2253             :             /* too complex for an inline implementation */
    2254      844384 :             ExecEvalAggOrderedTransDatum(state, op, econtext);
    2255             : 
    2256      844384 :             EEO_NEXT();
    2257             :         }
    2258             : 
    2259             :         /* process multi-column ordered aggregate tuple */
    2260         180 :         EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE)
    2261             :         {
    2262             :             /* too complex for an inline implementation */
    2263         180 :             ExecEvalAggOrderedTransTuple(state, op, econtext);
    2264             : 
    2265         180 :             EEO_NEXT();
    2266             :         }
    2267             : 
    2268           0 :         EEO_CASE(EEOP_LAST)
    2269             :         {
    2270             :             /* unreachable */
    2271             :             Assert(false);
    2272           0 :             goto out_error;
    2273             :         }
    2274             :     }
    2275             : 
    2276           0 : out_error:
    2277           0 :     pg_unreachable();
    2278             :     return (Datum) 0;
    2279             : }
    2280             : 
    2281             : /*
    2282             :  * Expression evaluation callback that performs extra checks before executing
    2283             :  * the expression. Declared extern so other methods of execution can use it
    2284             :  * too.
    2285             :  */
    2286             : Datum
    2287     1982442 : ExecInterpExprStillValid(ExprState *state, ExprContext *econtext, bool *isNull)
    2288             : {
    2289             :     /*
    2290             :      * First time through, check whether attribute matches Var.  Might not be
    2291             :      * ok anymore, due to schema changes.
    2292             :      */
    2293     1982442 :     CheckExprStillValid(state, econtext);
    2294             : 
    2295             :     /* skip the check during further executions */
    2296     1982418 :     state->evalfunc = (ExprStateEvalFunc) state->evalfunc_private;
    2297             : 
    2298             :     /* and actually execute */
    2299     1982418 :     return state->evalfunc(state, econtext, isNull);
    2300             : }
    2301             : 
    2302             : /*
    2303             :  * Check that an expression is still valid in the face of potential schema
    2304             :  * changes since the plan has been created.
    2305             :  */
    2306             : void
    2307     1987924 : CheckExprStillValid(ExprState *state, ExprContext *econtext)
    2308             : {
    2309             :     TupleTableSlot *innerslot;
    2310             :     TupleTableSlot *outerslot;
    2311             :     TupleTableSlot *scanslot;
    2312             :     TupleTableSlot *oldslot;
    2313             :     TupleTableSlot *newslot;
    2314             : 
    2315     1987924 :     innerslot = econtext->ecxt_innertuple;
    2316     1987924 :     outerslot = econtext->ecxt_outertuple;
    2317     1987924 :     scanslot = econtext->ecxt_scantuple;
    2318     1987924 :     oldslot = econtext->ecxt_oldtuple;
    2319     1987924 :     newslot = econtext->ecxt_newtuple;
    2320             : 
    2321    11701230 :     for (int i = 0; i < state->steps_len; i++)
    2322             :     {
    2323     9713330 :         ExprEvalStep *op = &state->steps[i];
    2324             : 
    2325     9713330 :         switch (ExecEvalStepOp(state, op))
    2326             :         {
    2327      132820 :             case EEOP_INNER_VAR:
    2328             :                 {
    2329      132820 :                     int         attnum = op->d.var.attnum;
    2330             : 
    2331      132820 :                     CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
    2332      132820 :                     break;
    2333             :                 }
    2334             : 
    2335      346816 :             case EEOP_OUTER_VAR:
    2336             :                 {
    2337      346816 :                     int         attnum = op->d.var.attnum;
    2338             : 
    2339      346816 :                     CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
    2340      346816 :                     break;
    2341             :                 }
    2342             : 
    2343      381172 :             case EEOP_SCAN_VAR:
    2344             :                 {
    2345      381172 :                     int         attnum = op->d.var.attnum;
    2346             : 
    2347      381172 :                     CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
    2348      381148 :                     break;
    2349             :                 }
    2350             : 
    2351         174 :             case EEOP_OLD_VAR:
    2352             :                 {
    2353         174 :                     int         attnum = op->d.var.attnum;
    2354             : 
    2355         174 :                     CheckVarSlotCompatibility(oldslot, attnum + 1, op->d.var.vartype);
    2356         174 :                     break;
    2357             :                 }
    2358             : 
    2359         174 :             case EEOP_NEW_VAR:
    2360             :                 {
    2361         174 :                     int         attnum = op->d.var.attnum;
    2362             : 
    2363         174 :                     CheckVarSlotCompatibility(newslot, attnum + 1, op->d.var.vartype);
    2364         174 :                     break;
    2365             :                 }
    2366     8852174 :             default:
    2367     8852174 :                 break;
    2368             :         }
    2369             :     }
    2370     1987900 : }
    2371             : 
    2372             : /*
    2373             :  * Check whether a user attribute in a slot can be referenced by a Var
    2374             :  * expression.  This should succeed unless there have been schema changes
    2375             :  * since the expression tree has been created.
    2376             :  */
    2377             : static void
    2378      861156 : CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
    2379             : {
    2380             :     /*
    2381             :      * What we have to check for here is the possibility of an attribute
    2382             :      * having been dropped or changed in type since the plan tree was created.
    2383             :      * Ideally the plan will get invalidated and not re-used, but just in
    2384             :      * case, we keep these defenses.  Fortunately it's sufficient to check
    2385             :      * once on the first time through.
    2386             :      *
    2387             :      * Note: ideally we'd check typmod as well as typid, but that seems
    2388             :      * impractical at the moment: in many cases the tupdesc will have been
    2389             :      * generated by ExecTypeFromTL(), and that can't guarantee to generate an
    2390             :      * accurate typmod in all cases, because some expression node types don't
    2391             :      * carry typmod.  Fortunately, for precisely that reason, there should be
    2392             :      * no places with a critical dependency on the typmod of a value.
    2393             :      *
    2394             :      * System attributes don't require checking since their types never
    2395             :      * change.
    2396             :      */
    2397      861156 :     if (attnum > 0)
    2398             :     {
    2399      861156 :         TupleDesc   slot_tupdesc = slot->tts_tupleDescriptor;
    2400             :         Form_pg_attribute attr;
    2401             : 
    2402      861156 :         if (attnum > slot_tupdesc->natts) /* should never happen */
    2403           0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    2404             :                  attnum, slot_tupdesc->natts);
    2405             : 
    2406      861156 :         attr = TupleDescAttr(slot_tupdesc, attnum - 1);
    2407             : 
    2408             :         /* Internal error: somebody forgot to expand it. */
    2409      861156 :         if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
    2410           0 :             elog(ERROR, "unexpected virtual generated column reference");
    2411             : 
    2412      861156 :         if (attr->attisdropped)
    2413          12 :             ereport(ERROR,
    2414             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    2415             :                      errmsg("attribute %d of type %s has been dropped",
    2416             :                             attnum, format_type_be(slot_tupdesc->tdtypeid))));
    2417             : 
    2418      861144 :         if (vartype != attr->atttypid)
    2419          12 :             ereport(ERROR,
    2420             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    2421             :                      errmsg("attribute %d of type %s has wrong type",
    2422             :                             attnum, format_type_be(slot_tupdesc->tdtypeid)),
    2423             :                      errdetail("Table has type %s, but query expects %s.",
    2424             :                                format_type_be(attr->atttypid),
    2425             :                                format_type_be(vartype))));
    2426             :     }
    2427      861132 : }
    2428             : 
    2429             : /*
    2430             :  * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
    2431             :  */
    2432             : static void
    2433   169742080 : CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot)
    2434             : {
    2435             : #ifdef USE_ASSERT_CHECKING
    2436             :     /* there's nothing to check */
    2437             :     if (!op->d.fetch.fixed)
    2438             :         return;
    2439             : 
    2440             :     /*
    2441             :      * Should probably fixed at some point, but for now it's easier to allow
    2442             :      * buffer and heap tuples to be used interchangeably.
    2443             :      */
    2444             :     if (slot->tts_ops == &TTSOpsBufferHeapTuple &&
    2445             :         op->d.fetch.kind == &TTSOpsHeapTuple)
    2446             :         return;
    2447             :     if (slot->tts_ops == &TTSOpsHeapTuple &&
    2448             :         op->d.fetch.kind == &TTSOpsBufferHeapTuple)
    2449             :         return;
    2450             : 
    2451             :     /*
    2452             :      * At the moment we consider it OK if a virtual slot is used instead of a
    2453             :      * specific type of slot, as a virtual slot never needs to be deformed.
    2454             :      */
    2455             :     if (slot->tts_ops == &TTSOpsVirtual)
    2456             :         return;
    2457             : 
    2458             :     Assert(op->d.fetch.kind == slot->tts_ops);
    2459             : #endif
    2460   169742080 : }
    2461             : 
    2462             : /*
    2463             :  * get_cached_rowtype: utility function to lookup a rowtype tupdesc
    2464             :  *
    2465             :  * type_id, typmod: identity of the rowtype
    2466             :  * rowcache: space for caching identity info
    2467             :  *      (rowcache->cacheptr must be initialized to NULL)
    2468             :  * changed: if not NULL, *changed is set to true on any update
    2469             :  *
    2470             :  * The returned TupleDesc is not guaranteed pinned; caller must pin it
    2471             :  * to use it across any operation that might incur cache invalidation,
    2472             :  * including for example detoasting of input tuples.
    2473             :  * (The TupleDesc is always refcounted, so just use IncrTupleDescRefCount.)
    2474             :  *
    2475             :  * NOTE: because composite types can change contents, we must be prepared
    2476             :  * to re-do this during any node execution; cannot call just once during
    2477             :  * expression initialization.
    2478             :  */
    2479             : static TupleDesc
    2480      428254 : get_cached_rowtype(Oid type_id, int32 typmod,
    2481             :                    ExprEvalRowtypeCache *rowcache,
    2482             :                    bool *changed)
    2483             : {
    2484      428254 :     if (type_id != RECORDOID)
    2485             :     {
    2486             :         /*
    2487             :          * It's a named composite type, so use the regular typcache.  Do a
    2488             :          * lookup first time through, or if the composite type changed.  Note:
    2489             :          * "tupdesc_id == 0" may look redundant, but it protects against the
    2490             :          * admittedly-theoretical possibility that type_id was RECORDOID the
    2491             :          * last time through, so that the cacheptr isn't TypeCacheEntry *.
    2492             :          */
    2493       44416 :         TypeCacheEntry *typentry = (TypeCacheEntry *) rowcache->cacheptr;
    2494             : 
    2495       44416 :         if (unlikely(typentry == NULL ||
    2496             :                      rowcache->tupdesc_id == 0 ||
    2497             :                      typentry->tupDesc_identifier != rowcache->tupdesc_id))
    2498             :         {
    2499        6752 :             typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
    2500        6752 :             if (typentry->tupDesc == NULL)
    2501           0 :                 ereport(ERROR,
    2502             :                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2503             :                          errmsg("type %s is not composite",
    2504             :                                 format_type_be(type_id))));
    2505        6752 :             rowcache->cacheptr = typentry;
    2506        6752 :             rowcache->tupdesc_id = typentry->tupDesc_identifier;
    2507        6752 :             if (changed)
    2508         960 :                 *changed = true;
    2509             :         }
    2510       44416 :         return typentry->tupDesc;
    2511             :     }
    2512             :     else
    2513             :     {
    2514             :         /*
    2515             :          * A RECORD type, once registered, doesn't change for the life of the
    2516             :          * backend.  So we don't need a typcache entry as such, which is good
    2517             :          * because there isn't one.  It's possible that the caller is asking
    2518             :          * about a different type than before, though.
    2519             :          */
    2520      383838 :         TupleDesc   tupDesc = (TupleDesc) rowcache->cacheptr;
    2521             : 
    2522      383838 :         if (unlikely(tupDesc == NULL ||
    2523             :                      rowcache->tupdesc_id != 0 ||
    2524             :                      type_id != tupDesc->tdtypeid ||
    2525             :                      typmod != tupDesc->tdtypmod))
    2526             :         {
    2527        2208 :             tupDesc = lookup_rowtype_tupdesc(type_id, typmod);
    2528             :             /* Drop pin acquired by lookup_rowtype_tupdesc */
    2529        2208 :             ReleaseTupleDesc(tupDesc);
    2530        2208 :             rowcache->cacheptr = tupDesc;
    2531        2208 :             rowcache->tupdesc_id = 0;    /* not a valid value for non-RECORD */
    2532        2208 :             if (changed)
    2533           0 :                 *changed = true;
    2534             :         }
    2535      383838 :         return tupDesc;
    2536             :     }
    2537             : }
    2538             : 
    2539             : 
    2540             : /*
    2541             :  * Fast-path functions, for very simple expressions
    2542             :  */
    2543             : 
    2544             : /* implementation of ExecJust(Inner|Outer|Scan)Var */
    2545             : static pg_attribute_always_inline Datum
    2546     6921180 : ExecJustVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2547             : {
    2548     6921180 :     ExprEvalStep *op = &state->steps[1];
    2549     6921180 :     int         attnum = op->d.var.attnum + 1;
    2550             : 
    2551     6921180 :     CheckOpSlotCompatibility(&state->steps[0], slot);
    2552             : 
    2553             :     /*
    2554             :      * Since we use slot_getattr(), we don't need to implement the FETCHSOME
    2555             :      * step explicitly, and we also needn't Assert that the attnum is in range
    2556             :      * --- slot_getattr() will take care of any problems.
    2557             :      */
    2558     6921180 :     return slot_getattr(slot, attnum, isnull);
    2559             : }
    2560             : 
    2561             : /* Simple reference to inner Var */
    2562             : static Datum
    2563     4563736 : ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2564             : {
    2565     4563736 :     return ExecJustVarImpl(state, econtext->ecxt_innertuple, isnull);
    2566             : }
    2567             : 
    2568             : /* Simple reference to outer Var */
    2569             : static Datum
    2570     2355412 : ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2571             : {
    2572     2355412 :     return ExecJustVarImpl(state, econtext->ecxt_outertuple, isnull);
    2573             : }
    2574             : 
    2575             : /* Simple reference to scan Var */
    2576             : static Datum
    2577        2032 : ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2578             : {
    2579        2032 :     return ExecJustVarImpl(state, econtext->ecxt_scantuple, isnull);
    2580             : }
    2581             : 
    2582             : /* implementation of ExecJustAssign(Inner|Outer|Scan)Var */
    2583             : static pg_attribute_always_inline Datum
    2584     9248458 : ExecJustAssignVarImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
    2585             : {
    2586     9248458 :     ExprEvalStep *op = &state->steps[1];
    2587     9248458 :     int         attnum = op->d.assign_var.attnum + 1;
    2588     9248458 :     int         resultnum = op->d.assign_var.resultnum;
    2589     9248458 :     TupleTableSlot *outslot = state->resultslot;
    2590             : 
    2591     9248458 :     CheckOpSlotCompatibility(&state->steps[0], inslot);
    2592             : 
    2593             :     /*
    2594             :      * We do not need CheckVarSlotCompatibility here; that was taken care of
    2595             :      * at compilation time.
    2596             :      *
    2597             :      * Since we use slot_getattr(), we don't need to implement the FETCHSOME
    2598             :      * step explicitly, and we also needn't Assert that the attnum is in range
    2599             :      * --- slot_getattr() will take care of any problems.  Nonetheless, check
    2600             :      * that resultnum is in range.
    2601             :      */
    2602             :     Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
    2603    18496916 :     outslot->tts_values[resultnum] =
    2604     9248458 :         slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
    2605     9248458 :     return 0;
    2606             : }
    2607             : 
    2608             : /* Evaluate inner Var and assign to appropriate column of result tuple */
    2609             : static Datum
    2610       65798 : ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2611             : {
    2612       65798 :     return ExecJustAssignVarImpl(state, econtext->ecxt_innertuple, isnull);
    2613             : }
    2614             : 
    2615             : /* Evaluate outer Var and assign to appropriate column of result tuple */
    2616             : static Datum
    2617      385274 : ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2618             : {
    2619      385274 :     return ExecJustAssignVarImpl(state, econtext->ecxt_outertuple, isnull);
    2620             : }
    2621             : 
    2622             : /* Evaluate scan Var and assign to appropriate column of result tuple */
    2623             : static Datum
    2624     8797386 : ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2625             : {
    2626     8797386 :     return ExecJustAssignVarImpl(state, econtext->ecxt_scantuple, isnull);
    2627             : }
    2628             : 
    2629             : /* Evaluate CASE_TESTVAL and apply a strict function to it */
    2630             : static Datum
    2631      421442 : ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
    2632             : {
    2633      421442 :     ExprEvalStep *op = &state->steps[0];
    2634             :     FunctionCallInfo fcinfo;
    2635             :     NullableDatum *args;
    2636             :     int         nargs;
    2637             :     Datum       d;
    2638             : 
    2639             :     /*
    2640             :      * XXX with some redesign of the CaseTestExpr mechanism, maybe we could
    2641             :      * get rid of this data shuffling?
    2642             :      */
    2643      421442 :     *op->resvalue = *op->d.casetest.value;
    2644      421442 :     *op->resnull = *op->d.casetest.isnull;
    2645             : 
    2646      421442 :     op++;
    2647             : 
    2648      421442 :     nargs = op->d.func.nargs;
    2649      421442 :     fcinfo = op->d.func.fcinfo_data;
    2650      421442 :     args = fcinfo->args;
    2651             : 
    2652             :     /* strict function, so check for NULL args */
    2653      843196 :     for (int argno = 0; argno < nargs; argno++)
    2654             :     {
    2655      421766 :         if (args[argno].isnull)
    2656             :         {
    2657          12 :             *isnull = true;
    2658          12 :             return (Datum) 0;
    2659             :         }
    2660             :     }
    2661      421430 :     fcinfo->isnull = false;
    2662      421430 :     d = op->d.func.fn_addr(fcinfo);
    2663      421412 :     *isnull = fcinfo->isnull;
    2664      421412 :     return d;
    2665             : }
    2666             : 
    2667             : /* Simple Const expression */
    2668             : static Datum
    2669     2004280 : ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
    2670             : {
    2671     2004280 :     ExprEvalStep *op = &state->steps[0];
    2672             : 
    2673     2004280 :     *isnull = op->d.constval.isnull;
    2674     2004280 :     return op->d.constval.value;
    2675             : }
    2676             : 
    2677             : /* implementation of ExecJust(Inner|Outer|Scan)VarVirt */
    2678             : static pg_attribute_always_inline Datum
    2679     1744684 : ExecJustVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2680             : {
    2681     1744684 :     ExprEvalStep *op = &state->steps[0];
    2682     1744684 :     int         attnum = op->d.var.attnum;
    2683             : 
    2684             :     /*
    2685             :      * As it is guaranteed that a virtual slot is used, there never is a need
    2686             :      * to perform tuple deforming (nor would it be possible). Therefore
    2687             :      * execExpr.c has not emitted an EEOP_*_FETCHSOME step. Verify, as much as
    2688             :      * possible, that that determination was accurate.
    2689             :      */
    2690             :     Assert(TTS_IS_VIRTUAL(slot));
    2691             :     Assert(TTS_FIXED(slot));
    2692             :     Assert(attnum >= 0 && attnum < slot->tts_nvalid);
    2693             : 
    2694     1744684 :     *isnull = slot->tts_isnull[attnum];
    2695             : 
    2696     1744684 :     return slot->tts_values[attnum];
    2697             : }
    2698             : 
    2699             : /* Like ExecJustInnerVar, optimized for virtual slots */
    2700             : static Datum
    2701      498926 : ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2702             : {
    2703      498926 :     return ExecJustVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2704             : }
    2705             : 
    2706             : /* Like ExecJustOuterVar, optimized for virtual slots */
    2707             : static Datum
    2708     1245758 : ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2709             : {
    2710     1245758 :     return ExecJustVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
    2711             : }
    2712             : 
    2713             : /* Like ExecJustScanVar, optimized for virtual slots */
    2714             : static Datum
    2715           0 : ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2716             : {
    2717           0 :     return ExecJustVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
    2718             : }
    2719             : 
    2720             : /* implementation of ExecJustAssign(Inner|Outer|Scan)VarVirt */
    2721             : static pg_attribute_always_inline Datum
    2722     1170670 : ExecJustAssignVarVirtImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
    2723             : {
    2724     1170670 :     ExprEvalStep *op = &state->steps[0];
    2725     1170670 :     int         attnum = op->d.assign_var.attnum;
    2726     1170670 :     int         resultnum = op->d.assign_var.resultnum;
    2727     1170670 :     TupleTableSlot *outslot = state->resultslot;
    2728             : 
    2729             :     /* see ExecJustVarVirtImpl for comments */
    2730             : 
    2731             :     Assert(TTS_IS_VIRTUAL(inslot));
    2732             :     Assert(TTS_FIXED(inslot));
    2733             :     Assert(attnum >= 0 && attnum < inslot->tts_nvalid);
    2734             :     Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
    2735             : 
    2736     1170670 :     outslot->tts_values[resultnum] = inslot->tts_values[attnum];
    2737     1170670 :     outslot->tts_isnull[resultnum] = inslot->tts_isnull[attnum];
    2738             : 
    2739     1170670 :     return 0;
    2740             : }
    2741             : 
    2742             : /* Like ExecJustAssignInnerVar, optimized for virtual slots */
    2743             : static Datum
    2744      121248 : ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2745             : {
    2746      121248 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2747             : }
    2748             : 
    2749             : /* Like ExecJustAssignOuterVar, optimized for virtual slots */
    2750             : static Datum
    2751      838756 : ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2752             : {
    2753      838756 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
    2754             : }
    2755             : 
    2756             : /* Like ExecJustAssignScanVar, optimized for virtual slots */
    2757             : static Datum
    2758      210666 : ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2759             : {
    2760      210666 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
    2761             : }
    2762             : 
    2763             : /*
    2764             :  * implementation for hashing an inner Var, seeding with an initial value.
    2765             :  */
    2766             : static Datum
    2767     1861620 : ExecJustHashInnerVarWithIV(ExprState *state, ExprContext *econtext,
    2768             :                            bool *isnull)
    2769             : {
    2770     1861620 :     ExprEvalStep *fetchop = &state->steps[0];
    2771     1861620 :     ExprEvalStep *setivop = &state->steps[1];
    2772     1861620 :     ExprEvalStep *innervar = &state->steps[2];
    2773     1861620 :     ExprEvalStep *hashop = &state->steps[3];
    2774     1861620 :     FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
    2775     1861620 :     int         attnum = innervar->d.var.attnum;
    2776             :     uint32      hashkey;
    2777             : 
    2778     1861620 :     CheckOpSlotCompatibility(fetchop, econtext->ecxt_innertuple);
    2779     1861620 :     slot_getsomeattrs(econtext->ecxt_innertuple, fetchop->d.fetch.last_var);
    2780             : 
    2781     1861620 :     fcinfo->args[0].value = econtext->ecxt_innertuple->tts_values[attnum];
    2782     1861620 :     fcinfo->args[0].isnull = econtext->ecxt_innertuple->tts_isnull[attnum];
    2783             : 
    2784     1861620 :     hashkey = DatumGetUInt32(setivop->d.hashdatum_initvalue.init_value);
    2785     1861620 :     hashkey = pg_rotate_left32(hashkey, 1);
    2786             : 
    2787     1861620 :     if (!fcinfo->args[0].isnull)
    2788             :     {
    2789             :         uint32      hashvalue;
    2790             : 
    2791     1860720 :         hashvalue = DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
    2792     1860720 :         hashkey = hashkey ^ hashvalue;
    2793             :     }
    2794             : 
    2795     1861620 :     *isnull = false;
    2796     1861620 :     return UInt32GetDatum(hashkey);
    2797             : }
    2798             : 
    2799             : /* implementation of ExecJustHash(Inner|Outer)Var */
    2800             : static pg_attribute_always_inline Datum
    2801     3770282 : ExecJustHashVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2802             : {
    2803     3770282 :     ExprEvalStep *fetchop = &state->steps[0];
    2804     3770282 :     ExprEvalStep *var = &state->steps[1];
    2805     3770282 :     ExprEvalStep *hashop = &state->steps[2];
    2806     3770282 :     FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
    2807     3770282 :     int         attnum = var->d.var.attnum;
    2808             : 
    2809     3770282 :     CheckOpSlotCompatibility(fetchop, slot);
    2810     3770282 :     slot_getsomeattrs(slot, fetchop->d.fetch.last_var);
    2811             : 
    2812     3770282 :     fcinfo->args[0].value = slot->tts_values[attnum];
    2813     3770282 :     fcinfo->args[0].isnull = slot->tts_isnull[attnum];
    2814             : 
    2815     3770282 :     *isnull = false;
    2816             : 
    2817     3770282 :     if (!fcinfo->args[0].isnull)
    2818     3767078 :         return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
    2819             :     else
    2820        3204 :         return (Datum) 0;
    2821             : }
    2822             : 
    2823             : /* implementation for hashing an outer Var */
    2824             : static Datum
    2825     1293618 : ExecJustHashOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2826             : {
    2827     1293618 :     return ExecJustHashVarImpl(state, econtext->ecxt_outertuple, isnull);
    2828             : }
    2829             : 
    2830             : /* implementation for hashing an inner Var */
    2831             : static Datum
    2832     2476664 : ExecJustHashInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2833             : {
    2834     2476664 :     return ExecJustHashVarImpl(state, econtext->ecxt_innertuple, isnull);
    2835             : }
    2836             : 
    2837             : /* implementation of ExecJustHash(Inner|Outer)VarVirt */
    2838             : static pg_attribute_always_inline Datum
    2839     5283362 : ExecJustHashVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2840             : {
    2841     5283362 :     ExprEvalStep *var = &state->steps[0];
    2842     5283362 :     ExprEvalStep *hashop = &state->steps[1];
    2843     5283362 :     FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
    2844     5283362 :     int         attnum = var->d.var.attnum;
    2845             : 
    2846     5283362 :     fcinfo->args[0].value = slot->tts_values[attnum];
    2847     5283362 :     fcinfo->args[0].isnull = slot->tts_isnull[attnum];
    2848             : 
    2849     5283362 :     *isnull = false;
    2850             : 
    2851     5283362 :     if (!fcinfo->args[0].isnull)
    2852     5283200 :         return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
    2853             :     else
    2854         162 :         return (Datum) 0;
    2855             : }
    2856             : 
    2857             : /* Like ExecJustHashInnerVar, optimized for virtual slots */
    2858             : static Datum
    2859     1307920 : ExecJustHashInnerVarVirt(ExprState *state, ExprContext *econtext,
    2860             :                          bool *isnull)
    2861             : {
    2862     1307920 :     return ExecJustHashVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2863             : }
    2864             : 
    2865             : /* Like ExecJustHashOuterVar, optimized for virtual slots */
    2866             : static Datum
    2867     3975442 : ExecJustHashOuterVarVirt(ExprState *state, ExprContext *econtext,
    2868             :                          bool *isnull)
    2869             : {
    2870     3975442 :     return ExecJustHashVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
    2871             : }
    2872             : 
    2873             : /*
    2874             :  * implementation for hashing an outer Var.  Returns NULL on NULL input.
    2875             :  */
    2876             : static Datum
    2877     7261862 : ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext,
    2878             :                            bool *isnull)
    2879             : {
    2880     7261862 :     ExprEvalStep *fetchop = &state->steps[0];
    2881     7261862 :     ExprEvalStep *var = &state->steps[1];
    2882     7261862 :     ExprEvalStep *hashop = &state->steps[2];
    2883     7261862 :     FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
    2884     7261862 :     int         attnum = var->d.var.attnum;
    2885             : 
    2886     7261862 :     CheckOpSlotCompatibility(fetchop, econtext->ecxt_outertuple);
    2887     7261862 :     slot_getsomeattrs(econtext->ecxt_outertuple, fetchop->d.fetch.last_var);
    2888             : 
    2889     7261862 :     fcinfo->args[0].value = econtext->ecxt_outertuple->tts_values[attnum];
    2890     7261862 :     fcinfo->args[0].isnull = econtext->ecxt_outertuple->tts_isnull[attnum];
    2891             : 
    2892     7261862 :     if (!fcinfo->args[0].isnull)
    2893             :     {
    2894     7261564 :         *isnull = false;
    2895     7261564 :         return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
    2896             :     }
    2897             :     else
    2898             :     {
    2899             :         /* return NULL on NULL input */
    2900         298 :         *isnull = true;
    2901         298 :         return (Datum) 0;
    2902             :     }
    2903             : }
    2904             : 
    2905             : #if defined(EEO_USE_COMPUTED_GOTO)
    2906             : /*
    2907             :  * Comparator used when building address->opcode lookup table for
    2908             :  * ExecEvalStepOp() in the threaded dispatch case.
    2909             :  */
    2910             : static int
    2911    64881762 : dispatch_compare_ptr(const void *a, const void *b)
    2912             : {
    2913    64881762 :     const ExprEvalOpLookup *la = (const ExprEvalOpLookup *) a;
    2914    64881762 :     const ExprEvalOpLookup *lb = (const ExprEvalOpLookup *) b;
    2915             : 
    2916    64881762 :     if (la->opcode < lb->opcode)
    2917    38799950 :         return -1;
    2918    26081812 :     else if (la->opcode > lb->opcode)
    2919    17474766 :         return 1;
    2920     8607046 :     return 0;
    2921             : }
    2922             : #endif
    2923             : 
    2924             : /*
    2925             :  * Do one-time initialization of interpretation machinery.
    2926             :  */
    2927             : static void
    2928     2628502 : ExecInitInterpreter(void)
    2929             : {
    2930             : #if defined(EEO_USE_COMPUTED_GOTO)
    2931             :     /* Set up externally-visible pointer to dispatch table */
    2932     2628502 :     if (dispatch_table == NULL)
    2933             :     {
    2934       23438 :         dispatch_table = (const void **)
    2935       23438 :             DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
    2936             : 
    2937             :         /* build reverse lookup table */
    2938     2835998 :         for (int i = 0; i < EEOP_LAST; i++)
    2939             :         {
    2940     2812560 :             reverse_dispatch_table[i].opcode = dispatch_table[i];
    2941     2812560 :             reverse_dispatch_table[i].op = (ExprEvalOp) i;
    2942             :         }
    2943             : 
    2944             :         /* make it bsearch()able */
    2945       23438 :         qsort(reverse_dispatch_table,
    2946             :               EEOP_LAST /* nmembers */ ,
    2947             :               sizeof(ExprEvalOpLookup),
    2948             :               dispatch_compare_ptr);
    2949             :     }
    2950             : #endif
    2951     2628502 : }
    2952             : 
    2953             : /*
    2954             :  * Function to return the opcode of an expression step.
    2955             :  *
    2956             :  * When direct-threading is in use, ExprState->opcode isn't easily
    2957             :  * decipherable. This function returns the appropriate enum member.
    2958             :  */
    2959             : ExprEvalOp
    2960     9761118 : ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
    2961             : {
    2962             : #if defined(EEO_USE_COMPUTED_GOTO)
    2963     9761118 :     if (state->flags & EEO_FLAG_DIRECT_THREADED)
    2964             :     {
    2965             :         ExprEvalOpLookup key;
    2966             :         ExprEvalOpLookup *res;
    2967             : 
    2968     8607046 :         key.opcode = (void *) op->opcode;
    2969     8607046 :         res = bsearch(&key,
    2970             :                       reverse_dispatch_table,
    2971             :                       EEOP_LAST /* nmembers */ ,
    2972             :                       sizeof(ExprEvalOpLookup),
    2973             :                       dispatch_compare_ptr);
    2974             :         Assert(res);            /* unknown ops shouldn't get looked up */
    2975     8607046 :         return res->op;
    2976             :     }
    2977             : #endif
    2978     1154072 :     return (ExprEvalOp) op->opcode;
    2979             : }
    2980             : 
    2981             : 
    2982             : /*
    2983             :  * Out-of-line helper functions for complex instructions.
    2984             :  */
    2985             : 
    2986             : /*
    2987             :  * Evaluate EEOP_FUNCEXPR_FUSAGE
    2988             :  */
    2989             : void
    2990         208 : ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op,
    2991             :                        ExprContext *econtext)
    2992             : {
    2993         208 :     FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    2994             :     PgStat_FunctionCallUsage fcusage;
    2995             :     Datum       d;
    2996             : 
    2997         208 :     pgstat_init_function_usage(fcinfo, &fcusage);
    2998             : 
    2999         208 :     fcinfo->isnull = false;
    3000         208 :     d = op->d.func.fn_addr(fcinfo);
    3001         208 :     *op->resvalue = d;
    3002         208 :     *op->resnull = fcinfo->isnull;
    3003             : 
    3004         208 :     pgstat_end_function_usage(&fcusage, true);
    3005         208 : }
    3006             : 
    3007             : /*
    3008             :  * Evaluate EEOP_FUNCEXPR_STRICT_FUSAGE
    3009             :  */
    3010             : void
    3011           6 : ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
    3012             :                              ExprContext *econtext)
    3013             : {
    3014             : 
    3015           6 :     FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    3016             :     PgStat_FunctionCallUsage fcusage;
    3017           6 :     NullableDatum *args = fcinfo->args;
    3018           6 :     int         nargs = op->d.func.nargs;
    3019             :     Datum       d;
    3020             : 
    3021             :     /* strict function, so check for NULL args */
    3022          18 :     for (int argno = 0; argno < nargs; argno++)
    3023             :     {
    3024          12 :         if (args[argno].isnull)
    3025             :         {
    3026           0 :             *op->resnull = true;
    3027           0 :             return;
    3028             :         }
    3029             :     }
    3030             : 
    3031           6 :     pgstat_init_function_usage(fcinfo, &fcusage);
    3032             : 
    3033           6 :     fcinfo->isnull = false;
    3034           6 :     d = op->d.func.fn_addr(fcinfo);
    3035           6 :     *op->resvalue = d;
    3036           6 :     *op->resnull = fcinfo->isnull;
    3037             : 
    3038           6 :     pgstat_end_function_usage(&fcusage, true);
    3039             : }
    3040             : 
    3041             : /*
    3042             :  * Evaluate a PARAM_EXEC parameter.
    3043             :  *
    3044             :  * PARAM_EXEC params (internal executor parameters) are stored in the
    3045             :  * ecxt_param_exec_vals array, and can be accessed by array index.
    3046             :  */
    3047             : void
    3048     7812768 : ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3049             : {
    3050             :     ParamExecData *prm;
    3051             : 
    3052     7812768 :     prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
    3053     7812768 :     if (unlikely(prm->execPlan != NULL))
    3054             :     {
    3055             :         /* Parameter not evaluated yet, so go do it */
    3056        9200 :         ExecSetParamPlan(prm->execPlan, econtext);
    3057             :         /* ExecSetParamPlan should have processed this param... */
    3058             :         Assert(prm->execPlan == NULL);
    3059             :     }
    3060     7812750 :     *op->resvalue = prm->value;
    3061     7812750 :     *op->resnull = prm->isnull;
    3062     7812750 : }
    3063             : 
    3064             : /*
    3065             :  * Evaluate a PARAM_EXTERN parameter.
    3066             :  *
    3067             :  * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
    3068             :  */
    3069             : void
    3070      785228 : ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3071             : {
    3072      785228 :     ParamListInfo paramInfo = econtext->ecxt_param_list_info;
    3073      785228 :     int         paramId = op->d.param.paramid;
    3074             : 
    3075      785228 :     if (likely(paramInfo &&
    3076             :                paramId > 0 && paramId <= paramInfo->numParams))
    3077             :     {
    3078             :         ParamExternData *prm;
    3079             :         ParamExternData prmdata;
    3080             : 
    3081             :         /* give hook a chance in case parameter is dynamic */
    3082      785228 :         if (paramInfo->paramFetch != NULL)
    3083         186 :             prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata);
    3084             :         else
    3085      785042 :             prm = &paramInfo->params[paramId - 1];
    3086             : 
    3087      785228 :         if (likely(OidIsValid(prm->ptype)))
    3088             :         {
    3089             :             /* safety check in case hook did something unexpected */
    3090      785228 :             if (unlikely(prm->ptype != op->d.param.paramtype))
    3091           0 :                 ereport(ERROR,
    3092             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3093             :                          errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    3094             :                                 paramId,
    3095             :                                 format_type_be(prm->ptype),
    3096             :                                 format_type_be(op->d.param.paramtype))));
    3097      785228 :             *op->resvalue = prm->value;
    3098      785228 :             *op->resnull = prm->isnull;
    3099      785228 :             return;
    3100             :         }
    3101             :     }
    3102             : 
    3103           0 :     ereport(ERROR,
    3104             :             (errcode(ERRCODE_UNDEFINED_OBJECT),
    3105             :              errmsg("no value found for parameter %d", paramId)));
    3106             : }
    3107             : 
    3108             : /*
    3109             :  * Set value of a param (currently always PARAM_EXEC) from
    3110             :  * state->res{value,null}.
    3111             :  */
    3112             : void
    3113     1631448 : ExecEvalParamSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3114             : {
    3115             :     ParamExecData *prm;
    3116             : 
    3117     1631448 :     prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
    3118             : 
    3119             :     /* Shouldn't have a pending evaluation anymore */
    3120             :     Assert(prm->execPlan == NULL);
    3121             : 
    3122     1631448 :     prm->value = state->resvalue;
    3123     1631448 :     prm->isnull = state->resnull;
    3124     1631448 : }
    3125             : 
    3126             : /*
    3127             :  * Evaluate a CoerceViaIO node in soft-error mode.
    3128             :  *
    3129             :  * The source value is in op's result variable.
    3130             :  *
    3131             :  * Note: This implements EEOP_IOCOERCE_SAFE. If you change anything here,
    3132             :  * also look at the inline code for EEOP_IOCOERCE.
    3133             :  */
    3134             : void
    3135           0 : ExecEvalCoerceViaIOSafe(ExprState *state, ExprEvalStep *op)
    3136             : {
    3137             :     char       *str;
    3138             : 
    3139             :     /* call output function (similar to OutputFunctionCall) */
    3140           0 :     if (*op->resnull)
    3141             :     {
    3142             :         /* output functions are not called on nulls */
    3143           0 :         str = NULL;
    3144             :     }
    3145             :     else
    3146             :     {
    3147             :         FunctionCallInfo fcinfo_out;
    3148             : 
    3149           0 :         fcinfo_out = op->d.iocoerce.fcinfo_data_out;
    3150           0 :         fcinfo_out->args[0].value = *op->resvalue;
    3151           0 :         fcinfo_out->args[0].isnull = false;
    3152             : 
    3153           0 :         fcinfo_out->isnull = false;
    3154           0 :         str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
    3155             : 
    3156             :         /* OutputFunctionCall assumes result isn't null */
    3157             :         Assert(!fcinfo_out->isnull);
    3158             :     }
    3159             : 
    3160             :     /* call input function (similar to InputFunctionCallSafe) */
    3161           0 :     if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
    3162             :     {
    3163             :         FunctionCallInfo fcinfo_in;
    3164             : 
    3165           0 :         fcinfo_in = op->d.iocoerce.fcinfo_data_in;
    3166           0 :         fcinfo_in->args[0].value = PointerGetDatum(str);
    3167           0 :         fcinfo_in->args[0].isnull = *op->resnull;
    3168             :         /* second and third arguments are already set up */
    3169             : 
    3170             :         /* ErrorSaveContext must be present. */
    3171             :         Assert(IsA(fcinfo_in->context, ErrorSaveContext));
    3172             : 
    3173           0 :         fcinfo_in->isnull = false;
    3174           0 :         *op->resvalue = FunctionCallInvoke(fcinfo_in);
    3175             : 
    3176           0 :         if (SOFT_ERROR_OCCURRED(fcinfo_in->context))
    3177             :         {
    3178           0 :             *op->resnull = true;
    3179           0 :             *op->resvalue = (Datum) 0;
    3180           0 :             return;
    3181             :         }
    3182             : 
    3183             :         /* Should get null result if and only if str is NULL */
    3184             :         if (str == NULL)
    3185             :             Assert(*op->resnull);
    3186             :         else
    3187             :             Assert(!*op->resnull);
    3188             :     }
    3189             : }
    3190             : 
    3191             : /*
    3192             :  * Evaluate a SQLValueFunction expression.
    3193             :  */
    3194             : void
    3195       19046 : ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
    3196             : {
    3197       19046 :     LOCAL_FCINFO(fcinfo, 0);
    3198       19046 :     SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
    3199             : 
    3200       19046 :     *op->resnull = false;
    3201             : 
    3202             :     /*
    3203             :      * Note: current_schema() can return NULL.  current_user() etc currently
    3204             :      * cannot, but might as well code those cases the same way for safety.
    3205             :      */
    3206       19046 :     switch (svf->op)
    3207             :     {
    3208          50 :         case SVFOP_CURRENT_DATE:
    3209          50 :             *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
    3210          50 :             break;
    3211          24 :         case SVFOP_CURRENT_TIME:
    3212             :         case SVFOP_CURRENT_TIME_N:
    3213          24 :             *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
    3214          24 :             break;
    3215         348 :         case SVFOP_CURRENT_TIMESTAMP:
    3216             :         case SVFOP_CURRENT_TIMESTAMP_N:
    3217         348 :             *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
    3218         348 :             break;
    3219          24 :         case SVFOP_LOCALTIME:
    3220             :         case SVFOP_LOCALTIME_N:
    3221          24 :             *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
    3222          24 :             break;
    3223          66 :         case SVFOP_LOCALTIMESTAMP:
    3224             :         case SVFOP_LOCALTIMESTAMP_N:
    3225          66 :             *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
    3226          66 :             break;
    3227       17908 :         case SVFOP_CURRENT_ROLE:
    3228             :         case SVFOP_CURRENT_USER:
    3229             :         case SVFOP_USER:
    3230       17908 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    3231       17908 :             *op->resvalue = current_user(fcinfo);
    3232       17908 :             *op->resnull = fcinfo->isnull;
    3233       17908 :             break;
    3234         566 :         case SVFOP_SESSION_USER:
    3235         566 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    3236         566 :             *op->resvalue = session_user(fcinfo);
    3237         566 :             *op->resnull = fcinfo->isnull;
    3238         566 :             break;
    3239          42 :         case SVFOP_CURRENT_CATALOG:
    3240          42 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    3241          42 :             *op->resvalue = current_database(fcinfo);
    3242          42 :             *op->resnull = fcinfo->isnull;
    3243          42 :             break;
    3244          18 :         case SVFOP_CURRENT_SCHEMA:
    3245          18 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    3246          18 :             *op->resvalue = current_schema(fcinfo);
    3247          18 :             *op->resnull = fcinfo->isnull;
    3248          18 :             break;
    3249             :     }
    3250       19046 : }
    3251             : 
    3252             : /*
    3253             :  * Raise error if a CURRENT OF expression is evaluated.
    3254             :  *
    3255             :  * The planner should convert CURRENT OF into a TidScan qualification, or some
    3256             :  * other special handling in a ForeignScan node.  So we have to be able to do
    3257             :  * ExecInitExpr on a CurrentOfExpr, but we shouldn't ever actually execute it.
    3258             :  * If we get here, we suppose we must be dealing with CURRENT OF on a foreign
    3259             :  * table whose FDW doesn't handle it, and complain accordingly.
    3260             :  */
    3261             : void
    3262           2 : ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
    3263             : {
    3264           2 :     ereport(ERROR,
    3265             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3266             :              errmsg("WHERE CURRENT OF is not supported for this table type")));
    3267             : }
    3268             : 
    3269             : /*
    3270             :  * Evaluate NextValueExpr.
    3271             :  */
    3272             : void
    3273         912 : ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
    3274             : {
    3275         912 :     int64       newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
    3276             : 
    3277         912 :     switch (op->d.nextvalueexpr.seqtypid)
    3278             :     {
    3279          30 :         case INT2OID:
    3280          30 :             *op->resvalue = Int16GetDatum((int16) newval);
    3281          30 :             break;
    3282         804 :         case INT4OID:
    3283         804 :             *op->resvalue = Int32GetDatum((int32) newval);
    3284         804 :             break;
    3285          78 :         case INT8OID:
    3286          78 :             *op->resvalue = Int64GetDatum((int64) newval);
    3287          78 :             break;
    3288           0 :         default:
    3289           0 :             elog(ERROR, "unsupported sequence type %u",
    3290             :                  op->d.nextvalueexpr.seqtypid);
    3291             :     }
    3292         912 :     *op->resnull = false;
    3293         912 : }
    3294             : 
    3295             : /*
    3296             :  * Evaluate NullTest / IS NULL for rows.
    3297             :  */
    3298             : void
    3299         696 : ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3300             : {
    3301         696 :     ExecEvalRowNullInt(state, op, econtext, true);
    3302         696 : }
    3303             : 
    3304             : /*
    3305             :  * Evaluate NullTest / IS NOT NULL for rows.
    3306             :  */
    3307             : void
    3308         566 : ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3309             : {
    3310         566 :     ExecEvalRowNullInt(state, op, econtext, false);
    3311         566 : }
    3312             : 
    3313             : /* Common code for IS [NOT] NULL on a row value */
    3314             : static void
    3315        1262 : ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
    3316             :                    ExprContext *econtext, bool checkisnull)
    3317             : {
    3318        1262 :     Datum       value = *op->resvalue;
    3319        1262 :     bool        isnull = *op->resnull;
    3320             :     HeapTupleHeader tuple;
    3321             :     Oid         tupType;
    3322             :     int32       tupTypmod;
    3323             :     TupleDesc   tupDesc;
    3324             :     HeapTupleData tmptup;
    3325             : 
    3326        1262 :     *op->resnull = false;
    3327             : 
    3328             :     /* NULL row variables are treated just as NULL scalar columns */
    3329        1262 :     if (isnull)
    3330             :     {
    3331         156 :         *op->resvalue = BoolGetDatum(checkisnull);
    3332         748 :         return;
    3333             :     }
    3334             : 
    3335             :     /*
    3336             :      * The SQL standard defines IS [NOT] NULL for a non-null rowtype argument
    3337             :      * as:
    3338             :      *
    3339             :      * "R IS NULL" is true if every field is the null value.
    3340             :      *
    3341             :      * "R IS NOT NULL" is true if no field is the null value.
    3342             :      *
    3343             :      * This definition is (apparently intentionally) not recursive; so our
    3344             :      * tests on the fields are primitive attisnull tests, not recursive checks
    3345             :      * to see if they are all-nulls or no-nulls rowtypes.
    3346             :      *
    3347             :      * The standard does not consider the possibility of zero-field rows, but
    3348             :      * here we consider them to vacuously satisfy both predicates.
    3349             :      */
    3350             : 
    3351        1106 :     tuple = DatumGetHeapTupleHeader(value);
    3352             : 
    3353        1106 :     tupType = HeapTupleHeaderGetTypeId(tuple);
    3354        1106 :     tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    3355             : 
    3356             :     /* Lookup tupdesc if first time through or if type changes */
    3357        1106 :     tupDesc = get_cached_rowtype(tupType, tupTypmod,
    3358             :                                  &op->d.nulltest_row.rowcache, NULL);
    3359             : 
    3360             :     /*
    3361             :      * heap_attisnull needs a HeapTuple not a bare HeapTupleHeader.
    3362             :      */
    3363        1106 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3364        1106 :     tmptup.t_data = tuple;
    3365             : 
    3366        2660 :     for (int att = 1; att <= tupDesc->natts; att++)
    3367             :     {
    3368             :         /* ignore dropped columns */
    3369        2146 :         if (TupleDescCompactAttr(tupDesc, att - 1)->attisdropped)
    3370           0 :             continue;
    3371        2146 :         if (heap_attisnull(&tmptup, att, tupDesc))
    3372             :         {
    3373             :             /* null field disproves IS NOT NULL */
    3374          62 :             if (!checkisnull)
    3375             :             {
    3376          38 :                 *op->resvalue = BoolGetDatum(false);
    3377          38 :                 return;
    3378             :             }
    3379             :         }
    3380             :         else
    3381             :         {
    3382             :             /* non-null field disproves IS NULL */
    3383        2084 :             if (checkisnull)
    3384             :             {
    3385         554 :                 *op->resvalue = BoolGetDatum(false);
    3386         554 :                 return;
    3387             :             }
    3388             :         }
    3389             :     }
    3390             : 
    3391         514 :     *op->resvalue = BoolGetDatum(true);
    3392             : }
    3393             : 
    3394             : /*
    3395             :  * Evaluate an ARRAY[] expression.
    3396             :  *
    3397             :  * The individual array elements (or subarrays) have already been evaluated
    3398             :  * into op->d.arrayexpr.elemvalues[]/elemnulls[].
    3399             :  */
    3400             : void
    3401      834118 : ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
    3402             : {
    3403             :     ArrayType  *result;
    3404      834118 :     Oid         element_type = op->d.arrayexpr.elemtype;
    3405      834118 :     int         nelems = op->d.arrayexpr.nelems;
    3406      834118 :     int         ndims = 0;
    3407             :     int         dims[MAXDIM];
    3408             :     int         lbs[MAXDIM];
    3409             : 
    3410             :     /* Set non-null as default */
    3411      834118 :     *op->resnull = false;
    3412             : 
    3413      834118 :     if (!op->d.arrayexpr.multidims)
    3414             :     {
    3415             :         /* Elements are presumably of scalar type */
    3416      833640 :         Datum      *dvalues = op->d.arrayexpr.elemvalues;
    3417      833640 :         bool       *dnulls = op->d.arrayexpr.elemnulls;
    3418             : 
    3419             :         /* setup for 1-D array of the given length */
    3420      833640 :         ndims = 1;
    3421      833640 :         dims[0] = nelems;
    3422      833640 :         lbs[0] = 1;
    3423             : 
    3424      833640 :         result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
    3425             :                                     element_type,
    3426      833640 :                                     op->d.arrayexpr.elemlength,
    3427      833640 :                                     op->d.arrayexpr.elembyval,
    3428      833640 :                                     op->d.arrayexpr.elemalign);
    3429             :     }
    3430             :     else
    3431             :     {
    3432             :         /* Must be nested array expressions */
    3433         478 :         int         nbytes = 0;
    3434             :         int         nitems;
    3435         478 :         int         outer_nelems = 0;
    3436         478 :         int         elem_ndims = 0;
    3437         478 :         int        *elem_dims = NULL;
    3438         478 :         int        *elem_lbs = NULL;
    3439         478 :         bool        firstone = true;
    3440         478 :         bool        havenulls = false;
    3441         478 :         bool        haveempty = false;
    3442             :         char      **subdata;
    3443             :         bits8     **subbitmaps;
    3444             :         int        *subbytes;
    3445             :         int        *subnitems;
    3446             :         int32       dataoffset;
    3447             :         char       *dat;
    3448             :         int         iitem;
    3449             : 
    3450         478 :         subdata = (char **) palloc(nelems * sizeof(char *));
    3451         478 :         subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *));
    3452         478 :         subbytes = (int *) palloc(nelems * sizeof(int));
    3453         478 :         subnitems = (int *) palloc(nelems * sizeof(int));
    3454             : 
    3455             :         /* loop through and get data area from each element */
    3456        1334 :         for (int elemoff = 0; elemoff < nelems; elemoff++)
    3457             :         {
    3458             :             Datum       arraydatum;
    3459             :             bool        eisnull;
    3460             :             ArrayType  *array;
    3461             :             int         this_ndims;
    3462             : 
    3463         856 :             arraydatum = op->d.arrayexpr.elemvalues[elemoff];
    3464         856 :             eisnull = op->d.arrayexpr.elemnulls[elemoff];
    3465             : 
    3466             :             /* temporarily ignore null subarrays */
    3467         856 :             if (eisnull)
    3468             :             {
    3469           0 :                 haveempty = true;
    3470           0 :                 continue;
    3471             :             }
    3472             : 
    3473         856 :             array = DatumGetArrayTypeP(arraydatum);
    3474             : 
    3475             :             /* run-time double-check on element type */
    3476         856 :             if (element_type != ARR_ELEMTYPE(array))
    3477           0 :                 ereport(ERROR,
    3478             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3479             :                          errmsg("cannot merge incompatible arrays"),
    3480             :                          errdetail("Array with element type %s cannot be "
    3481             :                                    "included in ARRAY construct with element type %s.",
    3482             :                                    format_type_be(ARR_ELEMTYPE(array)),
    3483             :                                    format_type_be(element_type))));
    3484             : 
    3485         856 :             this_ndims = ARR_NDIM(array);
    3486             :             /* temporarily ignore zero-dimensional subarrays */
    3487         856 :             if (this_ndims <= 0)
    3488             :             {
    3489           0 :                 haveempty = true;
    3490           0 :                 continue;
    3491             :             }
    3492             : 
    3493         856 :             if (firstone)
    3494             :             {
    3495             :                 /* Get sub-array details from first member */
    3496         478 :                 elem_ndims = this_ndims;
    3497         478 :                 ndims = elem_ndims + 1;
    3498         478 :                 if (ndims <= 0 || ndims > MAXDIM)
    3499           0 :                     ereport(ERROR,
    3500             :                             (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3501             :                              errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
    3502             :                                     ndims, MAXDIM)));
    3503             : 
    3504         478 :                 elem_dims = (int *) palloc(elem_ndims * sizeof(int));
    3505         478 :                 memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
    3506         478 :                 elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
    3507         478 :                 memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
    3508             : 
    3509         478 :                 firstone = false;
    3510             :             }
    3511             :             else
    3512             :             {
    3513             :                 /* Check other sub-arrays are compatible */
    3514         378 :                 if (elem_ndims != this_ndims ||
    3515         378 :                     memcmp(elem_dims, ARR_DIMS(array),
    3516         378 :                            elem_ndims * sizeof(int)) != 0 ||
    3517         378 :                     memcmp(elem_lbs, ARR_LBOUND(array),
    3518             :                            elem_ndims * sizeof(int)) != 0)
    3519           0 :                     ereport(ERROR,
    3520             :                             (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    3521             :                              errmsg("multidimensional arrays must have array "
    3522             :                                     "expressions with matching dimensions")));
    3523             :             }
    3524             : 
    3525         856 :             subdata[outer_nelems] = ARR_DATA_PTR(array);
    3526         856 :             subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
    3527         856 :             subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
    3528         856 :             nbytes += subbytes[outer_nelems];
    3529             :             /* check for overflow of total request */
    3530         856 :             if (!AllocSizeIsValid(nbytes))
    3531           0 :                 ereport(ERROR,
    3532             :                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3533             :                          errmsg("array size exceeds the maximum allowed (%d)",
    3534             :                                 (int) MaxAllocSize)));
    3535         856 :             subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
    3536             :                                                      ARR_DIMS(array));
    3537         856 :             havenulls |= ARR_HASNULL(array);
    3538         856 :             outer_nelems++;
    3539             :         }
    3540             : 
    3541             :         /*
    3542             :          * If all items were null or empty arrays, return an empty array;
    3543             :          * otherwise, if some were and some weren't, raise error.  (Note: we
    3544             :          * must special-case this somehow to avoid trying to generate a 1-D
    3545             :          * array formed from empty arrays.  It's not ideal...)
    3546             :          */
    3547         478 :         if (haveempty)
    3548             :         {
    3549           0 :             if (ndims == 0)     /* didn't find any nonempty array */
    3550             :             {
    3551           0 :                 *op->resvalue = PointerGetDatum(construct_empty_array(element_type));
    3552           0 :                 return;
    3553             :             }
    3554           0 :             ereport(ERROR,
    3555             :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    3556             :                      errmsg("multidimensional arrays must have array "
    3557             :                             "expressions with matching dimensions")));
    3558             :         }
    3559             : 
    3560             :         /* setup for multi-D array */
    3561         478 :         dims[0] = outer_nelems;
    3562         478 :         lbs[0] = 1;
    3563        1188 :         for (int i = 1; i < ndims; i++)
    3564             :         {
    3565         710 :             dims[i] = elem_dims[i - 1];
    3566         710 :             lbs[i] = elem_lbs[i - 1];
    3567             :         }
    3568             : 
    3569             :         /* check for subscript overflow */
    3570         478 :         nitems = ArrayGetNItems(ndims, dims);
    3571         478 :         ArrayCheckBounds(ndims, dims, lbs);
    3572             : 
    3573         478 :         if (havenulls)
    3574             :         {
    3575          30 :             dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
    3576          30 :             nbytes += dataoffset;
    3577             :         }
    3578             :         else
    3579             :         {
    3580         448 :             dataoffset = 0;     /* marker for no null bitmap */
    3581         448 :             nbytes += ARR_OVERHEAD_NONULLS(ndims);
    3582             :         }
    3583             : 
    3584         478 :         result = (ArrayType *) palloc0(nbytes);
    3585         478 :         SET_VARSIZE(result, nbytes);
    3586         478 :         result->ndim = ndims;
    3587         478 :         result->dataoffset = dataoffset;
    3588         478 :         result->elemtype = element_type;
    3589         478 :         memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
    3590         478 :         memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
    3591             : 
    3592         478 :         dat = ARR_DATA_PTR(result);
    3593         478 :         iitem = 0;
    3594        1334 :         for (int i = 0; i < outer_nelems; i++)
    3595             :         {
    3596         856 :             memcpy(dat, subdata[i], subbytes[i]);
    3597         856 :             dat += subbytes[i];
    3598         856 :             if (havenulls)
    3599          60 :                 array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
    3600          60 :                                   subbitmaps[i], 0,
    3601          60 :                                   subnitems[i]);
    3602         856 :             iitem += subnitems[i];
    3603             :         }
    3604             :     }
    3605             : 
    3606      834118 :     *op->resvalue = PointerGetDatum(result);
    3607             : }
    3608             : 
    3609             : /*
    3610             :  * Evaluate an ArrayCoerceExpr expression.
    3611             :  *
    3612             :  * Source array is in step's result variable.
    3613             :  */
    3614             : void
    3615      108332 : ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3616             : {
    3617             :     Datum       arraydatum;
    3618             : 
    3619             :     /* NULL array -> NULL result */
    3620      108332 :     if (*op->resnull)
    3621         312 :         return;
    3622             : 
    3623      108020 :     arraydatum = *op->resvalue;
    3624             : 
    3625             :     /*
    3626             :      * If it's binary-compatible, modify the element type in the array header,
    3627             :      * but otherwise leave the array as we received it.
    3628             :      */
    3629      108020 :     if (op->d.arraycoerce.elemexprstate == NULL)
    3630             :     {
    3631             :         /* Detoast input array if necessary, and copy in any case */
    3632       66994 :         ArrayType  *array = DatumGetArrayTypePCopy(arraydatum);
    3633             : 
    3634       66994 :         ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
    3635       66994 :         *op->resvalue = PointerGetDatum(array);
    3636       66994 :         return;
    3637             :     }
    3638             : 
    3639             :     /*
    3640             :      * Use array_map to apply the sub-expression to each array element.
    3641             :      */
    3642       40994 :     *op->resvalue = array_map(arraydatum,
    3643       41026 :                               op->d.arraycoerce.elemexprstate,
    3644             :                               econtext,
    3645             :                               op->d.arraycoerce.resultelemtype,
    3646       41026 :                               op->d.arraycoerce.amstate);
    3647             : }
    3648             : 
    3649             : /*
    3650             :  * Evaluate a ROW() expression.
    3651             :  *
    3652             :  * The individual columns have already been evaluated into
    3653             :  * op->d.row.elemvalues[]/elemnulls[].
    3654             :  */
    3655             : void
    3656       57904 : ExecEvalRow(ExprState *state, ExprEvalStep *op)
    3657             : {
    3658             :     HeapTuple   tuple;
    3659             : 
    3660             :     /* build tuple from evaluated field values */
    3661       57904 :     tuple = heap_form_tuple(op->d.row.tupdesc,
    3662       57904 :                             op->d.row.elemvalues,
    3663       57904 :                             op->d.row.elemnulls);
    3664             : 
    3665       57904 :     *op->resvalue = HeapTupleGetDatum(tuple);
    3666       57904 :     *op->resnull = false;
    3667       57904 : }
    3668             : 
    3669             : /*
    3670             :  * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()).
    3671             :  *
    3672             :  * All of the to-be-compared expressions have already been evaluated into
    3673             :  * op->d.minmax.values[]/nulls[].
    3674             :  */
    3675             : void
    3676       23276 : ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
    3677             : {
    3678       23276 :     Datum      *values = op->d.minmax.values;
    3679       23276 :     bool       *nulls = op->d.minmax.nulls;
    3680       23276 :     FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
    3681       23276 :     MinMaxOp    operator = op->d.minmax.op;
    3682             : 
    3683             :     /* set at initialization */
    3684             :     Assert(fcinfo->args[0].isnull == false);
    3685             :     Assert(fcinfo->args[1].isnull == false);
    3686             : 
    3687             :     /* default to null result */
    3688       23276 :     *op->resnull = true;
    3689             : 
    3690       70122 :     for (int off = 0; off < op->d.minmax.nelems; off++)
    3691             :     {
    3692             :         /* ignore NULL inputs */
    3693       46846 :         if (nulls[off])
    3694         122 :             continue;
    3695             : 
    3696       46724 :         if (*op->resnull)
    3697             :         {
    3698             :             /* first nonnull input, adopt value */
    3699       23276 :             *op->resvalue = values[off];
    3700       23276 :             *op->resnull = false;
    3701             :         }
    3702             :         else
    3703             :         {
    3704             :             int         cmpresult;
    3705             : 
    3706             :             /* apply comparison function */
    3707       23448 :             fcinfo->args[0].value = *op->resvalue;
    3708       23448 :             fcinfo->args[1].value = values[off];
    3709             : 
    3710       23448 :             fcinfo->isnull = false;
    3711       23448 :             cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
    3712       23448 :             if (fcinfo->isnull) /* probably should not happen */
    3713           0 :                 continue;
    3714             : 
    3715       23448 :             if (cmpresult > 0 && operator == IS_LEAST)
    3716         248 :                 *op->resvalue = values[off];
    3717       23200 :             else if (cmpresult < 0 && operator == IS_GREATEST)
    3718         200 :                 *op->resvalue = values[off];
    3719             :         }
    3720             :     }
    3721       23276 : }
    3722             : 
    3723             : /*
    3724             :  * Evaluate a FieldSelect node.
    3725             :  *
    3726             :  * Source record is in step's result variable.
    3727             :  */
    3728             : void
    3729      402782 : ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3730             : {
    3731      402782 :     AttrNumber  fieldnum = op->d.fieldselect.fieldnum;
    3732             :     Datum       tupDatum;
    3733             :     HeapTupleHeader tuple;
    3734             :     Oid         tupType;
    3735             :     int32       tupTypmod;
    3736             :     TupleDesc   tupDesc;
    3737             :     Form_pg_attribute attr;
    3738             :     HeapTupleData tmptup;
    3739             : 
    3740             :     /* NULL record -> NULL result */
    3741      402782 :     if (*op->resnull)
    3742         188 :         return;
    3743             : 
    3744      402594 :     tupDatum = *op->resvalue;
    3745             : 
    3746             :     /* We can special-case expanded records for speed */
    3747      402594 :     if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(tupDatum)))
    3748         662 :     {
    3749         662 :         ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(tupDatum);
    3750             : 
    3751             :         Assert(erh->er_magic == ER_MAGIC);
    3752             : 
    3753             :         /* Extract record's TupleDesc */
    3754         662 :         tupDesc = expanded_record_get_tupdesc(erh);
    3755             : 
    3756             :         /*
    3757             :          * Find field's attr record.  Note we don't support system columns
    3758             :          * here: a datum tuple doesn't have valid values for most of the
    3759             :          * interesting system columns anyway.
    3760             :          */
    3761         662 :         if (fieldnum <= 0)       /* should never happen */
    3762           0 :             elog(ERROR, "unsupported reference to system column %d in FieldSelect",
    3763             :                  fieldnum);
    3764         662 :         if (fieldnum > tupDesc->natts)    /* should never happen */
    3765           0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    3766             :                  fieldnum, tupDesc->natts);
    3767         662 :         attr = TupleDescAttr(tupDesc, fieldnum - 1);
    3768             : 
    3769             :         /* Check for dropped column, and force a NULL result if so */
    3770         662 :         if (attr->attisdropped)
    3771             :         {
    3772           0 :             *op->resnull = true;
    3773           0 :             return;
    3774             :         }
    3775             : 
    3776             :         /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
    3777             :         /* As in CheckVarSlotCompatibility, we should but can't check typmod */
    3778         662 :         if (op->d.fieldselect.resulttype != attr->atttypid)
    3779           0 :             ereport(ERROR,
    3780             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3781             :                      errmsg("attribute %d has wrong type", fieldnum),
    3782             :                      errdetail("Table has type %s, but query expects %s.",
    3783             :                                format_type_be(attr->atttypid),
    3784             :                                format_type_be(op->d.fieldselect.resulttype))));
    3785             : 
    3786             :         /* extract the field */
    3787         662 :         *op->resvalue = expanded_record_get_field(erh, fieldnum,
    3788             :                                                   op->resnull);
    3789             :     }
    3790             :     else
    3791             :     {
    3792             :         /* Get the composite datum and extract its type fields */
    3793      401932 :         tuple = DatumGetHeapTupleHeader(tupDatum);
    3794             : 
    3795      401932 :         tupType = HeapTupleHeaderGetTypeId(tuple);
    3796      401932 :         tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    3797             : 
    3798             :         /* Lookup tupdesc if first time through or if type changes */
    3799      401932 :         tupDesc = get_cached_rowtype(tupType, tupTypmod,
    3800             :                                      &op->d.fieldselect.rowcache, NULL);
    3801             : 
    3802             :         /*
    3803             :          * Find field's attr record.  Note we don't support system columns
    3804             :          * here: a datum tuple doesn't have valid values for most of the
    3805             :          * interesting system columns anyway.
    3806             :          */
    3807      401932 :         if (fieldnum <= 0)       /* should never happen */
    3808           0 :             elog(ERROR, "unsupported reference to system column %d in FieldSelect",
    3809             :                  fieldnum);
    3810      401932 :         if (fieldnum > tupDesc->natts)    /* should never happen */
    3811           0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    3812             :                  fieldnum, tupDesc->natts);
    3813      401932 :         attr = TupleDescAttr(tupDesc, fieldnum - 1);
    3814             : 
    3815             :         /* Check for dropped column, and force a NULL result if so */
    3816      401932 :         if (attr->attisdropped)
    3817             :         {
    3818           0 :             *op->resnull = true;
    3819           0 :             return;
    3820             :         }
    3821             : 
    3822             :         /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
    3823             :         /* As in CheckVarSlotCompatibility, we should but can't check typmod */
    3824      401932 :         if (op->d.fieldselect.resulttype != attr->atttypid)
    3825           0 :             ereport(ERROR,
    3826             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3827             :                      errmsg("attribute %d has wrong type", fieldnum),
    3828             :                      errdetail("Table has type %s, but query expects %s.",
    3829             :                                format_type_be(attr->atttypid),
    3830             :                                format_type_be(op->d.fieldselect.resulttype))));
    3831             : 
    3832             :         /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */
    3833      401932 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3834      401932 :         tmptup.t_data = tuple;
    3835             : 
    3836             :         /* extract the field */
    3837      401932 :         *op->resvalue = heap_getattr(&tmptup,
    3838             :                                      fieldnum,
    3839             :                                      tupDesc,
    3840             :                                      op->resnull);
    3841             :     }
    3842             : }
    3843             : 
    3844             : /*
    3845             :  * Deform source tuple, filling in the step's values/nulls arrays, before
    3846             :  * evaluating individual new values as part of a FieldStore expression.
    3847             :  * Subsequent steps will overwrite individual elements of the values/nulls
    3848             :  * arrays with the new field values, and then FIELDSTORE_FORM will build the
    3849             :  * new tuple value.
    3850             :  *
    3851             :  * Source record is in step's result variable.
    3852             :  */
    3853             : void
    3854         520 : ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3855             : {
    3856         520 :     if (*op->resnull)
    3857             :     {
    3858             :         /* Convert null input tuple into an all-nulls row */
    3859         256 :         memset(op->d.fieldstore.nulls, true,
    3860         256 :                op->d.fieldstore.ncolumns * sizeof(bool));
    3861             :     }
    3862             :     else
    3863             :     {
    3864             :         /*
    3865             :          * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We
    3866             :          * set all the fields in the struct just in case.
    3867             :          */
    3868         264 :         Datum       tupDatum = *op->resvalue;
    3869             :         HeapTupleHeader tuphdr;
    3870             :         HeapTupleData tmptup;
    3871             :         TupleDesc   tupDesc;
    3872             : 
    3873         264 :         tuphdr = DatumGetHeapTupleHeader(tupDatum);
    3874         264 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
    3875         264 :         ItemPointerSetInvalid(&(tmptup.t_self));
    3876         264 :         tmptup.t_tableOid = InvalidOid;
    3877         264 :         tmptup.t_data = tuphdr;
    3878             : 
    3879             :         /*
    3880             :          * Lookup tupdesc if first time through or if type changes.  Because
    3881             :          * we don't pin the tupdesc, we must not do this lookup until after
    3882             :          * doing DatumGetHeapTupleHeader: that could do database access while
    3883             :          * detoasting the datum.
    3884             :          */
    3885         264 :         tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
    3886             :                                      op->d.fieldstore.rowcache, NULL);
    3887             : 
    3888             :         /* Check that current tupdesc doesn't have more fields than allocated */
    3889         264 :         if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns))
    3890           0 :             elog(ERROR, "too many columns in composite type %u",
    3891             :                  op->d.fieldstore.fstore->resulttype);
    3892             : 
    3893         264 :         heap_deform_tuple(&tmptup, tupDesc,
    3894             :                           op->d.fieldstore.values,
    3895             :                           op->d.fieldstore.nulls);
    3896             :     }
    3897         520 : }
    3898             : 
    3899             : /*
    3900             :  * Compute the new composite datum after each individual field value of a
    3901             :  * FieldStore expression has been evaluated.
    3902             :  */
    3903             : void
    3904         520 : ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3905             : {
    3906             :     TupleDesc   tupDesc;
    3907             :     HeapTuple   tuple;
    3908             : 
    3909             :     /* Lookup tupdesc (should be valid already) */
    3910         520 :     tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
    3911             :                                  op->d.fieldstore.rowcache, NULL);
    3912             : 
    3913         520 :     tuple = heap_form_tuple(tupDesc,
    3914         520 :                             op->d.fieldstore.values,
    3915         520 :                             op->d.fieldstore.nulls);
    3916             : 
    3917         520 :     *op->resvalue = HeapTupleGetDatum(tuple);
    3918         520 :     *op->resnull = false;
    3919         520 : }
    3920             : 
    3921             : /*
    3922             :  * Evaluate a rowtype coercion operation.
    3923             :  * This may require rearranging field positions.
    3924             :  *
    3925             :  * Source record is in step's result variable.
    3926             :  */
    3927             : void
    3928       12260 : ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3929             : {
    3930             :     HeapTuple   result;
    3931             :     Datum       tupDatum;
    3932             :     HeapTupleHeader tuple;
    3933             :     HeapTupleData tmptup;
    3934             :     TupleDesc   indesc,
    3935             :                 outdesc;
    3936       12260 :     bool        changed = false;
    3937             : 
    3938             :     /* NULL in -> NULL out */
    3939       12260 :     if (*op->resnull)
    3940          44 :         return;
    3941             : 
    3942       12216 :     tupDatum = *op->resvalue;
    3943       12216 :     tuple = DatumGetHeapTupleHeader(tupDatum);
    3944             : 
    3945             :     /*
    3946             :      * Lookup tupdescs if first time through or if type changes.  We'd better
    3947             :      * pin them since type conversion functions could do catalog lookups and
    3948             :      * hence cause cache invalidation.
    3949             :      */
    3950       12216 :     indesc = get_cached_rowtype(op->d.convert_rowtype.inputtype, -1,
    3951             :                                 op->d.convert_rowtype.incache,
    3952             :                                 &changed);
    3953       12216 :     IncrTupleDescRefCount(indesc);
    3954       12216 :     outdesc = get_cached_rowtype(op->d.convert_rowtype.outputtype, -1,
    3955             :                                  op->d.convert_rowtype.outcache,
    3956             :                                  &changed);
    3957       12216 :     IncrTupleDescRefCount(outdesc);
    3958             : 
    3959             :     /*
    3960             :      * We used to be able to assert that incoming tuples are marked with
    3961             :      * exactly the rowtype of indesc.  However, now that ExecEvalWholeRowVar
    3962             :      * might change the tuples' marking to plain RECORD due to inserting
    3963             :      * aliases, we can only make this weak test:
    3964             :      */
    3965             :     Assert(HeapTupleHeaderGetTypeId(tuple) == indesc->tdtypeid ||
    3966             :            HeapTupleHeaderGetTypeId(tuple) == RECORDOID);
    3967             : 
    3968             :     /* if first time through, or after change, initialize conversion map */
    3969       12216 :     if (changed)
    3970             :     {
    3971             :         MemoryContext old_cxt;
    3972             : 
    3973             :         /* allocate map in long-lived memory context */
    3974         480 :         old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    3975             : 
    3976             :         /* prepare map from old to new attribute numbers */
    3977         480 :         op->d.convert_rowtype.map = convert_tuples_by_name(indesc, outdesc);
    3978             : 
    3979         480 :         MemoryContextSwitchTo(old_cxt);
    3980             :     }
    3981             : 
    3982             :     /* Following steps need a HeapTuple not a bare HeapTupleHeader */
    3983       12216 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3984       12216 :     tmptup.t_data = tuple;
    3985             : 
    3986       12216 :     if (op->d.convert_rowtype.map != NULL)
    3987             :     {
    3988             :         /* Full conversion with attribute rearrangement needed */
    3989         576 :         result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
    3990             :         /* Result already has appropriate composite-datum header fields */
    3991         576 :         *op->resvalue = HeapTupleGetDatum(result);
    3992             :     }
    3993             :     else
    3994             :     {
    3995             :         /*
    3996             :          * The tuple is physically compatible as-is, but we need to insert the
    3997             :          * destination rowtype OID in its composite-datum header field, so we
    3998             :          * have to copy it anyway.  heap_copy_tuple_as_datum() is convenient
    3999             :          * for this since it will both make the physical copy and insert the
    4000             :          * correct composite header fields.  Note that we aren't expecting to
    4001             :          * have to flatten any toasted fields: the input was a composite
    4002             :          * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
    4003             :          * is overkill here, but its check for external fields is cheap.
    4004             :          */
    4005       11640 :         *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
    4006             :     }
    4007             : 
    4008       12216 :     DecrTupleDescRefCount(indesc);
    4009       12216 :     DecrTupleDescRefCount(outdesc);
    4010             : }
    4011             : 
    4012             : /*
    4013             :  * Evaluate "scalar op ANY/ALL (array)".
    4014             :  *
    4015             :  * Source array is in our result area, scalar arg is already evaluated into
    4016             :  * fcinfo->args[0].
    4017             :  *
    4018             :  * The operator always yields boolean, and we combine the results across all
    4019             :  * array elements using OR and AND (for ANY and ALL respectively).  Of course
    4020             :  * we short-circuit as soon as the result is known.
    4021             :  */
    4022             : void
    4023     4438458 : ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
    4024             : {
    4025     4438458 :     FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
    4026     4438458 :     bool        useOr = op->d.scalararrayop.useOr;
    4027     4438458 :     bool        strictfunc = op->d.scalararrayop.finfo->fn_strict;
    4028             :     ArrayType  *arr;
    4029             :     int         nitems;
    4030             :     Datum       result;
    4031             :     bool        resultnull;
    4032             :     int16       typlen;
    4033             :     bool        typbyval;
    4034             :     char        typalign;
    4035             :     char       *s;
    4036             :     bits8      *bitmap;
    4037             :     int         bitmask;
    4038             : 
    4039             :     /*
    4040             :      * If the array is NULL then we return NULL --- it's not very meaningful
    4041             :      * to do anything else, even if the operator isn't strict.
    4042             :      */
    4043     4438458 :     if (*op->resnull)
    4044      181894 :         return;
    4045             : 
    4046             :     /* Else okay to fetch and detoast the array */
    4047     4256564 :     arr = DatumGetArrayTypeP(*op->resvalue);
    4048             : 
    4049             :     /*
    4050             :      * If the array is empty, we return either FALSE or TRUE per the useOr
    4051             :      * flag.  This is correct even if the scalar is NULL; since we would
    4052             :      * evaluate the operator zero times, it matters not whether it would want
    4053             :      * to return NULL.
    4054             :      */
    4055     4256564 :     nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    4056     4256564 :     if (nitems <= 0)
    4057             :     {
    4058       13438 :         *op->resvalue = BoolGetDatum(!useOr);
    4059       13438 :         *op->resnull = false;
    4060       13438 :         return;
    4061             :     }
    4062             : 
    4063             :     /*
    4064             :      * If the scalar is NULL, and the function is strict, return NULL; no
    4065             :      * point in iterating the loop.
    4066             :      */
    4067     4243126 :     if (fcinfo->args[0].isnull && strictfunc)
    4068             :     {
    4069         986 :         *op->resnull = true;
    4070         986 :         return;
    4071             :     }
    4072             : 
    4073             :     /*
    4074             :      * We arrange to look up info about the element type only once per series
    4075             :      * of calls, assuming the element type doesn't change underneath us.
    4076             :      */
    4077     4242140 :     if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
    4078             :     {
    4079       18054 :         get_typlenbyvalalign(ARR_ELEMTYPE(arr),
    4080             :                              &op->d.scalararrayop.typlen,
    4081             :                              &op->d.scalararrayop.typbyval,
    4082             :                              &op->d.scalararrayop.typalign);
    4083       18054 :         op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
    4084             :     }
    4085             : 
    4086     4242140 :     typlen = op->d.scalararrayop.typlen;
    4087     4242140 :     typbyval = op->d.scalararrayop.typbyval;
    4088     4242140 :     typalign = op->d.scalararrayop.typalign;
    4089             : 
    4090             :     /* Initialize result appropriately depending on useOr */
    4091     4242140 :     result = BoolGetDatum(!useOr);
    4092     4242140 :     resultnull = false;
    4093             : 
    4094             :     /* Loop over the array elements */
    4095     4242140 :     s = (char *) ARR_DATA_PTR(arr);
    4096     4242140 :     bitmap = ARR_NULLBITMAP(arr);
    4097     4242140 :     bitmask = 1;
    4098             : 
    4099    11570912 :     for (int i = 0; i < nitems; i++)
    4100             :     {
    4101             :         Datum       elt;
    4102             :         Datum       thisresult;
    4103             : 
    4104             :         /* Get array element, checking for NULL */
    4105     9230616 :         if (bitmap && (*bitmap & bitmask) == 0)
    4106             :         {
    4107      215264 :             fcinfo->args[1].value = (Datum) 0;
    4108      215264 :             fcinfo->args[1].isnull = true;
    4109             :         }
    4110             :         else
    4111             :         {
    4112     9015352 :             elt = fetch_att(s, typbyval, typlen);
    4113     9015352 :             s = att_addlength_pointer(s, typlen, s);
    4114     9015352 :             s = (char *) att_align_nominal(s, typalign);
    4115     9015352 :             fcinfo->args[1].value = elt;
    4116     9015352 :             fcinfo->args[1].isnull = false;
    4117             :         }
    4118             : 
    4119             :         /* Call comparison function */
    4120     9230616 :         if (fcinfo->args[1].isnull && strictfunc)
    4121             :         {
    4122      215240 :             fcinfo->isnull = true;
    4123      215240 :             thisresult = (Datum) 0;
    4124             :         }
    4125             :         else
    4126             :         {
    4127     9015376 :             fcinfo->isnull = false;
    4128     9015376 :             thisresult = op->d.scalararrayop.fn_addr(fcinfo);
    4129             :         }
    4130             : 
    4131             :         /* Combine results per OR or AND semantics */
    4132     9230616 :         if (fcinfo->isnull)
    4133      215336 :             resultnull = true;
    4134     9015280 :         else if (useOr)
    4135             :         {
    4136     8144692 :             if (DatumGetBool(thisresult))
    4137             :             {
    4138     1262642 :                 result = BoolGetDatum(true);
    4139     1262642 :                 resultnull = false;
    4140     1262642 :                 break;          /* needn't look at any more elements */
    4141             :             }
    4142             :         }
    4143             :         else
    4144             :         {
    4145      870588 :             if (!DatumGetBool(thisresult))
    4146             :             {
    4147      639202 :                 result = BoolGetDatum(false);
    4148      639202 :                 resultnull = false;
    4149      639202 :                 break;          /* needn't look at any more elements */
    4150             :             }
    4151             :         }
    4152             : 
    4153             :         /* advance bitmap pointer if any */
    4154     7328772 :         if (bitmap)
    4155             :         {
    4156      767988 :             bitmask <<= 1;
    4157      767988 :             if (bitmask == 0x100)
    4158             :             {
    4159         776 :                 bitmap++;
    4160         776 :                 bitmask = 1;
    4161             :             }
    4162             :         }
    4163             :     }
    4164             : 
    4165     4242140 :     *op->resvalue = result;
    4166     4242140 :     *op->resnull = resultnull;
    4167             : }
    4168             : 
    4169             : /*
    4170             :  * Hash function for scalar array hash op elements.
    4171             :  *
    4172             :  * We use the element type's default hash opclass, and the column collation
    4173             :  * if the type is collation-sensitive.
    4174             :  */
    4175             : static uint32
    4176        6766 : saop_element_hash(struct saophash_hash *tb, Datum key)
    4177             : {
    4178        6766 :     ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
    4179        6766 :     FunctionCallInfo fcinfo = &elements_tab->hash_fcinfo_data;
    4180             :     Datum       hash;
    4181             : 
    4182        6766 :     fcinfo->args[0].value = key;
    4183        6766 :     fcinfo->args[0].isnull = false;
    4184             : 
    4185        6766 :     hash = elements_tab->hash_finfo.fn_addr(fcinfo);
    4186             : 
    4187        6766 :     return DatumGetUInt32(hash);
    4188             : }
    4189             : 
    4190             : /*
    4191             :  * Matching function for scalar array hash op elements, to be used in hashtable
    4192             :  * lookups.
    4193             :  */
    4194             : static bool
    4195        4590 : saop_hash_element_match(struct saophash_hash *tb, Datum key1, Datum key2)
    4196             : {
    4197             :     Datum       result;
    4198             : 
    4199        4590 :     ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
    4200        4590 :     FunctionCallInfo fcinfo = elements_tab->op->d.hashedscalararrayop.fcinfo_data;
    4201             : 
    4202        4590 :     fcinfo->args[0].value = key1;
    4203        4590 :     fcinfo->args[0].isnull = false;
    4204        4590 :     fcinfo->args[1].value = key2;
    4205        4590 :     fcinfo->args[1].isnull = false;
    4206             : 
    4207        4590 :     result = elements_tab->op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
    4208             : 
    4209        4590 :     return DatumGetBool(result);
    4210             : }
    4211             : 
    4212             : /*
    4213             :  * Evaluate "scalar op ANY (const array)".
    4214             :  *
    4215             :  * Similar to ExecEvalScalarArrayOp, but optimized for faster repeat lookups
    4216             :  * by building a hashtable on the first lookup.  This hashtable will be reused
    4217             :  * by subsequent lookups.  Unlike ExecEvalScalarArrayOp, this version only
    4218             :  * supports OR semantics.
    4219             :  *
    4220             :  * Source array is in our result area, scalar arg is already evaluated into
    4221             :  * fcinfo->args[0].
    4222             :  *
    4223             :  * The operator always yields boolean.
    4224             :  */
    4225             : void
    4226        4806 : ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    4227             : {
    4228        4806 :     ScalarArrayOpExprHashTable *elements_tab = op->d.hashedscalararrayop.elements_tab;
    4229        4806 :     FunctionCallInfo fcinfo = op->d.hashedscalararrayop.fcinfo_data;
    4230        4806 :     bool        inclause = op->d.hashedscalararrayop.inclause;
    4231        4806 :     bool        strictfunc = op->d.hashedscalararrayop.finfo->fn_strict;
    4232        4806 :     Datum       scalar = fcinfo->args[0].value;
    4233        4806 :     bool        scalar_isnull = fcinfo->args[0].isnull;
    4234             :     Datum       result;
    4235             :     bool        resultnull;
    4236             :     bool        hashfound;
    4237             : 
    4238             :     /* We don't setup a hashed scalar array op if the array const is null. */
    4239             :     Assert(!*op->resnull);
    4240             : 
    4241             :     /*
    4242             :      * If the scalar is NULL, and the function is strict, return NULL; no
    4243             :      * point in executing the search.
    4244             :      */
    4245        4806 :     if (fcinfo->args[0].isnull && strictfunc)
    4246             :     {
    4247          68 :         *op->resnull = true;
    4248          68 :         return;
    4249             :     }
    4250             : 
    4251             :     /* Build the hash table on first evaluation */
    4252        4738 :     if (elements_tab == NULL)
    4253             :     {
    4254             :         ScalarArrayOpExpr *saop;
    4255             :         int16       typlen;
    4256             :         bool        typbyval;
    4257             :         char        typalign;
    4258             :         int         nitems;
    4259         156 :         bool        has_nulls = false;
    4260             :         char       *s;
    4261             :         bits8      *bitmap;
    4262             :         int         bitmask;
    4263             :         MemoryContext oldcontext;
    4264             :         ArrayType  *arr;
    4265             : 
    4266         156 :         saop = op->d.hashedscalararrayop.saop;
    4267             : 
    4268         156 :         arr = DatumGetArrayTypeP(*op->resvalue);
    4269         156 :         nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    4270             : 
    4271         156 :         get_typlenbyvalalign(ARR_ELEMTYPE(arr),
    4272             :                              &typlen,
    4273             :                              &typbyval,
    4274             :                              &typalign);
    4275             : 
    4276         156 :         oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    4277             : 
    4278             :         elements_tab = (ScalarArrayOpExprHashTable *)
    4279         156 :             palloc0(offsetof(ScalarArrayOpExprHashTable, hash_fcinfo_data) +
    4280             :                     SizeForFunctionCallInfo(1));
    4281         156 :         op->d.hashedscalararrayop.elements_tab = elements_tab;
    4282         156 :         elements_tab->op = op;
    4283             : 
    4284         156 :         fmgr_info(saop->hashfuncid, &elements_tab->hash_finfo);
    4285         156 :         fmgr_info_set_expr((Node *) saop, &elements_tab->hash_finfo);
    4286             : 
    4287         156 :         InitFunctionCallInfoData(elements_tab->hash_fcinfo_data,
    4288             :                                  &elements_tab->hash_finfo,
    4289             :                                  1,
    4290             :                                  saop->inputcollid,
    4291             :                                  NULL,
    4292             :                                  NULL);
    4293             : 
    4294             :         /*
    4295             :          * Create the hash table sizing it according to the number of elements
    4296             :          * in the array.  This does assume that the array has no duplicates.
    4297             :          * If the array happens to contain many duplicate values then it'll
    4298             :          * just mean that we sized the table a bit on the large side.
    4299             :          */
    4300         156 :         elements_tab->hashtab = saophash_create(CurrentMemoryContext, nitems,
    4301             :                                                 elements_tab);
    4302             : 
    4303         156 :         MemoryContextSwitchTo(oldcontext);
    4304             : 
    4305         156 :         s = (char *) ARR_DATA_PTR(arr);
    4306         156 :         bitmap = ARR_NULLBITMAP(arr);
    4307         156 :         bitmask = 1;
    4308        2358 :         for (int i = 0; i < nitems; i++)
    4309             :         {
    4310             :             /* Get array element, checking for NULL. */
    4311        2202 :             if (bitmap && (*bitmap & bitmask) == 0)
    4312             :             {
    4313         174 :                 has_nulls = true;
    4314             :             }
    4315             :             else
    4316             :             {
    4317             :                 Datum       element;
    4318             : 
    4319        2028 :                 element = fetch_att(s, typbyval, typlen);
    4320        2028 :                 s = att_addlength_pointer(s, typlen, s);
    4321        2028 :                 s = (char *) att_align_nominal(s, typalign);
    4322             : 
    4323        2028 :                 saophash_insert(elements_tab->hashtab, element, &hashfound);
    4324             :             }
    4325             : 
    4326             :             /* Advance bitmap pointer if any. */
    4327        2202 :             if (bitmap)
    4328             :             {
    4329         570 :                 bitmask <<= 1;
    4330         570 :                 if (bitmask == 0x100)
    4331             :                 {
    4332          54 :                     bitmap++;
    4333          54 :                     bitmask = 1;
    4334             :                 }
    4335             :             }
    4336             :         }
    4337             : 
    4338             :         /*
    4339             :          * Remember if we had any nulls so that we know if we need to execute
    4340             :          * non-strict functions with a null lhs value if no match is found.
    4341             :          */
    4342         156 :         op->d.hashedscalararrayop.has_nulls = has_nulls;
    4343             :     }
    4344             : 
    4345             :     /* Check the hash to see if we have a match. */
    4346        4738 :     hashfound = NULL != saophash_lookup(elements_tab->hashtab, scalar);
    4347             : 
    4348             :     /* the result depends on if the clause is an IN or NOT IN clause */
    4349        4738 :     if (inclause)
    4350         972 :         result = BoolGetDatum(hashfound);   /* IN */
    4351             :     else
    4352        3766 :         result = BoolGetDatum(!hashfound);  /* NOT IN */
    4353             : 
    4354        4738 :     resultnull = false;
    4355             : 
    4356             :     /*
    4357             :      * If we didn't find a match in the array, we still might need to handle
    4358             :      * the possibility of null values.  We didn't put any NULLs into the
    4359             :      * hashtable, but instead marked if we found any when building the table
    4360             :      * in has_nulls.
    4361             :      */
    4362        4738 :     if (!hashfound && op->d.hashedscalararrayop.has_nulls)
    4363             :     {
    4364          42 :         if (strictfunc)
    4365             :         {
    4366             : 
    4367             :             /*
    4368             :              * We have nulls in the array so a non-null lhs and no match must
    4369             :              * yield NULL.
    4370             :              */
    4371          24 :             result = (Datum) 0;
    4372          24 :             resultnull = true;
    4373             :         }
    4374             :         else
    4375             :         {
    4376             :             /*
    4377             :              * Execute function will null rhs just once.
    4378             :              *
    4379             :              * The hash lookup path will have scribbled on the lhs argument so
    4380             :              * we need to set it up also (even though we entered this function
    4381             :              * with it already set).
    4382             :              */
    4383          18 :             fcinfo->args[0].value = scalar;
    4384          18 :             fcinfo->args[0].isnull = scalar_isnull;
    4385          18 :             fcinfo->args[1].value = (Datum) 0;
    4386          18 :             fcinfo->args[1].isnull = true;
    4387             : 
    4388          18 :             result = op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
    4389          18 :             resultnull = fcinfo->isnull;
    4390             : 
    4391             :             /*
    4392             :              * Reverse the result for NOT IN clauses since the above function
    4393             :              * is the equality function and we need not-equals.
    4394             :              */
    4395          18 :             if (!inclause)
    4396          12 :                 result = !result;
    4397             :         }
    4398             :     }
    4399             : 
    4400        4738 :     *op->resvalue = result;
    4401        4738 :     *op->resnull = resultnull;
    4402             : }
    4403             : 
    4404             : /*
    4405             :  * Evaluate a NOT NULL domain constraint.
    4406             :  */
    4407             : void
    4408         378 : ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
    4409             : {
    4410         378 :     if (*op->resnull)
    4411         106 :         errsave((Node *) op->d.domaincheck.escontext,
    4412             :                 (errcode(ERRCODE_NOT_NULL_VIOLATION),
    4413             :                  errmsg("domain %s does not allow null values",
    4414             :                         format_type_be(op->d.domaincheck.resulttype)),
    4415             :                  errdatatype(op->d.domaincheck.resulttype)));
    4416         272 : }
    4417             : 
    4418             : /*
    4419             :  * Evaluate a CHECK domain constraint.
    4420             :  */
    4421             : void
    4422       13144 : ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
    4423             : {
    4424       13144 :     if (!*op->d.domaincheck.checknull &&
    4425       11974 :         !DatumGetBool(*op->d.domaincheck.checkvalue))
    4426         458 :         errsave((Node *) op->d.domaincheck.escontext,
    4427             :                 (errcode(ERRCODE_CHECK_VIOLATION),
    4428             :                  errmsg("value for domain %s violates check constraint \"%s\"",
    4429             :                         format_type_be(op->d.domaincheck.resulttype),
    4430             :                         op->d.domaincheck.constraintname),
    4431             :                  errdomainconstraint(op->d.domaincheck.resulttype,
    4432             :                                      op->d.domaincheck.constraintname)));
    4433       12716 : }
    4434             : 
    4435             : /*
    4436             :  * Evaluate the various forms of XmlExpr.
    4437             :  *
    4438             :  * Arguments have been evaluated into named_argvalue/named_argnull
    4439             :  * and/or argvalue/argnull arrays.
    4440             :  */
    4441             : void
    4442       45230 : ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
    4443             : {
    4444       45230 :     XmlExpr    *xexpr = op->d.xmlexpr.xexpr;
    4445             :     Datum       value;
    4446             : 
    4447       45230 :     *op->resnull = true;     /* until we get a result */
    4448       45230 :     *op->resvalue = (Datum) 0;
    4449             : 
    4450       45230 :     switch (xexpr->op)
    4451             :     {
    4452          54 :         case IS_XMLCONCAT:
    4453             :             {
    4454          54 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4455          54 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4456          54 :                 List       *values = NIL;
    4457             : 
    4458         174 :                 for (int i = 0; i < list_length(xexpr->args); i++)
    4459             :                 {
    4460         120 :                     if (!argnull[i])
    4461          90 :                         values = lappend(values, DatumGetPointer(argvalue[i]));
    4462             :                 }
    4463             : 
    4464          54 :                 if (values != NIL)
    4465             :                 {
    4466          42 :                     *op->resvalue = PointerGetDatum(xmlconcat(values));
    4467          42 :                     *op->resnull = false;
    4468             :                 }
    4469             :             }
    4470          54 :             break;
    4471             : 
    4472       22270 :         case IS_XMLFOREST:
    4473             :             {
    4474       22270 :                 Datum      *argvalue = op->d.xmlexpr.named_argvalue;
    4475       22270 :                 bool       *argnull = op->d.xmlexpr.named_argnull;
    4476             :                 StringInfoData buf;
    4477             :                 ListCell   *lc;
    4478             :                 ListCell   *lc2;
    4479             :                 int         i;
    4480             : 
    4481       22270 :                 initStringInfo(&buf);
    4482             : 
    4483       22270 :                 i = 0;
    4484      155770 :                 forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
    4485             :                 {
    4486      133500 :                     Expr       *e = (Expr *) lfirst(lc);
    4487      133500 :                     char       *argname = strVal(lfirst(lc2));
    4488             : 
    4489      133500 :                     if (!argnull[i])
    4490             :                     {
    4491      111416 :                         value = argvalue[i];
    4492      111416 :                         appendStringInfo(&buf, "<%s>%s</%s>",
    4493             :                                          argname,
    4494             :                                          map_sql_value_to_xml_value(value,
    4495             :                                                                     exprType((Node *) e), true),
    4496             :                                          argname);
    4497      111416 :                         *op->resnull = false;
    4498             :                     }
    4499      133500 :                     i++;
    4500             :                 }
    4501             : 
    4502       22270 :                 if (!*op->resnull)
    4503             :                 {
    4504             :                     text       *result;
    4505             : 
    4506       22270 :                     result = cstring_to_text_with_len(buf.data, buf.len);
    4507       22270 :                     *op->resvalue = PointerGetDatum(result);
    4508             :                 }
    4509             : 
    4510       22270 :                 pfree(buf.data);
    4511             :             }
    4512       22270 :             break;
    4513             : 
    4514       22426 :         case IS_XMLELEMENT:
    4515       22426 :             *op->resvalue = PointerGetDatum(xmlelement(xexpr,
    4516             :                                                        op->d.xmlexpr.named_argvalue,
    4517             :                                                        op->d.xmlexpr.named_argnull,
    4518             :                                                        op->d.xmlexpr.argvalue,
    4519             :                                                        op->d.xmlexpr.argnull));
    4520       22420 :             *op->resnull = false;
    4521       22420 :             break;
    4522             : 
    4523         132 :         case IS_XMLPARSE:
    4524             :             {
    4525         132 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4526         132 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4527             :                 text       *data;
    4528             :                 bool        preserve_whitespace;
    4529             : 
    4530             :                 /* arguments are known to be text, bool */
    4531             :                 Assert(list_length(xexpr->args) == 2);
    4532             : 
    4533         132 :                 if (argnull[0])
    4534           0 :                     return;
    4535         132 :                 value = argvalue[0];
    4536         132 :                 data = DatumGetTextPP(value);
    4537             : 
    4538         132 :                 if (argnull[1]) /* probably can't happen */
    4539           0 :                     return;
    4540         132 :                 value = argvalue[1];
    4541         132 :                 preserve_whitespace = DatumGetBool(value);
    4542             : 
    4543         132 :                 *op->resvalue = PointerGetDatum(xmlparse(data,
    4544             :                                                          xexpr->xmloption,
    4545             :                                                          preserve_whitespace));
    4546          84 :                 *op->resnull = false;
    4547             :             }
    4548          84 :             break;
    4549             : 
    4550          72 :         case IS_XMLPI:
    4551             :             {
    4552             :                 text       *arg;
    4553             :                 bool        isnull;
    4554             : 
    4555             :                 /* optional argument is known to be text */
    4556             :                 Assert(list_length(xexpr->args) <= 1);
    4557             : 
    4558          72 :                 if (xexpr->args)
    4559             :                 {
    4560          42 :                     isnull = op->d.xmlexpr.argnull[0];
    4561          42 :                     if (isnull)
    4562          18 :                         arg = NULL;
    4563             :                     else
    4564          24 :                         arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]);
    4565             :                 }
    4566             :                 else
    4567             :                 {
    4568          30 :                     arg = NULL;
    4569          30 :                     isnull = false;
    4570             :                 }
    4571             : 
    4572          72 :                 *op->resvalue = PointerGetDatum(xmlpi(xexpr->name,
    4573             :                                                       arg,
    4574             :                                                       isnull,
    4575             :                                                       op->resnull));
    4576             :             }
    4577          54 :             break;
    4578             : 
    4579          60 :         case IS_XMLROOT:
    4580             :             {
    4581          60 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4582          60 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4583             :                 xmltype    *data;
    4584             :                 text       *version;
    4585             :                 int         standalone;
    4586             : 
    4587             :                 /* arguments are known to be xml, text, int */
    4588             :                 Assert(list_length(xexpr->args) == 3);
    4589             : 
    4590          60 :                 if (argnull[0])
    4591           0 :                     return;
    4592          60 :                 data = DatumGetXmlP(argvalue[0]);
    4593             : 
    4594          60 :                 if (argnull[1])
    4595          36 :                     version = NULL;
    4596             :                 else
    4597          24 :                     version = DatumGetTextPP(argvalue[1]);
    4598             : 
    4599             :                 Assert(!argnull[2]);    /* always present */
    4600          60 :                 standalone = DatumGetInt32(argvalue[2]);
    4601             : 
    4602          60 :                 *op->resvalue = PointerGetDatum(xmlroot(data,
    4603             :                                                         version,
    4604             :                                                         standalone));
    4605          60 :                 *op->resnull = false;
    4606             :             }
    4607          60 :             break;
    4608             : 
    4609         192 :         case IS_XMLSERIALIZE:
    4610             :             {
    4611         192 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4612         192 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4613             : 
    4614             :                 /* argument type is known to be xml */
    4615             :                 Assert(list_length(xexpr->args) == 1);
    4616             : 
    4617         192 :                 if (argnull[0])
    4618          12 :                     return;
    4619         180 :                 value = argvalue[0];
    4620             : 
    4621         300 :                 *op->resvalue =
    4622         180 :                     PointerGetDatum(xmltotext_with_options(DatumGetXmlP(value),
    4623             :                                                            xexpr->xmloption,
    4624         180 :                                                            xexpr->indent));
    4625         150 :                 *op->resnull = false;
    4626             :             }
    4627         150 :             break;
    4628             : 
    4629          24 :         case IS_DOCUMENT:
    4630             :             {
    4631          24 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4632          24 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4633             : 
    4634             :                 /* optional argument is known to be xml */
    4635             :                 Assert(list_length(xexpr->args) == 1);
    4636             : 
    4637          24 :                 if (argnull[0])
    4638           0 :                     return;
    4639          24 :                 value = argvalue[0];
    4640             : 
    4641          48 :                 *op->resvalue =
    4642          24 :                     BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
    4643          24 :                 *op->resnull = false;
    4644             :             }
    4645          24 :             break;
    4646             : 
    4647           0 :         default:
    4648           0 :             elog(ERROR, "unrecognized XML operation");
    4649             :             break;
    4650             :     }
    4651             : }
    4652             : 
    4653             : /*
    4654             :  * Evaluate a JSON constructor expression.
    4655             :  */
    4656             : void
    4657         702 : ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
    4658             :                         ExprContext *econtext)
    4659             : {
    4660             :     Datum       res;
    4661         702 :     JsonConstructorExprState *jcstate = op->d.json_constructor.jcstate;
    4662         702 :     JsonConstructorExpr *ctor = jcstate->constructor;
    4663         702 :     bool        is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
    4664         702 :     bool        isnull = false;
    4665             : 
    4666         702 :     if (ctor->type == JSCTOR_JSON_ARRAY)
    4667             :         res = (is_jsonb ?
    4668         218 :                jsonb_build_array_worker :
    4669             :                json_build_array_worker) (jcstate->nargs,
    4670         218 :                                          jcstate->arg_values,
    4671         218 :                                          jcstate->arg_nulls,
    4672         218 :                                          jcstate->arg_types,
    4673         218 :                                          jcstate->constructor->absent_on_null);
    4674         484 :     else if (ctor->type == JSCTOR_JSON_OBJECT)
    4675             :         res = (is_jsonb ?
    4676         374 :                jsonb_build_object_worker :
    4677             :                json_build_object_worker) (jcstate->nargs,
    4678         374 :                                           jcstate->arg_values,
    4679         374 :                                           jcstate->arg_nulls,
    4680         374 :                                           jcstate->arg_types,
    4681         374 :                                           jcstate->constructor->absent_on_null,
    4682         374 :                                           jcstate->constructor->unique);
    4683         110 :     else if (ctor->type == JSCTOR_JSON_SCALAR)
    4684             :     {
    4685         100 :         if (jcstate->arg_nulls[0])
    4686             :         {
    4687          20 :             res = (Datum) 0;
    4688          20 :             isnull = true;
    4689             :         }
    4690             :         else
    4691             :         {
    4692          80 :             Datum       value = jcstate->arg_values[0];
    4693          80 :             Oid         outfuncid = jcstate->arg_type_cache[0].outfuncid;
    4694          80 :             JsonTypeCategory category = (JsonTypeCategory)
    4695          80 :                 jcstate->arg_type_cache[0].category;
    4696             : 
    4697          80 :             if (is_jsonb)
    4698           0 :                 res = datum_to_jsonb(value, category, outfuncid);
    4699             :             else
    4700          80 :                 res = datum_to_json(value, category, outfuncid);
    4701             :         }
    4702             :     }
    4703          10 :     else if (ctor->type == JSCTOR_JSON_PARSE)
    4704             :     {
    4705          10 :         if (jcstate->arg_nulls[0])
    4706             :         {
    4707           0 :             res = (Datum) 0;
    4708           0 :             isnull = true;
    4709             :         }
    4710             :         else
    4711             :         {
    4712          10 :             Datum       value = jcstate->arg_values[0];
    4713          10 :             text       *js = DatumGetTextP(value);
    4714             : 
    4715          10 :             if (is_jsonb)
    4716           0 :                 res = jsonb_from_text(js, true);
    4717             :             else
    4718             :             {
    4719          10 :                 (void) json_validate(js, true, true);
    4720           0 :                 res = value;
    4721             :             }
    4722             :         }
    4723             :     }
    4724             :     else
    4725           0 :         elog(ERROR, "invalid JsonConstructorExpr type %d", ctor->type);
    4726             : 
    4727         616 :     *op->resvalue = res;
    4728         616 :     *op->resnull = isnull;
    4729         616 : }
    4730             : 
    4731             : /*
    4732             :  * Evaluate a IS JSON predicate.
    4733             :  */
    4734             : void
    4735        2750 : ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
    4736             : {
    4737        2750 :     JsonIsPredicate *pred = op->d.is_json.pred;
    4738        2750 :     Datum       js = *op->resvalue;
    4739             :     Oid         exprtype;
    4740             :     bool        res;
    4741             : 
    4742        2750 :     if (*op->resnull)
    4743             :     {
    4744         102 :         *op->resvalue = BoolGetDatum(false);
    4745         102 :         return;
    4746             :     }
    4747             : 
    4748        2648 :     exprtype = exprType(pred->expr);
    4749             : 
    4750        2648 :     if (exprtype == TEXTOID || exprtype == JSONOID)
    4751        2120 :     {
    4752        2120 :         text       *json = DatumGetTextP(js);
    4753             : 
    4754        2120 :         if (pred->item_type == JS_TYPE_ANY)
    4755        1442 :             res = true;
    4756             :         else
    4757             :         {
    4758         678 :             switch (json_get_first_token(json, false))
    4759             :             {
    4760         300 :                 case JSON_TOKEN_OBJECT_START:
    4761         300 :                     res = pred->item_type == JS_TYPE_OBJECT;
    4762         300 :                     break;
    4763         126 :                 case JSON_TOKEN_ARRAY_START:
    4764         126 :                     res = pred->item_type == JS_TYPE_ARRAY;
    4765         126 :                     break;
    4766         216 :                 case JSON_TOKEN_STRING:
    4767             :                 case JSON_TOKEN_NUMBER:
    4768             :                 case JSON_TOKEN_TRUE:
    4769             :                 case JSON_TOKEN_FALSE:
    4770             :                 case JSON_TOKEN_NULL:
    4771         216 :                     res = pred->item_type == JS_TYPE_SCALAR;
    4772         216 :                     break;
    4773          36 :                 default:
    4774          36 :                     res = false;
    4775          36 :                     break;
    4776             :             }
    4777             :         }
    4778             : 
    4779             :         /*
    4780             :          * Do full parsing pass only for uniqueness check or for JSON text
    4781             :          * validation.
    4782             :          */
    4783        2120 :         if (res && (pred->unique_keys || exprtype == TEXTOID))
    4784        1326 :             res = json_validate(json, pred->unique_keys, false);
    4785             :     }
    4786         528 :     else if (exprtype == JSONBOID)
    4787             :     {
    4788         528 :         if (pred->item_type == JS_TYPE_ANY)
    4789         330 :             res = true;
    4790             :         else
    4791             :         {
    4792         198 :             Jsonb      *jb = DatumGetJsonbP(js);
    4793             : 
    4794         198 :             switch (pred->item_type)
    4795             :             {
    4796          66 :                 case JS_TYPE_OBJECT:
    4797          66 :                     res = JB_ROOT_IS_OBJECT(jb);
    4798          66 :                     break;
    4799          66 :                 case JS_TYPE_ARRAY:
    4800          66 :                     res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb);
    4801          66 :                     break;
    4802          66 :                 case JS_TYPE_SCALAR:
    4803          66 :                     res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb);
    4804          66 :                     break;
    4805           0 :                 default:
    4806           0 :                     res = false;
    4807           0 :                     break;
    4808             :             }
    4809             :         }
    4810             : 
    4811             :         /* Key uniqueness check is redundant for jsonb */
    4812             :     }
    4813             :     else
    4814           0 :         res = false;
    4815             : 
    4816        2648 :     *op->resvalue = BoolGetDatum(res);
    4817             : }
    4818             : 
    4819             : /*
    4820             :  * Evaluate a jsonpath against a document, both of which must have been
    4821             :  * evaluated and their values saved in op->d.jsonexpr.jsestate.
    4822             :  *
    4823             :  * If an error occurs during JsonPath* evaluation or when coercing its result
    4824             :  * to the RETURNING type, JsonExprState.error is set to true, provided the
    4825             :  * ON ERROR behavior is not ERROR.  Similarly, if JsonPath{Query|Value}() found
    4826             :  * no matching items, JsonExprState.empty is set to true, provided the ON EMPTY
    4827             :  * behavior is not ERROR.  That is to signal to the subsequent steps that check
    4828             :  * those flags to return the ON ERROR / ON EMPTY expression.
    4829             :  *
    4830             :  * Return value is the step address to be performed next.  It will be one of
    4831             :  * jump_error, jump_empty, jump_eval_coercion, or jump_end, all given in
    4832             :  * op->d.jsonexpr.jsestate.
    4833             :  */
    4834             : int
    4835        5282 : ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
    4836             :                      ExprContext *econtext)
    4837             : {
    4838        5282 :     JsonExprState *jsestate = op->d.jsonexpr.jsestate;
    4839        5282 :     JsonExpr   *jsexpr = jsestate->jsexpr;
    4840             :     Datum       item;
    4841             :     JsonPath   *path;
    4842        5282 :     bool        throw_error = jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR;
    4843        5282 :     bool        error = false,
    4844        5282 :                 empty = false;
    4845        5282 :     int         jump_eval_coercion = jsestate->jump_eval_coercion;
    4846        5282 :     char       *val_string = NULL;
    4847             : 
    4848        5282 :     item = jsestate->formatted_expr.value;
    4849        5282 :     path = DatumGetJsonPathP(jsestate->pathspec.value);
    4850             : 
    4851             :     /* Set error/empty to false. */
    4852        5282 :     memset(&jsestate->error, 0, sizeof(NullableDatum));
    4853        5282 :     memset(&jsestate->empty, 0, sizeof(NullableDatum));
    4854             : 
    4855             :     /* Also reset ErrorSaveContext contents for the next row. */
    4856        5282 :     if (jsestate->escontext.details_wanted)
    4857             :     {
    4858         912 :         jsestate->escontext.error_data = NULL;
    4859         912 :         jsestate->escontext.details_wanted = false;
    4860             :     }
    4861        5282 :     jsestate->escontext.error_occurred = false;
    4862             : 
    4863        5282 :     switch (jsexpr->op)
    4864             :     {
    4865         582 :         case JSON_EXISTS_OP:
    4866             :             {
    4867         582 :                 bool        exists = JsonPathExists(item, path,
    4868         582 :                                                     !throw_error ? &error : NULL,
    4869             :                                                     jsestate->args);
    4870             : 
    4871         576 :                 if (!error)
    4872             :                 {
    4873         420 :                     *op->resnull = false;
    4874         420 :                     *op->resvalue = BoolGetDatum(exists);
    4875             :                 }
    4876             :             }
    4877         576 :             break;
    4878             : 
    4879        2460 :         case JSON_QUERY_OP:
    4880        2460 :             *op->resvalue = JsonPathQuery(item, path, jsexpr->wrapper, &empty,
    4881        2460 :                                           !throw_error ? &error : NULL,
    4882             :                                           jsestate->args,
    4883        2460 :                                           jsexpr->column_name);
    4884             : 
    4885        2430 :             *op->resnull = (DatumGetPointer(*op->resvalue) == NULL);
    4886        2430 :             break;
    4887             : 
    4888        2240 :         case JSON_VALUE_OP:
    4889             :             {
    4890        2240 :                 JsonbValue *jbv = JsonPathValue(item, path, &empty,
    4891        2240 :                                                 !throw_error ? &error : NULL,
    4892             :                                                 jsestate->args,
    4893        2240 :                                                 jsexpr->column_name);
    4894             : 
    4895        2210 :                 if (jbv == NULL)
    4896             :                 {
    4897             :                     /* Will be coerced with json_populate_type(), if needed. */
    4898         516 :                     *op->resvalue = (Datum) 0;
    4899         516 :                     *op->resnull = true;
    4900             :                 }
    4901        1694 :                 else if (!error && !empty)
    4902             :                 {
    4903        1694 :                     if (jsexpr->returning->typid == JSONOID ||
    4904        1664 :                         jsexpr->returning->typid == JSONBOID)
    4905             :                     {
    4906          54 :                         val_string = DatumGetCString(DirectFunctionCall1(jsonb_out,
    4907             :                                                                          JsonbPGetDatum(JsonbValueToJsonb(jbv))));
    4908             :                     }
    4909        1640 :                     else if (jsexpr->use_json_coercion)
    4910             :                     {
    4911         102 :                         *op->resvalue = JsonbPGetDatum(JsonbValueToJsonb(jbv));
    4912         102 :                         *op->resnull = false;
    4913             :                     }
    4914             :                     else
    4915             :                     {
    4916        1538 :                         val_string = ExecGetJsonValueItemString(jbv, op->resnull);
    4917             : 
    4918             :                         /*
    4919             :                          * Simply convert to the default RETURNING type (text)
    4920             :                          * if no coercion needed.
    4921             :                          */
    4922        1538 :                         if (!jsexpr->use_io_coercion)
    4923         114 :                             *op->resvalue = DirectFunctionCall1(textin,
    4924             :                                                                 CStringGetDatum(val_string));
    4925             :                     }
    4926             :                 }
    4927        2210 :                 break;
    4928             :             }
    4929             : 
    4930             :             /* JSON_TABLE_OP can't happen here */
    4931             : 
    4932           0 :         default:
    4933           0 :             elog(ERROR, "unrecognized SQL/JSON expression op %d",
    4934             :                  (int) jsexpr->op);
    4935             :             return false;
    4936             :     }
    4937             : 
    4938             :     /*
    4939             :      * Coerce the result value to the RETURNING type by calling its input
    4940             :      * function.
    4941             :      */
    4942        5216 :     if (!*op->resnull && jsexpr->use_io_coercion)
    4943             :     {
    4944             :         FunctionCallInfo fcinfo;
    4945             : 
    4946             :         Assert(jump_eval_coercion == -1);
    4947        1478 :         fcinfo = jsestate->input_fcinfo;
    4948             :         Assert(fcinfo != NULL);
    4949             :         Assert(val_string != NULL);
    4950        1478 :         fcinfo->args[0].value = PointerGetDatum(val_string);
    4951        1478 :         fcinfo->args[0].isnull = *op->resnull;
    4952             : 
    4953             :         /*
    4954             :          * Second and third arguments are already set up in
    4955             :          * ExecInitJsonExpr().
    4956             :          */
    4957             : 
    4958        1478 :         fcinfo->isnull = false;
    4959        1478 :         *op->resvalue = FunctionCallInvoke(fcinfo);
    4960        1418 :         if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
    4961         186 :             error = true;
    4962             :     }
    4963             : 
    4964             :     /*
    4965             :      * When setting up the ErrorSaveContext (if needed) for capturing the
    4966             :      * errors that occur when coercing the JsonBehavior expression, set
    4967             :      * details_wanted to be able to show the actual error message as the
    4968             :      * DETAIL of the error message that tells that it is the JsonBehavior
    4969             :      * expression that caused the error; see ExecEvalJsonCoercionFinish().
    4970             :      */
    4971             : 
    4972             :     /* Handle ON EMPTY. */
    4973        5156 :     if (empty)
    4974             :     {
    4975         540 :         *op->resvalue = (Datum) 0;
    4976         540 :         *op->resnull = true;
    4977         540 :         if (jsexpr->on_empty)
    4978             :         {
    4979         540 :             if (jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR)
    4980             :             {
    4981         480 :                 jsestate->empty.value = BoolGetDatum(true);
    4982             :                 /* Set up to catch coercion errors of the ON EMPTY value. */
    4983         480 :                 jsestate->escontext.error_occurred = false;
    4984         480 :                 jsestate->escontext.details_wanted = true;
    4985             :                 /* Jump to end if the ON EMPTY behavior is to return NULL */
    4986         480 :                 return jsestate->jump_empty >= 0 ? jsestate->jump_empty : jsestate->jump_end;
    4987             :             }
    4988             :         }
    4989           0 :         else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
    4990             :         {
    4991           0 :             jsestate->error.value = BoolGetDatum(true);
    4992             :             /* Set up to catch coercion errors of the ON ERROR value. */
    4993           0 :             jsestate->escontext.error_occurred = false;
    4994           0 :             jsestate->escontext.details_wanted = true;
    4995             :             Assert(!throw_error);
    4996             :             /* Jump to end if the ON ERROR behavior is to return NULL */
    4997           0 :             return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
    4998             :         }
    4999             : 
    5000          60 :         if (jsexpr->column_name)
    5001          12 :             ereport(ERROR,
    5002             :                     errcode(ERRCODE_NO_SQL_JSON_ITEM),
    5003             :                     errmsg("no SQL/JSON item found for specified path of column \"%s\"",
    5004             :                            jsexpr->column_name));
    5005             :         else
    5006          48 :             ereport(ERROR,
    5007             :                     errcode(ERRCODE_NO_SQL_JSON_ITEM),
    5008             :                     errmsg("no SQL/JSON item found for specified path"));
    5009             :     }
    5010             : 
    5011             :     /*
    5012             :      * ON ERROR. Wouldn't get here if the behavior is ERROR, because they
    5013             :      * would have already been thrown.
    5014             :      */
    5015        4616 :     if (error)
    5016             :     {
    5017             :         Assert(!throw_error);
    5018         534 :         *op->resvalue = (Datum) 0;
    5019         534 :         *op->resnull = true;
    5020         534 :         jsestate->error.value = BoolGetDatum(true);
    5021             :         /* Set up to catch coercion errors of the ON ERROR value. */
    5022         534 :         jsestate->escontext.error_occurred = false;
    5023         534 :         jsestate->escontext.details_wanted = true;
    5024             :         /* Jump to end if the ON ERROR behavior is to return NULL */
    5025         534 :         return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
    5026             :     }
    5027             : 
    5028        4082 :     return jump_eval_coercion >= 0 ? jump_eval_coercion : jsestate->jump_end;
    5029             : }
    5030             : 
    5031             : /*
    5032             :  * Convert the given JsonbValue to its C string representation
    5033             :  *
    5034             :  * *resnull is set if the JsonbValue is a jbvNull.
    5035             :  */
    5036             : static char *
    5037        1538 : ExecGetJsonValueItemString(JsonbValue *item, bool *resnull)
    5038             : {
    5039        1538 :     *resnull = false;
    5040             : 
    5041             :     /* get coercion state reference and datum of the corresponding SQL type */
    5042        1538 :     switch (item->type)
    5043             :     {
    5044           0 :         case jbvNull:
    5045           0 :             *resnull = true;
    5046           0 :             return NULL;
    5047             : 
    5048         304 :         case jbvString:
    5049             :             {
    5050         304 :                 char       *str = palloc(item->val.string.len + 1);
    5051             : 
    5052         304 :                 memcpy(str, item->val.string.val, item->val.string.len);
    5053         304 :                 str[item->val.string.len] = '\0';
    5054         304 :                 return str;
    5055             :             }
    5056             : 
    5057        1120 :         case jbvNumeric:
    5058        1120 :             return DatumGetCString(DirectFunctionCall1(numeric_out,
    5059             :                                                        NumericGetDatum(item->val.numeric)));
    5060             : 
    5061          72 :         case jbvBool:
    5062          72 :             return DatumGetCString(DirectFunctionCall1(boolout,
    5063             :                                                        BoolGetDatum(item->val.boolean)));
    5064             : 
    5065          42 :         case jbvDatetime:
    5066          42 :             switch (item->val.datetime.typid)
    5067             :             {
    5068           6 :                 case DATEOID:
    5069           6 :                     return DatumGetCString(DirectFunctionCall1(date_out,
    5070             :                                                                item->val.datetime.value));
    5071           6 :                 case TIMEOID:
    5072           6 :                     return DatumGetCString(DirectFunctionCall1(time_out,
    5073             :                                                                item->val.datetime.value));
    5074           6 :                 case TIMETZOID:
    5075           6 :                     return DatumGetCString(DirectFunctionCall1(timetz_out,
    5076             :                                                                item->val.datetime.value));
    5077           6 :                 case TIMESTAMPOID:
    5078           6 :                     return DatumGetCString(DirectFunctionCall1(timestamp_out,
    5079             :                                                                item->val.datetime.value));
    5080          18 :                 case TIMESTAMPTZOID:
    5081          18 :                     return DatumGetCString(DirectFunctionCall1(timestamptz_out,
    5082             :                                                                item->val.datetime.value));
    5083           0 :                 default:
    5084           0 :                     elog(ERROR, "unexpected jsonb datetime type oid %u",
    5085             :                          item->val.datetime.typid);
    5086             :             }
    5087             :             break;
    5088             : 
    5089           0 :         case jbvArray:
    5090             :         case jbvObject:
    5091             :         case jbvBinary:
    5092           0 :             return DatumGetCString(DirectFunctionCall1(jsonb_out,
    5093             :                                                        JsonbPGetDatum(JsonbValueToJsonb(item))));
    5094             : 
    5095           0 :         default:
    5096           0 :             elog(ERROR, "unexpected jsonb value type %d", item->type);
    5097             :     }
    5098             : 
    5099             :     Assert(false);
    5100             :     *resnull = true;
    5101             :     return NULL;
    5102             : }
    5103             : 
    5104             : /*
    5105             :  * Coerce a jsonb value produced by ExecEvalJsonExprPath() or an ON ERROR /
    5106             :  * ON EMPTY behavior expression to the target type.
    5107             :  *
    5108             :  * Any soft errors that occur here will be checked by
    5109             :  * EEOP_JSONEXPR_COERCION_FINISH that will run after this.
    5110             :  */
    5111             : void
    5112        1806 : ExecEvalJsonCoercion(ExprState *state, ExprEvalStep *op,
    5113             :                      ExprContext *econtext)
    5114             : {
    5115        1806 :     ErrorSaveContext *escontext = op->d.jsonexpr_coercion.escontext;
    5116             : 
    5117             :     /*
    5118             :      * Prepare to call json_populate_type() to coerce the boolean result of
    5119             :      * JSON_EXISTS_OP to the target type.  If the target type is integer or a
    5120             :      * domain over integer, call the boolean-to-integer cast function instead,
    5121             :      * because the integer's input function (which is what
    5122             :      * json_populate_type() calls to coerce to scalar target types) doesn't
    5123             :      * accept boolean literals as valid input.  We only have a special case
    5124             :      * for integer and domains thereof as it seems common to use those types
    5125             :      * for EXISTS columns in JSON_TABLE().
    5126             :      */
    5127        1806 :     if (op->d.jsonexpr_coercion.exists_coerce)
    5128             :     {
    5129         180 :         if (op->d.jsonexpr_coercion.exists_cast_to_int)
    5130             :         {
    5131             :             /* Check domain constraints if any. */
    5132         126 :             if (op->d.jsonexpr_coercion.exists_check_domain &&
    5133          24 :                 !domain_check_safe(*op->resvalue, *op->resnull,
    5134             :                                    op->d.jsonexpr_coercion.targettype,
    5135             :                                    &op->d.jsonexpr_coercion.json_coercion_cache,
    5136             :                                    econtext->ecxt_per_query_memory,
    5137             :                                    (Node *) escontext))
    5138             :             {
    5139          18 :                 *op->resnull = true;
    5140          18 :                 *op->resvalue = (Datum) 0;
    5141             :             }
    5142             :             else
    5143         102 :                 *op->resvalue = DirectFunctionCall1(bool_int4, *op->resvalue);
    5144         120 :             return;
    5145             :         }
    5146             : 
    5147          54 :         *op->resvalue = DirectFunctionCall1(jsonb_in,
    5148             :                                             DatumGetBool(*op->resvalue) ?
    5149             :                                             CStringGetDatum("true") :
    5150             :                                             CStringGetDatum("false"));
    5151             :     }
    5152             : 
    5153        1530 :     *op->resvalue = json_populate_type(*op->resvalue, JSONBOID,
    5154             :                                        op->d.jsonexpr_coercion.targettype,
    5155             :                                        op->d.jsonexpr_coercion.targettypmod,
    5156             :                                        &op->d.jsonexpr_coercion.json_coercion_cache,
    5157             :                                        econtext->ecxt_per_query_memory,
    5158             :                                        op->resnull,
    5159        1680 :                                        op->d.jsonexpr_coercion.omit_quotes,
    5160             :                                        (Node *) escontext);
    5161             : }
    5162             : 
    5163             : static char *
    5164          78 : GetJsonBehaviorValueString(JsonBehavior *behavior)
    5165             : {
    5166             :     /*
    5167             :      * The order of array elements must correspond to the order of
    5168             :      * JsonBehaviorType members.
    5169             :      */
    5170          78 :     const char *behavior_names[] =
    5171             :     {
    5172             :         "NULL",
    5173             :         "ERROR",
    5174             :         "EMPTY",
    5175             :         "TRUE",
    5176             :         "FALSE",
    5177             :         "UNKNOWN",
    5178             :         "EMPTY ARRAY",
    5179             :         "EMPTY OBJECT",
    5180             :         "DEFAULT"
    5181             :     };
    5182             : 
    5183          78 :     return pstrdup(behavior_names[behavior->btype]);
    5184             : }
    5185             : 
    5186             : /*
    5187             :  * Checks if an error occurred in ExecEvalJsonCoercion().  If so, this sets
    5188             :  * JsonExprState.error to trigger the ON ERROR handling steps, unless the
    5189             :  * error is thrown when coercing a JsonBehavior value.
    5190             :  */
    5191             : void
    5192        1698 : ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op)
    5193             : {
    5194        1698 :     JsonExprState *jsestate = op->d.jsonexpr.jsestate;
    5195             : 
    5196        1698 :     if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
    5197             :     {
    5198             :         /*
    5199             :          * jsestate->error or jsestate->empty being set means that the error
    5200             :          * occurred when coercing the JsonBehavior value.  Throw the error in
    5201             :          * that case with the actual coercion error message shown in the
    5202             :          * DETAIL part.
    5203             :          */
    5204         552 :         if (DatumGetBool(jsestate->error.value))
    5205          60 :             ereport(ERROR,
    5206             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    5207             :             /*- translator: first %s is a SQL/JSON clause (e.g. ON ERROR) */
    5208             :                      errmsg("could not coerce %s expression (%s) to the RETURNING type",
    5209             :                             "ON ERROR",
    5210             :                             GetJsonBehaviorValueString(jsestate->jsexpr->on_error)),
    5211             :                      errdetail("%s", jsestate->escontext.error_data->message)));
    5212         492 :         else if (DatumGetBool(jsestate->empty.value))
    5213          18 :             ereport(ERROR,
    5214             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    5215             :             /*- translator: first %s is a SQL/JSON clause (e.g. ON ERROR) */
    5216             :                      errmsg("could not coerce %s expression (%s) to the RETURNING type",
    5217             :                             "ON EMPTY",
    5218             :                             GetJsonBehaviorValueString(jsestate->jsexpr->on_empty)),
    5219             :                      errdetail("%s", jsestate->escontext.error_data->message)));
    5220             : 
    5221         474 :         *op->resvalue = (Datum) 0;
    5222         474 :         *op->resnull = true;
    5223             : 
    5224         474 :         jsestate->error.value = BoolGetDatum(true);
    5225             : 
    5226             :         /*
    5227             :          * Reset for next use such as for catching errors when coercing a
    5228             :          * JsonBehavior expression.
    5229             :          */
    5230         474 :         jsestate->escontext.error_occurred = false;
    5231         474 :         jsestate->escontext.error_occurred = false;
    5232         474 :         jsestate->escontext.details_wanted = true;
    5233             :     }
    5234        1620 : }
    5235             : 
    5236             : /*
    5237             :  * ExecEvalGroupingFunc
    5238             :  *
    5239             :  * Computes a bitmask with a bit for each (unevaluated) argument expression
    5240             :  * (rightmost arg is least significant bit).
    5241             :  *
    5242             :  * A bit is set if the corresponding expression is NOT part of the set of
    5243             :  * grouping expressions in the current grouping set.
    5244             :  */
    5245             : void
    5246        1928 : ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
    5247             : {
    5248        1928 :     AggState   *aggstate = castNode(AggState, state->parent);
    5249        1928 :     int         result = 0;
    5250        1928 :     Bitmapset  *grouped_cols = aggstate->grouped_cols;
    5251             :     ListCell   *lc;
    5252             : 
    5253        4658 :     foreach(lc, op->d.grouping_func.clauses)
    5254             :     {
    5255        2730 :         int         attnum = lfirst_int(lc);
    5256             : 
    5257        2730 :         result <<= 1;
    5258             : 
    5259        2730 :         if (!bms_is_member(attnum, grouped_cols))
    5260        1092 :             result |= 1;
    5261             :     }
    5262             : 
    5263        1928 :     *op->resvalue = Int32GetDatum(result);
    5264        1928 :     *op->resnull = false;
    5265        1928 : }
    5266             : 
    5267             : /*
    5268             :  * ExecEvalMergeSupportFunc
    5269             :  *
    5270             :  * Returns information about the current MERGE action for its RETURNING list.
    5271             :  */
    5272             : void
    5273         458 : ExecEvalMergeSupportFunc(ExprState *state, ExprEvalStep *op,
    5274             :                          ExprContext *econtext)
    5275             : {
    5276         458 :     ModifyTableState *mtstate = castNode(ModifyTableState, state->parent);
    5277         458 :     MergeActionState *relaction = mtstate->mt_merge_action;
    5278             : 
    5279         458 :     if (!relaction)
    5280           0 :         elog(ERROR, "no merge action in progress");
    5281             : 
    5282             :     /* Return the MERGE action ("INSERT", "UPDATE", or "DELETE") */
    5283         458 :     switch (relaction->mas_action->commandType)
    5284             :     {
    5285         150 :         case CMD_INSERT:
    5286         150 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("INSERT", 6));
    5287         150 :             *op->resnull = false;
    5288         150 :             break;
    5289         188 :         case CMD_UPDATE:
    5290         188 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("UPDATE", 6));
    5291         188 :             *op->resnull = false;
    5292         188 :             break;
    5293         120 :         case CMD_DELETE:
    5294         120 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("DELETE", 6));
    5295         120 :             *op->resnull = false;
    5296         120 :             break;
    5297           0 :         case CMD_NOTHING:
    5298           0 :             elog(ERROR, "unexpected merge action: DO NOTHING");
    5299             :             break;
    5300           0 :         default:
    5301           0 :             elog(ERROR, "unrecognized commandType: %d",
    5302             :                  (int) relaction->mas_action->commandType);
    5303             :     }
    5304         458 : }
    5305             : 
    5306             : /*
    5307             :  * Hand off evaluation of a subplan to nodeSubplan.c
    5308             :  */
    5309             : void
    5310     3375546 : ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    5311             : {
    5312     3375546 :     SubPlanState *sstate = op->d.subplan.sstate;
    5313             : 
    5314             :     /* could potentially be nested, so make sure there's enough stack */
    5315     3375546 :     check_stack_depth();
    5316             : 
    5317     3375546 :     *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
    5318     3375540 : }
    5319             : 
    5320             : /*
    5321             :  * Evaluate a wholerow Var expression.
    5322             :  *
    5323             :  * Returns a Datum whose value is the value of a whole-row range variable
    5324             :  * with respect to given expression context.
    5325             :  */
    5326             : void
    5327       46062 : ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    5328             : {
    5329       46062 :     Var        *variable = op->d.wholerow.var;
    5330       46062 :     TupleTableSlot *slot = NULL;
    5331             :     TupleDesc   output_tupdesc;
    5332             :     MemoryContext oldcontext;
    5333             :     HeapTupleHeader dtuple;
    5334             :     HeapTuple   tuple;
    5335             : 
    5336             :     /* This was checked by ExecInitExpr */
    5337             :     Assert(variable->varattno == InvalidAttrNumber);
    5338             : 
    5339             :     /* Get the input slot we want */
    5340       46062 :     switch (variable->varno)
    5341             :     {
    5342          90 :         case INNER_VAR:
    5343             :             /* get the tuple from the inner node */
    5344          90 :             slot = econtext->ecxt_innertuple;
    5345          90 :             break;
    5346             : 
    5347          18 :         case OUTER_VAR:
    5348             :             /* get the tuple from the outer node */
    5349          18 :             slot = econtext->ecxt_outertuple;
    5350          18 :             break;
    5351             : 
    5352             :             /* INDEX_VAR is handled by default case */
    5353             : 
    5354       45954 :         default:
    5355             : 
    5356             :             /*
    5357             :              * Get the tuple from the relation being scanned.
    5358             :              *
    5359             :              * By default, this uses the "scan" tuple slot, but a wholerow Var
    5360             :              * in the RETURNING list may explicitly refer to OLD/NEW.  If the
    5361             :              * OLD/NEW row doesn't exist, we just return NULL.
    5362             :              */
    5363       45954 :             switch (variable->varreturningtype)
    5364             :             {
    5365       45490 :                 case VAR_RETURNING_DEFAULT:
    5366       45490 :                     slot = econtext->ecxt_scantuple;
    5367       45490 :                     break;
    5368             : 
    5369         232 :                 case VAR_RETURNING_OLD:
    5370         232 :                     if (state->flags & EEO_FLAG_OLD_IS_NULL)
    5371             :                     {
    5372          60 :                         *op->resvalue = (Datum) 0;
    5373          60 :                         *op->resnull = true;
    5374          60 :                         return;
    5375             :                     }
    5376         172 :                     slot = econtext->ecxt_oldtuple;
    5377         172 :                     break;
    5378             : 
    5379         232 :                 case VAR_RETURNING_NEW:
    5380         232 :                     if (state->flags & EEO_FLAG_NEW_IS_NULL)
    5381             :                     {
    5382          30 :                         *op->resvalue = (Datum) 0;
    5383          30 :                         *op->resnull = true;
    5384          30 :                         return;
    5385             :                     }
    5386         202 :                     slot = econtext->ecxt_newtuple;
    5387         202 :                     break;
    5388             :             }
    5389       45864 :             break;
    5390             :     }
    5391             : 
    5392             :     /* Apply the junkfilter if any */
    5393       45972 :     if (op->d.wholerow.junkFilter != NULL)
    5394          60 :         slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
    5395             : 
    5396             :     /*
    5397             :      * If first time through, obtain tuple descriptor and check compatibility.
    5398             :      *
    5399             :      * XXX: It'd be great if this could be moved to the expression
    5400             :      * initialization phase, but due to using slots that's currently not
    5401             :      * feasible.
    5402             :      */
    5403       45972 :     if (op->d.wholerow.first)
    5404             :     {
    5405             :         /* optimistically assume we don't need slow path */
    5406        2936 :         op->d.wholerow.slow = false;
    5407             : 
    5408             :         /*
    5409             :          * If the Var identifies a named composite type, we must check that
    5410             :          * the actual tuple type is compatible with it.
    5411             :          */
    5412        2936 :         if (variable->vartype != RECORDOID)
    5413             :         {
    5414             :             TupleDesc   var_tupdesc;
    5415             :             TupleDesc   slot_tupdesc;
    5416             : 
    5417             :             /*
    5418             :              * We really only care about numbers of attributes and data types.
    5419             :              * Also, we can ignore type mismatch on columns that are dropped
    5420             :              * in the destination type, so long as (1) the physical storage
    5421             :              * matches or (2) the actual column value is NULL.  Case (1) is
    5422             :              * helpful in some cases involving out-of-date cached plans, while
    5423             :              * case (2) is expected behavior in situations such as an INSERT
    5424             :              * into a table with dropped columns (the planner typically
    5425             :              * generates an INT4 NULL regardless of the dropped column type).
    5426             :              * If we find a dropped column and cannot verify that case (1)
    5427             :              * holds, we have to use the slow path to check (2) for each row.
    5428             :              *
    5429             :              * If vartype is a domain over composite, just look through that
    5430             :              * to the base composite type.
    5431             :              */
    5432        1844 :             var_tupdesc = lookup_rowtype_tupdesc_domain(variable->vartype,
    5433             :                                                         -1, false);
    5434             : 
    5435        1844 :             slot_tupdesc = slot->tts_tupleDescriptor;
    5436             : 
    5437        1844 :             if (var_tupdesc->natts != slot_tupdesc->natts)
    5438           0 :                 ereport(ERROR,
    5439             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    5440             :                          errmsg("table row type and query-specified row type do not match"),
    5441             :                          errdetail_plural("Table row contains %d attribute, but query expects %d.",
    5442             :                                           "Table row contains %d attributes, but query expects %d.",
    5443             :                                           slot_tupdesc->natts,
    5444             :                                           slot_tupdesc->natts,
    5445             :                                           var_tupdesc->natts)));
    5446             : 
    5447        7312 :             for (int i = 0; i < var_tupdesc->natts; i++)
    5448             :             {
    5449        5468 :                 Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
    5450        5468 :                 Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
    5451             : 
    5452        5468 :                 if (vattr->atttypid == sattr->atttypid)
    5453        5468 :                     continue;   /* no worries */
    5454           0 :                 if (!vattr->attisdropped)
    5455           0 :                     ereport(ERROR,
    5456             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    5457             :                              errmsg("table row type and query-specified row type do not match"),
    5458             :                              errdetail("Table has type %s at ordinal position %d, but query expects %s.",
    5459             :                                        format_type_be(sattr->atttypid),
    5460             :                                        i + 1,
    5461             :                                        format_type_be(vattr->atttypid))));
    5462             : 
    5463           0 :                 if (vattr->attlen != sattr->attlen ||
    5464           0 :                     vattr->attalign != sattr->attalign)
    5465           0 :                     op->d.wholerow.slow = true; /* need to check for nulls */
    5466             :             }
    5467             : 
    5468             :             /*
    5469             :              * Use the variable's declared rowtype as the descriptor for the
    5470             :              * output values.  In particular, we *must* absorb any
    5471             :              * attisdropped markings.
    5472             :              */
    5473        1844 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    5474        1844 :             output_tupdesc = CreateTupleDescCopy(var_tupdesc);
    5475        1844 :             MemoryContextSwitchTo(oldcontext);
    5476             : 
    5477        1844 :             ReleaseTupleDesc(var_tupdesc);
    5478             :         }
    5479             :         else
    5480             :         {
    5481             :             /*
    5482             :              * In the RECORD case, we use the input slot's rowtype as the
    5483             :              * descriptor for the output values, modulo possibly assigning new
    5484             :              * column names below.
    5485             :              */
    5486        1092 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    5487        1092 :             output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
    5488        1092 :             MemoryContextSwitchTo(oldcontext);
    5489             : 
    5490             :             /*
    5491             :              * It's possible that the input slot is a relation scan slot and
    5492             :              * so is marked with that relation's rowtype.  But we're supposed
    5493             :              * to be returning RECORD, so reset to that.
    5494             :              */
    5495        1092 :             output_tupdesc->tdtypeid = RECORDOID;
    5496        1092 :             output_tupdesc->tdtypmod = -1;
    5497             : 
    5498             :             /*
    5499             :              * We already got the correct physical datatype info above, but
    5500             :              * now we should try to find the source RTE and adopt its column
    5501             :              * aliases, since it's unlikely that the input slot has the
    5502             :              * desired names.
    5503             :              *
    5504             :              * If we can't locate the RTE, assume the column names we've got
    5505             :              * are OK.  (As of this writing, the only cases where we can't
    5506             :              * locate the RTE are in execution of trigger WHEN clauses, and
    5507             :              * then the Var will have the trigger's relation's rowtype, so its
    5508             :              * names are fine.)  Also, if the creator of the RTE didn't bother
    5509             :              * to fill in an eref field, assume our column names are OK. (This
    5510             :              * happens in COPY, and perhaps other places.)
    5511             :              */
    5512        1092 :             if (econtext->ecxt_estate &&
    5513        1092 :                 variable->varno <= econtext->ecxt_estate->es_range_table_size)
    5514             :             {
    5515        1092 :                 RangeTblEntry *rte = exec_rt_fetch(variable->varno,
    5516        1092 :                                                    econtext->ecxt_estate);
    5517             : 
    5518        1092 :                 if (rte->eref)
    5519        1092 :                     ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
    5520             :             }
    5521             :         }
    5522             : 
    5523             :         /* Bless the tupdesc if needed, and save it in the execution state */
    5524        2936 :         op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
    5525             : 
    5526        2936 :         op->d.wholerow.first = false;
    5527             :     }
    5528             : 
    5529             :     /*
    5530             :      * Make sure all columns of the slot are accessible in the slot's
    5531             :      * Datum/isnull arrays.
    5532             :      */
    5533       45972 :     slot_getallattrs(slot);
    5534             : 
    5535       45972 :     if (op->d.wholerow.slow)
    5536             :     {
    5537             :         /* Check to see if any dropped attributes are non-null */
    5538           0 :         TupleDesc   tupleDesc = slot->tts_tupleDescriptor;
    5539           0 :         TupleDesc   var_tupdesc = op->d.wholerow.tupdesc;
    5540             : 
    5541             :         Assert(var_tupdesc->natts == tupleDesc->natts);
    5542             : 
    5543           0 :         for (int i = 0; i < var_tupdesc->natts; i++)
    5544             :         {
    5545           0 :             CompactAttribute *vattr = TupleDescCompactAttr(var_tupdesc, i);
    5546           0 :             CompactAttribute *sattr = TupleDescCompactAttr(tupleDesc, i);
    5547             : 
    5548           0 :             if (!vattr->attisdropped)
    5549           0 :                 continue;       /* already checked non-dropped cols */
    5550           0 :             if (slot->tts_isnull[i])
    5551           0 :                 continue;       /* null is always okay */
    5552           0 :             if (vattr->attlen != sattr->attlen ||
    5553           0 :                 vattr->attalignby != sattr->attalignby)
    5554           0 :                 ereport(ERROR,
    5555             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    5556             :                          errmsg("table row type and query-specified row type do not match"),
    5557             :                          errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
    5558             :                                    i + 1)));
    5559             :         }
    5560             :     }
    5561             : 
    5562             :     /*
    5563             :      * Build a composite datum, making sure any toasted fields get detoasted.
    5564             :      *
    5565             :      * (Note: it is critical that we not change the slot's state here.)
    5566             :      */
    5567       45972 :     tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
    5568             :                                         slot->tts_values,
    5569             :                                         slot->tts_isnull);
    5570       45972 :     dtuple = tuple->t_data;
    5571             : 
    5572             :     /*
    5573             :      * Label the datum with the composite type info we identified before.
    5574             :      *
    5575             :      * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
    5576             :      * the tuple build step; but that seems a tad risky so let's not.)
    5577             :      */
    5578       45972 :     HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
    5579       45972 :     HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
    5580             : 
    5581       45972 :     *op->resvalue = PointerGetDatum(dtuple);
    5582       45972 :     *op->resnull = false;
    5583             : }
    5584             : 
    5585             : void
    5586     7162778 : ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
    5587             :                TupleTableSlot *slot)
    5588             : {
    5589             :     Datum       d;
    5590             : 
    5591             :     /* OLD/NEW system attribute is NULL if OLD/NEW row is NULL */
    5592     7162778 :     if ((op->d.var.varreturningtype == VAR_RETURNING_OLD &&
    5593         228 :          state->flags & EEO_FLAG_OLD_IS_NULL) ||
    5594     7162694 :         (op->d.var.varreturningtype == VAR_RETURNING_NEW &&
    5595         228 :          state->flags & EEO_FLAG_NEW_IS_NULL))
    5596             :     {
    5597         156 :         *op->resvalue = (Datum) 0;
    5598         156 :         *op->resnull = true;
    5599         156 :         return;
    5600             :     }
    5601             : 
    5602             :     /* slot_getsysattr has sufficient defenses against bad attnums */
    5603     7162622 :     d = slot_getsysattr(slot,
    5604             :                         op->d.var.attnum,
    5605             :                         op->resnull);
    5606     7162610 :     *op->resvalue = d;
    5607             :     /* this ought to be unreachable, but it's cheap enough to check */
    5608     7162610 :     if (unlikely(*op->resnull))
    5609           0 :         elog(ERROR, "failed to fetch attribute from slot");
    5610             : }
    5611             : 
    5612             : /*
    5613             :  * Transition value has not been initialized. This is the first non-NULL input
    5614             :  * value for a group. We use it as the initial value for transValue.
    5615             :  */
    5616             : void
    5617       60286 : ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
    5618             :                  ExprContext *aggcontext)
    5619             : {
    5620       60286 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    5621             :     MemoryContext oldContext;
    5622             : 
    5623             :     /*
    5624             :      * We must copy the datum into aggcontext if it is pass-by-ref. We do not
    5625             :      * need to pfree the old transValue, since it's NULL.  (We already checked
    5626             :      * that the agg's input type is binary-compatible with its transtype, so
    5627             :      * straight copy here is OK.)
    5628             :      */
    5629       60286 :     oldContext = MemoryContextSwitchTo(aggcontext->ecxt_per_tuple_memory);
    5630      120572 :     pergroup->transValue = datumCopy(fcinfo->args[1].value,
    5631       60286 :                                      pertrans->transtypeByVal,
    5632       60286 :                                      pertrans->transtypeLen);
    5633       60286 :     pergroup->transValueIsNull = false;
    5634       60286 :     pergroup->noTransValue = false;
    5635       60286 :     MemoryContextSwitchTo(oldContext);
    5636       60286 : }
    5637             : 
    5638             : /*
    5639             :  * Ensure that the new transition value is stored in the aggcontext,
    5640             :  * rather than the per-tuple context.  This should be invoked only when
    5641             :  * we know (a) the transition data type is pass-by-reference, and (b)
    5642             :  * the newValue is distinct from the oldValue.
    5643             :  *
    5644             :  * NB: This can change the current memory context.
    5645             :  *
    5646             :  * We copy the presented newValue into the aggcontext, except when the datum
    5647             :  * points to a R/W expanded object that is already a child of the aggcontext,
    5648             :  * in which case we need not copy.  We then delete the oldValue, if not null.
    5649             :  *
    5650             :  * If the presented datum points to a R/W expanded object that is a child of
    5651             :  * some other context, ideally we would just reparent it under the aggcontext.
    5652             :  * Unfortunately, that doesn't work easily, and it wouldn't help anyway for
    5653             :  * aggregate-aware transfns.  We expect that a transfn that deals in expanded
    5654             :  * objects and is aware of the memory management conventions for aggregate
    5655             :  * transition values will (1) on first call, return a R/W expanded object that
    5656             :  * is already in the right context, allowing us to do nothing here, and (2) on
    5657             :  * subsequent calls, modify and return that same object, so that control
    5658             :  * doesn't even reach here.  However, if we have a generic transfn that
    5659             :  * returns a new R/W expanded object (probably in the per-tuple context),
    5660             :  * reparenting that result would cause problems.  We'd pass that R/W object to
    5661             :  * the next invocation of the transfn, and then it would be at liberty to
    5662             :  * change or delete that object, and if it deletes it then our own attempt to
    5663             :  * delete the now-old transvalue afterwards would be a double free.  We avoid
    5664             :  * this problem by forcing the stored transvalue to always be a flat
    5665             :  * non-expanded object unless the transfn is visibly doing aggregate-aware
    5666             :  * memory management.  This is somewhat inefficient, but the best answer to
    5667             :  * that is to write a smarter transfn.
    5668             :  */
    5669             : Datum
    5670       62484 : ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
    5671             :                       Datum newValue, bool newValueIsNull,
    5672             :                       Datum oldValue, bool oldValueIsNull)
    5673             : {
    5674             :     Assert(newValue != oldValue);
    5675             : 
    5676       62484 :     if (!newValueIsNull)
    5677             :     {
    5678       62484 :         MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
    5679       62652 :         if (DatumIsReadWriteExpandedObject(newValue,
    5680             :                                            false,
    5681       62478 :                                            pertrans->transtypeLen) &&
    5682         168 :             MemoryContextGetParent(DatumGetEOHP(newValue)->eoh_context) == CurrentMemoryContext)
    5683             :              /* do nothing */ ;
    5684             :         else
    5685       62478 :             newValue = datumCopy(newValue,
    5686       62478 :                                  pertrans->transtypeByVal,
    5687       62478 :                                  pertrans->transtypeLen);
    5688             :     }
    5689             :     else
    5690             :     {
    5691             :         /*
    5692             :          * Ensure that AggStatePerGroup->transValue ends up being 0, so
    5693             :          * callers can safely compare newValue/oldValue without having to
    5694             :          * check their respective nullness.
    5695             :          */
    5696           0 :         newValue = (Datum) 0;
    5697             :     }
    5698             : 
    5699       62484 :     if (!oldValueIsNull)
    5700             :     {
    5701       62370 :         if (DatumIsReadWriteExpandedObject(oldValue,
    5702             :                                            false,
    5703             :                                            pertrans->transtypeLen))
    5704           0 :             DeleteExpandedObject(oldValue);
    5705             :         else
    5706       62370 :             pfree(DatumGetPointer(oldValue));
    5707             :     }
    5708             : 
    5709       62484 :     return newValue;
    5710             : }
    5711             : 
    5712             : /*
    5713             :  * ExecEvalPreOrderedDistinctSingle
    5714             :  *      Returns true when the aggregate transition value Datum is distinct
    5715             :  *      from the previous input Datum and returns false when the input Datum
    5716             :  *      matches the previous input Datum.
    5717             :  */
    5718             : bool
    5719      365850 : ExecEvalPreOrderedDistinctSingle(AggState *aggstate, AggStatePerTrans pertrans)
    5720             : {
    5721      365850 :     Datum       value = pertrans->transfn_fcinfo->args[1].value;
    5722      365850 :     bool        isnull = pertrans->transfn_fcinfo->args[1].isnull;
    5723             : 
    5724      365850 :     if (!pertrans->haslast ||
    5725      347586 :         pertrans->lastisnull != isnull ||
    5726      347556 :         (!isnull && !DatumGetBool(FunctionCall2Coll(&pertrans->equalfnOne,
    5727             :                                                     pertrans->aggCollation,
    5728             :                                                     pertrans->lastdatum, value))))
    5729             :     {
    5730      101956 :         if (pertrans->haslast && !pertrans->inputtypeByVal &&
    5731       25982 :             !pertrans->lastisnull)
    5732       25982 :             pfree(DatumGetPointer(pertrans->lastdatum));
    5733             : 
    5734      101956 :         pertrans->haslast = true;
    5735      101956 :         if (!isnull)
    5736             :         {
    5737             :             MemoryContext oldContext;
    5738             : 
    5739      101920 :             oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
    5740             : 
    5741      203840 :             pertrans->lastdatum = datumCopy(value, pertrans->inputtypeByVal,
    5742      101920 :                                             pertrans->inputtypeLen);
    5743             : 
    5744      101920 :             MemoryContextSwitchTo(oldContext);
    5745             :         }
    5746             :         else
    5747          36 :             pertrans->lastdatum = (Datum) 0;
    5748      101956 :         pertrans->lastisnull = isnull;
    5749      101956 :         return true;
    5750             :     }
    5751             : 
    5752      263894 :     return false;
    5753             : }
    5754             : 
    5755             : /*
    5756             :  * ExecEvalPreOrderedDistinctMulti
    5757             :  *      Returns true when the aggregate input is distinct from the previous
    5758             :  *      input and returns false when the input matches the previous input, or
    5759             :  *      when there was no previous input.
    5760             :  */
    5761             : bool
    5762         720 : ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans)
    5763             : {
    5764         720 :     ExprContext *tmpcontext = aggstate->tmpcontext;
    5765         720 :     bool        isdistinct = false; /* for now */
    5766             :     TupleTableSlot *save_outer;
    5767             :     TupleTableSlot *save_inner;
    5768             : 
    5769        2820 :     for (int i = 0; i < pertrans->numTransInputs; i++)
    5770             :     {
    5771        2100 :         pertrans->sortslot->tts_values[i] = pertrans->transfn_fcinfo->args[i + 1].value;
    5772        2100 :         pertrans->sortslot->tts_isnull[i] = pertrans->transfn_fcinfo->args[i + 1].isnull;
    5773             :     }
    5774             : 
    5775         720 :     ExecClearTuple(pertrans->sortslot);
    5776         720 :     pertrans->sortslot->tts_nvalid = pertrans->numInputs;
    5777         720 :     ExecStoreVirtualTuple(pertrans->sortslot);
    5778             : 
    5779             :     /* save the previous slots before we overwrite them */
    5780         720 :     save_outer = tmpcontext->ecxt_outertuple;
    5781         720 :     save_inner = tmpcontext->ecxt_innertuple;
    5782             : 
    5783         720 :     tmpcontext->ecxt_outertuple = pertrans->sortslot;
    5784         720 :     tmpcontext->ecxt_innertuple = pertrans->uniqslot;
    5785             : 
    5786         720 :     if (!pertrans->haslast ||
    5787         624 :         !ExecQual(pertrans->equalfnMulti, tmpcontext))
    5788             :     {
    5789         312 :         if (pertrans->haslast)
    5790         216 :             ExecClearTuple(pertrans->uniqslot);
    5791             : 
    5792         312 :         pertrans->haslast = true;
    5793         312 :         ExecCopySlot(pertrans->uniqslot, pertrans->sortslot);
    5794             : 
    5795         312 :         isdistinct = true;
    5796             :     }
    5797             : 
    5798             :     /* restore the original slots */
    5799         720 :     tmpcontext->ecxt_outertuple = save_outer;
    5800         720 :     tmpcontext->ecxt_innertuple = save_inner;
    5801             : 
    5802         720 :     return isdistinct;
    5803             : }
    5804             : 
    5805             : /*
    5806             :  * Invoke ordered transition function, with a datum argument.
    5807             :  */
    5808             : void
    5809      844384 : ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op,
    5810             :                              ExprContext *econtext)
    5811             : {
    5812      844384 :     AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    5813      844384 :     int         setno = op->d.agg_trans.setno;
    5814             : 
    5815      844384 :     tuplesort_putdatum(pertrans->sortstates[setno],
    5816      844384 :                        *op->resvalue, *op->resnull);
    5817      844384 : }
    5818             : 
    5819             : /*
    5820             :  * Invoke ordered transition function, with a tuple argument.
    5821             :  */
    5822             : void
    5823         180 : ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
    5824             :                              ExprContext *econtext)
    5825             : {
    5826         180 :     AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    5827         180 :     int         setno = op->d.agg_trans.setno;
    5828             : 
    5829         180 :     ExecClearTuple(pertrans->sortslot);
    5830         180 :     pertrans->sortslot->tts_nvalid = pertrans->numInputs;
    5831         180 :     ExecStoreVirtualTuple(pertrans->sortslot);
    5832         180 :     tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
    5833         180 : }
    5834             : 
    5835             : /* implementation of transition function invocation for byval types */
    5836             : static pg_attribute_always_inline void
    5837    30557554 : ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
    5838             :                        AggStatePerGroup pergroup,
    5839             :                        ExprContext *aggcontext, int setno)
    5840             : {
    5841    30557554 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    5842             :     MemoryContext oldContext;
    5843             :     Datum       newVal;
    5844             : 
    5845             :     /* cf. select_current_set() */
    5846    30557554 :     aggstate->curaggcontext = aggcontext;
    5847    30557554 :     aggstate->current_set = setno;
    5848             : 
    5849             :     /* set up aggstate->curpertrans for AggGetAggref() */
    5850    30557554 :     aggstate->curpertrans = pertrans;
    5851             : 
    5852             :     /* invoke transition function in per-tuple context */
    5853    30557554 :     oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    5854             : 
    5855    30557554 :     fcinfo->args[0].value = pergroup->transValue;
    5856    30557554 :     fcinfo->args[0].isnull = pergroup->transValueIsNull;
    5857    30557554 :     fcinfo->isnull = false;      /* just in case transfn doesn't set it */
    5858             : 
    5859    30557554 :     newVal = FunctionCallInvoke(fcinfo);
    5860             : 
    5861    30557482 :     pergroup->transValue = newVal;
    5862    30557482 :     pergroup->transValueIsNull = fcinfo->isnull;
    5863             : 
    5864    30557482 :     MemoryContextSwitchTo(oldContext);
    5865    30557482 : }
    5866             : 
    5867             : /* implementation of transition function invocation for byref types */
    5868             : static pg_attribute_always_inline void
    5869     2836404 : ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
    5870             :                        AggStatePerGroup pergroup,
    5871             :                        ExprContext *aggcontext, int setno)
    5872             : {
    5873     2836404 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    5874             :     MemoryContext oldContext;
    5875             :     Datum       newVal;
    5876             : 
    5877             :     /* cf. select_current_set() */
    5878     2836404 :     aggstate->curaggcontext = aggcontext;
    5879     2836404 :     aggstate->current_set = setno;
    5880             : 
    5881             :     /* set up aggstate->curpertrans for AggGetAggref() */
    5882     2836404 :     aggstate->curpertrans = pertrans;
    5883             : 
    5884             :     /* invoke transition function in per-tuple context */
    5885     2836404 :     oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    5886             : 
    5887     2836404 :     fcinfo->args[0].value = pergroup->transValue;
    5888     2836404 :     fcinfo->args[0].isnull = pergroup->transValueIsNull;
    5889     2836404 :     fcinfo->isnull = false;      /* just in case transfn doesn't set it */
    5890             : 
    5891     2836404 :     newVal = FunctionCallInvoke(fcinfo);
    5892             : 
    5893             :     /*
    5894             :      * For pass-by-ref datatype, must copy the new value into aggcontext and
    5895             :      * free the prior transValue.  But if transfn returned a pointer to its
    5896             :      * first input, we don't need to do anything.
    5897             :      *
    5898             :      * It's safe to compare newVal with pergroup->transValue without regard
    5899             :      * for either being NULL, because ExecAggCopyTransValue takes care to set
    5900             :      * transValue to 0 when NULL. Otherwise we could end up accidentally not
    5901             :      * reparenting, when the transValue has the same numerical value as
    5902             :      * newValue, despite being NULL.  This is a somewhat hot path, making it
    5903             :      * undesirable to instead solve this with another branch for the common
    5904             :      * case of the transition function returning its (modified) input
    5905             :      * argument.
    5906             :      */
    5907     2836398 :     if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
    5908       39288 :         newVal = ExecAggCopyTransValue(aggstate, pertrans,
    5909       39288 :                                        newVal, fcinfo->isnull,
    5910             :                                        pergroup->transValue,
    5911       39288 :                                        pergroup->transValueIsNull);
    5912             : 
    5913     2836398 :     pergroup->transValue = newVal;
    5914     2836398 :     pergroup->transValueIsNull = fcinfo->isnull;
    5915             : 
    5916     2836398 :     MemoryContextSwitchTo(oldContext);
    5917     2836398 : }

Generated by: LCOV version 1.14