LCOV - code coverage report
Current view: top level - src/backend/executor - execExprInterp.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 93.8 % 2078 1950
Test Date: 2026-02-17 17:20:33 Functions: 97.6 % 83 81
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-2026, 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      1254126 : ExecReadyInterpretedExpr(ExprState *state)
     243              : {
     244              :     /* Ensure one-time interpreter setup has been done */
     245      1254126 :     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      1254126 :     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      1254126 :     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      1254126 :     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      1254126 :     if (state->steps_len == 5)
     284              :     {
     285       157175 :         ExprEvalOp  step0 = state->steps[0].opcode;
     286       157175 :         ExprEvalOp  step1 = state->steps[1].opcode;
     287       157175 :         ExprEvalOp  step2 = state->steps[2].opcode;
     288       157175 :         ExprEvalOp  step3 = state->steps[3].opcode;
     289              : 
     290       157175 :         if (step0 == EEOP_INNER_FETCHSOME &&
     291          405 :             step1 == EEOP_HASHDATUM_SET_INITVAL &&
     292          405 :             step2 == EEOP_INNER_VAR &&
     293              :             step3 == EEOP_HASHDATUM_NEXT32)
     294              :         {
     295          405 :             state->evalfunc_private = (void *) ExecJustHashInnerVarWithIV;
     296          405 :             return;
     297              :         }
     298              :     }
     299      1096951 :     else if (state->steps_len == 4)
     300              :     {
     301        68016 :         ExprEvalOp  step0 = state->steps[0].opcode;
     302        68016 :         ExprEvalOp  step1 = state->steps[1].opcode;
     303        68016 :         ExprEvalOp  step2 = state->steps[2].opcode;
     304              : 
     305        68016 :         if (step0 == EEOP_OUTER_FETCHSOME &&
     306        13592 :             step1 == EEOP_OUTER_VAR &&
     307              :             step2 == EEOP_HASHDATUM_FIRST)
     308              :         {
     309         1034 :             state->evalfunc_private = (void *) ExecJustHashOuterVar;
     310         1034 :             return;
     311              :         }
     312        66982 :         else if (step0 == EEOP_INNER_FETCHSOME &&
     313         1376 :                  step1 == EEOP_INNER_VAR &&
     314              :                  step2 == EEOP_HASHDATUM_FIRST)
     315              :         {
     316         1361 :             state->evalfunc_private = (void *) ExecJustHashInnerVar;
     317         1361 :             return;
     318              :         }
     319        65621 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     320        12558 :                  step1 == EEOP_OUTER_VAR &&
     321              :                  step2 == EEOP_HASHDATUM_FIRST_STRICT)
     322              :         {
     323        10301 :             state->evalfunc_private = (void *) ExecJustHashOuterVarStrict;
     324        10301 :             return;
     325              :         }
     326              :     }
     327      1028935 :     else if (state->steps_len == 3)
     328              :     {
     329       207377 :         ExprEvalOp  step0 = state->steps[0].opcode;
     330       207377 :         ExprEvalOp  step1 = state->steps[1].opcode;
     331              : 
     332       207377 :         if (step0 == EEOP_INNER_FETCHSOME &&
     333              :             step1 == EEOP_INNER_VAR)
     334              :         {
     335         4054 :             state->evalfunc_private = ExecJustInnerVar;
     336         4054 :             return;
     337              :         }
     338       203323 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     339              :                  step1 == EEOP_OUTER_VAR)
     340              :         {
     341         5381 :             state->evalfunc_private = ExecJustOuterVar;
     342         5381 :             return;
     343              :         }
     344       197942 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     345              :                  step1 == EEOP_SCAN_VAR)
     346              :         {
     347           15 :             state->evalfunc_private = ExecJustScanVar;
     348           15 :             return;
     349              :         }
     350       197927 :         else if (step0 == EEOP_INNER_FETCHSOME &&
     351              :                  step1 == EEOP_ASSIGN_INNER_VAR)
     352              :         {
     353         4014 :             state->evalfunc_private = ExecJustAssignInnerVar;
     354         4014 :             return;
     355              :         }
     356       193913 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     357              :                  step1 == EEOP_ASSIGN_OUTER_VAR)
     358              :         {
     359         4749 :             state->evalfunc_private = ExecJustAssignOuterVar;
     360         4749 :             return;
     361              :         }
     362       189164 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     363              :                  step1 == EEOP_ASSIGN_SCAN_VAR)
     364              :         {
     365        22664 :             state->evalfunc_private = ExecJustAssignScanVar;
     366        22664 :             return;
     367              :         }
     368       166500 :         else if (step0 == EEOP_CASE_TESTVAL &&
     369          169 :                  (step1 == EEOP_FUNCEXPR_STRICT ||
     370           19 :                   step1 == EEOP_FUNCEXPR_STRICT_1 ||
     371              :                   step1 == EEOP_FUNCEXPR_STRICT_2))
     372              :         {
     373          192 :             state->evalfunc_private = ExecJustApplyFuncToCase;
     374          192 :             return;
     375              :         }
     376       166308 :         else if (step0 == EEOP_INNER_VAR &&
     377              :                  step1 == EEOP_HASHDATUM_FIRST)
     378              :         {
     379         1124 :             state->evalfunc_private = (void *) ExecJustHashInnerVarVirt;
     380         1124 :             return;
     381              :         }
     382       165184 :         else if (step0 == EEOP_OUTER_VAR &&
     383              :                  step1 == EEOP_HASHDATUM_FIRST)
     384              :         {
     385         3967 :             state->evalfunc_private = (void *) ExecJustHashOuterVarVirt;
     386         3967 :             return;
     387              :         }
     388              :     }
     389       821558 :     else if (state->steps_len == 2)
     390              :     {
     391       473622 :         ExprEvalOp  step0 = state->steps[0].opcode;
     392              : 
     393       473622 :         if (step0 == EEOP_CONST)
     394              :         {
     395       215840 :             state->evalfunc_private = ExecJustConst;
     396       215840 :             return;
     397              :         }
     398       257782 :         else if (step0 == EEOP_INNER_VAR)
     399              :         {
     400          152 :             state->evalfunc_private = ExecJustInnerVarVirt;
     401          152 :             return;
     402              :         }
     403       257630 :         else if (step0 == EEOP_OUTER_VAR)
     404              :         {
     405         1335 :             state->evalfunc_private = ExecJustOuterVarVirt;
     406         1335 :             return;
     407              :         }
     408       256295 :         else if (step0 == EEOP_SCAN_VAR)
     409              :         {
     410            0 :             state->evalfunc_private = ExecJustScanVarVirt;
     411            0 :             return;
     412              :         }
     413       256295 :         else if (step0 == EEOP_ASSIGN_INNER_VAR)
     414              :         {
     415          199 :             state->evalfunc_private = ExecJustAssignInnerVarVirt;
     416          199 :             return;
     417              :         }
     418       256096 :         else if (step0 == EEOP_ASSIGN_OUTER_VAR)
     419              :         {
     420         2233 :             state->evalfunc_private = ExecJustAssignOuterVarVirt;
     421         2233 :             return;
     422              :         }
     423       253863 :         else if (step0 == EEOP_ASSIGN_SCAN_VAR)
     424              :         {
     425         2144 :             state->evalfunc_private = ExecJustAssignScanVarVirt;
     426         2144 :             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      6586496 :     for (int off = 0; off < state->steps_len; off++)
     437              :     {
     438      5613534 :         ExprEvalStep *op = &state->steps[off];
     439              : 
     440      5613534 :         op->opcode = EEO_OPCODE(op->opcode);
     441              :     }
     442              : 
     443       972962 :     state->flags |= EEO_FLAG_DIRECT_THREADED;
     444              : #endif                          /* EEO_USE_COMPUTED_GOTO */
     445              : 
     446       972962 :     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     95804934 : 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     95804934 :     if (unlikely(state == NULL))
     602        11981 :         return PointerGetDatum(dispatch_table);
     603              : #else
     604              :     Assert(state != NULL);
     605              : #endif                          /* EEO_USE_COMPUTED_GOTO */
     606              : 
     607              :     /* setup state */
     608     95792953 :     op = state->steps;
     609     95792953 :     resultslot = state->resultslot;
     610     95792953 :     innerslot = econtext->ecxt_innertuple;
     611     95792953 :     outerslot = econtext->ecxt_outertuple;
     612     95792953 :     scanslot = econtext->ecxt_scantuple;
     613     95792953 :     oldslot = econtext->ecxt_oldtuple;
     614     95792953 :     newslot = econtext->ecxt_newtuple;
     615              : 
     616              : #if defined(EEO_USE_COMPUTED_GOTO)
     617     95792953 :     EEO_DISPATCH();
     618              : #endif
     619              : 
     620              :     EEO_SWITCH()
     621              :     {
     622     54375116 :         EEO_CASE(EEOP_DONE_RETURN)
     623              :         {
     624     54375116 :             *isnull = state->resnull;
     625     54375116 :             return state->resvalue;
     626              :         }
     627              : 
     628     41408744 :         EEO_CASE(EEOP_DONE_NO_RETURN)
     629              :         {
     630              :             Assert(isnull == NULL);
     631     41408744 :             return (Datum) 0;
     632              :         }
     633              : 
     634     20781658 :         EEO_CASE(EEOP_INNER_FETCHSOME)
     635              :         {
     636     20781658 :             CheckOpSlotCompatibility(op, innerslot);
     637              : 
     638     20781658 :             slot_getsomeattrs(innerslot, op->d.fetch.last_var);
     639              : 
     640     20781658 :             EEO_NEXT();
     641              :         }
     642              : 
     643     18037100 :         EEO_CASE(EEOP_OUTER_FETCHSOME)
     644              :         {
     645     18037100 :             CheckOpSlotCompatibility(op, outerslot);
     646              : 
     647     18037100 :             slot_getsomeattrs(outerslot, op->d.fetch.last_var);
     648              : 
     649     18037100 :             EEO_NEXT();
     650              :         }
     651              : 
     652     40871327 :         EEO_CASE(EEOP_SCAN_FETCHSOME)
     653              :         {
     654     40871327 :             CheckOpSlotCompatibility(op, scanslot);
     655              : 
     656     40871327 :             slot_getsomeattrs(scanslot, op->d.fetch.last_var);
     657              : 
     658     40871327 :             EEO_NEXT();
     659              :         }
     660              : 
     661          194 :         EEO_CASE(EEOP_OLD_FETCHSOME)
     662              :         {
     663          194 :             CheckOpSlotCompatibility(op, oldslot);
     664              : 
     665          194 :             slot_getsomeattrs(oldslot, op->d.fetch.last_var);
     666              : 
     667          194 :             EEO_NEXT();
     668              :         }
     669              : 
     670          193 :         EEO_CASE(EEOP_NEW_FETCHSOME)
     671              :         {
     672          193 :             CheckOpSlotCompatibility(op, newslot);
     673              : 
     674          193 :             slot_getsomeattrs(newslot, op->d.fetch.last_var);
     675              : 
     676          193 :             EEO_NEXT();
     677              :         }
     678              : 
     679     22354222 :         EEO_CASE(EEOP_INNER_VAR)
     680              :         {
     681     22354222 :             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     22354222 :             *op->resvalue = innerslot->tts_values[attnum];
     691     22354222 :             *op->resnull = innerslot->tts_isnull[attnum];
     692              : 
     693     22354222 :             EEO_NEXT();
     694              :         }
     695              : 
     696     40355390 :         EEO_CASE(EEOP_OUTER_VAR)
     697              :         {
     698     40355390 :             int         attnum = op->d.var.attnum;
     699              : 
     700              :             /* See EEOP_INNER_VAR comments */
     701              : 
     702              :             Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
     703     40355390 :             *op->resvalue = outerslot->tts_values[attnum];
     704     40355390 :             *op->resnull = outerslot->tts_isnull[attnum];
     705              : 
     706     40355390 :             EEO_NEXT();
     707              :         }
     708              : 
     709     42566971 :         EEO_CASE(EEOP_SCAN_VAR)
     710              :         {
     711     42566971 :             int         attnum = op->d.var.attnum;
     712              : 
     713              :             /* See EEOP_INNER_VAR comments */
     714              : 
     715              :             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
     716     42566971 :             *op->resvalue = scanslot->tts_values[attnum];
     717     42566971 :             *op->resnull = scanslot->tts_isnull[attnum];
     718              : 
     719     42566971 :             EEO_NEXT();
     720              :         }
     721              : 
     722          153 :         EEO_CASE(EEOP_OLD_VAR)
     723              :         {
     724          153 :             int         attnum = op->d.var.attnum;
     725              : 
     726              :             /* See EEOP_INNER_VAR comments */
     727              : 
     728              :             Assert(attnum >= 0 && attnum < oldslot->tts_nvalid);
     729          153 :             *op->resvalue = oldslot->tts_values[attnum];
     730          153 :             *op->resnull = oldslot->tts_isnull[attnum];
     731              : 
     732          153 :             EEO_NEXT();
     733              :         }
     734              : 
     735          156 :         EEO_CASE(EEOP_NEW_VAR)
     736              :         {
     737          156 :             int         attnum = op->d.var.attnum;
     738              : 
     739              :             /* See EEOP_INNER_VAR comments */
     740              : 
     741              :             Assert(attnum >= 0 && attnum < newslot->tts_nvalid);
     742          156 :             *op->resvalue = newslot->tts_values[attnum];
     743          156 :             *op->resnull = newslot->tts_isnull[attnum];
     744              : 
     745          156 :             EEO_NEXT();
     746              :         }
     747              : 
     748            3 :         EEO_CASE(EEOP_INNER_SYSVAR)
     749              :         {
     750            3 :             ExecEvalSysVar(state, op, econtext, innerslot);
     751            3 :             EEO_NEXT();
     752              :         }
     753              : 
     754            6 :         EEO_CASE(EEOP_OUTER_SYSVAR)
     755              :         {
     756            6 :             ExecEvalSysVar(state, op, econtext, outerslot);
     757            6 :             EEO_NEXT();
     758              :         }
     759              : 
     760      3793282 :         EEO_CASE(EEOP_SCAN_SYSVAR)
     761              :         {
     762      3793282 :             ExecEvalSysVar(state, op, econtext, scanslot);
     763      3793276 :             EEO_NEXT();
     764              :         }
     765              : 
     766          114 :         EEO_CASE(EEOP_OLD_SYSVAR)
     767              :         {
     768          114 :             ExecEvalSysVar(state, op, econtext, oldslot);
     769          114 :             EEO_NEXT();
     770              :         }
     771              : 
     772          114 :         EEO_CASE(EEOP_NEW_SYSVAR)
     773              :         {
     774          114 :             ExecEvalSysVar(state, op, econtext, newslot);
     775          114 :             EEO_NEXT();
     776              :         }
     777              : 
     778        22464 :         EEO_CASE(EEOP_WHOLEROW)
     779              :         {
     780              :             /* too complex for an inline implementation */
     781        22464 :             ExecEvalWholeRowVar(state, op, econtext);
     782              : 
     783        22464 :             EEO_NEXT();
     784              :         }
     785              : 
     786      6480283 :         EEO_CASE(EEOP_ASSIGN_INNER_VAR)
     787              :         {
     788      6480283 :             int         resultnum = op->d.assign_var.resultnum;
     789      6480283 :             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      6480283 :             resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
     798      6480283 :             resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
     799              : 
     800      6480283 :             EEO_NEXT();
     801              :         }
     802              : 
     803     16465267 :         EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
     804              :         {
     805     16465267 :             int         resultnum = op->d.assign_var.resultnum;
     806     16465267 :             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     16465267 :             resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
     815     16465267 :             resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
     816              : 
     817     16465267 :             EEO_NEXT();
     818              :         }
     819              : 
     820     33752513 :         EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
     821              :         {
     822     33752513 :             int         resultnum = op->d.assign_var.resultnum;
     823     33752513 :             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     33752513 :             resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
     832     33752513 :             resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
     833              : 
     834     33752513 :             EEO_NEXT();
     835              :         }
     836              : 
     837          432 :         EEO_CASE(EEOP_ASSIGN_OLD_VAR)
     838              :         {
     839          432 :             int         resultnum = op->d.assign_var.resultnum;
     840          432 :             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          432 :             resultslot->tts_values[resultnum] = oldslot->tts_values[attnum];
     849          432 :             resultslot->tts_isnull[resultnum] = oldslot->tts_isnull[attnum];
     850              : 
     851          432 :             EEO_NEXT();
     852              :         }
     853              : 
     854          431 :         EEO_CASE(EEOP_ASSIGN_NEW_VAR)
     855              :         {
     856          431 :             int         resultnum = op->d.assign_var.resultnum;
     857          431 :             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          431 :             resultslot->tts_values[resultnum] = newslot->tts_values[attnum];
     866          431 :             resultslot->tts_isnull[resultnum] = newslot->tts_isnull[attnum];
     867              : 
     868          431 :             EEO_NEXT();
     869              :         }
     870              : 
     871     14230887 :         EEO_CASE(EEOP_ASSIGN_TMP)
     872              :         {
     873     14230887 :             int         resultnum = op->d.assign_tmp.resultnum;
     874              : 
     875              :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     876     14230887 :             resultslot->tts_values[resultnum] = state->resvalue;
     877     14230887 :             resultslot->tts_isnull[resultnum] = state->resnull;
     878              : 
     879     14230887 :             EEO_NEXT();
     880              :         }
     881              : 
     882      5735426 :         EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
     883              :         {
     884      5735426 :             int         resultnum = op->d.assign_tmp.resultnum;
     885              : 
     886              :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     887      5735426 :             resultslot->tts_isnull[resultnum] = state->resnull;
     888      5735426 :             if (!resultslot->tts_isnull[resultnum])
     889      4120268 :                 resultslot->tts_values[resultnum] =
     890      4120268 :                     MakeExpandedObjectReadOnlyInternal(state->resvalue);
     891              :             else
     892      1615158 :                 resultslot->tts_values[resultnum] = state->resvalue;
     893              : 
     894      5735426 :             EEO_NEXT();
     895              :         }
     896              : 
     897     10260723 :         EEO_CASE(EEOP_CONST)
     898              :         {
     899     10260723 :             *op->resnull = op->d.constval.isnull;
     900     10260723 :             *op->resvalue = op->d.constval.value;
     901              : 
     902     10260723 :             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      1556239 :         EEO_CASE(EEOP_FUNCEXPR)
     921              :         {
     922      1556239 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     923              :             Datum       d;
     924              : 
     925      1556239 :             fcinfo->isnull = false;
     926      1556239 :             d = op->d.func.fn_addr(fcinfo);
     927      1551526 :             *op->resvalue = d;
     928      1551526 :             *op->resnull = fcinfo->isnull;
     929              : 
     930      1551526 :             EEO_NEXT();
     931              :         }
     932              : 
     933              :         /* strict function call with more than two arguments */
     934       417810 :         EEO_CASE(EEOP_FUNCEXPR_STRICT)
     935              :         {
     936       417810 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     937       417810 :             NullableDatum *args = fcinfo->args;
     938       417810 :             int         nargs = op->d.func.nargs;
     939              :             Datum       d;
     940              : 
     941              :             Assert(nargs > 2);
     942              : 
     943              :             /* strict function, so check for NULL args */
     944      1610888 :             for (int argno = 0; argno < nargs; argno++)
     945              :             {
     946      1216376 :                 if (args[argno].isnull)
     947              :                 {
     948        23298 :                     *op->resnull = true;
     949        23298 :                     goto strictfail;
     950              :                 }
     951              :             }
     952       394512 :             fcinfo->isnull = false;
     953       394512 :             d = op->d.func.fn_addr(fcinfo);
     954       393123 :             *op->resvalue = d;
     955       393123 :             *op->resnull = fcinfo->isnull;
     956              : 
     957       416421 :     strictfail:
     958       416421 :             EEO_NEXT();
     959              :         }
     960              : 
     961              :         /* strict function call with one argument */
     962      7182802 :         EEO_CASE(EEOP_FUNCEXPR_STRICT_1)
     963              :         {
     964      7182802 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     965      7182802 :             NullableDatum *args = fcinfo->args;
     966              : 
     967              :             Assert(op->d.func.nargs == 1);
     968              : 
     969              :             /* strict function, so check for NULL args */
     970      7182802 :             if (args[0].isnull)
     971        23613 :                 *op->resnull = true;
     972              :             else
     973              :             {
     974              :                 Datum       d;
     975              : 
     976      7159189 :                 fcinfo->isnull = false;
     977      7159189 :                 d = op->d.func.fn_addr(fcinfo);
     978      7158518 :                 *op->resvalue = d;
     979      7158518 :                 *op->resnull = fcinfo->isnull;
     980              :             }
     981              : 
     982      7182131 :             EEO_NEXT();
     983              :         }
     984              : 
     985              :         /* strict function call with two arguments */
     986     53343705 :         EEO_CASE(EEOP_FUNCEXPR_STRICT_2)
     987              :         {
     988     53343705 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     989     53343705 :             NullableDatum *args = fcinfo->args;
     990              : 
     991              :             Assert(op->d.func.nargs == 2);
     992              : 
     993              :             /* strict function, so check for NULL args */
     994     53343705 :             if (args[0].isnull || args[1].isnull)
     995       566652 :                 *op->resnull = true;
     996              :             else
     997              :             {
     998              :                 Datum       d;
     999              : 
    1000     52777053 :                 fcinfo->isnull = false;
    1001     52777053 :                 d = op->d.func.fn_addr(fcinfo);
    1002     52775482 :                 *op->resvalue = d;
    1003     52775482 :                 *op->resnull = fcinfo->isnull;
    1004              :             }
    1005              : 
    1006     53342134 :             EEO_NEXT();
    1007              :         }
    1008              : 
    1009          104 :         EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
    1010              :         {
    1011              :             /* not common enough to inline */
    1012          104 :             ExecEvalFuncExprFusage(state, op, econtext);
    1013              : 
    1014          104 :             EEO_NEXT();
    1015              :         }
    1016              : 
    1017            3 :         EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
    1018              :         {
    1019              :             /* not common enough to inline */
    1020            3 :             ExecEvalFuncExprStrictFusage(state, op, econtext);
    1021              : 
    1022            3 :             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       554356 :         EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
    1036              :         {
    1037       554356 :             *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       638170 :         EEO_CASE(EEOP_BOOL_AND_STEP)
    1048              :         {
    1049       638170 :             if (*op->resnull)
    1050              :             {
    1051          608 :                 *op->d.boolexpr.anynull = true;
    1052              :             }
    1053       637562 :             else if (!DatumGetBool(*op->resvalue))
    1054              :             {
    1055              :                 /* result is already set to FALSE, need not change it */
    1056              :                 /* bail out early */
    1057       412024 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
    1058              :             }
    1059              : 
    1060       226146 :             EEO_NEXT();
    1061              :         }
    1062              : 
    1063       142332 :         EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
    1064              :         {
    1065       142332 :             if (*op->resnull)
    1066              :             {
    1067              :                 /* result is already set to NULL, need not change it */
    1068              :             }
    1069       141893 :             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       105266 :             else if (*op->d.boolexpr.anynull)
    1080              :             {
    1081          186 :                 *op->resvalue = (Datum) 0;
    1082          186 :                 *op->resnull = true;
    1083              :             }
    1084              :             else
    1085              :             {
    1086              :                 /* result is already set to TRUE, need not change it */
    1087              :             }
    1088              : 
    1089       142332 :             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      2005064 :         EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
    1103              :         {
    1104      2005064 :             *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      4053829 :         EEO_CASE(EEOP_BOOL_OR_STEP)
    1115              :         {
    1116      4053829 :             if (*op->resnull)
    1117              :             {
    1118        81092 :                 *op->d.boolexpr.anynull = true;
    1119              :             }
    1120      3972737 :             else if (DatumGetBool(*op->resvalue))
    1121              :             {
    1122              :                 /* result is already set to TRUE, need not change it */
    1123              :                 /* bail out early */
    1124       249697 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
    1125              :             }
    1126              : 
    1127      3804132 :             EEO_NEXT();
    1128              :         }
    1129              : 
    1130      1755367 :         EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
    1131              :         {
    1132      1755367 :             if (*op->resnull)
    1133              :             {
    1134              :                 /* result is already set to NULL, need not change it */
    1135              :             }
    1136      1679755 :             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      1645810 :             else if (*op->d.boolexpr.anynull)
    1147              :             {
    1148         3266 :                 *op->resvalue = (Datum) 0;
    1149         3266 :                 *op->resnull = true;
    1150              :             }
    1151              :             else
    1152              :             {
    1153              :                 /* result is already set to FALSE, need not change it */
    1154              :             }
    1155              : 
    1156      1755367 :             EEO_NEXT();
    1157              :         }
    1158              : 
    1159      1582494 :         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      1582494 :             *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
    1168              : 
    1169      1582494 :             EEO_NEXT();
    1170              :         }
    1171              : 
    1172     48820968 :         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     48820968 :             if (*op->resnull ||
    1178     48344695 :                 !DatumGetBool(*op->resvalue))
    1179              :             {
    1180              :                 /* ... bail out early, returning FALSE */
    1181     22803413 :                 *op->resnull = false;
    1182     22803413 :                 *op->resvalue = BoolGetDatum(false);
    1183     22803413 :                 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     26017555 :             EEO_NEXT();
    1192              :         }
    1193              : 
    1194       184089 :         EEO_CASE(EEOP_JUMP)
    1195              :         {
    1196              :             /* Unconditionally jump to target step */
    1197       184089 :             EEO_JUMP(op->d.jump.jumpdone);
    1198              :         }
    1199              : 
    1200       364087 :         EEO_CASE(EEOP_JUMP_IF_NULL)
    1201              :         {
    1202              :             /* Transfer control if current result is null */
    1203       364087 :             if (*op->resnull)
    1204         1600 :                 EEO_JUMP(op->d.jump.jumpdone);
    1205              : 
    1206       362487 :             EEO_NEXT();
    1207              :         }
    1208              : 
    1209       168304 :         EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
    1210              :         {
    1211              :             /* Transfer control if current result is non-null */
    1212       168304 :             if (!*op->resnull)
    1213        99751 :                 EEO_JUMP(op->d.jump.jumpdone);
    1214              : 
    1215        68553 :             EEO_NEXT();
    1216              :         }
    1217              : 
    1218      1112696 :         EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
    1219              :         {
    1220              :             /* Transfer control if current result is null or false */
    1221      1112696 :             if (*op->resnull || !DatumGetBool(*op->resvalue))
    1222       870214 :                 EEO_JUMP(op->d.jump.jumpdone);
    1223              : 
    1224       242482 :             EEO_NEXT();
    1225              :         }
    1226              : 
    1227       497752 :         EEO_CASE(EEOP_NULLTEST_ISNULL)
    1228              :         {
    1229       497752 :             *op->resvalue = BoolGetDatum(*op->resnull);
    1230       497752 :             *op->resnull = false;
    1231              : 
    1232       497752 :             EEO_NEXT();
    1233              :         }
    1234              : 
    1235      1763560 :         EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
    1236              :         {
    1237      1763560 :             *op->resvalue = BoolGetDatum(!*op->resnull);
    1238      1763560 :             *op->resnull = false;
    1239              : 
    1240      1763560 :             EEO_NEXT();
    1241              :         }
    1242              : 
    1243          348 :         EEO_CASE(EEOP_NULLTEST_ROWISNULL)
    1244              :         {
    1245              :             /* out of line implementation: too large */
    1246          348 :             ExecEvalRowNull(state, op, econtext);
    1247              : 
    1248          348 :             EEO_NEXT();
    1249              :         }
    1250              : 
    1251          285 :         EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
    1252              :         {
    1253              :             /* out of line implementation: too large */
    1254          285 :             ExecEvalRowNotNull(state, op, econtext);
    1255              : 
    1256          285 :             EEO_NEXT();
    1257              :         }
    1258              : 
    1259              :         /* BooleanTest implementations for all booltesttypes */
    1260              : 
    1261        49615 :         EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
    1262              :         {
    1263        49615 :             if (*op->resnull)
    1264              :             {
    1265        49137 :                 *op->resvalue = BoolGetDatum(false);
    1266        49137 :                 *op->resnull = false;
    1267              :             }
    1268              :             /* else, input value is the correct output as well */
    1269              : 
    1270        49615 :             EEO_NEXT();
    1271              :         }
    1272              : 
    1273          445 :         EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE)
    1274              :         {
    1275          445 :             if (*op->resnull)
    1276              :             {
    1277           87 :                 *op->resvalue = BoolGetDatum(true);
    1278           87 :                 *op->resnull = false;
    1279              :             }
    1280              :             else
    1281          358 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
    1282              : 
    1283          445 :             EEO_NEXT();
    1284              :         }
    1285              : 
    1286          359 :         EEO_CASE(EEOP_BOOLTEST_IS_FALSE)
    1287              :         {
    1288          359 :             if (*op->resnull)
    1289              :             {
    1290           81 :                 *op->resvalue = BoolGetDatum(false);
    1291           81 :                 *op->resnull = false;
    1292              :             }
    1293              :             else
    1294          278 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
    1295              : 
    1296          359 :             EEO_NEXT();
    1297              :         }
    1298              : 
    1299          271 :         EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE)
    1300              :         {
    1301          271 :             if (*op->resnull)
    1302              :             {
    1303           21 :                 *op->resvalue = BoolGetDatum(true);
    1304           21 :                 *op->resnull = false;
    1305              :             }
    1306              :             /* else, input value is the correct output as well */
    1307              : 
    1308          271 :             EEO_NEXT();
    1309              :         }
    1310              : 
    1311      3818244 :         EEO_CASE(EEOP_PARAM_EXEC)
    1312              :         {
    1313              :             /* out of line implementation: too large */
    1314      3818244 :             ExecEvalParamExec(state, op, econtext);
    1315              : 
    1316      3818235 :             EEO_NEXT();
    1317              :         }
    1318              : 
    1319       202651 :         EEO_CASE(EEOP_PARAM_EXTERN)
    1320              :         {
    1321              :             /* out of line implementation: too large */
    1322       202651 :             ExecEvalParamExtern(state, op, econtext);
    1323       202651 :             EEO_NEXT();
    1324              :         }
    1325              : 
    1326       216471 :         EEO_CASE(EEOP_PARAM_CALLBACK)
    1327              :         {
    1328              :             /* allow an extension module to supply a PARAM_EXTERN value */
    1329       216471 :             op->d.cparam.paramfunc(state, op, econtext);
    1330       216468 :             EEO_NEXT();
    1331              :         }
    1332              : 
    1333       871943 :         EEO_CASE(EEOP_PARAM_SET)
    1334              :         {
    1335              :             /* out of line, unlikely to matter performance-wise */
    1336       871943 :             ExecEvalParamSet(state, op, econtext);
    1337       871943 :             EEO_NEXT();
    1338              :         }
    1339              : 
    1340        21867 :         EEO_CASE(EEOP_CASE_TESTVAL)
    1341              :         {
    1342        21867 :             *op->resvalue = *op->d.casetest.value;
    1343        21867 :             *op->resnull = *op->d.casetest.isnull;
    1344              : 
    1345        21867 :             EEO_NEXT();
    1346              :         }
    1347              : 
    1348         3235 :         EEO_CASE(EEOP_CASE_TESTVAL_EXT)
    1349              :         {
    1350         3235 :             *op->resvalue = econtext->caseValue_datum;
    1351         3235 :             *op->resnull = econtext->caseValue_isNull;
    1352              : 
    1353         3235 :             EEO_NEXT();
    1354              :         }
    1355              : 
    1356         2499 :         EEO_CASE(EEOP_MAKE_READONLY)
    1357              :         {
    1358              :             /*
    1359              :              * Force a varlena value that might be read multiple times to R/O
    1360              :              */
    1361         2499 :             if (!*op->d.make_readonly.isnull)
    1362         2467 :                 *op->resvalue =
    1363         2467 :                     MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
    1364         2499 :             *op->resnull = *op->d.make_readonly.isnull;
    1365              : 
    1366         2499 :             EEO_NEXT();
    1367              :         }
    1368              : 
    1369      3783867 :         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      3783867 :             if (*op->resnull)
    1383              :             {
    1384              :                 /* output functions are not called on nulls */
    1385        31011 :                 str = NULL;
    1386              :             }
    1387              :             else
    1388              :             {
    1389              :                 FunctionCallInfo fcinfo_out;
    1390              : 
    1391      3752856 :                 fcinfo_out = op->d.iocoerce.fcinfo_data_out;
    1392      3752856 :                 fcinfo_out->args[0].value = *op->resvalue;
    1393      3752856 :                 fcinfo_out->args[0].isnull = false;
    1394              : 
    1395      3752856 :                 fcinfo_out->isnull = false;
    1396      3752856 :                 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      3783867 :             if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
    1404              :             {
    1405              :                 FunctionCallInfo fcinfo_in;
    1406              :                 Datum       d;
    1407              : 
    1408      3752914 :                 fcinfo_in = op->d.iocoerce.fcinfo_data_in;
    1409      3752914 :                 fcinfo_in->args[0].value = PointerGetDatum(str);
    1410      3752914 :                 fcinfo_in->args[0].isnull = *op->resnull;
    1411              :                 /* second and third arguments are already set up */
    1412              : 
    1413      3752914 :                 fcinfo_in->isnull = false;
    1414      3752914 :                 d = FunctionCallInvoke(fcinfo_in);
    1415      3752894 :                 *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      3783847 :             EEO_NEXT();
    1431              :         }
    1432              : 
    1433            0 :         EEO_CASE(EEOP_IOCOERCE_SAFE)
    1434              :         {
    1435            0 :             ExecEvalCoerceViaIOSafe(state, op);
    1436            0 :             EEO_NEXT();
    1437              :         }
    1438              : 
    1439       804202 :         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       804202 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1451              : 
    1452              :             /* check function arguments for NULLness */
    1453       804202 :             if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
    1454              :             {
    1455              :                 /* Both NULL? Then is not distinct... */
    1456       630778 :                 *op->resvalue = BoolGetDatum(false);
    1457       630778 :                 *op->resnull = false;
    1458              :             }
    1459       173424 :             else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
    1460              :             {
    1461              :                 /* Only one is NULL? Then is distinct... */
    1462          181 :                 *op->resvalue = BoolGetDatum(true);
    1463          181 :                 *op->resnull = false;
    1464              :             }
    1465              :             else
    1466              :             {
    1467              :                 /* Neither null, so apply the equality function */
    1468              :                 Datum       eqresult;
    1469              : 
    1470       173243 :                 fcinfo->isnull = false;
    1471       173243 :                 eqresult = op->d.func.fn_addr(fcinfo);
    1472              :                 /* Must invert result of "="; safe to do even if null */
    1473       173243 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
    1474       173243 :                 *op->resnull = fcinfo->isnull;
    1475              :             }
    1476              : 
    1477       804202 :             EEO_NEXT();
    1478              :         }
    1479              : 
    1480              :         /* see EEOP_DISTINCT for comments, this is just inverted */
    1481      7757813 :         EEO_CASE(EEOP_NOT_DISTINCT)
    1482              :         {
    1483      7757813 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1484              : 
    1485      7757813 :             if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
    1486              :             {
    1487        39916 :                 *op->resvalue = BoolGetDatum(true);
    1488        39916 :                 *op->resnull = false;
    1489              :             }
    1490      7717897 :             else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
    1491              :             {
    1492          149 :                 *op->resvalue = BoolGetDatum(false);
    1493          149 :                 *op->resnull = false;
    1494              :             }
    1495              :             else
    1496              :             {
    1497              :                 Datum       eqresult;
    1498              : 
    1499      7717748 :                 fcinfo->isnull = false;
    1500      7717748 :                 eqresult = op->d.func.fn_addr(fcinfo);
    1501      7717748 :                 *op->resvalue = eqresult;
    1502      7717748 :                 *op->resnull = fcinfo->isnull;
    1503              :             }
    1504              : 
    1505      7757813 :             EEO_NEXT();
    1506              :         }
    1507              : 
    1508         3565 :         EEO_CASE(EEOP_NULLIF)
    1509              :         {
    1510              :             /*
    1511              :              * The arguments are already evaluated into fcinfo->args.
    1512              :              */
    1513         3565 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1514         3565 :             Datum       save_arg0 = fcinfo->args[0].value;
    1515              : 
    1516              :             /* if either argument is NULL they can't be equal */
    1517         3565 :             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         3535 :                 if (op->d.func.make_ro)
    1529          121 :                     fcinfo->args[0].value =
    1530          121 :                         MakeExpandedObjectReadOnlyInternal(save_arg0);
    1531              : 
    1532         3535 :                 fcinfo->isnull = false;
    1533         3535 :                 result = op->d.func.fn_addr(fcinfo);
    1534              : 
    1535              :                 /* if the arguments are equal return null */
    1536         3535 :                 if (!fcinfo->isnull && DatumGetBool(result))
    1537              :                 {
    1538           99 :                     *op->resvalue = (Datum) 0;
    1539           99 :                     *op->resnull = true;
    1540              : 
    1541           99 :                     EEO_NEXT();
    1542              :                 }
    1543              :             }
    1544              : 
    1545              :             /* Arguments aren't equal, so return the first one */
    1546         3466 :             *op->resvalue = save_arg0;
    1547         3466 :             *op->resnull = fcinfo->args[0].isnull;
    1548              : 
    1549         3466 :             EEO_NEXT();
    1550              :         }
    1551              : 
    1552         9717 :         EEO_CASE(EEOP_SQLVALUEFUNCTION)
    1553              :         {
    1554              :             /*
    1555              :              * Doesn't seem worthwhile to have an inline implementation
    1556              :              * efficiency-wise.
    1557              :              */
    1558         9717 :             ExecEvalSQLValueFunction(state, op);
    1559              : 
    1560         9717 :             EEO_NEXT();
    1561              :         }
    1562              : 
    1563            1 :         EEO_CASE(EEOP_CURRENTOFEXPR)
    1564              :         {
    1565              :             /* error invocation uses space, and shouldn't ever occur */
    1566            1 :             ExecEvalCurrentOfExpr(state, op);
    1567              : 
    1568            0 :             EEO_NEXT();
    1569              :         }
    1570              : 
    1571          517 :         EEO_CASE(EEOP_NEXTVALUEEXPR)
    1572              :         {
    1573              :             /*
    1574              :              * Doesn't seem worthwhile to have an inline implementation
    1575              :              * efficiency-wise.
    1576              :              */
    1577          517 :             ExecEvalNextValueExpr(state, op);
    1578              : 
    1579          517 :             EEO_NEXT();
    1580              :         }
    1581              : 
    1582          375 :         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          375 :             if (state->flags & op->d.returningexpr.nullflag)
    1589              :             {
    1590           66 :                 *op->resvalue = (Datum) 0;
    1591           66 :                 *op->resnull = true;
    1592              : 
    1593           66 :                 EEO_JUMP(op->d.returningexpr.jumpdone);
    1594              :             }
    1595              : 
    1596          309 :             EEO_NEXT();
    1597              :         }
    1598              : 
    1599       412382 :         EEO_CASE(EEOP_ARRAYEXPR)
    1600              :         {
    1601              :             /* too complex for an inline implementation */
    1602       412382 :             ExecEvalArrayExpr(state, op);
    1603              : 
    1604       412382 :             EEO_NEXT();
    1605              :         }
    1606              : 
    1607        54810 :         EEO_CASE(EEOP_ARRAYCOERCE)
    1608              :         {
    1609              :             /* too complex for an inline implementation */
    1610        54810 :             ExecEvalArrayCoerce(state, op, econtext);
    1611              : 
    1612        54794 :             EEO_NEXT();
    1613              :         }
    1614              : 
    1615        28983 :         EEO_CASE(EEOP_ROW)
    1616              :         {
    1617              :             /* too complex for an inline implementation */
    1618        28983 :             ExecEvalRow(state, op);
    1619              : 
    1620        28983 :             EEO_NEXT();
    1621              :         }
    1622              : 
    1623       104346 :         EEO_CASE(EEOP_ROWCOMPARE_STEP)
    1624              :         {
    1625       104346 :             FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
    1626              :             Datum       d;
    1627              : 
    1628              :             /* force NULL result if strict fn and NULL input */
    1629       104346 :             if (op->d.rowcompare_step.finfo->fn_strict &&
    1630       104346 :                 (fcinfo->args[0].isnull || fcinfo->args[1].isnull))
    1631              :             {
    1632            9 :                 *op->resnull = true;
    1633            9 :                 EEO_JUMP(op->d.rowcompare_step.jumpnull);
    1634              :             }
    1635              : 
    1636              :             /* Apply comparison function */
    1637       104337 :             fcinfo->isnull = false;
    1638       104337 :             d = op->d.rowcompare_step.fn_addr(fcinfo);
    1639       104337 :             *op->resvalue = d;
    1640              : 
    1641              :             /* force NULL result if NULL function result */
    1642       104337 :             if (fcinfo->isnull)
    1643              :             {
    1644            0 :                 *op->resnull = true;
    1645            0 :                 EEO_JUMP(op->d.rowcompare_step.jumpnull);
    1646              :             }
    1647       104337 :             *op->resnull = false;
    1648              : 
    1649              :             /* If unequal, no need to compare remaining columns */
    1650       104337 :             if (DatumGetInt32(*op->resvalue) != 0)
    1651              :             {
    1652        47256 :                 EEO_JUMP(op->d.rowcompare_step.jumpdone);
    1653              :             }
    1654              : 
    1655        57081 :             EEO_NEXT();
    1656              :         }
    1657              : 
    1658        47256 :         EEO_CASE(EEOP_ROWCOMPARE_FINAL)
    1659              :         {
    1660        47256 :             int32       cmpresult = DatumGetInt32(*op->resvalue);
    1661        47256 :             CompareType cmptype = op->d.rowcompare_final.cmptype;
    1662              : 
    1663        47256 :             *op->resnull = false;
    1664        47256 :             switch (cmptype)
    1665              :             {
    1666              :                     /* EQ and NE cases aren't allowed here */
    1667        17202 :                 case COMPARE_LT:
    1668        17202 :                     *op->resvalue = BoolGetDatum(cmpresult < 0);
    1669        17202 :                     break;
    1670        30000 :                 case COMPARE_LE:
    1671        30000 :                     *op->resvalue = BoolGetDatum(cmpresult <= 0);
    1672        30000 :                     break;
    1673            3 :                 case COMPARE_GE:
    1674            3 :                     *op->resvalue = BoolGetDatum(cmpresult >= 0);
    1675            3 :                     break;
    1676           51 :                 case COMPARE_GT:
    1677           51 :                     *op->resvalue = BoolGetDatum(cmpresult > 0);
    1678           51 :                     break;
    1679            0 :                 default:
    1680              :                     Assert(false);
    1681            0 :                     break;
    1682              :             }
    1683              : 
    1684        47256 :             EEO_NEXT();
    1685              :         }
    1686              : 
    1687        11644 :         EEO_CASE(EEOP_MINMAX)
    1688              :         {
    1689              :             /* too complex for an inline implementation */
    1690        11644 :             ExecEvalMinMax(state, op);
    1691              : 
    1692        11644 :             EEO_NEXT();
    1693              :         }
    1694              : 
    1695       207329 :         EEO_CASE(EEOP_FIELDSELECT)
    1696              :         {
    1697              :             /* too complex for an inline implementation */
    1698       207329 :             ExecEvalFieldSelect(state, op, econtext);
    1699              : 
    1700       207329 :             EEO_NEXT();
    1701              :         }
    1702              : 
    1703          260 :         EEO_CASE(EEOP_FIELDSTORE_DEFORM)
    1704              :         {
    1705              :             /* too complex for an inline implementation */
    1706          260 :             ExecEvalFieldStoreDeForm(state, op, econtext);
    1707              : 
    1708          260 :             EEO_NEXT();
    1709              :         }
    1710              : 
    1711          260 :         EEO_CASE(EEOP_FIELDSTORE_FORM)
    1712              :         {
    1713              :             /* too complex for an inline implementation */
    1714          260 :             ExecEvalFieldStoreForm(state, op, econtext);
    1715              : 
    1716          260 :             EEO_NEXT();
    1717              :         }
    1718              : 
    1719       358008 :         EEO_CASE(EEOP_SBSREF_SUBSCRIPTS)
    1720              :         {
    1721              :             /* Precheck SubscriptingRef subscript(s) */
    1722       358008 :             if (op->d.sbsref_subscript.subscriptfunc(state, op, econtext))
    1723              :             {
    1724       357981 :                 EEO_NEXT();
    1725              :             }
    1726              :             else
    1727              :             {
    1728              :                 /* Subscript is null, short-circuit SubscriptingRef to NULL */
    1729           15 :                 EEO_JUMP(op->d.sbsref_subscript.jumpdone);
    1730              :             }
    1731              :         }
    1732              : 
    1733          138 :         EEO_CASE(EEOP_SBSREF_OLD)
    1734          951 :             EEO_CASE(EEOP_SBSREF_ASSIGN)
    1735       358117 :             EEO_CASE(EEOP_SBSREF_FETCH)
    1736              :         {
    1737              :             /* Perform a SubscriptingRef fetch or assignment */
    1738       358117 :             op->d.sbsref.subscriptfunc(state, op, econtext);
    1739              : 
    1740       358054 :             EEO_NEXT();
    1741              :         }
    1742              : 
    1743         6065 :         EEO_CASE(EEOP_CONVERT_ROWTYPE)
    1744              :         {
    1745              :             /* too complex for an inline implementation */
    1746         6065 :             ExecEvalConvertRowtype(state, op, econtext);
    1747              : 
    1748         6065 :             EEO_NEXT();
    1749              :         }
    1750              : 
    1751      2292079 :         EEO_CASE(EEOP_SCALARARRAYOP)
    1752              :         {
    1753              :             /* too complex for an inline implementation */
    1754      2292079 :             ExecEvalScalarArrayOp(state, op);
    1755              : 
    1756      2292079 :             EEO_NEXT();
    1757              :         }
    1758              : 
    1759        20667 :         EEO_CASE(EEOP_HASHED_SCALARARRAYOP)
    1760              :         {
    1761              :             /* too complex for an inline implementation */
    1762        20667 :             ExecEvalHashedScalarArrayOp(state, op, econtext);
    1763              : 
    1764        20667 :             EEO_NEXT();
    1765              :         }
    1766              : 
    1767         7277 :         EEO_CASE(EEOP_DOMAIN_TESTVAL)
    1768              :         {
    1769         7277 :             *op->resvalue = *op->d.casetest.value;
    1770         7277 :             *op->resnull = *op->d.casetest.isnull;
    1771              : 
    1772         7277 :             EEO_NEXT();
    1773              :         }
    1774              : 
    1775        38850 :         EEO_CASE(EEOP_DOMAIN_TESTVAL_EXT)
    1776              :         {
    1777        38850 :             *op->resvalue = econtext->domainValue_datum;
    1778        38850 :             *op->resnull = econtext->domainValue_isNull;
    1779              : 
    1780        38850 :             EEO_NEXT();
    1781              :         }
    1782              : 
    1783          189 :         EEO_CASE(EEOP_DOMAIN_NOTNULL)
    1784              :         {
    1785              :             /* too complex for an inline implementation */
    1786          189 :             ExecEvalConstraintNotNull(state, op);
    1787              : 
    1788          136 :             EEO_NEXT();
    1789              :         }
    1790              : 
    1791         7005 :         EEO_CASE(EEOP_DOMAIN_CHECK)
    1792              :         {
    1793              :             /* too complex for an inline implementation */
    1794         7005 :             ExecEvalConstraintCheck(state, op);
    1795              : 
    1796         6788 :             EEO_NEXT();
    1797              :         }
    1798              : 
    1799       100020 :         EEO_CASE(EEOP_HASHDATUM_SET_INITVAL)
    1800              :         {
    1801       100020 :             *op->resvalue = op->d.hashdatum_initvalue.init_value;
    1802       100020 :             *op->resnull = false;
    1803              : 
    1804       100020 :             EEO_NEXT();
    1805              :         }
    1806              : 
    1807      1404578 :         EEO_CASE(EEOP_HASHDATUM_FIRST)
    1808              :         {
    1809      1404578 :             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      1404578 :             if (!fcinfo->args[0].isnull)
    1816      1399438 :                 *op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
    1817              :             else
    1818         5140 :                 *op->resvalue = (Datum) 0;
    1819              : 
    1820      1404575 :             *op->resnull = false;
    1821              : 
    1822      1404575 :             EEO_NEXT();
    1823              :         }
    1824              : 
    1825      8056317 :         EEO_CASE(EEOP_HASHDATUM_FIRST_STRICT)
    1826              :         {
    1827      8056317 :             FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
    1828              : 
    1829      8056317 :             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          261 :                 *op->resnull = true;
    1837          261 :                 *op->resvalue = (Datum) 0;
    1838          261 :                 EEO_JUMP(op->d.hashdatum.jumpdone);
    1839              :             }
    1840              : 
    1841              :             /* execute the hash function and save the resulting value */
    1842      8056056 :             *op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
    1843      8056056 :             *op->resnull = false;
    1844              : 
    1845      8056056 :             EEO_NEXT();
    1846              :         }
    1847              : 
    1848      2349942 :         EEO_CASE(EEOP_HASHDATUM_NEXT32)
    1849              :         {
    1850      2349942 :             FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
    1851              :             uint32      existinghash;
    1852              : 
    1853      2349942 :             existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value);
    1854              :             /* combine successive hash values by rotating */
    1855      2349942 :             existinghash = pg_rotate_left32(existinghash, 1);
    1856              : 
    1857              :             /* leave the hash value alone on NULL inputs */
    1858      2349942 :             if (!fcinfo->args[0].isnull)
    1859              :             {
    1860              :                 uint32      hashvalue;
    1861              : 
    1862              :                 /* execute hash func and combine with previous hash value */
    1863      2297067 :                 hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo));
    1864      2297067 :                 existinghash = existinghash ^ hashvalue;
    1865              :             }
    1866              : 
    1867      2349942 :             *op->resvalue = UInt32GetDatum(existinghash);
    1868      2349942 :             *op->resnull = false;
    1869              : 
    1870      2349942 :             EEO_NEXT();
    1871              :         }
    1872              : 
    1873      1037718 :         EEO_CASE(EEOP_HASHDATUM_NEXT32_STRICT)
    1874              :         {
    1875      1037718 :             FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
    1876              : 
    1877      1037718 :             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           61 :                 *op->resnull = true;
    1885           61 :                 *op->resvalue = (Datum) 0;
    1886           61 :                 EEO_JUMP(op->d.hashdatum.jumpdone);
    1887              :             }
    1888              :             else
    1889              :             {
    1890              :                 uint32      existinghash;
    1891              :                 uint32      hashvalue;
    1892              : 
    1893      1037657 :                 existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value);
    1894              :                 /* combine successive hash values by rotating */
    1895      1037657 :                 existinghash = pg_rotate_left32(existinghash, 1);
    1896              : 
    1897              :                 /* execute hash func and combine with previous hash value */
    1898      1037657 :                 hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo));
    1899      1037657 :                 *op->resvalue = UInt32GetDatum(existinghash ^ hashvalue);
    1900      1037657 :                 *op->resnull = false;
    1901              :             }
    1902              : 
    1903      1037657 :             EEO_NEXT();
    1904              :         }
    1905              : 
    1906        22827 :         EEO_CASE(EEOP_XMLEXPR)
    1907              :         {
    1908              :             /* too complex for an inline implementation */
    1909        22827 :             ExecEvalXmlExpr(state, op);
    1910              : 
    1911        22776 :             EEO_NEXT();
    1912              :         }
    1913              : 
    1914          351 :         EEO_CASE(EEOP_JSON_CONSTRUCTOR)
    1915              :         {
    1916              :             /* too complex for an inline implementation */
    1917          351 :             ExecEvalJsonConstructor(state, op, econtext);
    1918          308 :             EEO_NEXT();
    1919              :         }
    1920              : 
    1921         1375 :         EEO_CASE(EEOP_IS_JSON)
    1922              :         {
    1923              :             /* too complex for an inline implementation */
    1924         1375 :             ExecEvalJsonIsPredicate(state, op);
    1925              : 
    1926         1375 :             EEO_NEXT();
    1927              :         }
    1928              : 
    1929         2653 :         EEO_CASE(EEOP_JSONEXPR_PATH)
    1930              :         {
    1931              :             /* too complex for an inline implementation */
    1932         2653 :             EEO_JUMP(ExecEvalJsonExprPath(state, op, econtext));
    1933              :         }
    1934              : 
    1935          903 :         EEO_CASE(EEOP_JSONEXPR_COERCION)
    1936              :         {
    1937              :             /* too complex for an inline implementation */
    1938          903 :             ExecEvalJsonCoercion(state, op, econtext);
    1939              : 
    1940          825 :             EEO_NEXT();
    1941              :         }
    1942              : 
    1943          849 :         EEO_CASE(EEOP_JSONEXPR_COERCION_FINISH)
    1944              :         {
    1945              :             /* too complex for an inline implementation */
    1946          849 :             ExecEvalJsonCoercionFinish(state, op);
    1947              : 
    1948          810 :             EEO_NEXT();
    1949              :         }
    1950              : 
    1951       289229 :         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       289229 :             int         aggno = op->d.aggref.aggno;
    1958              : 
    1959              :             Assert(econtext->ecxt_aggvalues != NULL);
    1960              : 
    1961       289229 :             *op->resvalue = econtext->ecxt_aggvalues[aggno];
    1962       289229 :             *op->resnull = econtext->ecxt_aggnulls[aggno];
    1963              : 
    1964       289229 :             EEO_NEXT();
    1965              :         }
    1966              : 
    1967          839 :         EEO_CASE(EEOP_GROUPING_FUNC)
    1968              :         {
    1969              :             /* too complex/uncommon for an inline implementation */
    1970          839 :             ExecEvalGroupingFunc(state, op);
    1971              : 
    1972          839 :             EEO_NEXT();
    1973              :         }
    1974              : 
    1975       576496 :         EEO_CASE(EEOP_WINDOW_FUNC)
    1976              :         {
    1977              :             /*
    1978              :              * Like Aggref, just return a precomputed value from the econtext.
    1979              :              */
    1980       576496 :             WindowFuncExprState *wfunc = op->d.window_func.wfstate;
    1981              : 
    1982              :             Assert(econtext->ecxt_aggvalues != NULL);
    1983              : 
    1984       576496 :             *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];
    1985       576496 :             *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];
    1986              : 
    1987       576496 :             EEO_NEXT();
    1988              :         }
    1989              : 
    1990          229 :         EEO_CASE(EEOP_MERGE_SUPPORT_FUNC)
    1991              :         {
    1992              :             /* too complex/uncommon for an inline implementation */
    1993          229 :             ExecEvalMergeSupportFunc(state, op, econtext);
    1994              : 
    1995          229 :             EEO_NEXT();
    1996              :         }
    1997              : 
    1998      1814924 :         EEO_CASE(EEOP_SUBPLAN)
    1999              :         {
    2000              :             /* too complex for an inline implementation */
    2001      1814924 :             ExecEvalSubPlan(state, op, econtext);
    2002              : 
    2003      1814921 :             EEO_NEXT();
    2004              :         }
    2005              : 
    2006              :         /* evaluate a strict aggregate deserialization function */
    2007          333 :         EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
    2008              :         {
    2009              :             /* Don't call a strict deserialization function with NULL input */
    2010          333 :             if (op->d.agg_deserialize.fcinfo_data->args[0].isnull)
    2011           42 :                 EEO_JUMP(op->d.agg_deserialize.jumpnull);
    2012              : 
    2013              :             /* fallthrough */
    2014              :         }
    2015              : 
    2016              :         /* evaluate aggregate deserialization function (non-strict portion) */
    2017          291 :         EEO_CASE(EEOP_AGG_DESERIALIZE)
    2018              :         {
    2019          291 :             FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
    2020          291 :             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          291 :             oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    2028          291 :             fcinfo->isnull = false;
    2029          291 :             *op->resvalue = FunctionCallInvoke(fcinfo);
    2030          291 :             *op->resnull = fcinfo->isnull;
    2031          291 :             MemoryContextSwitchTo(oldContext);
    2032              : 
    2033          291 :             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       120849 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
    2043              :         {
    2044       120849 :             NullableDatum *args = op->d.agg_strict_input_check.args;
    2045       120849 :             int         nargs = op->d.agg_strict_input_check.nargs;
    2046              : 
    2047              :             Assert(nargs > 1);
    2048              : 
    2049       362589 :             for (int argno = 0; argno < nargs; argno++)
    2050              :             {
    2051       241761 :                 if (args[argno].isnull)
    2052           21 :                     EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    2053              :             }
    2054       120828 :             EEO_NEXT();
    2055              :         }
    2056              : 
    2057              :         /* special case for just one argument */
    2058      2921852 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1)
    2059              :         {
    2060      2921852 :             NullableDatum *args = op->d.agg_strict_input_check.args;
    2061      2921852 :             PG_USED_FOR_ASSERTS_ONLY int nargs = op->d.agg_strict_input_check.nargs;
    2062              : 
    2063              :             Assert(nargs == 1);
    2064              : 
    2065      2921852 :             if (args[0].isnull)
    2066        82212 :                 EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    2067      2839640 :             EEO_NEXT();
    2068              :         }
    2069              : 
    2070       188352 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
    2071              :         {
    2072       188352 :             bool       *nulls = op->d.agg_strict_input_check.nulls;
    2073       188352 :             int         nargs = op->d.agg_strict_input_check.nargs;
    2074              : 
    2075       354204 :             for (int argno = 0; argno < nargs; argno++)
    2076              :             {
    2077       188352 :                 if (nulls[argno])
    2078        22500 :                     EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    2079              :             }
    2080       165852 :             EEO_NEXT();
    2081              :         }
    2082              : 
    2083              :         /*
    2084              :          * Check for a NULL pointer to the per-group states.
    2085              :          */
    2086              : 
    2087       596424 :         EEO_CASE(EEOP_AGG_PLAIN_PERGROUP_NULLCHECK)
    2088              :         {
    2089       596424 :             AggState   *aggstate = castNode(AggState, state->parent);
    2090       596424 :             AggStatePerGroup pergroup_allaggs =
    2091       596424 :                 aggstate->all_pergroups[op->d.agg_plain_pergroup_nullcheck.setoff];
    2092              : 
    2093       596424 :             if (pergroup_allaggs == NULL)
    2094       285060 :                 EEO_JUMP(op->d.agg_plain_pergroup_nullcheck.jumpnull);
    2095              : 
    2096       311364 :             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       821452 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
    2112              :         {
    2113       821452 :             AggState   *aggstate = castNode(AggState, state->parent);
    2114       821452 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2115       821452 :             AggStatePerGroup pergroup =
    2116       821452 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2117              : 
    2118              :             Assert(pertrans->transtypeByVal);
    2119              : 
    2120       821452 :             if (pergroup->noTransValue)
    2121              :             {
    2122              :                 /* If transValue has not yet been initialized, do so now. */
    2123         5135 :                 ExecAggInitGroup(aggstate, pertrans, pergroup,
    2124              :                                  op->d.agg_trans.aggcontext);
    2125              :                 /* copied trans value from input, done this round */
    2126              :             }
    2127       816317 :             else if (likely(!pergroup->transValueIsNull))
    2128              :             {
    2129              :                 /* invoke transition function, unless prevented by strictness */
    2130       816317 :                 ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    2131              :                                        op->d.agg_trans.aggcontext,
    2132              :                                        op->d.agg_trans.setno);
    2133              :             }
    2134              : 
    2135       821452 :             EEO_NEXT();
    2136              :         }
    2137              : 
    2138              :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2139      9816115 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL)
    2140              :         {
    2141      9816115 :             AggState   *aggstate = castNode(AggState, state->parent);
    2142      9816115 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2143      9816115 :             AggStatePerGroup pergroup =
    2144      9816115 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2145              : 
    2146              :             Assert(pertrans->transtypeByVal);
    2147              : 
    2148      9816115 :             if (likely(!pergroup->transValueIsNull))
    2149      9786106 :                 ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    2150              :                                        op->d.agg_trans.aggcontext,
    2151              :                                        op->d.agg_trans.setno);
    2152              : 
    2153      9816115 :             EEO_NEXT();
    2154              :         }
    2155              : 
    2156              :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2157      6018445 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)
    2158              :         {
    2159      6018445 :             AggState   *aggstate = castNode(AggState, state->parent);
    2160      6018445 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2161      6018445 :             AggStatePerGroup pergroup =
    2162      6018445 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2163              : 
    2164              :             Assert(pertrans->transtypeByVal);
    2165              : 
    2166      6018445 :             ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    2167              :                                    op->d.agg_trans.aggcontext,
    2168              :                                    op->d.agg_trans.setno);
    2169              : 
    2170      6018409 :             EEO_NEXT();
    2171              :         }
    2172              : 
    2173              :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2174        99047 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
    2175              :         {
    2176        99047 :             AggState   *aggstate = castNode(AggState, state->parent);
    2177        99047 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2178        99047 :             AggStatePerGroup pergroup =
    2179        99047 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2180              : 
    2181              :             Assert(!pertrans->transtypeByVal);
    2182              : 
    2183        99047 :             if (pergroup->noTransValue)
    2184          458 :                 ExecAggInitGroup(aggstate, pertrans, pergroup,
    2185              :                                  op->d.agg_trans.aggcontext);
    2186        98589 :             else if (likely(!pergroup->transValueIsNull))
    2187        98589 :                 ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    2188              :                                        op->d.agg_trans.aggcontext,
    2189              :                                        op->d.agg_trans.setno);
    2190              : 
    2191        99044 :             EEO_NEXT();
    2192              :         }
    2193              : 
    2194              :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2195      1338919 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
    2196              :         {
    2197      1338919 :             AggState   *aggstate = castNode(AggState, state->parent);
    2198      1338919 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2199      1338919 :             AggStatePerGroup pergroup =
    2200      1338919 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2201              : 
    2202              :             Assert(!pertrans->transtypeByVal);
    2203              : 
    2204      1338919 :             if (likely(!pergroup->transValueIsNull))
    2205      1338919 :                 ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    2206              :                                        op->d.agg_trans.aggcontext,
    2207              :                                        op->d.agg_trans.setno);
    2208      1338919 :             EEO_NEXT();
    2209              :         }
    2210              : 
    2211              :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    2212        12169 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF)
    2213              :         {
    2214        12169 :             AggState   *aggstate = castNode(AggState, state->parent);
    2215        12169 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    2216        12169 :             AggStatePerGroup pergroup =
    2217        12169 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    2218              : 
    2219              :             Assert(!pertrans->transtypeByVal);
    2220              : 
    2221        12169 :             ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    2222              :                                    op->d.agg_trans.aggcontext,
    2223              :                                    op->d.agg_trans.setno);
    2224              : 
    2225        12169 :             EEO_NEXT();
    2226              :         }
    2227              : 
    2228       182861 :         EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_SINGLE)
    2229              :         {
    2230       182861 :             AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
    2231       182861 :             AggState   *aggstate = castNode(AggState, state->parent);
    2232              : 
    2233       182861 :             if (ExecEvalPreOrderedDistinctSingle(aggstate, pertrans))
    2234        50976 :                 EEO_NEXT();
    2235              :             else
    2236       131885 :                 EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
    2237              :         }
    2238              : 
    2239          360 :         EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_MULTI)
    2240              :         {
    2241          360 :             AggState   *aggstate = castNode(AggState, state->parent);
    2242          360 :             AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
    2243              : 
    2244          360 :             if (ExecEvalPreOrderedDistinctMulti(aggstate, pertrans))
    2245          156 :                 EEO_NEXT();
    2246              :             else
    2247          204 :                 EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
    2248              :         }
    2249              : 
    2250              :         /* process single-column ordered aggregate datum */
    2251       422259 :         EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM)
    2252              :         {
    2253              :             /* too complex for an inline implementation */
    2254       422259 :             ExecEvalAggOrderedTransDatum(state, op, econtext);
    2255              : 
    2256       422259 :             EEO_NEXT();
    2257              :         }
    2258              : 
    2259              :         /* process multi-column ordered aggregate tuple */
    2260          108 :         EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE)
    2261              :         {
    2262              :             /* too complex for an inline implementation */
    2263          108 :             ExecEvalAggOrderedTransTuple(state, op, econtext);
    2264              : 
    2265          108 :             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       946719 : 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       946719 :     CheckExprStillValid(state, econtext);
    2294              : 
    2295              :     /* skip the check during further executions */
    2296       946707 :     state->evalfunc = (ExprStateEvalFunc) state->evalfunc_private;
    2297              : 
    2298              :     /* and actually execute */
    2299       946707 :     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       948672 : CheckExprStillValid(ExprState *state, ExprContext *econtext)
    2308              : {
    2309              :     TupleTableSlot *innerslot;
    2310              :     TupleTableSlot *outerslot;
    2311              :     TupleTableSlot *scanslot;
    2312              :     TupleTableSlot *oldslot;
    2313              :     TupleTableSlot *newslot;
    2314              : 
    2315       948672 :     innerslot = econtext->ecxt_innertuple;
    2316       948672 :     outerslot = econtext->ecxt_outertuple;
    2317       948672 :     scanslot = econtext->ecxt_scantuple;
    2318       948672 :     oldslot = econtext->ecxt_oldtuple;
    2319       948672 :     newslot = econtext->ecxt_newtuple;
    2320              : 
    2321      5294480 :     for (int i = 0; i < state->steps_len; i++)
    2322              :     {
    2323      4345820 :         ExprEvalStep *op = &state->steps[i];
    2324              : 
    2325      4345820 :         switch (ExecEvalStepOp(state, op))
    2326              :         {
    2327        49256 :             case EEOP_INNER_VAR:
    2328              :                 {
    2329        49256 :                     int         attnum = op->d.var.attnum;
    2330              : 
    2331        49256 :                     CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
    2332        49256 :                     break;
    2333              :                 }
    2334              : 
    2335       125618 :             case EEOP_OUTER_VAR:
    2336              :                 {
    2337       125618 :                     int         attnum = op->d.var.attnum;
    2338              : 
    2339       125618 :                     CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
    2340       125618 :                     break;
    2341              :                 }
    2342              : 
    2343       177521 :             case EEOP_SCAN_VAR:
    2344              :                 {
    2345       177521 :                     int         attnum = op->d.var.attnum;
    2346              : 
    2347       177521 :                     CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
    2348       177509 :                     break;
    2349              :                 }
    2350              : 
    2351           99 :             case EEOP_OLD_VAR:
    2352              :                 {
    2353           99 :                     int         attnum = op->d.var.attnum;
    2354              : 
    2355           99 :                     CheckVarSlotCompatibility(oldslot, attnum + 1, op->d.var.vartype);
    2356           99 :                     break;
    2357              :                 }
    2358              : 
    2359           99 :             case EEOP_NEW_VAR:
    2360              :                 {
    2361           99 :                     int         attnum = op->d.var.attnum;
    2362              : 
    2363           99 :                     CheckVarSlotCompatibility(newslot, attnum + 1, op->d.var.vartype);
    2364           99 :                     break;
    2365              :                 }
    2366      3993227 :             default:
    2367      3993227 :                 break;
    2368              :         }
    2369              :     }
    2370       948660 : }
    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       352593 : 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       352593 :     if (attnum > 0)
    2398              :     {
    2399       352593 :         TupleDesc   slot_tupdesc = slot->tts_tupleDescriptor;
    2400              :         Form_pg_attribute attr;
    2401              : 
    2402       352593 :         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       352593 :         attr = TupleDescAttr(slot_tupdesc, attnum - 1);
    2407              : 
    2408              :         /* Internal error: somebody forgot to expand it. */
    2409       352593 :         if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
    2410            0 :             elog(ERROR, "unexpected virtual generated column reference");
    2411              : 
    2412       352593 :         if (attr->attisdropped)
    2413            6 :             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       352587 :         if (vartype != attr->atttypid)
    2419            6 :             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       352581 : }
    2428              : 
    2429              : /*
    2430              :  * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
    2431              :  */
    2432              : static void
    2433     97970619 : 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     97970619 : }
    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       220352 : get_cached_rowtype(Oid type_id, int32 typmod,
    2481              :                    ExprEvalRowtypeCache *rowcache,
    2482              :                    bool *changed)
    2483              : {
    2484       220352 :     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        22210 :         TypeCacheEntry *typentry = (TypeCacheEntry *) rowcache->cacheptr;
    2494              : 
    2495        22210 :         if (unlikely(typentry == NULL ||
    2496              :                      rowcache->tupdesc_id == 0 ||
    2497              :                      typentry->tupDesc_identifier != rowcache->tupdesc_id))
    2498              :         {
    2499         3468 :             typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
    2500         3468 :             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         3468 :             rowcache->cacheptr = typentry;
    2506         3468 :             rowcache->tupdesc_id = typentry->tupDesc_identifier;
    2507         3468 :             if (changed)
    2508          494 :                 *changed = true;
    2509              :         }
    2510        22210 :         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       198142 :         TupleDesc   tupDesc = (TupleDesc) rowcache->cacheptr;
    2521              : 
    2522       198142 :         if (unlikely(tupDesc == NULL ||
    2523              :                      rowcache->tupdesc_id != 0 ||
    2524              :                      type_id != tupDesc->tdtypeid ||
    2525              :                      typmod != tupDesc->tdtypmod))
    2526              :         {
    2527         1146 :             tupDesc = lookup_rowtype_tupdesc(type_id, typmod);
    2528              :             /* Drop pin acquired by lookup_rowtype_tupdesc */
    2529         1146 :             ReleaseTupleDesc(tupDesc);
    2530         1146 :             rowcache->cacheptr = tupDesc;
    2531         1146 :             rowcache->tupdesc_id = 0;    /* not a valid value for non-RECORD */
    2532         1146 :             if (changed)
    2533            0 :                 *changed = true;
    2534              :         }
    2535       198142 :         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      3788042 : ExecJustVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2547              : {
    2548      3788042 :     ExprEvalStep *op = &state->steps[1];
    2549      3788042 :     int         attnum = op->d.var.attnum + 1;
    2550              : 
    2551      3788042 :     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      3788042 :     return slot_getattr(slot, attnum, isnull);
    2559              : }
    2560              : 
    2561              : /* Simple reference to inner Var */
    2562              : static Datum
    2563      2494541 : ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2564              : {
    2565      2494541 :     return ExecJustVarImpl(state, econtext->ecxt_innertuple, isnull);
    2566              : }
    2567              : 
    2568              : /* Simple reference to outer Var */
    2569              : static Datum
    2570      1292485 : ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2571              : {
    2572      1292485 :     return ExecJustVarImpl(state, econtext->ecxt_outertuple, isnull);
    2573              : }
    2574              : 
    2575              : /* Simple reference to scan Var */
    2576              : static Datum
    2577         1016 : ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2578              : {
    2579         1016 :     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      6999744 : ExecJustAssignVarImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
    2585              : {
    2586      6999744 :     ExprEvalStep *op = &state->steps[1];
    2587      6999744 :     int         attnum = op->d.assign_var.attnum + 1;
    2588      6999744 :     int         resultnum = op->d.assign_var.resultnum;
    2589      6999744 :     TupleTableSlot *outslot = state->resultslot;
    2590              : 
    2591      6999744 :     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     13999488 :     outslot->tts_values[resultnum] =
    2604      6999744 :         slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
    2605      6999744 :     return 0;
    2606              : }
    2607              : 
    2608              : /* Evaluate inner Var and assign to appropriate column of result tuple */
    2609              : static Datum
    2610        31943 : ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2611              : {
    2612        31943 :     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       561117 : ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2618              : {
    2619       561117 :     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      6406684 : ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2625              : {
    2626      6406684 :     return ExecJustAssignVarImpl(state, econtext->ecxt_scantuple, isnull);
    2627              : }
    2628              : 
    2629              : /* Evaluate CASE_TESTVAL and apply a strict function to it */
    2630              : static Datum
    2631       210820 : ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
    2632              : {
    2633       210820 :     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       210820 :     *op->resvalue = *op->d.casetest.value;
    2644       210820 :     *op->resnull = *op->d.casetest.isnull;
    2645              : 
    2646       210820 :     op++;
    2647              : 
    2648       210820 :     nargs = op->d.func.nargs;
    2649       210820 :     fcinfo = op->d.func.fcinfo_data;
    2650       210820 :     args = fcinfo->args;
    2651              : 
    2652              :     /* strict function, so check for NULL args */
    2653       421796 :     for (int argno = 0; argno < nargs; argno++)
    2654              :     {
    2655       210982 :         if (args[argno].isnull)
    2656              :         {
    2657            6 :             *isnull = true;
    2658            6 :             return (Datum) 0;
    2659              :         }
    2660              :     }
    2661       210814 :     fcinfo->isnull = false;
    2662       210814 :     d = op->d.func.fn_addr(fcinfo);
    2663       210805 :     *isnull = fcinfo->isnull;
    2664       210805 :     return d;
    2665              : }
    2666              : 
    2667              : /* Simple Const expression */
    2668              : static Datum
    2669      1124369 : ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
    2670              : {
    2671      1124369 :     ExprEvalStep *op = &state->steps[0];
    2672              : 
    2673      1124369 :     *isnull = op->d.constval.isnull;
    2674      1124369 :     return op->d.constval.value;
    2675              : }
    2676              : 
    2677              : /* implementation of ExecJust(Inner|Outer|Scan)VarVirt */
    2678              : static pg_attribute_always_inline Datum
    2679       801307 : ExecJustVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2680              : {
    2681       801307 :     ExprEvalStep *op = &state->steps[0];
    2682       801307 :     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       801307 :     *isnull = slot->tts_isnull[attnum];
    2695              : 
    2696       801307 :     return slot->tts_values[attnum];
    2697              : }
    2698              : 
    2699              : /* Like ExecJustInnerVar, optimized for virtual slots */
    2700              : static Datum
    2701       223925 : ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2702              : {
    2703       223925 :     return ExecJustVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2704              : }
    2705              : 
    2706              : /* Like ExecJustOuterVar, optimized for virtual slots */
    2707              : static Datum
    2708       577382 : ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2709              : {
    2710       577382 :     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       896953 : ExecJustAssignVarVirtImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
    2723              : {
    2724       896953 :     ExprEvalStep *op = &state->steps[0];
    2725       896953 :     int         attnum = op->d.assign_var.attnum;
    2726       896953 :     int         resultnum = op->d.assign_var.resultnum;
    2727       896953 :     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       896953 :     outslot->tts_values[resultnum] = inslot->tts_values[attnum];
    2737       896953 :     outslot->tts_isnull[resultnum] = inslot->tts_isnull[attnum];
    2738              : 
    2739       896953 :     return 0;
    2740              : }
    2741              : 
    2742              : /* Like ExecJustAssignInnerVar, optimized for virtual slots */
    2743              : static Datum
    2744        60641 : ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2745              : {
    2746        60641 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2747              : }
    2748              : 
    2749              : /* Like ExecJustAssignOuterVar, optimized for virtual slots */
    2750              : static Datum
    2751       790971 : ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2752              : {
    2753       790971 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
    2754              : }
    2755              : 
    2756              : /* Like ExecJustAssignScanVar, optimized for virtual slots */
    2757              : static Datum
    2758        45341 : ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2759              : {
    2760        45341 :     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      1158667 : ExecJustHashInnerVarWithIV(ExprState *state, ExprContext *econtext,
    2768              :                            bool *isnull)
    2769              : {
    2770      1158667 :     ExprEvalStep *fetchop = &state->steps[0];
    2771      1158667 :     ExprEvalStep *setivop = &state->steps[1];
    2772      1158667 :     ExprEvalStep *innervar = &state->steps[2];
    2773      1158667 :     ExprEvalStep *hashop = &state->steps[3];
    2774      1158667 :     FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
    2775      1158667 :     int         attnum = innervar->d.var.attnum;
    2776              :     uint32      hashkey;
    2777              : 
    2778      1158667 :     CheckOpSlotCompatibility(fetchop, econtext->ecxt_innertuple);
    2779      1158667 :     slot_getsomeattrs(econtext->ecxt_innertuple, fetchop->d.fetch.last_var);
    2780              : 
    2781      1158667 :     fcinfo->args[0].value = econtext->ecxt_innertuple->tts_values[attnum];
    2782      1158667 :     fcinfo->args[0].isnull = econtext->ecxt_innertuple->tts_isnull[attnum];
    2783              : 
    2784      1158667 :     hashkey = DatumGetUInt32(setivop->d.hashdatum_initvalue.init_value);
    2785      1158667 :     hashkey = pg_rotate_left32(hashkey, 1);
    2786              : 
    2787      1158667 :     if (!fcinfo->args[0].isnull)
    2788              :     {
    2789              :         uint32      hashvalue;
    2790              : 
    2791      1158217 :         hashvalue = DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
    2792      1158217 :         hashkey = hashkey ^ hashvalue;
    2793              :     }
    2794              : 
    2795      1158667 :     *isnull = false;
    2796      1158667 :     return UInt32GetDatum(hashkey);
    2797              : }
    2798              : 
    2799              : /* implementation of ExecJustHash(Inner|Outer)Var */
    2800              : static pg_attribute_always_inline Datum
    2801      1949482 : ExecJustHashVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2802              : {
    2803      1949482 :     ExprEvalStep *fetchop = &state->steps[0];
    2804      1949482 :     ExprEvalStep *var = &state->steps[1];
    2805      1949482 :     ExprEvalStep *hashop = &state->steps[2];
    2806      1949482 :     FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
    2807      1949482 :     int         attnum = var->d.var.attnum;
    2808              : 
    2809      1949482 :     CheckOpSlotCompatibility(fetchop, slot);
    2810      1949482 :     slot_getsomeattrs(slot, fetchop->d.fetch.last_var);
    2811              : 
    2812      1949482 :     fcinfo->args[0].value = slot->tts_values[attnum];
    2813      1949482 :     fcinfo->args[0].isnull = slot->tts_isnull[attnum];
    2814              : 
    2815      1949482 :     *isnull = false;
    2816              : 
    2817      1949482 :     if (!fcinfo->args[0].isnull)
    2818      1944913 :         return hashop->d.hashdatum.fn_addr(fcinfo);
    2819              :     else
    2820         4569 :         return (Datum) 0;
    2821              : }
    2822              : 
    2823              : /* implementation for hashing an outer Var */
    2824              : static Datum
    2825       649690 : ExecJustHashOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2826              : {
    2827       649690 :     return ExecJustHashVarImpl(state, econtext->ecxt_outertuple, isnull);
    2828              : }
    2829              : 
    2830              : /* implementation for hashing an inner Var */
    2831              : static Datum
    2832      1299792 : ExecJustHashInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2833              : {
    2834      1299792 :     return ExecJustHashVarImpl(state, econtext->ecxt_innertuple, isnull);
    2835              : }
    2836              : 
    2837              : /* implementation of ExecJustHash(Inner|Outer)VarVirt */
    2838              : static pg_attribute_always_inline Datum
    2839      2645223 : ExecJustHashVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2840              : {
    2841      2645223 :     ExprEvalStep *var = &state->steps[0];
    2842      2645223 :     ExprEvalStep *hashop = &state->steps[1];
    2843      2645223 :     FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
    2844      2645223 :     int         attnum = var->d.var.attnum;
    2845              : 
    2846      2645223 :     fcinfo->args[0].value = slot->tts_values[attnum];
    2847      2645223 :     fcinfo->args[0].isnull = slot->tts_isnull[attnum];
    2848              : 
    2849      2645223 :     *isnull = false;
    2850              : 
    2851      2645223 :     if (!fcinfo->args[0].isnull)
    2852      2643349 :         return hashop->d.hashdatum.fn_addr(fcinfo);
    2853              :     else
    2854         1874 :         return (Datum) 0;
    2855              : }
    2856              : 
    2857              : /* Like ExecJustHashInnerVar, optimized for virtual slots */
    2858              : static Datum
    2859       670715 : ExecJustHashInnerVarVirt(ExprState *state, ExprContext *econtext,
    2860              :                          bool *isnull)
    2861              : {
    2862       670715 :     return ExecJustHashVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2863              : }
    2864              : 
    2865              : /* Like ExecJustHashOuterVar, optimized for virtual slots */
    2866              : static Datum
    2867      1974508 : ExecJustHashOuterVarVirt(ExprState *state, ExprContext *econtext,
    2868              :                          bool *isnull)
    2869              : {
    2870      1974508 :     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      4384212 : ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext,
    2878              :                            bool *isnull)
    2879              : {
    2880      4384212 :     ExprEvalStep *fetchop = &state->steps[0];
    2881      4384212 :     ExprEvalStep *var = &state->steps[1];
    2882      4384212 :     ExprEvalStep *hashop = &state->steps[2];
    2883      4384212 :     FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
    2884      4384212 :     int         attnum = var->d.var.attnum;
    2885              : 
    2886      4384212 :     CheckOpSlotCompatibility(fetchop, econtext->ecxt_outertuple);
    2887      4384212 :     slot_getsomeattrs(econtext->ecxt_outertuple, fetchop->d.fetch.last_var);
    2888              : 
    2889      4384212 :     fcinfo->args[0].value = econtext->ecxt_outertuple->tts_values[attnum];
    2890      4384212 :     fcinfo->args[0].isnull = econtext->ecxt_outertuple->tts_isnull[attnum];
    2891              : 
    2892      4384212 :     if (!fcinfo->args[0].isnull)
    2893              :     {
    2894      4384063 :         *isnull = false;
    2895      4384063 :         return hashop->d.hashdatum.fn_addr(fcinfo);
    2896              :     }
    2897              :     else
    2898              :     {
    2899              :         /* return NULL on NULL input */
    2900          149 :         *isnull = true;
    2901          149 :         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     29521471 : dispatch_compare_ptr(const void *a, const void *b)
    2912              : {
    2913     29521471 :     const ExprEvalOpLookup *la = (const ExprEvalOpLookup *) a;
    2914     29521471 :     const ExprEvalOpLookup *lb = (const ExprEvalOpLookup *) b;
    2915              : 
    2916     29521471 :     if (la->opcode < lb->opcode)
    2917     17905369 :         return -1;
    2918     11616102 :     else if (la->opcode > lb->opcode)
    2919      7825905 :         return 1;
    2920      3790197 :     return 0;
    2921              : }
    2922              : #endif
    2923              : 
    2924              : /*
    2925              :  * Do one-time initialization of interpretation machinery.
    2926              :  */
    2927              : static void
    2928      1254126 : ExecInitInterpreter(void)
    2929              : {
    2930              : #if defined(EEO_USE_COMPUTED_GOTO)
    2931              :     /* Set up externally-visible pointer to dispatch table */
    2932      1254126 :     if (dispatch_table == NULL)
    2933              :     {
    2934        11981 :         dispatch_table = (const void **)
    2935        11981 :             DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
    2936              : 
    2937              :         /* build reverse lookup table */
    2938      1449701 :         for (int i = 0; i < EEOP_LAST; i++)
    2939              :         {
    2940      1437720 :             reverse_dispatch_table[i].opcode = dispatch_table[i];
    2941      1437720 :             reverse_dispatch_table[i].op = (ExprEvalOp) i;
    2942              :         }
    2943              : 
    2944              :         /* make it bsearch()able */
    2945        11981 :         qsort(reverse_dispatch_table,
    2946              :               EEOP_LAST /* nmembers */ ,
    2947              :               sizeof(ExprEvalOpLookup),
    2948              :               dispatch_compare_ptr);
    2949              :     }
    2950              : #endif
    2951      1254126 : }
    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      4366318 : ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
    2961              : {
    2962              : #if defined(EEO_USE_COMPUTED_GOTO)
    2963      4366318 :     if (state->flags & EEO_FLAG_DIRECT_THREADED)
    2964              :     {
    2965              :         ExprEvalOpLookup key;
    2966              :         ExprEvalOpLookup *res;
    2967              : 
    2968      3790197 :         key.opcode = (void *) op->opcode;
    2969      3790197 :         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      3790197 :         return res->op;
    2976              :     }
    2977              : #endif
    2978       576121 :     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          104 : ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op,
    2991              :                        ExprContext *econtext)
    2992              : {
    2993          104 :     FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    2994              :     PgStat_FunctionCallUsage fcusage;
    2995              :     Datum       d;
    2996              : 
    2997          104 :     pgstat_init_function_usage(fcinfo, &fcusage);
    2998              : 
    2999          104 :     fcinfo->isnull = false;
    3000          104 :     d = op->d.func.fn_addr(fcinfo);
    3001          104 :     *op->resvalue = d;
    3002          104 :     *op->resnull = fcinfo->isnull;
    3003              : 
    3004          104 :     pgstat_end_function_usage(&fcusage, true);
    3005          104 : }
    3006              : 
    3007              : /*
    3008              :  * Evaluate EEOP_FUNCEXPR_STRICT_FUSAGE
    3009              :  */
    3010              : void
    3011            3 : ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
    3012              :                              ExprContext *econtext)
    3013              : {
    3014              : 
    3015            3 :     FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    3016              :     PgStat_FunctionCallUsage fcusage;
    3017            3 :     NullableDatum *args = fcinfo->args;
    3018            3 :     int         nargs = op->d.func.nargs;
    3019              :     Datum       d;
    3020              : 
    3021              :     /* strict function, so check for NULL args */
    3022            9 :     for (int argno = 0; argno < nargs; argno++)
    3023              :     {
    3024            6 :         if (args[argno].isnull)
    3025              :         {
    3026            0 :             *op->resnull = true;
    3027            0 :             return;
    3028              :         }
    3029              :     }
    3030              : 
    3031            3 :     pgstat_init_function_usage(fcinfo, &fcusage);
    3032              : 
    3033            3 :     fcinfo->isnull = false;
    3034            3 :     d = op->d.func.fn_addr(fcinfo);
    3035            3 :     *op->resvalue = d;
    3036            3 :     *op->resnull = fcinfo->isnull;
    3037              : 
    3038            3 :     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      3988025 : ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3049              : {
    3050              :     ParamExecData *prm;
    3051              : 
    3052      3988025 :     prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
    3053      3988025 :     if (unlikely(prm->execPlan != NULL))
    3054              :     {
    3055              :         /* Parameter not evaluated yet, so go do it */
    3056         4843 :         ExecSetParamPlan(prm->execPlan, econtext);
    3057              :         /* ExecSetParamPlan should have processed this param... */
    3058              :         Assert(prm->execPlan == NULL);
    3059              :     }
    3060      3988016 :     *op->resvalue = prm->value;
    3061      3988016 :     *op->resnull = prm->isnull;
    3062      3988016 : }
    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       202651 : ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3071              : {
    3072       202651 :     ParamListInfo paramInfo = econtext->ecxt_param_list_info;
    3073       202651 :     int         paramId = op->d.param.paramid;
    3074              : 
    3075       202651 :     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       202651 :         if (paramInfo->paramFetch != NULL)
    3083           93 :             prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata);
    3084              :         else
    3085       202558 :             prm = &paramInfo->params[paramId - 1];
    3086              : 
    3087       202651 :         if (likely(OidIsValid(prm->ptype)))
    3088              :         {
    3089              :             /* safety check in case hook did something unexpected */
    3090       202651 :             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       202651 :             *op->resvalue = prm->value;
    3098       202651 :             *op->resnull = prm->isnull;
    3099       202651 :             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              :  * op->res{value,null}.
    3111              :  */
    3112              : void
    3113       872129 : ExecEvalParamSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3114              : {
    3115              :     ParamExecData *prm;
    3116              : 
    3117       872129 :     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       872129 :     prm->value = *op->resvalue;
    3123       872129 :     prm->isnull = *op->resnull;
    3124       872129 : }
    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         9717 : ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
    3196              : {
    3197         9717 :     LOCAL_FCINFO(fcinfo, 0);
    3198         9717 :     SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
    3199              : 
    3200         9717 :     *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         9717 :     switch (svf->op)
    3207              :     {
    3208           25 :         case SVFOP_CURRENT_DATE:
    3209           25 :             *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
    3210           25 :             break;
    3211           12 :         case SVFOP_CURRENT_TIME:
    3212              :         case SVFOP_CURRENT_TIME_N:
    3213           12 :             *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
    3214           12 :             break;
    3215          173 :         case SVFOP_CURRENT_TIMESTAMP:
    3216              :         case SVFOP_CURRENT_TIMESTAMP_N:
    3217          173 :             *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
    3218          173 :             break;
    3219           12 :         case SVFOP_LOCALTIME:
    3220              :         case SVFOP_LOCALTIME_N:
    3221           12 :             *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
    3222           12 :             break;
    3223           33 :         case SVFOP_LOCALTIMESTAMP:
    3224              :         case SVFOP_LOCALTIMESTAMP_N:
    3225           33 :             *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
    3226           33 :             break;
    3227         9130 :         case SVFOP_CURRENT_ROLE:
    3228              :         case SVFOP_CURRENT_USER:
    3229              :         case SVFOP_USER:
    3230         9130 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    3231         9130 :             *op->resvalue = current_user(fcinfo);
    3232         9130 :             *op->resnull = fcinfo->isnull;
    3233         9130 :             break;
    3234          300 :         case SVFOP_SESSION_USER:
    3235          300 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    3236          300 :             *op->resvalue = session_user(fcinfo);
    3237          300 :             *op->resnull = fcinfo->isnull;
    3238          300 :             break;
    3239           23 :         case SVFOP_CURRENT_CATALOG:
    3240           23 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    3241           23 :             *op->resvalue = current_database(fcinfo);
    3242           23 :             *op->resnull = fcinfo->isnull;
    3243           23 :             break;
    3244            9 :         case SVFOP_CURRENT_SCHEMA:
    3245            9 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    3246            9 :             *op->resvalue = current_schema(fcinfo);
    3247            9 :             *op->resnull = fcinfo->isnull;
    3248            9 :             break;
    3249              :     }
    3250         9717 : }
    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            1 : ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
    3263              : {
    3264            1 :     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          517 : ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
    3274              : {
    3275          517 :     int64       newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
    3276              : 
    3277          517 :     switch (op->d.nextvalueexpr.seqtypid)
    3278              :     {
    3279           15 :         case INT2OID:
    3280           15 :             *op->resvalue = Int16GetDatum((int16) newval);
    3281           15 :             break;
    3282          463 :         case INT4OID:
    3283          463 :             *op->resvalue = Int32GetDatum((int32) newval);
    3284          463 :             break;
    3285           39 :         case INT8OID:
    3286           39 :             *op->resvalue = Int64GetDatum(newval);
    3287           39 :             break;
    3288            0 :         default:
    3289            0 :             elog(ERROR, "unsupported sequence type %u",
    3290              :                  op->d.nextvalueexpr.seqtypid);
    3291              :     }
    3292          517 :     *op->resnull = false;
    3293          517 : }
    3294              : 
    3295              : /*
    3296              :  * Evaluate NullTest / IS NULL for rows.
    3297              :  */
    3298              : void
    3299          348 : ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3300              : {
    3301          348 :     ExecEvalRowNullInt(state, op, econtext, true);
    3302          348 : }
    3303              : 
    3304              : /*
    3305              :  * Evaluate NullTest / IS NOT NULL for rows.
    3306              :  */
    3307              : void
    3308          285 : ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3309              : {
    3310          285 :     ExecEvalRowNullInt(state, op, econtext, false);
    3311          285 : }
    3312              : 
    3313              : /* Common code for IS [NOT] NULL on a row value */
    3314              : static void
    3315          633 : ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
    3316              :                    ExprContext *econtext, bool checkisnull)
    3317              : {
    3318          633 :     Datum       value = *op->resvalue;
    3319          633 :     bool        isnull = *op->resnull;
    3320              :     HeapTupleHeader tuple;
    3321              :     Oid         tupType;
    3322              :     int32       tupTypmod;
    3323              :     TupleDesc   tupDesc;
    3324              :     HeapTupleData tmptup;
    3325              : 
    3326          633 :     *op->resnull = false;
    3327              : 
    3328              :     /* NULL row variables are treated just as NULL scalar columns */
    3329          633 :     if (isnull)
    3330              :     {
    3331           78 :         *op->resvalue = BoolGetDatum(checkisnull);
    3332          374 :         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          555 :     tuple = DatumGetHeapTupleHeader(value);
    3352              : 
    3353          555 :     tupType = HeapTupleHeaderGetTypeId(tuple);
    3354          555 :     tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    3355              : 
    3356              :     /* Lookup tupdesc if first time through or if type changes */
    3357          555 :     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          555 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3364          555 :     tmptup.t_data = tuple;
    3365              : 
    3366         1337 :     for (int att = 1; att <= tupDesc->natts; att++)
    3367              :     {
    3368              :         /* ignore dropped columns */
    3369         1078 :         if (TupleDescCompactAttr(tupDesc, att - 1)->attisdropped)
    3370            0 :             continue;
    3371         1078 :         if (heap_attisnull(&tmptup, att, tupDesc))
    3372              :         {
    3373              :             /* null field disproves IS NOT NULL */
    3374           31 :             if (!checkisnull)
    3375              :             {
    3376           19 :                 *op->resvalue = BoolGetDatum(false);
    3377           19 :                 return;
    3378              :             }
    3379              :         }
    3380              :         else
    3381              :         {
    3382              :             /* non-null field disproves IS NULL */
    3383         1047 :             if (checkisnull)
    3384              :             {
    3385          277 :                 *op->resvalue = BoolGetDatum(false);
    3386          277 :                 return;
    3387              :             }
    3388              :         }
    3389              :     }
    3390              : 
    3391          259 :     *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       412446 : ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
    3402              : {
    3403              :     ArrayType  *result;
    3404       412446 :     Oid         element_type = op->d.arrayexpr.elemtype;
    3405       412446 :     int         nelems = op->d.arrayexpr.nelems;
    3406       412446 :     int         ndims = 0;
    3407              :     int         dims[MAXDIM];
    3408              :     int         lbs[MAXDIM];
    3409              : 
    3410              :     /* Set non-null as default */
    3411       412446 :     *op->resnull = false;
    3412              : 
    3413       412446 :     if (!op->d.arrayexpr.multidims)
    3414              :     {
    3415              :         /* Elements are presumably of scalar type */
    3416       412203 :         Datum      *dvalues = op->d.arrayexpr.elemvalues;
    3417       412203 :         bool       *dnulls = op->d.arrayexpr.elemnulls;
    3418              : 
    3419              :         /* setup for 1-D array of the given length */
    3420       412203 :         ndims = 1;
    3421       412203 :         dims[0] = nelems;
    3422       412203 :         lbs[0] = 1;
    3423              : 
    3424       412203 :         result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
    3425              :                                     element_type,
    3426       412203 :                                     op->d.arrayexpr.elemlength,
    3427       412203 :                                     op->d.arrayexpr.elembyval,
    3428       412203 :                                     op->d.arrayexpr.elemalign);
    3429              :     }
    3430              :     else
    3431              :     {
    3432              :         /* Must be nested array expressions */
    3433          243 :         int         nbytes = 0;
    3434              :         int         nitems;
    3435          243 :         int         outer_nelems = 0;
    3436          243 :         int         elem_ndims = 0;
    3437          243 :         int        *elem_dims = NULL;
    3438          243 :         int        *elem_lbs = NULL;
    3439          243 :         bool        firstone = true;
    3440          243 :         bool        havenulls = false;
    3441          243 :         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          243 :         subdata = (char **) palloc(nelems * sizeof(char *));
    3451          243 :         subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *));
    3452          243 :         subbytes = (int *) palloc(nelems * sizeof(int));
    3453          243 :         subnitems = (int *) palloc(nelems * sizeof(int));
    3454              : 
    3455              :         /* loop through and get data area from each element */
    3456          684 :         for (int elemoff = 0; elemoff < nelems; elemoff++)
    3457              :         {
    3458              :             Datum       arraydatum;
    3459              :             bool        eisnull;
    3460              :             ArrayType  *array;
    3461              :             int         this_ndims;
    3462              : 
    3463          441 :             arraydatum = op->d.arrayexpr.elemvalues[elemoff];
    3464          441 :             eisnull = op->d.arrayexpr.elemnulls[elemoff];
    3465              : 
    3466              :             /* temporarily ignore null subarrays */
    3467          441 :             if (eisnull)
    3468              :             {
    3469            0 :                 haveempty = true;
    3470            0 :                 continue;
    3471              :             }
    3472              : 
    3473          441 :             array = DatumGetArrayTypeP(arraydatum);
    3474              : 
    3475              :             /* run-time double-check on element type */
    3476          441 :             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          441 :             this_ndims = ARR_NDIM(array);
    3486              :             /* temporarily ignore zero-dimensional subarrays */
    3487          441 :             if (this_ndims <= 0)
    3488              :             {
    3489            0 :                 haveempty = true;
    3490            0 :                 continue;
    3491              :             }
    3492              : 
    3493          441 :             if (firstone)
    3494              :             {
    3495              :                 /* Get sub-array details from first member */
    3496          243 :                 elem_ndims = this_ndims;
    3497          243 :                 ndims = elem_ndims + 1;
    3498          243 :                 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          243 :                 elem_dims = (int *) palloc(elem_ndims * sizeof(int));
    3505          243 :                 memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
    3506          243 :                 elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
    3507          243 :                 memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
    3508              : 
    3509          243 :                 firstone = false;
    3510              :             }
    3511              :             else
    3512              :             {
    3513              :                 /* Check other sub-arrays are compatible */
    3514          198 :                 if (elem_ndims != this_ndims ||
    3515          198 :                     memcmp(elem_dims, ARR_DIMS(array),
    3516          198 :                            elem_ndims * sizeof(int)) != 0 ||
    3517          198 :                     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          441 :             subdata[outer_nelems] = ARR_DATA_PTR(array);
    3526          441 :             subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
    3527          441 :             subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
    3528          441 :             nbytes += subbytes[outer_nelems];
    3529              :             /* check for overflow of total request */
    3530          441 :             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          441 :             subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
    3536              :                                                      ARR_DIMS(array));
    3537          441 :             havenulls |= ARR_HASNULL(array);
    3538          441 :             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          243 :         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          243 :         dims[0] = outer_nelems;
    3562          243 :         lbs[0] = 1;
    3563          602 :         for (int i = 1; i < ndims; i++)
    3564              :         {
    3565          359 :             dims[i] = elem_dims[i - 1];
    3566          359 :             lbs[i] = elem_lbs[i - 1];
    3567              :         }
    3568              : 
    3569              :         /* check for subscript overflow */
    3570          243 :         nitems = ArrayGetNItems(ndims, dims);
    3571          243 :         ArrayCheckBounds(ndims, dims, lbs);
    3572              : 
    3573          243 :         if (havenulls)
    3574              :         {
    3575           15 :             dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
    3576           15 :             nbytes += dataoffset;
    3577              :         }
    3578              :         else
    3579              :         {
    3580          228 :             dataoffset = 0;     /* marker for no null bitmap */
    3581          228 :             nbytes += ARR_OVERHEAD_NONULLS(ndims);
    3582              :         }
    3583              : 
    3584          243 :         result = (ArrayType *) palloc0(nbytes);
    3585          243 :         SET_VARSIZE(result, nbytes);
    3586          243 :         result->ndim = ndims;
    3587          243 :         result->dataoffset = dataoffset;
    3588          243 :         result->elemtype = element_type;
    3589          243 :         memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
    3590          243 :         memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
    3591              : 
    3592          243 :         dat = ARR_DATA_PTR(result);
    3593          243 :         iitem = 0;
    3594          684 :         for (int i = 0; i < outer_nelems; i++)
    3595              :         {
    3596          441 :             memcpy(dat, subdata[i], subbytes[i]);
    3597          441 :             dat += subbytes[i];
    3598          441 :             if (havenulls)
    3599           30 :                 array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
    3600           30 :                                   subbitmaps[i], 0,
    3601           30 :                                   subnitems[i]);
    3602          441 :             iitem += subnitems[i];
    3603              :         }
    3604              :     }
    3605              : 
    3606       412446 :     *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        54810 : ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3616              : {
    3617              :     Datum       arraydatum;
    3618              : 
    3619              :     /* NULL array -> NULL result */
    3620        54810 :     if (*op->resnull)
    3621          160 :         return;
    3622              : 
    3623        54650 :     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        54650 :     if (op->d.arraycoerce.elemexprstate == NULL)
    3630              :     {
    3631              :         /* Detoast input array if necessary, and copy in any case */
    3632        34127 :         ArrayType  *array = DatumGetArrayTypePCopy(arraydatum);
    3633              : 
    3634        34127 :         ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
    3635        34127 :         *op->resvalue = PointerGetDatum(array);
    3636        34127 :         return;
    3637              :     }
    3638              : 
    3639              :     /*
    3640              :      * Use array_map to apply the sub-expression to each array element.
    3641              :      */
    3642        20507 :     *op->resvalue = array_map(arraydatum,
    3643              :                               op->d.arraycoerce.elemexprstate,
    3644              :                               econtext,
    3645              :                               op->d.arraycoerce.resultelemtype,
    3646        20523 :                               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        29079 : ExecEvalRow(ExprState *state, ExprEvalStep *op)
    3657              : {
    3658              :     HeapTuple   tuple;
    3659              : 
    3660              :     /* build tuple from evaluated field values */
    3661        29079 :     tuple = heap_form_tuple(op->d.row.tupdesc,
    3662        29079 :                             op->d.row.elemvalues,
    3663        29079 :                             op->d.row.elemnulls);
    3664              : 
    3665        29079 :     *op->resvalue = HeapTupleGetDatum(tuple);
    3666        29079 :     *op->resnull = false;
    3667        29079 : }
    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        11644 : ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
    3677              : {
    3678        11644 :     Datum      *values = op->d.minmax.values;
    3679        11644 :     bool       *nulls = op->d.minmax.nulls;
    3680        11644 :     FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
    3681        11644 :     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        11644 :     *op->resnull = true;
    3689              : 
    3690        35079 :     for (int off = 0; off < op->d.minmax.nelems; off++)
    3691              :     {
    3692              :         /* ignore NULL inputs */
    3693        23435 :         if (nulls[off])
    3694           62 :             continue;
    3695              : 
    3696        23373 :         if (*op->resnull)
    3697              :         {
    3698              :             /* first nonnull input, adopt value */
    3699        11644 :             *op->resvalue = values[off];
    3700        11644 :             *op->resnull = false;
    3701              :         }
    3702              :         else
    3703              :         {
    3704              :             int         cmpresult;
    3705              : 
    3706              :             /* apply comparison function */
    3707        11729 :             fcinfo->args[0].value = *op->resvalue;
    3708        11729 :             fcinfo->args[1].value = values[off];
    3709              : 
    3710        11729 :             fcinfo->isnull = false;
    3711        11729 :             cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
    3712        11729 :             if (fcinfo->isnull) /* probably should not happen */
    3713            0 :                 continue;
    3714              : 
    3715        11729 :             if (cmpresult > 0 && operator == IS_LEAST)
    3716           75 :                 *op->resvalue = values[off];
    3717        11654 :             else if (cmpresult < 0 && operator == IS_GREATEST)
    3718           95 :                 *op->resvalue = values[off];
    3719              :         }
    3720              :     }
    3721        11644 : }
    3722              : 
    3723              : /*
    3724              :  * Evaluate a FieldSelect node.
    3725              :  *
    3726              :  * Source record is in step's result variable.
    3727              :  */
    3728              : void
    3729       207605 : ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3730              : {
    3731       207605 :     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       207605 :     if (*op->resnull)
    3742           99 :         return;
    3743              : 
    3744       207506 :     tupDatum = *op->resvalue;
    3745              : 
    3746              :     /* We can special-case expanded records for speed */
    3747       207506 :     if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(tupDatum)))
    3748              :     {
    3749          331 :         ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(tupDatum);
    3750              : 
    3751              :         Assert(erh->er_magic == ER_MAGIC);
    3752              : 
    3753              :         /* Extract record's TupleDesc */
    3754          331 :         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          331 :         if (fieldnum <= 0)       /* should never happen */
    3762            0 :             elog(ERROR, "unsupported reference to system column %d in FieldSelect",
    3763              :                  fieldnum);
    3764          331 :         if (fieldnum > tupDesc->natts)    /* should never happen */
    3765            0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    3766              :                  fieldnum, tupDesc->natts);
    3767          331 :         attr = TupleDescAttr(tupDesc, fieldnum - 1);
    3768              : 
    3769              :         /* Check for dropped column, and force a NULL result if so */
    3770          331 :         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          331 :         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          331 :         *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       207175 :         tuple = DatumGetHeapTupleHeader(tupDatum);
    3794              : 
    3795       207175 :         tupType = HeapTupleHeaderGetTypeId(tuple);
    3796       207175 :         tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    3797              : 
    3798              :         /* Lookup tupdesc if first time through or if type changes */
    3799       207175 :         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       207175 :         if (fieldnum <= 0)       /* should never happen */
    3808            0 :             elog(ERROR, "unsupported reference to system column %d in FieldSelect",
    3809              :                  fieldnum);
    3810       207175 :         if (fieldnum > tupDesc->natts)    /* should never happen */
    3811            0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    3812              :                  fieldnum, tupDesc->natts);
    3813       207175 :         attr = TupleDescAttr(tupDesc, fieldnum - 1);
    3814              : 
    3815              :         /* Check for dropped column, and force a NULL result if so */
    3816       207175 :         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       207175 :         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       207175 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3834       207175 :         tmptup.t_data = tuple;
    3835              : 
    3836              :         /* extract the field */
    3837       207175 :         *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          260 : ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3855              : {
    3856          260 :     if (*op->resnull)
    3857              :     {
    3858              :         /* Convert null input tuple into an all-nulls row */
    3859          128 :         memset(op->d.fieldstore.nulls, true,
    3860          128 :                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          132 :         Datum       tupDatum = *op->resvalue;
    3869              :         HeapTupleHeader tuphdr;
    3870              :         HeapTupleData tmptup;
    3871              :         TupleDesc   tupDesc;
    3872              : 
    3873          132 :         tuphdr = DatumGetHeapTupleHeader(tupDatum);
    3874          132 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
    3875          132 :         ItemPointerSetInvalid(&(tmptup.t_self));
    3876          132 :         tmptup.t_tableOid = InvalidOid;
    3877          132 :         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          132 :         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          132 :         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          132 :         heap_deform_tuple(&tmptup, tupDesc,
    3894              :                           op->d.fieldstore.values,
    3895              :                           op->d.fieldstore.nulls);
    3896              :     }
    3897          260 : }
    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          260 : ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3905              : {
    3906              :     TupleDesc   tupDesc;
    3907              :     HeapTuple   tuple;
    3908              : 
    3909              :     /* Lookup tupdesc (should be valid already) */
    3910          260 :     tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
    3911              :                                  op->d.fieldstore.rowcache, NULL);
    3912              : 
    3913          260 :     tuple = heap_form_tuple(tupDesc,
    3914          260 :                             op->d.fieldstore.values,
    3915          260 :                             op->d.fieldstore.nulls);
    3916              : 
    3917          260 :     *op->resvalue = HeapTupleGetDatum(tuple);
    3918          260 :     *op->resnull = false;
    3919          260 : }
    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         6137 : 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         6137 :     bool        changed = false;
    3937              : 
    3938              :     /* NULL in -> NULL out */
    3939         6137 :     if (*op->resnull)
    3940           22 :         return;
    3941              : 
    3942         6115 :     tupDatum = *op->resvalue;
    3943         6115 :     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         6115 :     indesc = get_cached_rowtype(op->d.convert_rowtype.inputtype, -1,
    3951              :                                 op->d.convert_rowtype.incache,
    3952              :                                 &changed);
    3953         6115 :     IncrTupleDescRefCount(indesc);
    3954         6115 :     outdesc = get_cached_rowtype(op->d.convert_rowtype.outputtype, -1,
    3955              :                                  op->d.convert_rowtype.outcache,
    3956              :                                  &changed);
    3957         6115 :     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         6115 :     if (changed)
    3970              :     {
    3971              :         MemoryContext old_cxt;
    3972              : 
    3973              :         /* allocate map in long-lived memory context */
    3974          247 :         old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    3975              : 
    3976              :         /* prepare map from old to new attribute numbers */
    3977          247 :         op->d.convert_rowtype.map = convert_tuples_by_name(indesc, outdesc);
    3978              : 
    3979          247 :         MemoryContextSwitchTo(old_cxt);
    3980              :     }
    3981              : 
    3982              :     /* Following steps need a HeapTuple not a bare HeapTupleHeader */
    3983         6115 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3984         6115 :     tmptup.t_data = tuple;
    3985              : 
    3986         6115 :     if (op->d.convert_rowtype.map != NULL)
    3987              :     {
    3988              :         /* Full conversion with attribute rearrangement needed */
    3989          293 :         result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
    3990              :         /* Result already has appropriate composite-datum header fields */
    3991          293 :         *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         5822 :         *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
    4006              :     }
    4007              : 
    4008         6115 :     DecrTupleDescRefCount(indesc);
    4009         6115 :     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      2484554 : ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
    4024              : {
    4025      2484554 :     FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
    4026      2484554 :     bool        useOr = op->d.scalararrayop.useOr;
    4027      2484554 :     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              :     uint8       typalignby;
    4036              :     char       *s;
    4037              :     bits8      *bitmap;
    4038              :     int         bitmask;
    4039              : 
    4040              :     /*
    4041              :      * If the array is NULL then we return NULL --- it's not very meaningful
    4042              :      * to do anything else, even if the operator isn't strict.
    4043              :      */
    4044      2484554 :     if (*op->resnull)
    4045        97669 :         return;
    4046              : 
    4047              :     /* Else okay to fetch and detoast the array */
    4048      2386885 :     arr = DatumGetArrayTypeP(*op->resvalue);
    4049              : 
    4050              :     /*
    4051              :      * If the array is empty, we return either FALSE or TRUE per the useOr
    4052              :      * flag.  This is correct even if the scalar is NULL; since we would
    4053              :      * evaluate the operator zero times, it matters not whether it would want
    4054              :      * to return NULL.
    4055              :      */
    4056      2386885 :     nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    4057      2386885 :     if (nitems <= 0)
    4058              :     {
    4059         6511 :         *op->resvalue = BoolGetDatum(!useOr);
    4060         6511 :         *op->resnull = false;
    4061         6511 :         return;
    4062              :     }
    4063              : 
    4064              :     /*
    4065              :      * If the scalar is NULL, and the function is strict, return NULL; no
    4066              :      * point in iterating the loop.
    4067              :      */
    4068      2380374 :     if (fcinfo->args[0].isnull && strictfunc)
    4069              :     {
    4070          496 :         *op->resnull = true;
    4071          496 :         return;
    4072              :     }
    4073              : 
    4074              :     /*
    4075              :      * We arrange to look up info about the element type only once per series
    4076              :      * of calls, assuming the element type doesn't change underneath us.
    4077              :      */
    4078      2379878 :     if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
    4079              :     {
    4080         8598 :         get_typlenbyvalalign(ARR_ELEMTYPE(arr),
    4081              :                              &op->d.scalararrayop.typlen,
    4082              :                              &op->d.scalararrayop.typbyval,
    4083              :                              &op->d.scalararrayop.typalign);
    4084         8598 :         op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
    4085              :     }
    4086              : 
    4087      2379878 :     typlen = op->d.scalararrayop.typlen;
    4088      2379878 :     typbyval = op->d.scalararrayop.typbyval;
    4089      2379878 :     typalign = op->d.scalararrayop.typalign;
    4090      2379878 :     typalignby = typalign_to_alignby(typalign);
    4091              : 
    4092              :     /* Initialize result appropriately depending on useOr */
    4093      2379878 :     result = BoolGetDatum(!useOr);
    4094      2379878 :     resultnull = false;
    4095              : 
    4096              :     /* Loop over the array elements */
    4097      2379878 :     s = (char *) ARR_DATA_PTR(arr);
    4098      2379878 :     bitmap = ARR_NULLBITMAP(arr);
    4099      2379878 :     bitmask = 1;
    4100              : 
    4101      6166185 :     for (int i = 0; i < nitems; i++)
    4102              :     {
    4103              :         Datum       elt;
    4104              :         Datum       thisresult;
    4105              : 
    4106              :         /* Get array element, checking for NULL */
    4107      4959244 :         if (bitmap && (*bitmap & bitmask) == 0)
    4108              :         {
    4109       107632 :             fcinfo->args[1].value = (Datum) 0;
    4110       107632 :             fcinfo->args[1].isnull = true;
    4111              :         }
    4112              :         else
    4113              :         {
    4114      4851612 :             elt = fetch_att(s, typbyval, typlen);
    4115      4851612 :             s = att_addlength_pointer(s, typlen, s);
    4116      4851612 :             s = (char *) att_nominal_alignby(s, typalignby);
    4117      4851612 :             fcinfo->args[1].value = elt;
    4118      4851612 :             fcinfo->args[1].isnull = false;
    4119              :         }
    4120              : 
    4121              :         /* Call comparison function */
    4122      4959244 :         if (fcinfo->args[1].isnull && strictfunc)
    4123              :         {
    4124       107620 :             fcinfo->isnull = true;
    4125       107620 :             thisresult = (Datum) 0;
    4126              :         }
    4127              :         else
    4128              :         {
    4129      4851624 :             fcinfo->isnull = false;
    4130      4851624 :             thisresult = op->d.scalararrayop.fn_addr(fcinfo);
    4131              :         }
    4132              : 
    4133              :         /* Combine results per OR or AND semantics */
    4134      4959244 :         if (fcinfo->isnull)
    4135       107668 :             resultnull = true;
    4136      4851576 :         else if (useOr)
    4137              :         {
    4138      4210550 :             if (DatumGetBool(thisresult))
    4139              :             {
    4140       658791 :                 result = BoolGetDatum(true);
    4141       658791 :                 resultnull = false;
    4142       658791 :                 break;          /* needn't look at any more elements */
    4143              :             }
    4144              :         }
    4145              :         else
    4146              :         {
    4147       641026 :             if (!DatumGetBool(thisresult))
    4148              :             {
    4149       514146 :                 result = BoolGetDatum(false);
    4150       514146 :                 resultnull = false;
    4151       514146 :                 break;          /* needn't look at any more elements */
    4152              :             }
    4153              :         }
    4154              : 
    4155              :         /* advance bitmap pointer if any */
    4156      3786307 :         if (bitmap)
    4157              :         {
    4158       383994 :             bitmask <<= 1;
    4159       383994 :             if (bitmask == 0x100)
    4160              :             {
    4161          388 :                 bitmap++;
    4162          388 :                 bitmask = 1;
    4163              :             }
    4164              :         }
    4165              :     }
    4166              : 
    4167      2379878 :     *op->resvalue = result;
    4168      2379878 :     *op->resnull = resultnull;
    4169              : }
    4170              : 
    4171              : /*
    4172              :  * Hash function for scalar array hash op elements.
    4173              :  *
    4174              :  * We use the element type's default hash opclass, and the column collation
    4175              :  * if the type is collation-sensitive.
    4176              :  */
    4177              : static uint32
    4178        23700 : saop_element_hash(struct saophash_hash *tb, Datum key)
    4179              : {
    4180        23700 :     ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
    4181        23700 :     FunctionCallInfo fcinfo = &elements_tab->hash_fcinfo_data;
    4182              :     Datum       hash;
    4183              : 
    4184        23700 :     fcinfo->args[0].value = key;
    4185        23700 :     fcinfo->args[0].isnull = false;
    4186              : 
    4187        23700 :     hash = elements_tab->hash_finfo.fn_addr(fcinfo);
    4188              : 
    4189        23700 :     return DatumGetUInt32(hash);
    4190              : }
    4191              : 
    4192              : /*
    4193              :  * Matching function for scalar array hash op elements, to be used in hashtable
    4194              :  * lookups.
    4195              :  */
    4196              : static bool
    4197         4368 : saop_hash_element_match(struct saophash_hash *tb, Datum key1, Datum key2)
    4198              : {
    4199              :     Datum       result;
    4200              : 
    4201         4368 :     ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
    4202         4368 :     FunctionCallInfo fcinfo = elements_tab->op->d.hashedscalararrayop.fcinfo_data;
    4203              : 
    4204         4368 :     fcinfo->args[0].value = key1;
    4205         4368 :     fcinfo->args[0].isnull = false;
    4206         4368 :     fcinfo->args[1].value = key2;
    4207         4368 :     fcinfo->args[1].isnull = false;
    4208              : 
    4209         4368 :     result = elements_tab->op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
    4210              : 
    4211         4368 :     return DatumGetBool(result);
    4212              : }
    4213              : 
    4214              : /*
    4215              :  * Evaluate "scalar op ANY (const array)".
    4216              :  *
    4217              :  * Similar to ExecEvalScalarArrayOp, but optimized for faster repeat lookups
    4218              :  * by building a hashtable on the first lookup.  This hashtable will be reused
    4219              :  * by subsequent lookups.  Unlike ExecEvalScalarArrayOp, this version only
    4220              :  * supports OR semantics.
    4221              :  *
    4222              :  * Source array is in our result area, scalar arg is already evaluated into
    4223              :  * fcinfo->args[0].
    4224              :  *
    4225              :  * The operator always yields boolean.
    4226              :  */
    4227              : void
    4228        20667 : ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    4229              : {
    4230        20667 :     ScalarArrayOpExprHashTable *elements_tab = op->d.hashedscalararrayop.elements_tab;
    4231        20667 :     FunctionCallInfo fcinfo = op->d.hashedscalararrayop.fcinfo_data;
    4232        20667 :     bool        inclause = op->d.hashedscalararrayop.inclause;
    4233        20667 :     bool        strictfunc = op->d.hashedscalararrayop.finfo->fn_strict;
    4234        20667 :     Datum       scalar = fcinfo->args[0].value;
    4235        20667 :     bool        scalar_isnull = fcinfo->args[0].isnull;
    4236              :     Datum       result;
    4237              :     bool        resultnull;
    4238              :     bool        hashfound;
    4239              : 
    4240              :     /* We don't setup a hashed scalar array op if the array const is null. */
    4241              :     Assert(!*op->resnull);
    4242              : 
    4243              :     /*
    4244              :      * If the scalar is NULL, and the function is strict, return NULL; no
    4245              :      * point in executing the search.
    4246              :      */
    4247        20667 :     if (fcinfo->args[0].isnull && strictfunc)
    4248              :     {
    4249           34 :         *op->resnull = true;
    4250           34 :         return;
    4251              :     }
    4252              : 
    4253              :     /* Build the hash table on first evaluation */
    4254        20633 :     if (elements_tab == NULL)
    4255              :     {
    4256              :         ScalarArrayOpExpr *saop;
    4257              :         int16       typlen;
    4258              :         bool        typbyval;
    4259              :         char        typalign;
    4260              :         uint8       typalignby;
    4261              :         int         nitems;
    4262          116 :         bool        has_nulls = false;
    4263              :         char       *s;
    4264              :         bits8      *bitmap;
    4265              :         int         bitmask;
    4266              :         MemoryContext oldcontext;
    4267              :         ArrayType  *arr;
    4268              : 
    4269          116 :         saop = op->d.hashedscalararrayop.saop;
    4270              : 
    4271          116 :         arr = DatumGetArrayTypeP(*op->resvalue);
    4272          116 :         nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    4273              : 
    4274          116 :         get_typlenbyvalalign(ARR_ELEMTYPE(arr),
    4275              :                              &typlen,
    4276              :                              &typbyval,
    4277              :                              &typalign);
    4278          116 :         typalignby = typalign_to_alignby(typalign);
    4279              : 
    4280          116 :         oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    4281              : 
    4282              :         elements_tab = (ScalarArrayOpExprHashTable *)
    4283          116 :             palloc0(offsetof(ScalarArrayOpExprHashTable, hash_fcinfo_data) +
    4284              :                     SizeForFunctionCallInfo(1));
    4285          116 :         op->d.hashedscalararrayop.elements_tab = elements_tab;
    4286          116 :         elements_tab->op = op;
    4287              : 
    4288          116 :         fmgr_info(saop->hashfuncid, &elements_tab->hash_finfo);
    4289          116 :         fmgr_info_set_expr((Node *) saop, &elements_tab->hash_finfo);
    4290              : 
    4291          116 :         InitFunctionCallInfoData(elements_tab->hash_fcinfo_data,
    4292              :                                  &elements_tab->hash_finfo,
    4293              :                                  1,
    4294              :                                  saop->inputcollid,
    4295              :                                  NULL,
    4296              :                                  NULL);
    4297              : 
    4298              :         /*
    4299              :          * Create the hash table sizing it according to the number of elements
    4300              :          * in the array.  This does assume that the array has no duplicates.
    4301              :          * If the array happens to contain many duplicate values then it'll
    4302              :          * just mean that we sized the table a bit on the large side.
    4303              :          */
    4304          116 :         elements_tab->hashtab = saophash_create(CurrentMemoryContext, nitems,
    4305              :                                                 elements_tab);
    4306              : 
    4307          116 :         MemoryContextSwitchTo(oldcontext);
    4308              : 
    4309          116 :         s = (char *) ARR_DATA_PTR(arr);
    4310          116 :         bitmap = ARR_NULLBITMAP(arr);
    4311          116 :         bitmask = 1;
    4312         3270 :         for (int i = 0; i < nitems; i++)
    4313              :         {
    4314              :             /* Get array element, checking for NULL. */
    4315         3154 :             if (bitmap && (*bitmap & bitmask) == 0)
    4316              :             {
    4317           87 :                 has_nulls = true;
    4318              :             }
    4319              :             else
    4320              :             {
    4321              :                 Datum       element;
    4322              : 
    4323         3067 :                 element = fetch_att(s, typbyval, typlen);
    4324         3067 :                 s = att_addlength_pointer(s, typlen, s);
    4325         3067 :                 s = (char *) att_nominal_alignby(s, typalignby);
    4326              : 
    4327         3067 :                 saophash_insert(elements_tab->hashtab, element, &hashfound);
    4328              :             }
    4329              : 
    4330              :             /* Advance bitmap pointer if any. */
    4331         3154 :             if (bitmap)
    4332              :             {
    4333          285 :                 bitmask <<= 1;
    4334          285 :                 if (bitmask == 0x100)
    4335              :                 {
    4336           27 :                     bitmap++;
    4337           27 :                     bitmask = 1;
    4338              :                 }
    4339              :             }
    4340              :         }
    4341              : 
    4342              :         /*
    4343              :          * Remember if we had any nulls so that we know if we need to execute
    4344              :          * non-strict functions with a null lhs value if no match is found.
    4345              :          */
    4346          116 :         op->d.hashedscalararrayop.has_nulls = has_nulls;
    4347              :     }
    4348              : 
    4349              :     /* Check the hash to see if we have a match. */
    4350        20633 :     hashfound = NULL != saophash_lookup(elements_tab->hashtab, scalar);
    4351              : 
    4352              :     /* the result depends on if the clause is an IN or NOT IN clause */
    4353        20633 :     if (inclause)
    4354        18730 :         result = BoolGetDatum(hashfound);   /* IN */
    4355              :     else
    4356         1903 :         result = BoolGetDatum(!hashfound);  /* NOT IN */
    4357              : 
    4358        20633 :     resultnull = false;
    4359              : 
    4360              :     /*
    4361              :      * If we didn't find a match in the array, we still might need to handle
    4362              :      * the possibility of null values.  We didn't put any NULLs into the
    4363              :      * hashtable, but instead marked if we found any when building the table
    4364              :      * in has_nulls.
    4365              :      */
    4366        20633 :     if (!hashfound && op->d.hashedscalararrayop.has_nulls)
    4367              :     {
    4368           21 :         if (strictfunc)
    4369              :         {
    4370              : 
    4371              :             /*
    4372              :              * We have nulls in the array so a non-null lhs and no match must
    4373              :              * yield NULL.
    4374              :              */
    4375           12 :             result = (Datum) 0;
    4376           12 :             resultnull = true;
    4377              :         }
    4378              :         else
    4379              :         {
    4380              :             /*
    4381              :              * Execute function will null rhs just once.
    4382              :              *
    4383              :              * The hash lookup path will have scribbled on the lhs argument so
    4384              :              * we need to set it up also (even though we entered this function
    4385              :              * with it already set).
    4386              :              */
    4387            9 :             fcinfo->args[0].value = scalar;
    4388            9 :             fcinfo->args[0].isnull = scalar_isnull;
    4389            9 :             fcinfo->args[1].value = (Datum) 0;
    4390            9 :             fcinfo->args[1].isnull = true;
    4391              : 
    4392            9 :             result = op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
    4393            9 :             resultnull = fcinfo->isnull;
    4394              : 
    4395              :             /*
    4396              :              * Reverse the result for NOT IN clauses since the above function
    4397              :              * is the equality function and we need not-equals.
    4398              :              */
    4399            9 :             if (!inclause)
    4400            6 :                 result = BoolGetDatum(!DatumGetBool(result));
    4401              :         }
    4402              :     }
    4403              : 
    4404        20633 :     *op->resvalue = result;
    4405        20633 :     *op->resnull = resultnull;
    4406              : }
    4407              : 
    4408              : /*
    4409              :  * Evaluate a NOT NULL domain constraint.
    4410              :  */
    4411              : void
    4412          189 : ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
    4413              : {
    4414          189 :     if (*op->resnull)
    4415           53 :         errsave((Node *) op->d.domaincheck.escontext,
    4416              :                 (errcode(ERRCODE_NOT_NULL_VIOLATION),
    4417              :                  errmsg("domain %s does not allow null values",
    4418              :                         format_type_be(op->d.domaincheck.resulttype)),
    4419              :                  errdatatype(op->d.domaincheck.resulttype)));
    4420          136 : }
    4421              : 
    4422              : /*
    4423              :  * Evaluate a CHECK domain constraint.
    4424              :  */
    4425              : void
    4426         7005 : ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
    4427              : {
    4428         7005 :     if (!*op->d.domaincheck.checknull &&
    4429         6360 :         !DatumGetBool(*op->d.domaincheck.checkvalue))
    4430          232 :         errsave((Node *) op->d.domaincheck.escontext,
    4431              :                 (errcode(ERRCODE_CHECK_VIOLATION),
    4432              :                  errmsg("value for domain %s violates check constraint \"%s\"",
    4433              :                         format_type_be(op->d.domaincheck.resulttype),
    4434              :                         op->d.domaincheck.constraintname),
    4435              :                  errdomainconstraint(op->d.domaincheck.resulttype,
    4436              :                                      op->d.domaincheck.constraintname)));
    4437         6788 : }
    4438              : 
    4439              : /*
    4440              :  * Evaluate the various forms of XmlExpr.
    4441              :  *
    4442              :  * Arguments have been evaluated into named_argvalue/named_argnull
    4443              :  * and/or argvalue/argnull arrays.
    4444              :  */
    4445              : void
    4446        22827 : ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
    4447              : {
    4448        22827 :     XmlExpr    *xexpr = op->d.xmlexpr.xexpr;
    4449              :     Datum       value;
    4450              : 
    4451        22827 :     *op->resnull = true;     /* until we get a result */
    4452        22827 :     *op->resvalue = (Datum) 0;
    4453              : 
    4454        22827 :     switch (xexpr->op)
    4455              :     {
    4456           27 :         case IS_XMLCONCAT:
    4457              :             {
    4458           27 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4459           27 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4460           27 :                 List       *values = NIL;
    4461              : 
    4462           87 :                 for (int i = 0; i < list_length(xexpr->args); i++)
    4463              :                 {
    4464           60 :                     if (!argnull[i])
    4465           45 :                         values = lappend(values, DatumGetPointer(argvalue[i]));
    4466              :                 }
    4467              : 
    4468           27 :                 if (values != NIL)
    4469              :                 {
    4470           21 :                     *op->resvalue = PointerGetDatum(xmlconcat(values));
    4471           21 :                     *op->resnull = false;
    4472              :                 }
    4473              :             }
    4474           27 :             break;
    4475              : 
    4476        11241 :         case IS_XMLFOREST:
    4477              :             {
    4478        11241 :                 Datum      *argvalue = op->d.xmlexpr.named_argvalue;
    4479        11241 :                 bool       *argnull = op->d.xmlexpr.named_argnull;
    4480              :                 StringInfoData buf;
    4481              :                 ListCell   *lc;
    4482              :                 ListCell   *lc2;
    4483              :                 int         i;
    4484              : 
    4485        11241 :                 initStringInfo(&buf);
    4486              : 
    4487        11241 :                 i = 0;
    4488        78627 :                 forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
    4489              :                 {
    4490        67386 :                     Expr       *e = (Expr *) lfirst(lc);
    4491        67386 :                     char       *argname = strVal(lfirst(lc2));
    4492              : 
    4493        67386 :                     if (!argnull[i])
    4494              :                     {
    4495        56275 :                         value = argvalue[i];
    4496        56275 :                         appendStringInfo(&buf, "<%s>%s</%s>",
    4497              :                                          argname,
    4498              :                                          map_sql_value_to_xml_value(value,
    4499              :                                                                     exprType((Node *) e), true),
    4500              :                                          argname);
    4501        56275 :                         *op->resnull = false;
    4502              :                     }
    4503        67386 :                     i++;
    4504              :                 }
    4505              : 
    4506        11241 :                 if (!*op->resnull)
    4507              :                 {
    4508              :                     text       *result;
    4509              : 
    4510        11241 :                     result = cstring_to_text_with_len(buf.data, buf.len);
    4511        11241 :                     *op->resvalue = PointerGetDatum(result);
    4512              :                 }
    4513              : 
    4514        11241 :                 pfree(buf.data);
    4515              :             }
    4516        11241 :             break;
    4517              : 
    4518        11319 :         case IS_XMLELEMENT:
    4519        11316 :             *op->resvalue = PointerGetDatum(xmlelement(xexpr,
    4520        11319 :                                                        op->d.xmlexpr.named_argvalue,
    4521        11319 :                                                        op->d.xmlexpr.named_argnull,
    4522        11319 :                                                        op->d.xmlexpr.argvalue,
    4523        11319 :                                                        op->d.xmlexpr.argnull));
    4524        11316 :             *op->resnull = false;
    4525        11316 :             break;
    4526              : 
    4527           66 :         case IS_XMLPARSE:
    4528              :             {
    4529           66 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4530           66 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4531              :                 text       *data;
    4532              :                 bool        preserve_whitespace;
    4533              : 
    4534              :                 /* arguments are known to be text, bool */
    4535              :                 Assert(list_length(xexpr->args) == 2);
    4536              : 
    4537           66 :                 if (argnull[0])
    4538            0 :                     return;
    4539           66 :                 value = argvalue[0];
    4540           66 :                 data = DatumGetTextPP(value);
    4541              : 
    4542           66 :                 if (argnull[1]) /* probably can't happen */
    4543            0 :                     return;
    4544           66 :                 value = argvalue[1];
    4545           66 :                 preserve_whitespace = DatumGetBool(value);
    4546              : 
    4547           66 :                 *op->resvalue = PointerGetDatum(xmlparse(data,
    4548              :                                                          xexpr->xmloption,
    4549              :                                                          preserve_whitespace));
    4550           42 :                 *op->resnull = false;
    4551              :             }
    4552           42 :             break;
    4553              : 
    4554           36 :         case IS_XMLPI:
    4555              :             {
    4556              :                 text       *arg;
    4557              :                 bool        isnull;
    4558              : 
    4559              :                 /* optional argument is known to be text */
    4560              :                 Assert(list_length(xexpr->args) <= 1);
    4561              : 
    4562           36 :                 if (xexpr->args)
    4563              :                 {
    4564           21 :                     isnull = op->d.xmlexpr.argnull[0];
    4565           21 :                     if (isnull)
    4566            9 :                         arg = NULL;
    4567              :                     else
    4568           12 :                         arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]);
    4569              :                 }
    4570              :                 else
    4571              :                 {
    4572           15 :                     arg = NULL;
    4573           15 :                     isnull = false;
    4574              :                 }
    4575              : 
    4576           36 :                 *op->resvalue = PointerGetDatum(xmlpi(xexpr->name,
    4577              :                                                       arg,
    4578              :                                                       isnull,
    4579              :                                                       op->resnull));
    4580              :             }
    4581           27 :             break;
    4582              : 
    4583           30 :         case IS_XMLROOT:
    4584              :             {
    4585           30 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4586           30 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4587              :                 xmltype    *data;
    4588              :                 text       *version;
    4589              :                 int         standalone;
    4590              : 
    4591              :                 /* arguments are known to be xml, text, int */
    4592              :                 Assert(list_length(xexpr->args) == 3);
    4593              : 
    4594           30 :                 if (argnull[0])
    4595            0 :                     return;
    4596           30 :                 data = DatumGetXmlP(argvalue[0]);
    4597              : 
    4598           30 :                 if (argnull[1])
    4599           18 :                     version = NULL;
    4600              :                 else
    4601           12 :                     version = DatumGetTextPP(argvalue[1]);
    4602              : 
    4603              :                 Assert(!argnull[2]);    /* always present */
    4604           30 :                 standalone = DatumGetInt32(argvalue[2]);
    4605              : 
    4606           30 :                 *op->resvalue = PointerGetDatum(xmlroot(data,
    4607              :                                                         version,
    4608              :                                                         standalone));
    4609           30 :                 *op->resnull = false;
    4610              :             }
    4611           30 :             break;
    4612              : 
    4613           96 :         case IS_XMLSERIALIZE:
    4614              :             {
    4615           96 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4616           96 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4617              : 
    4618              :                 /* argument type is known to be xml */
    4619              :                 Assert(list_length(xexpr->args) == 1);
    4620              : 
    4621           96 :                 if (argnull[0])
    4622            6 :                     return;
    4623           90 :                 value = argvalue[0];
    4624              : 
    4625          150 :                 *op->resvalue =
    4626           90 :                     PointerGetDatum(xmltotext_with_options(DatumGetXmlP(value),
    4627              :                                                            xexpr->xmloption,
    4628           90 :                                                            xexpr->indent));
    4629           75 :                 *op->resnull = false;
    4630              :             }
    4631           75 :             break;
    4632              : 
    4633           12 :         case IS_DOCUMENT:
    4634              :             {
    4635           12 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    4636           12 :                 bool       *argnull = op->d.xmlexpr.argnull;
    4637              : 
    4638              :                 /* optional argument is known to be xml */
    4639              :                 Assert(list_length(xexpr->args) == 1);
    4640              : 
    4641           12 :                 if (argnull[0])
    4642            0 :                     return;
    4643           12 :                 value = argvalue[0];
    4644              : 
    4645           24 :                 *op->resvalue =
    4646           12 :                     BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
    4647           12 :                 *op->resnull = false;
    4648              :             }
    4649           12 :             break;
    4650              : 
    4651            0 :         default:
    4652            0 :             elog(ERROR, "unrecognized XML operation");
    4653              :             break;
    4654              :     }
    4655              : }
    4656              : 
    4657              : /*
    4658              :  * Evaluate a JSON constructor expression.
    4659              :  */
    4660              : void
    4661          351 : ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
    4662              :                         ExprContext *econtext)
    4663              : {
    4664              :     Datum       res;
    4665          351 :     JsonConstructorExprState *jcstate = op->d.json_constructor.jcstate;
    4666          351 :     JsonConstructorExpr *ctor = jcstate->constructor;
    4667          351 :     bool        is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
    4668          351 :     bool        isnull = false;
    4669              : 
    4670          351 :     if (ctor->type == JSCTOR_JSON_ARRAY)
    4671              :         res = (is_jsonb ?
    4672          109 :                jsonb_build_array_worker :
    4673              :                json_build_array_worker) (jcstate->nargs,
    4674          109 :                                          jcstate->arg_values,
    4675          109 :                                          jcstate->arg_nulls,
    4676          109 :                                          jcstate->arg_types,
    4677          109 :                                          jcstate->constructor->absent_on_null);
    4678          242 :     else if (ctor->type == JSCTOR_JSON_OBJECT)
    4679              :         res = (is_jsonb ?
    4680          187 :                jsonb_build_object_worker :
    4681              :                json_build_object_worker) (jcstate->nargs,
    4682          187 :                                           jcstate->arg_values,
    4683          187 :                                           jcstate->arg_nulls,
    4684          187 :                                           jcstate->arg_types,
    4685          187 :                                           jcstate->constructor->absent_on_null,
    4686          187 :                                           jcstate->constructor->unique);
    4687           55 :     else if (ctor->type == JSCTOR_JSON_SCALAR)
    4688              :     {
    4689           50 :         if (jcstate->arg_nulls[0])
    4690              :         {
    4691           10 :             res = (Datum) 0;
    4692           10 :             isnull = true;
    4693              :         }
    4694              :         else
    4695              :         {
    4696           40 :             Datum       value = jcstate->arg_values[0];
    4697           40 :             Oid         outfuncid = jcstate->arg_type_cache[0].outfuncid;
    4698           40 :             JsonTypeCategory category = (JsonTypeCategory)
    4699           40 :                 jcstate->arg_type_cache[0].category;
    4700              : 
    4701           40 :             if (is_jsonb)
    4702            0 :                 res = datum_to_jsonb(value, category, outfuncid);
    4703              :             else
    4704           40 :                 res = datum_to_json(value, category, outfuncid);
    4705              :         }
    4706              :     }
    4707            5 :     else if (ctor->type == JSCTOR_JSON_PARSE)
    4708              :     {
    4709            5 :         if (jcstate->arg_nulls[0])
    4710              :         {
    4711            0 :             res = (Datum) 0;
    4712            0 :             isnull = true;
    4713              :         }
    4714              :         else
    4715              :         {
    4716            5 :             Datum       value = jcstate->arg_values[0];
    4717            5 :             text       *js = DatumGetTextP(value);
    4718              : 
    4719            5 :             if (is_jsonb)
    4720            0 :                 res = jsonb_from_text(js, true);
    4721              :             else
    4722              :             {
    4723            5 :                 (void) json_validate(js, true, true);
    4724            0 :                 res = value;
    4725              :             }
    4726              :         }
    4727              :     }
    4728              :     else
    4729            0 :         elog(ERROR, "invalid JsonConstructorExpr type %d", ctor->type);
    4730              : 
    4731          308 :     *op->resvalue = res;
    4732          308 :     *op->resnull = isnull;
    4733          308 : }
    4734              : 
    4735              : /*
    4736              :  * Evaluate a IS JSON predicate.
    4737              :  */
    4738              : void
    4739         1375 : ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
    4740              : {
    4741         1375 :     JsonIsPredicate *pred = op->d.is_json.pred;
    4742         1375 :     Datum       js = *op->resvalue;
    4743              :     Oid         exprtype;
    4744              :     bool        res;
    4745              : 
    4746         1375 :     if (*op->resnull)
    4747              :     {
    4748           51 :         *op->resvalue = BoolGetDatum(false);
    4749           51 :         return;
    4750              :     }
    4751              : 
    4752         1324 :     exprtype = exprType(pred->expr);
    4753              : 
    4754         1324 :     if (exprtype == TEXTOID || exprtype == JSONOID)
    4755         1060 :     {
    4756         1060 :         text       *json = DatumGetTextP(js);
    4757              : 
    4758         1060 :         if (pred->item_type == JS_TYPE_ANY)
    4759          721 :             res = true;
    4760              :         else
    4761              :         {
    4762          339 :             switch (json_get_first_token(json, false))
    4763              :             {
    4764          150 :                 case JSON_TOKEN_OBJECT_START:
    4765          150 :                     res = pred->item_type == JS_TYPE_OBJECT;
    4766          150 :                     break;
    4767           63 :                 case JSON_TOKEN_ARRAY_START:
    4768           63 :                     res = pred->item_type == JS_TYPE_ARRAY;
    4769           63 :                     break;
    4770          108 :                 case JSON_TOKEN_STRING:
    4771              :                 case JSON_TOKEN_NUMBER:
    4772              :                 case JSON_TOKEN_TRUE:
    4773              :                 case JSON_TOKEN_FALSE:
    4774              :                 case JSON_TOKEN_NULL:
    4775          108 :                     res = pred->item_type == JS_TYPE_SCALAR;
    4776          108 :                     break;
    4777           18 :                 default:
    4778           18 :                     res = false;
    4779           18 :                     break;
    4780              :             }
    4781              :         }
    4782              : 
    4783              :         /*
    4784              :          * Do full parsing pass only for uniqueness check or for JSON text
    4785              :          * validation.
    4786              :          */
    4787         1060 :         if (res && (pred->unique_keys || exprtype == TEXTOID))
    4788          663 :             res = json_validate(json, pred->unique_keys, false);
    4789              :     }
    4790          264 :     else if (exprtype == JSONBOID)
    4791              :     {
    4792          264 :         if (pred->item_type == JS_TYPE_ANY)
    4793          165 :             res = true;
    4794              :         else
    4795              :         {
    4796           99 :             Jsonb      *jb = DatumGetJsonbP(js);
    4797              : 
    4798           99 :             switch (pred->item_type)
    4799              :             {
    4800           33 :                 case JS_TYPE_OBJECT:
    4801           33 :                     res = JB_ROOT_IS_OBJECT(jb);
    4802           33 :                     break;
    4803           33 :                 case JS_TYPE_ARRAY:
    4804           33 :                     res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb);
    4805           33 :                     break;
    4806           33 :                 case JS_TYPE_SCALAR:
    4807           33 :                     res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb);
    4808           33 :                     break;
    4809            0 :                 default:
    4810            0 :                     res = false;
    4811            0 :                     break;
    4812              :             }
    4813              :         }
    4814              : 
    4815              :         /* Key uniqueness check is redundant for jsonb */
    4816              :     }
    4817              :     else
    4818            0 :         res = false;
    4819              : 
    4820         1324 :     *op->resvalue = BoolGetDatum(res);
    4821              : }
    4822              : 
    4823              : /*
    4824              :  * Evaluate a jsonpath against a document, both of which must have been
    4825              :  * evaluated and their values saved in op->d.jsonexpr.jsestate.
    4826              :  *
    4827              :  * If an error occurs during JsonPath* evaluation or when coercing its result
    4828              :  * to the RETURNING type, JsonExprState.error is set to true, provided the
    4829              :  * ON ERROR behavior is not ERROR.  Similarly, if JsonPath{Query|Value}() found
    4830              :  * no matching items, JsonExprState.empty is set to true, provided the ON EMPTY
    4831              :  * behavior is not ERROR.  That is to signal to the subsequent steps that check
    4832              :  * those flags to return the ON ERROR / ON EMPTY expression.
    4833              :  *
    4834              :  * Return value is the step address to be performed next.  It will be one of
    4835              :  * jump_error, jump_empty, jump_eval_coercion, or jump_end, all given in
    4836              :  * op->d.jsonexpr.jsestate.
    4837              :  */
    4838              : int
    4839         2653 : ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
    4840              :                      ExprContext *econtext)
    4841              : {
    4842         2653 :     JsonExprState *jsestate = op->d.jsonexpr.jsestate;
    4843         2653 :     JsonExpr   *jsexpr = jsestate->jsexpr;
    4844              :     Datum       item;
    4845              :     JsonPath   *path;
    4846         2653 :     bool        throw_error = jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR;
    4847         2653 :     bool        error = false,
    4848         2653 :                 empty = false;
    4849         2653 :     int         jump_eval_coercion = jsestate->jump_eval_coercion;
    4850         2653 :     char       *val_string = NULL;
    4851              : 
    4852         2653 :     item = jsestate->formatted_expr.value;
    4853         2653 :     path = DatumGetJsonPathP(jsestate->pathspec.value);
    4854              : 
    4855              :     /* Set error/empty to false. */
    4856         2653 :     memset(&jsestate->error, 0, sizeof(NullableDatum));
    4857         2653 :     memset(&jsestate->empty, 0, sizeof(NullableDatum));
    4858              : 
    4859              :     /* Also reset ErrorSaveContext contents for the next row. */
    4860         2653 :     if (jsestate->escontext.details_wanted)
    4861              :     {
    4862          456 :         jsestate->escontext.error_data = NULL;
    4863          456 :         jsestate->escontext.details_wanted = false;
    4864              :     }
    4865         2653 :     jsestate->escontext.error_occurred = false;
    4866              : 
    4867         2653 :     switch (jsexpr->op)
    4868              :     {
    4869          291 :         case JSON_EXISTS_OP:
    4870              :             {
    4871          291 :                 bool        exists = JsonPathExists(item, path,
    4872          291 :                                                     !throw_error ? &error : NULL,
    4873              :                                                     jsestate->args);
    4874              : 
    4875          288 :                 if (!error)
    4876              :                 {
    4877          210 :                     *op->resnull = false;
    4878          210 :                     *op->resvalue = BoolGetDatum(exists);
    4879              :                 }
    4880              :             }
    4881          288 :             break;
    4882              : 
    4883         1230 :         case JSON_QUERY_OP:
    4884         1230 :             *op->resvalue = JsonPathQuery(item, path, jsexpr->wrapper, &empty,
    4885         1230 :                                           !throw_error ? &error : NULL,
    4886              :                                           jsestate->args,
    4887         1230 :                                           jsexpr->column_name);
    4888              : 
    4889         1215 :             *op->resnull = (DatumGetPointer(*op->resvalue) == NULL);
    4890         1215 :             break;
    4891              : 
    4892         1132 :         case JSON_VALUE_OP:
    4893              :             {
    4894         1132 :                 JsonbValue *jbv = JsonPathValue(item, path, &empty,
    4895         1132 :                                                 !throw_error ? &error : NULL,
    4896              :                                                 jsestate->args,
    4897         1132 :                                                 jsexpr->column_name);
    4898              : 
    4899         1117 :                 if (jbv == NULL)
    4900              :                 {
    4901              :                     /* Will be coerced with json_populate_type(), if needed. */
    4902          264 :                     *op->resvalue = (Datum) 0;
    4903          264 :                     *op->resnull = true;
    4904              :                 }
    4905          853 :                 else if (!error && !empty)
    4906              :                 {
    4907          853 :                     if (jsexpr->returning->typid == JSONOID ||
    4908          838 :                         jsexpr->returning->typid == JSONBOID)
    4909              :                     {
    4910           27 :                         val_string = DatumGetCString(DirectFunctionCall1(jsonb_out,
    4911              :                                                                          JsonbPGetDatum(JsonbValueToJsonb(jbv))));
    4912              :                     }
    4913          826 :                     else if (jsexpr->use_json_coercion)
    4914              :                     {
    4915           51 :                         *op->resvalue = JsonbPGetDatum(JsonbValueToJsonb(jbv));
    4916           51 :                         *op->resnull = false;
    4917              :                     }
    4918              :                     else
    4919              :                     {
    4920          775 :                         val_string = ExecGetJsonValueItemString(jbv, op->resnull);
    4921              : 
    4922              :                         /*
    4923              :                          * Simply convert to the default RETURNING type (text)
    4924              :                          * if no coercion needed.
    4925              :                          */
    4926          775 :                         if (!jsexpr->use_io_coercion)
    4927           57 :                             *op->resvalue = DirectFunctionCall1(textin,
    4928              :                                                                 CStringGetDatum(val_string));
    4929              :                     }
    4930              :                 }
    4931         1117 :                 break;
    4932              :             }
    4933              : 
    4934              :             /* JSON_TABLE_OP can't happen here */
    4935              : 
    4936            0 :         default:
    4937            0 :             elog(ERROR, "unrecognized SQL/JSON expression op %d",
    4938              :                  (int) jsexpr->op);
    4939              :             return false;
    4940              :     }
    4941              : 
    4942              :     /*
    4943              :      * Coerce the result value to the RETURNING type by calling its input
    4944              :      * function.
    4945              :      */
    4946         2620 :     if (!*op->resnull && jsexpr->use_io_coercion)
    4947              :     {
    4948              :         FunctionCallInfo fcinfo;
    4949              : 
    4950              :         Assert(jump_eval_coercion == -1);
    4951          745 :         fcinfo = jsestate->input_fcinfo;
    4952              :         Assert(fcinfo != NULL);
    4953              :         Assert(val_string != NULL);
    4954          745 :         fcinfo->args[0].value = PointerGetDatum(val_string);
    4955          745 :         fcinfo->args[0].isnull = *op->resnull;
    4956              : 
    4957              :         /*
    4958              :          * Second and third arguments are already set up in
    4959              :          * ExecInitJsonExpr().
    4960              :          */
    4961              : 
    4962          745 :         fcinfo->isnull = false;
    4963          745 :         *op->resvalue = FunctionCallInvoke(fcinfo);
    4964          715 :         if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
    4965           93 :             error = true;
    4966              :     }
    4967              : 
    4968              :     /*
    4969              :      * When setting up the ErrorSaveContext (if needed) for capturing the
    4970              :      * errors that occur when coercing the JsonBehavior expression, set
    4971              :      * details_wanted to be able to show the actual error message as the
    4972              :      * DETAIL of the error message that tells that it is the JsonBehavior
    4973              :      * expression that caused the error; see ExecEvalJsonCoercionFinish().
    4974              :      */
    4975              : 
    4976              :     /* Handle ON EMPTY. */
    4977         2590 :     if (empty)
    4978              :     {
    4979          276 :         *op->resvalue = (Datum) 0;
    4980          276 :         *op->resnull = true;
    4981          276 :         if (jsexpr->on_empty)
    4982              :         {
    4983          276 :             if (jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR)
    4984              :             {
    4985          246 :                 jsestate->empty.value = BoolGetDatum(true);
    4986              :                 /* Set up to catch coercion errors of the ON EMPTY value. */
    4987          246 :                 jsestate->escontext.error_occurred = false;
    4988          246 :                 jsestate->escontext.details_wanted = true;
    4989              :                 /* Jump to end if the ON EMPTY behavior is to return NULL */
    4990          246 :                 return jsestate->jump_empty >= 0 ? jsestate->jump_empty : jsestate->jump_end;
    4991              :             }
    4992              :         }
    4993            0 :         else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
    4994              :         {
    4995            0 :             jsestate->error.value = BoolGetDatum(true);
    4996              :             /* Set up to catch coercion errors of the ON ERROR value. */
    4997            0 :             jsestate->escontext.error_occurred = false;
    4998            0 :             jsestate->escontext.details_wanted = true;
    4999              :             Assert(!throw_error);
    5000              :             /* Jump to end if the ON ERROR behavior is to return NULL */
    5001            0 :             return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
    5002              :         }
    5003              : 
    5004           30 :         if (jsexpr->column_name)
    5005            6 :             ereport(ERROR,
    5006              :                     errcode(ERRCODE_NO_SQL_JSON_ITEM),
    5007              :                     errmsg("no SQL/JSON item found for specified path of column \"%s\"",
    5008              :                            jsexpr->column_name));
    5009              :         else
    5010           24 :             ereport(ERROR,
    5011              :                     errcode(ERRCODE_NO_SQL_JSON_ITEM),
    5012              :                     errmsg("no SQL/JSON item found for specified path"));
    5013              :     }
    5014              : 
    5015              :     /*
    5016              :      * ON ERROR. Wouldn't get here if the behavior is ERROR, because they
    5017              :      * would have already been thrown.
    5018              :      */
    5019         2314 :     if (error)
    5020              :     {
    5021              :         Assert(!throw_error);
    5022          267 :         *op->resvalue = (Datum) 0;
    5023          267 :         *op->resnull = true;
    5024          267 :         jsestate->error.value = BoolGetDatum(true);
    5025              :         /* Set up to catch coercion errors of the ON ERROR value. */
    5026          267 :         jsestate->escontext.error_occurred = false;
    5027          267 :         jsestate->escontext.details_wanted = true;
    5028              :         /* Jump to end if the ON ERROR behavior is to return NULL */
    5029          267 :         return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
    5030              :     }
    5031              : 
    5032         2047 :     return jump_eval_coercion >= 0 ? jump_eval_coercion : jsestate->jump_end;
    5033              : }
    5034              : 
    5035              : /*
    5036              :  * Convert the given JsonbValue to its C string representation
    5037              :  *
    5038              :  * *resnull is set if the JsonbValue is a jbvNull.
    5039              :  */
    5040              : static char *
    5041          775 : ExecGetJsonValueItemString(JsonbValue *item, bool *resnull)
    5042              : {
    5043          775 :     *resnull = false;
    5044              : 
    5045              :     /* get coercion state reference and datum of the corresponding SQL type */
    5046          775 :     switch (item->type)
    5047              :     {
    5048            0 :         case jbvNull:
    5049            0 :             *resnull = true;
    5050            0 :             return NULL;
    5051              : 
    5052          158 :         case jbvString:
    5053              :             {
    5054          158 :                 char       *str = palloc(item->val.string.len + 1);
    5055              : 
    5056          158 :                 memcpy(str, item->val.string.val, item->val.string.len);
    5057          158 :                 str[item->val.string.len] = '\0';
    5058          158 :                 return str;
    5059              :             }
    5060              : 
    5061          560 :         case jbvNumeric:
    5062          560 :             return DatumGetCString(DirectFunctionCall1(numeric_out,
    5063              :                                                        NumericGetDatum(item->val.numeric)));
    5064              : 
    5065           36 :         case jbvBool:
    5066           36 :             return DatumGetCString(DirectFunctionCall1(boolout,
    5067              :                                                        BoolGetDatum(item->val.boolean)));
    5068              : 
    5069           21 :         case jbvDatetime:
    5070           21 :             switch (item->val.datetime.typid)
    5071              :             {
    5072            3 :                 case DATEOID:
    5073            3 :                     return DatumGetCString(DirectFunctionCall1(date_out,
    5074              :                                                                item->val.datetime.value));
    5075            3 :                 case TIMEOID:
    5076            3 :                     return DatumGetCString(DirectFunctionCall1(time_out,
    5077              :                                                                item->val.datetime.value));
    5078            3 :                 case TIMETZOID:
    5079            3 :                     return DatumGetCString(DirectFunctionCall1(timetz_out,
    5080              :                                                                item->val.datetime.value));
    5081            3 :                 case TIMESTAMPOID:
    5082            3 :                     return DatumGetCString(DirectFunctionCall1(timestamp_out,
    5083              :                                                                item->val.datetime.value));
    5084            9 :                 case TIMESTAMPTZOID:
    5085            9 :                     return DatumGetCString(DirectFunctionCall1(timestamptz_out,
    5086              :                                                                item->val.datetime.value));
    5087            0 :                 default:
    5088            0 :                     elog(ERROR, "unexpected jsonb datetime type oid %u",
    5089              :                          item->val.datetime.typid);
    5090              :             }
    5091              :             break;
    5092              : 
    5093            0 :         case jbvArray:
    5094              :         case jbvObject:
    5095              :         case jbvBinary:
    5096            0 :             return DatumGetCString(DirectFunctionCall1(jsonb_out,
    5097              :                                                        JsonbPGetDatum(JsonbValueToJsonb(item))));
    5098              : 
    5099            0 :         default:
    5100            0 :             elog(ERROR, "unexpected jsonb value type %d", item->type);
    5101              :     }
    5102              : 
    5103              :     Assert(false);
    5104              :     *resnull = true;
    5105              :     return NULL;
    5106              : }
    5107              : 
    5108              : /*
    5109              :  * Coerce a jsonb value produced by ExecEvalJsonExprPath() or an ON ERROR /
    5110              :  * ON EMPTY behavior expression to the target type.
    5111              :  *
    5112              :  * Any soft errors that occur here will be checked by
    5113              :  * EEOP_JSONEXPR_COERCION_FINISH that will run after this.
    5114              :  */
    5115              : void
    5116          903 : ExecEvalJsonCoercion(ExprState *state, ExprEvalStep *op,
    5117              :                      ExprContext *econtext)
    5118              : {
    5119          903 :     ErrorSaveContext *escontext = op->d.jsonexpr_coercion.escontext;
    5120              : 
    5121              :     /*
    5122              :      * Prepare to call json_populate_type() to coerce the boolean result of
    5123              :      * JSON_EXISTS_OP to the target type.  If the target type is integer or a
    5124              :      * domain over integer, call the boolean-to-integer cast function instead,
    5125              :      * because the integer's input function (which is what
    5126              :      * json_populate_type() calls to coerce to scalar target types) doesn't
    5127              :      * accept boolean literals as valid input.  We only have a special case
    5128              :      * for integer and domains thereof as it seems common to use those types
    5129              :      * for EXISTS columns in JSON_TABLE().
    5130              :      */
    5131          903 :     if (op->d.jsonexpr_coercion.exists_coerce)
    5132              :     {
    5133           90 :         if (op->d.jsonexpr_coercion.exists_cast_to_int)
    5134              :         {
    5135              :             /* Check domain constraints if any. */
    5136           63 :             if (op->d.jsonexpr_coercion.exists_check_domain &&
    5137           12 :                 !domain_check_safe(*op->resvalue, *op->resnull,
    5138              :                                    op->d.jsonexpr_coercion.targettype,
    5139              :                                    &op->d.jsonexpr_coercion.json_coercion_cache,
    5140              :                                    econtext->ecxt_per_query_memory,
    5141              :                                    (Node *) escontext))
    5142              :             {
    5143            9 :                 *op->resnull = true;
    5144            9 :                 *op->resvalue = (Datum) 0;
    5145              :             }
    5146              :             else
    5147           51 :                 *op->resvalue = DirectFunctionCall1(bool_int4, *op->resvalue);
    5148           60 :             return;
    5149              :         }
    5150              : 
    5151           27 :         *op->resvalue = DirectFunctionCall1(jsonb_in,
    5152              :                                             DatumGetBool(*op->resvalue) ?
    5153              :                                             CStringGetDatum("true") :
    5154              :                                             CStringGetDatum("false"));
    5155              :     }
    5156              : 
    5157          765 :     *op->resvalue = json_populate_type(*op->resvalue, JSONBOID,
    5158              :                                        op->d.jsonexpr_coercion.targettype,
    5159              :                                        op->d.jsonexpr_coercion.targettypmod,
    5160              :                                        &op->d.jsonexpr_coercion.json_coercion_cache,
    5161              :                                        econtext->ecxt_per_query_memory,
    5162              :                                        op->resnull,
    5163          840 :                                        op->d.jsonexpr_coercion.omit_quotes,
    5164              :                                        (Node *) escontext);
    5165              : }
    5166              : 
    5167              : static char *
    5168           39 : GetJsonBehaviorValueString(JsonBehavior *behavior)
    5169              : {
    5170              :     /*
    5171              :      * The order of array elements must correspond to the order of
    5172              :      * JsonBehaviorType members.
    5173              :      */
    5174           39 :     const char *behavior_names[] =
    5175              :     {
    5176              :         "NULL",
    5177              :         "ERROR",
    5178              :         "EMPTY",
    5179              :         "TRUE",
    5180              :         "FALSE",
    5181              :         "UNKNOWN",
    5182              :         "EMPTY ARRAY",
    5183              :         "EMPTY OBJECT",
    5184              :         "DEFAULT"
    5185              :     };
    5186              : 
    5187           39 :     return pstrdup(behavior_names[behavior->btype]);
    5188              : }
    5189              : 
    5190              : /*
    5191              :  * Checks if an error occurred in ExecEvalJsonCoercion().  If so, this sets
    5192              :  * JsonExprState.error to trigger the ON ERROR handling steps, unless the
    5193              :  * error is thrown when coercing a JsonBehavior value.
    5194              :  */
    5195              : void
    5196          849 : ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op)
    5197              : {
    5198          849 :     JsonExprState *jsestate = op->d.jsonexpr.jsestate;
    5199              : 
    5200          849 :     if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
    5201              :     {
    5202              :         /*
    5203              :          * jsestate->error or jsestate->empty being set means that the error
    5204              :          * occurred when coercing the JsonBehavior value.  Throw the error in
    5205              :          * that case with the actual coercion error message shown in the
    5206              :          * DETAIL part.
    5207              :          */
    5208          276 :         if (DatumGetBool(jsestate->error.value))
    5209           30 :             ereport(ERROR,
    5210              :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    5211              :             /*- translator: first %s is a SQL/JSON clause (e.g. ON ERROR) */
    5212              :                      errmsg("could not coerce %s expression (%s) to the RETURNING type",
    5213              :                             "ON ERROR",
    5214              :                             GetJsonBehaviorValueString(jsestate->jsexpr->on_error)),
    5215              :                      errdetail("%s", jsestate->escontext.error_data->message)));
    5216          246 :         else if (DatumGetBool(jsestate->empty.value))
    5217            9 :             ereport(ERROR,
    5218              :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    5219              :             /*- translator: first %s is a SQL/JSON clause (e.g. ON ERROR) */
    5220              :                      errmsg("could not coerce %s expression (%s) to the RETURNING type",
    5221              :                             "ON EMPTY",
    5222              :                             GetJsonBehaviorValueString(jsestate->jsexpr->on_empty)),
    5223              :                      errdetail("%s", jsestate->escontext.error_data->message)));
    5224              : 
    5225          237 :         *op->resvalue = (Datum) 0;
    5226          237 :         *op->resnull = true;
    5227              : 
    5228          237 :         jsestate->error.value = BoolGetDatum(true);
    5229              : 
    5230              :         /*
    5231              :          * Reset for next use such as for catching errors when coercing a
    5232              :          * JsonBehavior expression.
    5233              :          */
    5234          237 :         jsestate->escontext.error_occurred = false;
    5235          237 :         jsestate->escontext.details_wanted = true;
    5236              :     }
    5237          810 : }
    5238              : 
    5239              : /*
    5240              :  * ExecEvalGroupingFunc
    5241              :  *
    5242              :  * Computes a bitmask with a bit for each (unevaluated) argument expression
    5243              :  * (rightmost arg is least significant bit).
    5244              :  *
    5245              :  * A bit is set if the corresponding expression is NOT part of the set of
    5246              :  * grouping expressions in the current grouping set.
    5247              :  */
    5248              : void
    5249          968 : ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
    5250              : {
    5251          968 :     AggState   *aggstate = castNode(AggState, state->parent);
    5252          968 :     int         result = 0;
    5253          968 :     Bitmapset  *grouped_cols = aggstate->grouped_cols;
    5254              :     ListCell   *lc;
    5255              : 
    5256         2333 :     foreach(lc, op->d.grouping_func.clauses)
    5257              :     {
    5258         1365 :         int         attnum = lfirst_int(lc);
    5259              : 
    5260         1365 :         result <<= 1;
    5261              : 
    5262         1365 :         if (!bms_is_member(attnum, grouped_cols))
    5263          546 :             result |= 1;
    5264              :     }
    5265              : 
    5266          968 :     *op->resvalue = Int32GetDatum(result);
    5267          968 :     *op->resnull = false;
    5268          968 : }
    5269              : 
    5270              : /*
    5271              :  * ExecEvalMergeSupportFunc
    5272              :  *
    5273              :  * Returns information about the current MERGE action for its RETURNING list.
    5274              :  */
    5275              : void
    5276          238 : ExecEvalMergeSupportFunc(ExprState *state, ExprEvalStep *op,
    5277              :                          ExprContext *econtext)
    5278              : {
    5279          238 :     ModifyTableState *mtstate = castNode(ModifyTableState, state->parent);
    5280          238 :     MergeActionState *relaction = mtstate->mt_merge_action;
    5281              : 
    5282          238 :     if (!relaction)
    5283            0 :         elog(ERROR, "no merge action in progress");
    5284              : 
    5285              :     /* Return the MERGE action ("INSERT", "UPDATE", or "DELETE") */
    5286          238 :     switch (relaction->mas_action->commandType)
    5287              :     {
    5288           80 :         case CMD_INSERT:
    5289           80 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("INSERT", 6));
    5290           80 :             *op->resnull = false;
    5291           80 :             break;
    5292           98 :         case CMD_UPDATE:
    5293           98 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("UPDATE", 6));
    5294           98 :             *op->resnull = false;
    5295           98 :             break;
    5296           60 :         case CMD_DELETE:
    5297           60 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("DELETE", 6));
    5298           60 :             *op->resnull = false;
    5299           60 :             break;
    5300            0 :         case CMD_NOTHING:
    5301            0 :             elog(ERROR, "unexpected merge action: DO NOTHING");
    5302              :             break;
    5303            0 :         default:
    5304            0 :             elog(ERROR, "unrecognized commandType: %d",
    5305              :                  (int) relaction->mas_action->commandType);
    5306              :     }
    5307          238 : }
    5308              : 
    5309              : /*
    5310              :  * Hand off evaluation of a subplan to nodeSubplan.c
    5311              :  */
    5312              : void
    5313      1815080 : ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    5314              : {
    5315      1815080 :     SubPlanState *sstate = op->d.subplan.sstate;
    5316              : 
    5317              :     /* could potentially be nested, so make sure there's enough stack */
    5318      1815080 :     check_stack_depth();
    5319              : 
    5320      1815080 :     *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
    5321      1815077 : }
    5322              : 
    5323              : /*
    5324              :  * Evaluate a wholerow Var expression.
    5325              :  *
    5326              :  * Returns a Datum whose value is the value of a whole-row range variable
    5327              :  * with respect to given expression context.
    5328              :  */
    5329              : void
    5330        23508 : ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    5331              : {
    5332        23508 :     Var        *variable = op->d.wholerow.var;
    5333        23508 :     TupleTableSlot *slot = NULL;
    5334              :     TupleDesc   output_tupdesc;
    5335              :     MemoryContext oldcontext;
    5336              :     HeapTupleHeader dtuple;
    5337              :     HeapTuple   tuple;
    5338              : 
    5339              :     /* This was checked by ExecInitExpr */
    5340              :     Assert(variable->varattno == InvalidAttrNumber);
    5341              : 
    5342              :     /* Get the input slot we want */
    5343        23508 :     switch (variable->varno)
    5344              :     {
    5345           54 :         case INNER_VAR:
    5346              :             /* get the tuple from the inner node */
    5347           54 :             slot = econtext->ecxt_innertuple;
    5348           54 :             break;
    5349              : 
    5350            9 :         case OUTER_VAR:
    5351              :             /* get the tuple from the outer node */
    5352            9 :             slot = econtext->ecxt_outertuple;
    5353            9 :             break;
    5354              : 
    5355              :             /* INDEX_VAR is handled by default case */
    5356              : 
    5357        23445 :         default:
    5358              : 
    5359              :             /*
    5360              :              * Get the tuple from the relation being scanned.
    5361              :              *
    5362              :              * By default, this uses the "scan" tuple slot, but a wholerow Var
    5363              :              * in the RETURNING list may explicitly refer to OLD/NEW.  If the
    5364              :              * OLD/NEW row doesn't exist, we just return NULL.
    5365              :              */
    5366        23445 :             switch (variable->varreturningtype)
    5367              :             {
    5368        23189 :                 case VAR_RETURNING_DEFAULT:
    5369        23189 :                     slot = econtext->ecxt_scantuple;
    5370        23189 :                     break;
    5371              : 
    5372          128 :                 case VAR_RETURNING_OLD:
    5373          128 :                     if (state->flags & EEO_FLAG_OLD_IS_NULL)
    5374              :                     {
    5375           35 :                         *op->resvalue = (Datum) 0;
    5376           35 :                         *op->resnull = true;
    5377           35 :                         return;
    5378              :                     }
    5379           93 :                     slot = econtext->ecxt_oldtuple;
    5380           93 :                     break;
    5381              : 
    5382          128 :                 case VAR_RETURNING_NEW:
    5383          128 :                     if (state->flags & EEO_FLAG_NEW_IS_NULL)
    5384              :                     {
    5385           15 :                         *op->resvalue = (Datum) 0;
    5386           15 :                         *op->resnull = true;
    5387           15 :                         return;
    5388              :                     }
    5389          113 :                     slot = econtext->ecxt_newtuple;
    5390          113 :                     break;
    5391              :             }
    5392        23395 :             break;
    5393              :     }
    5394              : 
    5395              :     /* Apply the junkfilter if any */
    5396        23458 :     if (op->d.wholerow.junkFilter != NULL)
    5397           30 :         slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
    5398              : 
    5399              :     /*
    5400              :      * If first time through, obtain tuple descriptor and check compatibility.
    5401              :      *
    5402              :      * XXX: It'd be great if this could be moved to the expression
    5403              :      * initialization phase, but due to using slots that's currently not
    5404              :      * feasible.
    5405              :      */
    5406        23458 :     if (op->d.wholerow.first)
    5407              :     {
    5408              :         /* optimistically assume we don't need slow path */
    5409         1789 :         op->d.wholerow.slow = false;
    5410              : 
    5411              :         /*
    5412              :          * If the Var identifies a named composite type, we must check that
    5413              :          * the actual tuple type is compatible with it.
    5414              :          */
    5415         1789 :         if (variable->vartype != RECORDOID)
    5416              :         {
    5417              :             TupleDesc   var_tupdesc;
    5418              :             TupleDesc   slot_tupdesc;
    5419              : 
    5420              :             /*
    5421              :              * We really only care about numbers of attributes and data types.
    5422              :              * Also, we can ignore type mismatch on columns that are dropped
    5423              :              * in the destination type, so long as (1) the physical storage
    5424              :              * matches or (2) the actual column value is NULL.  Case (1) is
    5425              :              * helpful in some cases involving out-of-date cached plans, while
    5426              :              * case (2) is expected behavior in situations such as an INSERT
    5427              :              * into a table with dropped columns (the planner typically
    5428              :              * generates an INT4 NULL regardless of the dropped column type).
    5429              :              * If we find a dropped column and cannot verify that case (1)
    5430              :              * holds, we have to use the slow path to check (2) for each row.
    5431              :              *
    5432              :              * If vartype is a domain over composite, just look through that
    5433              :              * to the base composite type.
    5434              :              */
    5435         1236 :             var_tupdesc = lookup_rowtype_tupdesc_domain(variable->vartype,
    5436              :                                                         -1, false);
    5437              : 
    5438         1236 :             slot_tupdesc = slot->tts_tupleDescriptor;
    5439              : 
    5440         1236 :             if (var_tupdesc->natts != slot_tupdesc->natts)
    5441            0 :                 ereport(ERROR,
    5442              :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    5443              :                          errmsg("table row type and query-specified row type do not match"),
    5444              :                          errdetail_plural("Table row contains %d attribute, but query expects %d.",
    5445              :                                           "Table row contains %d attributes, but query expects %d.",
    5446              :                                           slot_tupdesc->natts,
    5447              :                                           slot_tupdesc->natts,
    5448              :                                           var_tupdesc->natts)));
    5449              : 
    5450         4800 :             for (int i = 0; i < var_tupdesc->natts; i++)
    5451              :             {
    5452         3564 :                 Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
    5453         3564 :                 Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
    5454              : 
    5455         3564 :                 if (vattr->atttypid == sattr->atttypid)
    5456         3564 :                     continue;   /* no worries */
    5457            0 :                 if (!vattr->attisdropped)
    5458            0 :                     ereport(ERROR,
    5459              :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    5460              :                              errmsg("table row type and query-specified row type do not match"),
    5461              :                              errdetail("Table has type %s at ordinal position %d, but query expects %s.",
    5462              :                                        format_type_be(sattr->atttypid),
    5463              :                                        i + 1,
    5464              :                                        format_type_be(vattr->atttypid))));
    5465              : 
    5466            0 :                 if (vattr->attlen != sattr->attlen ||
    5467            0 :                     vattr->attalign != sattr->attalign)
    5468            0 :                     op->d.wholerow.slow = true; /* need to check for nulls */
    5469              :             }
    5470              : 
    5471              :             /*
    5472              :              * Use the variable's declared rowtype as the descriptor for the
    5473              :              * output values.  In particular, we *must* absorb any
    5474              :              * attisdropped markings.
    5475              :              */
    5476         1236 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    5477         1236 :             output_tupdesc = CreateTupleDescCopy(var_tupdesc);
    5478         1236 :             MemoryContextSwitchTo(oldcontext);
    5479              : 
    5480         1236 :             ReleaseTupleDesc(var_tupdesc);
    5481              :         }
    5482              :         else
    5483              :         {
    5484              :             /*
    5485              :              * In the RECORD case, we use the input slot's rowtype as the
    5486              :              * descriptor for the output values, modulo possibly assigning new
    5487              :              * column names below.
    5488              :              */
    5489          553 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    5490          553 :             output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
    5491          553 :             MemoryContextSwitchTo(oldcontext);
    5492              : 
    5493              :             /*
    5494              :              * It's possible that the input slot is a relation scan slot and
    5495              :              * so is marked with that relation's rowtype.  But we're supposed
    5496              :              * to be returning RECORD, so reset to that.
    5497              :              */
    5498          553 :             output_tupdesc->tdtypeid = RECORDOID;
    5499          553 :             output_tupdesc->tdtypmod = -1;
    5500              : 
    5501              :             /*
    5502              :              * We already got the correct physical datatype info above, but
    5503              :              * now we should try to find the source RTE and adopt its column
    5504              :              * aliases, since it's unlikely that the input slot has the
    5505              :              * desired names.
    5506              :              *
    5507              :              * If we can't locate the RTE, assume the column names we've got
    5508              :              * are OK.  (As of this writing, the only cases where we can't
    5509              :              * locate the RTE are in execution of trigger WHEN clauses, and
    5510              :              * then the Var will have the trigger's relation's rowtype, so its
    5511              :              * names are fine.)  Also, if the creator of the RTE didn't bother
    5512              :              * to fill in an eref field, assume our column names are OK. (This
    5513              :              * happens in COPY, and perhaps other places.)
    5514              :              */
    5515          553 :             if (econtext->ecxt_estate &&
    5516          553 :                 variable->varno <= econtext->ecxt_estate->es_range_table_size)
    5517              :             {
    5518          553 :                 RangeTblEntry *rte = exec_rt_fetch(variable->varno,
    5519          553 :                                                    econtext->ecxt_estate);
    5520              : 
    5521          553 :                 if (rte->eref)
    5522          553 :                     ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
    5523              :             }
    5524              :         }
    5525              : 
    5526              :         /* Bless the tupdesc if needed, and save it in the execution state */
    5527         1789 :         op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
    5528              : 
    5529         1789 :         op->d.wholerow.first = false;
    5530              :     }
    5531              : 
    5532              :     /*
    5533              :      * Make sure all columns of the slot are accessible in the slot's
    5534              :      * Datum/isnull arrays.
    5535              :      */
    5536        23458 :     slot_getallattrs(slot);
    5537              : 
    5538        23458 :     if (op->d.wholerow.slow)
    5539              :     {
    5540              :         /* Check to see if any dropped attributes are non-null */
    5541            0 :         TupleDesc   tupleDesc = slot->tts_tupleDescriptor;
    5542            0 :         TupleDesc   var_tupdesc = op->d.wholerow.tupdesc;
    5543              : 
    5544              :         Assert(var_tupdesc->natts == tupleDesc->natts);
    5545              : 
    5546            0 :         for (int i = 0; i < var_tupdesc->natts; i++)
    5547              :         {
    5548            0 :             CompactAttribute *vattr = TupleDescCompactAttr(var_tupdesc, i);
    5549            0 :             CompactAttribute *sattr = TupleDescCompactAttr(tupleDesc, i);
    5550              : 
    5551            0 :             if (!vattr->attisdropped)
    5552            0 :                 continue;       /* already checked non-dropped cols */
    5553            0 :             if (slot->tts_isnull[i])
    5554            0 :                 continue;       /* null is always okay */
    5555            0 :             if (vattr->attlen != sattr->attlen ||
    5556            0 :                 vattr->attalignby != sattr->attalignby)
    5557            0 :                 ereport(ERROR,
    5558              :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    5559              :                          errmsg("table row type and query-specified row type do not match"),
    5560              :                          errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
    5561              :                                    i + 1)));
    5562              :         }
    5563              :     }
    5564              : 
    5565              :     /*
    5566              :      * Build a composite datum, making sure any toasted fields get detoasted.
    5567              :      *
    5568              :      * (Note: it is critical that we not change the slot's state here.)
    5569              :      */
    5570        23458 :     tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
    5571        23458 :                                         slot->tts_values,
    5572        23458 :                                         slot->tts_isnull);
    5573        23458 :     dtuple = tuple->t_data;
    5574              : 
    5575              :     /*
    5576              :      * Label the datum with the composite type info we identified before.
    5577              :      *
    5578              :      * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
    5579              :      * the tuple build step; but that seems a tad risky so let's not.)
    5580              :      */
    5581        23458 :     HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
    5582        23458 :     HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
    5583              : 
    5584        23458 :     *op->resvalue = PointerGetDatum(dtuple);
    5585        23458 :     *op->resnull = false;
    5586              : }
    5587              : 
    5588              : void
    5589      3793552 : ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
    5590              :                TupleTableSlot *slot)
    5591              : {
    5592              :     Datum       d;
    5593              : 
    5594              :     /* OLD/NEW system attribute is NULL if OLD/NEW row is NULL */
    5595      3793552 :     if ((op->d.var.varreturningtype == VAR_RETURNING_OLD &&
    5596          114 :          state->flags & EEO_FLAG_OLD_IS_NULL) ||
    5597      3793510 :         (op->d.var.varreturningtype == VAR_RETURNING_NEW &&
    5598          114 :          state->flags & EEO_FLAG_NEW_IS_NULL))
    5599              :     {
    5600           78 :         *op->resvalue = (Datum) 0;
    5601           78 :         *op->resnull = true;
    5602           78 :         return;
    5603              :     }
    5604              : 
    5605              :     /* slot_getsysattr has sufficient defenses against bad attnums */
    5606      3793474 :     d = slot_getsysattr(slot,
    5607              :                         op->d.var.attnum,
    5608              :                         op->resnull);
    5609      3793468 :     *op->resvalue = d;
    5610              :     /* this ought to be unreachable, but it's cheap enough to check */
    5611      3793468 :     if (unlikely(*op->resnull))
    5612            0 :         elog(ERROR, "failed to fetch attribute from slot");
    5613              : }
    5614              : 
    5615              : /*
    5616              :  * Transition value has not been initialized. This is the first non-NULL input
    5617              :  * value for a group. We use it as the initial value for transValue.
    5618              :  */
    5619              : void
    5620        30859 : ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
    5621              :                  ExprContext *aggcontext)
    5622              : {
    5623        30859 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    5624              :     MemoryContext oldContext;
    5625              : 
    5626              :     /*
    5627              :      * We must copy the datum into aggcontext if it is pass-by-ref. We do not
    5628              :      * need to pfree the old transValue, since it's NULL.  (We already checked
    5629              :      * that the agg's input type is binary-compatible with its transtype, so
    5630              :      * straight copy here is OK.)
    5631              :      */
    5632        30859 :     oldContext = MemoryContextSwitchTo(aggcontext->ecxt_per_tuple_memory);
    5633        61718 :     pergroup->transValue = datumCopy(fcinfo->args[1].value,
    5634        30859 :                                      pertrans->transtypeByVal,
    5635        30859 :                                      pertrans->transtypeLen);
    5636        30859 :     pergroup->transValueIsNull = false;
    5637        30859 :     pergroup->noTransValue = false;
    5638        30859 :     MemoryContextSwitchTo(oldContext);
    5639        30859 : }
    5640              : 
    5641              : /*
    5642              :  * Ensure that the new transition value is stored in the aggcontext,
    5643              :  * rather than the per-tuple context.  This should be invoked only when
    5644              :  * we know (a) the transition data type is pass-by-reference, and (b)
    5645              :  * the newValue is distinct from the oldValue.
    5646              :  *
    5647              :  * NB: This can change the current memory context.
    5648              :  *
    5649              :  * We copy the presented newValue into the aggcontext, except when the datum
    5650              :  * points to a R/W expanded object that is already a child of the aggcontext,
    5651              :  * in which case we need not copy.  We then delete the oldValue, if not null.
    5652              :  *
    5653              :  * If the presented datum points to a R/W expanded object that is a child of
    5654              :  * some other context, ideally we would just reparent it under the aggcontext.
    5655              :  * Unfortunately, that doesn't work easily, and it wouldn't help anyway for
    5656              :  * aggregate-aware transfns.  We expect that a transfn that deals in expanded
    5657              :  * objects and is aware of the memory management conventions for aggregate
    5658              :  * transition values will (1) on first call, return a R/W expanded object that
    5659              :  * is already in the right context, allowing us to do nothing here, and (2) on
    5660              :  * subsequent calls, modify and return that same object, so that control
    5661              :  * doesn't even reach here.  However, if we have a generic transfn that
    5662              :  * returns a new R/W expanded object (probably in the per-tuple context),
    5663              :  * reparenting that result would cause problems.  We'd pass that R/W object to
    5664              :  * the next invocation of the transfn, and then it would be at liberty to
    5665              :  * change or delete that object, and if it deletes it then our own attempt to
    5666              :  * delete the now-old transvalue afterwards would be a double free.  We avoid
    5667              :  * this problem by forcing the stored transvalue to always be a flat
    5668              :  * non-expanded object unless the transfn is visibly doing aggregate-aware
    5669              :  * memory management.  This is somewhat inefficient, but the best answer to
    5670              :  * that is to write a smarter transfn.
    5671              :  */
    5672              : Datum
    5673        32330 : ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
    5674              :                       Datum newValue, bool newValueIsNull,
    5675              :                       Datum oldValue, bool oldValueIsNull)
    5676              : {
    5677              :     Assert(newValue != oldValue);
    5678              : 
    5679        32330 :     if (!newValueIsNull)
    5680              :     {
    5681        32330 :         MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
    5682        32330 :         if (DatumIsReadWriteExpandedObject(newValue,
    5683              :                                            false,
    5684        31733 :                                            pertrans->transtypeLen) &&
    5685           84 :             MemoryContextGetParent(DatumGetEOHP(newValue)->eoh_context) == CurrentMemoryContext)
    5686              :              /* do nothing */ ;
    5687              :         else
    5688        32327 :             newValue = datumCopy(newValue,
    5689        32327 :                                  pertrans->transtypeByVal,
    5690        32327 :                                  pertrans->transtypeLen);
    5691              :     }
    5692              :     else
    5693              :     {
    5694              :         /*
    5695              :          * Ensure that AggStatePerGroup->transValue ends up being 0, so
    5696              :          * callers can safely compare newValue/oldValue without having to
    5697              :          * check their respective nullness.
    5698              :          */
    5699            0 :         newValue = (Datum) 0;
    5700              :     }
    5701              : 
    5702        32330 :     if (!oldValueIsNull)
    5703              :     {
    5704        32273 :         if (DatumIsReadWriteExpandedObject(oldValue,
    5705              :                                            false,
    5706              :                                            pertrans->transtypeLen))
    5707            0 :             DeleteExpandedObject(oldValue);
    5708              :         else
    5709        32273 :             pfree(DatumGetPointer(oldValue));
    5710              :     }
    5711              : 
    5712        32330 :     return newValue;
    5713              : }
    5714              : 
    5715              : /*
    5716              :  * ExecEvalPreOrderedDistinctSingle
    5717              :  *      Returns true when the aggregate transition value Datum is distinct
    5718              :  *      from the previous input Datum and returns false when the input Datum
    5719              :  *      matches the previous input Datum.
    5720              :  */
    5721              : bool
    5722       182861 : ExecEvalPreOrderedDistinctSingle(AggState *aggstate, AggStatePerTrans pertrans)
    5723              : {
    5724       182861 :     Datum       value = pertrans->transfn_fcinfo->args[1].value;
    5725       182861 :     bool        isnull = pertrans->transfn_fcinfo->args[1].isnull;
    5726              : 
    5727       182861 :     if (!pertrans->haslast ||
    5728       173730 :         pertrans->lastisnull != isnull ||
    5729       173715 :         (!isnull && !DatumGetBool(FunctionCall2Coll(&pertrans->equalfnOne,
    5730              :                                                     pertrans->aggCollation,
    5731              :                                                     pertrans->lastdatum, value))))
    5732              :     {
    5733        50976 :         if (pertrans->haslast && !pertrans->inputtypeByVal &&
    5734        12991 :             !pertrans->lastisnull)
    5735        12991 :             pfree(DatumGetPointer(pertrans->lastdatum));
    5736              : 
    5737        50976 :         pertrans->haslast = true;
    5738        50976 :         if (!isnull)
    5739              :         {
    5740              :             MemoryContext oldContext;
    5741              : 
    5742        50958 :             oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
    5743              : 
    5744       101916 :             pertrans->lastdatum = datumCopy(value, pertrans->inputtypeByVal,
    5745        50958 :                                             pertrans->inputtypeLen);
    5746              : 
    5747        50958 :             MemoryContextSwitchTo(oldContext);
    5748              :         }
    5749              :         else
    5750           18 :             pertrans->lastdatum = (Datum) 0;
    5751        50976 :         pertrans->lastisnull = isnull;
    5752        50976 :         return true;
    5753              :     }
    5754              : 
    5755       131885 :     return false;
    5756              : }
    5757              : 
    5758              : /*
    5759              :  * ExecEvalPreOrderedDistinctMulti
    5760              :  *      Returns true when the aggregate input is distinct from the previous
    5761              :  *      input and returns false when the input matches the previous input, or
    5762              :  *      when there was no previous input.
    5763              :  */
    5764              : bool
    5765          360 : ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans)
    5766              : {
    5767          360 :     ExprContext *tmpcontext = aggstate->tmpcontext;
    5768          360 :     bool        isdistinct = false; /* for now */
    5769              :     TupleTableSlot *save_outer;
    5770              :     TupleTableSlot *save_inner;
    5771              : 
    5772         1410 :     for (int i = 0; i < pertrans->numTransInputs; i++)
    5773              :     {
    5774         1050 :         pertrans->sortslot->tts_values[i] = pertrans->transfn_fcinfo->args[i + 1].value;
    5775         1050 :         pertrans->sortslot->tts_isnull[i] = pertrans->transfn_fcinfo->args[i + 1].isnull;
    5776              :     }
    5777              : 
    5778          360 :     ExecClearTuple(pertrans->sortslot);
    5779          360 :     pertrans->sortslot->tts_nvalid = pertrans->numInputs;
    5780          360 :     ExecStoreVirtualTuple(pertrans->sortslot);
    5781              : 
    5782              :     /* save the previous slots before we overwrite them */
    5783          360 :     save_outer = tmpcontext->ecxt_outertuple;
    5784          360 :     save_inner = tmpcontext->ecxt_innertuple;
    5785              : 
    5786          360 :     tmpcontext->ecxt_outertuple = pertrans->sortslot;
    5787          360 :     tmpcontext->ecxt_innertuple = pertrans->uniqslot;
    5788              : 
    5789          360 :     if (!pertrans->haslast ||
    5790          312 :         !ExecQual(pertrans->equalfnMulti, tmpcontext))
    5791              :     {
    5792          156 :         if (pertrans->haslast)
    5793          108 :             ExecClearTuple(pertrans->uniqslot);
    5794              : 
    5795          156 :         pertrans->haslast = true;
    5796          156 :         ExecCopySlot(pertrans->uniqslot, pertrans->sortslot);
    5797              : 
    5798          156 :         isdistinct = true;
    5799              :     }
    5800              : 
    5801              :     /* restore the original slots */
    5802          360 :     tmpcontext->ecxt_outertuple = save_outer;
    5803          360 :     tmpcontext->ecxt_innertuple = save_inner;
    5804              : 
    5805          360 :     return isdistinct;
    5806              : }
    5807              : 
    5808              : /*
    5809              :  * Invoke ordered transition function, with a datum argument.
    5810              :  */
    5811              : void
    5812       422259 : ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op,
    5813              :                              ExprContext *econtext)
    5814              : {
    5815       422259 :     AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    5816       422259 :     int         setno = op->d.agg_trans.setno;
    5817              : 
    5818       422259 :     tuplesort_putdatum(pertrans->sortstates[setno],
    5819       422259 :                        *op->resvalue, *op->resnull);
    5820       422259 : }
    5821              : 
    5822              : /*
    5823              :  * Invoke ordered transition function, with a tuple argument.
    5824              :  */
    5825              : void
    5826          108 : ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
    5827              :                              ExprContext *econtext)
    5828              : {
    5829          108 :     AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    5830          108 :     int         setno = op->d.agg_trans.setno;
    5831              : 
    5832          108 :     ExecClearTuple(pertrans->sortslot);
    5833          108 :     pertrans->sortslot->tts_nvalid = pertrans->numInputs;
    5834          108 :     ExecStoreVirtualTuple(pertrans->sortslot);
    5835          108 :     tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
    5836          108 : }
    5837              : 
    5838              : /* implementation of transition function invocation for byval types */
    5839              : static pg_attribute_always_inline void
    5840     16620868 : ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
    5841              :                        AggStatePerGroup pergroup,
    5842              :                        ExprContext *aggcontext, int setno)
    5843              : {
    5844     16620868 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    5845              :     MemoryContext oldContext;
    5846              :     Datum       newVal;
    5847              : 
    5848              :     /* cf. select_current_set() */
    5849     16620868 :     aggstate->curaggcontext = aggcontext;
    5850     16620868 :     aggstate->current_set = setno;
    5851              : 
    5852              :     /* set up aggstate->curpertrans for AggGetAggref() */
    5853     16620868 :     aggstate->curpertrans = pertrans;
    5854              : 
    5855              :     /* invoke transition function in per-tuple context */
    5856     16620868 :     oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    5857              : 
    5858     16620868 :     fcinfo->args[0].value = pergroup->transValue;
    5859     16620868 :     fcinfo->args[0].isnull = pergroup->transValueIsNull;
    5860     16620868 :     fcinfo->isnull = false;      /* just in case transfn doesn't set it */
    5861              : 
    5862     16620868 :     newVal = FunctionCallInvoke(fcinfo);
    5863              : 
    5864     16620832 :     pergroup->transValue = newVal;
    5865     16620832 :     pergroup->transValueIsNull = fcinfo->isnull;
    5866              : 
    5867     16620832 :     MemoryContextSwitchTo(oldContext);
    5868     16620832 : }
    5869              : 
    5870              : /* implementation of transition function invocation for byref types */
    5871              : static pg_attribute_always_inline void
    5872      1449677 : ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
    5873              :                        AggStatePerGroup pergroup,
    5874              :                        ExprContext *aggcontext, int setno)
    5875              : {
    5876      1449677 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    5877              :     MemoryContext oldContext;
    5878              :     Datum       newVal;
    5879              : 
    5880              :     /* cf. select_current_set() */
    5881      1449677 :     aggstate->curaggcontext = aggcontext;
    5882      1449677 :     aggstate->current_set = setno;
    5883              : 
    5884              :     /* set up aggstate->curpertrans for AggGetAggref() */
    5885      1449677 :     aggstate->curpertrans = pertrans;
    5886              : 
    5887              :     /* invoke transition function in per-tuple context */
    5888      1449677 :     oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    5889              : 
    5890      1449677 :     fcinfo->args[0].value = pergroup->transValue;
    5891      1449677 :     fcinfo->args[0].isnull = pergroup->transValueIsNull;
    5892      1449677 :     fcinfo->isnull = false;      /* just in case transfn doesn't set it */
    5893              : 
    5894      1449677 :     newVal = FunctionCallInvoke(fcinfo);
    5895              : 
    5896              :     /*
    5897              :      * For pass-by-ref datatype, must copy the new value into aggcontext and
    5898              :      * free the prior transValue.  But if transfn returned a pointer to its
    5899              :      * first input, we don't need to do anything.
    5900              :      *
    5901              :      * It's safe to compare newVal with pergroup->transValue without regard
    5902              :      * for either being NULL, because ExecAggCopyTransValue takes care to set
    5903              :      * transValue to 0 when NULL. Otherwise we could end up accidentally not
    5904              :      * reparenting, when the transValue has the same numerical value as
    5905              :      * newValue, despite being NULL.  This is a somewhat hot path, making it
    5906              :      * undesirable to instead solve this with another branch for the common
    5907              :      * case of the transition function returning its (modified) input
    5908              :      * argument.
    5909              :      */
    5910      1449674 :     if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
    5911        20366 :         newVal = ExecAggCopyTransValue(aggstate, pertrans,
    5912        20366 :                                        newVal, fcinfo->isnull,
    5913              :                                        pergroup->transValue,
    5914        20366 :                                        pergroup->transValueIsNull);
    5915              : 
    5916      1449674 :     pergroup->transValue = newVal;
    5917      1449674 :     pergroup->transValueIsNull = fcinfo->isnull;
    5918              : 
    5919      1449674 :     MemoryContextSwitchTo(oldContext);
    5920      1449674 : }
        

Generated by: LCOV version 2.0-1