PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值
这篇文章主要介绍PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
表达式列是指除关系定义中的系统列/定义列之外的其他投影列.比如:
testdb=# create table t_expr(id int);
CREATE TABLE
testdb=# insert into t_expr values(1);
INSERT 0 1
testdb=# insert into t_expr values(2);
INSERT 0 1
testdb=# alter table t_expr add column c2 varchar(20);
ALTER TABLE
testdb=# insert into t_expr(id,c2) select x,'c2'||x from generate_series(3,100000) as x;
INSERT 0 99998
testdb=# select 1+id from t_expr;
该SQL语句中的”1+id”投影列视为表达式列.
一、数据结构
EEO_XXX宏定义
opcode分发器宏定义
#if defined(EEO_USE_COMPUTED_GOTO)
//--------------- 定义了EEO_USE_COMPUTED_GOTO
//跳转target -> opcode搜索表结构体
typedef struct ExprEvalOpLookup
{
const void *opcode;
ExprEvalOp op;
} ExprEvalOpLookup;
static const void **dispatch_table = NULL;
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
#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
#define EEO_NEXT() \
do { \
op++; \
EEO_DISPATCH(); \
} while (0)
#define EEO_JUMP(stepno) \
do { \
op = &state->steps[stepno]; \
EEO_DISPATCH(); \
} while (0)
ExprState
解析表达式中运行期状态节点
#define EEO_FLAG_IS_QUAL (1 << 0)
typedef struct ExprState
{
//节点tag
Node tag;
//EEO_FLAG_IS_QUAL
uint8 flags;
#define FIELDNO_EXPRSTATE_RESNULL 2
bool resnull;
#define FIELDNO_EXPRSTATE_RESVALUE 3
Datum resvalue;
#define FIELDNO_EXPRSTATE_RESULTSLOT 4
TupleTableSlot *resultslot;
struct ExprEvalStep *steps;
ExprStateEvalFunc evalfunc;
//原始的表达式树,仅用于debugging
Expr *expr;
//evalfunc的私有状态
void *evalfunc_private;
//当前的步数
int steps_len;
//steps数组已分配的长度
int steps_alloc;
//父PlanState节点(如存在)
struct PlanState *parent;
//用于编译PARAM_EXTERN节点
ParamListInfo ext_params;
//
Datum *innermost_caseval;
bool *innermost_casenull;
Datum *innermost_domainval;
bool *innermost_domainnull;
} ExprState;
ExprEvalStep
表达式解析步骤结构体
typedef struct ExprEvalStep
{
intptr_t opcode;
//存储该步骤的结果
Datum *resvalue;
bool *resnull;
union
{
//用于EEOP_INNER/OUTER/SCAN_FETCHSOME
struct
{
//获取到的属性编号
int last_var;
TupleDesc known_desc;
} fetch;
struct
{
//attnum是常规VAR的attr number - 1
//对于SYSVAR,该值是常规的attr number
int attnum;
Oid vartype;
} var;
struct
{
Var *var;
bool first;
bool slow;
TupleDesc tupdesc;
JunkFilter *junkFilter;
} wholerow;
struct
{
int resultnum;
int attnum;
} assign_var;
struct
{
int resultnum;
} assign_tmp;
struct
{
Datum value;
bool isnull;
} constval;
//对于EEOP_FUNCEXPR_* / NULLIF / DISTINCT
struct
{
//函数的检索数据
FmgrInfo *finfo;
//参数信息等
FunctionCallInfo fcinfo_data;
//无需额外的指向,更快速的访问
PGFunction fn_addr;
int nargs;
} func;
struct
{
bool *anynull;
int jumpdone;
} boolexpr;
struct
{
int jumpdone;
} qualexpr;
struct
{
int jumpdone;
} jump;
struct
{
TupleDesc argdesc;
} nulltest_row;
struct
{
int paramid;
Oid paramtype;
} param;
struct
{
ExecEvalSubroutine paramfunc;
void *paramarg;
int paramid;
Oid paramtype;
} cparam;
struct
{
Datum *value;
bool *isnull;
} casetest;
struct
{
Datum *value;
bool *isnull;
} make_readonly;
struct
{
FmgrInfo *finfo_out;
FunctionCallInfo fcinfo_data_out;
FmgrInfo *finfo_in;
FunctionCallInfo fcinfo_data_in;
} iocoerce;
struct
{
SQLValueFunction *svf;
} sqlvaluefunction;
//EEOP_NEXTVALUEEXPR
struct
{
Oid seqid;
Oid seqtypid;
} nextvalueexpr;
struct
{
Datum *elemvalues;
bool *elemnulls;
int nelems;
Oid elemtype;
int16 elemlength;
bool elembyval;
char elemalign;
bool multidims;
} arrayexpr;
struct
{
ExprState *elemexprstate;
Oid resultelemtype;
struct ArrayMapState *amstate;
} arraycoerce;
struct
{
TupleDesc tupdesc;
Datum *elemvalues;
bool *elemnulls;
} row;
struct
{
FmgrInfo *finfo;
FunctionCallInfo fcinfo_data;
PGFunction fn_addr;
int jumpnull;
int jumpdone;
} rowcompare_step;
struct
{
RowCompareType rctype;
} rowcompare_final;
struct
{
Datum *values;
bool *nulls;
int nelems;
MinMaxOp op;
FmgrInfo *finfo;
FunctionCallInfo fcinfo_data;
} minmax;
struct
{
AttrNumber fieldnum;
Oid resulttype;
TupleDesc argdesc;
} fieldselect;
struct
{
FieldStore *fstore;
TupleDesc *argdesc;
Datum *values;
bool *nulls;
int ncolumns;
} fieldstore;
struct
{
struct ArrayRefState *state;
int off;
bool isupper;
int jumpdone;
} arrayref_subscript;
struct
{
struct ArrayRefState *state;
} arrayref;
struct
{
char *constraintname;
Datum *checkvalue;
bool *checknull;
Oid resulttype;
} domaincheck;
struct
{
ConvertRowtypeExpr *convert;
TupleDesc indesc;
TupleDesc outdesc;
TupleConversionMap *map;
bool initialized;
} convert_rowtype;
struct
{
Oid element_type;
bool useOr;
int16 typlen;
bool typbyval;
char typalign;
FmgrInfo *finfo;
FunctionCallInfo fcinfo_data;
PGFunction fn_addr;
} scalararrayop;
struct
{
XmlExpr *xexpr;
Datum *named_argvalue;
bool *named_argnull;
Datum *argvalue;
bool *argnull;
} xmlexpr;
struct
{
AggrefExprState *astate;
} aggref;
struct
{
AggState *parent;
List *clauses;
} grouping_func;
struct
{
WindowFuncExprState *wfstate;
} window_func;
struct
{
SubPlanState *sstate;
} subplan;
struct
{
AlternativeSubPlanState *asstate;
} alternative_subplan;
struct
{
AggState *aggstate;
FunctionCallInfo fcinfo_data;
int jumpnull;
} agg_deserialize;
struct
{
bool *nulls;
int nargs;
int jumpnull;
} agg_strict_input_check;
struct
{
AggState *aggstate;
AggStatePerTrans pertrans;
ExprContext *aggcontext;
int setno;
int transno;
int setoff;
int jumpnull;
} agg_init_trans;
struct
{
AggState *aggstate;
int setno;
int transno;
int setoff;
int jumpnull;
} agg_strict_trans_check;
struct
{
AggState *aggstate;
AggStatePerTrans pertrans;
ExprContext *aggcontext;
int setno;
int transno;
int setoff;
} agg_trans;
} d;
} ExprEvalStep;
ExprEvalOp
ExprEvalSteps的鉴频器,定义哪个操作将被执行并且联合体ExprEvalStep->d中的哪个struct将被使用.
typedef enum ExprEvalOp
{
//整个表达式已被解析,返回
EEOP_DONE,
//在相应的元组slot上应用了slot_getsomeattrs方法
EEOP_INNER_FETCHSOME,
EEOP_OUTER_FETCHSOME,
EEOP_SCAN_FETCHSOME,
//计算非系统Var变量值
EEOP_INNER_VAR,
EEOP_OUTER_VAR,
EEOP_SCAN_VAR,
//计算系统Var变量值
EEOP_INNER_SYSVAR,
EEOP_OUTER_SYSVAR,
EEOP_SCAN_SYSVAR,
//计算整行Var
EEOP_WHOLEROW,
EEOP_ASSIGN_INNER_VAR,
EEOP_ASSIGN_OUTER_VAR,
EEOP_ASSIGN_SCAN_VAR,
//分配ExprState's resvalue/resnull到该列的resultslot中
EEOP_ASSIGN_TMP,
//同上,应用MakeExpandedObjectReadOnly()
EEOP_ASSIGN_TMP_MAKE_RO,
//解析常量值
EEOP_CONST,
EEOP_FUNCEXPR,
EEOP_FUNCEXPR_STRICT,
EEOP_FUNCEXPR_FUSAGE,
EEOP_FUNCEXPR_STRICT_FUSAGE,
EEOP_BOOL_AND_STEP_FIRST,
EEOP_BOOL_AND_STEP,
EEOP_BOOL_AND_STEP_LAST,
//与布尔OR表达式类似
EEOP_BOOL_OR_STEP_FIRST,
EEOP_BOOL_OR_STEP,
EEOP_BOOL_OR_STEP_LAST,
//解析布尔NOT表达式
EEOP_BOOL_NOT_STEP,
//用于ExecQual()中的BOOL_AND_STEP简化版本
EEOP_QUAL,
//无条件跳转到另外一个步骤
EEOP_JUMP,
//基于当前结果值的条件跳转
EEOP_JUMP_IF_NULL,
EEOP_JUMP_IF_NOT_NULL,
EEOP_JUMP_IF_NOT_TRUE,
//为scalar值执行NULL测试
EEOP_NULLTEST_ISNULL,
EEOP_NULLTEST_ISNOTNULL,
//为行值执行NULL测试
EEOP_NULLTEST_ROWISNULL,
EEOP_NULLTEST_ROWISNOTNULL,
//解析BooleanTest表达式
EEOP_BOOLTEST_IS_TRUE,
EEOP_BOOLTEST_IS_NOT_TRUE,
EEOP_BOOLTEST_IS_FALSE,
EEOP_BOOLTEST_IS_NOT_FALSE,
//解析PARAM_EXEC/EXTERN参数
EEOP_PARAM_EXEC,
EEOP_PARAM_EXTERN,
EEOP_PARAM_CALLBACK,
//返回CaseTestExpr值
EEOP_CASE_TESTVAL,
//对目标值应用MakeExpandedObjectReadOnly()
EEOP_MAKE_READONLY,
//解析各种特殊用途的表达式类型
EEOP_IOCOERCE,
EEOP_DISTINCT,
EEOP_NOT_DISTINCT,
EEOP_NULLIF,
EEOP_SQLVALUEFUNCTION,
EEOP_CURRENTOFEXPR,
EEOP_NEXTVALUEEXPR,
EEOP_ARRAYEXPR,
EEOP_ARRAYCOERCE,
EEOP_ROW,
EEOP_ROWCOMPARE_STEP,
//基于上一步的ROWCOMPARE_STEP操作解析布尔值
EEOP_ROWCOMPARE_FINAL,
//解析GREATEST()和LEAST()
EEOP_MINMAX,
//解析FieldSelect表达式
EEOP_FIELDSELECT,
EEOP_FIELDSTORE_DEFORM,
EEOP_FIELDSTORE_FORM,
//处理数组子脚本.如为NULL则短路表达式为NULL
EEOP_ARRAYREF_SUBSCRIPT,
EEOP_ARRAYREF_OLD,
//为ArrayRef分配118
EEOP_ARRAYREF_ASSIGN,
//为ArrayRef提取表达式计算element/slice
EEOP_ARRAYREF_FETCH,
//为CoerceToDomainValue解析值
EEOP_DOMAIN_TESTVAL,
//解析域 NOT NULL 约束
EEOP_DOMAIN_NOTNULL,
//解析单个域CHECK约束
EEOP_DOMAIN_CHECK,
//解析特殊目的的表达式类型
EEOP_CONVERT_ROWTYPE,
EEOP_SCALARARRAYOP,
EEOP_XMLEXPR,
EEOP_AGGREF,
EEOP_GROUPING_FUNC,
EEOP_WINDOW_FUNC,
EEOP_SUBPLAN,
EEOP_ALTERNATIVE_SUBPLAN,
//聚合相关节点
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,
//不存在的操作,比如用于检测数组长度
EEOP_LAST
} ExprEvalOp;
二、源码解读
ExecInterpExpr函数是实现表达式列解析的主函数,解析给定”econtext”在执行上下文中通过”state”标识的表达式.
其主要实现逻辑是根据ExprState->opcode(ExprState的初始化后续再行介绍)指定的操作指定,调整到相应的实现逻辑中,执行完毕调到下一个步骤直至到达EEOP_DONE,即完成所有步骤.
static Datum
ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
{
ExprEvalStep *op;
TupleTableSlot *resultslot;
TupleTableSlot *innerslot;
TupleTableSlot *outerslot;
TupleTableSlot *scanslot;
#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
//配置状态变量
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)
{
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;
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;
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;
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;
Assert(innerslot->tts_tuple != NULL);
Assert(innerslot->tts_tuple != &(innerslot->tts_minhdr));
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;
Assert(outerslot->tts_tuple != NULL);
Assert(outerslot->tts_tuple != &(outerslot->tts_minhdr));
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;
Assert(scanslot->tts_tuple != NULL);
Assert(scanslot->tts_tuple != &(scanslot->tts_minhdr));
d = heap_getsysattr(scanslot->tts_tuple, attnum,
scanslot->tts_tupleDescriptor,
op->resnull);
*op->resvalue = d;
EEO_NEXT();
}
EEO_CASE(EEOP_WHOLEROW)
{
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;
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;
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;
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();
}
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;
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)
{
ExecEvalFuncExprFusage(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
{
ExecEvalFuncExprStrictFusage(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
{
*op->d.boolexpr.anynull = false;
}
EEO_CASE(EEOP_BOOL_AND_STEP)
{
if (*op->resnull)
{
*op->d.boolexpr.anynull = true;
}
else if (!DatumGetBool(*op->resvalue))
{
EEO_JUMP(op->d.boolexpr.jumpdone);
}
EEO_NEXT();
}
EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
{
if (*op->resnull)
{
}
else if (!DatumGetBool(*op->resvalue))
{
}
else if (*op->d.boolexpr.anynull)
{
*op->resvalue = (Datum) 0;
*op->resnull = true;
}
else
{
}
EEO_NEXT();
}
EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
{
*op->d.boolexpr.anynull = false;
}
EEO_CASE(EEOP_BOOL_OR_STEP)
{
if (*op->resnull)
{
*op->d.boolexpr.anynull = true;
}
else if (DatumGetBool(*op->resvalue))
{
EEO_JUMP(op->d.boolexpr.jumpdone);
}
EEO_NEXT();
}
EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
{
if (*op->resnull)
{
}
else if (DatumGetBool(*op->resvalue))
{
}
else if (*op->d.boolexpr.anynull)
{
*op->resvalue = (Datum) 0;
*op->resnull = true;
}
else
{
}
EEO_NEXT();
}
EEO_CASE(EEOP_BOOL_NOT_STEP)
{
*op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
EEO_NEXT();
}
EEO_CASE(EEOP_QUAL)
{
if (*op->resnull ||
!DatumGetBool(*op->resvalue))
{
*op->resnull = false;
*op->resvalue = BoolGetDatum(false);
EEO_JUMP(op->d.qualexpr.jumpdone);
}
EEO_NEXT();
}
EEO_CASE(EEOP_JUMP)
{
EEO_JUMP(op->d.jump.jumpdone);
}
EEO_CASE(EEOP_JUMP_IF_NULL)
{
if (*op->resnull)
EEO_JUMP(op->d.jump.jumpdone);
EEO_NEXT();
}
EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
{
if (!*op->resnull)
EEO_JUMP(op->d.jump.jumpdone);
EEO_NEXT();
}
EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
{
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)
{
ExecEvalRowNull(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
{
ExecEvalRowNotNull(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
{
if (*op->resnull)
{
*op->resvalue = BoolGetDatum(false);
*op->resnull = false;
}
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;
}
EEO_NEXT();
}
EEO_CASE(EEOP_PARAM_EXEC)
{
ExecEvalParamExec(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_PARAM_EXTERN)
{
ExecEvalParamExtern(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_PARAM_CALLBACK)
{
op->d.cparam.paramfunc(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_CASE_TESTVAL)
{
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)
{
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)
{
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)
{
char *str;
if (*op->resnull)
{
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));
Assert(!fcinfo_out->isnull);
}
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;
fcinfo_in->isnull = false;
d = FunctionCallInvoke(fcinfo_in);
*op->resvalue = d;
if (str == NULL)
{
Assert(*op->resnull);
Assert(fcinfo_in->isnull);
}
else
{
Assert(!*op->resnull);
Assert(!fcinfo_in->isnull);
}
}
EEO_NEXT();
}
EEO_CASE(EEOP_DISTINCT)
{
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
if (fcinfo->argnull[0] && fcinfo->argnull[1])
{
*op->resvalue = BoolGetDatum(false);
*op->resnull = false;
}
else if (fcinfo->argnull[0] || fcinfo->argnull[1])
{
*op->resvalue = BoolGetDatum(true);
*op->resnull = false;
}
else
{
Datum eqresult;
fcinfo->isnull = false;
eqresult = op->d.func.fn_addr(fcinfo);
*op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
*op->resnull = fcinfo->isnull;
}
EEO_NEXT();
}
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)
{
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
if (!fcinfo->argnull[0] && !fcinfo->argnull[1])
{
Datum result;
fcinfo->isnull = false;
result = op->d.func.fn_addr(fcinfo);
if (!fcinfo->isnull && DatumGetBool(result))
{
*op->resvalue = (Datum) 0;
*op->resnull = true;
EEO_NEXT();
}
}
*op->resvalue = fcinfo->arg[0];
*op->resnull = fcinfo->argnull[0];
EEO_NEXT();
}
EEO_CASE(EEOP_SQLVALUEFUNCTION)
{
ExecEvalSQLValueFunction(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_CURRENTOFEXPR)
{
ExecEvalCurrentOfExpr(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_NEXTVALUEEXPR)
{
ExecEvalNextValueExpr(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_ARRAYEXPR)
{
ExecEvalArrayExpr(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_ARRAYCOERCE)
{
ExecEvalArrayCoerce(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_ROW)
{
ExecEvalRow(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_ROWCOMPARE_STEP)
{
FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
Datum d;
if (op->d.rowcompare_step.finfo->fn_strict &&
(fcinfo->argnull[0] || fcinfo->argnull[1]))
{
*op->resnull = true;
EEO_JUMP(op->d.rowcompare_step.jumpnull);
}
fcinfo->isnull = false;
d = op->d.rowcompare_step.fn_addr(fcinfo);
*op->resvalue = d;
if (fcinfo->isnull)
{
*op->resnull = true;
EEO_JUMP(op->d.rowcompare_step.jumpnull);
}
*op->resnull = false;
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)
{
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)
{
ExecEvalMinMax(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_FIELDSELECT)
{
ExecEvalFieldSelect(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_FIELDSTORE_DEFORM)
{
ExecEvalFieldStoreDeForm(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_FIELDSTORE_FORM)
{
ExecEvalFieldStoreForm(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT)
{
if (ExecEvalArrayRefSubscript(state, op))
{
EEO_NEXT();
}
else
{
EEO_JUMP(op->d.arrayref_subscript.jumpdone);
}
}
EEO_CASE(EEOP_ARRAYREF_OLD)
{
ExecEvalArrayRefOld(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_ARRAYREF_ASSIGN)
{
ExecEvalArrayRefAssign(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_ARRAYREF_FETCH)
{
ExecEvalArrayRefFetch(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_CONVERT_ROWTYPE)
{
ExecEvalConvertRowtype(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_SCALARARRAYOP)
{
ExecEvalScalarArrayOp(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_DOMAIN_NOTNULL)
{
ExecEvalConstraintNotNull(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_DOMAIN_CHECK)
{
ExecEvalConstraintCheck(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_XMLEXPR)
{
ExecEvalXmlExpr(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_AGGREF)
{
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)
{
ExecEvalGroupingFunc(state, op);
EEO_NEXT();
}
EEO_CASE(EEOP_WINDOW_FUNC)
{
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)
{
ExecEvalSubPlan(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN)
{
ExecEvalAlternativeSubPlan(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
{
bool *argnull = op->d.agg_deserialize.fcinfo_data->argnull;
if (argnull[0])
EEO_JUMP(op->d.agg_deserialize.jumpnull);
}
EEO_CASE(EEOP_AGG_DESERIALIZE)
{
FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
AggState *aggstate = op->d.agg_deserialize.aggstate;
MemoryContext oldContext;
oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
fcinfo->isnull = false;
*op->resvalue = FunctionCallInvoke(fcinfo);
*op->resnull = fcinfo->isnull;
MemoryContextSwitchTo(oldContext);
EEO_NEXT();
}
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();
}
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 (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);
EEO_JUMP(op->d.agg_init_trans.jumpnull);
}
EEO_NEXT();
}
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();
}
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;
aggstate->curaggcontext = op->d.agg_trans.aggcontext;
aggstate->current_set = op->d.agg_trans.setno;
aggstate->curpertrans = pertrans;
oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
fcinfo->arg[0] = pergroup->transValue;
fcinfo->argnull[0] = pergroup->transValueIsNull;
fcinfo->isnull = false;
newVal = FunctionCallInvoke(fcinfo);
pergroup->transValue = newVal;
pergroup->transValueIsNull = fcinfo->isnull;
MemoryContextSwitchTo(oldContext);
EEO_NEXT();
}
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;
aggstate->curaggcontext = op->d.agg_trans.aggcontext;
aggstate->current_set = op->d.agg_trans.setno;
aggstate->curpertrans = pertrans;
oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
fcinfo->arg[0] = pergroup->transValue;
fcinfo->argnull[0] = pergroup->transValueIsNull;
fcinfo->isnull = false;
newVal = FunctionCallInvoke(fcinfo);
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();
}
EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM)
{
ExecEvalAggOrderedTransDatum(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE)
{
ExecEvalAggOrderedTransTuple(state, op, econtext);
EEO_NEXT();
}
EEO_CASE(EEOP_LAST)
{
Assert(false);
goto out;
}
}
out:
*isnull = state->resnull;
return state->resvalue;
}
三、跟踪分析
测试脚本
testdb=# alter table t_expr add primary key(id);
ALTER TABLE
testdb=# 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 ../../../class="lazy" data-src/include/executor/executor.h:313
#3 0x00000000006e1fe8 in ExecProject (projInfo=0x1e6baa0) at ../../../class="lazy" data-src/include/executor/executor.h:347
#4 0x00000000006e2358 in ExecScan (node=0x1e6b5c0, accessMtd=0x7103a9 <SeqNext>, recheckMtd=0x710474 <SeqRecheck>)
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 ../../../class="lazy" data-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 <return> to continue, or q <return> 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:402
402 if (unlikely(state == NULL))
(gdb) c
Continuing.
Breakpoint 1, ExecInterpExpr (state=0x1e67678, econtext=0x1e672a8, isnull=0x7fffdbc3b877) at execExprInterp.c:402
402 if (unlikely(state == NULL))
获取步骤数组和相关的slot
(gdb) n
409 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) n
413 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) n
443 slot_getsomeattrs(scanslot, op->d.fetch.last_var);
(gdb) n
445 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 <repeats 98 times>}, argnull = {false <repeats 100 times>}}
(gdb) p *fcinfo->flinfo
$25 = {fn_addr = 0x93d60c <int4pl>, 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) n
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)
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) n
608 EEO_NEXT();
跳转到下一个步骤,EEO_DONE(STEP 5)
(gdb)
423 goto out;
退出,返回结果值
(gdb) n
1764 *isnull = state->resnull;
(gdb)
1765 return state->resvalue;
(gdb)
1766 }
(gdb)
ExecInterpExprStillValid (state=0x1e67678, econtext=0x1e672a8, isNull=0x7fffdbc3b877) at execExprInterp.c:1787
1787 }
(gdb) c
Continuing.
以上是“PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341