千家信息网

​PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值

发表于:2024-11-27 作者:千家信息网编辑
千家信息网最后更新 2024年11月27日,这篇文章主要介绍PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!表达式列是指除关系定义中的系统列/定义列之外的其
千家信息网最后更新 2024年11月27日​PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值

这篇文章主要介绍PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

表达式列是指除关系定义中的系统列/定义列之外的其他投影列.比如:

testdb=# create table t_expr(id int);CREATE TABLEtestdb=# insert into t_expr values(1);INSERT 0 1testdb=# insert into t_expr values(2);INSERT 0 1testdb=# alter table t_expr add column c2 varchar(20);ALTER TABLEtestdb=# insert into t_expr(id,c2) select x,'c2'||x from generate_series(3,100000) as x;INSERT 0 99998testdb=# select 1+id from t_expr;

该SQL语句中的"1+id"投影列视为表达式列.

一、数据结构

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;

二、源码解读

ExecInterpExpr函数是实现表达式列解析的主函数,解析给定"econtext"在执行上下文中通过"state"标识的表达式.
其主要实现逻辑是根据ExprState->opcode(ExprState的初始化后续再行介绍)指定的操作指定,调整到相应的实现逻辑中,执行完毕调到下一个步骤直至到达EEOP_DONE,即完成所有步骤.

/* * Evaluate expression identified by "state" in the execution context * given by "econtext".  *isnull is set to the is-null flag for the result, * and the Datum value is the function result. * 解析给定"econtext"在执行上下文中通过"state"标识的表达式. * *isnull用于设置结果是否为null,Datum是函数执行的结果. * * As a special case, return the dispatch table's address if state is NULL. * This is used by ExecInitInterpreter to set up the dispatch_table global. * (Only applies when EEO_USE_COMPUTED_GOTO is defined.) * 作为一个特别的情况,如state为NULL,返回分发器表的地址. * 这个情况用于ExecInitInterpreter配置dispatch_table. * (只是在定义了EEO_USE_COMPUTED_GOTO时才应用) */static DatumExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull){    ExprEvalStep *op;    TupleTableSlot *resultslot;    TupleTableSlot *innerslot;    TupleTableSlot *outerslot;    TupleTableSlot *scanslot;    /*     * This array has to be in the same order as enum ExprEvalOp.     * 该数组在枚举类型ExprEvalOp中具有同样的顺序     */#if defined(EEO_USE_COMPUTED_GOTO)    static const void *const dispatch_table[] = {        &&CASE_EEOP_DONE,        &&CASE_EEOP_INNER_FETCHSOME,        &&CASE_EEOP_OUTER_FETCHSOME,        &&CASE_EEOP_SCAN_FETCHSOME,        &&CASE_EEOP_INNER_VAR,        &&CASE_EEOP_OUTER_VAR,        &&CASE_EEOP_SCAN_VAR,        &&CASE_EEOP_INNER_SYSVAR,        &&CASE_EEOP_OUTER_SYSVAR,        &&CASE_EEOP_SCAN_SYSVAR,        &&CASE_EEOP_WHOLEROW,        &&CASE_EEOP_ASSIGN_INNER_VAR,        &&CASE_EEOP_ASSIGN_OUTER_VAR,        &&CASE_EEOP_ASSIGN_SCAN_VAR,        &&CASE_EEOP_ASSIGN_TMP,        &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,        &&CASE_EEOP_CONST,        &&CASE_EEOP_FUNCEXPR,        &&CASE_EEOP_FUNCEXPR_STRICT,        &&CASE_EEOP_FUNCEXPR_FUSAGE,        &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,        &&CASE_EEOP_BOOL_AND_STEP_FIRST,        &&CASE_EEOP_BOOL_AND_STEP,        &&CASE_EEOP_BOOL_AND_STEP_LAST,        &&CASE_EEOP_BOOL_OR_STEP_FIRST,        &&CASE_EEOP_BOOL_OR_STEP,        &&CASE_EEOP_BOOL_OR_STEP_LAST,        &&CASE_EEOP_BOOL_NOT_STEP,        &&CASE_EEOP_QUAL,        &&CASE_EEOP_JUMP,        &&CASE_EEOP_JUMP_IF_NULL,        &&CASE_EEOP_JUMP_IF_NOT_NULL,        &&CASE_EEOP_JUMP_IF_NOT_TRUE,        &&CASE_EEOP_NULLTEST_ISNULL,        &&CASE_EEOP_NULLTEST_ISNOTNULL,        &&CASE_EEOP_NULLTEST_ROWISNULL,        &&CASE_EEOP_NULLTEST_ROWISNOTNULL,        &&CASE_EEOP_BOOLTEST_IS_TRUE,        &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,        &&CASE_EEOP_BOOLTEST_IS_FALSE,        &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,        &&CASE_EEOP_PARAM_EXEC,        &&CASE_EEOP_PARAM_EXTERN,        &&CASE_EEOP_PARAM_CALLBACK,        &&CASE_EEOP_CASE_TESTVAL,        &&CASE_EEOP_MAKE_READONLY,        &&CASE_EEOP_IOCOERCE,        &&CASE_EEOP_DISTINCT,        &&CASE_EEOP_NOT_DISTINCT,        &&CASE_EEOP_NULLIF,        &&CASE_EEOP_SQLVALUEFUNCTION,        &&CASE_EEOP_CURRENTOFEXPR,        &&CASE_EEOP_NEXTVALUEEXPR,        &&CASE_EEOP_ARRAYEXPR,        &&CASE_EEOP_ARRAYCOERCE,        &&CASE_EEOP_ROW,        &&CASE_EEOP_ROWCOMPARE_STEP,        &&CASE_EEOP_ROWCOMPARE_FINAL,        &&CASE_EEOP_MINMAX,        &&CASE_EEOP_FIELDSELECT,        &&CASE_EEOP_FIELDSTORE_DEFORM,        &&CASE_EEOP_FIELDSTORE_FORM,        &&CASE_EEOP_ARRAYREF_SUBSCRIPT,        &&CASE_EEOP_ARRAYREF_OLD,        &&CASE_EEOP_ARRAYREF_ASSIGN,        &&CASE_EEOP_ARRAYREF_FETCH,        &&CASE_EEOP_DOMAIN_TESTVAL,        &&CASE_EEOP_DOMAIN_NOTNULL,        &&CASE_EEOP_DOMAIN_CHECK,        &&CASE_EEOP_CONVERT_ROWTYPE,        &&CASE_EEOP_SCALARARRAYOP,        &&CASE_EEOP_XMLEXPR,        &&CASE_EEOP_AGGREF,        &&CASE_EEOP_GROUPING_FUNC,        &&CASE_EEOP_WINDOW_FUNC,        &&CASE_EEOP_SUBPLAN,        &&CASE_EEOP_ALTERNATIVE_SUBPLAN,        &&CASE_EEOP_AGG_STRICT_DESERIALIZE,        &&CASE_EEOP_AGG_DESERIALIZE,        &&CASE_EEOP_AGG_STRICT_INPUT_CHECK,        &&CASE_EEOP_AGG_INIT_TRANS,        &&CASE_EEOP_AGG_STRICT_TRANS_CHECK,        &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,        &&CASE_EEOP_AGG_PLAIN_TRANS,        &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,        &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,        &&CASE_EEOP_LAST    };    StaticAssertStmt(EEOP_LAST + 1 == lengthof(dispatch_table),                     "dispatch_table out of whack with ExprEvalOp");    if (unlikely(state == NULL))        //如state == NULL,则调用PointerGetDatum        return PointerGetDatum(dispatch_table);#else    Assert(state != NULL);#endif                          /* EEO_USE_COMPUTED_GOTO */    /* setup state */    //配置状态变量    op = state->steps;    resultslot = state->resultslot;    innerslot = econtext->ecxt_innertuple;    outerslot = econtext->ecxt_outertuple;    scanslot = econtext->ecxt_scantuple;#if defined(EEO_USE_COMPUTED_GOTO)    EEO_DISPATCH();//分发#endif    EEO_SWITCH()    {        EEO_CASE(EEOP_DONE)        {            goto out;        }        EEO_CASE(EEOP_INNER_FETCHSOME)        {            /* XXX: worthwhile to check tts_nvalid inline first? */            slot_getsomeattrs(innerslot, op->d.fetch.last_var);            EEO_NEXT();        }        EEO_CASE(EEOP_OUTER_FETCHSOME)        {            slot_getsomeattrs(outerslot, op->d.fetch.last_var);            EEO_NEXT();        }        EEO_CASE(EEOP_SCAN_FETCHSOME)        {            slot_getsomeattrs(scanslot, op->d.fetch.last_var);            EEO_NEXT();        }        EEO_CASE(EEOP_INNER_VAR)        {            int         attnum = op->d.var.attnum;            /*             * Since we already extracted all referenced columns from the             * tuple with a FETCHSOME step, we can just grab the value             * directly out of the slot's decomposed-data arrays.  But let's             * have an Assert to check that that did happen.             */            Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);            *op->resvalue = innerslot->tts_values[attnum];            *op->resnull = innerslot->tts_isnull[attnum];            EEO_NEXT();        }        EEO_CASE(EEOP_OUTER_VAR)        {            int         attnum = op->d.var.attnum;            /* See EEOP_INNER_VAR comments */            Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);            *op->resvalue = outerslot->tts_values[attnum];            *op->resnull = outerslot->tts_isnull[attnum];            EEO_NEXT();        }        EEO_CASE(EEOP_SCAN_VAR)        {            int         attnum = op->d.var.attnum;            /* See EEOP_INNER_VAR comments */            Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);            *op->resvalue = scanslot->tts_values[attnum];            *op->resnull = scanslot->tts_isnull[attnum];            EEO_NEXT();        }        EEO_CASE(EEOP_INNER_SYSVAR)        {            int         attnum = op->d.var.attnum;            Datum       d;            /* these asserts must match defenses in slot_getattr */            Assert(innerslot->tts_tuple != NULL);            Assert(innerslot->tts_tuple != &(innerslot->tts_minhdr));            /* heap_getsysattr has sufficient defenses against bad attnums */            d = heap_getsysattr(innerslot->tts_tuple, attnum,                                innerslot->tts_tupleDescriptor,                                op->resnull);            *op->resvalue = d;            EEO_NEXT();        }        EEO_CASE(EEOP_OUTER_SYSVAR)        {            int         attnum = op->d.var.attnum;            Datum       d;            /* these asserts must match defenses in slot_getattr */            Assert(outerslot->tts_tuple != NULL);            Assert(outerslot->tts_tuple != &(outerslot->tts_minhdr));            /* heap_getsysattr has sufficient defenses against bad attnums */            d = heap_getsysattr(outerslot->tts_tuple, attnum,                                outerslot->tts_tupleDescriptor,                                op->resnull);            *op->resvalue = d;            EEO_NEXT();        }        EEO_CASE(EEOP_SCAN_SYSVAR)        {            int         attnum = op->d.var.attnum;            Datum       d;            /* these asserts must match defenses in slot_getattr */            Assert(scanslot->tts_tuple != NULL);            Assert(scanslot->tts_tuple != &(scanslot->tts_minhdr));            /* heap_getsysattr has sufficient defenses against bad attnums */            d = heap_getsysattr(scanslot->tts_tuple, attnum,                                scanslot->tts_tupleDescriptor,                                op->resnull);            *op->resvalue = d;            EEO_NEXT();        }        EEO_CASE(EEOP_WHOLEROW)        {            /* too complex for an inline implementation */            ExecEvalWholeRowVar(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_ASSIGN_INNER_VAR)        {            int         resultnum = op->d.assign_var.resultnum;            int         attnum = op->d.assign_var.attnum;            /*             * We do not need CheckVarSlotCompatibility here; that was taken             * care of at compilation time.  But see EEOP_INNER_VAR comments.             */            Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);            resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];            resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];            EEO_NEXT();        }        EEO_CASE(EEOP_ASSIGN_OUTER_VAR)        {            int         resultnum = op->d.assign_var.resultnum;            int         attnum = op->d.assign_var.attnum;            /*             * We do not need CheckVarSlotCompatibility here; that was taken             * care of at compilation time.  But see EEOP_INNER_VAR comments.             */            Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);            resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];            resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];            EEO_NEXT();        }        EEO_CASE(EEOP_ASSIGN_SCAN_VAR)        {            int         resultnum = op->d.assign_var.resultnum;            int         attnum = op->d.assign_var.attnum;            /*             * We do not need CheckVarSlotCompatibility here; that was taken             * care of at compilation time.  But see EEOP_INNER_VAR comments.             */            Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);            resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];            resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];            EEO_NEXT();        }        EEO_CASE(EEOP_ASSIGN_TMP)        {            int         resultnum = op->d.assign_tmp.resultnum;            resultslot->tts_values[resultnum] = state->resvalue;            resultslot->tts_isnull[resultnum] = state->resnull;            EEO_NEXT();        }        EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)        {            int         resultnum = op->d.assign_tmp.resultnum;            resultslot->tts_isnull[resultnum] = state->resnull;            if (!resultslot->tts_isnull[resultnum])                resultslot->tts_values[resultnum] =                    MakeExpandedObjectReadOnlyInternal(state->resvalue);            else                resultslot->tts_values[resultnum] = state->resvalue;            EEO_NEXT();        }        EEO_CASE(EEOP_CONST)        {            *op->resnull = op->d.constval.isnull;            *op->resvalue = op->d.constval.value;            EEO_NEXT();        }        /*         * Function-call implementations. Arguments have previously been         * evaluated directly into fcinfo->args.         *         * As both STRICT checks and function-usage are noticeable performance         * wise, and function calls are a very hot-path (they also back         * operators!), it's worth having so many separate opcodes.         *         * Note: the reason for using a temporary variable "d", here and in         * other places, is that some compilers think "*op->resvalue = f();"         * requires them to evaluate op->resvalue into a register before         * calling f(), just in case f() is able to modify op->resvalue         * somehow.  The extra line of code can save a useless register spill         * and reload across the function call.         */        EEO_CASE(EEOP_FUNCEXPR)        {            FunctionCallInfo fcinfo = op->d.func.fcinfo_data;            Datum       d;            fcinfo->isnull = false;            d = op->d.func.fn_addr(fcinfo);            *op->resvalue = d;            *op->resnull = fcinfo->isnull;            EEO_NEXT();        }        EEO_CASE(EEOP_FUNCEXPR_STRICT)        {            FunctionCallInfo fcinfo = op->d.func.fcinfo_data;            bool       *argnull = fcinfo->argnull;            int         argno;            Datum       d;            /* strict function, so check for NULL args */            for (argno = 0; argno < op->d.func.nargs; argno++)            {                if (argnull[argno])                {                    *op->resnull = true;                    goto strictfail;                }            }            fcinfo->isnull = false;            d = op->d.func.fn_addr(fcinfo);            *op->resvalue = d;            *op->resnull = fcinfo->isnull;    strictfail:            EEO_NEXT();        }        EEO_CASE(EEOP_FUNCEXPR_FUSAGE)        {            /* not common enough to inline */            ExecEvalFuncExprFusage(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)        {            /* not common enough to inline */            ExecEvalFuncExprStrictFusage(state, op, econtext);            EEO_NEXT();        }        /*         * If any of its clauses is FALSE, an AND's result is FALSE regardless         * of the states of the rest of the clauses, so we can stop evaluating         * and return FALSE immediately.  If none are FALSE and one or more is         * NULL, we return NULL; otherwise we return TRUE.  This makes sense         * when you interpret NULL as "don't know": perhaps one of the "don't         * knows" would have been FALSE if we'd known its value.  Only when         * all the inputs are known to be TRUE can we state confidently that         * the AND's result is TRUE.         */        EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)        {            *op->d.boolexpr.anynull = false;            /*             * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the             * same as EEOP_BOOL_AND_STEP - so fall through to that.             */            /* FALL THROUGH */        }        EEO_CASE(EEOP_BOOL_AND_STEP)        {            if (*op->resnull)            {                *op->d.boolexpr.anynull = true;            }            else if (!DatumGetBool(*op->resvalue))            {                /* result is already set to FALSE, need not change it */                /* bail out early */                EEO_JUMP(op->d.boolexpr.jumpdone);            }            EEO_NEXT();        }        EEO_CASE(EEOP_BOOL_AND_STEP_LAST)        {            if (*op->resnull)            {                /* result is already set to NULL, need not change it */            }            else if (!DatumGetBool(*op->resvalue))            {                /* result is already set to FALSE, need not change it */                /*                 * No point jumping early to jumpdone - would be same target                 * (as this is the last argument to the AND expression),                 * except more expensive.                 */            }            else if (*op->d.boolexpr.anynull)            {                *op->resvalue = (Datum) 0;                *op->resnull = true;            }            else            {                /* result is already set to TRUE, need not change it */            }            EEO_NEXT();        }        /*         * If any of its clauses is TRUE, an OR's result is TRUE regardless of         * the states of the rest of the clauses, so we can stop evaluating         * and return TRUE immediately.  If none are TRUE and one or more is         * NULL, we return NULL; otherwise we return FALSE.  This makes sense         * when you interpret NULL as "don't know": perhaps one of the "don't         * knows" would have been TRUE if we'd known its value.  Only when all         * the inputs are known to be FALSE can we state confidently that the         * OR's result is FALSE.         */        EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)        {            *op->d.boolexpr.anynull = false;            /*             * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same             * as EEOP_BOOL_OR_STEP - so fall through to that.             */            /* FALL THROUGH */        }        EEO_CASE(EEOP_BOOL_OR_STEP)        {            if (*op->resnull)            {                *op->d.boolexpr.anynull = true;            }            else if (DatumGetBool(*op->resvalue))            {                /* result is already set to TRUE, need not change it */                /* bail out early */                EEO_JUMP(op->d.boolexpr.jumpdone);            }            EEO_NEXT();        }        EEO_CASE(EEOP_BOOL_OR_STEP_LAST)        {            if (*op->resnull)            {                /* result is already set to NULL, need not change it */            }            else if (DatumGetBool(*op->resvalue))            {                /* result is already set to TRUE, need not change it */                /*                 * No point jumping to jumpdone - would be same target (as                 * this is the last argument to the AND expression), except                 * more expensive.                 */            }            else if (*op->d.boolexpr.anynull)            {                *op->resvalue = (Datum) 0;                *op->resnull = true;            }            else            {                /* result is already set to FALSE, need not change it */            }            EEO_NEXT();        }        EEO_CASE(EEOP_BOOL_NOT_STEP)        {            /*             * Evaluation of 'not' is simple... if expr is false, then return             * 'true' and vice versa.  It's safe to do this even on a             * nominally null value, so we ignore resnull; that means that             * NULL in produces NULL out, which is what we want.             */            *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));            EEO_NEXT();        }        EEO_CASE(EEOP_QUAL)        {            /* simplified version of BOOL_AND_STEP for use by ExecQual() */            /* If argument (also result) is false or null ... */            if (*op->resnull ||                !DatumGetBool(*op->resvalue))            {                /* ... bail out early, returning FALSE */                *op->resnull = false;                *op->resvalue = BoolGetDatum(false);                EEO_JUMP(op->d.qualexpr.jumpdone);            }            /*             * Otherwise, leave the TRUE value in place, in case this is the             * last qual.  Then, TRUE is the correct answer.             */            EEO_NEXT();        }        EEO_CASE(EEOP_JUMP)        {            /* Unconditionally jump to target step */            EEO_JUMP(op->d.jump.jumpdone);        }        EEO_CASE(EEOP_JUMP_IF_NULL)        {            /* Transfer control if current result is null */            if (*op->resnull)                EEO_JUMP(op->d.jump.jumpdone);            EEO_NEXT();        }        EEO_CASE(EEOP_JUMP_IF_NOT_NULL)        {            /* Transfer control if current result is non-null */            if (!*op->resnull)                EEO_JUMP(op->d.jump.jumpdone);            EEO_NEXT();        }        EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)        {            /* Transfer control if current result is null or false */            if (*op->resnull || !DatumGetBool(*op->resvalue))                EEO_JUMP(op->d.jump.jumpdone);            EEO_NEXT();        }        EEO_CASE(EEOP_NULLTEST_ISNULL)        {            *op->resvalue = BoolGetDatum(*op->resnull);            *op->resnull = false;            EEO_NEXT();        }        EEO_CASE(EEOP_NULLTEST_ISNOTNULL)        {            *op->resvalue = BoolGetDatum(!*op->resnull);            *op->resnull = false;            EEO_NEXT();        }        EEO_CASE(EEOP_NULLTEST_ROWISNULL)        {            /* out of line implementation: too large */            ExecEvalRowNull(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)        {            /* out of line implementation: too large */            ExecEvalRowNotNull(state, op, econtext);            EEO_NEXT();        }        /* BooleanTest implementations for all booltesttypes */        EEO_CASE(EEOP_BOOLTEST_IS_TRUE)        {            if (*op->resnull)            {                *op->resvalue = BoolGetDatum(false);                *op->resnull = false;            }            /* else, input value is the correct output as well */            EEO_NEXT();        }        EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE)        {            if (*op->resnull)            {                *op->resvalue = BoolGetDatum(true);                *op->resnull = false;            }            else                *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));            EEO_NEXT();        }        EEO_CASE(EEOP_BOOLTEST_IS_FALSE)        {            if (*op->resnull)            {                *op->resvalue = BoolGetDatum(false);                *op->resnull = false;            }            else                *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));            EEO_NEXT();        }        EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE)        {            if (*op->resnull)            {                *op->resvalue = BoolGetDatum(true);                *op->resnull = false;            }            /* else, input value is the correct output as well */            EEO_NEXT();        }        EEO_CASE(EEOP_PARAM_EXEC)        {            /* out of line implementation: too large */            ExecEvalParamExec(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_PARAM_EXTERN)        {            /* out of line implementation: too large */            ExecEvalParamExtern(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_PARAM_CALLBACK)        {            /* allow an extension module to supply a PARAM_EXTERN value */            op->d.cparam.paramfunc(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_CASE_TESTVAL)        {            /*             * Normally upper parts of the expression tree have setup the             * values to be returned here, but some parts of the system             * currently misuse {caseValue,domainValue}_{datum,isNull} to set             * run-time data.  So if no values have been set-up, use             * ExprContext's.  This isn't pretty, but also not *that* ugly,             * and this is unlikely to be performance sensitive enough to             * worry about an extra branch.             */            if (op->d.casetest.value)            {                *op->resvalue = *op->d.casetest.value;                *op->resnull = *op->d.casetest.isnull;            }            else            {                *op->resvalue = econtext->caseValue_datum;                *op->resnull = econtext->caseValue_isNull;            }            EEO_NEXT();        }        EEO_CASE(EEOP_DOMAIN_TESTVAL)        {            /*             * See EEOP_CASE_TESTVAL comment.             */            if (op->d.casetest.value)            {                *op->resvalue = *op->d.casetest.value;                *op->resnull = *op->d.casetest.isnull;            }            else            {                *op->resvalue = econtext->domainValue_datum;                *op->resnull = econtext->domainValue_isNull;            }            EEO_NEXT();        }        EEO_CASE(EEOP_MAKE_READONLY)        {            /*             * Force a varlena value that might be read multiple times to R/O             */            if (!*op->d.make_readonly.isnull)                *op->resvalue =                    MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);            *op->resnull = *op->d.make_readonly.isnull;            EEO_NEXT();        }        EEO_CASE(EEOP_IOCOERCE)        {            /*             * Evaluate a CoerceViaIO node.  This can be quite a hot path, so             * inline as much work as possible.  The source value is in our             * result variable.             */            char       *str;            /* call output function (similar to OutputFunctionCall) */            if (*op->resnull)            {                /* output functions are not called on nulls */                str = NULL;            }            else            {                FunctionCallInfo fcinfo_out;                fcinfo_out = op->d.iocoerce.fcinfo_data_out;                fcinfo_out->arg[0] = *op->resvalue;                fcinfo_out->argnull[0] = false;                fcinfo_out->isnull = false;                str = DatumGetCString(FunctionCallInvoke(fcinfo_out));                /* OutputFunctionCall assumes result isn't null */                Assert(!fcinfo_out->isnull);            }            /* call input function (similar to InputFunctionCall) */            if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)            {                FunctionCallInfo fcinfo_in;                Datum       d;                fcinfo_in = op->d.iocoerce.fcinfo_data_in;                fcinfo_in->arg[0] = PointerGetDatum(str);                fcinfo_in->argnull[0] = *op->resnull;                /* second and third arguments are already set up */                fcinfo_in->isnull = false;                d = FunctionCallInvoke(fcinfo_in);                *op->resvalue = d;                /* Should get null result if and only if str is NULL */                if (str == NULL)                {                    Assert(*op->resnull);                    Assert(fcinfo_in->isnull);                }                else                {                    Assert(!*op->resnull);                    Assert(!fcinfo_in->isnull);                }            }            EEO_NEXT();        }        EEO_CASE(EEOP_DISTINCT)        {            /*             * IS DISTINCT FROM must evaluate arguments (already done into             * fcinfo->arg/argnull) to determine whether they are NULL; if             * either is NULL then the result is determined.  If neither is             * NULL, then proceed to evaluate the comparison function, which             * is just the type's standard equality operator.  We need not             * care whether that function is strict.  Because the handling of             * nulls is different, we can't just reuse EEOP_FUNCEXPR.             */            FunctionCallInfo fcinfo = op->d.func.fcinfo_data;            /* check function arguments for NULLness */            if (fcinfo->argnull[0] && fcinfo->argnull[1])            {                /* Both NULL? Then is not distinct... */                *op->resvalue = BoolGetDatum(false);                *op->resnull = false;            }            else if (fcinfo->argnull[0] || fcinfo->argnull[1])            {                /* Only one is NULL? Then is distinct... */                *op->resvalue = BoolGetDatum(true);                *op->resnull = false;            }            else            {                /* Neither null, so apply the equality function */                Datum       eqresult;                fcinfo->isnull = false;                eqresult = op->d.func.fn_addr(fcinfo);                /* Must invert result of "="; safe to do even if null */                *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));                *op->resnull = fcinfo->isnull;            }            EEO_NEXT();        }        /* see EEOP_DISTINCT for comments, this is just inverted */        EEO_CASE(EEOP_NOT_DISTINCT)        {            FunctionCallInfo fcinfo = op->d.func.fcinfo_data;            if (fcinfo->argnull[0] && fcinfo->argnull[1])            {                *op->resvalue = BoolGetDatum(true);                *op->resnull = false;            }            else if (fcinfo->argnull[0] || fcinfo->argnull[1])            {                *op->resvalue = BoolGetDatum(false);                *op->resnull = false;            }            else            {                Datum       eqresult;                fcinfo->isnull = false;                eqresult = op->d.func.fn_addr(fcinfo);                *op->resvalue = eqresult;                *op->resnull = fcinfo->isnull;            }            EEO_NEXT();        }        EEO_CASE(EEOP_NULLIF)        {            /*             * The arguments are already evaluated into fcinfo->arg/argnull.             */            FunctionCallInfo fcinfo = op->d.func.fcinfo_data;            /* if either argument is NULL they can't be equal */            if (!fcinfo->argnull[0] && !fcinfo->argnull[1])            {                Datum       result;                fcinfo->isnull = false;                result = op->d.func.fn_addr(fcinfo);                /* if the arguments are equal return null */                if (!fcinfo->isnull && DatumGetBool(result))                {                    *op->resvalue = (Datum) 0;                    *op->resnull = true;                    EEO_NEXT();                }            }            /* Arguments aren't equal, so return the first one */            *op->resvalue = fcinfo->arg[0];            *op->resnull = fcinfo->argnull[0];            EEO_NEXT();        }        EEO_CASE(EEOP_SQLVALUEFUNCTION)        {            /*             * Doesn't seem worthwhile to have an inline implementation             * efficiency-wise.             */            ExecEvalSQLValueFunction(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_CURRENTOFEXPR)        {            /* error invocation uses space, and shouldn't ever occur */            ExecEvalCurrentOfExpr(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_NEXTVALUEEXPR)        {            /*             * Doesn't seem worthwhile to have an inline implementation             * efficiency-wise.             */            ExecEvalNextValueExpr(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_ARRAYEXPR)        {            /* too complex for an inline implementation */            ExecEvalArrayExpr(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_ARRAYCOERCE)        {            /* too complex for an inline implementation */            ExecEvalArrayCoerce(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_ROW)        {            /* too complex for an inline implementation */            ExecEvalRow(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_ROWCOMPARE_STEP)        {            FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;            Datum       d;            /* force NULL result if strict fn and NULL input */            if (op->d.rowcompare_step.finfo->fn_strict &&                (fcinfo->argnull[0] || fcinfo->argnull[1]))            {                *op->resnull = true;                EEO_JUMP(op->d.rowcompare_step.jumpnull);            }            /* Apply comparison function */            fcinfo->isnull = false;            d = op->d.rowcompare_step.fn_addr(fcinfo);            *op->resvalue = d;            /* force NULL result if NULL function result */            if (fcinfo->isnull)            {                *op->resnull = true;                EEO_JUMP(op->d.rowcompare_step.jumpnull);            }            *op->resnull = false;            /* If unequal, no need to compare remaining columns */            if (DatumGetInt32(*op->resvalue) != 0)            {                EEO_JUMP(op->d.rowcompare_step.jumpdone);            }            EEO_NEXT();        }        EEO_CASE(EEOP_ROWCOMPARE_FINAL)        {            int32       cmpresult = DatumGetInt32(*op->resvalue);            RowCompareType rctype = op->d.rowcompare_final.rctype;            *op->resnull = false;            switch (rctype)            {                    /* EQ and NE cases aren't allowed here */                case ROWCOMPARE_LT:                    *op->resvalue = BoolGetDatum(cmpresult < 0);                    break;                case ROWCOMPARE_LE:                    *op->resvalue = BoolGetDatum(cmpresult <= 0);                    break;                case ROWCOMPARE_GE:                    *op->resvalue = BoolGetDatum(cmpresult >= 0);                    break;                case ROWCOMPARE_GT:                    *op->resvalue = BoolGetDatum(cmpresult > 0);                    break;                default:                    Assert(false);                    break;            }            EEO_NEXT();        }        EEO_CASE(EEOP_MINMAX)        {            /* too complex for an inline implementation */            ExecEvalMinMax(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_FIELDSELECT)        {            /* too complex for an inline implementation */            ExecEvalFieldSelect(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_FIELDSTORE_DEFORM)        {            /* too complex for an inline implementation */            ExecEvalFieldStoreDeForm(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_FIELDSTORE_FORM)        {            /* too complex for an inline implementation */            ExecEvalFieldStoreForm(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT)        {            /* Process an array subscript */            /* too complex for an inline implementation */            if (ExecEvalArrayRefSubscript(state, op))            {                EEO_NEXT();            }            else            {                /* Subscript is null, short-circuit ArrayRef to NULL */                EEO_JUMP(op->d.arrayref_subscript.jumpdone);            }        }        EEO_CASE(EEOP_ARRAYREF_OLD)        {            /*             * Fetch the old value in an arrayref assignment, in case it's             * referenced (via a CaseTestExpr) inside the assignment             * expression.             */            /* too complex for an inline implementation */            ExecEvalArrayRefOld(state, op);            EEO_NEXT();        }        /*         * Perform ArrayRef assignment         */        EEO_CASE(EEOP_ARRAYREF_ASSIGN)        {            /* too complex for an inline implementation */            ExecEvalArrayRefAssign(state, op);            EEO_NEXT();        }        /*         * Fetch subset of an array.         */        EEO_CASE(EEOP_ARRAYREF_FETCH)        {            /* too complex for an inline implementation */            ExecEvalArrayRefFetch(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_CONVERT_ROWTYPE)        {            /* too complex for an inline implementation */            ExecEvalConvertRowtype(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_SCALARARRAYOP)        {            /* too complex for an inline implementation */            ExecEvalScalarArrayOp(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_DOMAIN_NOTNULL)        {            /* too complex for an inline implementation */            ExecEvalConstraintNotNull(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_DOMAIN_CHECK)        {            /* too complex for an inline implementation */            ExecEvalConstraintCheck(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_XMLEXPR)        {            /* too complex for an inline implementation */            ExecEvalXmlExpr(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_AGGREF)        {            /*             * Returns a Datum whose value is the precomputed aggregate value             * found in the given expression context.             */            AggrefExprState *aggref = op->d.aggref.astate;            Assert(econtext->ecxt_aggvalues != NULL);            *op->resvalue = econtext->ecxt_aggvalues[aggref->aggno];            *op->resnull = econtext->ecxt_aggnulls[aggref->aggno];            EEO_NEXT();        }        EEO_CASE(EEOP_GROUPING_FUNC)        {            /* too complex/uncommon for an inline implementation */            ExecEvalGroupingFunc(state, op);            EEO_NEXT();        }        EEO_CASE(EEOP_WINDOW_FUNC)        {            /*             * Like Aggref, just return a precomputed value from the econtext.             */            WindowFuncExprState *wfunc = op->d.window_func.wfstate;            Assert(econtext->ecxt_aggvalues != NULL);            *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];            *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];            EEO_NEXT();        }        EEO_CASE(EEOP_SUBPLAN)        {            /* too complex for an inline implementation */            ExecEvalSubPlan(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN)        {            /* too complex for an inline implementation */            ExecEvalAlternativeSubPlan(state, op, econtext);            EEO_NEXT();        }        /* evaluate a strict aggregate deserialization function */        EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)        {            bool       *argnull = op->d.agg_deserialize.fcinfo_data->argnull;            /* Don't call a strict deserialization function with NULL input */            if (argnull[0])                EEO_JUMP(op->d.agg_deserialize.jumpnull);            /* fallthrough */        }        /* evaluate aggregate deserialization function (non-strict portion) */        EEO_CASE(EEOP_AGG_DESERIALIZE)        {            FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;            AggState   *aggstate = op->d.agg_deserialize.aggstate;            MemoryContext oldContext;            /*             * We run the deserialization functions in per-input-tuple memory             * context.             */            oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);            fcinfo->isnull = false;            *op->resvalue = FunctionCallInvoke(fcinfo);            *op->resnull = fcinfo->isnull;            MemoryContextSwitchTo(oldContext);            EEO_NEXT();        }        /*         * Check that a strict aggregate transition / combination function's         * input is not NULL.         */        EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK)        {            int         argno;            bool       *nulls = op->d.agg_strict_input_check.nulls;            int         nargs = op->d.agg_strict_input_check.nargs;            for (argno = 0; argno < nargs; argno++)            {                if (nulls[argno])                    EEO_JUMP(op->d.agg_strict_input_check.jumpnull);            }            EEO_NEXT();        }        /*         * Initialize an aggregate's first value if necessary.         */        EEO_CASE(EEOP_AGG_INIT_TRANS)        {            AggState   *aggstate;            AggStatePerGroup pergroup;            aggstate = op->d.agg_init_trans.aggstate;            pergroup = &aggstate->all_pergroups                [op->d.agg_init_trans.setoff]                [op->d.agg_init_trans.transno];            /* If transValue has not yet been initialized, do so now. */            if (pergroup->noTransValue)            {                AggStatePerTrans pertrans = op->d.agg_init_trans.pertrans;                aggstate->curaggcontext = op->d.agg_init_trans.aggcontext;                aggstate->current_set = op->d.agg_init_trans.setno;                ExecAggInitGroup(aggstate, pertrans, pergroup);                /* copied trans value from input, done this round */                EEO_JUMP(op->d.agg_init_trans.jumpnull);            }            EEO_NEXT();        }        /* check that a strict aggregate's input isn't NULL */        EEO_CASE(EEOP_AGG_STRICT_TRANS_CHECK)        {            AggState   *aggstate;            AggStatePerGroup pergroup;            aggstate = op->d.agg_strict_trans_check.aggstate;            pergroup = &aggstate->all_pergroups                [op->d.agg_strict_trans_check.setoff]                [op->d.agg_strict_trans_check.transno];            if (unlikely(pergroup->transValueIsNull))                EEO_JUMP(op->d.agg_strict_trans_check.jumpnull);            EEO_NEXT();        }        /*         * Evaluate aggregate transition / combine function that has a         * by-value transition type. That's a seperate case from the         * by-reference implementation because it's a bit simpler.         */        EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)        {            AggState   *aggstate;            AggStatePerTrans pertrans;            AggStatePerGroup pergroup;            FunctionCallInfo fcinfo;            MemoryContext oldContext;            Datum       newVal;            aggstate = op->d.agg_trans.aggstate;            pertrans = op->d.agg_trans.pertrans;            pergroup = &aggstate->all_pergroups                [op->d.agg_trans.setoff]                [op->d.agg_trans.transno];            Assert(pertrans->transtypeByVal);            fcinfo = &pertrans->transfn_fcinfo;            /* cf. select_current_set() */            aggstate->curaggcontext = op->d.agg_trans.aggcontext;            aggstate->current_set = op->d.agg_trans.setno;            /* set up aggstate->curpertrans for AggGetAggref() */            aggstate->curpertrans = pertrans;            /* invoke transition function in per-tuple context */            oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);            fcinfo->arg[0] = pergroup->transValue;            fcinfo->argnull[0] = pergroup->transValueIsNull;            fcinfo->isnull = false; /* just in case transfn doesn't set it */            newVal = FunctionCallInvoke(fcinfo);            pergroup->transValue = newVal;            pergroup->transValueIsNull = fcinfo->isnull;            MemoryContextSwitchTo(oldContext);            EEO_NEXT();        }        /*         * Evaluate aggregate transition / combine function that has a         * by-reference transition type.         *         * Could optimize a bit further by splitting off by-reference         * fixed-length types, but currently that doesn't seem worth it.         */        EEO_CASE(EEOP_AGG_PLAIN_TRANS)        {            AggState   *aggstate;            AggStatePerTrans pertrans;            AggStatePerGroup pergroup;            FunctionCallInfo fcinfo;            MemoryContext oldContext;            Datum       newVal;            aggstate = op->d.agg_trans.aggstate;            pertrans = op->d.agg_trans.pertrans;            pergroup = &aggstate->all_pergroups                [op->d.agg_trans.setoff]                [op->d.agg_trans.transno];            Assert(!pertrans->transtypeByVal);            fcinfo = &pertrans->transfn_fcinfo;            /* cf. select_current_set() */            aggstate->curaggcontext = op->d.agg_trans.aggcontext;            aggstate->current_set = op->d.agg_trans.setno;            /* set up aggstate->curpertrans for AggGetAggref() */            aggstate->curpertrans = pertrans;            /* invoke transition function in per-tuple context */            oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);            fcinfo->arg[0] = pergroup->transValue;            fcinfo->argnull[0] = pergroup->transValueIsNull;            fcinfo->isnull = false; /* just in case transfn doesn't set it */            newVal = FunctionCallInvoke(fcinfo);            /*             * For pass-by-ref datatype, must copy the new value into             * aggcontext and free the prior transValue.  But if transfn             * returned a pointer to its first input, we don't need to do             * anything.  Also, if transfn returned a pointer to a R/W             * expanded object that is already a child of the aggcontext,             * assume we can adopt that value without copying it.             */            if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))                newVal = ExecAggTransReparent(aggstate, pertrans,                                              newVal, fcinfo->isnull,                                              pergroup->transValue,                                              pergroup->transValueIsNull);            pergroup->transValue = newVal;            pergroup->transValueIsNull = fcinfo->isnull;            MemoryContextSwitchTo(oldContext);            EEO_NEXT();        }        /* process single-column ordered aggregate datum */        EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM)        {            /* too complex for an inline implementation */            ExecEvalAggOrderedTransDatum(state, op, econtext);            EEO_NEXT();        }        /* process multi-column ordered aggregate tuple */        EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE)        {            /* too complex for an inline implementation */            ExecEvalAggOrderedTransTuple(state, op, econtext);            EEO_NEXT();        }        EEO_CASE(EEOP_LAST)        {            /* unreachable */            Assert(false);            goto out;        }    }out:    *isnull = state->resnull;    return state->resvalue;}

三、跟踪分析

测试脚本

testdb=# alter table t_expr add primary key(id);ALTER TABLEtestdb=# select 1+id from t_expr where id < 3;

调用栈

(gdb) bt#0  ExecInterpExpr (state=0x1e6baa8, econtext=0x1e6b6d8, isnull=0x7fffdbc3b877) at execExprInterp.c:402#1  0x00000000006cd7ed in ExecInterpExprStillValid (state=0x1e6baa8, econtext=0x1e6b6d8, isNull=0x7fffdbc3b877)    at execExprInterp.c:1786#2  0x00000000006e1f7f in ExecEvalExprSwitchContext (state=0x1e6baa8, econtext=0x1e6b6d8, isNull=0x7fffdbc3b877)    at ../../../src/include/executor/executor.h:313#3  0x00000000006e1fe8 in ExecProject (projInfo=0x1e6baa0) at ../../../src/include/executor/executor.h:347#4  0x00000000006e2358 in ExecScan (node=0x1e6b5c0, accessMtd=0x7103a9 , recheckMtd=0x710474 )    at execScan.c:201#5  0x00000000007104be in ExecSeqScan (pstate=0x1e6b5c0) at nodeSeqscan.c:129#6  0x00000000006e05bb in ExecProcNodeFirst (node=0x1e6b5c0) at execProcnode.c:445#7  0x00000000006d551e in ExecProcNode (node=0x1e6b5c0) at ../../../src/include/executor/executor.h:247#8  0x00000000006d7d56 in ExecutePlan (estate=0x1e6b3a8, planstate=0x1e6b5c0, use_parallel_mode=false,     operation=CMD_SELECT, sendTuples=true, numberTuples=0, direction=ForwardScanDirection, dest=0x1e5ff50,     execute_once=true) at execMain.c:1723#9  0x00000000006d5ae8 in standard_ExecutorRun (queryDesc=0x1da77e8, direction=ForwardScanDirection, count=0,     execute_once=true) at execMain.c:364#10 0x00000000006d5910 in ExecutorRun (queryDesc=0x1da77e8, direction=ForwardScanDirection, count=0, execute_once=true)    at execMain.c:307#11 0x00000000008c2206 in PortalRunSelect (portal=0x1df4608, forward=true, count=0, dest=0x1e5ff50) at pquery.c:932#12 0x00000000008c1ea4 in PortalRun (portal=0x1df4608, count=9223372036854775807, isTopLevel=true, run_once=true,     dest=0x1e5ff50, altdest=0x1e5ff50, completionTag=0x7fffdbc3bc20 "") at pquery.c:773#13 0x00000000008bbf06 in exec_simple_query (query_string=0x1d85d78 "select 1+id from t_expr;") at postgres.c:1145#14 0x00000000008c0191 in PostgresMain (argc=1, argv=0x1db3cd8, dbname=0x1db3b40 "testdb", username=0x1db3b20 "xdb")    at postgres.c:4182#15 0x000000000081e06c in BackendRun (port=0x1da7ae0) at postmaster.c:4361#16 0x000000000081d7df in BackendStartup (port=0x1da7ae0) at postmaster.c:4033#17 0x0000000000819bd9 in ServerLoop () at postmaster.c:1706---Type  to continue, or q  to quit---#18 0x000000000081948f in PostmasterMain (argc=1, argv=0x1d80a50) at postmaster.c:1379#19 0x0000000000742931 in main (argc=1, argv=0x1d80a50) at main.c:228

跟踪分析
进入ExecInterpExpr

Breakpoint 1, ExecInterpExpr (state=0x1e67678, econtext=0x1e672a8, isnull=0x7fffdbc3b897) at execExprInterp.c:402402     if (unlikely(state == NULL))(gdb) cContinuing.Breakpoint 1, ExecInterpExpr (state=0x1e67678, econtext=0x1e672a8, isnull=0x7fffdbc3b877) at execExprInterp.c:402402     if (unlikely(state == NULL))

获取步骤数组和相关的slot

(gdb) n409     op = state->steps;(gdb) 410     resultslot = state->resultslot;(gdb) 411     innerslot = econtext->ecxt_innertuple;(gdb) 412     outerslot = econtext->ecxt_outertuple;(gdb) p *econtext$21 = {type = T_ExprContext, ecxt_scantuple = 0x1e673a0, ecxt_innertuple = 0x0, ecxt_outertuple = 0x0,   ecxt_per_query_memory = 0x1e66e60, ecxt_per_tuple_memory = 0x1e6d290, ecxt_param_exec_vals = 0x0,   ecxt_param_list_info = 0x0, ecxt_aggvalues = 0x0, ecxt_aggnulls = 0x0, caseValue_datum = 0, caseValue_isNull = true,   domainValue_datum = 0, domainValue_isNull = true, ecxt_estate = 0x1e66f78, ecxt_callbacks = 0x0}(gdb) n413     scanslot = econtext->ecxt_scantuple;(gdb) (gdb) p *scanslot$22 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false,   tts_tuple = 0x1e683f0, tts_tupleDescriptor = 0x7fa4f307fab8, tts_mcxt = 0x1e66e60, tts_buffer = 98, tts_nvalid = 0,   tts_values = 0x1e67400, tts_isnull = 0x1e67408, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {        bi_hi = 0, bi_lo = 0}, ip_posid = 0}, t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true}

进行分发

416     EEO_DISPATCH();

首先是EEOP_SCAN_FETCHSOME(STEP 1),获取结果slot

(gdb) n443             slot_getsomeattrs(scanslot, op->d.fetch.last_var);(gdb) n445             EEO_NEXT();(gdb)

跳转到下一个步骤EEOP_SCAN_VAR(STEP 2),获取扫描获得的id列值

480             int         attnum = op->d.var.attnum;(gdb) 484             Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);(gdb) 485             *op->resvalue = scanslot->tts_values[attnum];(gdb) 486             *op->resnull = scanslot->tts_isnull[attnum];(gdb) 488             EEO_NEXT();(gdb)

跳转到下一个步骤EEOP_FUNCEXPR_STRICT(STEP 3)
首先获取函数调用信息(参数),然后根据参数个数循环判断,接着调用实际的函数(fn_addr指向的函数),调用后赋值给联合体d.

663             FunctionCallInfo fcinfo = op->d.func.fcinfo_data;(gdb) 664             bool       *argnull = fcinfo->argnull;(gdb) p fcinfo$23 = (FunctionCallInfo) 0x1e67b78(gdb) p *fcinfo$24 = {flinfo = 0x1e67b20, context = 0x0, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 2, arg = {1, 1,     0 }, argnull = {false }}(gdb) p *fcinfo->flinfo$25 = {fn_addr = 0x93d60c , fn_oid = 177, fn_nargs = 2, fn_strict = true, fn_retset = false, fn_stats = 2 '\002',   fn_extra = 0x0, fn_mcxt = 0x1e66e60, fn_expr = 0x1d87bf8}(gdb) p *fcinfo->flinfo->fn_expr$26 = {type = T_OpExpr}(gdb) n669             for (argno = 0; argno < op->d.func.nargs; argno++)(gdb) 671                 if (argnull[argno])(gdb) 669             for (argno = 0; argno < op->d.func.nargs; argno++)(gdb) 671                 if (argnull[argno])(gdb) 669             for (argno = 0; argno < op->d.func.nargs; argno++)(gdb) 677             fcinfo->isnull = false;(gdb) 678             d = op->d.func.fn_addr(fcinfo);(gdb) 679             *op->resvalue = d;(gdb) 680             *op->resnull = fcinfo->isnull;(gdb) 683             EEO_NEXT();(gdb)

跳转到下一个步骤EEOP_ASSIGN_TMP(STEP 4),获取结果列所在的编号,赋值

603             int         resultnum = op->d.assign_tmp.resultnum;(gdb) 605             resultslot->tts_values[resultnum] = state->resvalue;(gdb) 606             resultslot->tts_isnull[resultnum] = state->resnull;(gdb) p state->resvalue$27 = 2(gdb) n608             EEO_NEXT();

跳转到下一个步骤,EEO_DONE(STEP 5)

(gdb) 423             goto out;

退出,返回结果值

(gdb) n1764        *isnull = state->resnull;(gdb) 1765        return state->resvalue;(gdb) 1766    }(gdb) ExecInterpExprStillValid (state=0x1e67678, econtext=0x1e672a8, isNull=0x7fffdbc3b877) at execExprInterp.c:17871787    }(gdb) cContinuing.

以上是"PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

0