千家信息网

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

发表于:2025-11-13 作者:千家信息网编辑
千家信息网最后更新 2025年11月13日,这篇文章主要介绍PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!表达式列是指除关系定义中的系统列/定义列之外的其
千家信息网最后更新 2025年11月13日​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如何解析查询语句中的表达式列并计算得出该列的值"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

表达式 步骤 函数 结果 类型 数组 系统 节点 分配 应用 元素 参数 布尔 数据 结构 联合体 联合 语句 字段 指令 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 观看网络安全直播新闻 大量图片存储到服务器 平顶山网络技术有限公司 对网络安全共同体的看法 安卓可以存集合的数据库中 广州汇丰软件开发有限公司地址 服务器租赁管理办法出台 济源却纷网络技术有限公司 大学生网络安全的案例和启示 数据库是数组吗 苹果服务器怎么充q币 上海承影互联网科技有限公司 明日之后官服哪个服务器玩的人多 电脑未连接服务器未响应 网络安全专项清理整治情况汇报 互联网对科技创业的 中国建设域名和服务器 服务器同时开通公网和专线 计算机网络技术段欣 网络安全全民参与 聊天记录保存到腾讯服务器 软件开发一个月赚几百万 网络安全专家李满意 北京世纪联合网络技术 龙之谷 与服务器断开连接 dellr720服务器 网络安全在身边600字作文 数据库设置分组自增 北京恒山系列鲲鹏服务器供应公司 网络安全等级定级企业
0