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

Generated by: LCOV version 2.0-1