LCOV - code coverage report
Current view: top level - src/backend/executor - execExprInterp.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 1913 2043 93.6 %
Date: 2025-02-22 07:14:56 Functions: 81 83 97.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14