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

Generated by: LCOV version 1.14