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

Generated by: LCOV version 1.14