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

Generated by: LCOV version 1.14