LCOV - code coverage report
Current view: top level - src/backend/executor - execExprInterp.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 1690 1787 94.6 %
Date: 2024-05-09 19:10:57 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     2220960 : ExecReadyInterpretedExpr(ExprState *state)
     237             : {
     238             :     /* Ensure one-time interpreter setup has been done */
     239     2220960 :     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     2220960 :     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     2220960 :     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     2220960 :     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     2220960 :     if (state->steps_len == 3)
     277             :     {
     278      397840 :         ExprEvalOp  step0 = state->steps[0].opcode;
     279      397840 :         ExprEvalOp  step1 = state->steps[1].opcode;
     280             : 
     281      397840 :         if (step0 == EEOP_INNER_FETCHSOME &&
     282             :             step1 == EEOP_INNER_VAR)
     283             :         {
     284        6818 :             state->evalfunc_private = (void *) ExecJustInnerVar;
     285        6818 :             return;
     286             :         }
     287      391022 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     288             :                  step1 == EEOP_OUTER_VAR)
     289             :         {
     290       30362 :             state->evalfunc_private = (void *) ExecJustOuterVar;
     291       30362 :             return;
     292             :         }
     293      360660 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     294             :                  step1 == EEOP_SCAN_VAR)
     295             :         {
     296       23120 :             state->evalfunc_private = (void *) ExecJustScanVar;
     297       23120 :             return;
     298             :         }
     299      337540 :         else if (step0 == EEOP_INNER_FETCHSOME &&
     300             :                  step1 == EEOP_ASSIGN_INNER_VAR)
     301             :         {
     302        6362 :             state->evalfunc_private = (void *) ExecJustAssignInnerVar;
     303        6362 :             return;
     304             :         }
     305      331178 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     306             :                  step1 == EEOP_ASSIGN_OUTER_VAR)
     307             :         {
     308        7852 :             state->evalfunc_private = (void *) ExecJustAssignOuterVar;
     309        7852 :             return;
     310             :         }
     311      323326 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     312             :                  step1 == EEOP_ASSIGN_SCAN_VAR)
     313             :         {
     314       38860 :             state->evalfunc_private = (void *) ExecJustAssignScanVar;
     315       38860 :             return;
     316             :         }
     317      284466 :         else if (step0 == EEOP_CASE_TESTVAL &&
     318         554 :                  step1 == EEOP_FUNCEXPR_STRICT &&
     319         554 :                  state->steps[0].d.casetest.value)
     320             :         {
     321         356 :             state->evalfunc_private = (void *) ExecJustApplyFuncToCase;
     322         356 :             return;
     323             :         }
     324             :     }
     325     1823120 :     else if (state->steps_len == 2)
     326             :     {
     327      862070 :         ExprEvalOp  step0 = state->steps[0].opcode;
     328             : 
     329      862070 :         if (step0 == EEOP_CONST)
     330             :         {
     331      343092 :             state->evalfunc_private = (void *) ExecJustConst;
     332      343092 :             return;
     333             :         }
     334      518978 :         else if (step0 == EEOP_INNER_VAR)
     335             :         {
     336         452 :             state->evalfunc_private = (void *) ExecJustInnerVarVirt;
     337         452 :             return;
     338             :         }
     339      518526 :         else if (step0 == EEOP_OUTER_VAR)
     340             :         {
     341       51836 :             state->evalfunc_private = (void *) ExecJustOuterVarVirt;
     342       51836 :             return;
     343             :         }
     344      466690 :         else if (step0 == EEOP_SCAN_VAR)
     345             :         {
     346          72 :             state->evalfunc_private = (void *) ExecJustScanVarVirt;
     347          72 :             return;
     348             :         }
     349      466618 :         else if (step0 == EEOP_ASSIGN_INNER_VAR)
     350             :         {
     351         306 :             state->evalfunc_private = (void *) ExecJustAssignInnerVarVirt;
     352         306 :             return;
     353             :         }
     354      466312 :         else if (step0 == EEOP_ASSIGN_OUTER_VAR)
     355             :         {
     356        3578 :             state->evalfunc_private = (void *) ExecJustAssignOuterVarVirt;
     357        3578 :             return;
     358             :         }
     359      462734 :         else if (step0 == EEOP_ASSIGN_SCAN_VAR)
     360             :         {
     361        4004 :             state->evalfunc_private = (void *) ExecJustAssignScanVarVirt;
     362        4004 :             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    11177840 :     for (int off = 0; off < state->steps_len; off++)
     373             :     {
     374     9473950 :         ExprEvalStep *op = &state->steps[off];
     375             : 
     376     9473950 :         op->opcode = EEO_OPCODE(op->opcode);
     377             :     }
     378             : 
     379     1703890 :     state->flags |= EEO_FLAG_DIRECT_THREADED;
     380             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     381             : 
     382     1703890 :     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   132375906 : 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   132375906 :     if (unlikely(state == NULL))
     515       18030 :         return PointerGetDatum(dispatch_table);
     516             : #else
     517             :     Assert(state != NULL);
     518             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     519             : 
     520             :     /* setup state */
     521   132357876 :     op = state->steps;
     522   132357876 :     resultslot = state->resultslot;
     523   132357876 :     innerslot = econtext->ecxt_innertuple;
     524   132357876 :     outerslot = econtext->ecxt_outertuple;
     525   132357876 :     scanslot = econtext->ecxt_scantuple;
     526             : 
     527             : #if defined(EEO_USE_COMPUTED_GOTO)
     528   132357876 :     EEO_DISPATCH();
     529             : #endif
     530             : 
     531             :     EEO_SWITCH()
     532             :     {
     533   132340278 :         EEO_CASE(EEOP_DONE)
     534             :         {
     535   132340278 :             goto out;
     536             :         }
     537             : 
     538    26074638 :         EEO_CASE(EEOP_INNER_FETCHSOME)
     539             :         {
     540    26074638 :             CheckOpSlotCompatibility(op, innerslot);
     541             : 
     542    26074638 :             slot_getsomeattrs(innerslot, op->d.fetch.last_var);
     543             : 
     544    26074638 :             EEO_NEXT();
     545             :         }
     546             : 
     547    25251506 :         EEO_CASE(EEOP_OUTER_FETCHSOME)
     548             :         {
     549    25251506 :             CheckOpSlotCompatibility(op, outerslot);
     550             : 
     551    25251506 :             slot_getsomeattrs(outerslot, op->d.fetch.last_var);
     552             : 
     553    25251506 :             EEO_NEXT();
     554             :         }
     555             : 
     556    63111648 :         EEO_CASE(EEOP_SCAN_FETCHSOME)
     557             :         {
     558    63111648 :             CheckOpSlotCompatibility(op, scanslot);
     559             : 
     560    63111648 :             slot_getsomeattrs(scanslot, op->d.fetch.last_var);
     561             : 
     562    63111648 :             EEO_NEXT();
     563             :         }
     564             : 
     565    25157606 :         EEO_CASE(EEOP_INNER_VAR)
     566             :         {
     567    25157606 :             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    25157606 :             *op->resvalue = innerslot->tts_values[attnum];
     577    25157606 :             *op->resnull = innerslot->tts_isnull[attnum];
     578             : 
     579    25157606 :             EEO_NEXT();
     580             :         }
     581             : 
     582    43300420 :         EEO_CASE(EEOP_OUTER_VAR)
     583             :         {
     584    43300420 :             int         attnum = op->d.var.attnum;
     585             : 
     586             :             /* See EEOP_INNER_VAR comments */
     587             : 
     588             :             Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
     589    43300420 :             *op->resvalue = outerslot->tts_values[attnum];
     590    43300420 :             *op->resnull = outerslot->tts_isnull[attnum];
     591             : 
     592    43300420 :             EEO_NEXT();
     593             :         }
     594             : 
     595    65450858 :         EEO_CASE(EEOP_SCAN_VAR)
     596             :         {
     597    65450858 :             int         attnum = op->d.var.attnum;
     598             : 
     599             :             /* See EEOP_INNER_VAR comments */
     600             : 
     601             :             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
     602    65450858 :             *op->resvalue = scanslot->tts_values[attnum];
     603    65450858 :             *op->resnull = scanslot->tts_isnull[attnum];
     604             : 
     605    65450858 :             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     6528564 :         EEO_CASE(EEOP_SCAN_SYSVAR)
     621             :         {
     622     6528564 :             ExecEvalSysVar(state, op, econtext, scanslot);
     623     6528552 :             EEO_NEXT();
     624             :         }
     625             : 
     626       37200 :         EEO_CASE(EEOP_WHOLEROW)
     627             :         {
     628             :             /* too complex for an inline implementation */
     629       37200 :             ExecEvalWholeRowVar(state, op, econtext);
     630             : 
     631       37200 :             EEO_NEXT();
     632             :         }
     633             : 
     634     7128258 :         EEO_CASE(EEOP_ASSIGN_INNER_VAR)
     635             :         {
     636     7128258 :             int         resultnum = op->d.assign_var.resultnum;
     637     7128258 :             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     7128258 :             resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
     646     7128258 :             resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
     647             : 
     648     7128258 :             EEO_NEXT();
     649             :         }
     650             : 
     651    23984296 :         EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
     652             :         {
     653    23984296 :             int         resultnum = op->d.assign_var.resultnum;
     654    23984296 :             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    23984296 :             resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
     663    23984296 :             resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
     664             : 
     665    23984296 :             EEO_NEXT();
     666             :         }
     667             : 
     668    58056496 :         EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
     669             :         {
     670    58056496 :             int         resultnum = op->d.assign_var.resultnum;
     671    58056496 :             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    58056496 :             resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
     680    58056496 :             resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
     681             : 
     682    58056496 :             EEO_NEXT();
     683             :         }
     684             : 
     685    29082346 :         EEO_CASE(EEOP_ASSIGN_TMP)
     686             :         {
     687    29082346 :             int         resultnum = op->d.assign_tmp.resultnum;
     688             : 
     689             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     690    29082346 :             resultslot->tts_values[resultnum] = state->resvalue;
     691    29082346 :             resultslot->tts_isnull[resultnum] = state->resnull;
     692             : 
     693    29082346 :             EEO_NEXT();
     694             :         }
     695             : 
     696    10066552 :         EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
     697             :         {
     698    10066552 :             int         resultnum = op->d.assign_tmp.resultnum;
     699             : 
     700             :             Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
     701    10066552 :             resultslot->tts_isnull[resultnum] = state->resnull;
     702    10066552 :             if (!resultslot->tts_isnull[resultnum])
     703     6979346 :                 resultslot->tts_values[resultnum] =
     704     6979346 :                     MakeExpandedObjectReadOnlyInternal(state->resvalue);
     705             :             else
     706     3087206 :                 resultslot->tts_values[resultnum] = state->resvalue;
     707             : 
     708    10066552 :             EEO_NEXT();
     709             :         }
     710             : 
     711    22450100 :         EEO_CASE(EEOP_CONST)
     712             :         {
     713    22450100 :             *op->resnull = op->d.constval.isnull;
     714    22450100 :             *op->resvalue = op->d.constval.value;
     715             : 
     716    22450100 :             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     1625724 :         EEO_CASE(EEOP_FUNCEXPR)
     735             :         {
     736     1625724 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     737             :             Datum       d;
     738             : 
     739     1625724 :             fcinfo->isnull = false;
     740     1625724 :             d = op->d.func.fn_addr(fcinfo);
     741     1615824 :             *op->resvalue = d;
     742     1615824 :             *op->resnull = fcinfo->isnull;
     743             : 
     744     1615824 :             EEO_NEXT();
     745             :         }
     746             : 
     747    88357528 :         EEO_CASE(EEOP_FUNCEXPR_STRICT)
     748             :         {
     749    88357528 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     750    88357528 :             NullableDatum *args = fcinfo->args;
     751    88357528 :             int         nargs = op->d.func.nargs;
     752             :             Datum       d;
     753             : 
     754             :             /* strict function, so check for NULL args */
     755   251534358 :             for (int argno = 0; argno < nargs; argno++)
     756             :             {
     757   164254128 :                 if (args[argno].isnull)
     758             :                 {
     759     1077298 :                     *op->resnull = true;
     760     1077298 :                     goto strictfail;
     761             :                 }
     762             :             }
     763    87280230 :             fcinfo->isnull = false;
     764    87280230 :             d = op->d.func.fn_addr(fcinfo);
     765    87273842 :             *op->resvalue = d;
     766    87273842 :             *op->resnull = fcinfo->isnull;
     767             : 
     768    88351140 :     strictfail:
     769    88351140 :             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     1051708 :         EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
     799             :         {
     800     1051708 :             *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     1188818 :         EEO_CASE(EEOP_BOOL_AND_STEP)
     811             :         {
     812     1188818 :             if (*op->resnull)
     813             :             {
     814        1216 :                 *op->d.boolexpr.anynull = true;
     815             :             }
     816     1187602 :             else if (!DatumGetBool(*op->resvalue))
     817             :             {
     818             :                 /* result is already set to FALSE, need not change it */
     819             :                 /* bail out early */
     820      801316 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
     821             :             }
     822             : 
     823      387502 :             EEO_NEXT();
     824             :         }
     825             : 
     826      250392 :         EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
     827             :         {
     828      250392 :             if (*op->resnull)
     829             :             {
     830             :                 /* result is already set to NULL, need not change it */
     831             :             }
     832      249514 :             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      183248 :             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      250392 :             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     3456430 :         EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
     866             :         {
     867     3456430 :             *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     6849692 :         EEO_CASE(EEOP_BOOL_OR_STEP)
     878             :         {
     879     6849692 :             if (*op->resnull)
     880             :             {
     881      163054 :                 *op->d.boolexpr.anynull = true;
     882             :             }
     883     6686638 :             else if (DatumGetBool(*op->resvalue))
     884             :             {
     885             :                 /* result is already set to TRUE, need not change it */
     886             :                 /* bail out early */
     887      399830 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
     888             :             }
     889             : 
     890     6449862 :             EEO_NEXT();
     891             :         }
     892             : 
     893     3056600 :         EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
     894             :         {
     895     3056600 :             if (*op->resnull)
     896             :             {
     897             :                 /* result is already set to NULL, need not change it */
     898             :             }
     899     2959320 :             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     2888974 :             else if (*op->d.boolexpr.anynull)
     910             :             {
     911        6308 :                 *op->resvalue = (Datum) 0;
     912        6308 :                 *op->resnull = true;
     913             :             }
     914             :             else
     915             :             {
     916             :                 /* result is already set to FALSE, need not change it */
     917             :             }
     918             : 
     919     3056600 :             EEO_NEXT();
     920             :         }
     921             : 
     922     1835654 :         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     1835654 :             *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
     931             : 
     932     1835654 :             EEO_NEXT();
     933             :         }
     934             : 
     935    67904224 :         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    67904224 :             if (*op->resnull ||
     941    67038938 :                 !DatumGetBool(*op->resvalue))
     942             :             {
     943             :                 /* ... bail out early, returning FALSE */
     944    29306022 :                 *op->resnull = false;
     945    29306022 :                 *op->resvalue = BoolGetDatum(false);
     946    29306022 :                 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    38598202 :             EEO_NEXT();
     955             :         }
     956             : 
     957      325072 :         EEO_CASE(EEOP_JUMP)
     958             :         {
     959             :             /* Unconditionally jump to target step */
     960      325072 :             EEO_JUMP(op->d.jump.jumpdone);
     961             :         }
     962             : 
     963      630446 :         EEO_CASE(EEOP_JUMP_IF_NULL)
     964             :         {
     965             :             /* Transfer control if current result is null */
     966      630446 :             if (*op->resnull)
     967        3590 :                 EEO_JUMP(op->d.jump.jumpdone);
     968             : 
     969      626856 :             EEO_NEXT();
     970             :         }
     971             : 
     972      263996 :         EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
     973             :         {
     974             :             /* Transfer control if current result is non-null */
     975      263996 :             if (!*op->resnull)
     976      192320 :                 EEO_JUMP(op->d.jump.jumpdone);
     977             : 
     978       71676 :             EEO_NEXT();
     979             :         }
     980             : 
     981     2048650 :         EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
     982             :         {
     983             :             /* Transfer control if current result is null or false */
     984     2048650 :             if (*op->resnull || !DatumGetBool(*op->resvalue))
     985     1606858 :                 EEO_JUMP(op->d.jump.jumpdone);
     986             : 
     987      441792 :             EEO_NEXT();
     988             :         }
     989             : 
     990      899478 :         EEO_CASE(EEOP_NULLTEST_ISNULL)
     991             :         {
     992      899478 :             *op->resvalue = BoolGetDatum(*op->resnull);
     993      899478 :             *op->resnull = false;
     994             : 
     995      899478 :             EEO_NEXT();
     996             :         }
     997             : 
     998     3165512 :         EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
     999             :         {
    1000     3165512 :             *op->resvalue = BoolGetDatum(!*op->resnull);
    1001     3165512 :             *op->resnull = false;
    1002             : 
    1003     3165512 :             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       77574 :         EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
    1025             :         {
    1026       77574 :             if (*op->resnull)
    1027             :             {
    1028       76834 :                 *op->resvalue = BoolGetDatum(false);
    1029       76834 :                 *op->resnull = false;
    1030             :             }
    1031             :             /* else, input value is the correct output as well */
    1032             : 
    1033       77574 :             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     3911104 :         EEO_CASE(EEOP_PARAM_EXEC)
    1075             :         {
    1076             :             /* out of line implementation: too large */
    1077     3911104 :             ExecEvalParamExec(state, op, econtext);
    1078             : 
    1079     3911086 :             EEO_NEXT();
    1080             :         }
    1081             : 
    1082      501958 :         EEO_CASE(EEOP_PARAM_EXTERN)
    1083             :         {
    1084             :             /* out of line implementation: too large */
    1085      501958 :             ExecEvalParamExtern(state, op, econtext);
    1086      501958 :             EEO_NEXT();
    1087             :         }
    1088             : 
    1089      330034 :         EEO_CASE(EEOP_PARAM_CALLBACK)
    1090             :         {
    1091             :             /* allow an extension module to supply a PARAM_EXTERN value */
    1092      330034 :             op->d.cparam.paramfunc(state, op, econtext);
    1093      330028 :             EEO_NEXT();
    1094             :         }
    1095             : 
    1096       50560 :         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       50560 :             if (op->d.casetest.value)
    1108             :             {
    1109       44094 :                 *op->resvalue = *op->d.casetest.value;
    1110       44094 :                 *op->resnull = *op->d.casetest.isnull;
    1111             :             }
    1112             :             else
    1113             :             {
    1114        6466 :                 *op->resvalue = econtext->caseValue_datum;
    1115        6466 :                 *op->resnull = econtext->caseValue_isNull;
    1116             :             }
    1117             : 
    1118       50560 :             EEO_NEXT();
    1119             :         }
    1120             : 
    1121       73586 :         EEO_CASE(EEOP_DOMAIN_TESTVAL)
    1122             :         {
    1123             :             /*
    1124             :              * See EEOP_CASE_TESTVAL comment.
    1125             :              */
    1126       73586 :             if (op->d.casetest.value)
    1127             :             {
    1128       12632 :                 *op->resvalue = *op->d.casetest.value;
    1129       12632 :                 *op->resnull = *op->d.casetest.isnull;
    1130             :             }
    1131             :             else
    1132             :             {
    1133       60954 :                 *op->resvalue = econtext->domainValue_datum;
    1134       60954 :                 *op->resnull = econtext->domainValue_isNull;
    1135             :             }
    1136             : 
    1137       73586 :             EEO_NEXT();
    1138             :         }
    1139             : 
    1140        4612 :         EEO_CASE(EEOP_MAKE_READONLY)
    1141             :         {
    1142             :             /*
    1143             :              * Force a varlena value that might be read multiple times to R/O
    1144             :              */
    1145        4612 :             if (!*op->d.make_readonly.isnull)
    1146        4542 :                 *op->resvalue =
    1147        4542 :                     MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
    1148        4612 :             *op->resnull = *op->d.make_readonly.isnull;
    1149             : 
    1150        4612 :             EEO_NEXT();
    1151             :         }
    1152             : 
    1153     5599186 :         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     5599186 :             if (*op->resnull)
    1167             :             {
    1168             :                 /* output functions are not called on nulls */
    1169       61296 :                 str = NULL;
    1170             :             }
    1171             :             else
    1172             :             {
    1173             :                 FunctionCallInfo fcinfo_out;
    1174             : 
    1175     5537890 :                 fcinfo_out = op->d.iocoerce.fcinfo_data_out;
    1176     5537890 :                 fcinfo_out->args[0].value = *op->resvalue;
    1177     5537890 :                 fcinfo_out->args[0].isnull = false;
    1178             : 
    1179     5537890 :                 fcinfo_out->isnull = false;
    1180     5537890 :                 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     5599186 :             if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
    1188             :             {
    1189             :                 FunctionCallInfo fcinfo_in;
    1190             :                 Datum       d;
    1191             : 
    1192     5538000 :                 fcinfo_in = op->d.iocoerce.fcinfo_data_in;
    1193     5538000 :                 fcinfo_in->args[0].value = PointerGetDatum(str);
    1194     5538000 :                 fcinfo_in->args[0].isnull = *op->resnull;
    1195             :                 /* second and third arguments are already set up */
    1196             : 
    1197     5538000 :                 fcinfo_in->isnull = false;
    1198     5538000 :                 d = FunctionCallInvoke(fcinfo_in);
    1199     5537948 :                 *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     5599134 :             EEO_NEXT();
    1215             :         }
    1216             : 
    1217         834 :         EEO_CASE(EEOP_IOCOERCE_SAFE)
    1218             :         {
    1219         834 :             ExecEvalCoerceViaIOSafe(state, op);
    1220         834 :             EEO_NEXT();
    1221             :         }
    1222             : 
    1223     1052740 :         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     1052740 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1235             : 
    1236             :             /* check function arguments for NULLness */
    1237     1052740 :             if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
    1238             :             {
    1239             :                 /* Both NULL? Then is not distinct... */
    1240      990256 :                 *op->resvalue = BoolGetDatum(false);
    1241      990256 :                 *op->resnull = false;
    1242             :             }
    1243       62484 :             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       62200 :                 fcinfo->isnull = false;
    1255       62200 :                 eqresult = op->d.func.fn_addr(fcinfo);
    1256             :                 /* Must invert result of "="; safe to do even if null */
    1257       62200 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
    1258       62200 :                 *op->resnull = fcinfo->isnull;
    1259             :             }
    1260             : 
    1261     1052740 :             EEO_NEXT();
    1262             :         }
    1263             : 
    1264             :         /* see EEOP_DISTINCT for comments, this is just inverted */
    1265    11471632 :         EEO_CASE(EEOP_NOT_DISTINCT)
    1266             :         {
    1267    11471632 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1268             : 
    1269    11471632 :             if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
    1270             :             {
    1271       73040 :                 *op->resvalue = BoolGetDatum(true);
    1272       73040 :                 *op->resnull = false;
    1273             :             }
    1274    11398592 :             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    11398300 :                 fcinfo->isnull = false;
    1284    11398300 :                 eqresult = op->d.func.fn_addr(fcinfo);
    1285    11398300 :                 *op->resvalue = eqresult;
    1286    11398300 :                 *op->resnull = fcinfo->isnull;
    1287             :             }
    1288             : 
    1289    11471632 :             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       17830 :         EEO_CASE(EEOP_SQLVALUEFUNCTION)
    1325             :         {
    1326             :             /*
    1327             :              * Doesn't seem worthwhile to have an inline implementation
    1328             :              * efficiency-wise.
    1329             :              */
    1330       17830 :             ExecEvalSQLValueFunction(state, op);
    1331             : 
    1332       17830 :             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        1020 :         EEO_CASE(EEOP_NEXTVALUEEXPR)
    1344             :         {
    1345             :             /*
    1346             :              * Doesn't seem worthwhile to have an inline implementation
    1347             :              * efficiency-wise.
    1348             :              */
    1349        1020 :             ExecEvalNextValueExpr(state, op);
    1350             : 
    1351        1020 :             EEO_NEXT();
    1352             :         }
    1353             : 
    1354      759612 :         EEO_CASE(EEOP_ARRAYEXPR)
    1355             :         {
    1356             :             /* too complex for an inline implementation */
    1357      759612 :             ExecEvalArrayExpr(state, op);
    1358             : 
    1359      759612 :             EEO_NEXT();
    1360             :         }
    1361             : 
    1362       66092 :         EEO_CASE(EEOP_ARRAYCOERCE)
    1363             :         {
    1364             :             /* too complex for an inline implementation */
    1365       66092 :             ExecEvalArrayCoerce(state, op, econtext);
    1366             : 
    1367       66060 :             EEO_NEXT();
    1368             :         }
    1369             : 
    1370       26958 :         EEO_CASE(EEOP_ROW)
    1371             :         {
    1372             :             /* too complex for an inline implementation */
    1373       26958 :             ExecEvalRow(state, op);
    1374             : 
    1375       26958 :             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       23276 :         EEO_CASE(EEOP_MINMAX)
    1443             :         {
    1444             :             /* too complex for an inline implementation */
    1445       23276 :             ExecEvalMinMax(state, op);
    1446             : 
    1447       23276 :             EEO_NEXT();
    1448             :         }
    1449             : 
    1450       91200 :         EEO_CASE(EEOP_FIELDSELECT)
    1451             :         {
    1452             :             /* too complex for an inline implementation */
    1453       91200 :             ExecEvalFieldSelect(state, op, econtext);
    1454             : 
    1455       91200 :             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      618474 :         EEO_CASE(EEOP_SBSREF_SUBSCRIPTS)
    1475             :         {
    1476             :             /* Precheck SubscriptingRef subscript(s) */
    1477      618474 :             if (op->d.sbsref_subscript.subscriptfunc(state, op, econtext))
    1478             :             {
    1479      618420 :                 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      618668 :             EEO_CASE(EEOP_SBSREF_FETCH)
    1491             :         {
    1492             :             /* Perform a SubscriptingRef fetch or assignment */
    1493      618668 :             op->d.sbsref.subscriptfunc(state, op, econtext);
    1494             : 
    1495      618554 :             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     3989430 :         EEO_CASE(EEOP_SCALARARRAYOP)
    1507             :         {
    1508             :             /* too complex for an inline implementation */
    1509     3989430 :             ExecEvalScalarArrayOp(state, op);
    1510             : 
    1511     3989430 :             EEO_NEXT();
    1512             :         }
    1513             : 
    1514        4622 :         EEO_CASE(EEOP_HASHED_SCALARARRAYOP)
    1515             :         {
    1516             :             /* too complex for an inline implementation */
    1517        4622 :             ExecEvalHashedScalarArrayOp(state, op, econtext);
    1518             : 
    1519        4622 :             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       12088 :         EEO_CASE(EEOP_DOMAIN_CHECK)
    1531             :         {
    1532             :             /* too complex for an inline implementation */
    1533       12088 :             ExecEvalConstraintCheck(state, op);
    1534             : 
    1535       11654 :             EEO_NEXT();
    1536             :         }
    1537             : 
    1538       44234 :         EEO_CASE(EEOP_XMLEXPR)
    1539             :         {
    1540             :             /* too complex for an inline implementation */
    1541       44234 :             ExecEvalXmlExpr(state, op);
    1542             : 
    1543       44132 :             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        5018 :         EEO_CASE(EEOP_JSONEXPR_PATH)
    1562             :         {
    1563             :             /* too complex for an inline implementation */
    1564        5018 :             EEO_JUMP(ExecEvalJsonExprPath(state, op, econtext));
    1565             :         }
    1566             : 
    1567        2100 :         EEO_CASE(EEOP_JSONEXPR_COERCION)
    1568             :         {
    1569             :             /* too complex for an inline implementation */
    1570        2100 :             ExecEvalJsonCoercion(state, op, econtext);
    1571             : 
    1572        2016 :             EEO_NEXT();
    1573             :         }
    1574             : 
    1575        2232 :         EEO_CASE(EEOP_JSONEXPR_COERCION_FINISH)
    1576             :         {
    1577             :             /* too complex for an inline implementation */
    1578        2232 :             ExecEvalJsonCoercionFinish(state, op);
    1579             : 
    1580        2232 :             EEO_NEXT();
    1581             :         }
    1582             : 
    1583      391220 :         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      391220 :             int         aggno = op->d.aggref.aggno;
    1590             : 
    1591             :             Assert(econtext->ecxt_aggvalues != NULL);
    1592             : 
    1593      391220 :             *op->resvalue = econtext->ecxt_aggvalues[aggno];
    1594      391220 :             *op->resnull = econtext->ecxt_aggnulls[aggno];
    1595             : 
    1596      391220 :             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         410 :         EEO_CASE(EEOP_MERGE_SUPPORT_FUNC)
    1623             :         {
    1624             :             /* too complex/uncommon for an inline implementation */
    1625         410 :             ExecEvalMergeSupportFunc(state, op, econtext);
    1626             : 
    1627         410 :             EEO_NEXT();
    1628             :         }
    1629             : 
    1630     2783744 :         EEO_CASE(EEOP_SUBPLAN)
    1631             :         {
    1632             :             /* too complex for an inline implementation */
    1633     2783744 :             ExecEvalSubPlan(state, op, econtext);
    1634             : 
    1635     2783738 :             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         124 :                 EEO_JUMP(op->d.agg_deserialize.jumpnull);
    1644             : 
    1645             :             /* fallthrough */
    1646             :         }
    1647             : 
    1648             :         /* evaluate aggregate deserialization function (non-strict portion) */
    1649         302 :         EEO_CASE(EEOP_AGG_DESERIALIZE)
    1650             :         {
    1651         302 :             FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
    1652         302 :             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         302 :             oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    1660         302 :             fcinfo->isnull = false;
    1661         302 :             *op->resvalue = FunctionCallInvoke(fcinfo);
    1662         302 :             *op->resnull = fcinfo->isnull;
    1663         302 :             MemoryContextSwitchTo(oldContext);
    1664             : 
    1665         302 :             EEO_NEXT();
    1666             :         }
    1667             : 
    1668             :         /*
    1669             :          * Check that a strict aggregate transition / combination function's
    1670             :          * input is not NULL.
    1671             :          */
    1672             : 
    1673     4931292 :         EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
    1674             :         {
    1675     4931292 :             NullableDatum *args = op->d.agg_strict_input_check.args;
    1676     4931292 :             int         nargs = op->d.agg_strict_input_check.nargs;
    1677             : 
    1678     9944948 :             for (int argno = 0; argno < nargs; argno++)
    1679             :             {
    1680     5172000 :                 if (args[argno].isnull)
    1681      158344 :                     EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
    1682             :             }
    1683     4772948 :             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      648000 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
    1728             :         {
    1729      648000 :             AggState   *aggstate = castNode(AggState, state->parent);
    1730      648000 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1731      648000 :             AggStatePerGroup pergroup =
    1732      648000 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1733             : 
    1734             :             Assert(pertrans->transtypeByVal);
    1735             : 
    1736      648000 :             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      639246 :             else if (likely(!pergroup->transValueIsNull))
    1744             :             {
    1745             :                 /* invoke transition function, unless prevented by strictness */
    1746      639246 :                 ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    1747             :                                        op->d.agg_trans.aggcontext,
    1748             :                                        op->d.agg_trans.setno);
    1749             :             }
    1750             : 
    1751      648000 :             EEO_NEXT();
    1752             :         }
    1753             : 
    1754             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    1755    17251382 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL)
    1756             :         {
    1757    17251382 :             AggState   *aggstate = castNode(AggState, state->parent);
    1758    17251382 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1759    17251382 :             AggStatePerGroup pergroup =
    1760    17251382 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1761             : 
    1762             :             Assert(pertrans->transtypeByVal);
    1763             : 
    1764    17251382 :             if (likely(!pergroup->transValueIsNull))
    1765    17191364 :                 ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    1766             :                                        op->d.agg_trans.aggcontext,
    1767             :                                        op->d.agg_trans.setno);
    1768             : 
    1769    17251382 :             EEO_NEXT();
    1770             :         }
    1771             : 
    1772             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    1773     9240768 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)
    1774             :         {
    1775     9240768 :             AggState   *aggstate = castNode(AggState, state->parent);
    1776     9240768 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1777     9240768 :             AggStatePerGroup pergroup =
    1778     9240768 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1779             : 
    1780             :             Assert(pertrans->transtypeByVal);
    1781             : 
    1782     9240768 :             ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
    1783             :                                    op->d.agg_trans.aggcontext,
    1784             :                                    op->d.agg_trans.setno);
    1785             : 
    1786     9240708 :             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     2587610 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
    1812             :         {
    1813     2587610 :             AggState   *aggstate = castNode(AggState, state->parent);
    1814     2587610 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1815     2587610 :             AggStatePerGroup pergroup =
    1816     2587610 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1817             : 
    1818             :             Assert(!pertrans->transtypeByVal);
    1819             : 
    1820     2587610 :             if (likely(!pergroup->transValueIsNull))
    1821     2587610 :                 ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    1822             :                                        op->d.agg_trans.aggcontext,
    1823             :                                        op->d.agg_trans.setno);
    1824     2587610 :             EEO_NEXT();
    1825             :         }
    1826             : 
    1827             :         /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
    1828       23634 :         EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF)
    1829             :         {
    1830       23634 :             AggState   *aggstate = castNode(AggState, state->parent);
    1831       23634 :             AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    1832       23634 :             AggStatePerGroup pergroup =
    1833       23634 :                 &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
    1834             : 
    1835             :             Assert(!pertrans->transtypeByVal);
    1836             : 
    1837       23634 :             ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
    1838             :                                    op->d.agg_trans.aggcontext,
    1839             :                                    op->d.agg_trans.setno);
    1840             : 
    1841       23634 :             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      844384 :         EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM)
    1868             :         {
    1869             :             /* too complex for an inline implementation */
    1870      844384 :             ExecEvalAggOrderedTransDatum(state, op, econtext);
    1871             : 
    1872      844384 :             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   132340278 : out:
    1893   132340278 :     *isnull = state->resnull;
    1894   132340278 :     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     1729270 : 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     1729270 :     CheckExprStillValid(state, econtext);
    1910             : 
    1911             :     /* skip the check during further executions */
    1912     1729246 :     state->evalfunc = (ExprStateEvalFunc) state->evalfunc_private;
    1913             : 
    1914             :     /* and actually execute */
    1915     1729246 :     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     1735534 : CheckExprStillValid(ExprState *state, ExprContext *econtext)
    1924             : {
    1925             :     TupleTableSlot *innerslot;
    1926             :     TupleTableSlot *outerslot;
    1927             :     TupleTableSlot *scanslot;
    1928             : 
    1929     1735534 :     innerslot = econtext->ecxt_innertuple;
    1930     1735534 :     outerslot = econtext->ecxt_outertuple;
    1931     1735534 :     scanslot = econtext->ecxt_scantuple;
    1932             : 
    1933     9500746 :     for (int i = 0; i < state->steps_len; i++)
    1934             :     {
    1935     7765236 :         ExprEvalStep *op = &state->steps[i];
    1936             : 
    1937     7765236 :         switch (ExecEvalStepOp(state, op))
    1938             :         {
    1939       74258 :             case EEOP_INNER_VAR:
    1940             :                 {
    1941       74258 :                     int         attnum = op->d.var.attnum;
    1942             : 
    1943       74258 :                     CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
    1944       74258 :                     break;
    1945             :                 }
    1946             : 
    1947      188964 :             case EEOP_OUTER_VAR:
    1948             :                 {
    1949      188964 :                     int         attnum = op->d.var.attnum;
    1950             : 
    1951      188964 :                     CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
    1952      188964 :                     break;
    1953             :                 }
    1954             : 
    1955      294658 :             case EEOP_SCAN_VAR:
    1956             :                 {
    1957      294658 :                     int         attnum = op->d.var.attnum;
    1958             : 
    1959      294658 :                     CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
    1960      294634 :                     break;
    1961             :                 }
    1962     7207356 :             default:
    1963     7207356 :                 break;
    1964             :         }
    1965             :     }
    1966     1735510 : }
    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      557880 : 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      557880 :     if (attnum > 0)
    1994             :     {
    1995      557880 :         TupleDesc   slot_tupdesc = slot->tts_tupleDescriptor;
    1996             :         Form_pg_attribute attr;
    1997             : 
    1998      557880 :         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      557880 :         attr = TupleDescAttr(slot_tupdesc, attnum - 1);
    2003             : 
    2004      557880 :         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      557868 :         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      557856 : }
    2020             : 
    2021             : /*
    2022             :  * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
    2023             :  */
    2024             : static void
    2025   137503456 : 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   137503456 : }
    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      135928 : get_cached_rowtype(Oid type_id, int32 typmod,
    2073             :                    ExprEvalRowtypeCache *rowcache,
    2074             :                    bool *changed)
    2075             : {
    2076      135928 :     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       43948 :         TypeCacheEntry *typentry = (TypeCacheEntry *) rowcache->cacheptr;
    2086             : 
    2087       43948 :         if (unlikely(typentry == NULL ||
    2088             :                      rowcache->tupdesc_id == 0 ||
    2089             :                      typentry->tupDesc_identifier != rowcache->tupdesc_id))
    2090             :         {
    2091        6484 :             typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
    2092        6484 :             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        6484 :             rowcache->cacheptr = (void *) typentry;
    2098        6484 :             rowcache->tupdesc_id = typentry->tupDesc_identifier;
    2099        6484 :             if (changed)
    2100         716 :                 *changed = true;
    2101             :         }
    2102       43948 :         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       91980 :         TupleDesc   tupDesc = (TupleDesc) rowcache->cacheptr;
    2113             : 
    2114       91980 :         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       91980 :         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    14158880 : ExecJustVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2139             : {
    2140    14158880 :     ExprEvalStep *op = &state->steps[1];
    2141    14158880 :     int         attnum = op->d.var.attnum + 1;
    2142             : 
    2143    14158880 :     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    14158880 :     return slot_getattr(slot, attnum, isnull);
    2151             : }
    2152             : 
    2153             : /* Simple reference to inner Var */
    2154             : static Datum
    2155     3652074 : ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2156             : {
    2157     3652074 :     return ExecJustVarImpl(state, econtext->ecxt_innertuple, isnull);
    2158             : }
    2159             : 
    2160             : /* Simple reference to outer Var */
    2161             : static Datum
    2162    10257808 : ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2163             : {
    2164    10257808 :     return ExecJustVarImpl(state, econtext->ecxt_outertuple, isnull);
    2165             : }
    2166             : 
    2167             : /* Simple reference to scan Var */
    2168             : static Datum
    2169      248998 : ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2170             : {
    2171      248998 :     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     8906784 : ExecJustAssignVarImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
    2177             : {
    2178     8906784 :     ExprEvalStep *op = &state->steps[1];
    2179     8906784 :     int         attnum = op->d.assign_var.attnum + 1;
    2180     8906784 :     int         resultnum = op->d.assign_var.resultnum;
    2181     8906784 :     TupleTableSlot *outslot = state->resultslot;
    2182             : 
    2183     8906784 :     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    17813568 :     outslot->tts_values[resultnum] =
    2196     8906784 :         slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
    2197     8906784 :     return 0;
    2198             : }
    2199             : 
    2200             : /* Evaluate inner Var and assign to appropriate column of result tuple */
    2201             : static Datum
    2202       65616 : ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2203             : {
    2204       65616 :     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      385500 : ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2210             : {
    2211      385500 :     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     8455668 : ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    2217             : {
    2218     8455668 :     return ExecJustAssignVarImpl(state, econtext->ecxt_scantuple, isnull);
    2219             : }
    2220             : 
    2221             : /* Evaluate CASE_TESTVAL and apply a strict function to it */
    2222             : static Datum
    2223       21090 : ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
    2224             : {
    2225       21090 :     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       21090 :     *op->resvalue = *op->d.casetest.value;
    2236       21090 :     *op->resnull = *op->d.casetest.isnull;
    2237             : 
    2238       21090 :     op++;
    2239             : 
    2240       21090 :     nargs = op->d.func.nargs;
    2241       21090 :     fcinfo = op->d.func.fcinfo_data;
    2242       21090 :     args = fcinfo->args;
    2243             : 
    2244             :     /* strict function, so check for NULL args */
    2245       42492 :     for (int argno = 0; argno < nargs; argno++)
    2246             :     {
    2247       21414 :         if (args[argno].isnull)
    2248             :         {
    2249          12 :             *isnull = true;
    2250          12 :             return (Datum) 0;
    2251             :         }
    2252             :     }
    2253       21078 :     fcinfo->isnull = false;
    2254       21078 :     d = op->d.func.fn_addr(fcinfo);
    2255       21060 :     *isnull = fcinfo->isnull;
    2256       21060 :     return d;
    2257             : }
    2258             : 
    2259             : /* Simple Const expression */
    2260             : static Datum
    2261     1733500 : ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
    2262             : {
    2263     1733500 :     ExprEvalStep *op = &state->steps[0];
    2264             : 
    2265     1733500 :     *isnull = op->d.constval.isnull;
    2266     1733500 :     return op->d.constval.value;
    2267             : }
    2268             : 
    2269             : /* implementation of ExecJust(Inner|Outer|Scan)VarVirt */
    2270             : static pg_attribute_always_inline Datum
    2271    15841068 : ExecJustVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
    2272             : {
    2273    15841068 :     ExprEvalStep *op = &state->steps[0];
    2274    15841068 :     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    15841068 :     *isnull = slot->tts_isnull[attnum];
    2287             : 
    2288    15841068 :     return slot->tts_values[attnum];
    2289             : }
    2290             : 
    2291             : /* Like ExecJustInnerVar, optimized for virtual slots */
    2292             : static Datum
    2293      522050 : ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2294             : {
    2295      522050 :     return ExecJustVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2296             : }
    2297             : 
    2298             : /* Like ExecJustOuterVar, optimized for virtual slots */
    2299             : static Datum
    2300    15318832 : ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2301             : {
    2302    15318832 :     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      868692 : ExecJustAssignVarVirtImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
    2315             : {
    2316      868692 :     ExprEvalStep *op = &state->steps[0];
    2317      868692 :     int         attnum = op->d.assign_var.attnum;
    2318      868692 :     int         resultnum = op->d.assign_var.resultnum;
    2319      868692 :     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      868692 :     outslot->tts_values[resultnum] = inslot->tts_values[attnum];
    2329      868692 :     outslot->tts_isnull[resultnum] = inslot->tts_isnull[attnum];
    2330             : 
    2331      868692 :     return 0;
    2332             : }
    2333             : 
    2334             : /* Like ExecJustAssignInnerVar, optimized for virtual slots */
    2335             : static Datum
    2336      121218 : ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2337             : {
    2338      121218 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
    2339             : }
    2340             : 
    2341             : /* Like ExecJustAssignOuterVar, optimized for virtual slots */
    2342             : static Datum
    2343      563230 : ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2344             : {
    2345      563230 :     return ExecJustAssignVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
    2346             : }
    2347             : 
    2348             : /* Like ExecJustAssignScanVar, optimized for virtual slots */
    2349             : static Datum
    2350      184244 : ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
    2351             : {
    2352      184244 :     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    50185246 : dispatch_compare_ptr(const void *a, const void *b)
    2362             : {
    2363    50185246 :     const ExprEvalOpLookup *la = (const ExprEvalOpLookup *) a;
    2364    50185246 :     const ExprEvalOpLookup *lb = (const ExprEvalOpLookup *) b;
    2365             : 
    2366    50185246 :     if (la->opcode < lb->opcode)
    2367    32352370 :         return -1;
    2368    17832876 :     else if (la->opcode > lb->opcode)
    2369    11041638 :         return 1;
    2370     6791238 :     return 0;
    2371             : }
    2372             : #endif
    2373             : 
    2374             : /*
    2375             :  * Do one-time initialization of interpretation machinery.
    2376             :  */
    2377             : static void
    2378     2220964 : ExecInitInterpreter(void)
    2379             : {
    2380             : #if defined(EEO_USE_COMPUTED_GOTO)
    2381             :     /* Set up externally-visible pointer to dispatch table */
    2382     2220964 :     if (dispatch_table == NULL)
    2383             :     {
    2384       18032 :         dispatch_table = (const void **)
    2385       18032 :             DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
    2386             : 
    2387             :         /* build reverse lookup table */
    2388     1803200 :         for (int i = 0; i < EEOP_LAST; i++)
    2389             :         {
    2390     1785168 :             reverse_dispatch_table[i].opcode = dispatch_table[i];
    2391     1785168 :             reverse_dispatch_table[i].op = (ExprEvalOp) i;
    2392             :         }
    2393             : 
    2394             :         /* make it bsearch()able */
    2395       18032 :         qsort(reverse_dispatch_table,
    2396             :               EEOP_LAST /* nmembers */ ,
    2397             :               sizeof(ExprEvalOpLookup),
    2398             :               dispatch_compare_ptr);
    2399             :     }
    2400             : #endif
    2401     2220964 : }
    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     7817212 : ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
    2411             : {
    2412             : #if defined(EEO_USE_COMPUTED_GOTO)
    2413     7817212 :     if (state->flags & EEO_FLAG_DIRECT_THREADED)
    2414             :     {
    2415             :         ExprEvalOpLookup key;
    2416             :         ExprEvalOpLookup *res;
    2417             : 
    2418     6791238 :         key.opcode = (void *) op->opcode;
    2419     6791238 :         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     6791238 :         return res->op;
    2426             :     }
    2427             : #endif
    2428     1025974 :     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     4225692 : ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2499             : {
    2500             :     ParamExecData *prm;
    2501             : 
    2502     4225692 :     prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
    2503     4225692 :     if (unlikely(prm->execPlan != NULL))
    2504             :     {
    2505             :         /* Parameter not evaluated yet, so go do it */
    2506        8346 :         ExecSetParamPlan(prm->execPlan, econtext);
    2507             :         /* ExecSetParamPlan should have processed this param... */
    2508             :         Assert(prm->execPlan == NULL);
    2509             :     }
    2510     4225674 :     *op->resvalue = prm->value;
    2511     4225674 :     *op->resnull = prm->isnull;
    2512     4225674 : }
    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      501958 : ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2521             : {
    2522      501958 :     ParamListInfo paramInfo = econtext->ecxt_param_list_info;
    2523      501958 :     int         paramId = op->d.param.paramid;
    2524             : 
    2525      501958 :     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      501958 :         if (paramInfo->paramFetch != NULL)
    2533         184 :             prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata);
    2534             :         else
    2535      501774 :             prm = &paramInfo->params[paramId - 1];
    2536             : 
    2537      501958 :         if (likely(OidIsValid(prm->ptype)))
    2538             :         {
    2539             :             /* safety check in case hook did something unexpected */
    2540      501958 :             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      501958 :             *op->resvalue = prm->value;
    2548      501958 :             *op->resnull = prm->isnull;
    2549      501958 :             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         834 : ExecEvalCoerceViaIOSafe(ExprState *state, ExprEvalStep *op)
    2568             : {
    2569             :     char       *str;
    2570             : 
    2571             :     /* call output function (similar to OutputFunctionCall) */
    2572         834 :     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         828 :         fcinfo_out = op->d.iocoerce.fcinfo_data_out;
    2582         828 :         fcinfo_out->args[0].value = *op->resvalue;
    2583         828 :         fcinfo_out->args[0].isnull = false;
    2584             : 
    2585         828 :         fcinfo_out->isnull = false;
    2586         828 :         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         834 :     if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
    2594             :     {
    2595             :         FunctionCallInfo fcinfo_in;
    2596             : 
    2597         828 :         fcinfo_in = op->d.iocoerce.fcinfo_data_in;
    2598         828 :         fcinfo_in->args[0].value = PointerGetDatum(str);
    2599         828 :         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         828 :         fcinfo_in->isnull = false;
    2606         828 :         *op->resvalue = FunctionCallInvoke(fcinfo_in);
    2607             : 
    2608         828 :         if (SOFT_ERROR_OCCURRED(fcinfo_in->context))
    2609             :         {
    2610          24 :             *op->resnull = true;
    2611          24 :             *op->resvalue = (Datum) 0;
    2612          24 :             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       17830 : ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
    2628             : {
    2629       17830 :     LOCAL_FCINFO(fcinfo, 0);
    2630       17830 :     SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
    2631             : 
    2632       17830 :     *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       17830 :     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         288 :         case SVFOP_CURRENT_TIMESTAMP:
    2648             :         case SVFOP_CURRENT_TIMESTAMP_N:
    2649         288 :             *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
    2650         288 :             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       16868 :         case SVFOP_CURRENT_ROLE:
    2660             :         case SVFOP_CURRENT_USER:
    2661             :         case SVFOP_USER:
    2662       16868 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    2663       16868 :             *op->resvalue = current_user(fcinfo);
    2664       16868 :             *op->resnull = fcinfo->isnull;
    2665       16868 :             break;
    2666         480 :         case SVFOP_SESSION_USER:
    2667         480 :             InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    2668         480 :             *op->resvalue = session_user(fcinfo);
    2669         480 :             *op->resnull = fcinfo->isnull;
    2670         480 :             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       17830 : }
    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        1020 : ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
    2706             : {
    2707        1020 :     int64       newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
    2708             : 
    2709        1020 :     switch (op->d.nextvalueexpr.seqtypid)
    2710             :     {
    2711          30 :         case INT2OID:
    2712          30 :             *op->resvalue = Int16GetDatum((int16) newval);
    2713          30 :             break;
    2714         912 :         case INT4OID:
    2715         912 :             *op->resvalue = Int32GetDatum((int32) newval);
    2716         912 :             break;
    2717          78 :         case INT8OID:
    2718          78 :             *op->resvalue = Int64GetDatum((int64) newval);
    2719          78 :             break;
    2720           0 :         default:
    2721           0 :             elog(ERROR, "unsupported sequence type %u",
    2722             :                  op->d.nextvalueexpr.seqtypid);
    2723             :     }
    2724        1020 :     *op->resnull = false;
    2725        1020 : }
    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      759738 : ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
    2834             : {
    2835             :     ArrayType  *result;
    2836      759738 :     Oid         element_type = op->d.arrayexpr.elemtype;
    2837      759738 :     int         nelems = op->d.arrayexpr.nelems;
    2838      759738 :     int         ndims = 0;
    2839             :     int         dims[MAXDIM];
    2840             :     int         lbs[MAXDIM];
    2841             : 
    2842             :     /* Set non-null as default */
    2843      759738 :     *op->resnull = false;
    2844             : 
    2845      759738 :     if (!op->d.arrayexpr.multidims)
    2846             :     {
    2847             :         /* Elements are presumably of scalar type */
    2848      759260 :         Datum      *dvalues = op->d.arrayexpr.elemvalues;
    2849      759260 :         bool       *dnulls = op->d.arrayexpr.elemnulls;
    2850             : 
    2851             :         /* setup for 1-D array of the given length */
    2852      759260 :         ndims = 1;
    2853      759260 :         dims[0] = nelems;
    2854      759260 :         lbs[0] = 1;
    2855             : 
    2856      759260 :         result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
    2857             :                                     element_type,
    2858      759260 :                                     op->d.arrayexpr.elemlength,
    2859      759260 :                                     op->d.arrayexpr.elembyval,
    2860      759260 :                                     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      759738 :     *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       66092 : ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3048             : {
    3049             :     Datum       arraydatum;
    3050             : 
    3051             :     /* NULL array -> NULL result */
    3052       66092 :     if (*op->resnull)
    3053         232 :         return;
    3054             : 
    3055       65860 :     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       65860 :     if (op->d.arraycoerce.elemexprstate == NULL)
    3062             :     {
    3063             :         /* Detoast input array if necessary, and copy in any case */
    3064       65234 :         ArrayType  *array = DatumGetArrayTypePCopy(arraydatum);
    3065             : 
    3066       65234 :         ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
    3067       65234 :         *op->resvalue = PointerGetDatum(array);
    3068       65234 :         return;
    3069             :     }
    3070             : 
    3071             :     /*
    3072             :      * Use array_map to apply the sub-expression to each array element.
    3073             :      */
    3074         594 :     *op->resvalue = array_map(arraydatum,
    3075         626 :                               op->d.arraycoerce.elemexprstate,
    3076             :                               econtext,
    3077             :                               op->d.arraycoerce.resultelemtype,
    3078         626 :                               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       27126 : ExecEvalRow(ExprState *state, ExprEvalStep *op)
    3089             : {
    3090             :     HeapTuple   tuple;
    3091             : 
    3092             :     /* build tuple from evaluated field values */
    3093       27126 :     tuple = heap_form_tuple(op->d.row.tupdesc,
    3094       27126 :                             op->d.row.elemvalues,
    3095       27126 :                             op->d.row.elemnulls);
    3096             : 
    3097       27126 :     *op->resvalue = HeapTupleGetDatum(tuple);
    3098       27126 :     *op->resnull = false;
    3099       27126 : }
    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       23276 : ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
    3109             : {
    3110       23276 :     Datum      *values = op->d.minmax.values;
    3111       23276 :     bool       *nulls = op->d.minmax.nulls;
    3112       23276 :     FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
    3113       23276 :     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       23276 :     *op->resnull = true;
    3121             : 
    3122       70122 :     for (int off = 0; off < op->d.minmax.nelems; off++)
    3123             :     {
    3124             :         /* ignore NULL inputs */
    3125       46846 :         if (nulls[off])
    3126         122 :             continue;
    3127             : 
    3128       46724 :         if (*op->resnull)
    3129             :         {
    3130             :             /* first nonnull input, adopt value */
    3131       23276 :             *op->resvalue = values[off];
    3132       23276 :             *op->resnull = false;
    3133             :         }
    3134             :         else
    3135             :         {
    3136             :             int         cmpresult;
    3137             : 
    3138             :             /* apply comparison function */
    3139       23448 :             fcinfo->args[0].value = *op->resvalue;
    3140       23448 :             fcinfo->args[1].value = values[off];
    3141             : 
    3142       23448 :             fcinfo->isnull = false;
    3143       23448 :             cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
    3144       23448 :             if (fcinfo->isnull) /* probably should not happen */
    3145           0 :                 continue;
    3146             : 
    3147       23448 :             if (cmpresult > 0 && operator == IS_LEAST)
    3148         248 :                 *op->resvalue = values[off];
    3149       23200 :             else if (cmpresult < 0 && operator == IS_GREATEST)
    3150         204 :                 *op->resvalue = values[off];
    3151             :         }
    3152             :     }
    3153       23276 : }
    3154             : 
    3155             : /*
    3156             :  * Evaluate a FieldSelect node.
    3157             :  *
    3158             :  * Source record is in step's result variable.
    3159             :  */
    3160             : void
    3161      110876 : ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3162             : {
    3163      110876 :     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      110876 :     if (*op->resnull)
    3174         176 :         return;
    3175             : 
    3176      110700 :     tupDatum = *op->resvalue;
    3177             : 
    3178             :     /* We can special-case expanded records for speed */
    3179      110700 :     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      110038 :         tuple = DatumGetHeapTupleHeader(tupDatum);
    3226             : 
    3227      110038 :         tupType = HeapTupleHeaderGetTypeId(tuple);
    3228      110038 :         tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    3229             : 
    3230             :         /* Lookup tupdesc if first time through or if type changes */
    3231      110038 :         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      110038 :         if (fieldnum <= 0)       /* should never happen */
    3240           0 :             elog(ERROR, "unsupported reference to system column %d in FieldSelect",
    3241             :                  fieldnum);
    3242      110038 :         if (fieldnum > tupDesc->natts)    /* should never happen */
    3243           0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    3244             :                  fieldnum, tupDesc->natts);
    3245      110038 :         attr = TupleDescAttr(tupDesc, fieldnum - 1);
    3246             : 
    3247             :         /* Check for dropped column, and force a NULL result if so */
    3248      110038 :         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      110038 :         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      110038 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    3266      110038 :         tmptup.t_data = tuple;
    3267             : 
    3268             :         /* extract the field */
    3269      110038 :         *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     4006684 : ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
    3456             : {
    3457     4006684 :     FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
    3458     4006684 :     bool        useOr = op->d.scalararrayop.useOr;
    3459     4006684 :     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     4006684 :     if (*op->resnull)
    3476      152576 :         return;
    3477             : 
    3478             :     /* Else okay to fetch and detoast the array */
    3479     3854108 :     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     3854108 :     nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    3488     3854108 :     if (nitems <= 0)
    3489             :     {
    3490       12810 :         *op->resvalue = BoolGetDatum(!useOr);
    3491       12810 :         *op->resnull = false;
    3492       12810 :         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     3841298 :     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     3840312 :     if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
    3510             :     {
    3511       13652 :         get_typlenbyvalalign(ARR_ELEMTYPE(arr),
    3512             :                              &op->d.scalararrayop.typlen,
    3513             :                              &op->d.scalararrayop.typbyval,
    3514             :                              &op->d.scalararrayop.typalign);
    3515       13652 :         op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
    3516             :     }
    3517             : 
    3518     3840312 :     typlen = op->d.scalararrayop.typlen;
    3519     3840312 :     typbyval = op->d.scalararrayop.typbyval;
    3520     3840312 :     typalign = op->d.scalararrayop.typalign;
    3521             : 
    3522             :     /* Initialize result appropriately depending on useOr */
    3523     3840312 :     result = BoolGetDatum(!useOr);
    3524     3840312 :     resultnull = false;
    3525             : 
    3526             :     /* Loop over the array elements */
    3527     3840312 :     s = (char *) ARR_DATA_PTR(arr);
    3528     3840312 :     bitmap = ARR_NULLBITMAP(arr);
    3529     3840312 :     bitmask = 1;
    3530             : 
    3531    10355126 :     for (int i = 0; i < nitems; i++)
    3532             :     {
    3533             :         Datum       elt;
    3534             :         Datum       thisresult;
    3535             : 
    3536             :         /* Get array element, checking for NULL */
    3537     8177194 :         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     7961930 :             elt = fetch_att(s, typbyval, typlen);
    3545     7961930 :             s = att_addlength_pointer(s, typlen, s);
    3546     7961930 :             s = (char *) att_align_nominal(s, typalign);
    3547     7961930 :             fcinfo->args[1].value = elt;
    3548     7961930 :             fcinfo->args[1].isnull = false;
    3549             :         }
    3550             : 
    3551             :         /* Call comparison function */
    3552     8177194 :         if (fcinfo->args[1].isnull && strictfunc)
    3553             :         {
    3554      215240 :             fcinfo->isnull = true;
    3555      215240 :             thisresult = (Datum) 0;
    3556             :         }
    3557             :         else
    3558             :         {
    3559     7961954 :             fcinfo->isnull = false;
    3560     7961954 :             thisresult = op->d.scalararrayop.fn_addr(fcinfo);
    3561             :         }
    3562             : 
    3563             :         /* Combine results per OR or AND semantics */
    3564     8177194 :         if (fcinfo->isnull)
    3565      215336 :             resultnull = true;
    3566     7961858 :         else if (useOr)
    3567             :         {
    3568     7163436 :             if (DatumGetBool(thisresult))
    3569             :             {
    3570     1089508 :                 result = BoolGetDatum(true);
    3571     1089508 :                 resultnull = false;
    3572     1089508 :                 break;          /* needn't look at any more elements */
    3573             :             }
    3574             :         }
    3575             :         else
    3576             :         {
    3577      798422 :             if (!DatumGetBool(thisresult))
    3578             :             {
    3579      572872 :                 result = BoolGetDatum(false);
    3580      572872 :                 resultnull = false;
    3581      572872 :                 break;          /* needn't look at any more elements */
    3582             :             }
    3583             :         }
    3584             : 
    3585             :         /* advance bitmap pointer if any */
    3586     6514814 :         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     3840312 :     *op->resvalue = result;
    3598     3840312 :     *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        6468 : saop_element_hash(struct saophash_hash *tb, Datum key)
    3609             : {
    3610        6468 :     ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
    3611        6468 :     FunctionCallInfo fcinfo = &elements_tab->hash_fcinfo_data;
    3612             :     Datum       hash;
    3613             : 
    3614        6468 :     fcinfo->args[0].value = key;
    3615        6468 :     fcinfo->args[0].isnull = false;
    3616             : 
    3617        6468 :     hash = elements_tab->hash_finfo.fn_addr(fcinfo);
    3618             : 
    3619        6468 :     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        4410 : saop_hash_element_match(struct saophash_hash *tb, Datum key1, Datum key2)
    3628             : {
    3629             :     Datum       result;
    3630             : 
    3631        4410 :     ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
    3632        4410 :     FunctionCallInfo fcinfo = elements_tab->op->d.hashedscalararrayop.fcinfo_data;
    3633             : 
    3634        4410 :     fcinfo->args[0].value = key1;
    3635        4410 :     fcinfo->args[0].isnull = false;
    3636        4410 :     fcinfo->args[1].value = key2;
    3637        4410 :     fcinfo->args[1].isnull = false;
    3638             : 
    3639        4410 :     result = elements_tab->op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
    3640             : 
    3641        4410 :     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        4622 : ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3659             : {
    3660        4622 :     ScalarArrayOpExprHashTable *elements_tab = op->d.hashedscalararrayop.elements_tab;
    3661        4622 :     FunctionCallInfo fcinfo = op->d.hashedscalararrayop.fcinfo_data;
    3662        4622 :     bool        inclause = op->d.hashedscalararrayop.inclause;
    3663        4622 :     bool        strictfunc = op->d.hashedscalararrayop.finfo->fn_strict;
    3664        4622 :     Datum       scalar = fcinfo->args[0].value;
    3665        4622 :     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        4622 :     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        4554 :     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        4554 :     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        4554 :     if (inclause)
    3782         854 :         result = BoolGetDatum(hashfound);   /* IN */
    3783             :     else
    3784        3700 :         result = BoolGetDatum(!hashfound);  /* NOT IN */
    3785             : 
    3786        4554 :     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        4554 :     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        4554 :     *op->resvalue = result;
    3833        4554 :     *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       12088 : ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
    3855             : {
    3856       12088 :     if (!*op->d.domaincheck.checknull &&
    3857       11022 :         !DatumGetBool(*op->d.domaincheck.checkvalue))
    3858         452 :         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       11654 : }
    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       44234 : ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
    3875             : {
    3876       44234 :     XmlExpr    *xexpr = op->d.xmlexpr.xexpr;
    3877             :     Datum       value;
    3878             : 
    3879       44234 :     *op->resnull = true;     /* until we get a result */
    3880       44234 :     *op->resvalue = (Datum) 0;
    3881             : 
    3882       44234 :     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       21778 :         case IS_XMLFOREST:
    3905             :             {
    3906       21778 :                 Datum      *argvalue = op->d.xmlexpr.named_argvalue;
    3907       21778 :                 bool       *argnull = op->d.xmlexpr.named_argnull;
    3908             :                 StringInfoData buf;
    3909             :                 ListCell   *lc;
    3910             :                 ListCell   *lc2;
    3911             :                 int         i;
    3912             : 
    3913       21778 :                 initStringInfo(&buf);
    3914             : 
    3915       21778 :                 i = 0;
    3916      152326 :                 forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
    3917             :                 {
    3918      130548 :                     Expr       *e = (Expr *) lfirst(lc);
    3919      130548 :                     char       *argname = strVal(lfirst(lc2));
    3920             : 
    3921      130548 :                     if (!argnull[i])
    3922             :                     {
    3923      108754 :                         value = argvalue[i];
    3924      108754 :                         appendStringInfo(&buf, "<%s>%s</%s>",
    3925             :                                          argname,
    3926             :                                          map_sql_value_to_xml_value(value,
    3927             :                                                                     exprType((Node *) e), true),
    3928             :                                          argname);
    3929      108754 :                         *op->resnull = false;
    3930             :                     }
    3931      130548 :                     i++;
    3932             :                 }
    3933             : 
    3934       21778 :                 if (!*op->resnull)
    3935             :                 {
    3936             :                     text       *result;
    3937             : 
    3938       21778 :                     result = cstring_to_text_with_len(buf.data, buf.len);
    3939       21778 :                     *op->resvalue = PointerGetDatum(result);
    3940             :                 }
    3941             : 
    3942       21778 :                 pfree(buf.data);
    3943             :             }
    3944       21778 :             break;
    3945             : 
    3946       21934 :         case IS_XMLELEMENT:
    3947       21934 :             *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       21928 :             *op->resnull = false;
    3953       21928 :             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        5018 : ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
    4268             :                      ExprContext *econtext)
    4269             : {
    4270        5018 :     JsonExprState *jsestate = op->d.jsonexpr.jsestate;
    4271        5018 :     JsonExpr   *jsexpr = jsestate->jsexpr;
    4272             :     Datum       item;
    4273             :     JsonPath   *path;
    4274        5018 :     bool        throw_error = jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR;
    4275        5018 :     bool        error = false,
    4276        5018 :                 empty = false;
    4277        5018 :     int         jump_eval_coercion = jsestate->jump_eval_coercion;
    4278        5018 :     char       *val_string = NULL;
    4279             : 
    4280        5018 :     item = jsestate->formatted_expr.value;
    4281        5018 :     path = DatumGetJsonPathP(jsestate->pathspec.value);
    4282             : 
    4283             :     /* Set error/empty to false. */
    4284        5018 :     memset(&jsestate->error, 0, sizeof(NullableDatum));
    4285        5018 :     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        5018 :     jsestate->escontext.error_occurred = false;
    4295             : 
    4296        5018 :     switch (jsexpr->op)
    4297             :     {
    4298         510 :         case JSON_EXISTS_OP:
    4299             :             {
    4300         510 :                 bool        exists = JsonPathExists(item, path,
    4301         510 :                                                     !throw_error ? &error : NULL,
    4302             :                                                     jsestate->args);
    4303             : 
    4304         504 :                 if (!error)
    4305             :                 {
    4306         348 :                     *op->resvalue = BoolGetDatum(exists);
    4307         348 :                     *op->resnull = false;
    4308             :                 }
    4309             :             }
    4310         504 :             break;
    4311             : 
    4312        2382 :         case JSON_QUERY_OP:
    4313        2382 :             *op->resvalue = JsonPathQuery(item, path, jsexpr->wrapper, &empty,
    4314        2382 :                                           !throw_error ? &error : NULL,
    4315             :                                           jsestate->args,
    4316        2382 :                                           jsexpr->column_name);
    4317             : 
    4318        2370 :             *op->resnull = (DatumGetPointer(*op->resvalue) == NULL);
    4319             : 
    4320             :             /* Handle OMIT QUOTES. */
    4321        2370 :             if (!*op->resnull && jsexpr->omit_quotes)
    4322             :             {
    4323         258 :                 val_string = JsonbUnquote(DatumGetJsonbP(*op->resvalue));
    4324             : 
    4325             :                 /*
    4326             :                  * Pass the string as a text value to the cast expression if
    4327             :                  * one present.  If not, use the input function call below to
    4328             :                  * do the coercion.
    4329             :                  */
    4330         258 :                 if (jump_eval_coercion >= 0)
    4331         216 :                     *op->resvalue =
    4332         216 :                         DirectFunctionCall1(textin,
    4333             :                                             PointerGetDatum(val_string));
    4334             :             }
    4335        2370 :             break;
    4336             : 
    4337        2126 :         case JSON_VALUE_OP:
    4338             :             {
    4339        2126 :                 JsonbValue *jbv = JsonPathValue(item, path, &empty,
    4340        2126 :                                                 !throw_error ? &error : NULL,
    4341             :                                                 jsestate->args,
    4342        2126 :                                                 jsexpr->column_name);
    4343             : 
    4344        2096 :                 if (jbv == NULL)
    4345             :                 {
    4346             :                     /* Will be coerced with coercion_expr, if any. */
    4347         516 :                     *op->resvalue = (Datum) 0;
    4348         516 :                     *op->resnull = true;
    4349             :                 }
    4350        1580 :                 else if (!error && !empty)
    4351             :                 {
    4352        1580 :                     if (jsexpr->returning->typid == JSONOID ||
    4353        1550 :                         jsexpr->returning->typid == JSONBOID)
    4354             :                     {
    4355          54 :                         val_string = DatumGetCString(DirectFunctionCall1(jsonb_out,
    4356             :                                                                          JsonbPGetDatum(JsonbValueToJsonb(jbv))));
    4357             :                     }
    4358             :                     else
    4359             :                     {
    4360        1526 :                         val_string = ExecGetJsonValueItemString(jbv, op->resnull);
    4361             : 
    4362             :                         /*
    4363             :                          * Pass the string as a text value to the cast
    4364             :                          * expression if one present.  If not, use the input
    4365             :                          * function call below to do the coercion.
    4366             :                          */
    4367        1526 :                         *op->resvalue = PointerGetDatum(val_string);
    4368        1526 :                         if (jump_eval_coercion >= 0)
    4369         150 :                             *op->resvalue = DirectFunctionCall1(textin, *op->resvalue);
    4370             :                     }
    4371             :                 }
    4372        2096 :                 break;
    4373             :             }
    4374             : 
    4375             :             /* JSON_TABLE_OP can't happen here */
    4376             : 
    4377           0 :         default:
    4378           0 :             elog(ERROR, "unrecognized SQL/JSON expression op %d",
    4379             :                  (int) jsexpr->op);
    4380             :             return false;
    4381             :     }
    4382             : 
    4383             :     /*
    4384             :      * Coerce the result value to the RETURNING type by calling its input
    4385             :      * function.
    4386             :      */
    4387        4970 :     if (!*op->resnull && jsexpr->use_io_coercion)
    4388             :     {
    4389             :         FunctionCallInfo fcinfo;
    4390             : 
    4391             :         Assert(jump_eval_coercion == -1);
    4392        1472 :         fcinfo = jsestate->input_fcinfo;
    4393             :         Assert(fcinfo != NULL);
    4394             :         Assert(val_string != NULL);
    4395        1472 :         fcinfo->args[0].value = PointerGetDatum(val_string);
    4396        1472 :         fcinfo->args[0].isnull = *op->resnull;
    4397             : 
    4398             :         /*
    4399             :          * Second and third arguments are already set up in
    4400             :          * ExecInitJsonExpr().
    4401             :          */
    4402             : 
    4403        1472 :         fcinfo->isnull = false;
    4404        1472 :         *op->resvalue = FunctionCallInvoke(fcinfo);
    4405        1424 :         if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
    4406         150 :             error = true;
    4407             :     }
    4408             : 
    4409             :     /* Handle ON EMPTY. */
    4410        4922 :     if (empty)
    4411             :     {
    4412         540 :         *op->resvalue = (Datum) 0;
    4413         540 :         *op->resnull = true;
    4414         540 :         if (jsexpr->on_empty)
    4415             :         {
    4416         222 :             if (jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR)
    4417             :             {
    4418         168 :                 jsestate->empty.value = BoolGetDatum(true);
    4419             :                 Assert(jsestate->jump_empty >= 0);
    4420         168 :                 return jsestate->jump_empty;
    4421             :             }
    4422             :         }
    4423         318 :         else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
    4424             :         {
    4425         294 :             jsestate->error.value = BoolGetDatum(true);
    4426             :             Assert(!throw_error && jsestate->jump_error >= 0);
    4427         294 :             return jsestate->jump_error;
    4428             :         }
    4429             : 
    4430          78 :         if (jsexpr->column_name)
    4431          18 :             ereport(ERROR,
    4432             :                     errcode(ERRCODE_NO_SQL_JSON_ITEM),
    4433             :                     errmsg("no SQL/JSON item found for specified path of column \"%s\"",
    4434             :                            jsexpr->column_name));
    4435             :         else
    4436          60 :             ereport(ERROR,
    4437             :                     errcode(ERRCODE_NO_SQL_JSON_ITEM),
    4438             :                     errmsg("no SQL/JSON item found for specified path"));
    4439             :     }
    4440             : 
    4441             :     /*
    4442             :      * ON ERROR. Wouldn't get here if the behavior is ERROR, because they
    4443             :      * would have already been thrown.
    4444             :      */
    4445        4382 :     if (error)
    4446             :     {
    4447             :         Assert(!throw_error && jsestate->jump_error >= 0);
    4448         480 :         *op->resvalue = (Datum) 0;
    4449         480 :         *op->resnull = true;
    4450         480 :         jsestate->error.value = BoolGetDatum(true);
    4451         480 :         return jsestate->jump_error;
    4452             :     }
    4453             : 
    4454        3902 :     return jump_eval_coercion >= 0 ? jump_eval_coercion : jsestate->jump_end;
    4455             : }
    4456             : 
    4457             : /*
    4458             :  * Convert the given JsonbValue to its C string representation
    4459             :  *
    4460             :  * *resnull is set if the JsonbValue is a jbvNull.
    4461             :  */
    4462             : static char *
    4463        1526 : ExecGetJsonValueItemString(JsonbValue *item, bool *resnull)
    4464             : {
    4465        1526 :     *resnull = false;
    4466             : 
    4467             :     /* get coercion state reference and datum of the corresponding SQL type */
    4468        1526 :     switch (item->type)
    4469             :     {
    4470           0 :         case jbvNull:
    4471           0 :             *resnull = true;
    4472           0 :             return NULL;
    4473             : 
    4474         334 :         case jbvString:
    4475             :             {
    4476         334 :                 char       *str = palloc(item->val.string.len + 1);
    4477             : 
    4478         334 :                 memcpy(str, item->val.string.val, item->val.string.len);
    4479         334 :                 str[item->val.string.len] = '\0';
    4480         334 :                 return str;
    4481             :             }
    4482             : 
    4483        1066 :         case jbvNumeric:
    4484        1066 :             return DatumGetCString(DirectFunctionCall1(numeric_out,
    4485             :                                                        NumericGetDatum(item->val.numeric)));
    4486             : 
    4487          84 :         case jbvBool:
    4488          84 :             return DatumGetCString(DirectFunctionCall1(boolout,
    4489             :                                                        BoolGetDatum(item->val.boolean)));
    4490             : 
    4491          42 :         case jbvDatetime:
    4492          42 :             switch (item->val.datetime.typid)
    4493             :             {
    4494           6 :                 case DATEOID:
    4495           6 :                     return DatumGetCString(DirectFunctionCall1(date_out,
    4496             :                                                                item->val.datetime.value));
    4497           6 :                 case TIMEOID:
    4498           6 :                     return DatumGetCString(DirectFunctionCall1(time_out,
    4499             :                                                                item->val.datetime.value));
    4500           6 :                 case TIMETZOID:
    4501           6 :                     return DatumGetCString(DirectFunctionCall1(timetz_out,
    4502             :                                                                item->val.datetime.value));
    4503           6 :                 case TIMESTAMPOID:
    4504           6 :                     return DatumGetCString(DirectFunctionCall1(timestamp_out,
    4505             :                                                                item->val.datetime.value));
    4506          18 :                 case TIMESTAMPTZOID:
    4507          18 :                     return DatumGetCString(DirectFunctionCall1(timestamptz_out,
    4508             :                                                                item->val.datetime.value));
    4509           0 :                 default:
    4510           0 :                     elog(ERROR, "unexpected jsonb datetime type oid %u",
    4511             :                          item->val.datetime.typid);
    4512             :             }
    4513             :             break;
    4514             : 
    4515           0 :         case jbvArray:
    4516             :         case jbvObject:
    4517             :         case jbvBinary:
    4518           0 :             return DatumGetCString(DirectFunctionCall1(jsonb_out,
    4519             :                                                        JsonbPGetDatum(JsonbValueToJsonb(item))));
    4520             : 
    4521           0 :         default:
    4522           0 :             elog(ERROR, "unexpected jsonb value type %d", item->type);
    4523             :     }
    4524             : 
    4525             :     Assert(false);
    4526             :     *resnull = true;
    4527             :     return NULL;
    4528             : }
    4529             : 
    4530             : /*
    4531             :  * Coerce a jsonb value produced by ExecEvalJsonExprPath() or an ON ERROR /
    4532             :  * ON EMPTY behavior expression to the target type.
    4533             :  *
    4534             :  * Any soft errors that occur here will be checked by
    4535             :  * EEOP_JSONEXPR_COERCION_FINISH that will run after this.
    4536             :  */
    4537             : void
    4538        2100 : ExecEvalJsonCoercion(ExprState *state, ExprEvalStep *op,
    4539             :                      ExprContext *econtext)
    4540             : {
    4541        2100 :     ErrorSaveContext *escontext = op->d.jsonexpr_coercion.escontext;
    4542             : 
    4543        2100 :     *op->resvalue = json_populate_type(*op->resvalue, JSONBOID,
    4544             :                                        op->d.jsonexpr_coercion.targettype,
    4545             :                                        op->d.jsonexpr_coercion.targettypmod,
    4546             :                                        &op->d.jsonexpr_coercion.json_populate_type_cache,
    4547             :                                        econtext->ecxt_per_query_memory,
    4548             :                                        op->resnull, (Node *) escontext);
    4549        2016 : }
    4550             : 
    4551             : /*
    4552             :  * Checks if an error occurred either when evaluating JsonExpr.coercion_expr or
    4553             :  * in ExecEvalJsonCoercion().  If so, this sets JsonExprState.error to trigger
    4554             :  * the ON ERROR handling steps.
    4555             :  */
    4556             : void
    4557        2232 : ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op)
    4558             : {
    4559        2232 :     JsonExprState *jsestate = op->d.jsonexpr.jsestate;
    4560             : 
    4561        2232 :     if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
    4562             :     {
    4563         318 :         *op->resvalue = (Datum) 0;
    4564         318 :         *op->resnull = true;
    4565         318 :         jsestate->error.value = BoolGetDatum(true);
    4566             :     }
    4567        2232 : }
    4568             : 
    4569             : /*
    4570             :  * ExecEvalGroupingFunc
    4571             :  *
    4572             :  * Computes a bitmask with a bit for each (unevaluated) argument expression
    4573             :  * (rightmost arg is least significant bit).
    4574             :  *
    4575             :  * A bit is set if the corresponding expression is NOT part of the set of
    4576             :  * grouping expressions in the current grouping set.
    4577             :  */
    4578             : void
    4579        1688 : ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
    4580             : {
    4581        1688 :     AggState   *aggstate = castNode(AggState, state->parent);
    4582        1688 :     int         result = 0;
    4583        1688 :     Bitmapset  *grouped_cols = aggstate->grouped_cols;
    4584             :     ListCell   *lc;
    4585             : 
    4586        4178 :     foreach(lc, op->d.grouping_func.clauses)
    4587             :     {
    4588        2490 :         int         attnum = lfirst_int(lc);
    4589             : 
    4590        2490 :         result <<= 1;
    4591             : 
    4592        2490 :         if (!bms_is_member(attnum, grouped_cols))
    4593         972 :             result |= 1;
    4594             :     }
    4595             : 
    4596        1688 :     *op->resvalue = Int32GetDatum(result);
    4597        1688 :     *op->resnull = false;
    4598        1688 : }
    4599             : 
    4600             : /*
    4601             :  * ExecEvalMergeSupportFunc
    4602             :  *
    4603             :  * Returns information about the current MERGE action for its RETURNING list.
    4604             :  */
    4605             : void
    4606         410 : ExecEvalMergeSupportFunc(ExprState *state, ExprEvalStep *op,
    4607             :                          ExprContext *econtext)
    4608             : {
    4609         410 :     ModifyTableState *mtstate = castNode(ModifyTableState, state->parent);
    4610         410 :     MergeActionState *relaction = mtstate->mt_merge_action;
    4611             : 
    4612         410 :     if (!relaction)
    4613           0 :         elog(ERROR, "no merge action in progress");
    4614             : 
    4615             :     /* Return the MERGE action ("INSERT", "UPDATE", or "DELETE") */
    4616         410 :     switch (relaction->mas_action->commandType)
    4617             :     {
    4618         132 :         case CMD_INSERT:
    4619         132 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("INSERT", 6));
    4620         132 :             *op->resnull = false;
    4621         132 :             break;
    4622         170 :         case CMD_UPDATE:
    4623         170 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("UPDATE", 6));
    4624         170 :             *op->resnull = false;
    4625         170 :             break;
    4626         108 :         case CMD_DELETE:
    4627         108 :             *op->resvalue = PointerGetDatum(cstring_to_text_with_len("DELETE", 6));
    4628         108 :             *op->resnull = false;
    4629         108 :             break;
    4630           0 :         case CMD_NOTHING:
    4631           0 :             elog(ERROR, "unexpected merge action: DO NOTHING");
    4632             :             break;
    4633           0 :         default:
    4634           0 :             elog(ERROR, "unrecognized commandType: %d",
    4635             :                  (int) relaction->mas_action->commandType);
    4636             :     }
    4637         410 : }
    4638             : 
    4639             : /*
    4640             :  * Hand off evaluation of a subplan to nodeSubplan.c
    4641             :  */
    4642             : void
    4643     2783930 : ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    4644             : {
    4645     2783930 :     SubPlanState *sstate = op->d.subplan.sstate;
    4646             : 
    4647             :     /* could potentially be nested, so make sure there's enough stack */
    4648     2783930 :     check_stack_depth();
    4649             : 
    4650     2783930 :     *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
    4651     2783924 : }
    4652             : 
    4653             : /*
    4654             :  * Evaluate a wholerow Var expression.
    4655             :  *
    4656             :  * Returns a Datum whose value is the value of a whole-row range variable
    4657             :  * with respect to given expression context.
    4658             :  */
    4659             : void
    4660       39298 : ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    4661             : {
    4662       39298 :     Var        *variable = op->d.wholerow.var;
    4663             :     TupleTableSlot *slot;
    4664             :     TupleDesc   output_tupdesc;
    4665             :     MemoryContext oldcontext;
    4666             :     HeapTupleHeader dtuple;
    4667             :     HeapTuple   tuple;
    4668             : 
    4669             :     /* This was checked by ExecInitExpr */
    4670             :     Assert(variable->varattno == InvalidAttrNumber);
    4671             : 
    4672             :     /* Get the input slot we want */
    4673       39298 :     switch (variable->varno)
    4674             :     {
    4675          90 :         case INNER_VAR:
    4676             :             /* get the tuple from the inner node */
    4677          90 :             slot = econtext->ecxt_innertuple;
    4678          90 :             break;
    4679             : 
    4680          18 :         case OUTER_VAR:
    4681             :             /* get the tuple from the outer node */
    4682          18 :             slot = econtext->ecxt_outertuple;
    4683          18 :             break;
    4684             : 
    4685             :             /* INDEX_VAR is handled by default case */
    4686             : 
    4687       39190 :         default:
    4688             :             /* get the tuple from the relation being scanned */
    4689       39190 :             slot = econtext->ecxt_scantuple;
    4690       39190 :             break;
    4691             :     }
    4692             : 
    4693             :     /* Apply the junkfilter if any */
    4694       39298 :     if (op->d.wholerow.junkFilter != NULL)
    4695          60 :         slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
    4696             : 
    4697             :     /*
    4698             :      * If first time through, obtain tuple descriptor and check compatibility.
    4699             :      *
    4700             :      * XXX: It'd be great if this could be moved to the expression
    4701             :      * initialization phase, but due to using slots that's currently not
    4702             :      * feasible.
    4703             :      */
    4704       39298 :     if (op->d.wholerow.first)
    4705             :     {
    4706             :         /* optimistically assume we don't need slow path */
    4707        2558 :         op->d.wholerow.slow = false;
    4708             : 
    4709             :         /*
    4710             :          * If the Var identifies a named composite type, we must check that
    4711             :          * the actual tuple type is compatible with it.
    4712             :          */
    4713        2558 :         if (variable->vartype != RECORDOID)
    4714             :         {
    4715             :             TupleDesc   var_tupdesc;
    4716             :             TupleDesc   slot_tupdesc;
    4717             : 
    4718             :             /*
    4719             :              * We really only care about numbers of attributes and data types.
    4720             :              * Also, we can ignore type mismatch on columns that are dropped
    4721             :              * in the destination type, so long as (1) the physical storage
    4722             :              * matches or (2) the actual column value is NULL.  Case (1) is
    4723             :              * helpful in some cases involving out-of-date cached plans, while
    4724             :              * case (2) is expected behavior in situations such as an INSERT
    4725             :              * into a table with dropped columns (the planner typically
    4726             :              * generates an INT4 NULL regardless of the dropped column type).
    4727             :              * If we find a dropped column and cannot verify that case (1)
    4728             :              * holds, we have to use the slow path to check (2) for each row.
    4729             :              *
    4730             :              * If vartype is a domain over composite, just look through that
    4731             :              * to the base composite type.
    4732             :              */
    4733        1494 :             var_tupdesc = lookup_rowtype_tupdesc_domain(variable->vartype,
    4734             :                                                         -1, false);
    4735             : 
    4736        1494 :             slot_tupdesc = slot->tts_tupleDescriptor;
    4737             : 
    4738        1494 :             if (var_tupdesc->natts != slot_tupdesc->natts)
    4739           0 :                 ereport(ERROR,
    4740             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    4741             :                          errmsg("table row type and query-specified row type do not match"),
    4742             :                          errdetail_plural("Table row contains %d attribute, but query expects %d.",
    4743             :                                           "Table row contains %d attributes, but query expects %d.",
    4744             :                                           slot_tupdesc->natts,
    4745             :                                           slot_tupdesc->natts,
    4746             :                                           var_tupdesc->natts)));
    4747             : 
    4748        5950 :             for (int i = 0; i < var_tupdesc->natts; i++)
    4749             :             {
    4750        4456 :                 Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
    4751        4456 :                 Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
    4752             : 
    4753        4456 :                 if (vattr->atttypid == sattr->atttypid)
    4754        4456 :                     continue;   /* no worries */
    4755           0 :                 if (!vattr->attisdropped)
    4756           0 :                     ereport(ERROR,
    4757             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    4758             :                              errmsg("table row type and query-specified row type do not match"),
    4759             :                              errdetail("Table has type %s at ordinal position %d, but query expects %s.",
    4760             :                                        format_type_be(sattr->atttypid),
    4761             :                                        i + 1,
    4762             :                                        format_type_be(vattr->atttypid))));
    4763             : 
    4764           0 :                 if (vattr->attlen != sattr->attlen ||
    4765           0 :                     vattr->attalign != sattr->attalign)
    4766           0 :                     op->d.wholerow.slow = true; /* need to check for nulls */
    4767             :             }
    4768             : 
    4769             :             /*
    4770             :              * Use the variable's declared rowtype as the descriptor for the
    4771             :              * output values.  In particular, we *must* absorb any
    4772             :              * attisdropped markings.
    4773             :              */
    4774        1494 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    4775        1494 :             output_tupdesc = CreateTupleDescCopy(var_tupdesc);
    4776        1494 :             MemoryContextSwitchTo(oldcontext);
    4777             : 
    4778        1494 :             ReleaseTupleDesc(var_tupdesc);
    4779             :         }
    4780             :         else
    4781             :         {
    4782             :             /*
    4783             :              * In the RECORD case, we use the input slot's rowtype as the
    4784             :              * descriptor for the output values, modulo possibly assigning new
    4785             :              * column names below.
    4786             :              */
    4787        1064 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    4788        1064 :             output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
    4789        1064 :             MemoryContextSwitchTo(oldcontext);
    4790             : 
    4791             :             /*
    4792             :              * It's possible that the input slot is a relation scan slot and
    4793             :              * so is marked with that relation's rowtype.  But we're supposed
    4794             :              * to be returning RECORD, so reset to that.
    4795             :              */
    4796        1064 :             output_tupdesc->tdtypeid = RECORDOID;
    4797        1064 :             output_tupdesc->tdtypmod = -1;
    4798             : 
    4799             :             /*
    4800             :              * We already got the correct physical datatype info above, but
    4801             :              * now we should try to find the source RTE and adopt its column
    4802             :              * aliases, since it's unlikely that the input slot has the
    4803             :              * desired names.
    4804             :              *
    4805             :              * If we can't locate the RTE, assume the column names we've got
    4806             :              * are OK.  (As of this writing, the only cases where we can't
    4807             :              * locate the RTE are in execution of trigger WHEN clauses, and
    4808             :              * then the Var will have the trigger's relation's rowtype, so its
    4809             :              * names are fine.)  Also, if the creator of the RTE didn't bother
    4810             :              * to fill in an eref field, assume our column names are OK. (This
    4811             :              * happens in COPY, and perhaps other places.)
    4812             :              */
    4813        1064 :             if (econtext->ecxt_estate &&
    4814        1064 :                 variable->varno <= econtext->ecxt_estate->es_range_table_size)
    4815             :             {
    4816        1064 :                 RangeTblEntry *rte = exec_rt_fetch(variable->varno,
    4817        1064 :                                                    econtext->ecxt_estate);
    4818             : 
    4819        1064 :                 if (rte->eref)
    4820        1064 :                     ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
    4821             :             }
    4822             :         }
    4823             : 
    4824             :         /* Bless the tupdesc if needed, and save it in the execution state */
    4825        2558 :         op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
    4826             : 
    4827        2558 :         op->d.wholerow.first = false;
    4828             :     }
    4829             : 
    4830             :     /*
    4831             :      * Make sure all columns of the slot are accessible in the slot's
    4832             :      * Datum/isnull arrays.
    4833             :      */
    4834       39298 :     slot_getallattrs(slot);
    4835             : 
    4836       39298 :     if (op->d.wholerow.slow)
    4837             :     {
    4838             :         /* Check to see if any dropped attributes are non-null */
    4839           0 :         TupleDesc   tupleDesc = slot->tts_tupleDescriptor;
    4840           0 :         TupleDesc   var_tupdesc = op->d.wholerow.tupdesc;
    4841             : 
    4842             :         Assert(var_tupdesc->natts == tupleDesc->natts);
    4843             : 
    4844           0 :         for (int i = 0; i < var_tupdesc->natts; i++)
    4845             :         {
    4846           0 :             Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
    4847           0 :             Form_pg_attribute sattr = TupleDescAttr(tupleDesc, i);
    4848             : 
    4849           0 :             if (!vattr->attisdropped)
    4850           0 :                 continue;       /* already checked non-dropped cols */
    4851           0 :             if (slot->tts_isnull[i])
    4852           0 :                 continue;       /* null is always okay */
    4853           0 :             if (vattr->attlen != sattr->attlen ||
    4854           0 :                 vattr->attalign != sattr->attalign)
    4855           0 :                 ereport(ERROR,
    4856             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    4857             :                          errmsg("table row type and query-specified row type do not match"),
    4858             :                          errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
    4859             :                                    i + 1)));
    4860             :         }
    4861             :     }
    4862             : 
    4863             :     /*
    4864             :      * Build a composite datum, making sure any toasted fields get detoasted.
    4865             :      *
    4866             :      * (Note: it is critical that we not change the slot's state here.)
    4867             :      */
    4868       39298 :     tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
    4869             :                                         slot->tts_values,
    4870             :                                         slot->tts_isnull);
    4871       39298 :     dtuple = tuple->t_data;
    4872             : 
    4873             :     /*
    4874             :      * Label the datum with the composite type info we identified before.
    4875             :      *
    4876             :      * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
    4877             :      * the tuple build step; but that seems a tad risky so let's not.)
    4878             :      */
    4879       39298 :     HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
    4880       39298 :     HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
    4881             : 
    4882       39298 :     *op->resvalue = PointerGetDatum(dtuple);
    4883       39298 :     *op->resnull = false;
    4884       39298 : }
    4885             : 
    4886             : void
    4887     6528630 : ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
    4888             :                TupleTableSlot *slot)
    4889             : {
    4890             :     Datum       d;
    4891             : 
    4892             :     /* slot_getsysattr has sufficient defenses against bad attnums */
    4893     6528630 :     d = slot_getsysattr(slot,
    4894             :                         op->d.var.attnum,
    4895             :                         op->resnull);
    4896     6528618 :     *op->resvalue = d;
    4897             :     /* this ought to be unreachable, but it's cheap enough to check */
    4898     6528618 :     if (unlikely(*op->resnull))
    4899           0 :         elog(ERROR, "failed to fetch attribute from slot");
    4900     6528618 : }
    4901             : 
    4902             : /*
    4903             :  * Transition value has not been initialized. This is the first non-NULL input
    4904             :  * value for a group. We use it as the initial value for transValue.
    4905             :  */
    4906             : void
    4907       60116 : ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
    4908             :                  ExprContext *aggcontext)
    4909             : {
    4910       60116 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    4911             :     MemoryContext oldContext;
    4912             : 
    4913             :     /*
    4914             :      * We must copy the datum into aggcontext if it is pass-by-ref. We do not
    4915             :      * need to pfree the old transValue, since it's NULL.  (We already checked
    4916             :      * that the agg's input type is binary-compatible with its transtype, so
    4917             :      * straight copy here is OK.)
    4918             :      */
    4919       60116 :     oldContext = MemoryContextSwitchTo(aggcontext->ecxt_per_tuple_memory);
    4920      120232 :     pergroup->transValue = datumCopy(fcinfo->args[1].value,
    4921       60116 :                                      pertrans->transtypeByVal,
    4922       60116 :                                      pertrans->transtypeLen);
    4923       60116 :     pergroup->transValueIsNull = false;
    4924       60116 :     pergroup->noTransValue = false;
    4925       60116 :     MemoryContextSwitchTo(oldContext);
    4926       60116 : }
    4927             : 
    4928             : /*
    4929             :  * Ensure that the new transition value is stored in the aggcontext,
    4930             :  * rather than the per-tuple context.  This should be invoked only when
    4931             :  * we know (a) the transition data type is pass-by-reference, and (b)
    4932             :  * the newValue is distinct from the oldValue.
    4933             :  *
    4934             :  * NB: This can change the current memory context.
    4935             :  *
    4936             :  * We copy the presented newValue into the aggcontext, except when the datum
    4937             :  * points to a R/W expanded object that is already a child of the aggcontext,
    4938             :  * in which case we need not copy.  We then delete the oldValue, if not null.
    4939             :  *
    4940             :  * If the presented datum points to a R/W expanded object that is a child of
    4941             :  * some other context, ideally we would just reparent it under the aggcontext.
    4942             :  * Unfortunately, that doesn't work easily, and it wouldn't help anyway for
    4943             :  * aggregate-aware transfns.  We expect that a transfn that deals in expanded
    4944             :  * objects and is aware of the memory management conventions for aggregate
    4945             :  * transition values will (1) on first call, return a R/W expanded object that
    4946             :  * is already in the right context, allowing us to do nothing here, and (2) on
    4947             :  * subsequent calls, modify and return that same object, so that control
    4948             :  * doesn't even reach here.  However, if we have a generic transfn that
    4949             :  * returns a new R/W expanded object (probably in the per-tuple context),
    4950             :  * reparenting that result would cause problems.  We'd pass that R/W object to
    4951             :  * the next invocation of the transfn, and then it would be at liberty to
    4952             :  * change or delete that object, and if it deletes it then our own attempt to
    4953             :  * delete the now-old transvalue afterwards would be a double free.  We avoid
    4954             :  * this problem by forcing the stored transvalue to always be a flat
    4955             :  * non-expanded object unless the transfn is visibly doing aggregate-aware
    4956             :  * memory management.  This is somewhat inefficient, but the best answer to
    4957             :  * that is to write a smarter transfn.
    4958             :  */
    4959             : Datum
    4960       61936 : ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
    4961             :                       Datum newValue, bool newValueIsNull,
    4962             :                       Datum oldValue, bool oldValueIsNull)
    4963             : {
    4964             :     Assert(newValue != oldValue);
    4965             : 
    4966       61936 :     if (!newValueIsNull)
    4967             :     {
    4968       61936 :         MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
    4969       62104 :         if (DatumIsReadWriteExpandedObject(newValue,
    4970             :                                            false,
    4971       61930 :                                            pertrans->transtypeLen) &&
    4972         168 :             MemoryContextGetParent(DatumGetEOHP(newValue)->eoh_context) == CurrentMemoryContext)
    4973             :              /* do nothing */ ;
    4974             :         else
    4975       61930 :             newValue = datumCopy(newValue,
    4976       61930 :                                  pertrans->transtypeByVal,
    4977       61930 :                                  pertrans->transtypeLen);
    4978             :     }
    4979             :     else
    4980             :     {
    4981             :         /*
    4982             :          * Ensure that AggStatePerGroup->transValue ends up being 0, so
    4983             :          * callers can safely compare newValue/oldValue without having to
    4984             :          * check their respective nullness.
    4985             :          */
    4986           0 :         newValue = (Datum) 0;
    4987             :     }
    4988             : 
    4989       61936 :     if (!oldValueIsNull)
    4990             :     {
    4991       61822 :         if (DatumIsReadWriteExpandedObject(oldValue,
    4992             :                                            false,
    4993             :                                            pertrans->transtypeLen))
    4994           0 :             DeleteExpandedObject(oldValue);
    4995             :         else
    4996       61822 :             pfree(DatumGetPointer(oldValue));
    4997             :     }
    4998             : 
    4999       61936 :     return newValue;
    5000             : }
    5001             : 
    5002             : /*
    5003             :  * ExecEvalPreOrderedDistinctSingle
    5004             :  *      Returns true when the aggregate transition value Datum is distinct
    5005             :  *      from the previous input Datum and returns false when the input Datum
    5006             :  *      matches the previous input Datum.
    5007             :  */
    5008             : bool
    5009      365784 : ExecEvalPreOrderedDistinctSingle(AggState *aggstate, AggStatePerTrans pertrans)
    5010             : {
    5011      365784 :     Datum       value = pertrans->transfn_fcinfo->args[1].value;
    5012      365784 :     bool        isnull = pertrans->transfn_fcinfo->args[1].isnull;
    5013             : 
    5014      365784 :     if (!pertrans->haslast ||
    5015      347532 :         pertrans->lastisnull != isnull ||
    5016      347502 :         (!isnull && !DatumGetBool(FunctionCall2Coll(&pertrans->equalfnOne,
    5017             :                                                     pertrans->aggCollation,
    5018             :                                                     pertrans->lastdatum, value))))
    5019             :     {
    5020      101908 :         if (pertrans->haslast && !pertrans->inputtypeByVal &&
    5021       25946 :             !pertrans->lastisnull)
    5022       25946 :             pfree(DatumGetPointer(pertrans->lastdatum));
    5023             : 
    5024      101908 :         pertrans->haslast = true;
    5025      101908 :         if (!isnull)
    5026             :         {
    5027             :             MemoryContext oldContext;
    5028             : 
    5029      101872 :             oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
    5030             : 
    5031      203744 :             pertrans->lastdatum = datumCopy(value, pertrans->inputtypeByVal,
    5032      101872 :                                             pertrans->inputtypeLen);
    5033             : 
    5034      101872 :             MemoryContextSwitchTo(oldContext);
    5035             :         }
    5036             :         else
    5037          36 :             pertrans->lastdatum = (Datum) 0;
    5038      101908 :         pertrans->lastisnull = isnull;
    5039      101908 :         return true;
    5040             :     }
    5041             : 
    5042      263876 :     return false;
    5043             : }
    5044             : 
    5045             : /*
    5046             :  * ExecEvalPreOrderedDistinctMulti
    5047             :  *      Returns true when the aggregate input is distinct from the previous
    5048             :  *      input and returns false when the input matches the previous input, or
    5049             :  *      when there was no previous input.
    5050             :  */
    5051             : bool
    5052         720 : ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans)
    5053             : {
    5054         720 :     ExprContext *tmpcontext = aggstate->tmpcontext;
    5055         720 :     bool        isdistinct = false; /* for now */
    5056             :     TupleTableSlot *save_outer;
    5057             :     TupleTableSlot *save_inner;
    5058             : 
    5059        2820 :     for (int i = 0; i < pertrans->numTransInputs; i++)
    5060             :     {
    5061        2100 :         pertrans->sortslot->tts_values[i] = pertrans->transfn_fcinfo->args[i + 1].value;
    5062        2100 :         pertrans->sortslot->tts_isnull[i] = pertrans->transfn_fcinfo->args[i + 1].isnull;
    5063             :     }
    5064             : 
    5065         720 :     ExecClearTuple(pertrans->sortslot);
    5066         720 :     pertrans->sortslot->tts_nvalid = pertrans->numInputs;
    5067         720 :     ExecStoreVirtualTuple(pertrans->sortslot);
    5068             : 
    5069             :     /* save the previous slots before we overwrite them */
    5070         720 :     save_outer = tmpcontext->ecxt_outertuple;
    5071         720 :     save_inner = tmpcontext->ecxt_innertuple;
    5072             : 
    5073         720 :     tmpcontext->ecxt_outertuple = pertrans->sortslot;
    5074         720 :     tmpcontext->ecxt_innertuple = pertrans->uniqslot;
    5075             : 
    5076         720 :     if (!pertrans->haslast ||
    5077         624 :         !ExecQual(pertrans->equalfnMulti, tmpcontext))
    5078             :     {
    5079         312 :         if (pertrans->haslast)
    5080         216 :             ExecClearTuple(pertrans->uniqslot);
    5081             : 
    5082         312 :         pertrans->haslast = true;
    5083         312 :         ExecCopySlot(pertrans->uniqslot, pertrans->sortslot);
    5084             : 
    5085         312 :         isdistinct = true;
    5086             :     }
    5087             : 
    5088             :     /* restore the original slots */
    5089         720 :     tmpcontext->ecxt_outertuple = save_outer;
    5090         720 :     tmpcontext->ecxt_innertuple = save_inner;
    5091             : 
    5092         720 :     return isdistinct;
    5093             : }
    5094             : 
    5095             : /*
    5096             :  * Invoke ordered transition function, with a datum argument.
    5097             :  */
    5098             : void
    5099      844384 : ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op,
    5100             :                              ExprContext *econtext)
    5101             : {
    5102      844384 :     AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    5103      844384 :     int         setno = op->d.agg_trans.setno;
    5104             : 
    5105      844384 :     tuplesort_putdatum(pertrans->sortstates[setno],
    5106      844384 :                        *op->resvalue, *op->resnull);
    5107      844384 : }
    5108             : 
    5109             : /*
    5110             :  * Invoke ordered transition function, with a tuple argument.
    5111             :  */
    5112             : void
    5113         180 : ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
    5114             :                              ExprContext *econtext)
    5115             : {
    5116         180 :     AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
    5117         180 :     int         setno = op->d.agg_trans.setno;
    5118             : 
    5119         180 :     ExecClearTuple(pertrans->sortslot);
    5120         180 :     pertrans->sortslot->tts_nvalid = pertrans->numInputs;
    5121         180 :     ExecStoreVirtualTuple(pertrans->sortslot);
    5122         180 :     tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
    5123         180 : }
    5124             : 
    5125             : /* implementation of transition function invocation for byval types */
    5126             : static pg_attribute_always_inline void
    5127    27079378 : ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
    5128             :                        AggStatePerGroup pergroup,
    5129             :                        ExprContext *aggcontext, int setno)
    5130             : {
    5131    27079378 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    5132             :     MemoryContext oldContext;
    5133             :     Datum       newVal;
    5134             : 
    5135             :     /* cf. select_current_set() */
    5136    27079378 :     aggstate->curaggcontext = aggcontext;
    5137    27079378 :     aggstate->current_set = setno;
    5138             : 
    5139             :     /* set up aggstate->curpertrans for AggGetAggref() */
    5140    27079378 :     aggstate->curpertrans = pertrans;
    5141             : 
    5142             :     /* invoke transition function in per-tuple context */
    5143    27079378 :     oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    5144             : 
    5145    27079378 :     fcinfo->args[0].value = pergroup->transValue;
    5146    27079378 :     fcinfo->args[0].isnull = pergroup->transValueIsNull;
    5147    27079378 :     fcinfo->isnull = false;      /* just in case transfn doesn't set it */
    5148             : 
    5149    27079378 :     newVal = FunctionCallInvoke(fcinfo);
    5150             : 
    5151    27079318 :     pergroup->transValue = newVal;
    5152    27079318 :     pergroup->transValueIsNull = fcinfo->isnull;
    5153             : 
    5154    27079318 :     MemoryContextSwitchTo(oldContext);
    5155    27079318 : }
    5156             : 
    5157             : /* implementation of transition function invocation for byref types */
    5158             : static pg_attribute_always_inline void
    5159     2805902 : ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
    5160             :                        AggStatePerGroup pergroup,
    5161             :                        ExprContext *aggcontext, int setno)
    5162             : {
    5163     2805902 :     FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
    5164             :     MemoryContext oldContext;
    5165             :     Datum       newVal;
    5166             : 
    5167             :     /* cf. select_current_set() */
    5168     2805902 :     aggstate->curaggcontext = aggcontext;
    5169     2805902 :     aggstate->current_set = setno;
    5170             : 
    5171             :     /* set up aggstate->curpertrans for AggGetAggref() */
    5172     2805902 :     aggstate->curpertrans = pertrans;
    5173             : 
    5174             :     /* invoke transition function in per-tuple context */
    5175     2805902 :     oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
    5176             : 
    5177     2805902 :     fcinfo->args[0].value = pergroup->transValue;
    5178     2805902 :     fcinfo->args[0].isnull = pergroup->transValueIsNull;
    5179     2805902 :     fcinfo->isnull = false;      /* just in case transfn doesn't set it */
    5180             : 
    5181     2805902 :     newVal = FunctionCallInvoke(fcinfo);
    5182             : 
    5183             :     /*
    5184             :      * For pass-by-ref datatype, must copy the new value into aggcontext and
    5185             :      * free the prior transValue.  But if transfn returned a pointer to its
    5186             :      * first input, we don't need to do anything.
    5187             :      *
    5188             :      * It's safe to compare newVal with pergroup->transValue without regard
    5189             :      * for either being NULL, because ExecAggCopyTransValue takes care to set
    5190             :      * transValue to 0 when NULL. Otherwise we could end up accidentally not
    5191             :      * reparenting, when the transValue has the same numerical value as
    5192             :      * newValue, despite being NULL.  This is a somewhat hot path, making it
    5193             :      * undesirable to instead solve this with another branch for the common
    5194             :      * case of the transition function returning its (modified) input
    5195             :      * argument.
    5196             :      */
    5197     2805896 :     if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
    5198       38740 :         newVal = ExecAggCopyTransValue(aggstate, pertrans,
    5199       38740 :                                        newVal, fcinfo->isnull,
    5200             :                                        pergroup->transValue,
    5201       38740 :                                        pergroup->transValueIsNull);
    5202             : 
    5203     2805896 :     pergroup->transValue = newVal;
    5204     2805896 :     pergroup->transValueIsNull = fcinfo->isnull;
    5205             : 
    5206     2805896 :     MemoryContextSwitchTo(oldContext);
    5207     2805896 : }

Generated by: LCOV version 1.14