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

Generated by: LCOV version 1.14