这篇文章主要为大家展示了“PostgreSQL中表达式预处理主要的函数有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“PostgreSQL中表达式预处理主要的函数有哪些”这篇文章吧。

表达式预处理主要的函数主要有preprocess_expression和preprocess_qual_conditions(调用preprocess_expression),在文件src/backend/optimizer/plan/planner.c中。preprocess_expression调用了eval_const_expressions,该函数调用了mutator函数通过遍历的方式对表达式进行处理。

一、基本概念

PG源码对简化表达式的注释如下:

/*--------------------*eval_const_expressions**Reduceanyrecognizablyconstantsubexpressionsofthegiven*expressiontree,forexample"2+2"=>"4".Moreinterestingly,*wecanreducecertainbooleanexpressionsevenwhentheycontain*non-constantsubexpressions:"xORtrue"=>"true"nomatterwhat*thesubexpressionxis.(XXXWeassumethatnosuchsubexpression*willhaveimportantside-effects,whichisnotnecessarilyagood*assumptioninthepresenceofuser-definedfunctions;doweneeda*pg_procflagthatpreventsdiscardingtheexecutionofafunction?)**Wedounderstandthatcertainfunctionsmaydelivernon-constant*resultsevenwithconstantinputs,"nextval()"beingtheclassic*example.Functionsthatarenotmarked"immutable"inpg_proc*willnotbepre-evaluatedhere,althoughwewillreducetheir*argumentsasfaraspossible.**Wheneverafunctioniseliminatedfromtheexpressionbymeansof*constant-expressionevaluationorinlining,weaddthefunctionto*root->glob->invalItems.Thisensurestheplanisknowntodependon*suchfunctions,eventhoughtheyaren'treferencedanymore.**Weassumethatthetreehasalreadybeentype-checkedandcontains*onlyoperatorsandfunctionsthatarereasonabletotrytoexecute.**NOTE:"root"canbepassedasNULLifthecallerneverwantstodoany*Paramsubstitutionsnorreceiveinfoaboutinlinedfunctions.**NOTE:theplannerassumesthatthiswillalwaysflattennestedANDand*ORclausesintoN-argumentform.Seecommentsinprepqual.c.**NOTE:anothercriticaleffectisthatanyfunctioncallsthatrequire*defaultargumentswillbeexpanded,andnamed-argumentcallswillbe*convertedtopositionalnotation.Theexecutorwon'thandleeither.*--------------------*/

比如表达式1 + 2,直接求解得到3;x OR true,直接求解得到true而无需理会x的值,类似的x AND false直接求解得到false而无需理会x的值.
不过,这里的简化只是执行了基础分析,并没有做深入分析:

testdb=#explainverboseselectmax(a.dwbh::int+(1+2))fromt_dwxxa;QUERYPLAN-------------------------------------------------------------------------Aggregate(cost=13.20..13.21rows=1width=4)Output:max(((dwbh)::integer+3))->SeqScanonpublic.t_dwxxa(cost=0.00..11.60rows=160width=38)Output:dwmc,dwbh,dwdz(4rows)testdb=#explainverboseselectmax(a.dwbh::int+1+2)fromt_dwxxa;QUERYPLAN-------------------------------------------------------------------------Aggregate(cost=13.60..13.61rows=1width=4)Output:max((((dwbh)::integer+1)+2))->SeqScanonpublic.t_dwxxa(cost=0.00..11.60rows=160width=38)Output:dwmc,dwbh,dwdz(4rows)

见上测试脚本,如(1+2),把括号去掉,a.dwbh先跟1运算,再跟2运算,没有执行简化.

二、源码解读

主函数入口:
subquery_planner

/*--------------------*subquery_planner*Invokestheplanneronasubquery.Werecursetohereforeach*sub-SELECTfoundinthequerytree.**globistheglobalstateforthecurrentplannerrun.*parseisthequerytreeproducedbytheparser&rewriter.*parent_rootistheimmediateparentQuery'sinfo(NULLatthetoplevel).*hasRecursionistrueifthisisarecursiveWITHquery.*tuple_fractionisthefractionoftuplesweexpectwillberetrieved.*tuple_fractionisinterpretedasexplainedforgrouping_planner,below.**Basically,thisroutinedoesthestuffthatshouldonlybedoneonce*perQueryobject.Itthencallsgrouping_planner.Atonetime,*grouping_plannercouldbeinvokedrecursivelyonthesameQueryobject;*that'snotcurrentlytrue,butwekeeptheseparationbetweenthetwo*routinesanyway,incaseweneeditagainsomeday.**subquery_plannerwillbecalledrecursivelytohandlesub-Querynodes*foundwithinthequery'sexpressionsandrangetable.**ReturnsthePlannerInfostruct("root")thatcontainsalldatagenerated*whileplanningthesubquery.Inparticular,thePath(s)attachedto*the(UPPERREL_FINAL,NULL)upperrelrepresentourconclusionsaboutthe*cheapestway(s)toimplementthequery.Thetoplevelwillselectthe*bestPathandpassitthroughcreateplan.ctoproduceafinishedPlan.*--------------------*//*输入:glob-PlannerGlobalparse-Query结构体指针parent_root-父PlannerInfoRoot节点hasRecursion-是否递归?tuple_fraction-扫描Tuple比例输出:PlannerInfo指针*/PlannerInfo*subquery_planner(PlannerGlobal*glob,Query*parse,PlannerInfo*parent_root,boolhasRecursion,doubletuple_fraction){PlannerInfo*root;//返回值List*newWithCheckOptions;//List*newHaving;//Having子句boolhasOuterJoins;//是否存在OuterJoin?RelOptInfo*final_rel;//ListCell*l;//临时变量/*CreateaPlannerInfodatastructureforthissubquery*/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);elseroot->wt_param_id=-1;root->non_recursive_path=NULL;root->partColsUpdated=false;/**IfthereisaWITHlist,processeachWITHqueryandbuildaninitplan*SubPlanstructureforit.*/if(parse->cteList)SS_process_ctes(root);//处理With语句/**LookforANYandEXISTSSubLinksinWHEREandJOIN/ONclauses,andtry*totransformthemintojoins.Notethatthisstepdoesnotdescend*intosubqueries;ifwepullupanysubqueriesbelow,theirSubLinksare*processedjustbeforepullingthemup.*/if(parse->hasSubLinks)pull_up_sublinks(root);//上拉子链接/**Scantherangetableforset-returningfunctions,andinlinethemif*possible(producingsubqueriesthatmightgetpulledupnext).*RecursionissuesherearehandledinthesamewayasforSubLinks.*/inline_set_returning_functions(root);///**Checktoseeifanysubqueriesinthejointreecanbemergedintothis*query.*/pull_up_subqueries(root);//上拉子查询/**IfthisisasimpleUNIONALLquery,flattenitintoanappendrel.We*dothisnowbecauseitrequiresapplyingpull_up_subqueriestotheleaf*queriesoftheUNIONALL,whichweren'ttouchedabovebecausethey*weren'treferencedbythejointree(theywillbeafterwedothis).*/if(parse->setOperations)flatten_simple_union_all(root);//扁平化处理UNIONALL/**DetectwhetheranyrangetableentriesareRTE_JOINkind;ifnot,wecan*avoidtheexpenseofdoingflatten_join_alias_vars().Alsocheckfor*outerjoins---ifnone,wecanskipreduce_outer_joins().Andcheck*forLATERALRTEs,too.Thismustbedoneafterwehavedone*pull_up_subqueries(),ofcourse.*///判断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;}/**PreprocessRowMarkinformation.Weneedtodothisaftersubquery*pullup(sothatallnon-inheritedRTEsarepresent)andbefore*inheritanceexpansion(sothattheinfoisavailablefor*expand_inherited_tablestoexamineandmodify).*///预处理RowMark信息preprocess_rowmarks(root);/**Expandanyrangetableentriesthatareinheritancesetsinto"append*relations".Thiscanaddentriestotherangetable,buttheymustbe*plainbaserelationsnotjoins,soit'sOK(andmarginallymore*efficient)todoitaftercheckingforjoinRTEs.Wemustdoitafter*pullingupsubqueries,elsewe'dfailtohandleinheritedtablesin*subqueries.*///展开继承表expand_inherited_tables(root);/**SethasHavingQualtorememberifHAVINGclauseispresent.Needed*becausepreprocess_expressionwillreduceaconstant-trueconditionto*anemptyquallist...but"HAVINGTRUE"isnotasemanticno-op.*///是否存在Having表达式root->hasHavingQual=(parse->havingQual!=NULL);/*Clearthisflag;mightgetsetindistribute_qual_to_rels*/root->hasPseudoConstantQuals=false;/**Doexpressionpreprocessingontargetlistandquals,aswellasother*randomexpressionsinthequerytree.Notethatwedonotneedto*handlesort/groupexpressionsexplicitly,becausetheyareactually*partofthetargetlist.*///预处理表达式:targetList(投影列)parse->targetList=(List*)preprocess_expression(root,(Node*)parse->targetList,EXPRKIND_TARGET);/*Constant-foldingmighthaveremovedallset-returningfunctions*/if(parse->hasTargetSRFs)parse->hasTargetSRFs=expression_returns_set((Node*)parse->targetList);newWithCheckOptions=NIL;foreach(l,parse->withCheckOptions)//witchCheckOptions{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;//返回列信息returningListparse->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);/*partitionClause/orderClausearesort/groupexpressions*/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);//OnConflict子句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);/*exclRelTlistcontainsonlyVars,sonopreprocessingneeded*/}//集合操作(AppendRelInfo)root->append_rel_list=(List*)preprocess_expression(root,(Node*)root->append_rel_list,EXPRKIND_APPINFO);//RTE/*AlsoneedtopreprocessexpressionswithinRTEs*/foreach(l,parse->rtable){RangeTblEntry*rte=lfirst_node(RangeTblEntry,l);intkind;ListCell*lcsq;if(rte->rtekind==RTE_RELATION){if(rte->tablesample)rte->tablesample=(TableSampleClause*)preprocess_expression(root,(Node*)rte->tablesample,EXPRKIND_TABLESAMPLE);//数据表采样语句}elseif(rte->rtekind==RTE_SUBQUERY)//子查询{/**Wedon'twanttodoallpreprocessingyetonthesubquery's*expressions,sincethatwillhappenwhenweplanit.Butifit*containsanyjoinaliasesofourlevel,thosehavetoget*expandednow,becauseplanningofthesubquerywon'tdoit.*That'sonlypossibleifthesubqueryisLATERAL.*/if(rte->lateral&&root->hasJoinRTEs)rte->subquery=(Query*)flatten_join_alias_vars(root,(Node*)rte->subquery);}elseif(rte->rtekind==RTE_FUNCTION)//函数{/*Preprocessthefunctionexpression(s)fully*/kind=rte->lateral?EXPRKIND_RTFUNC_LATERAL:EXPRKIND_RTFUNC;rte->functions=(List*)preprocess_expression(root,(Node*)rte->functions,kind);}elseif(rte->rtekind==RTE_TABLEFUNC)//TABLEFUNC{/*Preprocessthefunctionexpression(s)fully*/kind=rte->lateral?EXPRKIND_TABLEFUNC_LATERAL:EXPRKIND_TABLEFUNC;rte->tablefunc=(TableFunc*)preprocess_expression(root,(Node*)rte->tablefunc,kind);}elseif(rte->rtekind==RTE_VALUES)//VALUES子句{/*Preprocessthevalueslistsfully*/kind=rte->lateral?EXPRKIND_VALUES_LATERAL:EXPRKIND_VALUES;rte->values_lists=(List*)preprocess_expression(root,(Node*)rte->values_lists,kind);}/**ProcesseachelementofthesecurityQualslistasifitwerea*separatequalexpression(asindeeditis).Weneedtodoitthis*waytogetpropercanonicalizationofAND/ORstructure.Notethat*thisconvertseachelementintoanimplicit-ANDsublist.*/foreach(lcsq,rte->securityQuals){lfirst(lcsq)=preprocess_expression(root,(Node*)lfirst(lcsq),EXPRKIND_QUAL);}}...//其他returnroot;}

preprocess_expression

/**preprocess_expression*Dosubquery_planner'spreprocessingworkforanexpression,*whichcanbeatargetlist,aWHEREclause(includingJOIN/ON*conditions),aHAVINGclause,orafewotherthings.*/staticNode*preprocess_expression(PlannerInfo*root,Node*expr,intkind){/**Falloutquicklyifexpressionisempty.Thisoccursoftenenoughto*beworthchecking.Notethatnull->nullisthecorrectconversionfor*implicit-ANDresultformat,too.*/if(expr==NULL)returnNULL;/**IfthequeryhasanyjoinRTEs,replacejoinaliasvariableswith*base-relationvariables.Wemustdothisfirst,sinceanyexpressions*wemayextractfromthejoinaliasvarslistshavenotbeenpreprocessed.*Forexample,ifwedidthisaftersublinkprocessing,sublinksexpanded*outfromjoinaliaseswouldnotgetprocessed.Butwecanskipthisin*non-lateralRTEfunctions,VALUESlists,andTABLESAMPLEclauses,since*theycan'tcontainanyVarsofthecurrentquerylevel.*/if(root->hasJoinRTEs&&!(kind==EXPRKIND_RTFUNC||kind==EXPRKIND_VALUES||kind==EXPRKIND_TABLESAMPLE||kind==EXPRKIND_TABLEFUNC))expr=flatten_join_alias_vars(root,expr);//扁平化处理joinaliasvars,上节已介绍/**Simplifyconstantexpressions.**Note:anessentialeffectofthisistoconvertnamed-argumentfunction*callstopositionalnotationandinsertthecurrentactualvaluesof*anydefaultargumentsforfunctions.Toensurethathappens,we*must**processallexpressionshere.PreviousPGversionssometimesskipped*const-simplificationifitdidn'tseemworththetrouble,butwecan't*dothatanymore.**Note:thisalsoflattensnestedANDandORexpressionsintoN-argument*form.Allprocessingofaqualexpressionafterthispointmustbe*carefultomaintainAND/ORflatness---thatis,donotgenerateatree*withANDdirectlyunderAND,norORdirectlyunderOR.*/expr=eval_const_expressions(root,expr);//简化常量表达式/**Ifit'saqualorhavingQual,canonicalizeit.*/if(kind==EXPRKIND_QUAL){expr=(Node*)canonicalize_qual((Expr*)expr,false);//表达式规约,下节介绍#ifdefOPTIMIZER_DEBUGprintf("Aftercanonicalize_qual()\n");pprint(expr);#endif}/*ExpandSubLinkstoSubPlans*/if(root->parse->hasSubLinks)//扩展子链接为子计划expr=SS_process_sublinks(root,expr,(kind==EXPRKIND_QUAL));/**XXXdonotinsertanythinghereunlessyouhavegrokkedthecommentsin*SS_replace_correlation_vars...*//*ReplaceuplevelvarswithParamnodes(thisISpossibleinVALUES)*/if(root->query_level>1)expr=SS_replace_correlation_vars(root,expr);//使用Param节点替换上层的Vars/**Ifit'saqualorhavingQual,convertittoimplicit-ANDformat.(We*don'twanttodothisbeforeeval_const_expressions,sincethelatter*wouldbeunabletosimplifyatop-levelANDcorrectly.Also,*SS_process_sublinksexpectsexplicit-ANDformat.)*/if(kind==EXPRKIND_QUAL)expr=(Node*)make_ands_implicit((Expr*)expr);returnexpr;}

preprocess_qual_conditions

/**preprocess_qual_conditions*Recursivelyscanthequery'sjointreeanddosubquery_planner's*preprocessingworkoneachqualconditionfoundtherein.*/staticvoidpreprocess_qual_conditions(PlannerInfo*root,Node*jtnode){if(jtnode==NULL)return;if(IsA(jtnode,RangeTblRef)){/*nothingtodohere*/}elseif(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);}elseif(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);}elseelog(ERROR,"unrecognizednodetype:%d",(int)nodeTag(jtnode));}

eval_const_expressions

Node*eval_const_expressions(PlannerInfo*root,Node*node){eval_const_expressions_contextcontext;if(root)context.boundParams=root->glob->boundParams;/*boundParams*/elsecontext.boundParams=NULL;context.root=root;/*forinlined-functiondependencies*/context.active_fns=NIL;/*nothingbeingrecursivelysimplified*/context.case_val=NULL;/*noCASEbeingexamined*/context.estimate=false;/*safetransformationsonly*///调用XX_mutator函数遍历处理returneval_const_expressions_mutator(node,&context);}

eval_const_expressions_mutator

/**Recursivegutsofeval_const_expressions/estimate_expression_value*/staticNode*eval_const_expressions_mutator(Node*node,eval_const_expressions_context*context){if(node==NULL)returnNULL;switch(nodeTag(node)){caseT_Param:{Param*param=(Param*)node;ParamListInfoparamLI=context->boundParams;/*Looktoseeifwe'vebeengivenavalueforthisParam*/if(param->paramkind==PARAM_EXTERN&&paramLI!=NULL&&param->paramid>0&&param->paramid<=paramLI->numParams){ParamExternData*prm;ParamExternDataprmdata;/**Givehookachanceincaseparameterisdynamic.Tell*itthatthisfetchisspeculative,soitshouldavoid*erroringoutifparameterisunavailable.*/if(paramLI->paramFetch!=NULL)prm=paramLI->paramFetch(paramLI,param->paramid,true,&prmdata);elseprm=&paramLI->params[param->paramid-1];/**Wedon'tjustcheckOidIsValid,butinsistthatthe*fetchedtypematchtheParam,justincasethehookdid*somethingunexpected.Noneedtothrowanerrorhere*though;leavethatforruntime.*/if(OidIsValid(prm->ptype)&&prm->ptype==param->paramtype){/*OKtosubstituteparametervalue?*/if(context->estimate||(prm->pflags&PARAM_FLAG_CONST)){/**ReturnaConstrepresentingtheparamvalue.*Mustcopypass-by-refdatatypes,sincethe*Parammightbeinamemorycontext*shorter-livedthanouroutputplanshouldbe.*/int16typLen;booltypByVal;Datumpval;get_typlenbyval(param->paramtype,&typLen,&typByVal);if(prm->isnull||typByVal)pval=prm->value;elsepval=datumCopy(prm->value,typByVal,typLen);return(Node*)makeConst(param->paramtype,param->paramtypmod,param->paramcollid,(int)typLen,pval,prm->isnull,typByVal);}}}/**Notreplaceable,sojustcopytheParam(noneedto*recurse)*/return(Node*)copyObject(param);}caseT_WindowFunc:{WindowFunc*expr=(WindowFunc*)node;Oidfuncid=expr->winfnoid;List*args;Expr*aggfilter;HeapTuplefunc_tuple;WindowFunc*newexpr;/**Wecan'treallysimplifyaWindowFuncnode,butwemustn't*justfallthroughtothedefaultprocessing,becausewe*havetoapplyexpand_function_argumentstoitsargument*list.Thattakescareofinsertingdefaultargumentsand*expandingnamed-argumentnotation.*/func_tuple=SearchSysCache1(PROCOID,ObjectIdGetDatum(funcid));if(!HeapTupleIsValid(func_tuple))elog(ERROR,"cachelookupfailedforfunction%u",funcid);args=expand_function_arguments(expr->args,expr->wintype,func_tuple);ReleaseSysCache(func_tuple);/*Now,recursivelysimplifytheargs(whichareaList)*/args=(List*)expression_tree_mutator((Node*)args,eval_const_expressions_mutator,(void*)context);/*...andthefilterexpression,whichisn't*/aggfilter=(Expr*)eval_const_expressions_mutator((Node*)expr->aggfilter,context);/*AndbuildthereplacementWindowFuncnode*/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;}caseT_FuncExpr:{FuncExpr*expr=(FuncExpr*)node;List*args=expr->args;Expr*simple;FuncExpr*newexpr;/**Codeforop/funcreductionisprettybulky,sosplititout*asaseparatefunction.Note:exprTypmodnormallyreturns*-1foraFuncExpr,butnotwhenthenodeisrecognizablya*lengthcoercion;wewanttopreservethetypmodinthe*eventualConstifso.*/simple=simplify_function(expr->funcid,expr->funcresulttype,exprTypmod(node),expr->funccollid,expr->inputcollid,&args,expr->funcvariadic,true,true,context);if(simple)/*successfullysimplifiedit*/return(Node*)simple;/**Theexpressioncannotbesimplifiedanyfurther,sobuild*andreturnareplacementFuncExprnodeusingthe*possibly-simplifiedarguments.Notethatwehavealso*convertedtheargumentlisttopositionalnotation.*/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;}caseT_OpExpr://操作(运算)表达式{OpExpr*expr=(OpExpr*)node;List*args=expr->args;Expr*simple;OpExpr*newexpr;/**NeedtogetOIDofunderlyingfunction.Okaytoscribble*oninputtothisextent.*/set_opfuncid(expr);/**Codeforop/funcreductionisprettybulky,sosplititout*asaseparatefunction.*/simple=simplify_function(expr->opfuncid,expr->opresulttype,-1,expr->opcollid,expr->inputcollid,&args,false,true,true,context);if(simple)/*successfullysimplifiedit*/return(Node*)simple;/**Iftheoperatorisbooleanequalityorinequality,weknow*howtosimplifycasesinvolvingoneconstantandone*non-constantargument.*/if(expr->opno==BooleanEqualOperator||expr->opno==BooleanNotEqualOperator){simple=(Expr*)simplify_boolean_equality(expr->opno,args);if(simple)/*successfullysimplifiedit*/return(Node*)simple;}/**Theexpressioncannotbesimplifiedanyfurther,sobuild*andreturnareplacementOpExprnodeusingthe*possibly-simplifiedarguments.*/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;}caseT_DistinctExpr:{DistinctExpr*expr=(DistinctExpr*)node;List*args;ListCell*arg;boolhas_null_input=false;boolall_null_input=true;boolhas_nonconst_input=false;Expr*simple;DistinctExpr*newexpr;/**ReduceconstantsintheDistinctExpr'sarguments.Weknow*argsiseitherNILoraListnode,sowecancall*expression_tree_mutatordirectlyratherthanrecursingto*self.*/args=(List*)expression_tree_mutator((Node*)expr->args,eval_const_expressions_mutator,(void*)context);/**WemustdoourowncheckforNULLsbecauseDistinctExprhas*differentresultsforNULLinputthantheunderlying*operatordoes.*/foreach(arg,args){if(IsA(lfirst(arg),Const)){has_null_input|=((Const*)lfirst(arg))->constisnull;all_null_input&=((Const*)lfirst(arg))->constisnull;}elsehas_nonconst_input=true;}/*allconstants?thencanoptimizethisout*/if(!has_nonconst_input){/*allnulls?thennotdistinct*/if(all_null_input)returnmakeBoolConst(false,false);/*onenull?thendistinct*/if(has_null_input)returnmakeBoolConst(true,false);/*otherwisetrytoevaluatethe'='operator*//*(NOTokaytotrytoinlineit,though!)*//**NeedtogetOIDofunderlyingfunction.Okayto*scribbleoninputtothisextent.*/set_opfuncid((OpExpr*)expr);/*relyonstruct*equivalence*//**Codeforop/funcreductionisprettybulky,sosplitit*outasaseparatefunction.*/simple=simplify_function(expr->opfuncid,expr->opresulttype,-1,expr->opcollid,expr->inputcollid,&args,false,false,false,context);if(simple)/*successfullysimplifiedit*/{/**Sincetheunderlyingoperatoris"=",mustnegate*itsresult*/Const*csimple=castNode(Const,simple);csimple->constvalue=BoolGetDatum(!DatumGetBool(csimple->constvalue));return(Node*)csimple;}}/**Theexpressioncannotbesimplifiedanyfurther,sobuild*andreturnareplacementDistinctExprnodeusingthe*possibly-simplifiedarguments.*/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;}caseT_ScalarArrayOpExpr:{ScalarArrayOpExpr*saop;/*Copythenodeandconst-simplifyitsarguments*/saop=(ScalarArrayOpExpr*)ece_generic_processing(node);/*Makesureweknowunderlyingfunction*/set_sa_opfuncid(saop);/**IfallargumentsareConsts,andit'sasafefunction,we*canfoldtoaconstant*/if(ece_all_arguments_const(saop)&&ece_function_is_safe(saop->opfuncid,context))returnece_evaluate_expr(saop);return(Node*)saop;}caseT_BoolExpr:{BoolExpr*expr=(BoolExpr*)node;switch(expr->boolop){caseOR_EXPR:{List*newargs;boolhaveNull=false;boolforceTrue=false;newargs=simplify_or_arguments(expr->args,context,&haveNull,&forceTrue);if(forceTrue)returnmakeBoolConst(true,false);if(haveNull)newargs=lappend(newargs,makeBoolConst(false,true));/*IfalltheinputsareFALSE,resultisFALSE*/if(newargs==NIL)returnmakeBoolConst(false,false);/**Ifonlyonenonconst-or-NULLinput,it'sthe*result*/if(list_length(newargs)==1)return(Node*)linitial(newargs);/*ElsewestillneedanORnode*/return(Node*)make_orclause(newargs);}caseAND_EXPR:{List*newargs;boolhaveNull=false;boolforceFalse=false;newargs=simplify_and_arguments(expr->args,context,&haveNull,&forceFalse);if(forceFalse)returnmakeBoolConst(false,false);if(haveNull)newargs=lappend(newargs,makeBoolConst(false,true));/*IfalltheinputsareTRUE,resultisTRUE*/if(newargs==NIL)returnmakeBoolConst(true,false);/**Ifonlyonenonconst-or-NULLinput,it'sthe*result*/if(list_length(newargs)==1)return(Node*)linitial(newargs);/*ElsewestillneedanANDnode*/return(Node*)make_andclause(newargs);}caseNOT_EXPR:{Node*arg;Assert(list_length(expr->args)==1);arg=eval_const_expressions_mutator(linitial(expr->args),context);/**Usenegate_clause()toseeifwecansimplify*awaytheNOT.*/returnnegate_clause(arg);}default:elog(ERROR,"unrecognizedboolop:%d",(int)expr->boolop);break;}break;}caseT_SubPlan:caseT_AlternativeSubPlan:/**ReturnaSubPlanunchanged---toolatetodoanythingwithit.**XXXshouldweereport()hereinstead?Probablythisroutine*shouldneverbeinvokedafterSubPlancreation.*/returnnode;caseT_RelabelType:{/**Ifwecansimplifytheinputtoaconstant,thenwedon't*needtheRelabelTypenodeanymore:justchangethetype*fieldoftheConstnode.Otherwise,mustcopythe*RelabelTypenode.*/RelabelType*relabel=(RelabelType*)node;Node*arg;arg=eval_const_expressions_mutator((Node*)relabel->arg,context);/**IfwefindstackedRelabelTypes(eg,fromfoo::int::*oid)wecandiscardallbutthetopone.*/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;}}caseT_CoerceViaIO:{CoerceViaIO*expr=(CoerceViaIO*)node;List*args;Oidoutfunc;boolouttypisvarlena;Oidinfunc;Oidintypioparam;Expr*simple;CoerceViaIO*newexpr;/*MakeaListsowecanusesimplify_function*/args=list_make1(expr->arg);/**CoerceViaIOrepresentscallingthesourcetype'soutput*functionthentheresulttype'sinputfunction.So,tryto*simplifyitasthoughitwereastackoftwosuchfunction*calls.Firstweneedtoknowwhatthefunctionsare.**Notethatthecoercionfunctionsareassumednottocare*aboutinputcollation,sowejustpassInvalidOidforthat.*/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)/*successfullysimplifiedoutputfn*/{/**Inputfunctionsmaywant1to3arguments.Wealways*supplyallthree,trustingthatnothingdownstreamwill*complain.*/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)/*successfullysimplifiedinputfn*/return(Node*)simple;}/**Theexpressioncannotbesimplifiedanyfurther,sobuild*andreturnareplacementCoerceViaIOnodeusingthe*possibly-simplifiedargument.*/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;}caseT_ArrayCoerceExpr:{ArrayCoerceExpr*ac;/*Copythenodeandconst-simplifyitsarguments*/ac=(ArrayCoerceExpr*)ece_generic_processing(node);/**Ifconstantargumentandtheper-elementexpressionis*immutable,wecansimplifythewholethingtoaconstant.*Exception:althoughcontain_mutable_functionsconsiders*CoerceToDomainimmutableforhistoricalreasons,let'snot*dosohere;thisensurescoerciontoanarray-over-domain*doesnotapplythedomain'sconstraintsuntilruntime.*/if(ac->arg&&IsA(ac->arg,Const)&&ac->elemexpr&&!IsA(ac->elemexpr,CoerceToDomain)&&!contain_mutable_functions((Node*)ac->elemexpr))returnece_evaluate_expr(ac);return(Node*)ac;}caseT_CollateExpr:{/**Ifwecansimplifytheinputtoaconstant,thenwedon't*needtheCollateExprnodeatall:justchangethe*constcollidfieldoftheConstnode.Otherwise,replace*theCollateExprwithaRelabelType.(Wedothatsoasto*improveuniformityofexpressionrepresentationandthus*simplifycomparisonofexpressions.)*/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;}elseif(collate->collOid==exprCollation(arg)){/*Don'tneedaRelabelTypeeither...*/returnarg;}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;/*Don'tcreatestackedRelabelTypes*/while(arg&&IsA(arg,RelabelType))arg=(Node*)((RelabelType*)arg)->arg;relabel->arg=(Expr*)arg;return(Node*)relabel;}}caseT_CaseExpr:{/*----------*CASEexpressionscanbesimplifiedifthereareconstant*conditionclauses:*FALSE(orNULL):dropthealternative*TRUE:dropallremainingalternatives*Ifthefirstnon-FALSEalternativeisaconstantTRUE,*wecansimplifytheentireCASEtothatalternative's*expression.Iftherearenonon-FALSEalternatives,*wesimplifytheentireCASEtothedefaultresult(ELSE).**Ifwehaveasimple-formCASEwithconstanttest*expression,wesubstitutetheconstantvalueforcontained*CaseTestExprplaceholdernodes,sothatwehavethe*opportunitytoreduceconstanttestconditions.For*examplethisallows*CASE0WHEN0THEN1ELSE1/0END*toreduceto1ratherthandrawingadivide-by-0error.*Notethatwhenthetestexpressionisconstant,wedon't*havetoincludeitintheresultingCASE;forexample*CASE0WHENxTHENyELSEzEND*istransformedbytheparserto*CASE0WHENCaseTestExpr=xTHENyELSEzEND*whichwecansimplifyto*CASEWHEN0=xTHENyELSEzEND*Itisnotnecessaryfortheexecutortoevaluatethe"arg"*expressionwhenexecutingtheCASE,sinceanycontained*CaseTestExprsthatmighthavereferredtoitwillhavebeen*replacedbytheconstant.*----------*/CaseExpr*caseexpr=(CaseExpr*)node;CaseExpr*newcase;Node*save_case_val;Node*newarg;List*newargs;boolconst_true_cond;Node*defresult=NULL;ListCell*arg;/*Simplifythetestexpression,ifany*/newarg=eval_const_expressions_mutator((Node*)caseexpr->arg,context);/*SetupforcontainedCaseTestExprnodes*/save_case_val=context->case_val;if(newarg&&IsA(newarg,Const)){context->case_val=newarg;newarg=NULL;/*notneededanymore,seeabove*/}elsecontext->case_val=NULL;/*SimplifytheWHENclauses*/newargs=NIL;const_true_cond=false;foreach(arg,caseexpr->args){CaseWhen*oldcasewhen=lfirst_node(CaseWhen,arg);Node*casecond;Node*caseresult;/*Simplifythisalternative'stestcondition*/casecond=eval_const_expressions_mutator((Node*)oldcasewhen->expr,context);/**IfthetestconditionisconstantFALSE(orNULL),then*dropthisWHENclausecompletely,withoutprocessing*theresult.*/if(casecond&&IsA(casecond,Const)){Const*const_input=(Const*)casecond;if(const_input->constisnull||!DatumGetBool(const_input->constvalue))continue;/*dropalternativewithFALSEcond*//*Elseit'sconstantTRUE*/const_true_cond=true;}/*Simplifythisalternative'sresultvalue*/caseresult=eval_const_expressions_mutator((Node*)oldcasewhen->result,context);/*Ifnon-constanttestcondition,emitanewWHENnode*/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;}/**FoundaTRUEcondition,sononeoftheremaining*alternativescanbereached.Wetreattheresultas*thedefaultresult.*/defresult=caseresult;break;}/*Simplifythedefaultresult,unlesswereplaceditabove*/if(!const_true_cond)defresult=eval_const_expressions_mutator((Node*)caseexpr->defresult,context);context->case_val=save_case_val;/**Ifnonon-FALSEalternatives,CASEreducestothedefault*result*/if(newargs==NIL)returndefresult;/*OtherwiseweneedanewCASEnode*/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;}caseT_CaseTestExpr:{/**IfweknowaconstanttestvalueforthecurrentCASE*construct,substituteitfortheplaceholder.Elsejust*returntheplaceholderas-is.*/if(context->case_val)returncopyObject(context->case_val);elsereturncopyObject(node);}caseT_ArrayRef:caseT_ArrayExpr:caseT_RowExpr:{/**Generichandlingfornodetypeswhoseownprocessingis*knowntobeimmutable,andforwhichweneednosmarts*beyond"simplifyifallinputsareconstants".*//*Copythenodeandconst-simplifyitsarguments*/node=ece_generic_processing(node);/*IfallargumentsareConsts,wecanfoldtoaconstant*/if(ece_all_arguments_const(node))returnece_evaluate_expr(node);returnnode;}caseT_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);/**Wecanremovenullconstantsfromthelist.Fora*non-nullconstant,ifithasnotbeenprecededbyany*othernon-null-constantexpressionsthenitisthe*result.Otherwise,it'sthenextargument,butwecan*dropfollowingargumentssincetheywillneverbe*reached.*/if(IsA(e,Const)){if(((Const*)e)->constisnull)continue;/*dropnullconstant*/if(newargs==NIL)returne;/*firstexpr*/newargs=lappend(newargs,e);break;}newargs=lappend(newargs,e);}/**Ifalltheargumentswereconstantnull,theresultisjust*null*/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;}caseT_SQLValueFunction:{/**AllvariantsofSQLValueFunctionarestable,soifweare*estimatingtheexpression'svalue,weshouldevaluatethe*currentfunctionvalue.Otherwisejustcopy.*/SQLValueFunction*svf=(SQLValueFunction*)node;if(context->estimate)return(Node*)evaluate_expr((Expr*)svf,svf->type,svf->typmod,InvalidOid);elsereturncopyObject((Node*)svf);}caseT_FieldSelect:{/**Wecanoptimizefieldselectionfromawhole-rowVarintoa*simpleVar.(Thiscasewon'tbegenerateddirectlybythe*parser,becauseParseComplexProjectionshort-circuitsit.*Butitcanarisewhilesimplifyingfunctions.)Also,we*canoptimizefieldselectionfromaRowExprconstruct,or*ofcoursefromaconstant.**However,replacingawhole-rowVarinthiswayhasa*pitfall:ifwe'vealreadybuiltthereltargetlistforthe*sourcerelation,thenthewhole-rowVarisscheduledtobe*producedbytherelationscan,butthesimpleVarprobably*isn't,whichwillleadtoafailureinsetrefs.c.Thisis*notaproblemwhenhandlingsimplesingle-levelqueries,in*whichexpressionsimplificationalwayshappensfirst.It*isariskforlateralreferencesfromsubqueries,though.*Toavoidsuchfailures,don'toptimizeuplevelreferences.**Wemustalsocheckthatthedeclaredtypeofthefieldis*stillthesameaswhentheFieldSelectwascreated---this*canchangeifsomeonedidALTERCOLUMNTYPEontherowtype.*Ifitisn't,weskiptheoptimization;thecasewill*probablyfailatruntime,butthat'snotourproblemhere.*/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))returnfld;}}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))returnece_evaluate_expr(newfselect);}return(Node*)newfselect;}caseT_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)){/**WebreakROW(...)IS[NOT]NULLintoseparatetestson*itscomponentfields.Thisformisusuallymore*efficienttoevaluate,aswellasbeingmoreamenable*tooptimization.*/RowExpr*rarg=(RowExpr*)arg;List*newargs=NIL;ListCell*l;foreach(l,rarg->args){Node*relem=(Node*)lfirst(l);/**AconstantfieldrefutesthewholeNullTestifit's*ofthewrongnullness;elsewecandiscardit.*/if(relem&&IsA(relem,Const)){Const*carg=(Const*)relem;if(carg->constisnull?(ntest->nulltesttype==IS_NOT_NULL):(ntest->nulltesttype==IS_NULL))returnmakeBoolConst(false,false);continue;}/**Else,makeascalar(argisrow==false)NullTest*forthisfield.Scalarsemanticsarerequired*becauseIS[NOT]NULLdoesn'trecurse;seecomments*inExecEvalRowNullInt().*/newntest=makeNode(NullTest);newntest->arg=(Expr*)relem;newntest->nulltesttype=ntest->nulltesttype;newntest->argisrow=false;newntest->location=ntest->location;newargs=lappend(newargs,newntest);}/*Ifalltheinputswereconstants,resultisTRUE*/if(newargs==NIL)returnmakeBoolConst(true,false);/*Ifonlyonenonconstinput,it'stheresult*/if(list_length(newargs)==1)return(Node*)linitial(newargs);/*ElseweneedanANDnode*/return(Node*)make_andclause(newargs);}if(!ntest->argisrow&&arg&&IsA(arg,Const)){Const*carg=(Const*)arg;boolresult;switch(ntest->nulltesttype){caseIS_NULL:result=carg->constisnull;break;caseIS_NOT_NULL:result=!carg->constisnull;break;default:elog(ERROR,"unrecognizednulltesttype:%d",(int)ntest->nulltesttype);result=false;/*keepcompilerquiet*/break;}returnmakeBoolConst(result,false);}newntest=makeNode(NullTest);newntest->arg=(Expr*)arg;newntest->nulltesttype=ntest->nulltesttype;newntest->argisrow=ntest->argisrow;newntest->location=ntest->location;return(Node*)newntest;}caseT_BooleanTest:{/**Thiscasecouldbefoldedintothegenerichandlingused*forArrayRefetc.Butbecausethesimplificationlogicis*sotrivial,applyingevaluate_expr()toperformitwouldbe*aheavyoverhead.BooleanTestisprobablycommonenoughto*justifykeepingthisbespokeimplementation.*/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;boolresult;switch(btest->booltesttype){caseIS_TRUE:result=(!carg->constisnull&&DatumGetBool(carg->constvalue));break;caseIS_NOT_TRUE:result=(carg->constisnull||!DatumGetBool(carg->constvalue));break;caseIS_FALSE:result=(!carg->constisnull&&!DatumGetBool(carg->constvalue));break;caseIS_NOT_FALSE:result=(carg->constisnull||DatumGetBool(carg->constvalue));break;caseIS_UNKNOWN:result=carg->constisnull;break;caseIS_NOT_UNKNOWN:result=!carg->constisnull;break;default:elog(ERROR,"unrecognizedbooltesttype:%d",(int)btest->booltesttype);result=false;/*keepcompilerquiet*/break;}returnmakeBoolConst(result,false);}newbtest=makeNode(BooleanTest);newbtest->arg=(Expr*)arg;newbtest->booltesttype=btest->booltesttype;newbtest->location=btest->location;return(Node*)newbtest;}caseT_PlaceHolderVar:/**Inestimationmode,juststripthePlaceHolderVarnode*altogether;thisamountstoestimatingthatthecontainedvalue*won'tbeforcedtonullbyanouterjoin.Inregularmodewe*justusethedefaultbehavior(ie,simplifytheexpressionbut*leavethePlaceHolderVarnodeintact).*/if(context->estimate){PlaceHolderVar*phv=(PlaceHolderVar*)node;returneval_const_expressions_mutator((Node*)phv->phexpr,context);}break;default:break;}/**Foranynodetypenothandledabove,copythenodeunchangedbut*const-simplifyitssubexpressions.Thisisthecorrectthingfornode*typeswhosebehaviormightchangebetweenplanningandexecution,such*asCoerceToDomain.It'salsoasafedefaultfornewnodetypesnot*knowntothisroutine.*/returnece_generic_processing(node);}

simplify_function

/**Subroutineforeval_const_expressions:trytosimplifyafunctioncall*(whichmightoriginallyhavebeenanoperator;wedon'tcare)**InputsarethefunctionOID,actualresulttypeOID(whichisneededfor*polymorphicfunctions),resulttypmod,resultcollation,theinput*collationtouseforthefunction,theoriginalargumentlist(not*const-simplifiedyet,unlessprocess_argsisfalse),andsomeflags;*alsothecontextdataforeval_const_expressions.**Returnsasimplifiedexpressionifsuccessful,orNULLifcannot*simplifythefunctioncall.**Thisfunctionisalsoresponsibleforconvertingnamed-notationargument*listsintopositionalnotationand/oraddinganyneededdefaultargument*expressions;whichisabitgrotty,butitavoidsextrafetchesofthe*function'spg_proctuple.Forthisreason,theargslistis*pass-by-reference.Conversionandconst-simplificationoftheargslist*willbedoneevenifsimplificationofthefunctioncallitselfisnot*possible.*/staticExpr*simplify_function(Oidfuncid,Oidresult_type,int32result_typmod,Oidresult_collid,Oidinput_collid,List**args_p,boolfuncvariadic,boolprocess_args,boolallow_non_const,eval_const_expressions_context*context){List*args=*args_p;HeapTuplefunc_tuple;Form_pg_procfunc_form;Expr*newexpr;/**Wehavethreestrategiesforsimplification:executethefunctionto*deliveraconstantresult,useatransformfunctiontogeneratea*substitutenodetree,orexpandin-linethebodyofthefunction*definition(whichonlyworksforsimpleSQL-languagefunctions,but*thatisacommoncase).Eachcaseneedsaccesstothefunction's*pg_proctuple,sofetchitjustonce.**Note:theallow_non_constflagsuppressesboththesecondandthird*strategies;soif!allow_non_const,simplify_functioncanonlyreturna*ConstorNULL.Argument-listrewritinghappensanyway,though.*///查询proc(视为Tuple)func_tuple=SearchSysCache1(PROCOID,ObjectIdGetDatum(funcid));if(!HeapTupleIsValid(func_tuple))elog(ERROR,"cachelookupfailedforfunction%u",funcid);//从Tuple中分解得到函数体func_form=(Form_pg_proc)GETSTRUCT(func_tuple);/**Processthefunctionarguments,unlessthecallerdiditalready.**Herewemustdealwithnamedordefaultedarguments,andthen*recursivelyapplyeval_const_expressionstothewholeargumentlist.*/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);//递归处理/*Argumentprocessingdone,giveitbacktothecaller*/*args_p=args;//重新赋值}/*Nowattemptsimplificationofthefunctioncallproper.*/newexpr=evaluate_function(funcid,result_type,result_typmod,result_collid,input_collid,args,funcvariadic,func_tuple,context);//对函数进行预求解//求解成功并且允许非Const值并且(func_form->protransform是合法的Oidif(!newexpr&&allow_non_const&&OidIsValid(func_form->protransform)){/**BuildadummyFuncExprnodecontainingthesimplifiedarglist.We*usethisapproachtopresentauniforminterfacetothetransform*functionregardlessofhowthefunctionisactuallybeinginvoked.*/FuncExprfexpr;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);returnnewexpr;}


/**evaluate_expr:pre-evaluateaconstantexpression**Weusetheexecutor'sroutineExecEvalExpr()toavoidduplicationof*codeandensurewegetthesameresultastheexecutorwouldget.*/staticExpr*evaluate_expr(Expr*expr,Oidresult_type,int32result_typmod,Oidresult_collation){EState*estate;ExprState*exprstate;MemoryContextoldcontext;Datumconst_val;boolconst_is_null;int16resultTypLen;boolresultTypByVal;/**Tousetheexecutor,weneedanEState.*/estate=CreateExecutorState();/*Wecanusetheestate'sworkingcontexttoavoidmemoryleaks.*/oldcontext=MemoryContextSwitchTo(estate->es_query_cxt);/*Makesureanyopfuncidsarefilledin.*/fix_opfuncids((Node*)expr);/**Prepareexprforexecution.(Note:wecan'tuseExecPrepareExpr*becauseit'dresultinrecursivelyinvokingeval_const_expressions.)*///初始化表达式,为执行作准备//把函数放在exprstate->evalfunc中exprstate=ExecInitExpr(expr,NULL);/**Andevaluateit.**ItisOKtouseadefaultecontextbecausenoneoftheExecEvalExpr()*codeusedinthissituationwilluseecontext.Thatmightseem*fortuitous,butit'snotsounreasonable---aconstantexpressiondoes*notdependoncontext,bydefinition,n'estcepas?*/const_val=ExecEvalExprSwitchContext(exprstate,GetPerTupleExprContext(estate),&const_is_null);//执行表达式求解/*Getinfoneededaboutresultdatatype*/get_typlenbyval(result_type,&resultTypLen,&resultTypByVal);/*Getbacktooutermemorycontext*/MemoryContextSwitchTo(oldcontext);/**Mustcopyresultoutofsub-contextusedbyexpressioneval.**Also,ifit'svarlena,forciblydetoastit.Thisprotectsusagainst*storingTOASTpointersintoplansthatmightoutlivethereferenced*data.(makeConstwouldhandledetoastinganyway,butit'sworthafew*extralinesheresothatwecandothecopyanddetoastinonestep.)*/if(!const_is_null){if(resultTypLen==-1)const_val=PointerGetDatum(PG_DETOAST_DATUM_COPY(const_val));elseconst_val=datumCopy(const_val,resultTypByVal,resultTypLen);}/*Releaseallthejunkwejustcreated*/FreeExecutorState(estate);/**Maketheconstantresultnode.*/return(Expr*)makeConst(result_type,result_typmod,result_collation,resultTypLen,const_val,const_is_null,resultTypByVal);}/**ExecEvalExprSwitchContext**SameasExecEvalExpr,butgetintotherightallocationcontextexplicitly.*/#ifndefFRONTENDstaticinlineDatumExecEvalExprSwitchContext(ExprState*state,ExprContext*econtext,bool*isNull){DatumretDatum;MemoryContextoldContext;oldContext=MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);retDatum=state->evalfunc(state,econtext,isNull);MemoryContextSwitchTo(oldContext);returnretDatum;}#endif三、跟踪分析

测试脚本,表达式位于targetList中:

selectmax(a.dwbh::int+(1+2))fromt_dwxxa;

gdb跟踪:

Breakpoint1,preprocess_expression(root=0x133eca8,expr=0x13441a8,kind=1)atplanner.c:10071007if(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)infobreakNumTypeDispEnbAddressWhat1breakpointkeepy0x000000000076ac6finpreprocess_expressionatplanner.c:1007breakpointalreadyhit8times(gdb)del1(gdb)bclauses.c:2713Breakpoint2at0x78952a:fileclauses.c,line2713.(gdb)cContinuing.Breakpoint2,eval_const_expressions_mutator(node=0x124cbf0,context=0x7ffebc48f630)atclauses.c:27162716set_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)cContinuing.Breakpoint2,eval_const_expressions_mutator(node=0x124cb30,context=0x7ffebc48f630)atclauses.c:27162716set_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)stepsimplify_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)atclauses.c:40224022List*args=*args_p;...#函数是int4pl(gdb)p*func_form$38={proname={data="int4pl",'\000'<repeats57times>},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)pconst_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)atclauses.c:44244424}(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)atclauses.c:40674067if(!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中表达式预处理主要的函数有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!