LCOV - code coverage report
Current view: top level - src/backend/executor - execExprInterp.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 977 1135 86.1 %
Date: 2017-09-29 15:12:54 Functions: 43 45 95.6 %
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 simple scalar Var
      38             :  * and Const expressions using special fast-path routines (ExecJust*).
      39             :  * Benchmarking shows anything more complex than those may as well use the
      40             :  * "full interpreter".
      41             :  *
      42             :  * Complex or uncommon instructions are not implemented in-line in
      43             :  * ExecInterpExpr(), rather we call out to a helper function appearing later
      44             :  * in this file.  For one reason, there'd not be a noticeable performance
      45             :  * benefit, but more importantly those complex routines are intended to be
      46             :  * shared between different expression evaluation approaches.  For instance
      47             :  * a JIT compiler would generate calls to them.  (This is why they are
      48             :  * exported rather than being "static" in this file.)
      49             :  *
      50             :  *
      51             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
      52             :  * Portions Copyright (c) 1994, Regents of the University of California
      53             :  *
      54             :  * IDENTIFICATION
      55             :  *    src/backend/executor/execExprInterp.c
      56             :  *
      57             :  *-------------------------------------------------------------------------
      58             :  */
      59             : #include "postgres.h"
      60             : 
      61             : #include "access/tuptoaster.h"
      62             : #include "catalog/pg_type.h"
      63             : #include "commands/sequence.h"
      64             : #include "executor/execExpr.h"
      65             : #include "executor/nodeSubplan.h"
      66             : #include "funcapi.h"
      67             : #include "miscadmin.h"
      68             : #include "nodes/nodeFuncs.h"
      69             : #include "parser/parsetree.h"
      70             : #include "pgstat.h"
      71             : #include "utils/builtins.h"
      72             : #include "utils/date.h"
      73             : #include "utils/lsyscache.h"
      74             : #include "utils/timestamp.h"
      75             : #include "utils/typcache.h"
      76             : #include "utils/xml.h"
      77             : 
      78             : 
      79             : /*
      80             :  * Use computed-goto-based opcode dispatch when computed gotos are available.
      81             :  * But use a separate symbol so that it's easy to adjust locally in this file
      82             :  * for development and testing.
      83             :  */
      84             : #ifdef HAVE_COMPUTED_GOTO
      85             : #define EEO_USE_COMPUTED_GOTO
      86             : #endif                          /* HAVE_COMPUTED_GOTO */
      87             : 
      88             : /*
      89             :  * Macros for opcode dispatch.
      90             :  *
      91             :  * EEO_SWITCH - just hides the switch if not in use.
      92             :  * EEO_CASE - labels the implementation of named expression step type.
      93             :  * EEO_DISPATCH - jump to the implementation of the step type for 'op'.
      94             :  * EEO_OPCODE - compute opcode required by used expression evaluation method.
      95             :  * EEO_NEXT - increment 'op' and jump to correct next step type.
      96             :  * EEO_JUMP - jump to the specified step number within the current expression.
      97             :  */
      98             : #if defined(EEO_USE_COMPUTED_GOTO)
      99             : 
     100             : /* to make dispatch_table accessible outside ExecInterpExpr() */
     101             : static const void **dispatch_table = NULL;
     102             : 
     103             : #define EEO_SWITCH()
     104             : #define EEO_CASE(name)      CASE_##name:
     105             : #define EEO_DISPATCH()      goto *((void *) op->opcode)
     106             : #define EEO_OPCODE(opcode)  ((intptr_t) dispatch_table[opcode])
     107             : 
     108             : #else                           /* !EEO_USE_COMPUTED_GOTO */
     109             : 
     110             : #define EEO_SWITCH()        starteval: switch ((ExprEvalOp) op->opcode)
     111             : #define EEO_CASE(name)      case name:
     112             : #define EEO_DISPATCH()      goto starteval
     113             : #define EEO_OPCODE(opcode)  (opcode)
     114             : 
     115             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     116             : 
     117             : #define EEO_NEXT() \
     118             :     do { \
     119             :         op++; \
     120             :         EEO_DISPATCH(); \
     121             :     } while (0)
     122             : 
     123             : #define EEO_JUMP(stepno) \
     124             :     do { \
     125             :         op = &state->steps[stepno]; \
     126             :         EEO_DISPATCH(); \
     127             :     } while (0)
     128             : 
     129             : 
     130             : static Datum ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull);
     131             : static void ExecInitInterpreter(void);
     132             : 
     133             : /* support functions */
     134             : static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype);
     135             : static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
     136             :                    TupleDesc *cache_field, ExprContext *econtext);
     137             : static void ShutdownTupleDescRef(Datum arg);
     138             : static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
     139             :                    ExprContext *econtext, bool checkisnull);
     140             : 
     141             : /* fast-path evaluation functions */
     142             : static Datum ExecJustInnerVarFirst(ExprState *state, ExprContext *econtext, bool *isnull);
     143             : static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
     144             : static Datum ExecJustOuterVarFirst(ExprState *state, ExprContext *econtext, bool *isnull);
     145             : static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
     146             : static Datum ExecJustScanVarFirst(ExprState *state, ExprContext *econtext, bool *isnull);
     147             : static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
     148             : static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull);
     149             : static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
     150             : static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
     151             : static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
     152             : 
     153             : 
     154             : /*
     155             :  * Prepare ExprState for interpreted execution.
     156             :  */
     157             : void
     158      108107 : ExecReadyInterpretedExpr(ExprState *state)
     159             : {
     160             :     /* Ensure one-time interpreter setup has been done */
     161      108107 :     ExecInitInterpreter();
     162             : 
     163             :     /* Simple validity checks on expression */
     164      108107 :     Assert(state->steps_len >= 1);
     165      108107 :     Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE);
     166             : 
     167             :     /*
     168             :      * Don't perform redundant initialization. This is unreachable in current
     169             :      * cases, but might be hit if there's additional expression evaluation
     170             :      * methods that rely on interpreted execution to work.
     171             :      */
     172      108107 :     if (state->flags & EEO_FLAG_INTERPRETER_INITIALIZED)
     173           0 :         return;
     174             : 
     175             :     /* DIRECT_THREADED should not already be set */
     176      108107 :     Assert((state->flags & EEO_FLAG_DIRECT_THREADED) == 0);
     177             : 
     178             :     /*
     179             :      * There shouldn't be any errors before the expression is fully
     180             :      * initialized, and even if so, it'd lead to the expression being
     181             :      * abandoned.  So we can set the flag now and save some code.
     182             :      */
     183      108107 :     state->flags |= EEO_FLAG_INTERPRETER_INITIALIZED;
     184             : 
     185             :     /*
     186             :      * Select fast-path evalfuncs for very simple expressions.  "Starting up"
     187             :      * the full interpreter is a measurable overhead for these.  Plain Vars
     188             :      * and Const seem to be the only ones where the intrinsic cost is small
     189             :      * enough that the overhead of ExecInterpExpr matters.  For more complex
     190             :      * expressions it's cheaper to use ExecInterpExpr always.
     191             :      */
     192      108107 :     if (state->steps_len == 3)
     193             :     {
     194       26699 :         ExprEvalOp  step0 = state->steps[0].opcode;
     195       26699 :         ExprEvalOp  step1 = state->steps[1].opcode;
     196             : 
     197       26699 :         if (step0 == EEOP_INNER_FETCHSOME &&
     198             :             step1 == EEOP_INNER_VAR_FIRST)
     199             :         {
     200        1770 :             state->evalfunc = ExecJustInnerVarFirst;
     201        1770 :             return;
     202             :         }
     203       24929 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     204             :                  step1 == EEOP_OUTER_VAR_FIRST)
     205             :         {
     206        2088 :             state->evalfunc = ExecJustOuterVarFirst;
     207        2088 :             return;
     208             :         }
     209       22841 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     210             :                  step1 == EEOP_SCAN_VAR_FIRST)
     211             :         {
     212        1837 :             state->evalfunc = ExecJustScanVarFirst;
     213        1837 :             return;
     214             :         }
     215       21004 :         else if (step0 == EEOP_INNER_FETCHSOME &&
     216             :                  step1 == EEOP_ASSIGN_INNER_VAR)
     217             :         {
     218          63 :             state->evalfunc = ExecJustAssignInnerVar;
     219          63 :             return;
     220             :         }
     221       20941 :         else if (step0 == EEOP_OUTER_FETCHSOME &&
     222             :                  step1 == EEOP_ASSIGN_OUTER_VAR)
     223             :         {
     224        2300 :             state->evalfunc = ExecJustAssignOuterVar;
     225        2300 :             return;
     226             :         }
     227       18641 :         else if (step0 == EEOP_SCAN_FETCHSOME &&
     228             :                  step1 == EEOP_ASSIGN_SCAN_VAR)
     229             :         {
     230        2519 :             state->evalfunc = ExecJustAssignScanVar;
     231        2519 :             return;
     232             :         }
     233             :     }
     234      122925 :     else if (state->steps_len == 2 &&
     235       41517 :              state->steps[0].opcode == EEOP_CONST)
     236             :     {
     237       17068 :         state->evalfunc = ExecJustConst;
     238       17068 :         return;
     239             :     }
     240             : 
     241             : #if defined(EEO_USE_COMPUTED_GOTO)
     242             : 
     243             :     /*
     244             :      * In the direct-threaded implementation, replace each opcode with the
     245             :      * address to jump to.  (Use ExecEvalStepOp() to get back the opcode.)
     246             :      */
     247             :     {
     248             :         int         off;
     249             : 
     250      465415 :         for (off = 0; off < state->steps_len; off++)
     251             :         {
     252      384953 :             ExprEvalStep *op = &state->steps[off];
     253             : 
     254      384953 :             op->opcode = EEO_OPCODE(op->opcode);
     255             :         }
     256             : 
     257       80462 :         state->flags |= EEO_FLAG_DIRECT_THREADED;
     258             :     }
     259             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     260             : 
     261       80462 :     state->evalfunc = ExecInterpExpr;
     262             : }
     263             : 
     264             : 
     265             : /*
     266             :  * Evaluate expression identified by "state" in the execution context
     267             :  * given by "econtext".  *isnull is set to the is-null flag for the result,
     268             :  * and the Datum value is the function result.
     269             :  *
     270             :  * As a special case, return the dispatch table's address if state is NULL.
     271             :  * This is used by ExecInitInterpreter to set up the dispatch_table global.
     272             :  * (Only applies when EEO_USE_COMPUTED_GOTO is defined.)
     273             :  */
     274             : static Datum
     275    21820228 : ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
     276             : {
     277             :     ExprEvalStep *op;
     278             :     TupleTableSlot *resultslot;
     279             :     TupleTableSlot *innerslot;
     280             :     TupleTableSlot *outerslot;
     281             :     TupleTableSlot *scanslot;
     282             : 
     283             :     /*
     284             :      * This array has to be in the same order as enum ExprEvalOp.
     285             :      */
     286             : #if defined(EEO_USE_COMPUTED_GOTO)
     287             :     static const void *const dispatch_table[] = {
     288             :         &&CASE_EEOP_DONE,
     289             :         &&CASE_EEOP_INNER_FETCHSOME,
     290             :         &&CASE_EEOP_OUTER_FETCHSOME,
     291             :         &&CASE_EEOP_SCAN_FETCHSOME,
     292             :         &&CASE_EEOP_INNER_VAR_FIRST,
     293             :         &&CASE_EEOP_INNER_VAR,
     294             :         &&CASE_EEOP_OUTER_VAR_FIRST,
     295             :         &&CASE_EEOP_OUTER_VAR,
     296             :         &&CASE_EEOP_SCAN_VAR_FIRST,
     297             :         &&CASE_EEOP_SCAN_VAR,
     298             :         &&CASE_EEOP_INNER_SYSVAR,
     299             :         &&CASE_EEOP_OUTER_SYSVAR,
     300             :         &&CASE_EEOP_SCAN_SYSVAR,
     301             :         &&CASE_EEOP_WHOLEROW,
     302             :         &&CASE_EEOP_ASSIGN_INNER_VAR,
     303             :         &&CASE_EEOP_ASSIGN_OUTER_VAR,
     304             :         &&CASE_EEOP_ASSIGN_SCAN_VAR,
     305             :         &&CASE_EEOP_ASSIGN_TMP,
     306             :         &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
     307             :         &&CASE_EEOP_CONST,
     308             :         &&CASE_EEOP_FUNCEXPR,
     309             :         &&CASE_EEOP_FUNCEXPR_STRICT,
     310             :         &&CASE_EEOP_FUNCEXPR_FUSAGE,
     311             :         &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
     312             :         &&CASE_EEOP_BOOL_AND_STEP_FIRST,
     313             :         &&CASE_EEOP_BOOL_AND_STEP,
     314             :         &&CASE_EEOP_BOOL_AND_STEP_LAST,
     315             :         &&CASE_EEOP_BOOL_OR_STEP_FIRST,
     316             :         &&CASE_EEOP_BOOL_OR_STEP,
     317             :         &&CASE_EEOP_BOOL_OR_STEP_LAST,
     318             :         &&CASE_EEOP_BOOL_NOT_STEP,
     319             :         &&CASE_EEOP_QUAL,
     320             :         &&CASE_EEOP_JUMP,
     321             :         &&CASE_EEOP_JUMP_IF_NULL,
     322             :         &&CASE_EEOP_JUMP_IF_NOT_NULL,
     323             :         &&CASE_EEOP_JUMP_IF_NOT_TRUE,
     324             :         &&CASE_EEOP_NULLTEST_ISNULL,
     325             :         &&CASE_EEOP_NULLTEST_ISNOTNULL,
     326             :         &&CASE_EEOP_NULLTEST_ROWISNULL,
     327             :         &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
     328             :         &&CASE_EEOP_BOOLTEST_IS_TRUE,
     329             :         &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
     330             :         &&CASE_EEOP_BOOLTEST_IS_FALSE,
     331             :         &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
     332             :         &&CASE_EEOP_PARAM_EXEC,
     333             :         &&CASE_EEOP_PARAM_EXTERN,
     334             :         &&CASE_EEOP_CASE_TESTVAL,
     335             :         &&CASE_EEOP_MAKE_READONLY,
     336             :         &&CASE_EEOP_IOCOERCE,
     337             :         &&CASE_EEOP_DISTINCT,
     338             :         &&CASE_EEOP_NULLIF,
     339             :         &&CASE_EEOP_SQLVALUEFUNCTION,
     340             :         &&CASE_EEOP_CURRENTOFEXPR,
     341             :         &&CASE_EEOP_NEXTVALUEEXPR,
     342             :         &&CASE_EEOP_ARRAYEXPR,
     343             :         &&CASE_EEOP_ARRAYCOERCE,
     344             :         &&CASE_EEOP_ROW,
     345             :         &&CASE_EEOP_ROWCOMPARE_STEP,
     346             :         &&CASE_EEOP_ROWCOMPARE_FINAL,
     347             :         &&CASE_EEOP_MINMAX,
     348             :         &&CASE_EEOP_FIELDSELECT,
     349             :         &&CASE_EEOP_FIELDSTORE_DEFORM,
     350             :         &&CASE_EEOP_FIELDSTORE_FORM,
     351             :         &&CASE_EEOP_ARRAYREF_SUBSCRIPT,
     352             :         &&CASE_EEOP_ARRAYREF_OLD,
     353             :         &&CASE_EEOP_ARRAYREF_ASSIGN,
     354             :         &&CASE_EEOP_ARRAYREF_FETCH,
     355             :         &&CASE_EEOP_DOMAIN_TESTVAL,
     356             :         &&CASE_EEOP_DOMAIN_NOTNULL,
     357             :         &&CASE_EEOP_DOMAIN_CHECK,
     358             :         &&CASE_EEOP_CONVERT_ROWTYPE,
     359             :         &&CASE_EEOP_SCALARARRAYOP,
     360             :         &&CASE_EEOP_XMLEXPR,
     361             :         &&CASE_EEOP_AGGREF,
     362             :         &&CASE_EEOP_GROUPING_FUNC,
     363             :         &&CASE_EEOP_WINDOW_FUNC,
     364             :         &&CASE_EEOP_SUBPLAN,
     365             :         &&CASE_EEOP_ALTERNATIVE_SUBPLAN,
     366             :         &&CASE_EEOP_LAST
     367             :     };
     368             : 
     369             :     StaticAssertStmt(EEOP_LAST + 1 == lengthof(dispatch_table),
     370             :                      "dispatch_table out of whack with ExprEvalOp");
     371             : 
     372    21820228 :     if (unlikely(state == NULL))
     373         309 :         return PointerGetDatum(dispatch_table);
     374             : #else
     375             :     Assert(state != NULL);
     376             : #endif                          /* EEO_USE_COMPUTED_GOTO */
     377             : 
     378             :     /* setup state */
     379    21819919 :     op = state->steps;
     380    21819919 :     resultslot = state->resultslot;
     381    21819919 :     innerslot = econtext->ecxt_innertuple;
     382    21819919 :     outerslot = econtext->ecxt_outertuple;
     383    21819919 :     scanslot = econtext->ecxt_scantuple;
     384             : 
     385             : #if defined(EEO_USE_COMPUTED_GOTO)
     386    21819919 :     EEO_DISPATCH();
     387             : #endif
     388             : 
     389             :     EEO_SWITCH()
     390             :     {
     391             :         EEO_CASE(EEOP_DONE)
     392             :         {
     393    21816800 :             goto out;
     394             :         }
     395             : 
     396             :         EEO_CASE(EEOP_INNER_FETCHSOME)
     397             :         {
     398             :             /* XXX: worthwhile to check tts_nvalid inline first? */
     399      700465 :             slot_getsomeattrs(innerslot, op->d.fetch.last_var);
     400             : 
     401      700465 :             EEO_NEXT();
     402             :         }
     403             : 
     404             :         EEO_CASE(EEOP_OUTER_FETCHSOME)
     405             :         {
     406      894291 :             slot_getsomeattrs(outerslot, op->d.fetch.last_var);
     407             : 
     408      894291 :             EEO_NEXT();
     409             :         }
     410             : 
     411             :         EEO_CASE(EEOP_SCAN_FETCHSOME)
     412             :         {
     413     2802489 :             slot_getsomeattrs(scanslot, op->d.fetch.last_var);
     414             : 
     415     2802489 :             EEO_NEXT();
     416             :         }
     417             : 
     418             :         EEO_CASE(EEOP_INNER_VAR_FIRST)
     419             :         {
     420        2086 :             int         attnum = op->d.var.attnum;
     421             : 
     422             :             /*
     423             :              * First time through, check whether attribute matches Var.  Might
     424             :              * not be ok anymore, due to schema changes.
     425             :              */
     426        2086 :             CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
     427             : 
     428             :             /* Skip that check on subsequent evaluations */
     429        2086 :             op->opcode = EEO_OPCODE(EEOP_INNER_VAR);
     430             : 
     431             :             /* FALL THROUGH to EEOP_INNER_VAR */
     432             :         }
     433             : 
     434             :         EEO_CASE(EEOP_INNER_VAR)
     435             :         {
     436      678951 :             int         attnum = op->d.var.attnum;
     437             : 
     438             :             /*
     439             :              * Since we already extracted all referenced columns from the
     440             :              * tuple with a FETCHSOME step, we can just grab the value
     441             :              * directly out of the slot's decomposed-data arrays.  But let's
     442             :              * have an Assert to check that that did happen.
     443             :              */
     444      678951 :             Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
     445      678951 :             *op->resvalue = innerslot->tts_values[attnum];
     446      678951 :             *op->resnull = innerslot->tts_isnull[attnum];
     447             : 
     448      678951 :             EEO_NEXT();
     449             :         }
     450             : 
     451             :         EEO_CASE(EEOP_OUTER_VAR_FIRST)
     452             :         {
     453        3129 :             int         attnum = op->d.var.attnum;
     454             : 
     455             :             /* See EEOP_INNER_VAR_FIRST comments */
     456             : 
     457        3129 :             CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
     458        3129 :             op->opcode = EEO_OPCODE(EEOP_OUTER_VAR);
     459             : 
     460             :             /* FALL THROUGH to EEOP_OUTER_VAR */
     461             :         }
     462             : 
     463             :         EEO_CASE(EEOP_OUTER_VAR)
     464             :         {
     465      727435 :             int         attnum = op->d.var.attnum;
     466             : 
     467             :             /* See EEOP_INNER_VAR comments */
     468             : 
     469      727435 :             Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
     470      727435 :             *op->resvalue = outerslot->tts_values[attnum];
     471      727435 :             *op->resnull = outerslot->tts_isnull[attnum];
     472             : 
     473      727435 :             EEO_NEXT();
     474             :         }
     475             : 
     476             :         EEO_CASE(EEOP_SCAN_VAR_FIRST)
     477             :         {
     478       11600 :             int         attnum = op->d.var.attnum;
     479             : 
     480             :             /* See EEOP_INNER_VAR_FIRST comments */
     481             : 
     482       11600 :             CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
     483       11596 :             op->opcode = EEO_OPCODE(EEOP_SCAN_VAR);
     484             : 
     485             :             /* FALL THROUGH to EEOP_SCAN_VAR */
     486             :         }
     487             : 
     488             :         EEO_CASE(EEOP_SCAN_VAR)
     489             :         {
     490     2878243 :             int         attnum = op->d.var.attnum;
     491             : 
     492             :             /* See EEOP_INNER_VAR comments */
     493             : 
     494     2878243 :             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
     495     2878243 :             *op->resvalue = scanslot->tts_values[attnum];
     496     2878243 :             *op->resnull = scanslot->tts_isnull[attnum];
     497             : 
     498     2878243 :             EEO_NEXT();
     499             :         }
     500             : 
     501             :         EEO_CASE(EEOP_INNER_SYSVAR)
     502             :         {
     503           0 :             int         attnum = op->d.var.attnum;
     504             : 
     505             :             /* these asserts must match defenses in slot_getattr */
     506           0 :             Assert(innerslot->tts_tuple != NULL);
     507           0 :             Assert(innerslot->tts_tuple != &(innerslot->tts_minhdr));
     508             :             /* heap_getsysattr has sufficient defenses against bad attnums */
     509             : 
     510           0 :             *op->resvalue = heap_getsysattr(innerslot->tts_tuple, attnum,
     511             :                                             innerslot->tts_tupleDescriptor,
     512             :                                             op->resnull);
     513             : 
     514           0 :             EEO_NEXT();
     515             :         }
     516             : 
     517             :         EEO_CASE(EEOP_OUTER_SYSVAR)
     518             :         {
     519           0 :             int         attnum = op->d.var.attnum;
     520             : 
     521             :             /* these asserts must match defenses in slot_getattr */
     522           0 :             Assert(outerslot->tts_tuple != NULL);
     523           0 :             Assert(outerslot->tts_tuple != &(outerslot->tts_minhdr));
     524             : 
     525             :             /* heap_getsysattr has sufficient defenses against bad attnums */
     526           0 :             *op->resvalue = heap_getsysattr(outerslot->tts_tuple, attnum,
     527             :                                             outerslot->tts_tupleDescriptor,
     528             :                                             op->resnull);
     529             : 
     530           0 :             EEO_NEXT();
     531             :         }
     532             : 
     533             :         EEO_CASE(EEOP_SCAN_SYSVAR)
     534             :         {
     535      575106 :             int         attnum = op->d.var.attnum;
     536             : 
     537             :             /* these asserts must match defenses in slot_getattr */
     538      575106 :             Assert(scanslot->tts_tuple != NULL);
     539      575106 :             Assert(scanslot->tts_tuple != &(scanslot->tts_minhdr));
     540             :             /* heap_getsysattr has sufficient defenses against bad attnums */
     541             : 
     542      575106 :             *op->resvalue = heap_getsysattr(scanslot->tts_tuple, attnum,
     543             :                                             scanslot->tts_tupleDescriptor,
     544             :                                             op->resnull);
     545             : 
     546      575106 :             EEO_NEXT();
     547             :         }
     548             : 
     549             :         EEO_CASE(EEOP_WHOLEROW)
     550             :         {
     551             :             /* too complex for an inline implementation */
     552        1041 :             ExecEvalWholeRowVar(state, op, econtext);
     553             : 
     554        1041 :             EEO_NEXT();
     555             :         }
     556             : 
     557             :         EEO_CASE(EEOP_ASSIGN_INNER_VAR)
     558             :         {
     559      104296 :             int         resultnum = op->d.assign_var.resultnum;
     560      104296 :             int         attnum = op->d.assign_var.attnum;
     561             : 
     562             :             /*
     563             :              * We do not need CheckVarSlotCompatibility here; that was taken
     564             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     565             :              */
     566      104296 :             Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
     567      104296 :             resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
     568      104296 :             resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
     569             : 
     570      104296 :             EEO_NEXT();
     571             :         }
     572             : 
     573             :         EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
     574             :         {
     575      697309 :             int         resultnum = op->d.assign_var.resultnum;
     576      697309 :             int         attnum = op->d.assign_var.attnum;
     577             : 
     578             :             /*
     579             :              * We do not need CheckVarSlotCompatibility here; that was taken
     580             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     581             :              */
     582      697309 :             Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
     583      697309 :             resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
     584      697309 :             resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
     585             : 
     586      697309 :             EEO_NEXT();
     587             :         }
     588             : 
     589             :         EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
     590             :         {
     591     1983363 :             int         resultnum = op->d.assign_var.resultnum;
     592     1983363 :             int         attnum = op->d.assign_var.attnum;
     593             : 
     594             :             /*
     595             :              * We do not need CheckVarSlotCompatibility here; that was taken
     596             :              * care of at compilation time.  But see EEOP_INNER_VAR comments.
     597             :              */
     598     1983363 :             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
     599     1983363 :             resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
     600     1983363 :             resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
     601             : 
     602     1983363 :             EEO_NEXT();
     603             :         }
     604             : 
     605             :         EEO_CASE(EEOP_ASSIGN_TMP)
     606             :         {
     607     1622806 :             int         resultnum = op->d.assign_tmp.resultnum;
     608             : 
     609     1622806 :             resultslot->tts_values[resultnum] = state->resvalue;
     610     1622806 :             resultslot->tts_isnull[resultnum] = state->resnull;
     611             : 
     612     1622806 :             EEO_NEXT();
     613             :         }
     614             : 
     615             :         EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
     616             :         {
     617      698796 :             int         resultnum = op->d.assign_tmp.resultnum;
     618             : 
     619      698796 :             resultslot->tts_isnull[resultnum] = state->resnull;
     620      698796 :             if (!resultslot->tts_isnull[resultnum])
     621     1242878 :                 resultslot->tts_values[resultnum] =
     622      621439 :                     MakeExpandedObjectReadOnlyInternal(state->resvalue);
     623             :             else
     624       77357 :                 resultslot->tts_values[resultnum] = state->resvalue;
     625             : 
     626      698796 :             EEO_NEXT();
     627             :         }
     628             : 
     629             :         EEO_CASE(EEOP_CONST)
     630             :         {
     631     1072268 :             *op->resnull = op->d.constval.isnull;
     632     1072268 :             *op->resvalue = op->d.constval.value;
     633             : 
     634     1072268 :             EEO_NEXT();
     635             :         }
     636             : 
     637             :         /*
     638             :          * Function-call implementations. Arguments have previously been
     639             :          * evaluated directly into fcinfo->args.
     640             :          *
     641             :          * As both STRICT checks and function-usage are noticeable performance
     642             :          * wise, and function calls are a very hot-path (they also back
     643             :          * operators!), it's worth having so many separate opcodes.
     644             :          */
     645             :         EEO_CASE(EEOP_FUNCEXPR)
     646             :         {
     647       35323 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     648             : 
     649       35323 :             fcinfo->isnull = false;
     650       35323 :             *op->resvalue = (op->d.func.fn_addr) (fcinfo);
     651       32915 :             *op->resnull = fcinfo->isnull;
     652             : 
     653       32915 :             EEO_NEXT();
     654             :         }
     655             : 
     656             :         EEO_CASE(EEOP_FUNCEXPR_STRICT)
     657             :         {
     658     3939815 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     659     3939815 :             bool       *argnull = fcinfo->argnull;
     660             :             int         argno;
     661             : 
     662             :             /* strict function, so check for NULL args */
     663    11145542 :             for (argno = 0; argno < op->d.func.nargs; argno++)
     664             :             {
     665     7277012 :                 if (argnull[argno])
     666             :                 {
     667       71285 :                     *op->resnull = true;
     668       71285 :                     goto strictfail;
     669             :                 }
     670             :             }
     671     3868530 :             fcinfo->isnull = false;
     672     3868530 :             *op->resvalue = (op->d.func.fn_addr) (fcinfo);
     673     3867914 :             *op->resnull = fcinfo->isnull;
     674             : 
     675             :     strictfail:
     676     3939199 :             EEO_NEXT();
     677             :         }
     678             : 
     679             :         EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
     680             :         {
     681           0 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     682             :             PgStat_FunctionCallUsage fcusage;
     683             : 
     684           0 :             pgstat_init_function_usage(fcinfo, &fcusage);
     685             : 
     686           0 :             fcinfo->isnull = false;
     687           0 :             *op->resvalue = (op->d.func.fn_addr) (fcinfo);
     688           0 :             *op->resnull = fcinfo->isnull;
     689             : 
     690           0 :             pgstat_end_function_usage(&fcusage, true);
     691             : 
     692           0 :             EEO_NEXT();
     693             :         }
     694             : 
     695             :         EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
     696             :         {
     697           0 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
     698             :             PgStat_FunctionCallUsage fcusage;
     699           0 :             bool       *argnull = fcinfo->argnull;
     700             :             int         argno;
     701             : 
     702             :             /* strict function, so check for NULL args */
     703           0 :             for (argno = 0; argno < op->d.func.nargs; argno++)
     704             :             {
     705           0 :                 if (argnull[argno])
     706             :                 {
     707           0 :                     *op->resnull = true;
     708           0 :                     goto strictfail_fusage;
     709             :                 }
     710             :             }
     711             : 
     712           0 :             pgstat_init_function_usage(fcinfo, &fcusage);
     713             : 
     714           0 :             fcinfo->isnull = false;
     715           0 :             *op->resvalue = (op->d.func.fn_addr) (fcinfo);
     716           0 :             *op->resnull = fcinfo->isnull;
     717             : 
     718           0 :             pgstat_end_function_usage(&fcusage, true);
     719             : 
     720             :     strictfail_fusage:
     721           0 :             EEO_NEXT();
     722             :         }
     723             : 
     724             :         /*
     725             :          * If any of its clauses is FALSE, an AND's result is FALSE regardless
     726             :          * of the states of the rest of the clauses, so we can stop evaluating
     727             :          * and return FALSE immediately.  If none are FALSE and one or more is
     728             :          * NULL, we return NULL; otherwise we return TRUE.  This makes sense
     729             :          * when you interpret NULL as "don't know": perhaps one of the "don't
     730             :          * knows" would have been FALSE if we'd known its value.  Only when
     731             :          * all the inputs are known to be TRUE can we state confidently that
     732             :          * the AND's result is TRUE.
     733             :          */
     734             :         EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
     735             :         {
     736       35338 :             *op->d.boolexpr.anynull = false;
     737             : 
     738             :             /*
     739             :              * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the
     740             :              * same as EEOP_BOOL_AND_STEP - so fall through to that.
     741             :              */
     742             : 
     743             :             /* FALL THROUGH */
     744             :         }
     745             : 
     746             :         EEO_CASE(EEOP_BOOL_AND_STEP)
     747             :         {
     748       36094 :             if (*op->resnull)
     749             :             {
     750           5 :                 *op->d.boolexpr.anynull = true;
     751             :             }
     752       36089 :             else if (!DatumGetBool(*op->resvalue))
     753             :             {
     754             :                 /* result is already set to FALSE, need not change it */
     755             :                 /* bail out early */
     756       18909 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
     757             :             }
     758             : 
     759       17185 :             EEO_NEXT();
     760             :         }
     761             : 
     762             :         EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
     763             :         {
     764       16429 :             if (*op->resnull)
     765             :             {
     766             :                 /* result is already set to NULL, need not change it */
     767             :             }
     768       16415 :             else if (!DatumGetBool(*op->resvalue))
     769             :             {
     770             :                 /* result is already set to FALSE, need not change it */
     771             : 
     772             :                 /*
     773             :                  * No point jumping early to jumpdone - would be same target
     774             :                  * (as this is the last argument to the AND expression),
     775             :                  * except more expensive.
     776             :                  */
     777             :             }
     778        1957 :             else if (*op->d.boolexpr.anynull)
     779             :             {
     780           0 :                 *op->resvalue = (Datum) 0;
     781           0 :                 *op->resnull = true;
     782             :             }
     783             :             else
     784             :             {
     785             :                 /* result is already set to TRUE, need not change it */
     786             :             }
     787             : 
     788       16429 :             EEO_NEXT();
     789             :         }
     790             : 
     791             :         /*
     792             :          * If any of its clauses is TRUE, an OR's result is TRUE regardless of
     793             :          * the states of the rest of the clauses, so we can stop evaluating
     794             :          * and return TRUE immediately.  If none are TRUE and one or more is
     795             :          * NULL, we return NULL; otherwise we return FALSE.  This makes sense
     796             :          * when you interpret NULL as "don't know": perhaps one of the "don't
     797             :          * knows" would have been TRUE if we'd known its value.  Only when all
     798             :          * the inputs are known to be FALSE can we state confidently that the
     799             :          * OR's result is FALSE.
     800             :          */
     801             :         EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
     802             :         {
     803      170003 :             *op->d.boolexpr.anynull = false;
     804             : 
     805             :             /*
     806             :              * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same
     807             :              * as EEOP_BOOL_OR_STEP - so fall through to that.
     808             :              */
     809             : 
     810             :             /* FALL THROUGH */
     811             :         }
     812             : 
     813             :         EEO_CASE(EEOP_BOOL_OR_STEP)
     814             :         {
     815      289946 :             if (*op->resnull)
     816             :             {
     817          32 :                 *op->d.boolexpr.anynull = true;
     818             :             }
     819      289914 :             else if (DatumGetBool(*op->resvalue))
     820             :             {
     821             :                 /* result is already set to TRUE, need not change it */
     822             :                 /* bail out early */
     823       53587 :                 EEO_JUMP(op->d.boolexpr.jumpdone);
     824             :             }
     825             : 
     826      236359 :             EEO_NEXT();
     827             :         }
     828             : 
     829             :         EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
     830             :         {
     831      116416 :             if (*op->resnull)
     832             :             {
     833             :                 /* result is already set to NULL, need not change it */
     834             :             }
     835      116391 :             else if (DatumGetBool(*op->resvalue))
     836             :             {
     837             :                 /* result is already set to TRUE, need not change it */
     838             : 
     839             :                 /*
     840             :                  * No point jumping to jumpdone - would be same target (as
     841             :                  * this is the last argument to the AND expression), except
     842             :                  * more expensive.
     843             :                  */
     844             :             }
     845      113181 :             else if (*op->d.boolexpr.anynull)
     846             :             {
     847          11 :                 *op->resvalue = (Datum) 0;
     848          11 :                 *op->resnull = true;
     849             :             }
     850             :             else
     851             :             {
     852             :                 /* result is already set to FALSE, need not change it */
     853             :             }
     854             : 
     855      116416 :             EEO_NEXT();
     856             :         }
     857             : 
     858             :         EEO_CASE(EEOP_BOOL_NOT_STEP)
     859             :         {
     860             :             /*
     861             :              * Evaluation of 'not' is simple... if expr is false, then return
     862             :              * 'true' and vice versa.  It's safe to do this even on a
     863             :              * nominally null value, so we ignore resnull; that means that
     864             :              * NULL in produces NULL out, which is what we want.
     865             :              */
     866      128402 :             *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
     867             : 
     868      128402 :             EEO_NEXT();
     869             :         }
     870             : 
     871             :         EEO_CASE(EEOP_QUAL)
     872             :         {
     873             :             /* simplified version of BOOL_AND_STEP for use by ExecQual() */
     874             : 
     875             :             /* If argument (also result) is false or null ... */
     876     4608294 :             if (*op->resnull ||
     877     2270830 :                 !DatumGetBool(*op->resvalue))
     878             :             {
     879             :                 /* ... bail out early, returning FALSE */
     880     1334035 :                 *op->resnull = false;
     881     1334035 :                 *op->resvalue = BoolGetDatum(false);
     882     1334035 :                 EEO_JUMP(op->d.qualexpr.jumpdone);
     883             :             }
     884             : 
     885             :             /*
     886             :              * Otherwise, leave the TRUE value in place, in case this is the
     887             :              * last qual.  Then, TRUE is the correct answer.
     888             :              */
     889             : 
     890     1003429 :             EEO_NEXT();
     891             :         }
     892             : 
     893             :         EEO_CASE(EEOP_JUMP)
     894             :         {
     895             :             /* Unconditionally jump to target step */
     896        2423 :             EEO_JUMP(op->d.jump.jumpdone);
     897             :         }
     898             : 
     899             :         EEO_CASE(EEOP_JUMP_IF_NULL)
     900             :         {
     901             :             /* Transfer control if current result is null */
     902       27009 :             if (*op->resnull)
     903         457 :                 EEO_JUMP(op->d.jump.jumpdone);
     904             : 
     905       26552 :             EEO_NEXT();
     906             :         }
     907             : 
     908             :         EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
     909             :         {
     910             :             /* Transfer control if current result is non-null */
     911       22542 :             if (!*op->resnull)
     912       12377 :                 EEO_JUMP(op->d.jump.jumpdone);
     913             : 
     914       10165 :             EEO_NEXT();
     915             :         }
     916             : 
     917             :         EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
     918             :         {
     919             :             /* Transfer control if current result is null or false */
     920       48616 :             if (*op->resnull || !DatumGetBool(*op->resvalue))
     921       46193 :                 EEO_JUMP(op->d.jump.jumpdone);
     922             : 
     923        2423 :             EEO_NEXT();
     924             :         }
     925             : 
     926             :         EEO_CASE(EEOP_NULLTEST_ISNULL)
     927             :         {
     928       20576 :             *op->resvalue = BoolGetDatum(*op->resnull);
     929       20576 :             *op->resnull = false;
     930             : 
     931       20576 :             EEO_NEXT();
     932             :         }
     933             : 
     934             :         EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
     935             :         {
     936       45406 :             *op->resvalue = BoolGetDatum(!*op->resnull);
     937       45406 :             *op->resnull = false;
     938             : 
     939       45406 :             EEO_NEXT();
     940             :         }
     941             : 
     942             :         EEO_CASE(EEOP_NULLTEST_ROWISNULL)
     943             :         {
     944             :             /* out of line implementation: too large */
     945          90 :             ExecEvalRowNull(state, op, econtext);
     946             : 
     947          90 :             EEO_NEXT();
     948             :         }
     949             : 
     950             :         EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
     951             :         {
     952             :             /* out of line implementation: too large */
     953          49 :             ExecEvalRowNotNull(state, op, econtext);
     954             : 
     955          49 :             EEO_NEXT();
     956             :         }
     957             : 
     958             :         /* BooleanTest implementations for all booltesttypes */
     959             : 
     960             :         EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
     961             :         {
     962          14 :             if (*op->resnull)
     963             :             {
     964           2 :                 *op->resvalue = BoolGetDatum(false);
     965           2 :                 *op->resnull = false;
     966             :             }
     967             :             /* else, input value is the correct output as well */
     968             : 
     969          14 :             EEO_NEXT();
     970             :         }
     971             : 
     972             :         EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE)
     973             :         {
     974         253 :             if (*op->resnull)
     975             :             {
     976           1 :                 *op->resvalue = BoolGetDatum(true);
     977           1 :                 *op->resnull = false;
     978             :             }
     979             :             else
     980         252 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
     981             : 
     982         253 :             EEO_NEXT();
     983             :         }
     984             : 
     985             :         EEO_CASE(EEOP_BOOLTEST_IS_FALSE)
     986             :         {
     987          13 :             if (*op->resnull)
     988             :             {
     989           2 :                 *op->resvalue = BoolGetDatum(false);
     990           2 :                 *op->resnull = false;
     991             :             }
     992             :             else
     993          11 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
     994             : 
     995          13 :             EEO_NEXT();
     996             :         }
     997             : 
     998             :         EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE)
     999             :         {
    1000          53 :             if (*op->resnull)
    1001             :             {
    1002           1 :                 *op->resvalue = BoolGetDatum(true);
    1003           1 :                 *op->resnull = false;
    1004             :             }
    1005             :             /* else, input value is the correct output as well */
    1006             : 
    1007          53 :             EEO_NEXT();
    1008             :         }
    1009             : 
    1010             :         EEO_CASE(EEOP_PARAM_EXEC)
    1011             :         {
    1012             :             /* out of line implementation: too large */
    1013      135806 :             ExecEvalParamExec(state, op, econtext);
    1014             : 
    1015      135804 :             EEO_NEXT();
    1016             :         }
    1017             : 
    1018             :         EEO_CASE(EEOP_PARAM_EXTERN)
    1019             :         {
    1020             :             /* out of line implementation: too large */
    1021      152588 :             ExecEvalParamExtern(state, op, econtext);
    1022      152588 :             EEO_NEXT();
    1023             :         }
    1024             : 
    1025             :         EEO_CASE(EEOP_CASE_TESTVAL)
    1026             :         {
    1027             :             /*
    1028             :              * Normally upper parts of the expression tree have setup the
    1029             :              * values to be returned here, but some parts of the system
    1030             :              * currently misuse {caseValue,domainValue}_{datum,isNull} to set
    1031             :              * run-time data.  So if no values have been set-up, use
    1032             :              * ExprContext's.  This isn't pretty, but also not *that* ugly,
    1033             :              * and this is unlikely to be performance sensitive enough to
    1034             :              * worry about an extra branch.
    1035             :              */
    1036        1075 :             if (op->d.casetest.value)
    1037             :             {
    1038         206 :                 *op->resvalue = *op->d.casetest.value;
    1039         206 :                 *op->resnull = *op->d.casetest.isnull;
    1040             :             }
    1041             :             else
    1042             :             {
    1043         869 :                 *op->resvalue = econtext->caseValue_datum;
    1044         869 :                 *op->resnull = econtext->caseValue_isNull;
    1045             :             }
    1046             : 
    1047        1075 :             EEO_NEXT();
    1048             :         }
    1049             : 
    1050             :         EEO_CASE(EEOP_DOMAIN_TESTVAL)
    1051             :         {
    1052             :             /*
    1053             :              * See EEOP_CASE_TESTVAL comment.
    1054             :              */
    1055        1898 :             if (op->d.casetest.value)
    1056             :             {
    1057         737 :                 *op->resvalue = *op->d.casetest.value;
    1058         737 :                 *op->resnull = *op->d.casetest.isnull;
    1059             :             }
    1060             :             else
    1061             :             {
    1062        1161 :                 *op->resvalue = econtext->domainValue_datum;
    1063        1161 :                 *op->resnull = econtext->domainValue_isNull;
    1064             :             }
    1065             : 
    1066        1898 :             EEO_NEXT();
    1067             :         }
    1068             : 
    1069             :         EEO_CASE(EEOP_MAKE_READONLY)
    1070             :         {
    1071             :             /*
    1072             :              * Force a varlena value that might be read multiple times to R/O
    1073             :              */
    1074         438 :             if (!*op->d.make_readonly.isnull)
    1075         868 :                 *op->resvalue =
    1076         434 :                     MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
    1077         438 :             *op->resnull = *op->d.make_readonly.isnull;
    1078             : 
    1079         438 :             EEO_NEXT();
    1080             :         }
    1081             : 
    1082             :         EEO_CASE(EEOP_IOCOERCE)
    1083             :         {
    1084             :             /*
    1085             :              * Evaluate a CoerceViaIO node.  This can be quite a hot path, so
    1086             :              * inline as much work as possible.  The source value is in our
    1087             :              * result variable.
    1088             :              */
    1089             :             char       *str;
    1090             : 
    1091             :             /* call output function (similar to OutputFunctionCall) */
    1092       89285 :             if (*op->resnull)
    1093             :             {
    1094             :                 /* output functions are not called on nulls */
    1095          65 :                 str = NULL;
    1096             :             }
    1097             :             else
    1098             :             {
    1099             :                 FunctionCallInfo fcinfo_out;
    1100             : 
    1101       89220 :                 fcinfo_out = op->d.iocoerce.fcinfo_data_out;
    1102       89220 :                 fcinfo_out->arg[0] = *op->resvalue;
    1103       89220 :                 fcinfo_out->argnull[0] = false;
    1104             : 
    1105       89220 :                 fcinfo_out->isnull = false;
    1106       89220 :                 str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
    1107             : 
    1108             :                 /* OutputFunctionCall assumes result isn't null */
    1109       89220 :                 Assert(!fcinfo_out->isnull);
    1110             :             }
    1111             : 
    1112             :             /* call input function (similar to InputFunctionCall) */
    1113       89285 :             if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
    1114             :             {
    1115             :                 FunctionCallInfo fcinfo_in;
    1116             : 
    1117       89235 :                 fcinfo_in = op->d.iocoerce.fcinfo_data_in;
    1118       89235 :                 fcinfo_in->arg[0] = PointerGetDatum(str);
    1119       89235 :                 fcinfo_in->argnull[0] = *op->resnull;
    1120             :                 /* second and third arguments are already set up */
    1121             : 
    1122       89235 :                 fcinfo_in->isnull = false;
    1123       89235 :                 *op->resvalue = FunctionCallInvoke(fcinfo_in);
    1124             : 
    1125             :                 /* Should get null result if and only if str is NULL */
    1126       89230 :                 if (str == NULL)
    1127             :                 {
    1128          14 :                     Assert(*op->resnull);
    1129          14 :                     Assert(fcinfo_in->isnull);
    1130             :                 }
    1131             :                 else
    1132             :                 {
    1133       89216 :                     Assert(!*op->resnull);
    1134       89216 :                     Assert(!fcinfo_in->isnull);
    1135             :                 }
    1136             :             }
    1137             : 
    1138       89280 :             EEO_NEXT();
    1139             :         }
    1140             : 
    1141             :         EEO_CASE(EEOP_DISTINCT)
    1142             :         {
    1143             :             /*
    1144             :              * IS DISTINCT FROM must evaluate arguments (already done into
    1145             :              * fcinfo->arg/argnull) to determine whether they are NULL; if
    1146             :              * either is NULL then the result is determined.  If neither is
    1147             :              * NULL, then proceed to evaluate the comparison function, which
    1148             :              * is just the type's standard equality operator.  We need not
    1149             :              * care whether that function is strict.  Because the handling of
    1150             :              * nulls is different, we can't just reuse EEOP_FUNCEXPR.
    1151             :              */
    1152        2535 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1153             : 
    1154             :             /* check function arguments for NULLness */
    1155        2535 :             if (fcinfo->argnull[0] && fcinfo->argnull[1])
    1156             :             {
    1157             :                 /* Both NULL? Then is not distinct... */
    1158          10 :                 *op->resvalue = BoolGetDatum(false);
    1159          10 :                 *op->resnull = false;
    1160             :             }
    1161        2525 :             else if (fcinfo->argnull[0] || fcinfo->argnull[1])
    1162             :             {
    1163             :                 /* Only one is NULL? Then is distinct... */
    1164          21 :                 *op->resvalue = BoolGetDatum(true);
    1165          21 :                 *op->resnull = false;
    1166             :             }
    1167             :             else
    1168             :             {
    1169             :                 /* Neither null, so apply the equality function */
    1170             :                 Datum       eqresult;
    1171             : 
    1172        2504 :                 fcinfo->isnull = false;
    1173        2504 :                 eqresult = (op->d.func.fn_addr) (fcinfo);
    1174             :                 /* Must invert result of "="; safe to do even if null */
    1175        2504 :                 *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
    1176        2504 :                 *op->resnull = fcinfo->isnull;
    1177             :             }
    1178             : 
    1179        2535 :             EEO_NEXT();
    1180             :         }
    1181             : 
    1182             :         EEO_CASE(EEOP_NULLIF)
    1183             :         {
    1184             :             /*
    1185             :              * The arguments are already evaluated into fcinfo->arg/argnull.
    1186             :              */
    1187        1090 :             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
    1188             : 
    1189             :             /* if either argument is NULL they can't be equal */
    1190        1090 :             if (!fcinfo->argnull[0] && !fcinfo->argnull[1])
    1191             :             {
    1192             :                 Datum       result;
    1193             : 
    1194        1081 :                 fcinfo->isnull = false;
    1195        1081 :                 result = (op->d.func.fn_addr) (fcinfo);
    1196             : 
    1197             :                 /* if the arguments are equal return null */
    1198        1081 :                 if (!fcinfo->isnull && DatumGetBool(result))
    1199             :                 {
    1200          11 :                     *op->resvalue = (Datum) 0;
    1201          11 :                     *op->resnull = true;
    1202             : 
    1203          11 :                     EEO_NEXT();
    1204             :                 }
    1205             :             }
    1206             : 
    1207             :             /* Arguments aren't equal, so return the first one */
    1208        1079 :             *op->resvalue = fcinfo->arg[0];
    1209        1079 :             *op->resnull = fcinfo->argnull[0];
    1210             : 
    1211        1079 :             EEO_NEXT();
    1212             :         }
    1213             : 
    1214             :         EEO_CASE(EEOP_SQLVALUEFUNCTION)
    1215             :         {
    1216             :             /*
    1217             :              * Doesn't seem worthwhile to have an inline implementation
    1218             :              * efficiency-wise.
    1219             :              */
    1220         750 :             ExecEvalSQLValueFunction(state, op);
    1221             : 
    1222         750 :             EEO_NEXT();
    1223             :         }
    1224             : 
    1225             :         EEO_CASE(EEOP_CURRENTOFEXPR)
    1226             :         {
    1227             :             /* error invocation uses space, and shouldn't ever occur */
    1228           0 :             ExecEvalCurrentOfExpr(state, op);
    1229             : 
    1230           0 :             EEO_NEXT();
    1231             :         }
    1232             : 
    1233             :         EEO_CASE(EEOP_NEXTVALUEEXPR)
    1234             :         {
    1235             :             /*
    1236             :              * Doesn't seem worthwhile to have an inline implementation
    1237             :              * efficiency-wise.
    1238             :              */
    1239          30 :             ExecEvalNextValueExpr(state, op);
    1240             : 
    1241          30 :             EEO_NEXT();
    1242             :         }
    1243             : 
    1244             :         EEO_CASE(EEOP_ARRAYEXPR)
    1245             :         {
    1246             :             /* too complex for an inline implementation */
    1247       35641 :             ExecEvalArrayExpr(state, op);
    1248             : 
    1249       35641 :             EEO_NEXT();
    1250             :         }
    1251             : 
    1252             :         EEO_CASE(EEOP_ARRAYCOERCE)
    1253             :         {
    1254             :             /* too complex for an inline implementation */
    1255        6258 :             ExecEvalArrayCoerce(state, op);
    1256             : 
    1257        6256 :             EEO_NEXT();
    1258             :         }
    1259             : 
    1260             :         EEO_CASE(EEOP_ROW)
    1261             :         {
    1262             :             /* too complex for an inline implementation */
    1263         645 :             ExecEvalRow(state, op);
    1264             : 
    1265         645 :             EEO_NEXT();
    1266             :         }
    1267             : 
    1268             :         EEO_CASE(EEOP_ROWCOMPARE_STEP)
    1269             :         {
    1270       63628 :             FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
    1271             : 
    1272             :             /* force NULL result if strict fn and NULL input */
    1273      127256 :             if (op->d.rowcompare_step.finfo->fn_strict &&
    1274      127256 :                 (fcinfo->argnull[0] || fcinfo->argnull[1]))
    1275             :             {
    1276           4 :                 *op->resnull = true;
    1277           4 :                 EEO_JUMP(op->d.rowcompare_step.jumpnull);
    1278             :             }
    1279             : 
    1280             :             /* Apply comparison function */
    1281       63624 :             fcinfo->isnull = false;
    1282       63624 :             *op->resvalue = (op->d.rowcompare_step.fn_addr) (fcinfo);
    1283             : 
    1284             :             /* force NULL result if NULL function result */
    1285       63624 :             if (fcinfo->isnull)
    1286             :             {
    1287           0 :                 *op->resnull = true;
    1288           0 :                 EEO_JUMP(op->d.rowcompare_step.jumpnull);
    1289             :             }
    1290       63624 :             *op->resnull = false;
    1291             : 
    1292             :             /* If unequal, no need to compare remaining columns */
    1293       63624 :             if (DatumGetInt32(*op->resvalue) != 0)
    1294             :             {
    1295       25713 :                 EEO_JUMP(op->d.rowcompare_step.jumpdone);
    1296             :             }
    1297             : 
    1298       37911 :             EEO_NEXT();
    1299             :         }
    1300             : 
    1301             :         EEO_CASE(EEOP_ROWCOMPARE_FINAL)
    1302             :         {
    1303       25713 :             int32       cmpresult = DatumGetInt32(*op->resvalue);
    1304       25713 :             RowCompareType rctype = op->d.rowcompare_final.rctype;
    1305             : 
    1306       25713 :             *op->resnull = false;
    1307       25713 :             switch (rctype)
    1308             :             {
    1309             :                     /* EQ and NE cases aren't allowed here */
    1310             :                 case ROWCOMPARE_LT:
    1311        5711 :                     *op->resvalue = BoolGetDatum(cmpresult < 0);
    1312        5711 :                     break;
    1313             :                 case ROWCOMPARE_LE:
    1314       19999 :                     *op->resvalue = BoolGetDatum(cmpresult <= 0);
    1315       19999 :                     break;
    1316             :                 case ROWCOMPARE_GE:
    1317           1 :                     *op->resvalue = BoolGetDatum(cmpresult >= 0);
    1318           1 :                     break;
    1319             :                 case ROWCOMPARE_GT:
    1320           2 :                     *op->resvalue = BoolGetDatum(cmpresult > 0);
    1321           2 :                     break;
    1322             :                 default:
    1323           0 :                     Assert(false);
    1324             :                     break;
    1325             :             }
    1326             : 
    1327       25713 :             EEO_NEXT();
    1328             :         }
    1329             : 
    1330             :         EEO_CASE(EEOP_MINMAX)
    1331             :         {
    1332             :             /* too complex for an inline implementation */
    1333          99 :             ExecEvalMinMax(state, op);
    1334             : 
    1335          99 :             EEO_NEXT();
    1336             :         }
    1337             : 
    1338             :         EEO_CASE(EEOP_FIELDSELECT)
    1339             :         {
    1340             :             /* too complex for an inline implementation */
    1341       13047 :             ExecEvalFieldSelect(state, op, econtext);
    1342             : 
    1343       13047 :             EEO_NEXT();
    1344             :         }
    1345             : 
    1346             :         EEO_CASE(EEOP_FIELDSTORE_DEFORM)
    1347             :         {
    1348             :             /* too complex for an inline implementation */
    1349          45 :             ExecEvalFieldStoreDeForm(state, op, econtext);
    1350             : 
    1351          45 :             EEO_NEXT();
    1352             :         }
    1353             : 
    1354             :         EEO_CASE(EEOP_FIELDSTORE_FORM)
    1355             :         {
    1356             :             /* too complex for an inline implementation */
    1357          45 :             ExecEvalFieldStoreForm(state, op, econtext);
    1358             : 
    1359          45 :             EEO_NEXT();
    1360             :         }
    1361             : 
    1362             :         EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT)
    1363             :         {
    1364             :             /* Process an array subscript */
    1365             : 
    1366             :             /* too complex for an inline implementation */
    1367       26864 :             if (ExecEvalArrayRefSubscript(state, op))
    1368             :             {
    1369       26858 :                 EEO_NEXT();
    1370             :             }
    1371             :             else
    1372             :             {
    1373             :                 /* Subscript is null, short-circuit ArrayRef to NULL */
    1374           3 :                 EEO_JUMP(op->d.arrayref_subscript.jumpdone);
    1375             :             }
    1376             :         }
    1377             : 
    1378             :         EEO_CASE(EEOP_ARRAYREF_OLD)
    1379             :         {
    1380             :             /*
    1381             :              * Fetch the old value in an arrayref assignment, in case it's
    1382             :              * referenced (via a CaseTestExpr) inside the assignment
    1383             :              * expression.
    1384             :              */
    1385             : 
    1386             :             /* too complex for an inline implementation */
    1387          33 :             ExecEvalArrayRefOld(state, op);
    1388             : 
    1389          33 :             EEO_NEXT();
    1390             :         }
    1391             : 
    1392             :         /*
    1393             :          * Perform ArrayRef assignment
    1394             :          */
    1395             :         EEO_CASE(EEOP_ARRAYREF_ASSIGN)
    1396             :         {
    1397             :             /* too complex for an inline implementation */
    1398         140 :             ExecEvalArrayRefAssign(state, op);
    1399             : 
    1400         137 :             EEO_NEXT();
    1401             :         }
    1402             : 
    1403             :         /*
    1404             :          * Fetch subset of an array.
    1405             :          */
    1406             :         EEO_CASE(EEOP_ARRAYREF_FETCH)
    1407             :         {
    1408             :             /* too complex for an inline implementation */
    1409       26549 :             ExecEvalArrayRefFetch(state, op);
    1410             : 
    1411       26545 :             EEO_NEXT();
    1412             :         }
    1413             : 
    1414             :         EEO_CASE(EEOP_CONVERT_ROWTYPE)
    1415             :         {
    1416             :             /* too complex for an inline implementation */
    1417          57 :             ExecEvalConvertRowtype(state, op, econtext);
    1418             : 
    1419          57 :             EEO_NEXT();
    1420             :         }
    1421             : 
    1422             :         EEO_CASE(EEOP_SCALARARRAYOP)
    1423             :         {
    1424             :             /* too complex for an inline implementation */
    1425       84404 :             ExecEvalScalarArrayOp(state, op);
    1426             : 
    1427       84404 :             EEO_NEXT();
    1428             :         }
    1429             : 
    1430             :         EEO_CASE(EEOP_DOMAIN_NOTNULL)
    1431             :         {
    1432             :             /* too complex for an inline implementation */
    1433          52 :             ExecEvalConstraintNotNull(state, op);
    1434             : 
    1435          40 :             EEO_NEXT();
    1436             :         }
    1437             : 
    1438             :         EEO_CASE(EEOP_DOMAIN_CHECK)
    1439             :         {
    1440             :             /* too complex for an inline implementation */
    1441         703 :             ExecEvalConstraintCheck(state, op);
    1442             : 
    1443         665 :             EEO_NEXT();
    1444             :         }
    1445             : 
    1446             :         EEO_CASE(EEOP_XMLEXPR)
    1447             :         {
    1448             :             /* too complex for an inline implementation */
    1449          24 :             ExecEvalXmlExpr(state, op);
    1450             : 
    1451           2 :             EEO_NEXT();
    1452             :         }
    1453             : 
    1454             :         EEO_CASE(EEOP_AGGREF)
    1455             :         {
    1456             :             /*
    1457             :              * Returns a Datum whose value is the precomputed aggregate value
    1458             :              * found in the given expression context.
    1459             :              */
    1460        4436 :             AggrefExprState *aggref = op->d.aggref.astate;
    1461             : 
    1462        4436 :             Assert(econtext->ecxt_aggvalues != NULL);
    1463             : 
    1464        4436 :             *op->resvalue = econtext->ecxt_aggvalues[aggref->aggno];
    1465        4436 :             *op->resnull = econtext->ecxt_aggnulls[aggref->aggno];
    1466             : 
    1467        4436 :             EEO_NEXT();
    1468             :         }
    1469             : 
    1470             :         EEO_CASE(EEOP_GROUPING_FUNC)
    1471             :         {
    1472             :             /* too complex/uncommon for an inline implementation */
    1473         264 :             ExecEvalGroupingFunc(state, op);
    1474             : 
    1475         264 :             EEO_NEXT();
    1476             :         }
    1477             : 
    1478             :         EEO_CASE(EEOP_WINDOW_FUNC)
    1479             :         {
    1480             :             /*
    1481             :              * Like Aggref, just return a precomputed value from the econtext.
    1482             :              */
    1483       91572 :             WindowFuncExprState *wfunc = op->d.window_func.wfstate;
    1484             : 
    1485       91572 :             Assert(econtext->ecxt_aggvalues != NULL);
    1486             : 
    1487       91572 :             *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];
    1488       91572 :             *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];
    1489             : 
    1490       91572 :             EEO_NEXT();
    1491             :         }
    1492             : 
    1493             :         EEO_CASE(EEOP_SUBPLAN)
    1494             :         {
    1495             :             /* too complex for an inline implementation */
    1496       82700 :             ExecEvalSubPlan(state, op, econtext);
    1497             : 
    1498       82700 :             EEO_NEXT();
    1499             :         }
    1500             : 
    1501             :         EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN)
    1502             :         {
    1503             :             /* too complex for an inline implementation */
    1504         143 :             ExecEvalAlternativeSubPlan(state, op, econtext);
    1505             : 
    1506         143 :             EEO_NEXT();
    1507             :         }
    1508             : 
    1509             :         EEO_CASE(EEOP_LAST)
    1510             :         {
    1511             :             /* unreachable */
    1512           0 :             Assert(false);
    1513             :             goto out;
    1514             :         }
    1515             :     }
    1516             : 
    1517             : out:
    1518    21816800 :     *isnull = state->resnull;
    1519    21816800 :     return state->resvalue;
    1520             : }
    1521             : 
    1522             : /*
    1523             :  * Check whether a user attribute in a slot can be referenced by a Var
    1524             :  * expression.  This should succeed unless there have been schema changes
    1525             :  * since the expression tree has been created.
    1526             :  */
    1527             : static void
    1528       20615 : CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
    1529             : {
    1530             :     /*
    1531             :      * What we have to check for here is the possibility of an attribute
    1532             :      * having been dropped or changed in type since the plan tree was created.
    1533             :      * Ideally the plan will get invalidated and not re-used, but just in
    1534             :      * case, we keep these defenses.  Fortunately it's sufficient to check
    1535             :      * once on the first time through.
    1536             :      *
    1537             :      * Note: ideally we'd check typmod as well as typid, but that seems
    1538             :      * impractical at the moment: in many cases the tupdesc will have been
    1539             :      * generated by ExecTypeFromTL(), and that can't guarantee to generate an
    1540             :      * accurate typmod in all cases, because some expression node types don't
    1541             :      * carry typmod.  Fortunately, for precisely that reason, there should be
    1542             :      * no places with a critical dependency on the typmod of a value.
    1543             :      *
    1544             :      * System attributes don't require checking since their types never
    1545             :      * change.
    1546             :      */
    1547       20615 :     if (attnum > 0)
    1548             :     {
    1549       20615 :         TupleDesc   slot_tupdesc = slot->tts_tupleDescriptor;
    1550             :         Form_pg_attribute attr;
    1551             : 
    1552       20615 :         if (attnum > slot_tupdesc->natts) /* should never happen */
    1553           0 :             elog(ERROR, "attribute number %d exceeds number of columns %d",
    1554             :                  attnum, slot_tupdesc->natts);
    1555             : 
    1556       20615 :         attr = TupleDescAttr(slot_tupdesc, attnum - 1);
    1557             : 
    1558       20615 :         if (attr->attisdropped)
    1559           2 :             ereport(ERROR,
    1560             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    1561             :                      errmsg("attribute %d of type %s has been dropped",
    1562             :                             attnum, format_type_be(slot_tupdesc->tdtypeid))));
    1563             : 
    1564       20613 :         if (vartype != attr->atttypid)
    1565           2 :             ereport(ERROR,
    1566             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    1567             :                      errmsg("attribute %d of type %s has wrong type",
    1568             :                             attnum, format_type_be(slot_tupdesc->tdtypeid)),
    1569             :                      errdetail("Table has type %s, but query expects %s.",
    1570             :                                format_type_be(attr->atttypid),
    1571             :                                format_type_be(vartype))));
    1572             :     }
    1573       20611 : }
    1574             : 
    1575             : /*
    1576             :  * get_cached_rowtype: utility function to lookup a rowtype tupdesc
    1577             :  *
    1578             :  * type_id, typmod: identity of the rowtype
    1579             :  * cache_field: where to cache the TupleDesc pointer in expression state node
    1580             :  *      (field must be initialized to NULL)
    1581             :  * econtext: expression context we are executing in
    1582             :  *
    1583             :  * NOTE: because the shutdown callback will be called during plan rescan,
    1584             :  * must be prepared to re-do this during any node execution; cannot call
    1585             :  * just once during expression initialization.
    1586             :  */
    1587             : static TupleDesc
    1588       13277 : get_cached_rowtype(Oid type_id, int32 typmod,
    1589             :                    TupleDesc *cache_field, ExprContext *econtext)
    1590             : {
    1591       13277 :     TupleDesc   tupDesc = *cache_field;
    1592             : 
    1593             :     /* Do lookup if no cached value or if requested type changed */
    1594       25650 :     if (tupDesc == NULL ||
    1595       24746 :         type_id != tupDesc->tdtypeid ||
    1596       12373 :         typmod != tupDesc->tdtypmod)
    1597             :     {
    1598         904 :         tupDesc = lookup_rowtype_tupdesc(type_id, typmod);
    1599             : 
    1600         904 :         if (*cache_field)
    1601             :         {
    1602             :             /* Release old tupdesc; but callback is already registered */
    1603           0 :             ReleaseTupleDesc(*cache_field);
    1604             :         }
    1605             :         else
    1606             :         {
    1607             :             /* Need to register shutdown callback to release tupdesc */
    1608         904 :             RegisterExprContextCallback(econtext,
    1609             :                                         ShutdownTupleDescRef,
    1610             :                                         PointerGetDatum(cache_field));
    1611             :         }
    1612         904 :         *cache_field = tupDesc;
    1613             :     }
    1614       13277 :     return tupDesc;
    1615             : }
    1616             : 
    1617             : /*
    1618             :  * Callback function to release a tupdesc refcount at econtext shutdown
    1619             :  */
    1620             : static void
    1621         885 : ShutdownTupleDescRef(Datum arg)
    1622             : {
    1623         885 :     TupleDesc  *cache_field = (TupleDesc *) DatumGetPointer(arg);
    1624             : 
    1625         885 :     if (*cache_field)
    1626         885 :         ReleaseTupleDesc(*cache_field);
    1627         885 :     *cache_field = NULL;
    1628         885 : }
    1629             : 
    1630             : /*
    1631             :  * Fast-path functions, for very simple expressions
    1632             :  */
    1633             : 
    1634             : /* Simple reference to inner Var, first time through */
    1635             : static Datum
    1636        1153 : ExecJustInnerVarFirst(ExprState *state, ExprContext *econtext, bool *isnull)
    1637             : {
    1638        1153 :     ExprEvalStep *op = &state->steps[1];
    1639        1153 :     int         attnum = op->d.var.attnum + 1;
    1640        1153 :     TupleTableSlot *slot = econtext->ecxt_innertuple;
    1641             : 
    1642             :     /* See ExecInterpExpr()'s comments for EEOP_INNER_VAR_FIRST */
    1643             : 
    1644        1153 :     CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype);
    1645        1153 :     op->opcode = EEOP_INNER_VAR; /* just for cleanliness */
    1646        1153 :     state->evalfunc = ExecJustInnerVar;
    1647             : 
    1648             :     /*
    1649             :      * Since we use slot_getattr(), we don't need to implement the FETCHSOME
    1650             :      * step explicitly, and we also needn't Assert that the attnum is in range
    1651             :      * --- slot_getattr() will take care of any problems.
    1652             :      */
    1653        1153 :     return slot_getattr(slot, attnum, isnull);
    1654             : }
    1655             : 
    1656             : /* Simple reference to inner Var */
    1657             : static Datum
    1658      543755 : ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    1659             : {
    1660      543755 :     ExprEvalStep *op = &state->steps[1];
    1661      543755 :     int         attnum = op->d.var.attnum + 1;
    1662      543755 :     TupleTableSlot *slot = econtext->ecxt_innertuple;
    1663             : 
    1664             :     /* See comments in ExecJustInnerVarFirst */
    1665      543755 :     return slot_getattr(slot, attnum, isnull);
    1666             : }
    1667             : 
    1668             : /* Simple reference to outer Var, first time through */
    1669             : static Datum
    1670        1376 : ExecJustOuterVarFirst(ExprState *state, ExprContext *econtext, bool *isnull)
    1671             : {
    1672        1376 :     ExprEvalStep *op = &state->steps[1];
    1673        1376 :     int         attnum = op->d.var.attnum + 1;
    1674        1376 :     TupleTableSlot *slot = econtext->ecxt_outertuple;
    1675             : 
    1676        1376 :     CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype);
    1677        1376 :     op->opcode = EEOP_OUTER_VAR; /* just for cleanliness */
    1678        1376 :     state->evalfunc = ExecJustOuterVar;
    1679             : 
    1680             :     /* See comments in ExecJustInnerVarFirst */
    1681        1376 :     return slot_getattr(slot, attnum, isnull);
    1682             : }
    1683             : 
    1684             : /* Simple reference to outer Var */
    1685             : static Datum
    1686      679974 : ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    1687             : {
    1688      679974 :     ExprEvalStep *op = &state->steps[1];
    1689      679974 :     int         attnum = op->d.var.attnum + 1;
    1690      679974 :     TupleTableSlot *slot = econtext->ecxt_outertuple;
    1691             : 
    1692             :     /* See comments in ExecJustInnerVarFirst */
    1693      679974 :     return slot_getattr(slot, attnum, isnull);
    1694             : }
    1695             : 
    1696             : /* Simple reference to scan Var, first time through */
    1697             : static Datum
    1698        1271 : ExecJustScanVarFirst(ExprState *state, ExprContext *econtext, bool *isnull)
    1699             : {
    1700        1271 :     ExprEvalStep *op = &state->steps[1];
    1701        1271 :     int         attnum = op->d.var.attnum + 1;
    1702        1271 :     TupleTableSlot *slot = econtext->ecxt_scantuple;
    1703             : 
    1704        1271 :     CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype);
    1705        1271 :     op->opcode = EEOP_SCAN_VAR; /* just for cleanliness */
    1706        1271 :     state->evalfunc = ExecJustScanVar;
    1707             : 
    1708             :     /* See comments in ExecJustInnerVarFirst */
    1709        1271 :     return slot_getattr(slot, attnum, isnull);
    1710             : }
    1711             : 
    1712             : /* Simple reference to scan Var */
    1713             : static Datum
    1714        2583 : ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    1715             : {
    1716        2583 :     ExprEvalStep *op = &state->steps[1];
    1717        2583 :     int         attnum = op->d.var.attnum + 1;
    1718        2583 :     TupleTableSlot *slot = econtext->ecxt_scantuple;
    1719             : 
    1720             :     /* See comments in ExecJustInnerVarFirst */
    1721        2583 :     return slot_getattr(slot, attnum, isnull);
    1722             : }
    1723             : 
    1724             : /* Simple Const expression */
    1725             : static Datum
    1726       35577 : ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
    1727             : {
    1728       35577 :     ExprEvalStep *op = &state->steps[0];
    1729             : 
    1730       35577 :     *isnull = op->d.constval.isnull;
    1731       35577 :     return op->d.constval.value;
    1732             : }
    1733             : 
    1734             : /* Evaluate inner Var and assign to appropriate column of result tuple */
    1735             : static Datum
    1736       20166 : ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
    1737             : {
    1738       20166 :     ExprEvalStep *op = &state->steps[1];
    1739       20166 :     int         attnum = op->d.assign_var.attnum + 1;
    1740       20166 :     int         resultnum = op->d.assign_var.resultnum;
    1741       20166 :     TupleTableSlot *inslot = econtext->ecxt_innertuple;
    1742       20166 :     TupleTableSlot *outslot = state->resultslot;
    1743             : 
    1744             :     /*
    1745             :      * We do not need CheckVarSlotCompatibility here; that was taken care of
    1746             :      * at compilation time.
    1747             :      *
    1748             :      * Since we use slot_getattr(), we don't need to implement the FETCHSOME
    1749             :      * step explicitly, and we also needn't Assert that the attnum is in range
    1750             :      * --- slot_getattr() will take care of any problems.
    1751             :      */
    1752       40332 :     outslot->tts_values[resultnum] =
    1753       20166 :         slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
    1754       20166 :     return 0;
    1755             : }
    1756             : 
    1757             : /* Evaluate outer Var and assign to appropriate column of result tuple */
    1758             : static Datum
    1759      309728 : ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
    1760             : {
    1761      309728 :     ExprEvalStep *op = &state->steps[1];
    1762      309728 :     int         attnum = op->d.assign_var.attnum + 1;
    1763      309728 :     int         resultnum = op->d.assign_var.resultnum;
    1764      309728 :     TupleTableSlot *inslot = econtext->ecxt_outertuple;
    1765      309728 :     TupleTableSlot *outslot = state->resultslot;
    1766             : 
    1767             :     /* See comments in ExecJustAssignInnerVar */
    1768      619456 :     outslot->tts_values[resultnum] =
    1769      309728 :         slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
    1770      309728 :     return 0;
    1771             : }
    1772             : 
    1773             : /* Evaluate scan Var and assign to appropriate column of result tuple */
    1774             : static Datum
    1775      185063 : ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
    1776             : {
    1777      185063 :     ExprEvalStep *op = &state->steps[1];
    1778      185063 :     int         attnum = op->d.assign_var.attnum + 1;
    1779      185063 :     int         resultnum = op->d.assign_var.resultnum;
    1780      185063 :     TupleTableSlot *inslot = econtext->ecxt_scantuple;
    1781      185063 :     TupleTableSlot *outslot = state->resultslot;
    1782             : 
    1783             :     /* See comments in ExecJustAssignInnerVar */
    1784      370126 :     outslot->tts_values[resultnum] =
    1785      185063 :         slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
    1786      185063 :     return 0;
    1787             : }
    1788             : 
    1789             : 
    1790             : /*
    1791             :  * Do one-time initialization of interpretation machinery.
    1792             :  */
    1793             : static void
    1794      108107 : ExecInitInterpreter(void)
    1795             : {
    1796             : #if defined(EEO_USE_COMPUTED_GOTO)
    1797             :     /* Set up externally-visible pointer to dispatch table */
    1798      108107 :     if (dispatch_table == NULL)
    1799         309 :         dispatch_table = (const void **)
    1800         309 :             DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
    1801             : #endif
    1802      108107 : }
    1803             : 
    1804             : /*
    1805             :  * Function to return the opcode of an expression step.
    1806             :  *
    1807             :  * When direct-threading is in use, ExprState->opcode isn't easily
    1808             :  * decipherable. This function returns the appropriate enum member.
    1809             :  *
    1810             :  * This currently is only supposed to be used in paths that aren't critical
    1811             :  * performance-wise.  If that changes, we could add an inverse dispatch_table
    1812             :  * that's sorted on the address, so a binary search can be performed.
    1813             :  */
    1814             : ExprEvalOp
    1815           0 : ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
    1816             : {
    1817             : #if defined(EEO_USE_COMPUTED_GOTO)
    1818           0 :     if (state->flags & EEO_FLAG_DIRECT_THREADED)
    1819             :     {
    1820             :         int         i;
    1821             : 
    1822           0 :         for (i = 0; i < EEOP_LAST; i++)
    1823             :         {
    1824           0 :             if ((void *) op->opcode == dispatch_table[i])
    1825             :             {
    1826           0 :                 return (ExprEvalOp) i;
    1827             :             }
    1828             :         }
    1829           0 :         elog(ERROR, "unknown opcode");
    1830             :     }
    1831             : #endif
    1832           0 :     return (ExprEvalOp) op->opcode;
    1833             : }
    1834             : 
    1835             : 
    1836             : /*
    1837             :  * Out-of-line helper functions for complex instructions.
    1838             :  */
    1839             : 
    1840             : /*
    1841             :  * Evaluate a PARAM_EXEC parameter.
    1842             :  *
    1843             :  * PARAM_EXEC params (internal executor parameters) are stored in the
    1844             :  * ecxt_param_exec_vals array, and can be accessed by array index.
    1845             :  */
    1846             : void
    1847      135806 : ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    1848             : {
    1849             :     ParamExecData *prm;
    1850             : 
    1851      135806 :     prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
    1852      135806 :     if (unlikely(prm->execPlan != NULL))
    1853             :     {
    1854             :         /* Parameter not evaluated yet, so go do it */
    1855        1727 :         ExecSetParamPlan(prm->execPlan, econtext);
    1856             :         /* ExecSetParamPlan should have processed this param... */
    1857        1725 :         Assert(prm->execPlan == NULL);
    1858             :     }
    1859      135804 :     *op->resvalue = prm->value;
    1860      135804 :     *op->resnull = prm->isnull;
    1861      135804 : }
    1862             : 
    1863             : /*
    1864             :  * Evaluate a PARAM_EXTERN parameter.
    1865             :  *
    1866             :  * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
    1867             :  */
    1868             : void
    1869      152588 : ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    1870             : {
    1871      152588 :     ParamListInfo paramInfo = econtext->ecxt_param_list_info;
    1872      152588 :     int         paramId = op->d.param.paramid;
    1873             : 
    1874      152588 :     if (likely(paramInfo &&
    1875             :                paramId > 0 && paramId <= paramInfo->numParams))
    1876             :     {
    1877      152588 :         ParamExternData *prm = &paramInfo->params[paramId - 1];
    1878             : 
    1879             :         /* give hook a chance in case parameter is dynamic */
    1880      152588 :         if (!OidIsValid(prm->ptype) && paramInfo->paramFetch != NULL)
    1881        5588 :             (*paramInfo->paramFetch) (paramInfo, paramId);
    1882             : 
    1883      152588 :         if (likely(OidIsValid(prm->ptype)))
    1884             :         {
    1885             :             /* safety check in case hook did something unexpected */
    1886      152588 :             if (unlikely(prm->ptype != op->d.param.paramtype))
    1887           0 :                 ereport(ERROR,
    1888             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    1889             :                          errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    1890             :                                 paramId,
    1891             :                                 format_type_be(prm->ptype),
    1892             :                                 format_type_be(op->d.param.paramtype))));
    1893      152588 :             *op->resvalue = prm->value;
    1894      152588 :             *op->resnull = prm->isnull;
    1895      305176 :             return;
    1896             :         }
    1897             :     }
    1898             : 
    1899           0 :     ereport(ERROR,
    1900             :             (errcode(ERRCODE_UNDEFINED_OBJECT),
    1901             :              errmsg("no value found for parameter %d", paramId)));
    1902             : }
    1903             : 
    1904             : /*
    1905             :  * Evaluate a SQLValueFunction expression.
    1906             :  */
    1907             : void
    1908         750 : ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
    1909             : {
    1910         750 :     SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
    1911             :     FunctionCallInfoData fcinfo;
    1912             : 
    1913         750 :     *op->resnull = false;
    1914             : 
    1915             :     /*
    1916             :      * Note: current_schema() can return NULL.  current_user() etc currently
    1917             :      * cannot, but might as well code those cases the same way for safety.
    1918             :      */
    1919         750 :     switch (svf->op)
    1920             :     {
    1921             :         case SVFOP_CURRENT_DATE:
    1922           4 :             *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
    1923           4 :             break;
    1924             :         case SVFOP_CURRENT_TIME:
    1925             :         case SVFOP_CURRENT_TIME_N:
    1926           1 :             *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
    1927           1 :             break;
    1928             :         case SVFOP_CURRENT_TIMESTAMP:
    1929             :         case SVFOP_CURRENT_TIMESTAMP_N:
    1930           3 :             *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
    1931           3 :             break;
    1932             :         case SVFOP_LOCALTIME:
    1933             :         case SVFOP_LOCALTIME_N:
    1934           1 :             *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
    1935           1 :             break;
    1936             :         case SVFOP_LOCALTIMESTAMP:
    1937             :         case SVFOP_LOCALTIMESTAMP_N:
    1938           1 :             *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
    1939           1 :             break;
    1940             :         case SVFOP_CURRENT_ROLE:
    1941             :         case SVFOP_CURRENT_USER:
    1942             :         case SVFOP_USER:
    1943         711 :             InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    1944         711 :             *op->resvalue = current_user(&fcinfo);
    1945         711 :             *op->resnull = fcinfo.isnull;
    1946         711 :             break;
    1947             :         case SVFOP_SESSION_USER:
    1948          25 :             InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    1949          25 :             *op->resvalue = session_user(&fcinfo);
    1950          25 :             *op->resnull = fcinfo.isnull;
    1951          25 :             break;
    1952             :         case SVFOP_CURRENT_CATALOG:
    1953           1 :             InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    1954           1 :             *op->resvalue = current_database(&fcinfo);
    1955           1 :             *op->resnull = fcinfo.isnull;
    1956           1 :             break;
    1957             :         case SVFOP_CURRENT_SCHEMA:
    1958           3 :             InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
    1959           3 :             *op->resvalue = current_schema(&fcinfo);
    1960           3 :             *op->resnull = fcinfo.isnull;
    1961           3 :             break;
    1962             :     }
    1963         750 : }
    1964             : 
    1965             : /*
    1966             :  * Raise error if a CURRENT OF expression is evaluated.
    1967             :  *
    1968             :  * The planner should convert CURRENT OF into a TidScan qualification, or some
    1969             :  * other special handling in a ForeignScan node.  So we have to be able to do
    1970             :  * ExecInitExpr on a CurrentOfExpr, but we shouldn't ever actually execute it.
    1971             :  * If we get here, we suppose we must be dealing with CURRENT OF on a foreign
    1972             :  * table whose FDW doesn't handle it, and complain accordingly.
    1973             :  */
    1974             : void
    1975           0 : ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
    1976             : {
    1977           0 :     ereport(ERROR,
    1978             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1979             :              errmsg("WHERE CURRENT OF is not supported for this table type")));
    1980             : }
    1981             : 
    1982             : /*
    1983             :  * Evaluate NextValueExpr.
    1984             :  */
    1985             : void
    1986          30 : ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
    1987             : {
    1988          30 :     int64       newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
    1989             : 
    1990          30 :     switch (op->d.nextvalueexpr.seqtypid)
    1991             :     {
    1992             :         case INT2OID:
    1993           2 :             *op->resvalue = Int16GetDatum((int16) newval);
    1994           2 :             break;
    1995             :         case INT4OID:
    1996          25 :             *op->resvalue = Int32GetDatum((int32) newval);
    1997          25 :             break;
    1998             :         case INT8OID:
    1999           3 :             *op->resvalue = Int64GetDatum((int64) newval);
    2000           3 :             break;
    2001             :         default:
    2002           0 :             elog(ERROR, "unsupported sequence type %u",
    2003             :                  op->d.nextvalueexpr.seqtypid);
    2004             :     }
    2005          30 :     *op->resnull = false;
    2006          30 : }
    2007             : 
    2008             : /*
    2009             :  * Evaluate NullTest / IS NULL for rows.
    2010             :  */
    2011             : void
    2012          90 : ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2013             : {
    2014          90 :     ExecEvalRowNullInt(state, op, econtext, true);
    2015          90 : }
    2016             : 
    2017             : /*
    2018             :  * Evaluate NullTest / IS NOT NULL for rows.
    2019             :  */
    2020             : void
    2021          49 : ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2022             : {
    2023          49 :     ExecEvalRowNullInt(state, op, econtext, false);
    2024          49 : }
    2025             : 
    2026             : /* Common code for IS [NOT] NULL on a row value */
    2027             : static void
    2028         139 : ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
    2029             :                    ExprContext *econtext, bool checkisnull)
    2030             : {
    2031         139 :     Datum       value = *op->resvalue;
    2032         139 :     bool        isnull = *op->resnull;
    2033             :     HeapTupleHeader tuple;
    2034             :     Oid         tupType;
    2035             :     int32       tupTypmod;
    2036             :     TupleDesc   tupDesc;
    2037             :     HeapTupleData tmptup;
    2038             :     int         att;
    2039             : 
    2040         139 :     *op->resnull = false;
    2041             : 
    2042             :     /* NULL row variables are treated just as NULL scalar columns */
    2043         139 :     if (isnull)
    2044             :     {
    2045           9 :         *op->resvalue = BoolGetDatum(checkisnull);
    2046          93 :         return;
    2047             :     }
    2048             : 
    2049             :     /*
    2050             :      * The SQL standard defines IS [NOT] NULL for a non-null rowtype argument
    2051             :      * as:
    2052             :      *
    2053             :      * "R IS NULL" is true if every field is the null value.
    2054             :      *
    2055             :      * "R IS NOT NULL" is true if no field is the null value.
    2056             :      *
    2057             :      * This definition is (apparently intentionally) not recursive; so our
    2058             :      * tests on the fields are primitive attisnull tests, not recursive checks
    2059             :      * to see if they are all-nulls or no-nulls rowtypes.
    2060             :      *
    2061             :      * The standard does not consider the possibility of zero-field rows, but
    2062             :      * here we consider them to vacuously satisfy both predicates.
    2063             :      */
    2064             : 
    2065         130 :     tuple = DatumGetHeapTupleHeader(value);
    2066             : 
    2067         130 :     tupType = HeapTupleHeaderGetTypeId(tuple);
    2068         130 :     tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    2069             : 
    2070             :     /* Lookup tupdesc if first time through or if type changes */
    2071         130 :     tupDesc = get_cached_rowtype(tupType, tupTypmod,
    2072             :                                  &op->d.nulltest_row.argdesc,
    2073             :                                  econtext);
    2074             : 
    2075             :     /*
    2076             :      * heap_attisnull needs a HeapTuple not a bare HeapTupleHeader.
    2077             :      */
    2078         130 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    2079         130 :     tmptup.t_data = tuple;
    2080             : 
    2081         249 :     for (att = 1; att <= tupDesc->natts; att++)
    2082             :     {
    2083             :         /* ignore dropped columns */
    2084         194 :         if (TupleDescAttr(tupDesc, att - 1)->attisdropped)
    2085           0 :             continue;
    2086         194 :         if (heap_attisnull(&tmptup, att))
    2087             :         {
    2088             :             /* null field disproves IS NOT NULL */
    2089          26 :             if (!checkisnull)
    2090             :             {
    2091           4 :                 *op->resvalue = BoolGetDatum(false);
    2092           4 :                 return;
    2093             :             }
    2094             :         }
    2095             :         else
    2096             :         {
    2097             :             /* non-null field disproves IS NULL */
    2098         168 :             if (checkisnull)
    2099             :             {
    2100          71 :                 *op->resvalue = BoolGetDatum(false);
    2101          71 :                 return;
    2102             :             }
    2103             :         }
    2104             :     }
    2105             : 
    2106          55 :     *op->resvalue = BoolGetDatum(true);
    2107             : }
    2108             : 
    2109             : /*
    2110             :  * Evaluate an ARRAY[] expression.
    2111             :  *
    2112             :  * The individual array elements (or subarrays) have already been evaluated
    2113             :  * into op->d.arrayexpr.elemvalues[]/elemnulls[].
    2114             :  */
    2115             : void
    2116       35641 : ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
    2117             : {
    2118             :     ArrayType  *result;
    2119       35641 :     Oid         element_type = op->d.arrayexpr.elemtype;
    2120       35641 :     int         nelems = op->d.arrayexpr.nelems;
    2121       35641 :     int         ndims = 0;
    2122             :     int         dims[MAXDIM];
    2123             :     int         lbs[MAXDIM];
    2124             : 
    2125             :     /* Set non-null as default */
    2126       35641 :     *op->resnull = false;
    2127             : 
    2128       35641 :     if (!op->d.arrayexpr.multidims)
    2129             :     {
    2130             :         /* Elements are presumably of scalar type */
    2131       35585 :         Datum      *dvalues = op->d.arrayexpr.elemvalues;
    2132       35585 :         bool       *dnulls = op->d.arrayexpr.elemnulls;
    2133             : 
    2134             :         /* Shouldn't happen here, but if length is 0, return empty array */
    2135       35585 :         if (nelems == 0)
    2136             :         {
    2137          22 :             *op->resvalue =
    2138          11 :                 PointerGetDatum(construct_empty_array(element_type));
    2139          22 :             return;
    2140             :         }
    2141             : 
    2142             :         /* setup for 1-D array of the given length */
    2143       35574 :         ndims = 1;
    2144       35574 :         dims[0] = nelems;
    2145       35574 :         lbs[0] = 1;
    2146             : 
    2147      106722 :         result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
    2148             :                                     element_type,
    2149       35574 :                                     op->d.arrayexpr.elemlength,
    2150       35574 :                                     op->d.arrayexpr.elembyval,
    2151       35574 :                                     op->d.arrayexpr.elemalign);
    2152             :     }
    2153             :     else
    2154             :     {
    2155             :         /* Must be nested array expressions */
    2156          56 :         int         nbytes = 0;
    2157          56 :         int         nitems = 0;
    2158          56 :         int         outer_nelems = 0;
    2159          56 :         int         elem_ndims = 0;
    2160          56 :         int        *elem_dims = NULL;
    2161          56 :         int        *elem_lbs = NULL;
    2162          56 :         bool        firstone = true;
    2163          56 :         bool        havenulls = false;
    2164          56 :         bool        haveempty = false;
    2165             :         char      **subdata;
    2166             :         bits8     **subbitmaps;
    2167             :         int        *subbytes;
    2168             :         int        *subnitems;
    2169             :         int32       dataoffset;
    2170             :         char       *dat;
    2171             :         int         iitem;
    2172             :         int         elemoff;
    2173             :         int         i;
    2174             : 
    2175          56 :         subdata = (char **) palloc(nelems * sizeof(char *));
    2176          56 :         subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *));
    2177          56 :         subbytes = (int *) palloc(nelems * sizeof(int));
    2178          56 :         subnitems = (int *) palloc(nelems * sizeof(int));
    2179             : 
    2180             :         /* loop through and get data area from each element */
    2181         154 :         for (elemoff = 0; elemoff < nelems; elemoff++)
    2182             :         {
    2183             :             Datum       arraydatum;
    2184             :             bool        eisnull;
    2185             :             ArrayType  *array;
    2186             :             int         this_ndims;
    2187             : 
    2188          98 :             arraydatum = op->d.arrayexpr.elemvalues[elemoff];
    2189          98 :             eisnull = op->d.arrayexpr.elemnulls[elemoff];
    2190             : 
    2191             :             /* temporarily ignore null subarrays */
    2192          98 :             if (eisnull)
    2193             :             {
    2194           0 :                 haveempty = true;
    2195           0 :                 continue;
    2196             :             }
    2197             : 
    2198          98 :             array = DatumGetArrayTypeP(arraydatum);
    2199             : 
    2200             :             /* run-time double-check on element type */
    2201          98 :             if (element_type != ARR_ELEMTYPE(array))
    2202           0 :                 ereport(ERROR,
    2203             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    2204             :                          errmsg("cannot merge incompatible arrays"),
    2205             :                          errdetail("Array with element type %s cannot be "
    2206             :                                    "included in ARRAY construct with element type %s.",
    2207             :                                    format_type_be(ARR_ELEMTYPE(array)),
    2208             :                                    format_type_be(element_type))));
    2209             : 
    2210          98 :             this_ndims = ARR_NDIM(array);
    2211             :             /* temporarily ignore zero-dimensional subarrays */
    2212          98 :             if (this_ndims <= 0)
    2213             :             {
    2214           0 :                 haveempty = true;
    2215           0 :                 continue;
    2216             :             }
    2217             : 
    2218          98 :             if (firstone)
    2219             :             {
    2220             :                 /* Get sub-array details from first member */
    2221          56 :                 elem_ndims = this_ndims;
    2222          56 :                 ndims = elem_ndims + 1;
    2223          56 :                 if (ndims <= 0 || ndims > MAXDIM)
    2224           0 :                     ereport(ERROR,
    2225             :                             (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2226             :                              errmsg("number of array dimensions (%d) exceeds " \
    2227             :                                     "the maximum allowed (%d)", ndims, MAXDIM)));
    2228             : 
    2229          56 :                 elem_dims = (int *) palloc(elem_ndims * sizeof(int));
    2230          56 :                 memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
    2231          56 :                 elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
    2232          56 :                 memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
    2233             : 
    2234          56 :                 firstone = false;
    2235             :             }
    2236             :             else
    2237             :             {
    2238             :                 /* Check other sub-arrays are compatible */
    2239          84 :                 if (elem_ndims != this_ndims ||
    2240          42 :                     memcmp(elem_dims, ARR_DIMS(array),
    2241          42 :                            elem_ndims * sizeof(int)) != 0 ||
    2242          42 :                     memcmp(elem_lbs, ARR_LBOUND(array),
    2243             :                            elem_ndims * sizeof(int)) != 0)
    2244           0 :                     ereport(ERROR,
    2245             :                             (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2246             :                              errmsg("multidimensional arrays must have array "
    2247             :                                     "expressions with matching dimensions")));
    2248             :             }
    2249             : 
    2250          98 :             subdata[outer_nelems] = ARR_DATA_PTR(array);
    2251          98 :             subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
    2252          98 :             subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
    2253          98 :             nbytes += subbytes[outer_nelems];
    2254          98 :             subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
    2255             :                                                      ARR_DIMS(array));
    2256          98 :             nitems += subnitems[outer_nelems];
    2257          98 :             havenulls |= ARR_HASNULL(array);
    2258          98 :             outer_nelems++;
    2259             :         }
    2260             : 
    2261             :         /*
    2262             :          * If all items were null or empty arrays, return an empty array;
    2263             :          * otherwise, if some were and some weren't, raise error.  (Note: we
    2264             :          * must special-case this somehow to avoid trying to generate a 1-D
    2265             :          * array formed from empty arrays.  It's not ideal...)
    2266             :          */
    2267          56 :         if (haveempty)
    2268             :         {
    2269           0 :             if (ndims == 0)     /* didn't find any nonempty array */
    2270             :             {
    2271           0 :                 *op->resvalue = PointerGetDatum(construct_empty_array(element_type));
    2272           0 :                 return;
    2273             :             }
    2274           0 :             ereport(ERROR,
    2275             :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2276             :                      errmsg("multidimensional arrays must have array "
    2277             :                             "expressions with matching dimensions")));
    2278             :         }
    2279             : 
    2280             :         /* setup for multi-D array */
    2281          56 :         dims[0] = outer_nelems;
    2282          56 :         lbs[0] = 1;
    2283         140 :         for (i = 1; i < ndims; i++)
    2284             :         {
    2285          84 :             dims[i] = elem_dims[i - 1];
    2286          84 :             lbs[i] = elem_lbs[i - 1];
    2287             :         }
    2288             : 
    2289          56 :         if (havenulls)
    2290             :         {
    2291           1 :             dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
    2292           1 :             nbytes += dataoffset;
    2293             :         }
    2294             :         else
    2295             :         {
    2296          55 :             dataoffset = 0;     /* marker for no null bitmap */
    2297          55 :             nbytes += ARR_OVERHEAD_NONULLS(ndims);
    2298             :         }
    2299             : 
    2300          56 :         result = (ArrayType *) palloc(nbytes);
    2301          56 :         SET_VARSIZE(result, nbytes);
    2302          56 :         result->ndim = ndims;
    2303          56 :         result->dataoffset = dataoffset;
    2304          56 :         result->elemtype = element_type;
    2305          56 :         memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
    2306          56 :         memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
    2307             : 
    2308          56 :         dat = ARR_DATA_PTR(result);
    2309          56 :         iitem = 0;
    2310         154 :         for (i = 0; i < outer_nelems; i++)
    2311             :         {
    2312          98 :             memcpy(dat, subdata[i], subbytes[i]);
    2313          98 :             dat += subbytes[i];
    2314          98 :             if (havenulls)
    2315           4 :                 array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
    2316           2 :                                   subbitmaps[i], 0,
    2317           2 :                                   subnitems[i]);
    2318          98 :             iitem += subnitems[i];
    2319             :         }
    2320             :     }
    2321             : 
    2322       35630 :     *op->resvalue = PointerGetDatum(result);
    2323             : }
    2324             : 
    2325             : /*
    2326             :  * Evaluate an ArrayCoerceExpr expression.
    2327             :  *
    2328             :  * Source array is in step's result variable.
    2329             :  */
    2330             : void
    2331        6258 : ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op)
    2332             : {
    2333        6258 :     ArrayCoerceExpr *acoerce = op->d.arraycoerce.coerceexpr;
    2334             :     Datum       arraydatum;
    2335             :     FunctionCallInfoData locfcinfo;
    2336             : 
    2337             :     /* NULL array -> NULL result */
    2338        6258 :     if (*op->resnull)
    2339        6237 :         return;
    2340             : 
    2341        6255 :     arraydatum = *op->resvalue;
    2342             : 
    2343             :     /*
    2344             :      * If it's binary-compatible, modify the element type in the array header,
    2345             :      * but otherwise leave the array as we received it.
    2346             :      */
    2347        6255 :     if (!OidIsValid(acoerce->elemfuncid))
    2348             :     {
    2349             :         /* Detoast input array if necessary, and copy in any case */
    2350        6231 :         ArrayType  *array = DatumGetArrayTypePCopy(arraydatum);
    2351             : 
    2352        6231 :         ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
    2353        6231 :         *op->resvalue = PointerGetDatum(array);
    2354        6231 :         return;
    2355             :     }
    2356             : 
    2357             :     /*
    2358             :      * Use array_map to apply the function to each array element.
    2359             :      *
    2360             :      * We pass on the desttypmod and isExplicit flags whether or not the
    2361             :      * function wants them.
    2362             :      *
    2363             :      * Note: coercion functions are assumed to not use collation.
    2364             :      */
    2365          24 :     InitFunctionCallInfoData(locfcinfo, op->d.arraycoerce.elemfunc, 3,
    2366             :                              InvalidOid, NULL, NULL);
    2367          24 :     locfcinfo.arg[0] = arraydatum;
    2368          24 :     locfcinfo.arg[1] = Int32GetDatum(acoerce->resulttypmod);
    2369          24 :     locfcinfo.arg[2] = BoolGetDatum(acoerce->isExplicit);
    2370          24 :     locfcinfo.argnull[0] = false;
    2371          24 :     locfcinfo.argnull[1] = false;
    2372          24 :     locfcinfo.argnull[2] = false;
    2373             : 
    2374          48 :     *op->resvalue = array_map(&locfcinfo, op->d.arraycoerce.resultelemtype,
    2375          24 :                               op->d.arraycoerce.amstate);
    2376             : }
    2377             : 
    2378             : /*
    2379             :  * Evaluate a ROW() expression.
    2380             :  *
    2381             :  * The individual columns have already been evaluated into
    2382             :  * op->d.row.elemvalues[]/elemnulls[].
    2383             :  */
    2384             : void
    2385         645 : ExecEvalRow(ExprState *state, ExprEvalStep *op)
    2386             : {
    2387             :     HeapTuple   tuple;
    2388             : 
    2389             :     /* build tuple from evaluated field values */
    2390         645 :     tuple = heap_form_tuple(op->d.row.tupdesc,
    2391             :                             op->d.row.elemvalues,
    2392             :                             op->d.row.elemnulls);
    2393             : 
    2394         645 :     *op->resvalue = HeapTupleGetDatum(tuple);
    2395         645 :     *op->resnull = false;
    2396         645 : }
    2397             : 
    2398             : /*
    2399             :  * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()).
    2400             :  *
    2401             :  * All of the to-be-compared expressions have already been evaluated into
    2402             :  * op->d.minmax.values[]/nulls[].
    2403             :  */
    2404             : void
    2405          99 : ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
    2406             : {
    2407          99 :     Datum      *values = op->d.minmax.values;
    2408          99 :     bool       *nulls = op->d.minmax.nulls;
    2409          99 :     FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
    2410          99 :     MinMaxOp    operator = op->d.minmax.op;
    2411             :     int         off;
    2412             : 
    2413             :     /* set at initialization */
    2414          99 :     Assert(fcinfo->argnull[0] == false);
    2415          99 :     Assert(fcinfo->argnull[1] == false);
    2416             : 
    2417             :     /* default to null result */
    2418          99 :     *op->resnull = true;
    2419             : 
    2420         337 :     for (off = 0; off < op->d.minmax.nelems; off++)
    2421             :     {
    2422             :         /* ignore NULL inputs */
    2423         238 :         if (nulls[off])
    2424           2 :             continue;
    2425             : 
    2426         236 :         if (*op->resnull)
    2427             :         {
    2428             :             /* first nonnull input, adopt value */
    2429          99 :             *op->resvalue = values[off];
    2430          99 :             *op->resnull = false;
    2431             :         }
    2432             :         else
    2433             :         {
    2434             :             int         cmpresult;
    2435             : 
    2436             :             /* apply comparison function */
    2437         137 :             fcinfo->arg[0] = *op->resvalue;
    2438         137 :             fcinfo->arg[1] = values[off];
    2439             : 
    2440         137 :             fcinfo->isnull = false;
    2441         137 :             cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
    2442         137 :             if (fcinfo->isnull) /* probably should not happen */
    2443           0 :                 continue;
    2444             : 
    2445         137 :             if (cmpresult > 0 && operator == IS_LEAST)
    2446          18 :                 *op->resvalue = values[off];
    2447         119 :             else if (cmpresult < 0 && operator == IS_GREATEST)
    2448          16 :                 *op->resvalue = values[off];
    2449             :         }
    2450             :     }
    2451          99 : }
    2452             : 
    2453             : /*
    2454             :  * Evaluate a FieldSelect node.
    2455             :  *
    2456             :  * Source record is in step's result variable.
    2457             :  */
    2458             : void
    2459       13047 : ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2460             : {
    2461       13047 :     AttrNumber  fieldnum = op->d.fieldselect.fieldnum;
    2462             :     Datum       tupDatum;
    2463             :     HeapTupleHeader tuple;
    2464             :     Oid         tupType;
    2465             :     int32       tupTypmod;
    2466             :     TupleDesc   tupDesc;
    2467             :     Form_pg_attribute attr;
    2468             :     HeapTupleData tmptup;
    2469             : 
    2470             :     /* NULL record -> NULL result */
    2471       13047 :     if (*op->resnull)
    2472          14 :         return;
    2473             : 
    2474             :     /* Get the composite datum and extract its type fields */
    2475       13040 :     tupDatum = *op->resvalue;
    2476       13040 :     tuple = DatumGetHeapTupleHeader(tupDatum);
    2477             : 
    2478       13040 :     tupType = HeapTupleHeaderGetTypeId(tuple);
    2479       13040 :     tupTypmod = HeapTupleHeaderGetTypMod(tuple);
    2480             : 
    2481             :     /* Lookup tupdesc if first time through or if type changes */
    2482       13040 :     tupDesc = get_cached_rowtype(tupType, tupTypmod,
    2483             :                                  &op->d.fieldselect.argdesc,
    2484             :                                  econtext);
    2485             : 
    2486             :     /*
    2487             :      * Find field's attr record.  Note we don't support system columns here: a
    2488             :      * datum tuple doesn't have valid values for most of the interesting
    2489             :      * system columns anyway.
    2490             :      */
    2491       13040 :     if (fieldnum <= 0)           /* should never happen */
    2492           0 :         elog(ERROR, "unsupported reference to system column %d in FieldSelect",
    2493             :              fieldnum);
    2494       13040 :     if (fieldnum > tupDesc->natts)    /* should never happen */
    2495           0 :         elog(ERROR, "attribute number %d exceeds number of columns %d",
    2496             :              fieldnum, tupDesc->natts);
    2497       13040 :     attr = TupleDescAttr(tupDesc, fieldnum - 1);
    2498             : 
    2499             :     /* Check for dropped column, and force a NULL result if so */
    2500       13040 :     if (attr->attisdropped)
    2501             :     {
    2502           0 :         *op->resnull = true;
    2503           0 :         return;
    2504             :     }
    2505             : 
    2506             :     /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
    2507             :     /* As in CheckVarSlotCompatibility, we should but can't check typmod */
    2508       13040 :     if (op->d.fieldselect.resulttype != attr->atttypid)
    2509           0 :         ereport(ERROR,
    2510             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    2511             :                  errmsg("attribute %d has wrong type", fieldnum),
    2512             :                  errdetail("Table has type %s, but query expects %s.",
    2513             :                            format_type_be(attr->atttypid),
    2514             :                            format_type_be(op->d.fieldselect.resulttype))));
    2515             : 
    2516             :     /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */
    2517       13040 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    2518       13040 :     tmptup.t_data = tuple;
    2519             : 
    2520             :     /* extract the field */
    2521       13040 :     *op->resvalue = heap_getattr(&tmptup,
    2522             :                                  fieldnum,
    2523             :                                  tupDesc,
    2524             :                                  op->resnull);
    2525             : }
    2526             : 
    2527             : /*
    2528             :  * Deform source tuple, filling in the step's values/nulls arrays, before
    2529             :  * evaluating individual new values as part of a FieldStore expression.
    2530             :  * Subsequent steps will overwrite individual elements of the values/nulls
    2531             :  * arrays with the new field values, and then FIELDSTORE_FORM will build the
    2532             :  * new tuple value.
    2533             :  *
    2534             :  * Source record is in step's result variable.
    2535             :  */
    2536             : void
    2537          45 : ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2538             : {
    2539             :     TupleDesc   tupDesc;
    2540             : 
    2541             :     /* Lookup tupdesc if first time through or after rescan */
    2542          45 :     tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
    2543             :                                  op->d.fieldstore.argdesc, econtext);
    2544             : 
    2545             :     /* Check that current tupdesc doesn't have more fields than we allocated */
    2546          45 :     if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns))
    2547           0 :         elog(ERROR, "too many columns in composite type %u",
    2548             :              op->d.fieldstore.fstore->resulttype);
    2549             : 
    2550          45 :     if (*op->resnull)
    2551             :     {
    2552             :         /* Convert null input tuple into an all-nulls row */
    2553          20 :         memset(op->d.fieldstore.nulls, true,
    2554          20 :                op->d.fieldstore.ncolumns * sizeof(bool));
    2555             :     }
    2556             :     else
    2557             :     {
    2558             :         /*
    2559             :          * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We
    2560             :          * set all the fields in the struct just in case.
    2561             :          */
    2562          25 :         Datum       tupDatum = *op->resvalue;
    2563             :         HeapTupleHeader tuphdr;
    2564             :         HeapTupleData tmptup;
    2565             : 
    2566          25 :         tuphdr = DatumGetHeapTupleHeader(tupDatum);
    2567          25 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
    2568          25 :         ItemPointerSetInvalid(&(tmptup.t_self));
    2569          25 :         tmptup.t_tableOid = InvalidOid;
    2570          25 :         tmptup.t_data = tuphdr;
    2571             : 
    2572          25 :         heap_deform_tuple(&tmptup, tupDesc,
    2573             :                           op->d.fieldstore.values,
    2574             :                           op->d.fieldstore.nulls);
    2575             :     }
    2576          45 : }
    2577             : 
    2578             : /*
    2579             :  * Compute the new composite datum after each individual field value of a
    2580             :  * FieldStore expression has been evaluated.
    2581             :  */
    2582             : void
    2583          45 : ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2584             : {
    2585             :     HeapTuple   tuple;
    2586             : 
    2587             :     /* argdesc should already be valid from the DeForm step */
    2588          45 :     tuple = heap_form_tuple(*op->d.fieldstore.argdesc,
    2589             :                             op->d.fieldstore.values,
    2590             :                             op->d.fieldstore.nulls);
    2591             : 
    2592          45 :     *op->resvalue = HeapTupleGetDatum(tuple);
    2593          45 :     *op->resnull = false;
    2594          45 : }
    2595             : 
    2596             : /*
    2597             :  * Process a subscript in an ArrayRef expression.
    2598             :  *
    2599             :  * If subscript is NULL, throw error in assignment case, or in fetch case
    2600             :  * set result to NULL and return false (instructing caller to skip the rest
    2601             :  * of the ArrayRef sequence).
    2602             :  *
    2603             :  * Subscript expression result is in subscriptvalue/subscriptnull.
    2604             :  * On success, integer subscript value has been saved in upperindex[] or
    2605             :  * lowerindex[] for use later.
    2606             :  */
    2607             : bool
    2608       26864 : ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op)
    2609             : {
    2610       26864 :     ArrayRefState *arefstate = op->d.arrayref_subscript.state;
    2611             :     int        *indexes;
    2612             :     int         off;
    2613             : 
    2614             :     /* If any index expr yields NULL, result is NULL or error */
    2615       26864 :     if (arefstate->subscriptnull)
    2616             :     {
    2617           6 :         if (arefstate->isassignment)
    2618           3 :             ereport(ERROR,
    2619             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2620             :                      errmsg("array subscript in assignment must not be null")));
    2621           3 :         *op->resnull = true;
    2622           3 :         return false;
    2623             :     }
    2624             : 
    2625             :     /* Convert datum to int, save in appropriate place */
    2626       26858 :     if (op->d.arrayref_subscript.isupper)
    2627       26742 :         indexes = arefstate->upperindex;
    2628             :     else
    2629         116 :         indexes = arefstate->lowerindex;
    2630       26858 :     off = op->d.arrayref_subscript.off;
    2631             : 
    2632       26858 :     indexes[off] = DatumGetInt32(arefstate->subscriptvalue);
    2633             : 
    2634       26858 :     return true;
    2635             : }
    2636             : 
    2637             : /*
    2638             :  * Evaluate ArrayRef fetch.
    2639             :  *
    2640             :  * Source array is in step's result variable.
    2641             :  */
    2642             : void
    2643       26549 : ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op)
    2644             : {
    2645       26549 :     ArrayRefState *arefstate = op->d.arrayref.state;
    2646             : 
    2647             :     /* Should not get here if source array (or any subscript) is null */
    2648       26549 :     Assert(!(*op->resnull));
    2649             : 
    2650       26549 :     if (arefstate->numlower == 0)
    2651             :     {
    2652             :         /* Scalar case */
    2653      158976 :         *op->resvalue = array_get_element(*op->resvalue,
    2654             :                                           arefstate->numupper,
    2655       26496 :                                           arefstate->upperindex,
    2656       26496 :                                           arefstate->refattrlength,
    2657       26496 :                                           arefstate->refelemlength,
    2658       26496 :                                           arefstate->refelembyval,
    2659       26496 :                                           arefstate->refelemalign,
    2660             :                                           op->resnull);
    2661             :     }
    2662             :     else
    2663             :     {
    2664             :         /* Slice case */
    2665         318 :         *op->resvalue = array_get_slice(*op->resvalue,
    2666             :                                         arefstate->numupper,
    2667          53 :                                         arefstate->upperindex,
    2668          53 :                                         arefstate->lowerindex,
    2669          53 :                                         arefstate->upperprovided,
    2670          53 :                                         arefstate->lowerprovided,
    2671          53 :                                         arefstate->refattrlength,
    2672          53 :                                         arefstate->refelemlength,
    2673          53 :                                         arefstate->refelembyval,
    2674          53 :                                         arefstate->refelemalign);
    2675             :     }
    2676       26545 : }
    2677             : 
    2678             : /*
    2679             :  * Compute old array element/slice value for an ArrayRef assignment
    2680             :  * expression.  Will only be generated if the new-value subexpression
    2681             :  * contains ArrayRef or FieldStore.  The value is stored into the
    2682             :  * ArrayRefState's prevvalue/prevnull fields.
    2683             :  */
    2684             : void
    2685          33 : ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op)
    2686             : {
    2687          33 :     ArrayRefState *arefstate = op->d.arrayref.state;
    2688             : 
    2689          33 :     if (*op->resnull)
    2690             :     {
    2691             :         /* whole array is null, so any element or slice is too */
    2692           9 :         arefstate->prevvalue = (Datum) 0;
    2693           9 :         arefstate->prevnull = true;
    2694             :     }
    2695          24 :     else if (arefstate->numlower == 0)
    2696             :     {
    2697             :         /* Scalar case */
    2698         144 :         arefstate->prevvalue = array_get_element(*op->resvalue,
    2699             :                                                  arefstate->numupper,
    2700          24 :                                                  arefstate->upperindex,
    2701          24 :                                                  arefstate->refattrlength,
    2702          24 :                                                  arefstate->refelemlength,
    2703          24 :                                                  arefstate->refelembyval,
    2704          24 :                                                  arefstate->refelemalign,
    2705             :                                                  &arefstate->prevnull);
    2706             :     }
    2707             :     else
    2708             :     {
    2709             :         /* Slice case */
    2710             :         /* this is currently unreachable */
    2711           0 :         arefstate->prevvalue = array_get_slice(*op->resvalue,
    2712             :                                                arefstate->numupper,
    2713           0 :                                                arefstate->upperindex,
    2714           0 :                                                arefstate->lowerindex,
    2715           0 :                                                arefstate->upperprovided,
    2716           0 :                                                arefstate->lowerprovided,
    2717           0 :                                                arefstate->refattrlength,
    2718           0 :                                                arefstate->refelemlength,
    2719           0 :                                                arefstate->refelembyval,
    2720           0 :                                                arefstate->refelemalign);
    2721           0 :         arefstate->prevnull = false;
    2722             :     }
    2723          33 : }
    2724             : 
    2725             : /*
    2726             :  * Evaluate ArrayRef assignment.
    2727             :  *
    2728             :  * Input array (possibly null) is in result area, replacement value is in
    2729             :  * ArrayRefState's replacevalue/replacenull.
    2730             :  */
    2731             : void
    2732         140 : ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op)
    2733             : {
    2734         140 :     ArrayRefState *arefstate = op->d.arrayref.state;
    2735             : 
    2736             :     /*
    2737             :      * For an assignment to a fixed-length array type, both the original array
    2738             :      * and the value to be assigned into it must be non-NULL, else we punt and
    2739             :      * return the original array.
    2740             :      */
    2741         140 :     if (arefstate->refattrlength > 0) /* fixed-length array? */
    2742             :     {
    2743           6 :         if (*op->resnull || arefstate->replacenull)
    2744         140 :             return;
    2745             :     }
    2746             : 
    2747             :     /*
    2748             :      * For assignment to varlena arrays, we handle a NULL original array by
    2749             :      * substituting an empty (zero-dimensional) array; insertion of the new
    2750             :      * element will result in a singleton array value.  It does not matter
    2751             :      * whether the new element is NULL.
    2752             :      */
    2753         137 :     if (*op->resnull)
    2754             :     {
    2755          32 :         *op->resvalue = PointerGetDatum(construct_empty_array(arefstate->refelemtype));
    2756          32 :         *op->resnull = false;
    2757             :     }
    2758             : 
    2759         137 :     if (arefstate->numlower == 0)
    2760             :     {
    2761             :         /* Scalar case */
    2762         679 :         *op->resvalue = array_set_element(*op->resvalue,
    2763             :                                           arefstate->numupper,
    2764          97 :                                           arefstate->upperindex,
    2765             :                                           arefstate->replacevalue,
    2766          97 :                                           arefstate->replacenull,
    2767          97 :                                           arefstate->refattrlength,
    2768          97 :                                           arefstate->refelemlength,
    2769          97 :                                           arefstate->refelembyval,
    2770          97 :                                           arefstate->refelemalign);
    2771             :     }
    2772             :     else
    2773             :     {
    2774             :         /* Slice case */
    2775         280 :         *op->resvalue = array_set_slice(*op->resvalue,
    2776             :                                         arefstate->numupper,
    2777          40 :                                         arefstate->upperindex,
    2778          40 :                                         arefstate->lowerindex,
    2779          40 :                                         arefstate->upperprovided,
    2780          40 :                                         arefstate->lowerprovided,
    2781             :                                         arefstate->replacevalue,
    2782          40 :                                         arefstate->replacenull,
    2783          40 :                                         arefstate->refattrlength,
    2784          40 :                                         arefstate->refelemlength,
    2785          40 :                                         arefstate->refelembyval,
    2786          40 :                                         arefstate->refelemalign);
    2787             :     }
    2788             : }
    2789             : 
    2790             : /*
    2791             :  * Evaluate a rowtype coercion operation.
    2792             :  * This may require rearranging field positions.
    2793             :  *
    2794             :  * Source record is in step's result variable.
    2795             :  */
    2796             : void
    2797          57 : ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    2798             : {
    2799          57 :     ConvertRowtypeExpr *convert = op->d.convert_rowtype.convert;
    2800             :     HeapTuple   result;
    2801             :     Datum       tupDatum;
    2802             :     HeapTupleHeader tuple;
    2803             :     HeapTupleData tmptup;
    2804             :     TupleDesc   indesc,
    2805             :                 outdesc;
    2806             : 
    2807             :     /* NULL in -> NULL out */
    2808          57 :     if (*op->resnull)
    2809          58 :         return;
    2810             : 
    2811          56 :     tupDatum = *op->resvalue;
    2812          56 :     tuple = DatumGetHeapTupleHeader(tupDatum);
    2813             : 
    2814             :     /* Lookup tupdescs if first time through or after rescan */
    2815          56 :     if (op->d.convert_rowtype.indesc == NULL)
    2816             :     {
    2817          31 :         get_cached_rowtype(exprType((Node *) convert->arg), -1,
    2818             :                            &op->d.convert_rowtype.indesc,
    2819             :                            econtext);
    2820          31 :         op->d.convert_rowtype.initialized = false;
    2821             :     }
    2822          56 :     if (op->d.convert_rowtype.outdesc == NULL)
    2823             :     {
    2824          31 :         get_cached_rowtype(convert->resulttype, -1,
    2825             :                            &op->d.convert_rowtype.outdesc,
    2826             :                            econtext);
    2827          31 :         op->d.convert_rowtype.initialized = false;
    2828             :     }
    2829             : 
    2830          56 :     indesc = op->d.convert_rowtype.indesc;
    2831          56 :     outdesc = op->d.convert_rowtype.outdesc;
    2832             : 
    2833             :     /*
    2834             :      * We used to be able to assert that incoming tuples are marked with
    2835             :      * exactly the rowtype of indesc.  However, now that ExecEvalWholeRowVar
    2836             :      * might change the tuples' marking to plain RECORD due to inserting
    2837             :      * aliases, we can only make this weak test:
    2838             :      */
    2839          56 :     Assert(HeapTupleHeaderGetTypeId(tuple) == indesc->tdtypeid ||
    2840             :            HeapTupleHeaderGetTypeId(tuple) == RECORDOID);
    2841             : 
    2842             :     /* if first time through, initialize conversion map */
    2843          56 :     if (!op->d.convert_rowtype.initialized)
    2844             :     {
    2845             :         MemoryContext old_cxt;
    2846             : 
    2847             :         /* allocate map in long-lived memory context */
    2848          31 :         old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    2849             : 
    2850             :         /* prepare map from old to new attribute numbers */
    2851          31 :         op->d.convert_rowtype.map =
    2852          31 :             convert_tuples_by_name(indesc, outdesc,
    2853             :                                    gettext_noop("could not convert row type"));
    2854          31 :         op->d.convert_rowtype.initialized = true;
    2855             : 
    2856          31 :         MemoryContextSwitchTo(old_cxt);
    2857             :     }
    2858             : 
    2859             :     /* Following steps need a HeapTuple not a bare HeapTupleHeader */
    2860          56 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
    2861          56 :     tmptup.t_data = tuple;
    2862             : 
    2863          56 :     if (op->d.convert_rowtype.map != NULL)
    2864             :     {
    2865             :         /* Full conversion with attribute rearrangement needed */
    2866          50 :         result = do_convert_tuple(&tmptup, op->d.convert_rowtype.map);
    2867             :         /* Result already has appropriate composite-datum header fields */
    2868          50 :         *op->resvalue = HeapTupleGetDatum(result);
    2869             :     }
    2870             :     else
    2871             :     {
    2872             :         /*
    2873             :          * The tuple is physically compatible as-is, but we need to insert the
    2874             :          * destination rowtype OID in its composite-datum header field, so we
    2875             :          * have to copy it anyway.  heap_copy_tuple_as_datum() is convenient
    2876             :          * for this since it will both make the physical copy and insert the
    2877             :          * correct composite header fields.  Note that we aren't expecting to
    2878             :          * have to flatten any toasted fields: the input was a composite
    2879             :          * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
    2880             :          * is overkill here, but its check for external fields is cheap.
    2881             :          */
    2882           6 :         *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
    2883             :     }
    2884             : }
    2885             : 
    2886             : /*
    2887             :  * Evaluate "scalar op ANY/ALL (array)".
    2888             :  *
    2889             :  * Source array is in our result area, scalar arg is already evaluated into
    2890             :  * fcinfo->arg[0]/argnull[0].
    2891             :  *
    2892             :  * The operator always yields boolean, and we combine the results across all
    2893             :  * array elements using OR and AND (for ANY and ALL respectively).  Of course
    2894             :  * we short-circuit as soon as the result is known.
    2895             :  */
    2896             : void
    2897       84404 : ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
    2898             : {
    2899       84404 :     FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
    2900       84404 :     bool        useOr = op->d.scalararrayop.useOr;
    2901       84404 :     bool        strictfunc = op->d.scalararrayop.finfo->fn_strict;
    2902             :     ArrayType  *arr;
    2903             :     int         nitems;
    2904             :     Datum       result;
    2905             :     bool        resultnull;
    2906             :     int         i;
    2907             :     int16       typlen;
    2908             :     bool        typbyval;
    2909             :     char        typalign;
    2910             :     char       *s;
    2911             :     bits8      *bitmap;
    2912             :     int         bitmask;
    2913             : 
    2914             :     /*
    2915             :      * If the array is NULL then we return NULL --- it's not very meaningful
    2916             :      * to do anything else, even if the operator isn't strict.
    2917             :      */
    2918       84404 :     if (*op->resnull)
    2919           8 :         return;
    2920             : 
    2921             :     /* Else okay to fetch and detoast the array */
    2922       84396 :     arr = DatumGetArrayTypeP(*op->resvalue);
    2923             : 
    2924             :     /*
    2925             :      * If the array is empty, we return either FALSE or TRUE per the useOr
    2926             :      * flag.  This is correct even if the scalar is NULL; since we would
    2927             :      * evaluate the operator zero times, it matters not whether it would want
    2928             :      * to return NULL.
    2929             :      */
    2930       84396 :     nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    2931       84396 :     if (nitems <= 0)
    2932             :     {
    2933         254 :         *op->resvalue = BoolGetDatum(!useOr);
    2934         254 :         *op->resnull = false;
    2935         254 :         return;
    2936             :     }
    2937             : 
    2938             :     /*
    2939             :      * If the scalar is NULL, and the function is strict, return NULL; no
    2940             :      * point in iterating the loop.
    2941             :      */
    2942       84142 :     if (fcinfo->argnull[0] && strictfunc)
    2943             :     {
    2944           5 :         *op->resnull = true;
    2945           5 :         return;
    2946             :     }
    2947             : 
    2948             :     /*
    2949             :      * We arrange to look up info about the element type only once per series
    2950             :      * of calls, assuming the element type doesn't change underneath us.
    2951             :      */
    2952       84137 :     if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
    2953             :     {
    2954         652 :         get_typlenbyvalalign(ARR_ELEMTYPE(arr),
    2955             :                              &op->d.scalararrayop.typlen,
    2956             :                              &op->d.scalararrayop.typbyval,
    2957             :                              &op->d.scalararrayop.typalign);
    2958         652 :         op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
    2959             :     }
    2960             : 
    2961       84137 :     typlen = op->d.scalararrayop.typlen;
    2962       84137 :     typbyval = op->d.scalararrayop.typbyval;
    2963       84137 :     typalign = op->d.scalararrayop.typalign;
    2964             : 
    2965             :     /* Initialize result appropriately depending on useOr */
    2966       84137 :     result = BoolGetDatum(!useOr);
    2967       84137 :     resultnull = false;
    2968             : 
    2969             :     /* Loop over the array elements */
    2970       84137 :     s = (char *) ARR_DATA_PTR(arr);
    2971       84137 :     bitmap = ARR_NULLBITMAP(arr);
    2972       84137 :     bitmask = 1;
    2973             : 
    2974      218097 :     for (i = 0; i < nitems; i++)
    2975             :     {
    2976             :         Datum       elt;
    2977             :         Datum       thisresult;
    2978             : 
    2979             :         /* Get array element, checking for NULL */
    2980      190495 :         if (bitmap && (*bitmap & bitmask) == 0)
    2981             :         {
    2982           4 :             fcinfo->arg[1] = (Datum) 0;
    2983           4 :             fcinfo->argnull[1] = true;
    2984             :         }
    2985             :         else
    2986             :         {
    2987      190491 :             elt = fetch_att(s, typbyval, typlen);
    2988      190491 :             s = att_addlength_pointer(s, typlen, s);
    2989      190491 :             s = (char *) att_align_nominal(s, typalign);
    2990      190491 :             fcinfo->arg[1] = elt;
    2991      190491 :             fcinfo->argnull[1] = false;
    2992             :         }
    2993             : 
    2994             :         /* Call comparison function */
    2995      190495 :         if (fcinfo->argnull[1] && strictfunc)
    2996             :         {
    2997           4 :             fcinfo->isnull = true;
    2998           4 :             thisresult = (Datum) 0;
    2999             :         }
    3000             :         else
    3001             :         {
    3002      190491 :             fcinfo->isnull = false;
    3003      190491 :             thisresult = (op->d.scalararrayop.fn_addr) (fcinfo);
    3004             :         }
    3005             : 
    3006             :         /* Combine results per OR or AND semantics */
    3007      190495 :         if (fcinfo->isnull)
    3008           4 :             resultnull = true;
    3009      190491 :         else if (useOr)
    3010             :         {
    3011      104960 :             if (DatumGetBool(thisresult))
    3012             :             {
    3013       15827 :                 result = BoolGetDatum(true);
    3014       15827 :                 resultnull = false;
    3015       15827 :                 break;          /* needn't look at any more elements */
    3016             :             }
    3017             :         }
    3018             :         else
    3019             :         {
    3020       85531 :             if (!DatumGetBool(thisresult))
    3021             :             {
    3022       40708 :                 result = BoolGetDatum(false);
    3023       40708 :                 resultnull = false;
    3024       40708 :                 break;          /* needn't look at any more elements */
    3025             :             }
    3026             :         }
    3027             : 
    3028             :         /* advance bitmap pointer if any */
    3029      133960 :         if (bitmap)
    3030             :         {
    3031        1008 :             bitmask <<= 1;
    3032        1008 :             if (bitmask == 0x100)
    3033             :             {
    3034         125 :                 bitmap++;
    3035         125 :                 bitmask = 1;
    3036             :             }
    3037             :         }
    3038             :     }
    3039             : 
    3040       84137 :     *op->resvalue = result;
    3041       84137 :     *op->resnull = resultnull;
    3042             : }
    3043             : 
    3044             : /*
    3045             :  * Evaluate a NOT NULL domain constraint.
    3046             :  */
    3047             : void
    3048          52 : ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
    3049             : {
    3050          52 :     if (*op->resnull)
    3051          12 :         ereport(ERROR,
    3052             :                 (errcode(ERRCODE_NOT_NULL_VIOLATION),
    3053             :                  errmsg("domain %s does not allow null values",
    3054             :                         format_type_be(op->d.domaincheck.resulttype)),
    3055             :                  errdatatype(op->d.domaincheck.resulttype)));
    3056          40 : }
    3057             : 
    3058             : /*
    3059             :  * Evaluate a CHECK domain constraint.
    3060             :  */
    3061             : void
    3062         703 : ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
    3063             : {
    3064        1389 :     if (!*op->d.domaincheck.checknull &&
    3065         686 :         !DatumGetBool(*op->d.domaincheck.checkvalue))
    3066          38 :         ereport(ERROR,
    3067             :                 (errcode(ERRCODE_CHECK_VIOLATION),
    3068             :                  errmsg("value for domain %s violates check constraint \"%s\"",
    3069             :                         format_type_be(op->d.domaincheck.resulttype),
    3070             :                         op->d.domaincheck.constraintname),
    3071             :                  errdomainconstraint(op->d.domaincheck.resulttype,
    3072             :                                      op->d.domaincheck.constraintname)));
    3073         665 : }
    3074             : 
    3075             : /*
    3076             :  * Evaluate the various forms of XmlExpr.
    3077             :  *
    3078             :  * Arguments have been evaluated into named_argvalue/named_argnull
    3079             :  * and/or argvalue/argnull arrays.
    3080             :  */
    3081             : void
    3082          24 : ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
    3083             : {
    3084          24 :     XmlExpr    *xexpr = op->d.xmlexpr.xexpr;
    3085             :     Datum       value;
    3086             :     int         i;
    3087             : 
    3088          24 :     *op->resnull = true;     /* until we get a result */
    3089          24 :     *op->resvalue = (Datum) 0;
    3090             : 
    3091          24 :     switch (xexpr->op)
    3092             :     {
    3093             :         case IS_XMLCONCAT:
    3094             :             {
    3095           2 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3096           2 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3097           2 :                 List       *values = NIL;
    3098             : 
    3099           5 :                 for (i = 0; i < list_length(xexpr->args); i++)
    3100             :                 {
    3101           3 :                     if (!argnull[i])
    3102           0 :                         values = lappend(values, DatumGetPointer(argvalue[i]));
    3103             :                 }
    3104             : 
    3105           2 :                 if (values != NIL)
    3106             :                 {
    3107           0 :                     *op->resvalue = PointerGetDatum(xmlconcat(values));
    3108           0 :                     *op->resnull = false;
    3109             :                 }
    3110             :             }
    3111           2 :             break;
    3112             : 
    3113             :         case IS_XMLFOREST:
    3114             :             {
    3115           0 :                 Datum      *argvalue = op->d.xmlexpr.named_argvalue;
    3116           0 :                 bool       *argnull = op->d.xmlexpr.named_argnull;
    3117             :                 StringInfoData buf;
    3118             :                 ListCell   *lc;
    3119             :                 ListCell   *lc2;
    3120             : 
    3121           0 :                 initStringInfo(&buf);
    3122             : 
    3123           0 :                 i = 0;
    3124           0 :                 forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
    3125             :                 {
    3126           0 :                     Expr       *e = (Expr *) lfirst(lc);
    3127           0 :                     char       *argname = strVal(lfirst(lc2));
    3128             : 
    3129           0 :                     if (!argnull[i])
    3130             :                     {
    3131           0 :                         value = argvalue[i];
    3132           0 :                         appendStringInfo(&buf, "<%s>%s</%s>",
    3133             :                                          argname,
    3134             :                                          map_sql_value_to_xml_value(value,
    3135             :                                                                     exprType((Node *) e), true),
    3136             :                                          argname);
    3137           0 :                         *op->resnull = false;
    3138             :                     }
    3139           0 :                     i++;
    3140             :                 }
    3141             : 
    3142           0 :                 if (!*op->resnull)
    3143             :                 {
    3144             :                     text       *result;
    3145             : 
    3146           0 :                     result = cstring_to_text_with_len(buf.data, buf.len);
    3147           0 :                     *op->resvalue = PointerGetDatum(result);
    3148             :                 }
    3149             : 
    3150           0 :                 pfree(buf.data);
    3151             :             }
    3152           0 :             break;
    3153             : 
    3154             :         case IS_XMLELEMENT:
    3155           0 :             *op->resvalue = PointerGetDatum(xmlelement(xexpr,
    3156             :                                                        op->d.xmlexpr.named_argvalue,
    3157             :                                                        op->d.xmlexpr.named_argnull,
    3158             :                                                        op->d.xmlexpr.argvalue,
    3159             :                                                        op->d.xmlexpr.argnull));
    3160           0 :             *op->resnull = false;
    3161           0 :             break;
    3162             : 
    3163             :         case IS_XMLPARSE:
    3164             :             {
    3165          22 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3166          22 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3167             :                 text       *data;
    3168             :                 bool        preserve_whitespace;
    3169             : 
    3170             :                 /* arguments are known to be text, bool */
    3171          22 :                 Assert(list_length(xexpr->args) == 2);
    3172             : 
    3173          22 :                 if (argnull[0])
    3174           0 :                     return;
    3175          22 :                 value = argvalue[0];
    3176          22 :                 data = DatumGetTextPP(value);
    3177             : 
    3178          22 :                 if (argnull[1]) /* probably can't happen */
    3179           0 :                     return;
    3180          22 :                 value = argvalue[1];
    3181          22 :                 preserve_whitespace = DatumGetBool(value);
    3182             : 
    3183          22 :                 *op->resvalue = PointerGetDatum(xmlparse(data,
    3184             :                                                          xexpr->xmloption,
    3185             :                                                          preserve_whitespace));
    3186           0 :                 *op->resnull = false;
    3187             :             }
    3188           0 :             break;
    3189             : 
    3190             :         case IS_XMLPI:
    3191             :             {
    3192             :                 text       *arg;
    3193             :                 bool        isnull;
    3194             : 
    3195             :                 /* optional argument is known to be text */
    3196           0 :                 Assert(list_length(xexpr->args) <= 1);
    3197             : 
    3198           0 :                 if (xexpr->args)
    3199             :                 {
    3200           0 :                     isnull = op->d.xmlexpr.argnull[0];
    3201           0 :                     if (isnull)
    3202           0 :                         arg = NULL;
    3203             :                     else
    3204           0 :                         arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]);
    3205             :                 }
    3206             :                 else
    3207             :                 {
    3208           0 :                     arg = NULL;
    3209           0 :                     isnull = false;
    3210             :                 }
    3211             : 
    3212           0 :                 *op->resvalue = PointerGetDatum(xmlpi(xexpr->name,
    3213             :                                                       arg,
    3214             :                                                       isnull,
    3215             :                                                       op->resnull));
    3216             :             }
    3217           0 :             break;
    3218             : 
    3219             :         case IS_XMLROOT:
    3220             :             {
    3221           0 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3222           0 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3223             :                 xmltype    *data;
    3224             :                 text       *version;
    3225             :                 int         standalone;
    3226             : 
    3227             :                 /* arguments are known to be xml, text, int */
    3228           0 :                 Assert(list_length(xexpr->args) == 3);
    3229             : 
    3230           0 :                 if (argnull[0])
    3231           0 :                     return;
    3232           0 :                 data = DatumGetXmlP(argvalue[0]);
    3233             : 
    3234           0 :                 if (argnull[1])
    3235           0 :                     version = NULL;
    3236             :                 else
    3237           0 :                     version = DatumGetTextPP(argvalue[1]);
    3238             : 
    3239           0 :                 Assert(!argnull[2]);    /* always present */
    3240           0 :                 standalone = DatumGetInt32(argvalue[2]);
    3241             : 
    3242           0 :                 *op->resvalue = PointerGetDatum(xmlroot(data,
    3243             :                                                         version,
    3244             :                                                         standalone));
    3245           0 :                 *op->resnull = false;
    3246             :             }
    3247           0 :             break;
    3248             : 
    3249             :         case IS_XMLSERIALIZE:
    3250             :             {
    3251           0 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3252           0 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3253             : 
    3254             :                 /* argument type is known to be xml */
    3255           0 :                 Assert(list_length(xexpr->args) == 1);
    3256             : 
    3257           0 :                 if (argnull[0])
    3258           0 :                     return;
    3259           0 :                 value = argvalue[0];
    3260             : 
    3261           0 :                 *op->resvalue = PointerGetDatum(
    3262             :                                                 xmltotext_with_xmloption(DatumGetXmlP(value),
    3263             :                                                                          xexpr->xmloption));
    3264           0 :                 *op->resnull = false;
    3265             :             }
    3266           0 :             break;
    3267             : 
    3268             :         case IS_DOCUMENT:
    3269             :             {
    3270           0 :                 Datum      *argvalue = op->d.xmlexpr.argvalue;
    3271           0 :                 bool       *argnull = op->d.xmlexpr.argnull;
    3272             : 
    3273             :                 /* optional argument is known to be xml */
    3274           0 :                 Assert(list_length(xexpr->args) == 1);
    3275             : 
    3276           0 :                 if (argnull[0])
    3277           0 :                     return;
    3278           0 :                 value = argvalue[0];
    3279             : 
    3280           0 :                 *op->resvalue =
    3281           0 :                     BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
    3282           0 :                 *op->resnull = false;
    3283             :             }
    3284           0 :             break;
    3285             : 
    3286             :         default:
    3287           0 :             elog(ERROR, "unrecognized XML operation");
    3288             :             break;
    3289             :     }
    3290             : }
    3291             : 
    3292             : /*
    3293             :  * ExecEvalGroupingFunc
    3294             :  *
    3295             :  * Computes a bitmask with a bit for each (unevaluated) argument expression
    3296             :  * (rightmost arg is least significant bit).
    3297             :  *
    3298             :  * A bit is set if the corresponding expression is NOT part of the set of
    3299             :  * grouping expressions in the current grouping set.
    3300             :  */
    3301             : void
    3302         264 : ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
    3303             : {
    3304         264 :     int         result = 0;
    3305         264 :     Bitmapset  *grouped_cols = op->d.grouping_func.parent->grouped_cols;
    3306             :     ListCell   *lc;
    3307             : 
    3308         667 :     foreach(lc, op->d.grouping_func.clauses)
    3309             :     {
    3310         403 :         int         attnum = lfirst_int(lc);
    3311             : 
    3312         403 :         result <<= 1;
    3313             : 
    3314         403 :         if (!bms_is_member(attnum, grouped_cols))
    3315         156 :             result |= 1;
    3316             :     }
    3317             : 
    3318         264 :     *op->resvalue = Int32GetDatum(result);
    3319         264 :     *op->resnull = false;
    3320         264 : }
    3321             : 
    3322             : /*
    3323             :  * Hand off evaluation of a subplan to nodeSubplan.c
    3324             :  */
    3325             : void
    3326       82700 : ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3327             : {
    3328       82700 :     SubPlanState *sstate = op->d.subplan.sstate;
    3329             : 
    3330             :     /* could potentially be nested, so make sure there's enough stack */
    3331       82700 :     check_stack_depth();
    3332             : 
    3333       82700 :     *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
    3334       82700 : }
    3335             : 
    3336             : /*
    3337             :  * Hand off evaluation of an alternative subplan to nodeSubplan.c
    3338             :  */
    3339             : void
    3340         143 : ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3341             : {
    3342         143 :     AlternativeSubPlanState *asstate = op->d.alternative_subplan.asstate;
    3343             : 
    3344             :     /* could potentially be nested, so make sure there's enough stack */
    3345         143 :     check_stack_depth();
    3346             : 
    3347         143 :     *op->resvalue = ExecAlternativeSubPlan(asstate, econtext, op->resnull);
    3348         143 : }
    3349             : 
    3350             : /*
    3351             :  * Evaluate a wholerow Var expression.
    3352             :  *
    3353             :  * Returns a Datum whose value is the value of a whole-row range variable
    3354             :  * with respect to given expression context.
    3355             :  */
    3356             : void
    3357        1041 : ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
    3358             : {
    3359        1041 :     Var        *variable = op->d.wholerow.var;
    3360             :     TupleTableSlot *slot;
    3361             :     TupleDesc   output_tupdesc;
    3362             :     MemoryContext oldcontext;
    3363             :     HeapTupleHeader dtuple;
    3364             :     HeapTuple   tuple;
    3365             : 
    3366             :     /* This was checked by ExecInitExpr */
    3367        1041 :     Assert(variable->varattno == InvalidAttrNumber);
    3368             : 
    3369             :     /* Get the input slot we want */
    3370        1041 :     switch (variable->varno)
    3371             :     {
    3372             :         case INNER_VAR:
    3373             :             /* get the tuple from the inner node */
    3374           9 :             slot = econtext->ecxt_innertuple;
    3375           9 :             break;
    3376             : 
    3377             :         case OUTER_VAR:
    3378             :             /* get the tuple from the outer node */
    3379           3 :             slot = econtext->ecxt_outertuple;
    3380           3 :             break;
    3381             : 
    3382             :             /* INDEX_VAR is handled by default case */
    3383             : 
    3384             :         default:
    3385             :             /* get the tuple from the relation being scanned */
    3386        1029 :             slot = econtext->ecxt_scantuple;
    3387        1029 :             break;
    3388             :     }
    3389             : 
    3390             :     /* Apply the junkfilter if any */
    3391        1041 :     if (op->d.wholerow.junkFilter != NULL)
    3392          10 :         slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
    3393             : 
    3394             :     /*
    3395             :      * If first time through, obtain tuple descriptor and check compatibility.
    3396             :      *
    3397             :      * XXX: It'd be great if this could be moved to the expression
    3398             :      * initialization phase, but due to using slots that's currently not
    3399             :      * feasible.
    3400             :      */
    3401        1041 :     if (op->d.wholerow.first)
    3402             :     {
    3403             :         /* optimistically assume we don't need slow path */
    3404         222 :         op->d.wholerow.slow = false;
    3405             : 
    3406             :         /*
    3407             :          * If the Var identifies a named composite type, we must check that
    3408             :          * the actual tuple type is compatible with it.
    3409             :          */
    3410         222 :         if (variable->vartype != RECORDOID)
    3411             :         {
    3412             :             TupleDesc   var_tupdesc;
    3413             :             TupleDesc   slot_tupdesc;
    3414             :             int         i;
    3415             : 
    3416             :             /*
    3417             :              * We really only care about numbers of attributes and data types.
    3418             :              * Also, we can ignore type mismatch on columns that are dropped
    3419             :              * in the destination type, so long as (1) the physical storage
    3420             :              * matches or (2) the actual column value is NULL.  Case (1) is
    3421             :              * helpful in some cases involving out-of-date cached plans, while
    3422             :              * case (2) is expected behavior in situations such as an INSERT
    3423             :              * into a table with dropped columns (the planner typically
    3424             :              * generates an INT4 NULL regardless of the dropped column type).
    3425             :              * If we find a dropped column and cannot verify that case (1)
    3426             :              * holds, we have to use the slow path to check (2) for each row.
    3427             :              */
    3428         142 :             var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
    3429             : 
    3430         142 :             slot_tupdesc = slot->tts_tupleDescriptor;
    3431             : 
    3432         142 :             if (var_tupdesc->natts != slot_tupdesc->natts)
    3433           0 :                 ereport(ERROR,
    3434             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3435             :                          errmsg("table row type and query-specified row type do not match"),
    3436             :                          errdetail_plural("Table row contains %d attribute, but query expects %d.",
    3437             :                                           "Table row contains %d attributes, but query expects %d.",
    3438             :                                           slot_tupdesc->natts,
    3439             :                                           slot_tupdesc->natts,
    3440             :                                           var_tupdesc->natts)));
    3441             : 
    3442         530 :             for (i = 0; i < var_tupdesc->natts; i++)
    3443             :             {
    3444         388 :                 Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
    3445         388 :                 Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
    3446             : 
    3447         388 :                 if (vattr->atttypid == sattr->atttypid)
    3448         385 :                     continue;   /* no worries */
    3449           3 :                 if (!vattr->attisdropped)
    3450           0 :                     ereport(ERROR,
    3451             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    3452             :                              errmsg("table row type and query-specified row type do not match"),
    3453             :                              errdetail("Table has type %s at ordinal position %d, but query expects %s.",
    3454             :                                        format_type_be(sattr->atttypid),
    3455             :                                        i + 1,
    3456             :                                        format_type_be(vattr->atttypid))));
    3457             : 
    3458           3 :                 if (vattr->attlen != sattr->attlen ||
    3459           0 :                     vattr->attalign != sattr->attalign)
    3460           3 :                     op->d.wholerow.slow = true; /* need to check for nulls */
    3461             :             }
    3462             : 
    3463             :             /*
    3464             :              * Use the variable's declared rowtype as the descriptor for the
    3465             :              * output values, modulo possibly assigning new column names
    3466             :              * below. In particular, we *must* absorb any attisdropped
    3467             :              * markings.
    3468             :              */
    3469         142 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    3470         142 :             output_tupdesc = CreateTupleDescCopy(var_tupdesc);
    3471         142 :             MemoryContextSwitchTo(oldcontext);
    3472             : 
    3473         142 :             ReleaseTupleDesc(var_tupdesc);
    3474             :         }
    3475             :         else
    3476             :         {
    3477             :             /*
    3478             :              * In the RECORD case, we use the input slot's rowtype as the
    3479             :              * descriptor for the output values, modulo possibly assigning new
    3480             :              * column names below.
    3481             :              */
    3482          80 :             oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    3483          80 :             output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
    3484          80 :             MemoryContextSwitchTo(oldcontext);
    3485             :         }
    3486             : 
    3487             :         /*
    3488             :          * Construct a tuple descriptor for the composite values we'll
    3489             :          * produce, and make sure its record type is "blessed".  The main
    3490             :          * reason to do this is to be sure that operations such as
    3491             :          * row_to_json() will see the desired column names when they look up
    3492             :          * the descriptor from the type information embedded in the composite
    3493             :          * values.
    3494             :          *
    3495             :          * We already got the correct physical datatype info above, but now we
    3496             :          * should try to find the source RTE and adopt its column aliases, in
    3497             :          * case they are different from the original rowtype's names.  For
    3498             :          * example, in "SELECT foo(t) FROM tab t(x,y)", the first two columns
    3499             :          * in the composite output should be named "x" and "y" regardless of
    3500             :          * tab's column names.
    3501             :          *
    3502             :          * If we can't locate the RTE, assume the column names we've got are
    3503             :          * OK.  (As of this writing, the only cases where we can't locate the
    3504             :          * RTE are in execution of trigger WHEN clauses, and then the Var will
    3505             :          * have the trigger's relation's rowtype, so its names are fine.)
    3506             :          * Also, if the creator of the RTE didn't bother to fill in an eref
    3507             :          * field, assume our column names are OK.  (This happens in COPY, and
    3508             :          * perhaps other places.)
    3509             :          */
    3510         444 :         if (econtext->ecxt_estate &&
    3511         222 :             variable->varno <= list_length(econtext->ecxt_estate->es_range_table))
    3512             :         {
    3513         214 :             RangeTblEntry *rte = rt_fetch(variable->varno,
    3514             :                                           econtext->ecxt_estate->es_range_table);
    3515             : 
    3516         214 :             if (rte->eref)
    3517         214 :                 ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
    3518             :         }
    3519             : 
    3520             :         /* Bless the tupdesc if needed, and save it in the execution state */
    3521         222 :         op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
    3522             : 
    3523         222 :         op->d.wholerow.first = false;
    3524             :     }
    3525             : 
    3526             :     /*
    3527             :      * Make sure all columns of the slot are accessible in the slot's
    3528             :      * Datum/isnull arrays.
    3529             :      */
    3530        1041 :     slot_getallattrs(slot);
    3531             : 
    3532        1041 :     if (op->d.wholerow.slow)
    3533             :     {
    3534             :         /* Check to see if any dropped attributes are non-null */
    3535           5 :         TupleDesc   tupleDesc = slot->tts_tupleDescriptor;
    3536           5 :         TupleDesc   var_tupdesc = op->d.wholerow.tupdesc;
    3537             :         int         i;
    3538             : 
    3539           5 :         Assert(var_tupdesc->natts == tupleDesc->natts);
    3540             : 
    3541          20 :         for (i = 0; i < var_tupdesc->natts; i++)
    3542             :         {
    3543          15 :             Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
    3544          15 :             Form_pg_attribute sattr = TupleDescAttr(tupleDesc, i);
    3545             : 
    3546          15 :             if (!vattr->attisdropped)
    3547          10 :                 continue;       /* already checked non-dropped cols */
    3548           5 :             if (slot->tts_isnull[i])
    3549           5 :                 continue;       /* null is always okay */
    3550           0 :             if (vattr->attlen != sattr->attlen ||
    3551           0 :                 vattr->attalign != sattr->attalign)
    3552           0 :                 ereport(ERROR,
    3553             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3554             :                          errmsg("table row type and query-specified row type do not match"),
    3555             :                          errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
    3556             :                                    i + 1)));
    3557             :         }
    3558             :     }
    3559             : 
    3560             :     /*
    3561             :      * Build a composite datum, making sure any toasted fields get detoasted.
    3562             :      *
    3563             :      * (Note: it is critical that we not change the slot's state here.)
    3564             :      */
    3565        1041 :     tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
    3566             :                                         slot->tts_values,
    3567             :                                         slot->tts_isnull);
    3568        1041 :     dtuple = tuple->t_data;
    3569             : 
    3570             :     /*
    3571             :      * Label the datum with the composite type info we identified before.
    3572             :      *
    3573             :      * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
    3574             :      * the tuple build step; but that seems a tad risky so let's not.)
    3575             :      */
    3576        1041 :     HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
    3577        1041 :     HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
    3578             : 
    3579        1041 :     *op->resvalue = PointerGetDatum(dtuple);
    3580        1041 :     *op->resnull = false;
    3581        1041 : }

Generated by: LCOV version 1.11