这篇文章主要为大家展示了“PostgreSQL中表达式预处理主要的函数有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“PostgreSQL中表达式预处理主要的函数有哪些”这篇文章吧。
表达式预处理主要的函数主要有preprocess_expression和preprocess_qual_conditions(调用preprocess_expression),在文件src/backend/optimizer/plan/planner.c中。preprocess_expression调用了eval_const_expressions,该函数调用了mutator函数通过遍历的方式对表达式进行处理。
一、基本概念
PG源码对简化表达式的注释如下:
比如表达式1 + 2,直接求解得到3;x OR true,直接求解得到true而无需理会x的值,类似的x AND false直接求解得到false而无需理会x的值.
不过,这里的简化只是执行了基础分析,并没有做深入分析:
testdb=# explain verbose select max(a.dwbh::int+(1+2)) from t_dwxx a;
QUERY PLAN
-------------------------------------------------------------------------
Aggregate (cost=13.20..13.21 rows=1 width=4)
Output: max(((dwbh)::integer + 3))
-> Seq Scan on public.t_dwxx a (cost=0.00..11.60 rows=160 width=38)
Output: dwmc, dwbh, dwdz
(4 rows)
testdb=# explain verbose select max(a.dwbh::int+1+2) from t_dwxx a;
QUERY PLAN
-------------------------------------------------------------------------
Aggregate (cost=13.60..13.61 rows=1 width=4)
Output: max((((dwbh)::integer + 1) + 2))
-> Seq Scan on public.t_dwxx a (cost=0.00..11.60 rows=160 width=38)
Output: dwmc, dwbh, dwdz
(4 rows)
见上测试脚本,如(1+2),把括号去掉,a.dwbh先跟1运算,再跟2运算,没有执行简化.
二、源码解读
主函数入口:
subquery_planner
PlannerInfo *
subquery_planner(PlannerGlobal *glob, Query *parse,
PlannerInfo *parent_root,
bool hasRecursion, double tuple_fraction)
{
PlannerInfo *root;//返回值
List *newWithCheckOptions;//
List *newHaving;//Having子句
bool hasOuterJoins;//是否存在Outer Join?
RelOptInfo *final_rel;//
ListCell *l;//临时变量
root = makeNode(PlannerInfo);//构造返回值
root->parse = parse;
root->glob = glob;
root->query_level = parent_root ? parent_root->query_level + 1 : 1;
root->parent_root = parent_root;
root->plan_params = NIL;
root->outer_params = NULL;
root->planner_cxt = CurrentMemoryContext;
root->init_plans = NIL;
root->cte_plan_ids = NIL;
root->multiexpr_params = NIL;
root->eq_classes = NIL;
root->append_rel_list = NIL;
root->rowMarks = NIL;
memset(root->upper_rels, 0, sizeof(root->upper_rels));
memset(root->upper_targets, 0, sizeof(root->upper_targets));
root->processed_tlist = NIL;
root->grouping_map = NULL;
root->minmax_aggs = NIL;
root->qual_security_level = 0;
root->inhTargetKind = INHKIND_NONE;
root->hasRecursion = hasRecursion;
if (hasRecursion)
root->wt_param_id = SS_assign_special_param(root);
else
root->wt_param_id = -1;
root->non_recursive_path = NULL;
root->partColsUpdated = false;
if (parse->cteList)
SS_process_ctes(root);//处理With 语句
if (parse->hasSubLinks)
pull_up_sublinks(root); //上拉子链接
inline_set_returning_functions(root);//
pull_up_subqueries(root);//上拉子查询
if (parse->setOperations)
flatten_simple_union_all(root);//扁平化处理UNION ALL
//判断RTE中是否存在RTE_JOIN?
root->hasJoinRTEs = false;
root->hasLateralRTEs = false;
hasOuterJoins = false;
foreach(l, parse->rtable)
{
RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
if (rte->rtekind == RTE_JOIN)
{
root->hasJoinRTEs = true;
if (IS_OUTER_JOIN(rte->jointype))
hasOuterJoins = true;
}
if (rte->lateral)
root->hasLateralRTEs = true;
}
//预处理RowMark信息
preprocess_rowmarks(root);
//展开继承表
expand_inherited_tables(root);
//是否存在Having表达式
root->hasHavingQual = (parse->havingQual != NULL);
root->hasPseudoConstantQuals = false;
//预处理表达式:targetList(投影列)
parse->targetList = (List *)
preprocess_expression(root, (Node *) parse->targetList,
EXPRKIND_TARGET);
if (parse->hasTargetSRFs)
parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList);
newWithCheckOptions = NIL;
foreach(l, parse->withCheckOptions)//witch Check Options
{
WithCheckOption *wco = lfirst_node(WithCheckOption, l);
wco->qual = preprocess_expression(root, wco->qual,
EXPRKIND_QUAL);
if (wco->qual != NULL)
newWithCheckOptions = lappend(newWithCheckOptions, wco);
}
parse->withCheckOptions = newWithCheckOptions;
//返回列信息returningList
parse->returningList = (List *)
preprocess_expression(root, (Node *) parse->returningList,
EXPRKIND_TARGET);
//预处理条件表达式
preprocess_qual_conditions(root, (Node *) parse->jointree);
//预处理Having表达式
parse->havingQual = preprocess_expression(root, parse->havingQual,
EXPRKIND_QUAL);
//窗口函数
foreach(l, parse->windowClause)
{
WindowClause *wc = lfirst_node(WindowClause, l);
wc->startOffset = preprocess_expression(root, wc->startOffset,
EXPRKIND_LIMIT);
wc->endOffset = preprocess_expression(root, wc->endOffset,
EXPRKIND_LIMIT);
}
//Limit子句
parse->limitOffset = preprocess_expression(root, parse->limitOffset,
EXPRKIND_LIMIT);
parse->limitCount = preprocess_expression(root, parse->limitCount,
EXPRKIND_LIMIT);
//On Conflict子句
if (parse->onConflict)
{
parse->onConflict->arbiterElems = (List *)
preprocess_expression(root,
(Node *) parse->onConflict->arbiterElems,
EXPRKIND_ARBITER_ELEM);
parse->onConflict->arbiterWhere =
preprocess_expression(root,
parse->onConflict->arbiterWhere,
EXPRKIND_QUAL);
parse->onConflict->onConflictSet = (List *)
preprocess_expression(root,
(Node *) parse->onConflict->onConflictSet,
EXPRKIND_TARGET);
parse->onConflict->onConflictWhere =
preprocess_expression(root,
parse->onConflict->onConflictWhere,
EXPRKIND_QUAL);
}
//集合操作(AppendRelInfo)
root->append_rel_list = (List *)
preprocess_expression(root, (Node *) root->append_rel_list,
EXPRKIND_APPINFO);
//RTE
foreach(l, parse->rtable)
{
RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
int kind;
ListCell *lcsq;
if (rte->rtekind == RTE_RELATION)
{
if (rte->tablesample)
rte->tablesample = (TableSampleClause *)
preprocess_expression(root,
(Node *) rte->tablesample,
EXPRKIND_TABLESAMPLE);//数据表采样语句
}
else if (rte->rtekind == RTE_SUBQUERY)//子查询
{
if (rte->lateral && root->hasJoinRTEs)
rte->subquery = (Query *)
flatten_join_alias_vars(root, (Node *) rte->subquery);
}
else if (rte->rtekind == RTE_FUNCTION)//函数
{
kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC;
rte->functions = (List *)
preprocess_expression(root, (Node *) rte->functions, kind);
}
else if (rte->rtekind == RTE_TABLEFUNC)//TABLE FUNC
{
kind = rte->lateral ? EXPRKIND_TABLEFUNC_LATERAL : EXPRKIND_TABLEFUNC;
rte->tablefunc = (TableFunc *)
preprocess_expression(root, (Node *) rte->tablefunc, kind);
}
else if (rte->rtekind == RTE_VALUES)//VALUES子句
{
kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES;
rte->values_lists = (List *)
preprocess_expression(root, (Node *) rte->values_lists, kind);
}
foreach(lcsq, rte->securityQuals)
{
lfirst(lcsq) = preprocess_expression(root,
(Node *) lfirst(lcsq),
EXPRKIND_QUAL);
}
}
...//其他
return root;
}
preprocess_expression
static Node *
preprocess_expression(PlannerInfo *root, Node *expr, int kind)
{
if (expr == NULL)
return NULL;
if (root->hasJoinRTEs &&
!(kind == EXPRKIND_RTFUNC ||
kind == EXPRKIND_VALUES ||
kind == EXPRKIND_TABLESAMPLE ||
kind == EXPRKIND_TABLEFUNC))
expr = flatten_join_alias_vars(root, expr);//扁平化处理joinaliasvars,上节已介绍
expr = eval_const_expressions(root, expr);//简化常量表达式
if (kind == EXPRKIND_QUAL)
{
expr = (Node *) canonicalize_qual((Expr *) expr, false);//表达式规约,下节介绍
#ifdef OPTIMIZER_DEBUG
printf("After canonicalize_qual()\n");
pprint(expr);
#endif
}
if (root->parse->hasSubLinks)//扩展子链接为子计划
expr = SS_process_sublinks(root, expr, (kind == EXPRKIND_QUAL));
if (root->query_level > 1)
expr = SS_replace_correlation_vars(root, expr);//使用Param节点替换上层的Vars
if (kind == EXPRKIND_QUAL)
expr = (Node *) make_ands_implicit((Expr *) expr);
return expr;
}
preprocess_qual_conditions
static void
preprocess_qual_conditions(PlannerInfo *root, Node *jtnode)
{
if (jtnode == NULL)
return;
if (IsA(jtnode, RangeTblRef))
{
}
else if (IsA(jtnode, FromExpr))
{
FromExpr *f = (FromExpr *) jtnode;
ListCell *l;
foreach(l, f->fromlist)
preprocess_qual_conditions(root, lfirst(l));//递归调用
f->quals = preprocess_expression(root, f->quals, EXPRKIND_QUAL);
}
else if (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
preprocess_qual_conditions(root, j->larg);//递归调用
preprocess_qual_conditions(root, j->rarg);//递归调用
j->quals = preprocess_expression(root, j->quals, EXPRKIND_QUAL);
}
else
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(jtnode));
}
eval_const_expressions
Node *
eval_const_expressions(PlannerInfo *root, Node *node)
{
eval_const_expressions_context context;
if (root)
context.boundParams = root->glob->boundParams;
else
context.boundParams = NULL;
context.root = root;
context.active_fns = NIL;
context.case_val = NULL;
context.estimate = false;
//调用XX_mutator函数遍历处理
return eval_const_expressions_mutator(node, &context);
}
eval_const_expressions_mutator
static Node *
eval_const_expressions_mutator(Node *node,
eval_const_expressions_context *context)
{
if (node == NULL)
return NULL;
switch (nodeTag(node))
{
case T_Param:
{
Param *param = (Param *) node;
ParamListInfo paramLI = context->boundParams;
if (param->paramkind == PARAM_EXTERN &&
paramLI != NULL &&
param->paramid > 0 &&
param->paramid <= paramLI->numParams)
{
ParamExternData *prm;
ParamExternData prmdata;
if (paramLI->paramFetch != NULL)
prm = paramLI->paramFetch(paramLI, param->paramid,
true, &prmdata);
else
prm = ¶mLI->params[param->paramid - 1];
if (OidIsValid(prm->ptype) &&
prm->ptype == param->paramtype)
{
if (context->estimate ||
(prm->pflags & PARAM_FLAG_CONST))
{
int16 typLen;
bool typByVal;
Datum pval;
get_typlenbyval(param->paramtype,
&typLen, &typByVal);
if (prm->isnull || typByVal)
pval = prm->value;
else
pval = datumCopy(prm->value, typByVal, typLen);
return (Node *) makeConst(param->paramtype,
param->paramtypmod,
param->paramcollid,
(int) typLen,
pval,
prm->isnull,
typByVal);
}
}
}
return (Node *) copyObject(param);
}
case T_WindowFunc:
{
WindowFunc *expr = (WindowFunc *) node;
Oid funcid = expr->winfnoid;
List *args;
Expr *aggfilter;
HeapTuple func_tuple;
WindowFunc *newexpr;
func_tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(func_tuple))
elog(ERROR, "cache lookup failed for function %u", funcid);
args = expand_function_arguments(expr->args, expr->wintype,
func_tuple);
ReleaseSysCache(func_tuple);
args = (List *)
expression_tree_mutator((Node *) args,
eval_const_expressions_mutator,
(void *) context);
aggfilter = (Expr *)
eval_const_expressions_mutator((Node *) expr->aggfilter,
context);
newexpr = makeNode(WindowFunc);
newexpr->winfnoid = expr->winfnoid;
newexpr->wintype = expr->wintype;
newexpr->wincollid = expr->wincollid;
newexpr->inputcollid = expr->inputcollid;
newexpr->args = args;
newexpr->aggfilter = aggfilter;
newexpr->winref = expr->winref;
newexpr->winstar = expr->winstar;
newexpr->winagg = expr->winagg;
newexpr->location = expr->location;
return (Node *) newexpr;
}
case T_FuncExpr:
{
FuncExpr *expr = (FuncExpr *) node;
List *args = expr->args;
Expr *simple;
FuncExpr *newexpr;
simple = simplify_function(expr->funcid,
expr->funcresulttype,
exprTypmod(node),
expr->funccollid,
expr->inputcollid,
&args,
expr->funcvariadic,
true,
true,
context);
if (simple)
return (Node *) simple;
newexpr = makeNode(FuncExpr);
newexpr->funcid = expr->funcid;
newexpr->funcresulttype = expr->funcresulttype;
newexpr->funcretset = expr->funcretset;
newexpr->funcvariadic = expr->funcvariadic;
newexpr->funcformat = expr->funcformat;
newexpr->funccollid = expr->funccollid;
newexpr->inputcollid = expr->inputcollid;
newexpr->args = args;
newexpr->location = expr->location;
return (Node *) newexpr;
}
case T_OpExpr://操作(运算)表达式
{
OpExpr *expr = (OpExpr *) node;
List *args = expr->args;
Expr *simple;
OpExpr *newexpr;
set_opfuncid(expr);
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
expr->opcollid,
expr->inputcollid,
&args,
false,
true,
true,
context);
if (simple)
return (Node *) simple;
if (expr->opno == BooleanEqualOperator ||
expr->opno == BooleanNotEqualOperator)
{
simple = (Expr *) simplify_boolean_equality(expr->opno,
args);
if (simple)
return (Node *) simple;
}
newexpr = makeNode(OpExpr);
newexpr->opno = expr->opno;
newexpr->opfuncid = expr->opfuncid;
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->opcollid = expr->opcollid;
newexpr->inputcollid = expr->inputcollid;
newexpr->args = args;
newexpr->location = expr->location;
return (Node *) newexpr;
}
case T_DistinctExpr:
{
DistinctExpr *expr = (DistinctExpr *) node;
List *args;
ListCell *arg;
bool has_null_input = false;
bool all_null_input = true;
bool has_nonconst_input = false;
Expr *simple;
DistinctExpr *newexpr;
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
(void *) context);
foreach(arg, args)
{
if (IsA(lfirst(arg), Const))
{
has_null_input |= ((Const *) lfirst(arg))->constisnull;
all_null_input &= ((Const *) lfirst(arg))->constisnull;
}
else
has_nonconst_input = true;
}
if (!has_nonconst_input)
{
if (all_null_input)
return makeBoolConst(false, false);
if (has_null_input)
return makeBoolConst(true, false);
set_opfuncid((OpExpr *) expr);
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
expr->opcollid,
expr->inputcollid,
&args,
false,
false,
false,
context);
if (simple)
{
Const *csimple = castNode(Const, simple);
csimple->constvalue =
BoolGetDatum(!DatumGetBool(csimple->constvalue));
return (Node *) csimple;
}
}
newexpr = makeNode(DistinctExpr);
newexpr->opno = expr->opno;
newexpr->opfuncid = expr->opfuncid;
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->opcollid = expr->opcollid;
newexpr->inputcollid = expr->inputcollid;
newexpr->args = args;
newexpr->location = expr->location;
return (Node *) newexpr;
}
case T_ScalarArrayOpExpr:
{
ScalarArrayOpExpr *saop;
saop = (ScalarArrayOpExpr *) ece_generic_processing(node);
set_sa_opfuncid(saop);
if (ece_all_arguments_const(saop) &&
ece_function_is_safe(saop->opfuncid, context))
return ece_evaluate_expr(saop);
return (Node *) saop;
}
case T_BoolExpr:
{
BoolExpr *expr = (BoolExpr *) node;
switch (expr->boolop)
{
case OR_EXPR:
{
List *newargs;
bool haveNull = false;
bool forceTrue = false;
newargs = simplify_or_arguments(expr->args,
context,
&haveNull,
&forceTrue);
if (forceTrue)
return makeBoolConst(true, false);
if (haveNull)
newargs = lappend(newargs,
makeBoolConst(false, true));
if (newargs == NIL)
return makeBoolConst(false, false);
if (list_length(newargs) == 1)
return (Node *) linitial(newargs);
return (Node *) make_orclause(newargs);
}
case AND_EXPR:
{
List *newargs;
bool haveNull = false;
bool forceFalse = false;
newargs = simplify_and_arguments(expr->args,
context,
&haveNull,
&forceFalse);
if (forceFalse)
return makeBoolConst(false, false);
if (haveNull)
newargs = lappend(newargs,
makeBoolConst(false, true));
if (newargs == NIL)
return makeBoolConst(true, false);
if (list_length(newargs) == 1)
return (Node *) linitial(newargs);
return (Node *) make_andclause(newargs);
}
case NOT_EXPR:
{
Node *arg;
Assert(list_length(expr->args) == 1);
arg = eval_const_expressions_mutator(linitial(expr->args),
context);
return negate_clause(arg);
}
default:
elog(ERROR, "unrecognized boolop: %d",
(int) expr->boolop);
break;
}
break;
}
case T_SubPlan:
case T_AlternativeSubPlan:
return node;
case T_RelabelType:
{
RelabelType *relabel = (RelabelType *) node;
Node *arg;
arg = eval_const_expressions_mutator((Node *) relabel->arg,
context);
while (arg && IsA(arg, RelabelType))
arg = (Node *) ((RelabelType *) arg)->arg;
if (arg && IsA(arg, Const))
{
Const *con = (Const *) arg;
con->consttype = relabel->resulttype;
con->consttypmod = relabel->resulttypmod;
con->constcollid = relabel->resultcollid;
return (Node *) con;
}
else
{
RelabelType *newrelabel = makeNode(RelabelType);
newrelabel->arg = (Expr *) arg;
newrelabel->resulttype = relabel->resulttype;
newrelabel->resulttypmod = relabel->resulttypmod;
newrelabel->resultcollid = relabel->resultcollid;
newrelabel->relabelformat = relabel->relabelformat;
newrelabel->location = relabel->location;
return (Node *) newrelabel;
}
}
case T_CoerceViaIO:
{
CoerceViaIO *expr = (CoerceViaIO *) node;
List *args;
Oid outfunc;
bool outtypisvarlena;
Oid infunc;
Oid intypioparam;
Expr *simple;
CoerceViaIO *newexpr;
args = list_make1(expr->arg);
getTypeOutputInfo(exprType((Node *) expr->arg),
&outfunc, &outtypisvarlena);
getTypeInputInfo(expr->resulttype,
&infunc, &intypioparam);
simple = simplify_function(outfunc,
CSTRINGOID, -1,
InvalidOid,
InvalidOid,
&args,
false,
true,
true,
context);
if (simple)
{
args = list_make3(simple,
makeConst(OIDOID,
-1,
InvalidOid,
sizeof(Oid),
ObjectIdGetDatum(intypioparam),
false,
true),
makeConst(INT4OID,
-1,
InvalidOid,
sizeof(int32),
Int32GetDatum(-1),
false,
true));
simple = simplify_function(infunc,
expr->resulttype, -1,
expr->resultcollid,
InvalidOid,
&args,
false,
false,
true,
context);
if (simple)
return (Node *) simple;
}
newexpr = makeNode(CoerceViaIO);
newexpr->arg = (Expr *) linitial(args);
newexpr->resulttype = expr->resulttype;
newexpr->resultcollid = expr->resultcollid;
newexpr->coerceformat = expr->coerceformat;
newexpr->location = expr->location;
return (Node *) newexpr;
}
case T_ArrayCoerceExpr:
{
ArrayCoerceExpr *ac;
ac = (ArrayCoerceExpr *) ece_generic_processing(node);
if (ac->arg && IsA(ac->arg, Const) &&
ac->elemexpr && !IsA(ac->elemexpr, CoerceToDomain) &&
!contain_mutable_functions((Node *) ac->elemexpr))
return ece_evaluate_expr(ac);
return (Node *) ac;
}
case T_CollateExpr:
{
CollateExpr *collate = (CollateExpr *) node;
Node *arg;
arg = eval_const_expressions_mutator((Node *) collate->arg,
context);
if (arg && IsA(arg, Const))
{
Const *con = (Const *) arg;
con->constcollid = collate->collOid;
return (Node *) con;
}
else if (collate->collOid == exprCollation(arg))
{
return arg;
}
else
{
RelabelType *relabel = makeNode(RelabelType);
relabel->resulttype = exprType(arg);
relabel->resulttypmod = exprTypmod(arg);
relabel->resultcollid = collate->collOid;
relabel->relabelformat = COERCE_IMPLICIT_CAST;
relabel->location = collate->location;
while (arg && IsA(arg, RelabelType))
arg = (Node *) ((RelabelType *) arg)->arg;
relabel->arg = (Expr *) arg;
return (Node *) relabel;
}
}
case T_CaseExpr:
{
CaseExpr *caseexpr = (CaseExpr *) node;
CaseExpr *newcase;
Node *save_case_val;
Node *newarg;
List *newargs;
bool const_true_cond;
Node *defresult = NULL;
ListCell *arg;
newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
context);
save_case_val = context->case_val;
if (newarg && IsA(newarg, Const))
{
context->case_val = newarg;
newarg = NULL;
}
else
context->case_val = NULL;
newargs = NIL;
const_true_cond = false;
foreach(arg, caseexpr->args)
{
CaseWhen *oldcasewhen = lfirst_node(CaseWhen, arg);
Node *casecond;
Node *caseresult;
casecond = eval_const_expressions_mutator((Node *) oldcasewhen->expr,
context);
if (casecond && IsA(casecond, Const))
{
Const *const_input = (Const *) casecond;
if (const_input->constisnull ||
!DatumGetBool(const_input->constvalue))
continue;
const_true_cond = true;
}
caseresult = eval_const_expressions_mutator((Node *) oldcasewhen->result,
context);
if (!const_true_cond)
{
CaseWhen *newcasewhen = makeNode(CaseWhen);
newcasewhen->expr = (Expr *) casecond;
newcasewhen->result = (Expr *) caseresult;
newcasewhen->location = oldcasewhen->location;
newargs = lappend(newargs, newcasewhen);
continue;
}
defresult = caseresult;
break;
}
if (!const_true_cond)
defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,
context);
context->case_val = save_case_val;
if (newargs == NIL)
return defresult;
newcase = makeNode(CaseExpr);
newcase->casetype = caseexpr->casetype;
newcase->casecollid = caseexpr->casecollid;
newcase->arg = (Expr *) newarg;
newcase->args = newargs;
newcase->defresult = (Expr *) defresult;
newcase->location = caseexpr->location;
return (Node *) newcase;
}
case T_CaseTestExpr:
{
if (context->case_val)
return copyObject(context->case_val);
else
return copyObject(node);
}
case T_ArrayRef:
case T_ArrayExpr:
case T_RowExpr:
{
node = ece_generic_processing(node);
if (ece_all_arguments_const(node))
return ece_evaluate_expr(node);
return node;
}
case T_CoalesceExpr:
{
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
CoalesceExpr *newcoalesce;
List *newargs;
ListCell *arg;
newargs = NIL;
foreach(arg, coalesceexpr->args)
{
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(arg),
context);
if (IsA(e, Const))
{
if (((Const *) e)->constisnull)
continue;
if (newargs == NIL)
return e;
newargs = lappend(newargs, e);
break;
}
newargs = lappend(newargs, e);
}
if (newargs == NIL)
return (Node *) makeNullConst(coalesceexpr->coalescetype,
-1,
coalesceexpr->coalescecollid);
newcoalesce = makeNode(CoalesceExpr);
newcoalesce->coalescetype = coalesceexpr->coalescetype;
newcoalesce->coalescecollid = coalesceexpr->coalescecollid;
newcoalesce->args = newargs;
newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
}
case T_SQLValueFunction:
{
SQLValueFunction *svf = (SQLValueFunction *) node;
if (context->estimate)
return (Node *) evaluate_expr((Expr *) svf,
svf->type,
svf->typmod,
InvalidOid);
else
return copyObject((Node *) svf);
}
case T_FieldSelect:
{
FieldSelect *fselect = (FieldSelect *) node;
FieldSelect *newfselect;
Node *arg;
arg = eval_const_expressions_mutator((Node *) fselect->arg,
context);
if (arg && IsA(arg, Var) &&
((Var *) arg)->varattno == InvalidAttrNumber &&
((Var *) arg)->varlevelsup == 0)
{
if (rowtype_field_matches(((Var *) arg)->vartype,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
fselect->resultcollid))
return (Node *) makeVar(((Var *) arg)->varno,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
fselect->resultcollid,
((Var *) arg)->varlevelsup);
}
if (arg && IsA(arg, RowExpr))
{
RowExpr *rowexpr = (RowExpr *) arg;
if (fselect->fieldnum > 0 &&
fselect->fieldnum <= list_length(rowexpr->args))
{
Node *fld = (Node *) list_nth(rowexpr->args,
fselect->fieldnum - 1);
if (rowtype_field_matches(rowexpr->row_typeid,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
fselect->resultcollid) &&
fselect->resulttype == exprType(fld) &&
fselect->resulttypmod == exprTypmod(fld) &&
fselect->resultcollid == exprCollation(fld))
return fld;
}
}
newfselect = makeNode(FieldSelect);
newfselect->arg = (Expr *) arg;
newfselect->fieldnum = fselect->fieldnum;
newfselect->resulttype = fselect->resulttype;
newfselect->resulttypmod = fselect->resulttypmod;
newfselect->resultcollid = fselect->resultcollid;
if (arg && IsA(arg, Const))
{
Const *con = (Const *) arg;
if (rowtype_field_matches(con->consttype,
newfselect->fieldnum,
newfselect->resulttype,
newfselect->resulttypmod,
newfselect->resultcollid))
return ece_evaluate_expr(newfselect);
}
return (Node *) newfselect;
}
case T_NullTest:
{
NullTest *ntest = (NullTest *) node;
NullTest *newntest;
Node *arg;
arg = eval_const_expressions_mutator((Node *) ntest->arg,
context);
if (ntest->argisrow && arg && IsA(arg, RowExpr))
{
RowExpr *rarg = (RowExpr *) arg;
List *newargs = NIL;
ListCell *l;
foreach(l, rarg->args)
{
Node *relem = (Node *) lfirst(l);
if (relem && IsA(relem, Const))
{
Const *carg = (Const *) relem;
if (carg->constisnull ?
(ntest->nulltesttype == IS_NOT_NULL) :
(ntest->nulltesttype == IS_NULL))
return makeBoolConst(false, false);
continue;
}
newntest = makeNode(NullTest);
newntest->arg = (Expr *) relem;
newntest->nulltesttype = ntest->nulltesttype;
newntest->argisrow = false;
newntest->location = ntest->location;
newargs = lappend(newargs, newntest);
}
if (newargs == NIL)
return makeBoolConst(true, false);
if (list_length(newargs) == 1)
return (Node *) linitial(newargs);
return (Node *) make_andclause(newargs);
}
if (!ntest->argisrow && arg && IsA(arg, Const))
{
Const *carg = (Const *) arg;
bool result;
switch (ntest->nulltesttype)
{
case IS_NULL:
result = carg->constisnull;
break;
case IS_NOT_NULL:
result = !carg->constisnull;
break;
default:
elog(ERROR, "unrecognized nulltesttype: %d",
(int) ntest->nulltesttype);
result = false;
break;
}
return makeBoolConst(result, false);
}
newntest = makeNode(NullTest);
newntest->arg = (Expr *) arg;
newntest->nulltesttype = ntest->nulltesttype;
newntest->argisrow = ntest->argisrow;
newntest->location = ntest->location;
return (Node *) newntest;
}
case T_BooleanTest:
{
BooleanTest *btest = (BooleanTest *) node;
BooleanTest *newbtest;
Node *arg;
arg = eval_const_expressions_mutator((Node *) btest->arg,
context);
if (arg && IsA(arg, Const))
{
Const *carg = (Const *) arg;
bool result;
switch (btest->booltesttype)
{
case IS_TRUE:
result = (!carg->constisnull &&
DatumGetBool(carg->constvalue));
break;
case IS_NOT_TRUE:
result = (carg->constisnull ||
!DatumGetBool(carg->constvalue));
break;
case IS_FALSE:
result = (!carg->constisnull &&
!DatumGetBool(carg->constvalue));
break;
case IS_NOT_FALSE:
result = (carg->constisnull ||
DatumGetBool(carg->constvalue));
break;
case IS_UNKNOWN:
result = carg->constisnull;
break;
case IS_NOT_UNKNOWN:
result = !carg->constisnull;
break;
default:
elog(ERROR, "unrecognized booltesttype: %d",
(int) btest->booltesttype);
result = false;
break;
}
return makeBoolConst(result, false);
}
newbtest = makeNode(BooleanTest);
newbtest->arg = (Expr *) arg;
newbtest->booltesttype = btest->booltesttype;
newbtest->location = btest->location;
return (Node *) newbtest;
}
case T_PlaceHolderVar:
if (context->estimate)
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
return eval_const_expressions_mutator((Node *) phv->phexpr,
context);
}
break;
default:
break;
}
return ece_generic_processing(node);
}
simplify_function
static Expr *
simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
Oid result_collid, Oid input_collid, List **args_p,
bool funcvariadic, bool process_args, bool allow_non_const,
eval_const_expressions_context *context)
{
List *args = *args_p;
HeapTuple func_tuple;
Form_pg_proc func_form;
Expr *newexpr;
//查询proc(视为Tuple)
func_tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(func_tuple))
elog(ERROR, "cache lookup failed for function %u", funcid);
//从Tuple中分解得到函数体
func_form = (Form_pg_proc) GETSTRUCT(func_tuple);
if (process_args)//参数不为空
{
args = expand_function_arguments(args, result_type, func_tuple);//展开参数
args = (List *) expression_tree_mutator((Node *) args,
eval_const_expressions_mutator,
(void *) context);//递归处理
*args_p = args;//重新赋值
}
newexpr = evaluate_function(funcid, result_type, result_typmod,
result_collid, input_collid,
args, funcvariadic,
func_tuple, context);//对函数进行预求解
//求解成功并且允许非Const值并且(func_form->protransform是合法的Oid
if (!newexpr && allow_non_const && OidIsValid(func_form->protransform))
{
FuncExpr fexpr;
fexpr.xpr.type = T_FuncExpr;
fexpr.funcid = funcid;
fexpr.funcresulttype = result_type;
fexpr.funcretset = func_form->proretset;
fexpr.funcvariadic = funcvariadic;
fexpr.funcformat = COERCE_EXPLICIT_CALL;
fexpr.funccollid = result_collid;
fexpr.inputcollid = input_collid;
fexpr.args = args;
fexpr.location = -1;
newexpr = (Expr *)
DatumGetPointer(OidFunctionCall1(func_form->protransform,
PointerGetDatum(&fexpr)));
}
if (!newexpr && allow_non_const)
newexpr = inline_function(funcid, result_type, result_collid,
input_collid, args, funcvariadic,
func_tuple, context);
ReleaseSysCache(func_tuple);
return newexpr;
}
static Expr *
evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
Oid result_collation)
{
EState *estate;
ExprState *exprstate;
MemoryContext oldcontext;
Datum const_val;
bool const_is_null;
int16 resultTypLen;
bool resultTypByVal;
estate = CreateExecutorState();
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
fix_opfuncids((Node *) expr);
//初始化表达式,为执行作准备
//把函数放在exprstate->evalfunc中
exprstate = ExecInitExpr(expr, NULL);
const_val = ExecEvalExprSwitchContext(exprstate,
GetPerTupleExprContext(estate),
&const_is_null);//执行表达式求解
get_typlenbyval(result_type, &resultTypLen, &resultTypByVal);
MemoryContextSwitchTo(oldcontext);
if (!const_is_null)
{
if (resultTypLen == -1)
const_val = PointerGetDatum(PG_DETOAST_DATUM_COPY(const_val));
else
const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
}
FreeExecutorState(estate);
return (Expr *) makeConst(result_type, result_typmod, result_collation,
resultTypLen,
const_val, const_is_null,
resultTypByVal);
}
#ifndef FRONTEND
static inline Datum
ExecEvalExprSwitchContext(ExprState *state,
ExprContext *econtext,
bool *isNull)
{
Datum retDatum;
MemoryContext oldContext;
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
retDatum = state->evalfunc(state, econtext, isNull);
MemoryContextSwitchTo(oldContext);
return retDatum;
}
#endif
三、跟踪分析
测试脚本,表达式位于targetList中:
select max(a.dwbh::int+(1+2))
from t_dwxx a;
gdb跟踪:
Breakpoint 1, preprocess_expression (root=0x133eca8, expr=0x13441a8, kind=1) at planner.c:1007
1007 if (expr == NULL)
...
(gdb) p *(TargetEntry *)((List *)expr)->head->data.ptr_value
$6 = {xpr = {type = T_TargetEntry}, expr = 0x1343fb8, resno = 1, resname = 0x124bb38 "max", ressortgroupref = 0,
resorigtbl = 0, resorigcol = 0, resjunk = false}
...
#OpExpr,参数args链表,第1个参数是1,第2个参数是2
(gdb) p *(Const *)$opexpr->args->head->data.ptr_value
$25 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 1,
constisnull = false, constbyval = true, location = 24}
(gdb) p *(Const *)$opexpr->args->tail->data.ptr_value
$26 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 2,
constisnull = false, constbyval = true, location = 26}
(gdb)
#调整断点
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000076ac6f in preprocess_expression at planner.c:1007
breakpoint already hit 8 times
(gdb) del 1
(gdb) b clauses.c:2713
Breakpoint 2 at 0x78952a: file clauses.c, line 2713.
(gdb) c
Continuing.
Breakpoint 2, eval_const_expressions_mutator (node=0x124cbf0, context=0x7ffebc48f630) at clauses.c:2716
2716 set_opfuncid(expr);
#这个表达式是a.dwbh::int+(1+2)
(gdb) p *((OpExpr *)node)->args
$29 = {type = T_List, length = 2, head = 0x124cbd0, tail = 0x124cb80}
(gdb) p *(Node *)((OpExpr *)node)->args->head->data.ptr_value
$30 = {type = T_CoerceViaIO}
(gdb) c
Continuing.
Breakpoint 2, eval_const_expressions_mutator (node=0x124cb30, context=0x7ffebc48f630) at clauses.c:2716
2716 set_opfuncid(expr);
#这个表达式是1+2,对此表达式进行求解
(gdb) p *(Node *)((OpExpr *)node)->args->head->data.ptr_value
$34 = {type = T_Const}
(gdb) p *(Const *)((OpExpr *)node)->args->head->data.ptr_value
$35 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 1,
constisnull = false, constbyval = true, location = 24}
#进入simplify_function
(gdb) step
simplify_function (funcid=177, result_type=23, result_typmod=-1, result_collid=0, input_collid=0, args_p=0x7ffebc48c838,
funcvariadic=false, process_args=true, allow_non_const=true, context=0x7ffebc48f630) at clauses.c:4022
4022 List *args = *args_p;
...
#函数是int4pl
(gdb) p *func_form
$38 = {proname = {data = "int4pl", '\000' <repeats 57 times>}, pronamespace = 11, proowner = 10, prolang = 12, procost = 1,
prorows = 0, provariadic = 0, protransform = 0, prokind = 102 'f', prosecdef = false, proleakproof = false,
proisstrict = true, proretset = false, provolatile = 105 'i', proparallel = 115 's', pronargs = 2, pronargdefaults = 0,
prorettype = 23, proargtypes = {vl_len_ = 128, ndim = 1, dataoffset = 0, elemtype = 26, dim1 = 2, lbound1 = 0,
values = 0x7fd820a599a4}}
...
#求解,得到结果为3
(gdb) p const_val
$48 = 3
(gdb)
evaluate_function (funcid=177, result_type=23, result_typmod=-1, result_collid=0, input_collid=0, args=0x13135c8,
funcvariadic=false, func_tuple=0x7fd820a598d8, context=0x7ffebc48f630) at clauses.c:4424
4424 }
(gdb)
simplify_function (funcid=177, result_type=23, result_typmod=-1, result_collid=0, input_collid=0, args_p=0x7ffebc48c838,
funcvariadic=false, process_args=true, allow_non_const=true, context=0x7ffebc48f630) at clauses.c:4067
4067 if (!newexpr && allow_non_const && OidIsValid(func_form->protransform))
(gdb) p *newexpr
$50 = {type = T_Const}
(gdb) p *(Const *)newexpr
$51 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 3,
constisnull = false, constbyval = true, location = -1}
...
#DONE!
#把1+2的T_OpExpr变换为T_Const
四、小结
1、简化过程:通过eval_const_expressions_mutator函数遍历相关节点,根据函数信息读取pg_proc中的函数并通过这些函数对表达式逐个处理;
2、表达式求解:通过调用evaluate_expr进而调用内置函数进行求解。
以上是“PostgreSQL中表达式预处理主要的函数有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!