温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么使用PostgreSQL中ExecInitExprRec函数

发布时间:2021-11-09 14:40:31 来源:亿速云 阅读:627 作者:iii 栏目:关系型数据库

本篇内容主要讲解“怎么使用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 void ExecInitExprRec(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.  */ void ExprEvalPushStep(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) step ExecInitExprRec (node=0x1c9a930, state=0x1c8f7d8, resv=0x1c8f7e0, resnull=0x1c8f7dd) at execExpr.c:645 645     ExprEvalStep scratch = {0}; (gdb) n 648     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) n 893                 ExecInitFunc(&scratch, node, (gdb)  896                 ExprEvalPushStep(state, &scratch); (gdb)  897                 break; (gdb)  2122    } (gdb)

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

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI