PostgreSQL 如何构建表达式解析

分类:编程技术 时间:2024-02-20 15:50 浏览:0 评论:0
0
本文主要介绍PostgreSQL如何构造表达式解析。介绍的很详细,有一定的参考价值。感兴趣的朋友一定要读一下!

1.数据结构

EEO_XXX宏定义
操作码调度程序宏定义

/* * 用于操作码调度的宏。 * 操作码调度程序宏定义 * * EEO_SWITCH - 如果不使用则隐藏开关。 * EEO_SWITCH - as 如果不使用,则隐藏开关 * * EEO_CASE - 标记命名表达式步骤类型的实现。 * EEO_CASE - 标记命名表达式步骤类型的实现 * * EEO_DISPATCH - 跳转到“op”步骤类型的实现。 * EEO_DISPATCH - 跳转到'op'指定的步骤类型的实现 * * EEO_OPCODE - 计算所使用的表达式求值方法所需的操作码。*-Apcode**eeo_next-增量'op'并通过请求分析跳转到正确的下一步类型方法。 ifIED 当前表达式中的步数。 * EEO_JUMP - 跳转到当前表达式中的指定步骤号 */#if Defined(EEO_USE_COMPUTED_GOTO)//------------- EEO_USE_COMPUTED_GOTO is Defined /* 跳转目标的结构 -> 操作码查找表*///跳转目标->操作码查找表结构 typedef struct ExprEvalOpLookup{ const void *opcode; ExprEvalOp op;} ExprEvalOpLookup;/* 使dispatch_table 在 Execinterpexpr () 之外可访问*/Static Const void ** Dispatch_table = NULL;/*JUMP TARGET-> 操作码查找表*/Static Exprevalookup Revers e_dispatch_table [eeop_last];#define eeo_switch ( )#define eeo_case (name) case _ ## 名称: #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) 案例名称:#定义 EEO_DISPATCH() 转到 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
解析表达式中的运行时状态节点

/* ExprState->flags 中的位(参见私有标志位也为 execExpr.h): *//* 表达式与 ExecQual() 一起使用 */#define EEO_FLAG_IS_QUAL (1 << 0)typedef struct ExprState{ //Node tag Node tag; //EEO_FLAG_IS_QUAL uint8 标志; nbsp;由 ExecBuildProjectionInfo() 构建。 * 存储标量表达式 * 以及通过 ExecBuildProjectionInfo() 函数创建的单列表达式的结果在。 */#define FIELDNO_EXPSTATE_RESNULL 2 bool resnull;#define FIELDNO_ EXPSTATE_RESVALUE 3 基准重新值; /* * 如果投影元组结果,该槽保存结果;否则为空。 * 如果元组结果被投影,则该槽存储结果,否则为NULL。 */#define FIELDNO_EXPRSTATE_RESULTSLOT 4 TupleTableSlot *resultslot; /* * 计算表达式返回值的指令。 * 计算表达式返回结果的基本“结构” */ struct ExprEvalStep *steps; /* * 实际计算表达式的函数。 * 根据表达式的复杂程度,可以设置为不同的值。 * 实际解析表达式的函数。 * 可以根据表达式的复杂程度设置不同的值。 */ ExprStateEvalFunc evalfunc; /* 原始表达式树,仅用于调试 */ //原始表达式树,仅用于调试调试 Expr *expr; /* private state foran evalfunc */ //evalfunc 的私有状态 void *evalfunc_私人的; /* * XXX: 以下字段仅在“编译”期间需要 (ExecInitExpr); * 之后可能会被扔掉。 “编译”(在 ExecInitExpr 期间需要),之后可以“扔掉”。 */ //当前步数 int steps_len; /* 当前步数 */ //分配的步数数组长度 int steps_alloc; /* 分配的步骤数组长度*/ //父 PlanState 节点(如果存在) struct PlanState *parent; /* 父 PlanState 节点,如果有 */ //用于编译 PARAM_EXTERN 节点 ParamListInfo ext_params; /* 用于编译 PARAM_EXTERN 节点 */ // 数据 *innermost_caseval;布尔 *innermost_casenull;数据*innermost_domainval; bool *innermost_domainnull;} ExprState;

ExprEvalStep
表达式解析步骤结构

typedef struct ExprEvalStep { /* * 要执行的指令。在指令准备期间,这是一个 * enum ExprEvalOp,但稍后可以将其更改为其他类型,例如计算 goto 的 * 指针(即为什么它是一个 intptr_t)。 * 这是指令准备期间的枚举。 type ExprEvalOp, * 但后来会改成其他一些类型,比如用于goto的指针,所以定义为intprt_t类型 */ intptr_t opcode; /* 存放本步结果的位置 */ //存放本步 Datum 的结果 *resvalue;布尔*resnull; /** 操作的内联数据。内联数据的访问速度更快,但 * 也会使所有指令的大小膨胀。 * 在 64 位系统上,联合体的大小不应超过 40 个字节(以便整个结构 * 不超过 64 个字节,在常见系统上为单个缓存行)。保持在 40 字节范围内 *(因此整个结构不应大于 64 字节,这是正常系统上单个缓存行的大小) */ union {                           p; /* for EEOP_INNER/OUTER/SCAN_FETCHSOME */         //For EEOP_INNER/OUTER/SCAN_FETCHSOME        struct                                       // 获取的属性号 int last_var;元组描述已知描述; ;p;结构体                                                                                                                                                                                                                                                                                                                      。 for SYSVAR */        //对于SYSVAR,值为常规属性编号 int attnum; Oid 类型; /* 类型 OIDof 变量 */ } var;变量; /* 对于 EEOP_WHOLEROW */ struct var *var; /* 计划树中的原始 Var 节点 */                                                                1 运行时检查是否为空? */ ; /* for EEOP_ASSIGN_*_VAR */ struct struct { /* ExprState->resultslot->tts_values 中的目标索引 /nulls */ int resultnum;  / {                 /* ExprState->resultslot-> tts_values/nulls 中的目标索引 *//* 目标索引                         ssign_tmp;/*for eeop_const*/struct {/*常量的值*/数据值; book isnull;} constVal;/*对于 eeop_funcexpr_*/nullif/disincture */// 对于 EEOP_FUNCEXPR_*/NULLIF/DISTINCT 结构 & NBSp ; /                /* 无需额外指示即可更快访问: */                                                                                                                                                                                                                                                                           /*             。指向,更快的访问PGFunction fn_addr; /* 实际调用地址 */int nargs; /* 参数数量 */ } func; /* 对于 EEOP_BOOL_*_STEP */ struct struct { bool *anynull; /* 跟踪是否有任何输入为 NULL */ int Jumpdone; /* 如果结果确定则跳转到这里 */ } boolexpr; /* 对于 EEOP_QUAL */ struct struct { int Jumpdone; /* 当 false 或 null 时跳转到此处 */ } qual expr; /* 对于 EEOP_JUMP[_CONDITION] */ 结构体 { int Jumpdone; /* 目标指令索引 */ }                                                                                                                                                                                                     argdesc; } } nulltest_row; /* 对于 EEOP_PARAM_EXEC/EXTERN */ struct struct { int paramid;&nBSP;/*参数的数字 ID*/OID PARAMTYPE;/*参数数据类型的 OID*/} Param;/*对于 Eeop_param_Callback*/Strucks {ExecevalSubro Utine Paramfunc; /*附加评估子例程*/Void*Paramarg;/*相同的私有数据*//* int paramid; /* 参数的数字 ID */ Oid paramtype; /* 参数数据类型的 OID */ } cparam; /* 对于 EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */ struct struct { Datum *value; /* 要返回的值 */ bool  *isnull;} casetest;/*for eeop_make_reamOnly*/Strut {datum*value;/*只读值*/bool*isnull;} Make_readonly;/*for eeop_iocoerce*/struct {& nBSP;/*查找并调用源类型的输出函数的信息n*/fmgrinfo*finfo_out; functionCallinfo fcinfo_data_out;/*查找并调用int O作为结果类型的输入函数*/fmgrinfo*finfo_in; functionCallinfo fcinfo_data_in;} icoerce;/*for eeop_sQLVALUEFUNCTION*/Struct {sqlvalueFunction*svf;} sqlvalueFunction;/*for eeop_nextValueExpr*// EEOP_NEXTVALUEEEEEEEEEEEEEEEEEEEECT {OID {OID {OID {OID Seqid; oid seqtypid;}下一个值表达式; /* 对于 EEOP_ARRAYEXPR */ struct struct Datum *elemvalues; /* 元素值存储在这里 */ bool *elemnull s; int int nelems; /* 上述数组的长度 */ Oid elemtype; /* 数组元素类型 */ int16 elemlength; /* 数组元素类型的 typen */ bool elembyval; /* 元素类型是值传递吗? */ 字符对齐; /* 元素类型的 typealign */ bool multidims; /* 是数组表达式多维吗?*/} Arrayexpr;/*for EEOP_ARAYCOERCE*/ 结构体ExprState                                                           struct ArrayMapState *amstate; /* array_map 的工作空间 */ } arraycoerce; /* for EEOP_ROW * / struct {   TupleDesc Tupdesc;/*结果元组的描述符*//*构成行的值的工作空间:*/Datum*Elemvalues;布尔*Elemnulls; } Row;/*for EEOP_ROWCOMPARE_STEP*/Struct {/*查找并调用列比较函数的数据*/                                                                                                                             FmgrInfo         *finfo; in NULL */ int Jumpnull; /* 产生不等式的比较目标 */ int int Jumpdone; } rowcompare_step;/*for eeop_rowcompare_final*/struct {rowcomparetype rctype;} rowcompare_final;/*for eeop_minmax*/struct {/*参数值的工作节奏*/datum*values;  布尔*空; Int Nelems;/*它是最大还是最小?*/Minmaxop OP;/*用于比较函数的查找和调用数据*/FMGRINFO*FINFO;函数调用 facinfo_data;} minmax;   /* 对于 EEOP_FIELDSELECT */ struct { AttrNumber fieldnum; /* 要提取的字段号 */                                                                                           /* 缓存的 tupdesc 指针 - 在运行时填充 */        TupleDES argdesc;字段选择; EEOP_FIELDSTORE_DEFORM /&nBSP; FieldStore_form*/Struct {/*原始表达式节点*/FieldStore*FSTORE;/*缓存的Tupdesc指针ND表单对共享相同的Tupdesc*/Tupledesc*Argdesc;/*列值的工作空间​​*/       Datum *values;布尔*空; int n列; } 字段存储; /* 对于 EEOP_ARRAYREF_SUBSCRIPT */ struct struct ArrayRefState *state; /* 太大而无法内联 */ struct ArrayRefState *state; int 关闭; /* 该下标从 0 开始的索引 */       bool       isupper; / FETCH */ struct                                                                                         具有内联 */ struct ArrayRefState *state; } 大批参考; /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */ struct struct { * 约束名称 */ char *constraintname; /* CHECK 约束结果的存储位置 */ Datum *checkvalue;布尔 *checknull; /* 域类型的 OID */ Oid resulttype; } 域名检查; /* 对于 EEOP_CONVERT_ROWTYPE */                                                                                                                                                                                             ConvertRowtype       *convert;;/* 这三个字段在运行时填充:*/         TupleDesc    indesc; pleConversionMap *map; /* 列映射 */         bool       初始化; /* 为当前类型初始化?*/} Convert_rowtype;/*for EEOP_SCALARARRAYOP */ struct struct { /* element_type/typlen/typbyval/typalign 在运行时填充 */ Oid element_type; /* 如果未填写则为 InvalidOid */                                                                            bool       bool       useOr; * 数组元素类型存储年龄信息 */        booltybyval;字符类型对齐; FmgrInfo *finfo; /* 函数的查找数据 */ FunctionCallInfo fcinfo_data; /* 参数等 *** scalararrayop; /* 对于 EEOP_XMLEXPR */ struct struct {XmlExpr *xexpr; /* 原始表达式节点 */ Datum *named_argvalue;布尔 *named_argnull; /* 用于评估未命名参数的工作空间(如果有)*/                              p;数据*argvalue;布尔*argnull; } xmlexpr; /* for EEOP_AGGREF */ struct { 外线状态,由 nodeAgg.c 修改 */           AggrefExprState *astate;struct                                                        AggState        AggState       *parent; /* for EEOP_WINDOW_FUNC */ struct struct { /* 线外状态,由nodeWindowFunc.c 修改 */ WindowFuncExprState *wfstat;计划状态 *sstate; } 子计划; /* for EEOP_ALTERNATIVE_SUBPLAN */ struct struct { 外线状态,由nodeSubplan.c 创建 */          AlternativeSubPlanState *asstate;替代子计划;替代子计划                                            AggState *aggstate; FunctionCallInfo fcinfo_data; int 跳转空; agg_反序列化; /* 对于 EEOP_AGG_STRICT_INPUT_CHECK */ struct                                        ;ggstate; AggStatePerTrans pertrans; ExprContext *aggcontext; int 设置号; int 反式; int 抵消;结构体 { AggState *aggstate; int 设置号; int 反式; int 抵消; int 跳转空; agg_strict_trans_check; /* 对于 EEOP_AGG_{PLAIN,ORDERED}_TRANS* */   struct                                                                                AggState     *aggstate; AggStatePerTrans                                                                                                                                                                      int transno; int 抵消; agg_trans; } d;} ExprEvalStep;

ExprEvalOp
ExprEvalSteps 的判别符,定义将执行哪个操作以及使用联合 ExprEvalStep->d 中的哪个结构体。

/* * ExprEvalSteps 的判别符。 * ExprEvalSteps 的鉴别器 * * 标识要执行的操作以及 * ExprEvalStep->d 联合中的哪个成员有效。 * 定义将执行哪个操作以及将使用联合体 ExprEvalStep->d 中的哪个结构体。 * * 条目的顺序需要与 execExprInterp.c:ExecInterpExpr() 中的dispatch_table[] * 数组保持同步。 * 条目的顺序需要与 execExprInterp.c:ExecInterpExpr() 中的dispatch_table[] * 数组保持同步。与execExprInterp.c中dispatch_table[]数组的元素一致:ExecInterpExpr() */typedef enum ExprEvalOp{ /*整个表达式已经被完整求值,返回*/ //整个表表达式已经被解析并返回 EEOP_DONE, / * 在 corresp 上应用 slot_getsomeattrsonding tuple slot */ //对对应的tuple slot应用slot_getsomeattrs方法 EEOP_INNER_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, /* 计算非系统Var值 */ // 计算非系统Var值 EEOP_INNER_VAR, EEOP_OUTER_VAR, EEOP_SCAN_VAR, /* 计算系统Var value */ //计算系统Var值 EEOP_INNER_SYSVAR, EEOP_OUTER_SYSVAR, EEOP_SCAN_SYSVAR, /* 计算整行Var */ //计算整行Var EEOP_WHOLEROW, /*   * 计算非系统Var值,将其分配到ExprState的resultslot中。 * 如果需要 CheckVarSlotCompatibility() 检查,则不会使用这些。 * 计算非系统Var值,将其分配到ExprState的resultslot字段中。 * 如果需要CheckVarSlotCompatibility()时,则不需要这些。 */ EEOP_ASSIGN_INNER_VAR, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, /* 将 ExprState 的 resvalue/resnull 分配给其结果槽的列 */ //将 ExprState 的 resvalue/resnull 分配给列的结果槽 EEOP_ASSIGN_TMP, /*同上,应用 MakeExpandedObjectReadOnly() */ //同上,应用 MakeExpandedObjectReadOnly() EEOP_ASSIGN_TMP_MAKE_RO, /* 评估常量值 */ //评估常量值 EEOP_CONST, /* * * 评估函数调用(包括 OpExprs 等)。为了速度,我们 * 在操作码中区分该函数是否严格和/或 * 需要使用统计跟踪。 * 解析函数调用(包括OpExprs等)。 * 出于性能考虑,需要区分操作码是严格函数还是非严格函数,以及是否需要统计跟踪。 */ EEOP_FUNCEXPR, EEOP_FUNCEXPR_STRICT, EEOP_FUNCEXPR_FUSAGE, EEOP_FUNCEXPR_STRICT_FUSAGE, /* * 计算布尔 AND 表达式,每个子表达式一步。 FIRST/LAST * 子表达式是为了性能而特殊设计的。由于 AND 始终具有至少两个子表达式,因此 FIRST 和 LAST 永远不会应用于同一个子表达式。 * 分析布尔AND表达式,每个子表达式一步。 * FIRST/LAST 子表达式 are 性能特例。 * 由于 AND 通常至少有两个子表达式,因此 FIRST 和 LAST 永远不会应用于同一个子表达式。向上。 */ EEOP_BOOL_AND_STEP_FIRST, EEOP_BOOL_AND_STEP, EEOP_BOOL_AND_STEP_LAST, /* 与布尔 OR 表达式类似 */ // 与布尔 OR 表达式类似 EEOP_BOOL_OR_STEP_FIRST, EEOP_BOOL_OR_STEP, EEOP_BOOL_OR_STEP_LAST, /* 计算布尔 NOT 表达式 */ // 分析 Bo olean NOT 表达式 EEOP_BOOL_NOT_STEP, /* 简化版本of BOOL_AND_STEP for use by ExecQual() */ //ExecQual()中使用的BOOL_AND_STEP的简化版本 EEOP_QUAL, /* 无条件跳转到另一步 */ //无条件跳转到另一步 EEOP_JUMP, /* 根据当前结果值有条件跳转*/ //根据当前结果值条件跳转 EEOP_JUMP_IF_NULL, EEOP_JUMP_IF_NOT_NULL,  EEOP_JUMP_IF_NOT_TRUE, /* 对标量值执行 NULL 测试*/ //对标量值执行 NULL 测试 EEOP_NULLTEST_ISNULL, EEOP_NULLTEST_ISNOTNULL, /* perform 对行值进行NULL测试*/ //对行值进行NULL测试 EEOP_NULLTEST_ROWISNULL, EEOP_NULLTEST_ROWISNOTNULL, /*评估一个BooleanTest表达式 */ //分析BooleanTest表达式 EEOP_BOOLTEST_IS_TRUE, EEOP_BOOLTEST_IS_NOT_TRUE, EEOP_BOOLTEST_IS_FALSE, EEOP_BOOLT EST_IS_NOT_FALSE, /* 评估 PARAM_EXEC/EXTERN 参数meters */ //解析 PARAM_EXEC/EXTERN 参数 EEOP_PARAM_EXEC, EEOP_PARAM_EXTERN, EEOP_PARAM_CALLBACK, /* return CaseTestExpr 值 */ //返回 CaseTestExpr 值 EEOP_CASE_TESTVAL, /* apply MakeExpandedObjectReadOnly() to target value */ //对目标值 Apply MakeExpandedObjectReadOnly() EEOP_MAKE_READONLY, /* 评估各种特殊用途表达式类型 */ // 解析各种特殊用途表达式类型 EEOP_IOCOERCE, EEOP_DISTINCT, EEOP_NOT_DISTINCT, EEOP_NULLIF, EEOP_SQLVALUEFUNCTION, EEOP_CURRENTOFEXPR, EEOP_NEXTVALUEEXPR, EEOP_ARRAY EXPR, EEOP_ARRAYCO ERCE,EEOP_ROW, /* * 比较两个单独的元素两个比较中的每一个 ROW() * expressionions。如果元素不相等,则跳至 ROWCOMPARE_FINAL。 * 给定两个需要比较的 ROW() 表达式,成对比较行中的元素。 。 * 如果元素不相等,则跳转到 ROWCOMPARE_FINAL */ EEOP_ROWCOMPARE_STEP, /* 根据之前的 ROWCOMPARE_STEP 操作评估布尔值 */ //根据之前的 ROWCOMPARE_STEP 操作评估布尔值 EEOP_ROWCOMPARE_FIN AL, /* 评估 GREATEST() 或 LEAST ( ) */ //分析 GREATEST() 和 LEAST() EEOP_MINMAX, /* 评估 FieldSelect 表达式 */ //解析 FieldSelect 表达式 EEOP_FIELDSELECT, /* * 在评估 FieldStore 表达式中各个字段的新值之前变形元组。 * 在解析 FieldStore 表达式中独立列的新值之前重建元组 */ EEOP_FIELDSTORE_DEFORM , /* * 形成 FieldStore 表达式的新元组。各个字段将被评估为由前面的 DEFORM 步骤变形的元组的列。 *个别字段为p插入元组列(行已被上一步 EEOP_FIELDSTORE_DEFORM 破坏) */ EEOP_FIELDSTORE_FORM, /* 处理数组下标;如果为 NULL,则将表达式短路为 NULL */ // 处理数组下标。如果为 NULL,则短路表达式为 NULL EEOP_ARRAYREF_SUBSCRIPT, /* * 当 ArrayRef 赋值表达式 * 包含 ArrayRef/FieldStore 子表达式时,计算旧数组元素/切片。使用 CaseTest 机制访问值。 * 计算旧数组元素/切片时,ArrayRef 中的赋值表达式包含 ArrayRef/ FieldStore 子表达式。 * 通过 CaseTest 机制访问 Value */ EEOP_ARRAYREF_OLD, /* 计算 ArrayRef 赋值表达式的新值 */ // 将 118 EEOP_ARRAYREF_ASSIGN 赋值给 ArrayRef, /* 计算 ArrayRef 获取表达式的元素/切片 */ // 计算 ArrayRef 获取的元素/切片expression EEOP_ARRAYREF_ FETCH, /* 计算 CoerceToDomainValue 的值 */ // 解析 CoerceToDomainVa 的值lue EEOP_DOMAIN_TESTVAL, /* 评估域的 NOT NULL 约束 */ // 解析域 NOT NULL 约束 EEOP_DOMAIN_NOTNULL, /* 评估单个域 CHECK 约束 */ // 解析单个域 CHECK 约束 EEOP_DOMAIN_CHECK, /* 评估各种特殊用途expression types */ //分析专用表达式类型 EEOP_CONVERT_ROWTYPE, EEOP_SCALARARRAYOP, EEOP_XMLEXPR, EEOP_AGGREF, EEOP_GROUPING_FUNC, EEOP_WINDOW_FUNC, EEOP_SUBPLAN, EEOP_ALTERNATIVE_SUBPLAN, /*聚合相关节点 */ //聚合相关节点 EEOP_AGG_STRICT_DESER IALIZE、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, /* 不存在的操作,例如使用检查数组长度 */ //不存在的操作,如用于检查数组长度 EEOP_LAST} ExprEvalOp;

2.源码解读

ExecInitIndexScan
初始化Index Scan运行时状态信息并调用ExecAssignScanProjectionInfo->…->ExecBuildProjectionInfo函数构建投影信息。

/* ---------------------------------- --- ------------------------------- * ExecInitIndexScan * * 初始化索引扫描的状态信息,创建 * 扫描键,并打开基址和索引关系。 * * 注:索引扫描有 2 组状态信息,因为 *                                                                                                                                                                                        ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ -  -  -  -  -  - 我们有(  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate, int eflags){ ... /* * 初始化结果槽、类型和投影 * 初始化结果槽、类型和投影 */ ExecInitResultTupleSlotTL(estate, &indexstate->ss.ps); ExecAssignScanProjectionInfo(&indexstate->s s); ... }

ExecBuildProjectionInfo
对于给定的 econtext 中的 tlist 构建 ProjectionInfo 并将结果存储在元组槽中。 (调用者必须保证tuple槽与这个tlist匹配)
主要逻辑是:
1.初始化
2.如有必要,插入EEOP*_FETCHSOME步骤(调用ExecInitExprSlots)
3.遍历targetList并处理targetList中的每一列(目标列)
3.1.对于“安全”Var,只需生成 EEOP_ASSIGN*_VAR 的步骤
3.2 ​​对于非“安全”Var,使用常规方法处理列表达式,调用 ExecInitExprRec 函数处理,通过 ExprEvalPushStep 推送步骤< br/>4.推送 EEOP_DONE 步骤

/*
* ExecAssignScanProjectionInfo
* 如有必要,为扫描节点设置投影信息。
* ExecAssignScanProjectionInfo< br/> * 配置扫描节点信息的投影。
*
* 如果请求的 tlist 与底层元组类型完全匹配,我们可以避免投影步骤。如果是这样,我们只需将 ps_ProjInfo 设置为 NULL。
* 请注意,这种情况不仅发生在简单的“SELECT * FROM ...”中,而且
* 在大多数存在连接或其他处理的情况下也会发生
* 扫描节点之上的节点,因为规划器会优先生成匹配的
* tlist。
* 如果请求的tlist恰好与潜在的tlist uple类型匹配,则投影步骤可以
* 因此,只需将 ps_ProjInfo 设置为 NULL 即可。
* 注意,这种情况不仅限于“SELECT * FROM ...”会发生,
* 也会发生在以下情况有连接或者其他处理节点正在扫描该节点的上层,
* 因为规划器会优先生成匹配的tlist。
*
* 扫描槽的描述符必须已经存在已设置。
* 扫描槽的描述符必须已设置。
*/
void
ExecAssignScanProjectionInfo(ScanState *node)
{
//扫描节点
Scan *scan = (Scan *) node->ps.plan;< br/> //元组描述符
TupleDesc tupdesc = node-> ss_ScanTupleSlot->tts_tupleDescriptor;
//执行ExecConditionalAssignProjectionInfo
ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid);< br/>}
/* ------- ---------
* ExecConditionalAssignProjectionInfo
*
* 作为 ExecAssignProjectionInfo,但存储 NULL 而不是构建投影
* 如果不需要投影,则为info
* 与ExecAssignProjectionInfo类似,但是不需要投影操作时,只需要存储NULL,而不需要构造投影信息
* ----- -----------
*/
void
ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
> ExecConditionalAssignProjectionInfo ( planstate,
PlanState->Plan->TargetList,
varno,
inputDesc))
Planstate->ps_projinfo = null;
else
// 否则 o
ExecAssignProjectionInfo(planstate, inputDesc);
}
/* --------------- -
* ExecAssignProjectionInfo
*
* 根据节点的targetlist形成投影信息
* 通过节点的targetlist构建投影信息。
*
* 注意事项inputDesc 与 ExecBuildProjectionInfo 相同:提供它
* 对于关系扫描节点,可以为上层节点传递 NULL
* 请注意,inputDesc 与 ExecBuildProjectionInfo 相同:
* 提供此信息关系扫描节点的描述符,并且可以为上层节点传递NULL值
* -- --------------
*/
void
ExecAssignProjectionInfo(PlanState *planstate,
                                                                  TupleDesc inputDesc)
{
//直接调用ExecBuildProjectionInfo
planstate->ps_ProjInfo =
ExecBuildProjectionInfo(planstate->plan->targetlist,
  putDesc);
}
/*
* ExecBuildProjectionInfo
*
* 构建一个ProjectionInfo节点,用于评估给定
* econtext中给定的tlist,并将结果存储到元组槽中。 (调用者必须
* 确保元组槽具有与 tlist 匹配的描述符!)
* 为给定 econtext 中的 tlist 构造 ProjectionInfo 并将结果存储在元组槽中。
* (调用者必须确保元组槽与此 tlist 匹配)
*
* inputDesc 可以为 NULL,但如果不是,我们检查 simple
* tlist 中的变量是否匹配描述符。为关系扫描计划节点提供
* inputDesc 非常重要,作为交叉检查关系
* 自计划制定以来尚未更改。在计划的更高级别,
* 无需重新检查。
* inputDesc 可以为 NULL,但如果不匹配,则检查tlist中的简单Var是否与描述符匹配。
* 关系扫描节点提供inputDesc非常重要,
* 在计划中进行交叉检查
*
* 这是通过内部构建一个ExprState来实现的
/> * 一次性完成整个投影。
* 通过内部构造ExprState来实现(一轮执行完成整个投影操作)。
*
* 注意:在 PG v10 之前,targetList 是 ExprStates 列表;现在
* 应该是planner创建的targetlist,因为我们在这里进行编译。
* 注意:在PG v10之前,targetlist是ExprState链表,现在tlist应该是planner创建的targetlist,
* 如果没有,一定报错。
*/
ProjectionInfo *
ExecBuildProjectionInfo(List *targetList,
TupleTableSlot *slot,
                                                  PlanState *parent,
                                                          的 ' 元组Desc的inputDesc)
{ //表达式状态节点
ExprState *state;
//表达式解析步骤
ExprEvalStep scrap = {0};
//临时变量
ListCell *lc ;
//expr context< br/> projInfo->pi_exprContext = econtext;
/* 我们将 ExprState 嵌入到 ProjectionInfo 中,而不是做额外的 palloc */
//将 ExprState 集成到 ProjectionInfo 中,不需要额外的 palloc
projInfo ->pi_state.tag.type = T_ExprState;
state = &projInfo->pi_state;
state->expr = (Expr *) targetList;
state->parent = Parent;
state->ext_params = NULL;
state->resultslot = slot;
/* 根据需要插入 EEOP_*_FETCHSOME 步骤 */
//如果需要,插入 EEOP_*_FETCHSOME 步骤
ExecInitExprSlots(state, (Node *) targetList);
/* 现在编译每个 tlist 列 */
//现在“编译”tlist中的每一列
foreach(lc, targetList)
{
TargetEntry *tle = lfirst_node(TargetEntry, lc);
Var * *variable = NULL;
        AttrNumber   attnum = 0;
        bool           isSafeVar = false;
            /*
            ' 的 tlist 表达式是一个安全的非系统变量,使用 fast- path
* ASSIGN_*_VAR 操作码。“安全”意味着我们不需要在计划启动期间应用
* CheckVarSlotCompatibility()。如果提供了源插槽
*,我们将在此处进行等效测试;如果某个插槽不是
                                                                                                                                       * 前提是,我们假设不需要检查,因为我们正在处理
           快速路径 ASSIGN_*_VAR 操作码。
* “安全”意味着我们不需要当计划开始执行时应用CheckVarSlotCompatibility()。
* 如果提供了源槽,则假设no 需要更多检查,因为我们正在处理非关系扫描级别表达式。 ((Var *) tle->expr)->varattno > 0)
*/ ;
Attnum = 变量-> Varaattno;
if (inputDesc == NULL)
// 无法检查,假设没问题。
ISSAFEVAR = TRUE;/* Canon'T 检查,假设 OK */
Else If (ATTNUM <= Inputdesc-> NATTS)
{
// ---- - 属性编号的数量小于输入的属性数量
form_pg_attribute attr = TupleDescAttr(inputDesc, attnum - 1);
                    /*
* 如果用户属性被删除或具有类型不匹配,请勿
* 使用Assign __ VAR。相反,让正常表达
* 机械处理它; / }
  步骤 */
// 快速路径:只需生成 EEOP_ASSIGN _ *_AAR 步骤。 * 从infer节点获取table */
// 内部关系VAR,从inner节点获取meta group
scrap.opcode = eeop_assign_inner_var;
休息;
= EEOP_分配_OUTER_VAR;
                 break;
                               /* INDEX_VAR 按默认情况处理 */
                                    //默认: INDEX_VAR
                                                                 /* 从正在扫描的关系中获取元组 */< br/>                       //从正在扫描的关系中检索元组
         scratch.opcode = EEOP_ASSIGN_SCAN_VAR;
                                                                                                                               中断; tnum - 1;
            scrap.d. allocate_var.resultnum = tle->resno - 1;
                                                                                使用 using ‐                                                                            use ' ' ' ' ' using using ' s ' using tle-> ‐ ‐ ‐ ‐ ‐ through ‐ of * 否则,编译通常列表达式。直接求值到
* 结果槽,因为结果槽(及其 exprstate
              * 很重要)可以在执行之间发生变化。
                                                                                                                   移动。我们只需要解析 ExprState 的 resvalue/resnull 并将其移动即可。
null) ;
              /*
                                                             nbsp; * 列可能在上层节点中被多次引用,所以 ,因此强制值是 R/O - 仅当数据可扩展时才以这种方式处理
                                                                 ) tle->expr)) == -1)
to scrap.d.assign_tmp.resultnum = tle ->resno - 1;
ExprEvalPushStep(state, &scratch);
}
}
 scratch.opcode = EEOP_DONE;
ExprEvalPushStep(state, &scratch);
ExecReadyExpr(state);
//返回投影信息。
return projInfo;
}

3.跟踪分析

测试脚本

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

调用堆栈

(gdb) bt
#0 ExecBuildProjectionInfo (targetList=0x1cc7550, econtext= 0x1c8f408,插槽 = 0x1c8f710,父级 = 0x1c8f1f0,
inputDesc=0x7f8386bb6ab8) 在 execExpr.c:355
#1 0x00000000006e60d5 在 ExecAssignProjectionInfo (planstate=0x1c8f1f0,inputDesc=0x7f838 6bb6ab8) 在 execU tils.c:468< br/>#2 ExecConditionalAssignProjectionInfo 中的 0x00000000006e613c (planstate=0x1c8f1f0, inputDesc=0x7f8386bb6ab8, varno=1)
在 execUtils.c:493
#3 0x00000000ExecAssignScanProjectionInfo (node=0x1c8f1f0) 中的 006e23f5 在 execScan.c:240
#4 0x0000000000700afc 在 ExecInitIndexScan (node=0x1ba8a18, Estate=0x1c8efd8, eflags=16) 在 nodeIndexscan.c:962
#5 0x00 000000006e00cc 中ExecInitNode (node=0x1ba 8a18, Estate=0x1c8efd8, eflags=16 ) at execProcnode.c:217
#6 0x00000000006d6abe initPlan (queryDesc=0x1c94aa8, eflags=16) at execMain.c:1046
# 7 execMain.c:265 处的 standard_ExecutorStart 中的 0x00000000006d58ad (queryDesc=0x 1c94aa8, eflags=16)#8 execMain.c:1 处的 ExecutorStart 中的 0x00000000006d5649 (queryDesc=0x1c94aa8, eflags=0) 47
#9 PortalStart 中的 0x00000000008c18d6 (portal=0x1c15608、params=0x0、eflags=0、snapshot=0x0) 位于 pquery.c:520
#10 exec_simple_query 中的 0x00000000008bbe1b (query_string=0x1ba6d78"从中选择 1+id,c2 t_expr 其中 id < 3;")
at postgres.c:1106
#11 0x00000000008c0191 in PostgresMain (argc=1, argv=0x1bd4cb8, dbname=0x1bd4b20 "testdb", username=0x1ba3a98 "xdb")
在 postgres.c: 4182
#120x000000000081e06c 在 Backendrun (端口 = 0x1bc8ae0) 在 postmaster.c: 4361
#13 0x000000000081d7df 在 Backendstartup (端口 = 0x1BC8AE0) 在 postmaster.c: 4033
#14 0x000000000081 postmaster.c 中的 ServerLoop () 中的 9bd9 :1706
#15 0x000000000081948f in PostmasterMain (argc=1, argv=0x1ba1a50) at postmaster.c:1379
#16 0x000000000074293 1 in main (argc=1, argv =0x1ba1a50) at main.c: 228

执行跟踪并输入函数Exec​​BuildProjectionInfo

(gdb) b ExecBuildProjectionInfo
断点1在0x6c5377:文件execExpr.c,第355行。
(gdb)c
继续。
断点1,ExecBuildProjectionInfo(targetList = 0x1c93498,econtext = 0x1c883a8,slot = 0x1c887c8,parent = 0x1c88190,
inputDesc=0x1c884a0) at execExpr.c:355
355 ProjectionInfo *projInfo = makeNode(ProjectionInfo);
(gdb)

1.初始化

(gdb) n
357 ExprEvalStep scrap = {0};
(gdb )
360 projInfo->pi_exprContext = econtext;
(gdb)
362 projInfo->pi_state.tag.type = T_ExprState;
(gdb)
363 state = &projInfo->pi_state;
(gdb )
364 state->expr = (Expr *) targetList;
(gdb)
365 state->parent =parent;
(gdb)
366 state- >ext_params = NULL;
(gdb)
368 state->resultslot = slot;
(gdb)

查看相关变量

(gdb) p *state
$1 = {tag = {type = T_ExprState}, flags = 0 '\000', resnull = false , resvalue = 0,结果槽 = 0x1c8f710,步骤 = 0x0,
evalfunc = 0x0,expr = 0x1cc7550,evalfunc_private = 0x0,steps_len = 0,steps_alloc = 0,父级 = 0x1c8f1f0,
ext_params = 0x0,innermost_caseval = 0x0 , insidemost_casenull = 0x0, insidemost_domainval = 0x0,
insidemost_domainnull = 0x0}

目标列链表

 (gdb) p targetList
$2 = (List *) 0x1cc7550
(gdb) p *targetList
$3 = {type = T_List, length = 2, head = 0x1cc7528, tail = 0x1cc75e0}

T第一个元素是1+id,第二个元素是c2

(gdb) p *(TargetEntry *)targetList->head->data.ptr_value
$7 = { xpr = {type = T_TargetEntry},expr = 0x1c9a930,resno = 1,resname = 0xbcf498“?列?”,ressortgroupref = 0,
resorigtbl = 0,resorigcol = 0,resjunk = false}< br/>( gdb) p *(OpExpr *)((TargetEntry *)targetList->head->data.ptr_value)->expr
$9 = {xpr = {type = T_OpExpr}, opno = 551, opfuncid = 177,opresulttype = 23,opretset = false,opcollid = 0,
inputcollid = 0,args = 0x1c9a878,位置 = 8}
(gdb) p *(Node *)targetList->head-> next->data .ptr_value
$10 = {type = T_TargetEntry}
(gdb) p *(TargetEntry *)targetList->head->next->data.ptr_value
$11 = {xpr = {type = T_TargetEntry},expr = 0x1c9aa40,resno = 2,resname = 0x1ba7a40“c2”,ressortgroupref = 0,
resorigtbl = 237600,resorigcol = 2,resjunk = false}

2.如有必要,插入 EEOP_*_FETCHSOME 步骤(调用 ExecInitExprSlots)

(gdb) 
371 ExecInitExprSlots(state, (Node *) targetList);

第一步,opcode = 3,即EEOP_SCAN_FETCHSOME

(gdb) n
374 foreach(lc, targetList)
(gdb) p *state
$13 = { tag = {类型 = T_ExprState},标志 = 0 '\000',resnull = false,resvalue = 0,结果槽 = 0x1c8f710,
步骤 = 0x1c8f868,evalfunc = 0x0,expr = 0x1cc7550,evalfunc_private = 0x0,steps_len = 1,steps_alloc = 16,
父= 0x1c8f1f0,ext_params = 0x0,innermost_caseval = 0x0,innermost_casenull = 0x0,innermost_domainval = 0x0,
innermost_domainnull = 0x0}
(gdb)p状态->步骤[0]
$14 = {操作码 = 3,resvalue = 0x0,resnull = 0x0,d = {fetch = {last_var = 2,known_desc = 0x0},var = {attnum = 2,
vartype = 0}, Wholerow = {var = 0x2、first = false、slow = false、tupdesc = 0x0、junkFilter = 0x0}、assign_var = {
  resultnum = 2、attnum = 0}、assign_tmp = {resultnum = 2}、constval = {value = 2, isnull = false}, func = {
finfo= 0x2、fcinfo_data = 0x0、fn_addr = 0x0、nargs = 0}、boolexpr = {anynull = 0x2、jumpdone = 0}、qualexpr = {
Jumpdone = 2}、jump = {jumpdone = 2}、nulltest_row = {argdesc = 0x2},param = {paramid = 2,paramtype = 0},cparam = {
paramfunc = 0x2,paramarg = 0x0,paramid = 0,paramtype = 0},casetest = {值= 0x2,isnull = 0x0},
make_readonly = {value = 0x2, isnull = 0x0}, iocoerce = {finfo_out = 0x2, fcinfo_data_out = 0x0, finfo_in = 0x0,
fcinfo_data_in = 0x0}, sqlvaluefunction = {svf = 0x2 }, nextvalueexpr = {seqid = 2, seqtypid = 0}, arrayexpr = {
elemvalues = 0x2, elemnulls = 0x0, nelems = 0, elemtype = 0, elemlength = 0, elembyval = false, elemalign=0 '\000',
multidims = false}, arraycoerce = {elemexprstate = 0x2, resultelemtype = 0, amstate = 0x0}, row = {tupdesc = 0x2,
elemvalues = 0x0, elemnulls = 0x0 } , rowcompare_step = {finfo = 0x2, fcinfo_data = 0x0, fn_addr = 0x0, Jumpnull = 0,
Jumpdone = 0}, rowcompare_final = {rctype = ROWCOMPARE_LE}, minmax = {values = 0x2, nulls = 0x0, nelems = 0,
op = IS_GREATEST, finfo = 0x0, fcinfo_data = 0x0}, fieldselect = {fieldnum = 2, resulttype = 0, argdesc = 0x0},
fieldstore = {fstore = 0x2,argdesc = 0x0,值= 0x0,nulls = 0x0,ncolumns = 0},arrayref_subscript = {state = 0x2,
off = 0,isupper = false,jumpdone=0},arrayref={state=0x2},domaincheck={
constraintname=0x2<地址0x2越界>,checkvalue=0x0,checknull=0x0,resulttype=0},
Convert_rowtype = {convert= 0x2,indesc = 0x0,outdesc = 0x0,map = 0x0,初始化= false},scalararrayop = {
element_type = 2,useOr = false,typlen = 0,typbyval = false,typalign = 0 '\000'、finfo = 0x0、fcinfo_data = 0x0、
fn_addr = 0x0}、xmlexpr = {xexpr = 0x2、named_argvalue = 0x0、named_argnull = 0x0、argvalue = 0x0、argnull = 0x0}、
aggref = {astate = 0x2},grouping_func = {parent = 0x2,子句 = 0x0},window_func = {wfstate = 0x2},子计划 = {
sstate = 0x2},alternative_subplan = {asstate = 0x2},agg_deserialize = {aggstate = 0x2,fcinfo_data = 0x0,
Jumpnull = 0},agg_strict_input_check = {nulls = 0x2,nargs = 0,jumpnull = 0},agg_init_trans = {aggstate = 0x2,
pertrans = 0x0,aggcontext = 0x0,setno = 0,transno = 0,setoff = 0,jumpnull = 0},agg_strict_trans_check = {
aggstate = 0x2,setno = 0, transno = 0,setoff = 0,jumpnull = 0},agg_trans = {aggstate = 0x2,pertrans = 0x0,
aggcontext = 0x0,setno = 0,transno = 0,setoff = 0}}}
(gdb)

3.遍历targetList并处理targetList中的每一列(目标列)
3.1.对于“安全”Var,只需生成 EEOPASSIGN*_VAR 步骤
3.2。对于非“安全”的VAr,使用常规方法处理列表达式,调用ExecInitExprRec函数处理,通过ExprEvalPushStep推送步骤

(gdb) n
376 TargetEntry *tle = lfirst_node(TargetEntry, lc);
(gdb)
377 Var *variable = NULL;
(gdb)
378 AttrNumber attnum = 0;
(gdb)
379 bool isSafeVar = false;
(gdb)
389 if (tle->expr != NULL &&
( gdb)
390 IsA(tle->expr, Var) &&
(gdb)
389 if (tle->expr != NULL &&
(gdb)
415  if (isSafeVar)
(gdb) p *tle
$15 = {xpr = {type = T_TargetEntry},expr = 0x1c9a930,resno = 1,resname = 0xbcf498“?列?”,ressortgroupref = 0,
resorigtbl = 0,resorigcol = 0,resjunk = false}
(gdb)n
452 ExecInitExprRec(tle-> expr, state,
(gdb)

进入ExecInitExprRec,Node节点为OpExpr,执行ExprEvalPushStep推送步骤

(gdb) 步骤
ExecInitExprRec (node=0x1c9a930, state=0x1c8f7d8, resv=0x1c8f7e0, resnull=0x1c8f7dd) at execExpr.c:645
645 ExprEvalStep scrap = {0} ;
(gdb) n
648 check_stack_depth();
(gdb)
651 Assert(resv != NULL && resnull != NULL);
(gdb)
652 scrap.resvalue = resv;
(gdb)
653 scrap.resnull = resnull;
(gdb)
656 switch (nodeTag(node))
(gdb)
891   OpExpr *op = (OpExpr *) node;
(gdb) p *节点
$16 = {type = T_OpExpr}
(gdb) n
893 ExecInitFunc(&scratch, node,
(gdb)
896 ExprEvalPushStep(state, &scratch);
(gdb)
897 中断;
(gdb)
2122 }
(gdb)
ExecBuildProjectionInfo (targetList=0x1cc7550, econtext=0x1c8f408, slot= 0x1c8f710,parent=0x1c8f1f0,
inputDesc=0x7f8386bb6ab8) at execExpr.c:459
459 If (get_typlen( exprType((Node *) tle->expr)) == -1)
(gdb)
462                 scrap.opcode = EEOP_ASSIGN_TMP;
(gdb)

ExecInitExprRec被调用,并添加了2个步骤,其中分别是:
1.opcode = 6,即 EEOP_SCAN_VAR
2.opcode = 18,即 EEOP_FUNCEXPR_STRICT

(gdb) p *state
$17 = {tag = {type = T_ExprState},flags = 0 '\000',resnull = false,resvalue = 0,resultslot = 0x1c8f710,
步骤 = 0x1c8f868,evalfunc = 0x0,expr = 0x1cc7550,evalfunc_private =0x0、steps_len = 3、steps_alloc = 16、
父级 = 0x1c8f1f0、ext_params = 0x0、innermost_caseval = 0x0、innermost_casenull = 0x0、innermost_domainval = 0x0、
insidemost_domainnull = 0x 0}
(gdb) p state->steps[1]
$18 = {操作码 = 6,resvalue = 0x1c8fd00,resnull = 0x1c90019,d = {fetch = {last_var = 0,known_desc = 0x0},var = {
attnum = 0,vartype = 23},wholerow = {var = 0x1700000000,first = false,slow = false,tupdesc = 0x0,
junkFilter = 0x0},assign_var = {resultnum = 0,attnum = 23},assign_tmp = {resultnum = 0},constval = {
值= 98784247808,isnull = false},func = {finfo = 0x1700000000,fcinfo_data = 0x0,fn_addr = 0x0,nargs = 0},
boolexpr = {anynull = 0x1700000000、jumpdone = 0}、qualexpr = {jumpdone = 0}、jump = {jumpdone = 0}、nulltest_row = {
argdesc = 0x1700000000}、param = {paramid = 0、paramtype = 23}、cparam = {paramfunc = 0x1700000000,paramarg = 0x0,
paramid = 0,paramtype = 0},casetest = {value = 0x1700000000,是null = 0x0}, make_readonly = {value = 0x1700000000,
isnull = 0x 0}, iocoerce = {finfo_out = 0x1700000000, fcinfo_data_out = 0x0, finfo_in = 0x0, fcinfo_data_in = 0x0},
sqlvaluefunction = {svf = 0x1700000000},nextvalueexpr = {seqid = 0,seqtypid = 23},arrayexp r = {
elemvalues = 0x1700000000,elemnulls = 0x0,nelems = 0,elemtype = 0,elemlength = 0,elembyval = false,
elemalign = 0 '\000',multidims = false},arraycoerce = {elemexprstate = 0x1700000000,resultelemtype = 0,
amstate = 0x0},row = {tupdesc = 0x1700000000,elemvalues = 0x0, elemnulls = 0x0},rowcompare_step = {
finfo = 0x1700000000,fcinfo_data = 0x0,fn_addr = 0x0,jumpnull = 0,jumpdone = 0},rowcompare_final = {rctype = 0},
minmax = {值​​= 0x1700000000、nulls = 0x0、nelems = 0、op = IS_GREATEST、finfo = 0x0、fcinfo_data = 0x0}、
fieldselect = {fieldnum = 0、resulttype = 23、argdesc = 0x0}、fieldstore = {fstore = 0x1700000000,argdesc = 0x0,
值= 0x0,nulls = 0x0,ncolumns = 0},arrayref_subscript = {state = 0x1700000000,off = 0,isupper = false,
Jumpdone = 0},arrayref = {state = 0x1700000000},domaincheck = {
约束名称= 0x1700000000 <地址0x1700000000越界>,checkvalue = 0x0,checknull = 0x0,
resulttype = 0},convert_rowtype = {convert = 0x17 00000000,index = 0x0,outdesc = 0x0,map = 0x0,
/> 初始化 = false}、scalararrayop ={element_type = 0、useOr = 23、typlen = 0、typbyval = false、
typalign = 0 '\000'、finfo = 0x0、fcinfo_data = 0x0、fn_addr = 0x0} 、 xmlexpr = {xexpr = 0x1700000000、
named_argvalue = 0x0、named_argnull = 0x0、argvalue = 0x0、argnull = 0x0}、aggref = {astate = 0x1700000000}、
grouping_func = {parent = 0x1700000000、子句 = 0x0},window_f unc = {wfstate = 0x1700000000},子计划 = {
sstate = 0x1700000000},alternative_subplan = {asstate = 0x1700000000},agg_deserialize = {aggstate = 0x1700000000,
fcinfo_data = 0x0 , 跳转空 = 0 }, agg_strict_input_ check = {nulls = 0x1700000000,nargs = 0,jumpnull = 0},
agg_init_trans = {aggstate = 0x1700000000,pertrans = 0x0,aggcontext = 0x0,setno = 0,transno = 0,setoff = 0,
/> Jumpnull = 0}, agg_strict_trans_check = {aggstate = 0x1700000000, setno = 0, transno = 0, setoff = 0, Jumpnull = 0},
---键入 继续,或 q 退出---
agg_trans = {aggstate = 0x1700000000, pertrans = 0x0, aggcontext = 0x0, setno = 0, transno = 0, setoff = 0}}}
(gdb) p state->steps [2]
$19 = {操作码 = 18,resvalue = 0x1c8f7e0,resnull = 0x1c8f7dd,d = {fetch = {last_var = 29949056,known_desc = 0x1c8fcd8},
var = {attnum = 29949056,vartype = 0}、wholerow = {var = 0x1c8fc80、first = 216、slow = 252、
tupdesc = 0x93d60c < int4Pl>、junkfilter = 0x2}、assign_var = {resultnum = 29949056、attnum = 0}、assign_tmp = {< br/> ResultNum = 29949056},Constval = {va Lue = 29949056,isnull = 216},func = {finfo = 0x1c8fc80,
fcinfo_data = 0x1c8fcd8,fn_addr= 0x93d60c ,nargs = 2},boolexpr = {anynull = 0x1c8fc80,
Jumpdone = 29949144},qualexpr = {jumpdone = 29949 056},jump = {jumpdone = 29949056},nulltest_row = {
argdesc = 0x1c8fc80},param = {paramid = 29949056,paramtype = 0},cparam = {paramfunc = 0x1c8fc80,
paramarg = 0x1c8fcd8,paramid = 9688588,paramtype = 0},casetest = {值= 0x1c8fc80,isnull = 0x1c8fcd8},
make_readonly = {value = 0x1c8fc80, isnull = 0x1c8fcd8}, iocoerce = {finfo_out = 0x1c8fc80,
fcinfo_data_out = 0x1c8fcd 8, finfo_in = 0x93d60c , fcinfo_data_in = 0x2 }, sql值函数 = {
svf = 0x1c8fc80},nextvalueexpr = {seqid = 29949056,seqtypid = 0},arrayexpr = {elemvalues = 0x1c8fc80,
elemnulls = 0x1c8fcd8,nelems = 96 88588,elemtype = 0,elemlength = 2、elembyval = false,elemalign = 0 '\000',
multidims = false},arraycoerce = {elemexprstate = 0x1c8fc80,resultelemtype = 29949144,
amstate = 0x93d60c },row = { tupdesc = 0x1c8fc80,elemvalues = 0x1c8fcd8,elemnulls = 0x93d60c },
rowcompare_step = {finfo = 0x1c8fc80,fcinfo_data = 0x1c8fcd8,fn_addr = 0x93d60c ,jumpnull = 2,
跳转完成= 0},rowcompare_final = { rctype = 29949056},minmax = {值= 0x1c8fc80,nulls = 0x1c8fcd8,
nelems = 9688588,op = IS_GREATEST,finfo = 0x2,fcinfo_data = 0x0},fieldselect = {fieldnum = -896,resulttype = 0、argdesc = 0x1c8fcd8}、fieldstore = {fstore = 0x1c8fc80、argdesc = 0x1c8fcd8、值 = 0x93d60c 、nulls = 0x2、
ncolumns = 0}、arrayref_subscript = {state = 0x1c8f c80,off = 29949144,isupper = false,jumpdone = 9688588},
arrayref = {state = 0x1c8fc80},domaincheck = {constraintname = 0x1c8fc80“\f֓”,checkvalue = 0x1c8fcd8,
checknull = 0x93d60c < int4pl>,resulttype = 2 },convert_rowtype = {convert = 0x1c8fc80,indesc = 0x1c8fcd8,
outdesc = 0x93d60c ,map = 0x2,初始化= false},scalararrayop = {element_type = 29949056,
useOr = falsee、typlen = 0、typbyval = 216、typalign = - 4 '\374'、finfo = 0x93d60c 、fcinfo_data = 0x2、
fn_addr = 0x0}、xmlexpr = {xexpr = 0x1c8fc80、named_argvalue = 0x1c8fcd8、 name_argnull = 0x93d60c
/> argvalue = 0x2、argnull = 0x0}、aggref = {astate = 0x1c8fc80}、grouping_func = {parent = 0x1c8fc80、
子句 = 0x1c8fcd8}、window_func = {wfstate = 0x1c8fc80},子计划= {sstate = 0x1c8fc80},alternative_subplan = {
asstate = 0x1c8fc80},agg_deserialize = {aggstate = 0x1c8fc80,fcinfo_data = 0x1c8fcd8,jumpnull = 9688588},
---类型 继续,或 q 退出---< br/> agg_strict_input_check = {nulls = 0x1c8fc80, nargs = 29949144, Jumpnull = 0}, agg_init_trans = {aggstate = 0x1c8fc80,
pertrans = 0x1c8fcd8, aggcontext = 0x93d60c ,setno = 2,transno = 0,setoff = 0,jumpnull = 0},
agg_strict_trans_check = {aggstate = 0x1c8fc80,setno = 29949144,transno = 0,setoff = 9688588,jumpnull = 0} ,
agg_trans = {aggstate = 0x1c8fc80,pertrans = 0x1c8fcd8,aggcontext = 0x93d60c ,setno = 2,transno = 0,
setoff = 0}}}
(gdb)

压入表达式列对应的数字,opcode = 14,即EEOP_ASSIGN_TMP

(gdb) n
463             scrap .d.assign_tmp.resultnum = tle->resno - 1;
(gdb)
464 ExprEvalPushStep(state, &scratch);
(gdb)
(gdb)
374 foreach(lc, targetList)
(gdb) p *state
$20 = {tag = {type = T_ExprState}, flags = 0 '\000', resnull = false, resvalue = 0, resultslot = 0x1c8f710,
步骤= 0x1c8f868,evalfunc = 0x0,expr = 0x1cc7550,evalfunc_private = 0x0,steps_len = 4,steps_alloc = 16,
父= 0x1c8f1f0,ext_params = 0x0,innermost_caseval = 0x0,innermost _case空 = 0x0,innermost_domainval = 0x0,
insidemost_domainnull = 0x0}
(gdb)p状态->步骤[3]
$21 = {操作码= 14,resvalue = 0x0,resnull = 0x0,d = {fetch = {last_var = 0,known_desc = 0x0},var = {attnum = 0,
vartype = 0}、wholerow = {var = 0x0、first = false、slow = false、tupdesc = 0x0、junkFilter = 0x0}、assign_var = {
 resultnum = 0、attnum = 0}、assign_tmp = {resultnum = 0}、constval = {value = 0、isnull = false}、func = {
finfo = 0x0、fcinfo_data = 0x0、fn_addr = 0x0、nargs = 0}、boolexpr = {anynull = 0x0、jumpdone = 0}、qualexpr = {
Jumpdone = 0}、jump = {jumpdone = 0}、nulltest_row = {argdesc = 0x0}、param = {paramid = 0、paramtype = 0}、cparam = {
paramfunc = 0x0、paramarg = 0x0、paramid = 0、paramtype = 0}、casetest = {value = 0x0、isnull = 0x0}、
make_readonly = {value = 0x0、isnull = 0x0 }、iocoerce = {finfo_out = 0x0, fcinfo_data_out = 0x0, finfo_in = 0x0,
   fcinfo_data_in = 0x0}, sqlvaluefunction = {svf = 0x0}, nextvalueexpr = {seqid = 0, seqtypid = 0}, arrayexpr = {
elemvalues​​ = 0x0、elemnulls = 0x0、nelems = 0、elemtype = 0、elemlength = 0、elembyval = false、elemalign = 0 '\000'、
multidims = false}、arraycoerce = {elemexprstate = 0x0,resultelemtype = 0,amstate = 0x0},row = {tupdesc = 0x0,
elemvalues = 0x0,elemnulls = 0x0},rowcompare_step = {finfo = 0x0,fcinfo_data = 0x0,fn_addr = 0x0, Jumpnull = 0, Jumpdone = 0}, rowcompare_final = {rctype = 0}, minmax = {values = 0x0, nulls = 0x0, nelems = 0, op = IS_GREATEST,
finfo = 0x0, fcinfo_data = 0x0},fieldselect = {fieldnum = 0,resulttype = 0,argdesc = 0x0},fieldstore = {
fstore = 0x0,argdesc = 0x0,值= 0x0,nulls = 0x0,ncolumns = 0} 、 arrayref_subscript = {state = 0x0、off = 0、
isupper = false、jumpdone = 0}、arrayref = {state = 0x0}、domaincheck = {constraintname = 0x0、checkvalue = 0x0、
checknull = 0x0,resulttype = 0},convert_rowtype = {convert = 0x0,indesc = 0x0,outdesc = 0x0,map = 0x0,
初始化= false},scalararrayop = {element_type = 0,useOr = false,typlen = 0, typbyval = false,
typalign = 0 '\000',finfo = 0x0,fcinfo_data = 0x0,fn_addr = 0x0},xmlexpr = {xexpr= 0x0,named_argvalue = 0x0,
named_argnull = 0x0,argvalue = 0x0,argnull = 0x0},aggref = {astate = 0x0},grouping_func = {parent = 0x0,
子句 = 0x0},window_func = {wfstate = 0x0},子计划 = {sstate = 0x0},alternative_subplan = {asstate = 0x0},
agg_deserialize = {aggstate = 0x0,fcinfo_data = 0x0,jumpnull = 0},agg_strict_input_check = {nulls = 0x0,nargs = 0,
Jumpnull = 0}, agg_init_trans = {aggstate = 0x0, pertrans = 0x0, aggcontext = 0x0, setno = 0, transno = 0,
setoff = 0, Jumpnull = 0}, agg_strict_trans_check = { aggstate = 0x0,setno = 0,transno = 0,setoff = 0,
jumpnull = 0},agg_trans = {aggstate = 0x0,pertrans = 0x0,aggcontext = 0x0,setno = 0,transno = 0,setoff = 0}}}
(gdb)

继续处理下一列,这是一个“安全”列,推动 EEOP_ASSIGN_SCAN_VAR 步骤

(gdb) n
376 TargetEntry *tle = lfirst_node(TargetEntry, lc);
(gdb)
377 Var *variable = NULL; < br/>(gdb) p*tle
$22 = {xpr = {type = T_TargetEntry},expr = 0x1c9aa40,resno = 2,resname = 0x1ba7a40“c2”,ressortgroupref = 0,
resorigtbl = 237600,resorigcol = 2,resjunk = false}
(gdb) n
378 AttrNumber attnum = 0;
(gdb)
379 BOOL ISSAFEVAR = FALSE;
(GDB)
389 if (TLE-> Expr!= Null &&
(GDB)
390 ISA (TLE-> EXPR , Var) &&
(gdb )
389 if (tle->expr != NULL &&
(gdb)
391 ((Var *) tle->expr)-> varattno > 0)
(gdb )
390 IsA(tle->expr, Var) &&
(gdb)
394 变量 = (Var *) tle->expr;
(gdb)
第395章num <= 输入描述->natts)
(gdb)
401        Form_pg_attribute attr = TupleDescAttr(inputDesc, attnum - 1 );
(gdb)
408 if (!attr->attisdropped && 变量->vartype == attr- >atttypid)
(gdb)
410 isSafeVar = true;
(gdb)
415EEOP_ASSIGN_SCAN_VAR;
(gdb)
435                         break;
(gdb)
439             scrap.d.assign_var.resultnum = tle->resno - 1;
(gdb)
440                                                                                                                                                                                       (gdb) p *state
$23 = {tag = {type = T_ExprState}, flags = 0 '\000', resnull = false, resvalue = 0,结果槽 = 0x1c8f710,
步骤= 0x1c8f868,evalfunc = 0x0,expr = 0x1cc7550,evalfunc_private = 0x0,steps_len = 4,steps_alloc = 16,
父= 0x1c8f1f0,ext_params = 0x0,innermost_caseval = 0x0,innermost_casenull = 0x0,innermost_domainval = 0x 0,
最里面的 _domainnull = 0x0 }
(gdb) n
374 foreach(lc, targetList)
(gdb) p *状态
$24 = {tag = {type = T_ExprState},flags = 0 '\ 000',resnull = false,resvalue = 0,resultslot = 0x1c8f710,
步骤 = 0x1c8f868,evalfunc = 0x0,expr = 0x1cc7550,evalfunc_private = 0x0,steps_len = 5,steps_alloc = 16,
父= 0x1c8f1 f0,ext_params = 0x0,innermost_caseval = 0x0,innermost_casenull = 0x0,innermost_domainval = 0x0,
innermost_domainnull = 0x0}
(gdb) p 状态->步骤[4]
$25 = {操作码 = 13,resvalue = 0x0,resnull = 0x0,d = {fetch = {last_var = 1,known_desc = 0x0},var = {attnum = 1,
vartype = 1},wholerow = {var = 0x100000001,first = false,slow = false,tupdesc = 0x0,junkFilter = 0x0},
allocate_var = {resultnum = 1,attnum = 1 }, allocate_tmp = {resultnum = 1}, constval = {value = 4294967297,
isnull = false}, func = {finfo = 0x100000001, fcinfo_data = 0x0, fn_addr = 0x0, nargs = 0}, boolexpr = {< br/> anynull = 0x100000001,jumpdone = 0},qualexpr = {jumpdone = 1},jump = {jumpdone = 1},nulltest_row = {
argdesc= 0x100000001},param = {paramid = 1,paramtype = 1},cparam = {paramfunc = 0x100000001,paramarg = 0x0,
paramid = 0,paramtype = 0},caset = {value = 0x100000001,isnull = 0x0 }, make_readonly = {value = 0x100000001,
isnull = 0x0}, iocoerce = {finfo_out = 0x100000001, fcinfo_data_out = 0x0, finfo_in = 0x0, fcinfo_ data_in = 0x0},
SqlvalueFunction = {svf = 0x1000 00001} , nextValueExpr = {seqid = 1, seqtypid = 1}, arrayExpr = {
Elemvalues = 0x100000001, Elemnulls = 0x0, nelems = 0, eLemtype = 0, Elemlength = 0, Elembyval = false,
elemalign = 0 '\000',multidims = false},arraycoerce = {elemexprstate = 0x100000001,resultelemtype = 0,
amstate = 0x0},row = {tupdesc = 0x100000001,elemvalues = 0x0,elemnulls = 0x0} 、 rowcompare_step = {
finfo = 0x100000001、fcinfo_data = 0x0、fn_addr = 0x0、jumpnull = 0、jumpdone = 0}、rowcompare_final = {
rctype = ROWCOMPARE_LT}、minmax = {values = 0x100000001、nulls = 0x0,nelems = 0,op = IS_GREATEST,finfo = 0x0,
fcinfo_data = 0x0},fieldselect = {fieldnum = 1,resulttype = 1,argdesc = 0x0},fieldstore = {fstore = 0x100000001,
argdesc = 0x0,值= 0x0, nulls = 0x0,ncolumns = 0},arrayref_subscript = {state = 0x100000001,off = 0,
isupper = false,jumpdone = 0},arrayref = {state = 0x100000001},domainCheck = {<<< Constraintname = 0x100000001 <地址0x100000001越界>,checkvalue = 0x0,checknull = 0x0,resulttype = 0},
convert_rowtype = {convert = 0x100000001,indesc = 0x0,outdesc = 0x0,map = 0x0,初始化 = false},
scalararrayop = {element_type = 1,useOr = true,typlen = 0,typbyval = false,typalign = 0 '\000',finfo = 0x0,
fcinfo_data = 0x0,fn_addr = 0x0},xmlexpr = {xexpr = 0x100000001,named_argvalue = 0x0,named_argnull = 0x0,
argvalue = 0x0,argnull = 0x0},aggref = {astate = 0x100000001},grouping_func = {parent = 0x100000001,
子句 = 0x0},window_func = {wfstate = 0x100000001},子计划 = {sstate = 0x100000001},alternative_subplan = {
as state = 0x100000001},agg_deserialize = {aggstate = 0x100000001,fcinfo_data = 0x0,jumpnull = 0},
agg_strict_input_check = {nulls = 0x100000001,nargs = 0,跳转空= 0}、agg_init_trans = {aggstate = 0x100000001、
pertrans = 0x0、aggcontext = 0x0、setno = 0、transno = 0、setoff = 0、jumpnull = 0}、agg_strict_trans_check = {
aggstate = 0x100000001 , setno = 0, transno = 0, setoff = 0, Jumpnull = 0}, agg_trans = {aggstate = 0x100000001,
---键入 继续,或 q 退出---< br/> pertrans = 0x0,aggcontext = 0x0,setno = 0,transno = 0,setoff = 0}}}
(gdb)

4.推送 EEOP_DONE 步骤

(gdb) n
468   scrap.opcode = EEOP_DONE;
(gdb)
469 ExprEvalPushStep(state, &scratch) ;
(gdb)
471 ExecReadyExpr(state);
(gdb) p state->steps[5]
$26 = {opcode = 0, resvalue = 0x0, resnull = 0x0,d = {获取 = {last_var = 1,known_desc = 0x0},var = {attnum = 1,vartype = 1},wholerow = {var = 0x100000001,first = false,slow = false,tupdesc = 0x0,junkFilter = 0x0},
allocate_var = {resultnum = 1,attnum = 1}、assign_tmp = {resultnum = 1}、constval = {值 = 4294967297、
isnull = false}、func = {finfo = 0x100000001、fcinfo_data = 0x0、fn_addr = 0x0、nargs = 0}、boolexpr = {
anynull = 0x100000001,jumpdone = 0},qualexpr = {jumpdone = 1},jump = {jumpdone = 1},nulltest_row = {
argdesc = 0x100000001},param = {paramid = 1,paramtype = 1}、cparam = {paramfunc = 0x100000001、paramarg = 0x0、
paramid =0、paramtype = 0}、casetest = {value = 0x100000001、isnull = 0x0}、make_readonly = {value = 0x100000001、
isnull = 0x0}, iocoerce = {finfo_out = 0x100000001, fcinfo_data_out = 0x0, finfo_ in = 0x0, fcinfo_data_in = 0x0},
sqlvaluefunction = {svf = 0x100000001}, nextvalueexpr = {seqid = 1, seqtypid = 1}, arrayexpr = {
elemvalues = 0x100000001, elemnulls = 0x0, nelems = 0, e lemtype = 0, elemlength = 0, elembyval = false,
elemalign = 0 '\000', multidims = false}, arraycoerce = {elemexprstate = 0x100000001, resultelemtype = 0,
amstate = 0x0}, row = { tupdesc = 0x100000001,elemvalues = 0x0,elemnulls = 0x0},rowcompare_step = {
finfo = 0x100000001,fcinfo_data = 0x0,fn_addr = 0x0,jumpnull = 0,jumpdone = 0},rowcompare_final = {
rctype = ROWCOMPARE_LT}, minmax = {values = 0x100000001, nulls = 0x0, nelems = 0, op =IS_GREATEST, finfo = 0x0,
fcinfo_data = 0x0}, fieldselect = {fieldnum = 1, resulttype = 1, argdesc = 0x0},fieldstore = {fstore = 0x100000001,
argdesc = 0x0,值= 0x0,nulls = 0x0,ncolumns = 0},arrayref_subscript = {state = 0x100000001,off = 0,
isupper = false,jumpdone=0},arrayref={state=0x100000001},domaincheck={
constraintname=0x100000001<地址0x100000001越界>,checkvalue=0x0,checknull=0x0,resulttype=0},
Convert_rowtype = {convert = 0x100000001,indesc = 0x0,outdesc = 0x0,map = 0x0,初始化 = false},
scalararrayop = {element_type = 1,useOr = true,typlen = 0,typbyval = false,typalign = 0 '\000',finfo = 0x0,
fcinfo_data = 0x0,fn_addr = 0x0},xmlexpr = {xexpr = 0x100000001,named_argvalue = 0x0,named_argnull = 0x0,
argvalue = 0x0,argnull = 0x0},aggref = {astate = 0x100000001},grouping_func = {父 = 0x100000001、
子句 = 0x0}、window_func = {wfstate = 0x100000001}、子计划 = {sstate = 0x100000001}、alternative_subplan = {
asstate = 0x100000001}、agg_deserialize = {aggstate = 0x1000000 01、fcinfo_data = 0x0,jumpnull = 0},
agg_strict_input_check = {nulls = 0x100000001,nargs = 0,jumpnull = 0},agg_init_trans = {aggstate = 0x100000001,
 pertrans = 0x0,aggcontext = 0x0,setno = 0, transno = 0,setoff = 0,jumpnull = 0},agg_strict_trans_check = {
 aggstate = 0x100000001,setno = 0,transno = 0,setoff = 0,jumpnull = 0},agg_trans = {aggstate = 0x100000001,
---输入继续,或 q 退出---
pertrans = 0x0, aggcontext = 0x0 , setno = 0, transno = 0, setoff = 0}}}
(gdb)

结束调用

(gdb) n
473 return projInfo;
(gdb) < br/>474 }
(gdb)
ExecAssignProjectionInfo (planstate=0x1c8f1f0, inputDesc=0x7f8386bb6ab8) at execUtils.c:467
467 planstate ->ps_ProjInfo =
(gdb)< br/>

以上就是《PostgreSQL如何构建表达式解析》一文的全部内容,感谢大家的阅读!希望分享的内容对大家有所帮助。更多相关知识,欢迎关注行业资讯频道!

1. 本站所有资源来源于用户上传或网络,仅作为参考研究使用,如有侵权请邮件联系站长!
2. 本站积分货币获取途径以及用途的解读,想在本站混的好,请务必认真阅读!
3. 本站强烈打击盗版/破解等有损他人权益和违法作为,请各位会员支持正版!
4. 编程技术 > PostgreSQL 如何构建表达式解析

用户评论