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

Generated by: LCOV version 1.14