千家信息网

怎么使用PostgreSQL中ExecInitExprRec函数

发表于:2025-01-24 作者:千家信息网编辑
千家信息网最后更新 2025年01月24日,本篇内容主要讲解"怎么使用PostgreSQL中ExecInitExprRec函数",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么使用PostgreSQ
千家信息网最后更新 2025年01月24日怎么使用PostgreSQL中ExecInitExprRec函数

本篇内容主要讲解"怎么使用PostgreSQL中ExecInitExprRec函数",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么使用PostgreSQL中ExecInitExprRec函数"吧!

EEO_XXX宏定义
opcode分发器宏定义

/* * Macros for opcode dispatch. * opcode分发器宏定义 * * EEO_SWITCH - just hides the switch if not in use. * EEO_SWITCH - 如未使用,则隐藏switch *  * EEO_CASE - labels the implementation of named expression step type. * EEO_CASE - 标签化已命名的表达式步骤类型的实现 *  * EEO_DISPATCH - jump to the implementation of the step type for 'op'. * EEO_DISPATCH - 跳到'op'指定的步骤类型的实现 *  * EEO_OPCODE - compute opcode required by used expression evaluation method. *            - 通过请求的表达式解析方法计算opcode *  * EEO_NEXT - increment 'op' and jump to correct next step type. *          - 'op'++并跳转到下一个步骤类型 * * EEO_JUMP - jump to the specified step number within the current expression. * EEO_JUMP - 在当前表达式中跳转到指定的步骤编号 */#if defined(EEO_USE_COMPUTED_GOTO)//--------------- 定义了EEO_USE_COMPUTED_GOTO/* struct for jump target -> opcode lookup table *///跳转target -> opcode搜索表结构体typedef struct ExprEvalOpLookup{    const void *opcode;    ExprEvalOp  op;} ExprEvalOpLookup;/* to make dispatch_table accessible outside ExecInterpExpr() */static const void **dispatch_table = NULL;/* jump target -> opcode lookup table */static ExprEvalOpLookup reverse_dispatch_table[EEOP_LAST];#define EEO_SWITCH()#define EEO_CASE(name)      CASE_##name:#define EEO_DISPATCH()      goto *((void *) op->opcode)#define EEO_OPCODE(opcode)  ((intptr_t) dispatch_table[opcode])#else                           /* !EEO_USE_COMPUTED_GOTO *///--------------- 没有定义EEO_USE_COMPUTED_GOTO#define EEO_SWITCH()        starteval: switch ((ExprEvalOp) op->opcode)#define EEO_CASE(name)      case name:#define EEO_DISPATCH()      goto starteval#define EEO_OPCODE(opcode)  (opcode)#endif                          /* EEO_USE_COMPUTED_GOTO */#define EEO_NEXT() \    do { \        op++; \        EEO_DISPATCH(); \    } while (0)#define EEO_JUMP(stepno) \    do { \        op = &state->steps[stepno]; \        EEO_DISPATCH(); \    } while (0)

ExprState
解析表达式中运行期状态节点

/* Bits in ExprState->flags (see also execExpr.h for private flag bits): *//* expression is for use with ExecQual() */#define EEO_FLAG_IS_QUAL                    (1 << 0)typedef struct ExprState{    //节点tag    Node        tag;    //EEO_FLAG_IS_QUAL    uint8       flags;          /* bitmask of EEO_FLAG_* bits, see above */    /*     * Storage for result value of a scalar expression, or for individual     * column results within expressions built by ExecBuildProjectionInfo().     * 存储scalar expression表达式     *   和通过ExecBuildProjectionInfo()函数创建的expressions单列的结果.     */#define FIELDNO_EXPRSTATE_RESNULL 2    bool        resnull;#define FIELDNO_EXPRSTATE_RESVALUE 3    Datum       resvalue;    /*     * If projecting a tuple result, this slot holds the result; else NULL.     * 如果投影元组结果,该slot存储结果,或者为NULL.     */#define FIELDNO_EXPRSTATE_RESULTSLOT 4    TupleTableSlot *resultslot;    /*     * Instructions to compute expression's return value.     * 计算表达式返回结果的基础"架构"     */    struct ExprEvalStep *steps;    /*     * Function that actually evaluates the expression.  This can be set to     * different values depending on the complexity of the expression.     * 实际解析表达式的函数.     * 根据表达式的复杂程度,可以设置为不同的值.     */    ExprStateEvalFunc evalfunc;    /* original expression tree, for debugging only */    //原始的表达式树,仅用于debugging    Expr       *expr;    /* private state for an evalfunc */    //evalfunc的私有状态    void       *evalfunc_private;    /*     * XXX: following fields only needed during "compilation" (ExecInitExpr);     * could be thrown away afterwards.     * XXX: 接下来的字段在"compilation" (ExecInitExpr)期间需要,之后可被"扔掉".     */    //当前的步数    int         steps_len;      /* number of steps currently */    //steps数组已分配的长度    int         steps_alloc;    /* allocated length of steps array */    //父PlanState节点(如存在)    struct PlanState *parent;   /* parent PlanState node, if any */    //用于编译PARAM_EXTERN节点    ParamListInfo ext_params;   /* for compiling PARAM_EXTERN nodes */    //    Datum      *innermost_caseval;    bool       *innermost_casenull;    Datum      *innermost_domainval;    bool       *innermost_domainnull;} ExprState;

ExprEvalStep
表达式解析步骤结构体

typedef struct ExprEvalStep{    /*     * Instruction to be executed.  During instruction preparation this is an     * enum ExprEvalOp, but later it can be changed to some other type, e.g. a     * pointer for computed goto (that's why it's an intptr_t).     * 待执行指令.     * 在指令准备期间这是枚举型的ExprEvalOp,     *   但后续会被改变为某些其他类型,比如用于goto的指针,因此被定义为intprt_t类型     */    intptr_t    opcode;    /* where to store the result of this step */    //存储该步骤的结果    Datum      *resvalue;    bool       *resnull;    /*     * Inline data for the operation.  Inline data is faster to access, but     * also bloats the size of all instructions.  The union should be kept to     * no more than 40 bytes on 64-bit systems (so that the entire struct is     * no more than 64 bytes, a single cacheline on common systems).     * 操作的内联数据.     * 内联数据用于更快的访问,但同时会导致指令的盘膨胀.     * 联合体在64-bit系统上应保持在40字节范围内     * (因此整个结构体不应大于64字节,普通系统上的单个缓存线大小)     */    union    {        /* for EEOP_INNER/OUTER/SCAN_FETCHSOME */        //用于EEOP_INNER/OUTER/SCAN_FETCHSOME        struct        {            /* attribute number up to which to fetch (inclusive) */            //获取到的属性编号            int         last_var;            TupleDesc   known_desc;        }           fetch;        /* for EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */        struct        {            /* attnum is attr number - 1 for regular VAR ... */            //attnum是常规VAR的attr number - 1            /* but it's just the normal (negative) attr number for SYSVAR */            //对于SYSVAR,该值是常规的attr number            int         attnum;            Oid         vartype;    /* type OID of variable */        }           var;        /* for EEOP_WHOLEROW */        struct        {            Var        *var;    /* original Var node in plan tree */            bool        first;  /* first time through, need to initialize? */            bool        slow;   /* need runtime check for nulls? */            TupleDesc   tupdesc;    /* descriptor for resulting tuples */            JunkFilter *junkFilter; /* JunkFilter to remove resjunk cols */        }           wholerow;        /* for EEOP_ASSIGN_*_VAR */        struct        {            /* target index in ExprState->resultslot->tts_values/nulls */            int         resultnum;            /* source attribute number - 1 */            int         attnum;        }           assign_var;        /* for EEOP_ASSIGN_TMP[_MAKE_RO] */        struct        {            /* target index in ExprState->resultslot->tts_values/nulls */            int         resultnum;        }           assign_tmp;        /* for EEOP_CONST */        struct        {            /* constant's value */            Datum       value;            bool        isnull;        }           constval;        /* for EEOP_FUNCEXPR_* / NULLIF / DISTINCT */        //对于EEOP_FUNCEXPR_* / NULLIF / DISTINCT        struct        {            //函数的检索数据            FmgrInfo   *finfo;  /* function's lookup data */            //参数信息等            FunctionCallInfo fcinfo_data;   /* arguments etc */            /* faster to access without additional indirection: */            //无需额外的指向,更快速的访问            PGFunction  fn_addr;    /* actual call address */            int         nargs;  /* number of arguments */        }           func;        /* for EEOP_BOOL_*_STEP */        struct        {            bool       *anynull;    /* track if any input was NULL */            int         jumpdone;   /* jump here if result determined */        }           boolexpr;        /* for EEOP_QUAL */        struct        {            int         jumpdone;   /* jump here on false or null */        }           qualexpr;        /* for EEOP_JUMP[_CONDITION] */        struct        {            int         jumpdone;   /* target instruction's index */        }           jump;        /* for EEOP_NULLTEST_ROWIS[NOT]NULL */        struct        {            /* cached tupdesc pointer - filled at runtime */            TupleDesc   argdesc;        }           nulltest_row;        /* for EEOP_PARAM_EXEC/EXTERN */        struct        {            int         paramid;    /* numeric ID for parameter */            Oid         paramtype;  /* OID of parameter's datatype */        }           param;        /* for EEOP_PARAM_CALLBACK */        struct        {            ExecEvalSubroutine paramfunc;   /* add-on evaluation subroutine */            void       *paramarg;   /* private data for same */            int         paramid;    /* numeric ID for parameter */            Oid         paramtype;  /* OID of parameter's datatype */        }           cparam;        /* for EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */        struct        {            Datum      *value;  /* value to return */            bool       *isnull;        }           casetest;        /* for EEOP_MAKE_READONLY */        struct        {            Datum      *value;  /* value to coerce to read-only */            bool       *isnull;        }           make_readonly;        /* for EEOP_IOCOERCE */        struct        {            /* lookup and call info for source type's output function */            FmgrInfo   *finfo_out;            FunctionCallInfo fcinfo_data_out;            /* lookup and call info for result type's input function */            FmgrInfo   *finfo_in;            FunctionCallInfo fcinfo_data_in;        }           iocoerce;        /* for EEOP_SQLVALUEFUNCTION */        struct        {            SQLValueFunction *svf;        }           sqlvaluefunction;        /* for EEOP_NEXTVALUEEXPR */        //EEOP_NEXTVALUEEXPR        struct        {            Oid         seqid;            Oid         seqtypid;        }           nextvalueexpr;        /* for EEOP_ARRAYEXPR */        struct        {            Datum      *elemvalues; /* element values get stored here */            bool       *elemnulls;            int         nelems; /* length of the above arrays */            Oid         elemtype;   /* array element type */            int16       elemlength; /* typlen of the array element type */            bool        elembyval;  /* is the element type pass-by-value? */            char        elemalign;  /* typalign of the element type */            bool        multidims;  /* is array expression multi-D? */        }           arrayexpr;        /* for EEOP_ARRAYCOERCE */        struct        {            ExprState  *elemexprstate;  /* null if no per-element work */            Oid         resultelemtype; /* element type of result array */            struct ArrayMapState *amstate;  /* workspace for array_map */        }           arraycoerce;        /* for EEOP_ROW */        struct        {            TupleDesc   tupdesc;    /* descriptor for result tuples */            /* workspace for the values constituting the row: */            Datum      *elemvalues;            bool       *elemnulls;        }           row;        /* for EEOP_ROWCOMPARE_STEP */        struct        {            /* lookup and call data for column comparison function */            FmgrInfo   *finfo;            FunctionCallInfo fcinfo_data;            PGFunction  fn_addr;            /* target for comparison resulting in NULL */            int         jumpnull;            /* target for comparison yielding inequality */            int         jumpdone;        }           rowcompare_step;        /* for EEOP_ROWCOMPARE_FINAL */        struct        {            RowCompareType rctype;        }           rowcompare_final;        /* for EEOP_MINMAX */        struct        {            /* workspace for argument values */            Datum      *values;            bool       *nulls;            int         nelems;            /* is it GREATEST or LEAST? */            MinMaxOp    op;            /* lookup and call data for comparison function */            FmgrInfo   *finfo;            FunctionCallInfo fcinfo_data;        }           minmax;        /* for EEOP_FIELDSELECT */        struct        {            AttrNumber  fieldnum;   /* field number to extract */            Oid         resulttype; /* field's type */            /* cached tupdesc pointer - filled at runtime */            TupleDesc   argdesc;        }           fieldselect;        /* for EEOP_FIELDSTORE_DEFORM / FIELDSTORE_FORM */        struct        {            /* original expression node */            FieldStore *fstore;            /* cached tupdesc pointer - filled at runtime */            /* note that a DEFORM and FORM pair share the same tupdesc */            TupleDesc  *argdesc;            /* workspace for column values */            Datum      *values;            bool       *nulls;            int         ncolumns;        }           fieldstore;        /* for EEOP_ARRAYREF_SUBSCRIPT */        struct        {            /* too big to have inline */            struct ArrayRefState *state;            int         off;    /* 0-based index of this subscript */            bool        isupper;    /* is it upper or lower subscript? */            int         jumpdone;   /* jump here on null */        }           arrayref_subscript;        /* for EEOP_ARRAYREF_OLD / ASSIGN / FETCH */        struct        {            /* too big to have inline */            struct ArrayRefState *state;        }           arrayref;        /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */        struct        {            /* name of constraint */            char       *constraintname;            /* where the result of a CHECK constraint will be stored */            Datum      *checkvalue;            bool       *checknull;            /* OID of domain type */            Oid         resulttype;        }           domaincheck;        /* for EEOP_CONVERT_ROWTYPE */        struct        {            ConvertRowtypeExpr *convert;    /* original expression */            /* these three fields are filled at runtime: */            TupleDesc   indesc; /* tupdesc for input type */            TupleDesc   outdesc;    /* tupdesc for output type */            TupleConversionMap *map;    /* column mapping */            bool        initialized;    /* initialized for current types? */        }           convert_rowtype;        /* for EEOP_SCALARARRAYOP */        struct        {            /* element_type/typlen/typbyval/typalign are filled at runtime */            Oid         element_type;   /* InvalidOid if not yet filled */            bool        useOr;  /* use OR or AND semantics? */            int16       typlen; /* array element type storage info */            bool        typbyval;            char        typalign;            FmgrInfo   *finfo;  /* function's lookup data */            FunctionCallInfo fcinfo_data;   /* arguments etc */            /* faster to access without additional indirection: */            PGFunction  fn_addr;    /* actual call address */        }           scalararrayop;        /* for EEOP_XMLEXPR */        struct        {            XmlExpr    *xexpr;  /* original expression node */            /* workspace for evaluating named args, if any */            Datum      *named_argvalue;            bool       *named_argnull;            /* workspace for evaluating unnamed args, if any */            Datum      *argvalue;            bool       *argnull;        }           xmlexpr;        /* for EEOP_AGGREF */        struct        {            /* out-of-line state, modified by nodeAgg.c */            AggrefExprState *astate;        }           aggref;        /* for EEOP_GROUPING_FUNC */        struct        {            AggState   *parent; /* parent Agg */            List       *clauses;    /* integer list of column numbers */        }           grouping_func;        /* for EEOP_WINDOW_FUNC */        struct        {            /* out-of-line state, modified by nodeWindowFunc.c */            WindowFuncExprState *wfstate;        }           window_func;        /* for EEOP_SUBPLAN */        struct        {            /* out-of-line state, created by nodeSubplan.c */            SubPlanState *sstate;        }           subplan;        /* for EEOP_ALTERNATIVE_SUBPLAN */        struct        {            /* out-of-line state, created by nodeSubplan.c */            AlternativeSubPlanState *asstate;        }           alternative_subplan;        /* for EEOP_AGG_*DESERIALIZE */        struct        {            AggState   *aggstate;            FunctionCallInfo fcinfo_data;            int         jumpnull;        }           agg_deserialize;        /* for EEOP_AGG_STRICT_INPUT_CHECK */        struct        {            bool       *nulls;            int         nargs;            int         jumpnull;        }           agg_strict_input_check;        /* for EEOP_AGG_INIT_TRANS */        struct        {            AggState   *aggstate;            AggStatePerTrans pertrans;            ExprContext *aggcontext;            int         setno;            int         transno;            int         setoff;            int         jumpnull;        }           agg_init_trans;        /* for EEOP_AGG_STRICT_TRANS_CHECK */        struct        {            AggState   *aggstate;            int         setno;            int         transno;            int         setoff;            int         jumpnull;        }           agg_strict_trans_check;        /* for EEOP_AGG_{PLAIN,ORDERED}_TRANS* */        struct        {            AggState   *aggstate;            AggStatePerTrans pertrans;            ExprContext *aggcontext;            int         setno;            int         transno;            int         setoff;        }           agg_trans;    }           d;} ExprEvalStep;

ExprEvalOp
ExprEvalSteps的鉴频器,定义哪个操作将被执行并且联合体ExprEvalStep->d中的哪个struct将被使用.

/* * Discriminator for ExprEvalSteps. * ExprEvalSteps的鉴频器 * * Identifies the operation to be executed and which member in the * ExprEvalStep->d union is valid. * 定义哪个操作将被执行并且联合体ExprEvalStep->d中的哪个struct将被使用. * * The order of entries needs to be kept in sync with the dispatch_table[] * array in execExprInterp.c:ExecInterpExpr(). * 条目的排序需要与execExprInterp.c:ExecInterpExpr()中dispatch_table[]数组的元素保持一致 */typedef enum ExprEvalOp{    /* entire expression has been evaluated completely, return */    //整个表达式已被解析,返回    EEOP_DONE,    /* apply slot_getsomeattrs on corresponding tuple slot */    //在相应的元组slot上应用了slot_getsomeattrs方法    EEOP_INNER_FETCHSOME,    EEOP_OUTER_FETCHSOME,    EEOP_SCAN_FETCHSOME,    /* compute non-system Var value */    //计算非系统Var变量值    EEOP_INNER_VAR,    EEOP_OUTER_VAR,    EEOP_SCAN_VAR,    /* compute system Var value */    //计算系统Var变量值    EEOP_INNER_SYSVAR,    EEOP_OUTER_SYSVAR,    EEOP_SCAN_SYSVAR,    /* compute wholerow Var */    //计算整行Var    EEOP_WHOLEROW,    /*     * Compute non-system Var value, assign it into ExprState's resultslot.     * These are not used if a CheckVarSlotCompatibility() check would be     * needed.     * 计算非系统Var值,分配到ExprState's的resultslot字段中.     * 如果CheckVarSlotCompatibility()需要时,这些都不需要.     */    EEOP_ASSIGN_INNER_VAR,    EEOP_ASSIGN_OUTER_VAR,    EEOP_ASSIGN_SCAN_VAR,    /* assign ExprState's resvalue/resnull to a column of its resultslot */    //分配ExprState's resvalue/resnull到该列的resultslot中    EEOP_ASSIGN_TMP,    /* ditto, applying MakeExpandedObjectReadOnly() */    //同上,应用MakeExpandedObjectReadOnly()    EEOP_ASSIGN_TMP_MAKE_RO,    /* evaluate Const value */    //解析常量值    EEOP_CONST,    /*     * Evaluate function call (including OpExprs etc).  For speed, we     * distinguish in the opcode whether the function is strict and/or     * requires usage stats tracking.     * 解析函数调用(包括OpExprs等等).     * 出于性能的考虑,需要区分opcode是strict函数还是非strict函数,以及是否需要统计跟踪.     */    EEOP_FUNCEXPR,    EEOP_FUNCEXPR_STRICT,    EEOP_FUNCEXPR_FUSAGE,    EEOP_FUNCEXPR_STRICT_FUSAGE,    /*     * Evaluate boolean AND expression, one step per subexpression. FIRST/LAST     * subexpressions are special-cased for performance.  Since AND always has     * at least two subexpressions, FIRST and LAST never apply to the same     * subexpression.     * 解析布尔AND表达式,每一个子表达式一个步骤.     * FIRST/LAST子表达式是性能上的特例.     * 由于AND通常至少有两个子表达式,FIRST和LAST永远都不会应用在同一个子表达式上.     */    EEOP_BOOL_AND_STEP_FIRST,    EEOP_BOOL_AND_STEP,    EEOP_BOOL_AND_STEP_LAST,    /* similarly for boolean OR expression */    //与布尔OR表达式类似    EEOP_BOOL_OR_STEP_FIRST,    EEOP_BOOL_OR_STEP,    EEOP_BOOL_OR_STEP_LAST,    /* evaluate boolean NOT expression */    //解析布尔NOT表达式    EEOP_BOOL_NOT_STEP,    /* simplified version of BOOL_AND_STEP for use by ExecQual() */    //用于ExecQual()中的BOOL_AND_STEP简化版本    EEOP_QUAL,    /* unconditional jump to another step */    //无条件跳转到另外一个步骤    EEOP_JUMP,    /* conditional jumps based on current result value */    //基于当前结果值的条件跳转    EEOP_JUMP_IF_NULL,    EEOP_JUMP_IF_NOT_NULL,    EEOP_JUMP_IF_NOT_TRUE,    /* perform NULL tests for scalar values */    //为scalar值执行NULL测试    EEOP_NULLTEST_ISNULL,    EEOP_NULLTEST_ISNOTNULL,    /* perform NULL tests for row values */    //为行值执行NULL测试    EEOP_NULLTEST_ROWISNULL,    EEOP_NULLTEST_ROWISNOTNULL,    /* evaluate a BooleanTest expression */    //解析BooleanTest表达式    EEOP_BOOLTEST_IS_TRUE,    EEOP_BOOLTEST_IS_NOT_TRUE,    EEOP_BOOLTEST_IS_FALSE,    EEOP_BOOLTEST_IS_NOT_FALSE,    /* evaluate PARAM_EXEC/EXTERN parameters */    //解析PARAM_EXEC/EXTERN参数    EEOP_PARAM_EXEC,    EEOP_PARAM_EXTERN,    EEOP_PARAM_CALLBACK,    /* return CaseTestExpr value */    //返回CaseTestExpr值    EEOP_CASE_TESTVAL,    /* apply MakeExpandedObjectReadOnly() to target value */    //对目标值应用MakeExpandedObjectReadOnly()    EEOP_MAKE_READONLY,    /* evaluate assorted special-purpose expression types */    //解析各种特殊用途的表达式类型    EEOP_IOCOERCE,    EEOP_DISTINCT,    EEOP_NOT_DISTINCT,    EEOP_NULLIF,    EEOP_SQLVALUEFUNCTION,    EEOP_CURRENTOFEXPR,    EEOP_NEXTVALUEEXPR,    EEOP_ARRAYEXPR,    EEOP_ARRAYCOERCE,    EEOP_ROW,    /*     * Compare two individual elements of each of two compared ROW()     * expressions.  Skip to ROWCOMPARE_FINAL if elements are not equal.     * 给出两个需要对比的ROW()表达式,两两比较行中的元素.     * 如果元素不相等,则跳转到ROWCOMPARE_FINAL     */    EEOP_ROWCOMPARE_STEP,    /* evaluate boolean value based on previous ROWCOMPARE_STEP operations */    //基于上一步的ROWCOMPARE_STEP操作解析布尔值    EEOP_ROWCOMPARE_FINAL,    /* evaluate GREATEST() or LEAST() */    //解析GREATEST()和LEAST()    EEOP_MINMAX,    /* evaluate FieldSelect expression */    //解析FieldSelect表达式    EEOP_FIELDSELECT,    /*     * Deform tuple before evaluating new values for individual fields in a     * FieldStore expression.     * 在解析FieldStore表达式中的独立列新值前重构元组     */    EEOP_FIELDSTORE_DEFORM,    /*     * Form the new tuple for a FieldStore expression.  Individual fields will     * have been evaluated into columns of the tuple deformed by the preceding     * DEFORM step.     * 为FieldStore表达式构成新元组.     * 单独的字段会解析到元组的列中(行已被上一个步骤EEOP_FIELDSTORE_DEFORM析构)     */    EEOP_FIELDSTORE_FORM,    /* Process an array subscript; short-circuit expression to NULL if NULL */    //处理数组子脚本.如为NULL则短路表达式为NULL    EEOP_ARRAYREF_SUBSCRIPT,    /*     * Compute old array element/slice when an ArrayRef assignment expression     * contains ArrayRef/FieldStore subexpressions.  Value is accessed using     * the CaseTest mechanism.     * 在ArrayRef分配表达式包含ArrayRef/FieldStore子表达式时计算旧的数组元素/片.     * 通过CaseTest机制访问Value     */    EEOP_ARRAYREF_OLD,    /* compute new value for ArrayRef assignment expression */    //为ArrayRef分配118    EEOP_ARRAYREF_ASSIGN,    /* compute element/slice for ArrayRef fetch expression */    //为ArrayRef提取表达式计算element/slice    EEOP_ARRAYREF_FETCH,    /* evaluate value for CoerceToDomainValue */    //为CoerceToDomainValue解析值    EEOP_DOMAIN_TESTVAL,    /* evaluate a domain's NOT NULL constraint */    //解析域 NOT NULL 约束    EEOP_DOMAIN_NOTNULL,    /* evaluate a single domain CHECK constraint */    //解析单个域CHECK约束    EEOP_DOMAIN_CHECK,    /* evaluate assorted special-purpose expression types */    //解析特殊目的的表达式类型    EEOP_CONVERT_ROWTYPE,    EEOP_SCALARARRAYOP,    EEOP_XMLEXPR,    EEOP_AGGREF,    EEOP_GROUPING_FUNC,    EEOP_WINDOW_FUNC,    EEOP_SUBPLAN,    EEOP_ALTERNATIVE_SUBPLAN,    /* aggregation related nodes */    //聚合相关节点    EEOP_AGG_STRICT_DESERIALIZE,    EEOP_AGG_DESERIALIZE,    EEOP_AGG_STRICT_INPUT_CHECK,    EEOP_AGG_INIT_TRANS,    EEOP_AGG_STRICT_TRANS_CHECK,    EEOP_AGG_PLAIN_TRANS_BYVAL,    EEOP_AGG_PLAIN_TRANS,    EEOP_AGG_ORDERED_TRANS_DATUM,    EEOP_AGG_ORDERED_TRANS_TUPLE,    /* non-existent operation, used e.g. to check array lengths */    //不存在的操作,比如用于检测数组长度    EEOP_LAST} ExprEvalOp;

二、源码解读

ExecInitExprRec函数,把表达式解析需要的步骤追加到ExprState->steps中,可能会递归进入到子表达式节点中.
其主要逻辑是根据节点类型,执行相应的处理逻辑,比如节点类型为OpExpr,则其逻辑为:

case T_OpExpr://操作符表达式            {                OpExpr     *op = (OpExpr *) node;                ExecInitFunc(&scratch, node,                             op->args, op->opfuncid, op->inputcollid,                             state);                ExprEvalPushStep(state, &scratch);                break;            }

其他节点类型类似,代码虽然很长,但逻辑清晰简单.

/* * Append the steps necessary for the evaluation of node to ExprState->steps, * possibly recursing into sub-expressions of node. * 把表达式解析需要的步骤追加到ExprState->steps中,可能会递归进入到子表达式节点中. * * node - expression to evaluate * state - ExprState to whose ->steps to append the necessary operations * resv / resnull - where to store the result of the node into * node - 待解析的表达式 * state - 步骤追加到该ExprState ->steps中 * resv / resnull - 节点结果存储的位置 */static voidExecInitExprRec(Expr *node, ExprState *state,                Datum *resv, bool *resnull){    ExprEvalStep scratch = {0};    /* Guard against stack overflow due to overly complex expressions */    //避免出现堆栈溢出    check_stack_depth();    /* Step's output location is always what the caller gave us */    //步骤的输出位置往往是调用者提供给我们的    Assert(resv != NULL && resnull != NULL);    scratch.resvalue = resv;    scratch.resnull = resnull;    /* cases should be ordered as they are in enum NodeTag */    //CASE的顺序与NodeTag枚举类型中的顺序一样    switch (nodeTag(node))    {        case T_Var://VAR            {                Var        *variable = (Var *) node;                if (variable->varattno == InvalidAttrNumber)                {                    /* whole-row Var */                    ExecInitWholeRowVar(&scratch, variable, state);                }                else if (variable->varattno <= 0)                {                    /* system column */                    scratch.d.var.attnum = variable->varattno;                    scratch.d.var.vartype = variable->vartype;                    switch (variable->varno)                    {                        case INNER_VAR:                            scratch.opcode = EEOP_INNER_SYSVAR;                            break;                        case OUTER_VAR:                            scratch.opcode = EEOP_OUTER_SYSVAR;                            break;                            /* INDEX_VAR is handled by default case */                        default:                            scratch.opcode = EEOP_SCAN_SYSVAR;                            break;                    }                }                else                {                    /* regular user column */                    scratch.d.var.attnum = variable->varattno - 1;                    scratch.d.var.vartype = variable->vartype;                    switch (variable->varno)                    {                        case INNER_VAR:                            scratch.opcode = EEOP_INNER_VAR;                            break;                        case OUTER_VAR:                            scratch.opcode = EEOP_OUTER_VAR;                            break;                            /* INDEX_VAR is handled by default case */                        default:                            scratch.opcode = EEOP_SCAN_VAR;                            break;                    }                }                ExprEvalPushStep(state, &scratch);                break;            }        case T_Const://常量            {                Const      *con = (Const *) node;                scratch.opcode = EEOP_CONST;                scratch.d.constval.value = con->constvalue;                scratch.d.constval.isnull = con->constisnull;                ExprEvalPushStep(state, &scratch);                break;            }        case T_Param://参数            {                Param      *param = (Param *) node;                ParamListInfo params;                switch (param->paramkind)                {                    case PARAM_EXEC:                        scratch.opcode = EEOP_PARAM_EXEC;                        scratch.d.param.paramid = param->paramid;                        scratch.d.param.paramtype = param->paramtype;                        ExprEvalPushStep(state, &scratch);                        break;                    case PARAM_EXTERN:                        /*                         * If we have a relevant ParamCompileHook, use it;                         * otherwise compile a standard EEOP_PARAM_EXTERN                         * step.  ext_params, if supplied, takes precedence                         * over info from the parent node's EState (if any).                         */                        if (state->ext_params)                            params = state->ext_params;                        else if (state->parent &&                                 state->parent->state)                            params = state->parent->state->es_param_list_info;                        else                            params = NULL;                        if (params && params->paramCompile)                        {                            params->paramCompile(params, param, state,                                                 resv, resnull);                        }                        else                        {                            scratch.opcode = EEOP_PARAM_EXTERN;                            scratch.d.param.paramid = param->paramid;                            scratch.d.param.paramtype = param->paramtype;                            ExprEvalPushStep(state, &scratch);                        }                        break;                    default:                        elog(ERROR, "unrecognized paramkind: %d",                             (int) param->paramkind);                        break;                }                break;            }        case T_Aggref://聚集            {                Aggref     *aggref = (Aggref *) node;                AggrefExprState *astate = makeNode(AggrefExprState);                scratch.opcode = EEOP_AGGREF;                scratch.d.aggref.astate = astate;                astate->aggref = aggref;                if (state->parent && IsA(state->parent, AggState))                {                    AggState   *aggstate = (AggState *) state->parent;                    aggstate->aggs = lcons(astate, aggstate->aggs);                    aggstate->numaggs++;                }                else                {                    /* planner messed up */                    elog(ERROR, "Aggref found in non-Agg plan node");                }                ExprEvalPushStep(state, &scratch);                break;            }        case T_GroupingFunc:            {                GroupingFunc *grp_node = (GroupingFunc *) node;                Agg        *agg;                if (!state->parent || !IsA(state->parent, AggState) ||                    !IsA(state->parent->plan, Agg))                    elog(ERROR, "GroupingFunc found in non-Agg plan node");                scratch.opcode = EEOP_GROUPING_FUNC;                scratch.d.grouping_func.parent = (AggState *) state->parent;                agg = (Agg *) (state->parent->plan);                if (agg->groupingSets)                    scratch.d.grouping_func.clauses = grp_node->cols;                else                    scratch.d.grouping_func.clauses = NIL;                ExprEvalPushStep(state, &scratch);                break;            }        case T_WindowFunc:            {                WindowFunc *wfunc = (WindowFunc *) node;                WindowFuncExprState *wfstate = makeNode(WindowFuncExprState);                wfstate->wfunc = wfunc;                if (state->parent && IsA(state->parent, WindowAggState))                {                    WindowAggState *winstate = (WindowAggState *) state->parent;                    int         nfuncs;                    winstate->funcs = lcons(wfstate, winstate->funcs);                    nfuncs = ++winstate->numfuncs;                    if (wfunc->winagg)                        winstate->numaggs++;                    /* for now initialize agg using old style expressions */                    wfstate->args = ExecInitExprList(wfunc->args,                                                     state->parent);                    wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter,                                                      state->parent);                    /*                     * Complain if the windowfunc's arguments contain any                     * windowfuncs; nested window functions are semantically                     * nonsensical.  (This should have been caught earlier,                     * but we defend against it here anyway.)                     */                    if (nfuncs != winstate->numfuncs)                        ereport(ERROR,                                (errcode(ERRCODE_WINDOWING_ERROR),                                 errmsg("window function calls cannot be nested")));                }                else                {                    /* planner messed up */                    elog(ERROR, "WindowFunc found in non-WindowAgg plan node");                }                scratch.opcode = EEOP_WINDOW_FUNC;                scratch.d.window_func.wfstate = wfstate;                ExprEvalPushStep(state, &scratch);                break;            }        case T_ArrayRef:            {                ArrayRef   *aref = (ArrayRef *) node;                ExecInitArrayRef(&scratch, aref, state, resv, resnull);                break;            }        case T_FuncExpr://函数表达式            {                FuncExpr   *func = (FuncExpr *) node;                ExecInitFunc(&scratch, node,                             func->args, func->funcid, func->inputcollid,                             state);                ExprEvalPushStep(state, &scratch);                break;            }        case T_OpExpr://操作符表达式            {                OpExpr     *op = (OpExpr *) node;                ExecInitFunc(&scratch, node,                             op->args, op->opfuncid, op->inputcollid,                             state);                ExprEvalPushStep(state, &scratch);                break;            }        case T_DistinctExpr:            {                DistinctExpr *op = (DistinctExpr *) node;                ExecInitFunc(&scratch, node,                             op->args, op->opfuncid, op->inputcollid,                             state);                /*                 * Change opcode of call instruction to EEOP_DISTINCT.                 *                 * XXX: historically we've not called the function usage                 * pgstat infrastructure - that seems inconsistent given that                 * we do so for normal function *and* operator evaluation.  If                 * we decided to do that here, we'd probably want separate                 * opcodes for FUSAGE or not.                 */                scratch.opcode = EEOP_DISTINCT;                ExprEvalPushStep(state, &scratch);                break;            }        case T_NullIfExpr:            {                NullIfExpr *op = (NullIfExpr *) node;                ExecInitFunc(&scratch, node,                             op->args, op->opfuncid, op->inputcollid,                             state);                /*                 * Change opcode of call instruction to EEOP_NULLIF.                 *                 * XXX: historically we've not called the function usage                 * pgstat infrastructure - that seems inconsistent given that                 * we do so for normal function *and* operator evaluation.  If                 * we decided to do that here, we'd probably want separate                 * opcodes for FUSAGE or not.                 */                scratch.opcode = EEOP_NULLIF;                ExprEvalPushStep(state, &scratch);                break;            }        case T_ScalarArrayOpExpr:            {                ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;                Expr       *scalararg;                Expr       *arrayarg;                FmgrInfo   *finfo;                FunctionCallInfo fcinfo;                AclResult   aclresult;                Assert(list_length(opexpr->args) == 2);                scalararg = (Expr *) linitial(opexpr->args);                arrayarg = (Expr *) lsecond(opexpr->args);                /* Check permission to call function */                aclresult = pg_proc_aclcheck(opexpr->opfuncid,                                             GetUserId(),                                             ACL_EXECUTE);                if (aclresult != ACLCHECK_OK)                    aclcheck_error(aclresult, OBJECT_FUNCTION,                                   get_func_name(opexpr->opfuncid));                InvokeFunctionExecuteHook(opexpr->opfuncid);                /* Set up the primary fmgr lookup information */                finfo = palloc0(sizeof(FmgrInfo));                fcinfo = palloc0(sizeof(FunctionCallInfoData));                fmgr_info(opexpr->opfuncid, finfo);                fmgr_info_set_expr((Node *) node, finfo);                InitFunctionCallInfoData(*fcinfo, finfo, 2,                                         opexpr->inputcollid, NULL, NULL);                /* Evaluate scalar directly into left function argument */                ExecInitExprRec(scalararg, state,                                &fcinfo->arg[0], &fcinfo->argnull[0]);                /*                 * Evaluate array argument into our return value.  There's no                 * danger in that, because the return value is guaranteed to                 * be overwritten by EEOP_SCALARARRAYOP, and will not be                 * passed to any other expression.                 */                ExecInitExprRec(arrayarg, state, resv, resnull);                /* And perform the operation */                scratch.opcode = EEOP_SCALARARRAYOP;                scratch.d.scalararrayop.element_type = InvalidOid;                scratch.d.scalararrayop.useOr = opexpr->useOr;                scratch.d.scalararrayop.finfo = finfo;                scratch.d.scalararrayop.fcinfo_data = fcinfo;                scratch.d.scalararrayop.fn_addr = finfo->fn_addr;                ExprEvalPushStep(state, &scratch);                break;            }        case T_BoolExpr:            {                BoolExpr   *boolexpr = (BoolExpr *) node;                int         nargs = list_length(boolexpr->args);                List       *adjust_jumps = NIL;                int         off;                ListCell   *lc;                /* allocate scratch memory used by all steps of AND/OR */                if (boolexpr->boolop != NOT_EXPR)                    scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool));                /*                 * For each argument evaluate the argument itself, then                 * perform the bool operation's appropriate handling.                 *                 * We can evaluate each argument into our result area, since                 * the short-circuiting logic means we only need to remember                 * previous NULL values.                 *                 * AND/OR is split into separate STEP_FIRST (one) / STEP (zero                 * or more) / STEP_LAST (one) steps, as each of those has to                 * perform different work.  The FIRST/LAST split is valid                 * because AND/OR have at least two arguments.                 */                off = 0;                foreach(lc, boolexpr->args)                {                    Expr       *arg = (Expr *) lfirst(lc);                    /* Evaluate argument into our output variable */                    ExecInitExprRec(arg, state, resv, resnull);                    /* Perform the appropriate step type */                    switch (boolexpr->boolop)                    {                        case AND_EXPR:                            Assert(nargs >= 2);                            if (off == 0)                                scratch.opcode = EEOP_BOOL_AND_STEP_FIRST;                            else if (off + 1 == nargs)                                scratch.opcode = EEOP_BOOL_AND_STEP_LAST;                            else                                scratch.opcode = EEOP_BOOL_AND_STEP;                            break;                        case OR_EXPR:                            Assert(nargs >= 2);                            if (off == 0)                                scratch.opcode = EEOP_BOOL_OR_STEP_FIRST;                            else if (off + 1 == nargs)                                scratch.opcode = EEOP_BOOL_OR_STEP_LAST;                            else                                scratch.opcode = EEOP_BOOL_OR_STEP;                            break;                        case NOT_EXPR:                            Assert(nargs == 1);                            scratch.opcode = EEOP_BOOL_NOT_STEP;                            break;                        default:                            elog(ERROR, "unrecognized boolop: %d",                                 (int) boolexpr->boolop);                            break;                    }                    scratch.d.boolexpr.jumpdone = -1;                    ExprEvalPushStep(state, &scratch);                    adjust_jumps = lappend_int(adjust_jumps,                                               state->steps_len - 1);                    off++;                }                /* adjust jump targets */                foreach(lc, adjust_jumps)                {                    ExprEvalStep *as = &state->steps[lfirst_int(lc)];                    Assert(as->d.boolexpr.jumpdone == -1);                    as->d.boolexpr.jumpdone = state->steps_len;                }                break;            }        case T_SubPlan:            {                SubPlan    *subplan = (SubPlan *) node;                SubPlanState *sstate;                if (!state->parent)                    elog(ERROR, "SubPlan found with no parent plan");                sstate = ExecInitSubPlan(subplan, state->parent);                /* add SubPlanState nodes to state->parent->subPlan */                state->parent->subPlan = lappend(state->parent->subPlan,                                                 sstate);                scratch.opcode = EEOP_SUBPLAN;                scratch.d.subplan.sstate = sstate;                ExprEvalPushStep(state, &scratch);                break;            }        case T_AlternativeSubPlan:            {                AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;                AlternativeSubPlanState *asstate;                if (!state->parent)                    elog(ERROR, "AlternativeSubPlan found with no parent plan");                asstate = ExecInitAlternativeSubPlan(asplan, state->parent);                scratch.opcode = EEOP_ALTERNATIVE_SUBPLAN;                scratch.d.alternative_subplan.asstate = asstate;                ExprEvalPushStep(state, &scratch);                break;            }        case T_FieldSelect:            {                FieldSelect *fselect = (FieldSelect *) node;                /* evaluate row/record argument into result area */                ExecInitExprRec(fselect->arg, state, resv, resnull);                /* and extract field */                scratch.opcode = EEOP_FIELDSELECT;                scratch.d.fieldselect.fieldnum = fselect->fieldnum;                scratch.d.fieldselect.resulttype = fselect->resulttype;                scratch.d.fieldselect.argdesc = NULL;                ExprEvalPushStep(state, &scratch);                break;            }        case T_FieldStore:            {                FieldStore *fstore = (FieldStore *) node;                TupleDesc   tupDesc;                TupleDesc  *descp;                Datum      *values;                bool       *nulls;                int         ncolumns;                ListCell   *l1,                           *l2;                /* find out the number of columns in the composite type */                tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1);                ncolumns = tupDesc->natts;                DecrTupleDescRefCount(tupDesc);                /* create workspace for column values */                values = (Datum *) palloc(sizeof(Datum) * ncolumns);                nulls = (bool *) palloc(sizeof(bool) * ncolumns);                /* create workspace for runtime tupdesc cache */                descp = (TupleDesc *) palloc(sizeof(TupleDesc));                *descp = NULL;                /* emit code to evaluate the composite input value */                ExecInitExprRec(fstore->arg, state, resv, resnull);                /* next, deform the input tuple into our workspace */                scratch.opcode = EEOP_FIELDSTORE_DEFORM;                scratch.d.fieldstore.fstore = fstore;                scratch.d.fieldstore.argdesc = descp;                scratch.d.fieldstore.values = values;                scratch.d.fieldstore.nulls = nulls;                scratch.d.fieldstore.ncolumns = ncolumns;                ExprEvalPushStep(state, &scratch);                /* evaluate new field values, store in workspace columns */                forboth(l1, fstore->newvals, l2, fstore->fieldnums)                {                    Expr       *e = (Expr *) lfirst(l1);                    AttrNumber  fieldnum = lfirst_int(l2);                    Datum      *save_innermost_caseval;                    bool       *save_innermost_casenull;                    if (fieldnum <= 0 || fieldnum > ncolumns)                        elog(ERROR, "field number %d is out of range in FieldStore",                             fieldnum);                    /*                     * Use the CaseTestExpr mechanism to pass down the old                     * value of the field being replaced; this is needed in                     * case the newval is itself a FieldStore or ArrayRef that                     * has to obtain and modify the old value.  It's safe to                     * reuse the CASE mechanism because there cannot be a CASE                     * between here and where the value would be needed, and a                     * field assignment can't be within a CASE either.  (So                     * saving and restoring innermost_caseval is just                     * paranoia, but let's do it anyway.)                     *                     * Another non-obvious point is that it's safe to use the                     * field's values[]/nulls[] entries as both the caseval                     * source and the result address for this subexpression.                     * That's okay only because (1) both FieldStore and                     * ArrayRef evaluate their arg or refexpr inputs first,                     * and (2) any such CaseTestExpr is directly the arg or                     * refexpr input.  So any read of the caseval will occur                     * before there's a chance to overwrite it.  Also, if                     * multiple entries in the newvals/fieldnums lists target                     * the same field, they'll effectively be applied                     * left-to-right which is what we want.                     */                    save_innermost_caseval = state->innermost_caseval;                    save_innermost_casenull = state->innermost_casenull;                    state->innermost_caseval = &values[fieldnum - 1];                    state->innermost_casenull = &nulls[fieldnum - 1];                    ExecInitExprRec(e, state,                                    &values[fieldnum - 1],                                    &nulls[fieldnum - 1]);                    state->innermost_caseval = save_innermost_caseval;                    state->innermost_casenull = save_innermost_casenull;                }                /* finally, form result tuple */                scratch.opcode = EEOP_FIELDSTORE_FORM;                scratch.d.fieldstore.fstore = fstore;                scratch.d.fieldstore.argdesc = descp;                scratch.d.fieldstore.values = values;                scratch.d.fieldstore.nulls = nulls;                scratch.d.fieldstore.ncolumns = ncolumns;                ExprEvalPushStep(state, &scratch);                break;            }        case T_RelabelType:            {                /* relabel doesn't need to do anything at runtime */                RelabelType *relabel = (RelabelType *) node;                ExecInitExprRec(relabel->arg, state, resv, resnull);                break;            }        case T_CoerceViaIO:            {                CoerceViaIO *iocoerce = (CoerceViaIO *) node;                Oid         iofunc;                bool        typisvarlena;                Oid         typioparam;                FunctionCallInfo fcinfo_in;                /* evaluate argument into step's result area */                ExecInitExprRec(iocoerce->arg, state, resv, resnull);                /*                 * Prepare both output and input function calls, to be                 * evaluated inside a single evaluation step for speed - this                 * can be a very common operation.                 *                 * We don't check permissions here as a type's input/output                 * function are assumed to be executable by everyone.                 */                scratch.opcode = EEOP_IOCOERCE;                /* lookup the source type's output function */                scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));                scratch.d.iocoerce.fcinfo_data_out = palloc0(sizeof(FunctionCallInfoData));                getTypeOutputInfo(exprType((Node *) iocoerce->arg),                                  &iofunc, &typisvarlena);                fmgr_info(iofunc, scratch.d.iocoerce.finfo_out);                fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out);                InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out,                                         scratch.d.iocoerce.finfo_out,                                         1, InvalidOid, NULL, NULL);                /* lookup the result type's input function */                scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));                scratch.d.iocoerce.fcinfo_data_in = palloc0(sizeof(FunctionCallInfoData));                getTypeInputInfo(iocoerce->resulttype,                                 &iofunc, &typioparam);                fmgr_info(iofunc, scratch.d.iocoerce.finfo_in);                fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in);                InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in,                                         scratch.d.iocoerce.finfo_in,                                         3, InvalidOid, NULL, NULL);                /*                 * We can preload the second and third arguments for the input                 * function, since they're constants.                 */                fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;                fcinfo_in->arg[1] = ObjectIdGetDatum(typioparam);                fcinfo_in->argnull[1] = false;                fcinfo_in->arg[2] = Int32GetDatum(-1);                fcinfo_in->argnull[2] = false;                ExprEvalPushStep(state, &scratch);                break;            }        case T_ArrayCoerceExpr:            {                ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;                Oid         resultelemtype;                ExprState  *elemstate;                /* evaluate argument into step's result area */                ExecInitExprRec(acoerce->arg, state, resv, resnull);                resultelemtype = get_element_type(acoerce->resulttype);                if (!OidIsValid(resultelemtype))                    ereport(ERROR,                            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),                             errmsg("target type is not an array")));                /*                 * Construct a sub-expression for the per-element expression;                 * but don't ready it until after we check it for triviality.                 * We assume it hasn't any Var references, but does have a                 * CaseTestExpr representing the source array element values.                 */                elemstate = makeNode(ExprState);                elemstate->expr = acoerce->elemexpr;                elemstate->parent = state->parent;                elemstate->ext_params = state->ext_params;                elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum));                elemstate->innermost_casenull = (bool *) palloc(sizeof(bool));                ExecInitExprRec(acoerce->elemexpr, elemstate,                                &elemstate->resvalue, &elemstate->resnull);                if (elemstate->steps_len == 1 &&                    elemstate->steps[0].opcode == EEOP_CASE_TESTVAL)                {                    /* Trivial, so we need no per-element work at runtime */                    elemstate = NULL;                }                else                {                    /* Not trivial, so append a DONE step */                    scratch.opcode = EEOP_DONE;                    ExprEvalPushStep(elemstate, &scratch);                    /* and ready the subexpression */                    ExecReadyExpr(elemstate);                }                scratch.opcode = EEOP_ARRAYCOERCE;                scratch.d.arraycoerce.elemexprstate = elemstate;                scratch.d.arraycoerce.resultelemtype = resultelemtype;                if (elemstate)                {                    /* Set up workspace for array_map */                    scratch.d.arraycoerce.amstate =                        (ArrayMapState *) palloc0(sizeof(ArrayMapState));                }                else                {                    /* Don't need workspace if there's no subexpression */                    scratch.d.arraycoerce.amstate = NULL;                }                ExprEvalPushStep(state, &scratch);                break;            }        case T_ConvertRowtypeExpr:            {                ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;                /* evaluate argument into step's result area */                ExecInitExprRec(convert->arg, state, resv, resnull);                /* and push conversion step */                scratch.opcode = EEOP_CONVERT_ROWTYPE;                scratch.d.convert_rowtype.convert = convert;                scratch.d.convert_rowtype.indesc = NULL;                scratch.d.convert_rowtype.outdesc = NULL;                scratch.d.convert_rowtype.map = NULL;                scratch.d.convert_rowtype.initialized = false;                ExprEvalPushStep(state, &scratch);                break;            }            /* note that CaseWhen expressions are handled within this block */        case T_CaseExpr:            {                CaseExpr   *caseExpr = (CaseExpr *) node;                List       *adjust_jumps = NIL;                Datum      *caseval = NULL;                bool       *casenull = NULL;                ListCell   *lc;                /*                 * If there's a test expression, we have to evaluate it and                 * save the value where the CaseTestExpr placeholders can find                 * it.                 */                if (caseExpr->arg != NULL)                {                    /* Evaluate testexpr into caseval/casenull workspace */                    caseval = palloc(sizeof(Datum));                    casenull = palloc(sizeof(bool));                    ExecInitExprRec(caseExpr->arg, state,                                    caseval, casenull);                    /*                     * Since value might be read multiple times, force to R/O                     * - but only if it could be an expanded datum.                     */                    if (get_typlen(exprType((Node *) caseExpr->arg)) == -1)                    {                        /* change caseval in-place */                        scratch.opcode = EEOP_MAKE_READONLY;                        scratch.resvalue = caseval;                        scratch.resnull = casenull;                        scratch.d.make_readonly.value = caseval;                        scratch.d.make_readonly.isnull = casenull;                        ExprEvalPushStep(state, &scratch);                        /* restore normal settings of scratch fields */                        scratch.resvalue = resv;                        scratch.resnull = resnull;                    }                }                /*                 * Prepare to evaluate each of the WHEN clauses in turn; as                 * soon as one is true we return the value of the                 * corresponding THEN clause.  If none are true then we return                 * the value of the ELSE clause, or NULL if there is none.                 */                foreach(lc, caseExpr->args)                {                    CaseWhen   *when = (CaseWhen *) lfirst(lc);                    Datum      *save_innermost_caseval;                    bool       *save_innermost_casenull;                    int         whenstep;                    /*                     * Make testexpr result available to CaseTestExpr nodes                     * within the condition.  We must save and restore prior                     * setting of innermost_caseval fields, in case this node                     * is itself within a larger CASE.                     *                     * If there's no test expression, we don't actually need                     * to save and restore these fields; but it's less code to                     * just do so unconditionally.                     */                    save_innermost_caseval = state->innermost_caseval;                    save_innermost_casenull = state->innermost_casenull;                    state->innermost_caseval = caseval;                    state->innermost_casenull = casenull;                    /* evaluate condition into CASE's result variables */                    ExecInitExprRec(when->expr, state, resv, resnull);                    state->innermost_caseval = save_innermost_caseval;                    state->innermost_casenull = save_innermost_casenull;                    /* If WHEN result isn't true, jump to next CASE arm */                    scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;                    scratch.d.jump.jumpdone = -1;   /* computed later */                    ExprEvalPushStep(state, &scratch);                    whenstep = state->steps_len - 1;                    /*                     * If WHEN result is true, evaluate THEN result, storing                     * it into the CASE's result variables.                     */                    ExecInitExprRec(when->result, state, resv, resnull);                    /* Emit JUMP step to jump to end of CASE's code */                    scratch.opcode = EEOP_JUMP;                    scratch.d.jump.jumpdone = -1;   /* computed later */                    ExprEvalPushStep(state, &scratch);                    /*                     * Don't know address for that jump yet, compute once the                     * whole CASE expression is built.                     */                    adjust_jumps = lappend_int(adjust_jumps,                                               state->steps_len - 1);                    /*                     * But we can set WHEN test's jump target now, to make it                     * jump to the next WHEN subexpression or the ELSE.                     */                    state->steps[whenstep].d.jump.jumpdone = state->steps_len;                }                /* transformCaseExpr always adds a default */                Assert(caseExpr->defresult);                /* evaluate ELSE expr into CASE's result variables */                ExecInitExprRec(caseExpr->defresult, state,                                resv, resnull);                /* adjust jump targets */                foreach(lc, adjust_jumps)                {                    ExprEvalStep *as = &state->steps[lfirst_int(lc)];                    Assert(as->opcode == EEOP_JUMP);                    Assert(as->d.jump.jumpdone == -1);                    as->d.jump.jumpdone = state->steps_len;                }                break;            }        case T_CaseTestExpr:            {                /*                 * Read from location identified by innermost_caseval.  Note                 * that innermost_caseval could be NULL, if this node isn't                 * actually within a CaseExpr, ArrayCoerceExpr, etc structure.                 * That can happen because some parts of the system abuse                 * CaseTestExpr to cause a read of a value externally supplied                 * in econtext->caseValue_datum.  We'll take care of that                 * scenario at runtime.                 */                scratch.opcode = EEOP_CASE_TESTVAL;                scratch.d.casetest.value = state->innermost_caseval;                scratch.d.casetest.isnull = state->innermost_casenull;                ExprEvalPushStep(state, &scratch);                break;            }        case T_ArrayExpr:            {                ArrayExpr  *arrayexpr = (ArrayExpr *) node;                int         nelems = list_length(arrayexpr->elements);                ListCell   *lc;                int         elemoff;                /*                 * Evaluate by computing each element, and then forming the                 * array.  Elements are computed into scratch arrays                 * associated with the ARRAYEXPR step.                 */                scratch.opcode = EEOP_ARRAYEXPR;                scratch.d.arrayexpr.elemvalues =                    (Datum *) palloc(sizeof(Datum) * nelems);                scratch.d.arrayexpr.elemnulls =                    (bool *) palloc(sizeof(bool) * nelems);                scratch.d.arrayexpr.nelems = nelems;                /* fill remaining fields of step */                scratch.d.arrayexpr.multidims = arrayexpr->multidims;                scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid;                /* do one-time catalog lookup for type info */                get_typlenbyvalalign(arrayexpr->element_typeid,                                     &scratch.d.arrayexpr.elemlength,                                     &scratch.d.arrayexpr.elembyval,                                     &scratch.d.arrayexpr.elemalign);                /* prepare to evaluate all arguments */                elemoff = 0;                foreach(lc, arrayexpr->elements)                {                    Expr       *e = (Expr *) lfirst(lc);                    ExecInitExprRec(e, state,                                    &scratch.d.arrayexpr.elemvalues[elemoff],                                    &scratch.d.arrayexpr.elemnulls[elemoff]);                    elemoff++;                }                /* and then collect all into an array */                ExprEvalPushStep(state, &scratch);                break;            }        case T_RowExpr:            {                RowExpr    *rowexpr = (RowExpr *) node;                int         nelems = list_length(rowexpr->args);                TupleDesc   tupdesc;                int         i;                ListCell   *l;                /* Build tupdesc to describe result tuples */                if (rowexpr->row_typeid == RECORDOID)                {                    /* generic record, use types of given expressions */                    tupdesc = ExecTypeFromExprList(rowexpr->args);                }                else                {                    /* it's been cast to a named type, use that */                    tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1);                }                /* In either case, adopt RowExpr's column aliases */                ExecTypeSetColNames(tupdesc, rowexpr->colnames);                /* Bless the tupdesc in case it's now of type RECORD */                BlessTupleDesc(tupdesc);                /*                 * In the named-type case, the tupdesc could have more columns                 * than are in the args list, since the type might have had                 * columns added since the ROW() was parsed.  We want those                 * extra columns to go to nulls, so we make sure that the                 * workspace arrays are large enough and then initialize any                 * extra columns to read as NULLs.                 */                Assert(nelems <= tupdesc->natts);                nelems = Max(nelems, tupdesc->natts);                /*                 * Evaluate by first building datums for each field, and then                 * a final step forming the composite datum.                 */                scratch.opcode = EEOP_ROW;                scratch.d.row.tupdesc = tupdesc;                /* space for the individual field datums */                scratch.d.row.elemvalues =                    (Datum *) palloc(sizeof(Datum) * nelems);                scratch.d.row.elemnulls =                    (bool *) palloc(sizeof(bool) * nelems);                /* as explained above, make sure any extra columns are null */                memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems);                /* Set up evaluation, skipping any deleted columns */                i = 0;                foreach(l, rowexpr->args)                {                    Form_pg_attribute att = TupleDescAttr(tupdesc, i);                    Expr       *e = (Expr *) lfirst(l);                    if (!att->attisdropped)                    {                        /*                         * Guard against ALTER COLUMN TYPE on rowtype since                         * the RowExpr was created.  XXX should we check                         * typmod too?  Not sure we can be sure it'll be the                         * same.                         */                        if (exprType((Node *) e) != att->atttypid)                            ereport(ERROR,                                    (errcode(ERRCODE_DATATYPE_MISMATCH),                                     errmsg("ROW() column has type %s instead of type %s",                                            format_type_be(exprType((Node *) e)),                                            format_type_be(att->atttypid))));                    }                    else                    {                        /*                         * Ignore original expression and insert a NULL. We                         * don't really care what type of NULL it is, so                         * always make an int4 NULL.                         */                        e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid);                    }                    /* Evaluate column expr into appropriate workspace slot */                    ExecInitExprRec(e, state,                                    &scratch.d.row.elemvalues[i],                                    &scratch.d.row.elemnulls[i]);                    i++;                }                /* And finally build the row value */                ExprEvalPushStep(state, &scratch);                break;            }        case T_RowCompareExpr:            {                RowCompareExpr *rcexpr = (RowCompareExpr *) node;                int         nopers = list_length(rcexpr->opnos);                List       *adjust_jumps = NIL;                ListCell   *l_left_expr,                           *l_right_expr,                           *l_opno,                           *l_opfamily,                           *l_inputcollid;                ListCell   *lc;                int         off;                /*                 * Iterate over each field, prepare comparisons.  To handle                 * NULL results, prepare jumps to after the expression.  If a                 * comparison yields a != 0 result, jump to the final step.                 */                Assert(list_length(rcexpr->largs) == nopers);                Assert(list_length(rcexpr->rargs) == nopers);                Assert(list_length(rcexpr->opfamilies) == nopers);                Assert(list_length(rcexpr->inputcollids) == nopers);                off = 0;                for (off = 0,                     l_left_expr = list_head(rcexpr->largs),                     l_right_expr = list_head(rcexpr->rargs),                     l_opno = list_head(rcexpr->opnos),                     l_opfamily = list_head(rcexpr->opfamilies),                     l_inputcollid = list_head(rcexpr->inputcollids);                     off < nopers;                     off++,                     l_left_expr = lnext(l_left_expr),                     l_right_expr = lnext(l_right_expr),                     l_opno = lnext(l_opno),                     l_opfamily = lnext(l_opfamily),                     l_inputcollid = lnext(l_inputcollid))                {                    Expr       *left_expr = (Expr *) lfirst(l_left_expr);                    Expr       *right_expr = (Expr *) lfirst(l_right_expr);                    Oid         opno = lfirst_oid(l_opno);                    Oid         opfamily = lfirst_oid(l_opfamily);                    Oid         inputcollid = lfirst_oid(l_inputcollid);                    int         strategy;                    Oid         lefttype;                    Oid         righttype;                    Oid         proc;                    FmgrInfo   *finfo;                    FunctionCallInfo fcinfo;                    get_op_opfamily_properties(opno, opfamily, false,                                               &strategy,                                               &lefttype,                                               &righttype);                    proc = get_opfamily_proc(opfamily,                                             lefttype,                                             righttype,                                             BTORDER_PROC);                    if (!OidIsValid(proc))                        elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",                             BTORDER_PROC, lefttype, righttype, opfamily);                    /* Set up the primary fmgr lookup information */                    finfo = palloc0(sizeof(FmgrInfo));                    fcinfo = palloc0(sizeof(FunctionCallInfoData));                    fmgr_info(proc, finfo);                    fmgr_info_set_expr((Node *) node, finfo);                    InitFunctionCallInfoData(*fcinfo, finfo, 2,                                             inputcollid, NULL, NULL);                    /*                     * If we enforced permissions checks on index support                     * functions, we'd need to make a check here.  But the                     * index support machinery doesn't do that, and thus                     * neither does this code.                     */                    /* evaluate left and right args directly into fcinfo */                    ExecInitExprRec(left_expr, state,                                    &fcinfo->arg[0], &fcinfo->argnull[0]);                    ExecInitExprRec(right_expr, state,                                    &fcinfo->arg[1], &fcinfo->argnull[1]);                    scratch.opcode = EEOP_ROWCOMPARE_STEP;                    scratch.d.rowcompare_step.finfo = finfo;                    scratch.d.rowcompare_step.fcinfo_data = fcinfo;                    scratch.d.rowcompare_step.fn_addr = finfo->fn_addr;                    /* jump targets filled below */                    scratch.d.rowcompare_step.jumpnull = -1;                    scratch.d.rowcompare_step.jumpdone = -1;                    ExprEvalPushStep(state, &scratch);                    adjust_jumps = lappend_int(adjust_jumps,                                               state->steps_len - 1);                }                /*                 * We could have a zero-column rowtype, in which case the rows                 * necessarily compare equal.                 */                if (nopers == 0)                {                    scratch.opcode = EEOP_CONST;                    scratch.d.constval.value = Int32GetDatum(0);                    scratch.d.constval.isnull = false;                    ExprEvalPushStep(state, &scratch);                }                /* Finally, examine the last comparison result */                scratch.opcode = EEOP_ROWCOMPARE_FINAL;                scratch.d.rowcompare_final.rctype = rcexpr->rctype;                ExprEvalPushStep(state, &scratch);                /* adjust jump targetss */                foreach(lc, adjust_jumps)                {                    ExprEvalStep *as = &state->steps[lfirst_int(lc)];                    Assert(as->opcode == EEOP_ROWCOMPARE_STEP);                    Assert(as->d.rowcompare_step.jumpdone == -1);                    Assert(as->d.rowcompare_step.jumpnull == -1);                    /* jump to comparison evaluation */                    as->d.rowcompare_step.jumpdone = state->steps_len - 1;                    /* jump to the following expression */                    as->d.rowcompare_step.jumpnull = state->steps_len;                }                break;            }        case T_CoalesceExpr:            {                CoalesceExpr *coalesce = (CoalesceExpr *) node;                List       *adjust_jumps = NIL;                ListCell   *lc;                /* We assume there's at least one arg */                Assert(coalesce->args != NIL);                /*                 * Prepare evaluation of all coalesced arguments, after each                 * one push a step that short-circuits if not null.                 */                foreach(lc, coalesce->args)                {                    Expr       *e = (Expr *) lfirst(lc);                    /* evaluate argument, directly into result datum */                    ExecInitExprRec(e, state, resv, resnull);                    /* if it's not null, skip to end of COALESCE expr */                    scratch.opcode = EEOP_JUMP_IF_NOT_NULL;                    scratch.d.jump.jumpdone = -1;   /* adjust later */                    ExprEvalPushStep(state, &scratch);                    adjust_jumps = lappend_int(adjust_jumps,                                               state->steps_len - 1);                }                /*                 * No need to add a constant NULL return - we only can get to                 * the end of the expression if a NULL already is being                 * returned.                 */                /* adjust jump targets */                foreach(lc, adjust_jumps)                {                    ExprEvalStep *as = &state->steps[lfirst_int(lc)];                    Assert(as->opcode == EEOP_JUMP_IF_NOT_NULL);                    Assert(as->d.jump.jumpdone == -1);                    as->d.jump.jumpdone = state->steps_len;                }                break;            }        case T_MinMaxExpr:            {                MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;                int         nelems = list_length(minmaxexpr->args);                TypeCacheEntry *typentry;                FmgrInfo   *finfo;                FunctionCallInfo fcinfo;                ListCell   *lc;                int         off;                /* Look up the btree comparison function for the datatype */                typentry = lookup_type_cache(minmaxexpr->minmaxtype,                                             TYPECACHE_CMP_PROC);                if (!OidIsValid(typentry->cmp_proc))                    ereport(ERROR,                            (errcode(ERRCODE_UNDEFINED_FUNCTION),                             errmsg("could not identify a comparison function for type %s",                                    format_type_be(minmaxexpr->minmaxtype))));                /*                 * If we enforced permissions checks on index support                 * functions, we'd need to make a check here.  But the index                 * support machinery doesn't do that, and thus neither does                 * this code.                 */                /* Perform function lookup */                finfo = palloc0(sizeof(FmgrInfo));                fcinfo = palloc0(sizeof(FunctionCallInfoData));                fmgr_info(typentry->cmp_proc, finfo);                fmgr_info_set_expr((Node *) node, finfo);                InitFunctionCallInfoData(*fcinfo, finfo, 2,                                         minmaxexpr->inputcollid, NULL, NULL);                scratch.opcode = EEOP_MINMAX;                /* allocate space to store arguments */                scratch.d.minmax.values =                    (Datum *) palloc(sizeof(Datum) * nelems);                scratch.d.minmax.nulls =                    (bool *) palloc(sizeof(bool) * nelems);                scratch.d.minmax.nelems = nelems;                scratch.d.minmax.op = minmaxexpr->op;                scratch.d.minmax.finfo = finfo;                scratch.d.minmax.fcinfo_data = fcinfo;                /* evaluate expressions into minmax->values/nulls */                off = 0;                foreach(lc, minmaxexpr->args)                {                    Expr       *e = (Expr *) lfirst(lc);                    ExecInitExprRec(e, state,                                    &scratch.d.minmax.values[off],                                    &scratch.d.minmax.nulls[off]);                    off++;                }                /* and push the final comparison */                ExprEvalPushStep(state, &scratch);                break;            }        case T_SQLValueFunction:            {                SQLValueFunction *svf = (SQLValueFunction *) node;                scratch.opcode = EEOP_SQLVALUEFUNCTION;                scratch.d.sqlvaluefunction.svf = svf;                ExprEvalPushStep(state, &scratch);                break;            }        case T_XmlExpr:            {                XmlExpr    *xexpr = (XmlExpr *) node;                int         nnamed = list_length(xexpr->named_args);                int         nargs = list_length(xexpr->args);                int         off;                ListCell   *arg;                scratch.opcode = EEOP_XMLEXPR;                scratch.d.xmlexpr.xexpr = xexpr;                /* allocate space for storing all the arguments */                if (nnamed)                {                    scratch.d.xmlexpr.named_argvalue =                        (Datum *) palloc(sizeof(Datum) * nnamed);                    scratch.d.xmlexpr.named_argnull =                        (bool *) palloc(sizeof(bool) * nnamed);                }                else                {                    scratch.d.xmlexpr.named_argvalue = NULL;                    scratch.d.xmlexpr.named_argnull = NULL;                }                if (nargs)                {                    scratch.d.xmlexpr.argvalue =                        (Datum *) palloc(sizeof(Datum) * nargs);                    scratch.d.xmlexpr.argnull =                        (bool *) palloc(sizeof(bool) * nargs);                }                else                {                    scratch.d.xmlexpr.argvalue = NULL;                    scratch.d.xmlexpr.argnull = NULL;                }                /* prepare argument execution */                off = 0;                foreach(arg, xexpr->named_args)                {                    Expr       *e = (Expr *) lfirst(arg);                    ExecInitExprRec(e, state,                                    &scratch.d.xmlexpr.named_argvalue[off],                                    &scratch.d.xmlexpr.named_argnull[off]);                    off++;                }                off = 0;                foreach(arg, xexpr->args)                {                    Expr       *e = (Expr *) lfirst(arg);                    ExecInitExprRec(e, state,                                    &scratch.d.xmlexpr.argvalue[off],                                    &scratch.d.xmlexpr.argnull[off]);                    off++;                }                /* and evaluate the actual XML expression */                ExprEvalPushStep(state, &scratch);                break;            }        case T_NullTest:            {                NullTest   *ntest = (NullTest *) node;                if (ntest->nulltesttype == IS_NULL)                {                    if (ntest->argisrow)                        scratch.opcode = EEOP_NULLTEST_ROWISNULL;                    else                        scratch.opcode = EEOP_NULLTEST_ISNULL;                }                else if (ntest->nulltesttype == IS_NOT_NULL)                {                    if (ntest->argisrow)                        scratch.opcode = EEOP_NULLTEST_ROWISNOTNULL;                    else                        scratch.opcode = EEOP_NULLTEST_ISNOTNULL;                }                else                {                    elog(ERROR, "unrecognized nulltesttype: %d",                         (int) ntest->nulltesttype);                }                /* initialize cache in case it's a row test */                scratch.d.nulltest_row.argdesc = NULL;                /* first evaluate argument into result variable */                ExecInitExprRec(ntest->arg, state,                                resv, resnull);                /* then push the test of that argument */                ExprEvalPushStep(state, &scratch);                break;            }        case T_BooleanTest:            {                BooleanTest *btest = (BooleanTest *) node;                /*                 * Evaluate argument, directly into result datum.  That's ok,                 * because resv/resnull is definitely not used anywhere else,                 * and will get overwritten by the below EEOP_BOOLTEST_IS_*                 * step.                 */                ExecInitExprRec(btest->arg, state, resv, resnull);                switch (btest->booltesttype)                {                    case IS_TRUE:                        scratch.opcode = EEOP_BOOLTEST_IS_TRUE;                        break;                    case IS_NOT_TRUE:                        scratch.opcode = EEOP_BOOLTEST_IS_NOT_TRUE;                        break;                    case IS_FALSE:                        scratch.opcode = EEOP_BOOLTEST_IS_FALSE;                        break;                    case IS_NOT_FALSE:                        scratch.opcode = EEOP_BOOLTEST_IS_NOT_FALSE;                        break;                    case IS_UNKNOWN:                        /* Same as scalar IS NULL test */                        scratch.opcode = EEOP_NULLTEST_ISNULL;                        break;                    case IS_NOT_UNKNOWN:                        /* Same as scalar IS NOT NULL test */                        scratch.opcode = EEOP_NULLTEST_ISNOTNULL;                        break;                    default:                        elog(ERROR, "unrecognized booltesttype: %d",                             (int) btest->booltesttype);                }                ExprEvalPushStep(state, &scratch);                break;            }        case T_CoerceToDomain:            {                CoerceToDomain *ctest = (CoerceToDomain *) node;                ExecInitCoerceToDomain(&scratch, ctest, state,                                       resv, resnull);                break;            }        case T_CoerceToDomainValue:            {                /*                 * Read from location identified by innermost_domainval.  Note                 * that innermost_domainval could be NULL, if we're compiling                 * a standalone domain check rather than one embedded in a                 * larger expression.  In that case we must read from                 * econtext->domainValue_datum.  We'll take care of that                 * scenario at runtime.                 */                scratch.opcode = EEOP_DOMAIN_TESTVAL;                /* we share instruction union variant with case testval */                scratch.d.casetest.value = state->innermost_domainval;                scratch.d.casetest.isnull = state->innermost_domainnull;                ExprEvalPushStep(state, &scratch);                break;            }        case T_CurrentOfExpr:            {                scratch.opcode = EEOP_CURRENTOFEXPR;                ExprEvalPushStep(state, &scratch);                break;            }        case T_NextValueExpr:            {                NextValueExpr *nve = (NextValueExpr *) node;                scratch.opcode = EEOP_NEXTVALUEEXPR;                scratch.d.nextvalueexpr.seqid = nve->seqid;                scratch.d.nextvalueexpr.seqtypid = nve->typeId;                ExprEvalPushStep(state, &scratch);                break;            }        default:            elog(ERROR, "unrecognized node type: %d",                 (int) nodeTag(node));            break;    }}/* * Add another expression evaluation step to ExprState->steps. * 添加表达式解析步骤到ExprState->steps数组中. * * Note that this potentially re-allocates es->steps, therefore no pointer * into that array may be used while the expression is still being built. */voidExprEvalPushStep(ExprState *es, const ExprEvalStep *s){    if (es->steps_alloc == 0)    {        es->steps_alloc = 16;        es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);    }    else if (es->steps_alloc == es->steps_len)    {        es->steps_alloc *= 2;        es->steps = repalloc(es->steps,                             sizeof(ExprEvalStep) * es->steps_alloc);    }    memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));}

三、跟踪分析

测试脚本

testdb=# select 1+id,c2 from t_expr where id < 3;

进入ExecInitExprRec,Node节点为OpExpr,执行ExprEvalPushStep压入步骤中

(gdb) stepExecInitExprRec (node=0x1c9a930, state=0x1c8f7d8, resv=0x1c8f7e0, resnull=0x1c8f7dd) at execExpr.c:645645     ExprEvalStep scratch = {0};(gdb) n648     check_stack_depth();(gdb) 651     Assert(resv != NULL && resnull != NULL);(gdb) 652     scratch.resvalue = resv;(gdb) 653     scratch.resnull = resnull;(gdb) 656     switch (nodeTag(node))(gdb) 891                 OpExpr     *op = (OpExpr *) node;(gdb) p *node$16 = {type = T_OpExpr}(gdb) n893                 ExecInitFunc(&scratch, node,(gdb) 896                 ExprEvalPushStep(state, &scratch);(gdb) 897                 break;(gdb) 2122    }(gdb)

到此,相信大家对"怎么使用PostgreSQL中ExecInitExprRec函数"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0