文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

PostgreSQL中表达式预处理主要的函数有哪些

2024-04-02 19:55

关注

这篇文章主要为大家展示了“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 = &paramLI->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中表达式预处理主要的函数有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯