这篇文章主要介绍了PostgreSQL如何实现上拉子链接,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

按官方文档的介绍,子链接Sublink代表的是出现在表达式(可能会出现组合运算符)中的子查询,子查询的类型包括:
EXISTS_SUBLINK
语法:EXISTS(SELECT ...)

select*fromt_dwxxawhereexists(selectb.dwbhfromt_grxxbwherea.dwbh=b.dwbh);

ALL_SUBLINK
语法:(lefthand) op ALL (SELECT ...)

select*fromt_dwxxawheredwbh>all(selectb.dwbhfromt_grxxb);

ANY_SUBLINK
语法:(lefthand) op ANY (SELECT ...)

select*fromt_dwxxawheredwbh=any(selectb.dwbhfromt_grxxb);

ROWCOMPARE_SUBLINK
语法:(lefthand) op (SELECT ...)

select*fromt_dwxxawheredwbh>(selectmax(b.dwbh)fromt_grxxb);

EXPR_SUBLINK
语法:(SELECT with single targetlist item ...)

select*,(selectmax(dwbh)fromt_grxx)fromt_dwxxa;

MULTIEXPR_SUBLINK
语法:(SELECT with multiple targetlist items ...)

ARRAY_SUBLINK
语法:ARRAY(SELECT with single targetlist item ...)

CTE_SUBLINK
语法:
WITH query (never actually part of an expression)

官方说明:

/**SubLink**ASubLinkrepresentsasubselectappearinginanexpression,andinsome*casesalsothecombiningoperator(s)justaboveit.ThesubLinkType*indicatestheformoftheexpressionrepresented:*EXISTS_SUBLINKEXISTS(SELECT...)*ALL_SUBLINK(lefthand)opALL(SELECT...)*ANY_SUBLINK(lefthand)opANY(SELECT...)*ROWCOMPARE_SUBLINK(lefthand)op(SELECT...)*EXPR_SUBLINK(SELECTwithsingletargetlistitem...)*MULTIEXPR_SUBLINK(SELECTwithmultipletargetlistitems...)*ARRAY_SUBLINKARRAY(SELECTwithsingletargetlistitem...)*CTE_SUBLINKWITHquery(neveractuallypartofanexpression)*ForALL,ANY,andROWCOMPARE,thelefthandisalistofexpressionsofthe*samelengthasthesubselect'stargetlist.ROWCOMPAREwill*always*have*alistwithmorethanoneentry;ifthesubselecthasjustonetarget*thentheparserwillcreateanEXPR_SUBLINKinstead(andanyoperator*abovethesubselectwillberepresentedseparately).*ROWCOMPARE,EXPR,andMULTIEXPRrequirethesubselecttodeliveratmost*onerow(ifitreturnsnorows,theresultisNULL).*ALL,ANY,andROWCOMPARErequirethecombiningoperatorstodeliverboolean*results.ALLandANYcombinetheper-rowresultsusingANDandOR*semanticsrespectively.*ARRAYrequiresjustonetargetcolumn,andcreatesanarrayofthetarget*column'stypeusinganynumberofrowsresultingfromthesubselect.**子链接属于ExprNode,但并不意味着子链接是可以执行的.子链接必须在计划期间通过子计划节点在表达式树中替换*SubLinkisclassedasanExprnode,butitisnotactuallyexecutable;*itmustbereplacedintheexpressiontreebyaSubPlannodeduring*planning.**NOTE:intherawoutputofgram.y,testexprcontainsjusttherawform*ofthelefthandexpression(ifany),andoperNameistheStringnameof*thecombiningoperator.Also,subselectisarawparsetree.Duringparse*analysis,theparsertransformstestexprintoacompletebooleanexpression*thatcomparesthelefthandvalue(s)toPARAM_SUBLINKnodesrepresentingthe*outputcolumnsofthesubselect.AndsubselectistransformedtoaQuery.*Thisistherepresentationseeninsavedrulesandintherewriter.**InEXISTS,EXPR,MULTIEXPR,andARRAYSubLinks,testexprandoperName*areunusedandarealwaysnull.**subLinkIdiscurrentlyusedonlyforMULTIEXPRSubLinks,andiszeroin*otherSubLinks.Thisnumberidentifiesdifferentmultiple-assignment*subquerieswithinanUPDATEstatement'sSETlist.Itisuniqueonly*withinaparticulartargetlist.Theoutputcolumn(s)oftheMULTIEXPR*arereferencedbyPARAM_MULTIEXPRParamsappearingelsewhereinthetlist.**TheCTE_SUBLINKcaseneveroccursinactualSubLinknodes,butitisused*inSubPlansgeneratedforWITHsubqueries.*/typedefenumSubLinkType{EXISTS_SUBLINK,ALL_SUBLINK,ANY_SUBLINK,ROWCOMPARE_SUBLINK,EXPR_SUBLINK,MULTIEXPR_SUBLINK,ARRAY_SUBLINK,CTE_SUBLINK/*forSubPlansonly*/}SubLinkType;typedefstructSubLink{Exprxpr;SubLinkTypesubLinkType;/*seeabove*/intsubLinkId;/*ID(1..n);0ifnotMULTIEXPR*/Node*testexpr;/*outer-querytestforALL/ANY/ROWCOMPARE*/List*operName;/*originallyspecifiedoperatorname*/Node*subselect;/*subselectasQuery*orrawparsetree*/intlocation;/*tokenlocation,or-1ifunknown*/}SubLink;二、源码解读

standard_planner函数

/*******************************************************************************Queryoptimizerentrypoint**Tosupportloadablepluginsthatmonitorormodifyplannerbehavior,*weprovideahookvariablethatletsaplugingetcontrolbeforeand*afterthestandardplanningprocess.Thepluginwouldnormallycall*standard_planner().**Notetopluginauthors:standard_planner()scribblesonitsQueryinput,*soyou'dbettercopythatdatastructureifyouwanttoplanmorethanonce.******************************************************************************/PlannedStmt*planner(Query*parse,intcursorOptions,ParamListInfoboundParams){PlannedStmt*result;if(planner_hook)result=(*planner_hook)(parse,cursorOptions,boundParams);//钩子函数,可以实现定制化开发elseresult=standard_planner(parse,cursorOptions,boundParams);//PG的标准实现returnresult;}/*输入参数:parse-查询树cursorOptions-游标处理选项,见本节中的数据结构boundParams-绑定变量?输出参数:*/PlannedStmt*standard_planner(Query*parse,intcursorOptions,ParamListInfoboundParams){PlannedStmt*result;//最终结果PlannerGlobal*glob;//全局优化信息doubletuple_fraction;//优化过程中元组的采样率PlannerInfo*root;//执行计划的根节点RelOptInfo*final_rel;//优化后的Relation信息Path*best_path;//最优路径Plan*top_plan;//顶层计划ListCell*lp,//临时变量*lr;/**Setupglobalstateforthisplannerinvocation.Thisdataisneeded*acrossalllevelsofsub-Querythatmightexistinthegivencommand,*sowekeepitinaseparatestructthat'slinkedtobyeachper-Query*PlannerInfo.*///初始化全局优化信息glob=makeNode(PlannerGlobal);glob->boundParams=boundParams;glob->subplans=NIL;glob->subroots=NIL;glob->rewindPlanIDs=NULL;glob->finalrtable=NIL;glob->finalrowmarks=NIL;glob->resultRelations=NIL;glob->nonleafResultRelations=NIL;glob->rootResultRelations=NIL;glob->relationOids=NIL;glob->invalItems=NIL;glob->paramExecTypes=NIL;glob->lastPHId=0;glob->lastRowMarkId=0;glob->lastPlanNodeId=0;glob->transientPlan=false;glob->dependsOnRole=false;/**Assesswhetherit'sfeasibletouseparallelmodeforthisquery.We*can'tdothisinastandalonebackend,orifthecommandwilltryto*modifyanydata,orifthisisacursoroperation,orifGUCsareset*tovaluesthatdon'tpermitparallelism,orifparallel-unsafe*functionsarepresentinthequerytree.**(NotethatwedoallowCREATETABLEAS,SELECTINTO,andCREATE*MATERIALIZEDVIEWtouseparallelplans,butthisissafeonlybecause*thecommandiswritingintoacompletelynewtablewhichworkerswon't*beabletosee.Iftheworkerscouldseethetable,thefactthat*grouplockingwouldcausethemtoignoretheleader'sheavyweight*relationextensionlockandGINpagelockswouldmakethisunsafe.*We'llhavetofixthatsomehowifwewanttoallowparallelinsertsin*general;updatesanddeleteshaveadditionalproblemsespeciallyaround*comboCIDs.)**Fornow,wedon'ttrytouseparallelmodeifwe'rerunninginsidea*parallelworker.Wemighteventuallybeabletorelaxthis*restriction,butfornowitseemsbestnottohaveparallelworkers*tryingtocreatetheirownparallelworkers.**Wecan'tuseparallelisminserializablemodebecausethepredicate*lockingcodeisnotparallel-aware.It'snotcatastrophicifsomeone*triestorunaparallelplaninserializablemode;itjustwon'tget*anyworkersandwillrunserially.Butitseemslikeagoodheuristic*toassumethatthesameserializationlevelwillbeineffectatplan*timeandexecutiontime,sodon'tgenerateaparallelplanifwe'rein*serializablemode.*///判断是否可以使用并行模式//并行是很大的一个话题,有待以后再谈if((cursorOptions&CURSOR_OPT_PARALLEL_OK)!=0&&IsUnderPostmaster&&parse->commandType==CMD_SELECT&&!parse->hasModifyingCTE&&max_parallel_workers_per_gather>0&&!IsParallelWorker()&&!IsolationIsSerializable()){/*allthecheaptestspass,soscanthequerytree*/glob->maxParallelHazard=max_parallel_hazard(parse);glob->parallelModeOK=(glob->maxParallelHazard!=PROPARALLEL_UNSAFE);}else{/*skipthequerytreescan,justassumeit'sunsafe*/glob->maxParallelHazard=PROPARALLEL_UNSAFE;glob->parallelModeOK=false;}/**glob->parallelModeNeededisnormallysettofalsehereandchangedto*trueduringplancreationifaGatherorGatherMergeplanisactually*created(cf.create_gather_plan,create_gather_merge_plan).**However,ifforce_parallel_mode=onorforce_parallel_mode=regress,*thenweimposeparallelmodewheneverit'ssafetodoso,evenifthe*finalplandoesn'tuseparallelism.It'snotsafetodosoifthe*querycontainsanythingparallel-unsafe;parallelModeOKwillbefalse*inthatcase.NotethatparallelModeOKcan'tchangeafterthispoint.*Otherwise,everythinginthequeryiseitherparallel-safeor*parallel-restricted,andineithercaseitshouldbeOKtoimpose*parallel-moderestrictions.Ifthatendsupbreakingsomething,then*eithersomefunctiontheuserincludedinthequeryisincorrectly*labelledasparallel-safeorparallel-restrictedwheninrealityit's*parallel-unsafe,orelsethequeryplanneritselfhasabug.*/glob->parallelModeNeeded=glob->parallelModeOK&&(force_parallel_mode!=FORCE_PARALLEL_OFF);/*Determinewhatfractionoftheplanislikelytobescanned*/if(cursorOptions&CURSOR_OPT_FAST_PLAN)//fast-startplan?{/**WehavenorealideahowmanytuplestheuserwillultimatelyFETCH*fromacursor,butitisoftenthecasethathedoesn'twant'em*all,orwouldpreferafast-startplananywaysothathecan*processsomeofthetuplessooner.UseaGUCparametertodecide*whatfractiontooptimizefor.*/tuple_fraction=cursor_tuple_fraction;/**Wedocumentcursor_tuple_fractionassimplybeingafraction,which*meanstheedgecases0and1havetobetreatedspeciallyhere.We*convert1to0("allthetuples")and0toaverysmallfraction.*/if(tuple_fraction>=1.0)tuple_fraction=0.0;elseif(tuple_fraction<=0.0)tuple_fraction=1e-10;}else{/*Defaultassumptionisweneedallthetuples*/tuple_fraction=0.0;}//以上:setupforrecursivehandlingofsubqueries,为子查询配置处理器(递归方式)/*primaryplanningentrypoint(mayrecurseforsubqueries)*/root=subquery_planner(glob,parse,NULL,false,tuple_fraction);//进入子查询优化器/*SelectbestPathandturnitintoaPlan*/final_rel=fetch_upper_rel(root,UPPERREL_FINAL,NULL);//获得最上层的优化后的Relationbest_path=get_cheapest_fractional_path(final_rel,tuple_fraction);//获得最佳路径top_plan=create_plan(root,best_path);//创建计划/**Ifcreatingaplanforascrollablecursor,makesureitcanrun*backwardsondemand.AddaMaterialnodeatthetopatneed.*/if(cursorOptions&CURSOR_OPT_SCROLL){if(!ExecSupportsBackwardScan(top_plan))top_plan=materialize_finished_plan(top_plan);//如果是Scroll游标,在前台执行,那么物化之(数据不能长期占用内存,但又要满足Scroll的要求,需要物化至磁盘中)}/**OptionallyaddaGathernodefortestingpurposes,providedthisis*actuallyasafethingtodo.*/if(force_parallel_mode!=FORCE_PARALLEL_OFF&&top_plan->parallel_safe)//并行执行,添加Gather节点{Gather*gather=makeNode(Gather);/**IfthereareanyinitPlansattachedtotheformerly-topplannode,*movethemuptotheGathernode;sameaswedoforMaterialnodein*materialize_finished_plan.*/gather->plan.initPlan=top_plan->initPlan;top_plan->initPlan=NIL;gather->plan.targetlist=top_plan->targetlist;gather->plan.qual=NIL;gather->plan.lefttree=top_plan;gather->plan.righttree=NULL;gather->num_workers=1;gather->single_copy=true;gather->invisible=(force_parallel_mode==FORCE_PARALLEL_REGRESS);/**SincethisGatherhasnoparallel-awaredescendantstosignalto,*wedon'tneedarescanParam.*/gather->rescan_param=-1;/**Ideallywe'dusecost_gatherhere,butsettingupdummypathdata*tosatisfyitdoesn'tseemmuchcleanerthanknowingwhatitdoes.*/gather->plan.startup_cost=top_plan->startup_cost+parallel_setup_cost;gather->plan.total_cost=top_plan->total_cost+parallel_setup_cost+parallel_tuple_cost*top_plan->plan_rows;gather->plan.plan_rows=top_plan->plan_rows;gather->plan.plan_width=top_plan->plan_width;gather->plan.parallel_aware=false;gather->plan.parallel_safe=false;/*useparallelmodeforparallelplans.*/root->glob->parallelModeNeeded=true;top_plan=&gather->plan;}/**IfanyParamsweregenerated,runthroughtheplantreeandcompute*eachplannode'sextParam/allParamsets.Ideallywe'dmergethisinto*set_plan_references'treetraversal,butfornowithastobeseparate*becauseweneedtovisitsubplansbeforenotaftermainplan.*/if(glob->paramExecTypes!=NIL){Assert(list_length(glob->subplans)==list_length(glob->subroots));forboth(lp,glob->subplans,lr,glob->subroots){Plan*subplan=(Plan*)lfirst(lp);PlannerInfo*subroot=lfirst_node(PlannerInfo,lr);SS_finalize_plan(subroot,subplan);}SS_finalize_plan(root,top_plan);}/*finalcleanupoftheplan*/Assert(glob->finalrtable==NIL);Assert(glob->finalrowmarks==NIL);Assert(glob->resultRelations==NIL);Assert(glob->nonleafResultRelations==NIL);Assert(glob->rootResultRelations==NIL);top_plan=set_plan_references(root,top_plan);/*...andthesubplans(bothregularsubplansandinitplans)*/Assert(list_length(glob->subplans)==list_length(glob->subroots));forboth(lp,glob->subplans,lr,glob->subroots){Plan*subplan=(Plan*)lfirst(lp);PlannerInfo*subroot=lfirst_node(PlannerInfo,lr);lfirst(lp)=set_plan_references(subroot,subplan);}/*buildthePlannedStmtresult*/result=makeNode(PlannedStmt);result->commandType=parse->commandType;result->queryId=parse->queryId;result->hasReturning=(parse->returningList!=NIL);result->hasModifyingCTE=parse->hasModifyingCTE;result->canSetTag=parse->canSetTag;result->transientPlan=glob->transientPlan;result->dependsOnRole=glob->dependsOnRole;result->parallelModeNeeded=glob->parallelModeNeeded;result->planTree=top_plan;result->rtable=glob->finalrtable;result->resultRelations=glob->resultRelations;result->nonleafResultRelations=glob->nonleafResultRelations;result->rootResultRelations=glob->rootResultRelations;result->subplans=glob->subplans;result->rewindPlanIDs=glob->rewindPlanIDs;result->rowMarks=glob->finalrowmarks;result->relationOids=glob->relationOids;result->invalItems=glob->invalItems;result->paramExecTypes=glob->paramExecTypes;/*utilityStmtshouldbenull,butwemightaswellcopyit*/result->utilityStmt=parse->utilityStmt;result->stmt_location=parse->stmt_location;result->stmt_len=parse->stmt_len;result->jitFlags=PGJIT_NONE;if(jit_enabled&&jit_above_cost>=0&&top_plan->total_cost>jit_above_cost){result->jitFlags|=PGJIT_PERFORM;/**Decidehowmucheffortshouldbeputintogeneratingbettercode.*/if(jit_optimize_above_cost>=0&&top_plan->total_cost>jit_optimize_above_cost)result->jitFlags|=PGJIT_OPT3;if(jit_inline_above_cost>=0&&top_plan->total_cost>jit_inline_above_cost)result->jitFlags|=PGJIT_INLINE;/**DecidewhichoperationsshouldbeJITed.*/if(jit_expressions)result->jitFlags|=PGJIT_EXPR;if(jit_tuple_deforming)result->jitFlags|=PGJIT_DEFORM;}returnresult;}

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);//上拉子链接//其他内容...returnroot;}

pull_up_sublinks

下一小节介绍三、基础信息

数据结构/宏定义
1、cursorOptions

/*----------------------*DeclareCursorStatement**The"query"fieldisinitiallyarawparsetree,andisconvertedtoa*Querynodeduringparseanalysis.Notethatrewritingandplanning*ofthequeryarealwayspostponeduntilexecution.*----------------------*/#defineCURSOR_OPT_BINARY0x0001/*BINARY*/#defineCURSOR_OPT_SCROLL0x0002/*SCROLLexplicitlygiven*/#defineCURSOR_OPT_NO_SCROLL0x0004/*NOSCROLLexplicitlygiven*/#defineCURSOR_OPT_INSENSITIVE0x0008/*INSENSITIVE*/#defineCURSOR_OPT_HOLD0x0010/*WITHHOLD*//*theseplanner-controlflagsdonotcorrespondtoanySQLgrammar:*/#defineCURSOR_OPT_FAST_PLAN0x0020/*preferfast-startplan*/#defineCURSOR_OPT_GENERIC_PLAN0x0040/*forceuseofgenericplan*/#defineCURSOR_OPT_CUSTOM_PLAN0x0080/*forceuseofcustom#defineCURSOR_OPT_PARALLEL_OK0x0100/*parallelmodeOK*/

2、Relids

/**Relids*Setofrelationidentifiers(indexesintotherangetable).*/typedefBitmapset*Relids;/*Theunitsizecanbeadjustedbychangingthesethreedeclarations:*/#defineBITS_PER_BITMAPWORD32typedefuint32bitmapword;/*mustbeanunsignedtype*/typedefint32signedbitmapword;/*mustbethematchingsignedtype*/typedefstructBitmapset{intnwords;/*numberofwordsinarray*/bitmapwordwords[FLEXIBLE_ARRAY_MEMBER];/*really[nwords]*/}Bitmapset;四、跟踪分析

测试脚本:

testdb=#explainselect*fromt_dwxxawheredwbh>all(selectb.dwbhfromt_grxxb);QUERYPLAN--------------------------------------------------------------------------SeqScanont_dwxxa(cost=0.00..1498.00rows=80width=474)Filter:(SubPlan1)SubPlan1->Materialize(cost=0.00..17.35rows=490width=38)->SeqScanont_grxxb(cost=0.00..14.90rows=490width=38)(5rows)

启动gdb跟踪:

(gdb)bpull_up_sublinksBreakpoint1at0x77cbc6:fileprepjointree.c,line157.(gdb)cContinuing.Breakpoint1,pull_up_sublinks(root=0x126fd48)atprepjointree.c:157157(Node*)root->parse->jointree,(gdb)#查看输入参数(gdb)p*root$1={type=T_PlannerInfo,parse=0x11b43d8,glob=0x11b4e00,query_level=1,parent_root=0x0,plan_params=0x0,outer_params=0x0,simple_rel_array=0x0,simple_rel_array_size=0,simple_rte_array=0x0,all_baserels=0x0,nullable_baserels=0x0,join_rel_list=0x0,join_rel_hash=0x0,join_rel_level=0x0,join_cur_level=0,init_plans=0x0,cte_plan_ids=0x0,multiexpr_params=0x0,eq_classes=0x0,canon_pathkeys=0x0,left_join_clauses=0x0,right_join_clauses=0x0,full_join_clauses=0x0,join_info_list=0x0,append_rel_list=0x0,rowMarks=0x0,placeholder_list=0x0,fkey_list=0x0,query_pathkeys=0x0,group_pathkeys=0x0,window_pathkeys=0x0,distinct_pathkeys=0x0,sort_pathkeys=0x0,part_schemes=0x0,initial_rels=0x0,upper_rels={0x0,0x0,0x0,0x0,0x0,0x0,0x0},upper_targets={0x0,0x0,0x0,0x0,0x0,0x0,0x0},processed_tlist=0x0,grouping_map=0x0,minmax_aggs=0x0,planner_cxt=0x11b2e90,total_table_pages=0,tuple_fraction=0,limit_tuples=0,qual_security_level=0,inhTargetKind=INHKIND_NONE,hasJoinRTEs=false,hasLateralRTEs=false,hasDeletedRTEs=false,hasHavingQual=false,hasPseudoConstantQuals=false,hasRecursion=false,wt_param_id=-1,non_recursive_path=0x0,curOuterRels=0x0,curOuterParams=0x0,join_search_private=0x0,partColsUpdated=false}#jointree的类型为FromExpr(gdb)p*root->parse->jointree$3={type=T_FromExpr,fromlist=0x11b4870,quals=0x11b40e8}(gdb)n156jtnode=pull_up_sublinks_jointree_recurse(root,#进入pull_up_sublinks_jointree_recurse函数(gdb)steppull_up_sublinks_jointree_recurse(root=0x126fd48,jtnode=0x1282ea0,relids=0x7ffe830ab9b0)atprepjointree.c:180180if(jtnode==NULL)#查看参数#1.root与pull_up_sublinks函数的输入一致#2.jtnode类型为FromExpr#3.relids(gdb)p*jtnode$7={type=T_FromExpr}(gdb)p*(FromExpr*)jtnode$8={type=T_FromExpr,fromlist=0x11b4870,quals=0x11b40e8}#FromExpr->fromlist中的的元素类型为RangeTblRef(gdb)p*((FromExpr*)jtnode)->fromlist$9={type=T_List,length=1,head=0x11b4850,tail=0x11b4850}(gdb)p*(Node*)((FromExpr*)jtnode)->fromlist->head->data.ptr_value$10={type=T_RangeTblRef}...#进入FromExpr分支191elseif(IsA(jtnode,FromExpr))...201foreach(l,f->fromlist)(gdb)207lfirst(l),(gdb)p*l$11={data={ptr_value=0x11b4838,int_value=18565176,oid_value=18565176},next=0x0}(gdb)p*(RangeTblRef*)l->data.ptr_value$13={type=T_RangeTblRef,rtindex=1}#递归调用pull_up_sublinks_jointree_recurse(gdb)n206newchild=pull_up_sublinks_jointree_recurse(root,(gdb)steppull_up_sublinks_jointree_recurse(root=0x126fd48,jtnode=0x11b4838,relids=0x7ffe830ab940)atprepjointree.c:180180if(jtnode==NULL)#输入参数#1.root与pull_up_sublinks函数的输入一致#2.jtnode类型为RangeTblRef#3.relids#进入RangeTblRef分支(gdb)n184elseif(IsA(jtnode,RangeTblRef))(gdb)n186intvarno=((RangeTblRef*)jtnode)->rtindex;(gdb)188*relids=bms_make_singleton(varno);(gdb)312returnjtnode;(gdb)p*relids$16=(Relids)0x12704c8...(gdb)p*newchild$19={type=T_RangeTblRef}(gdb)n210frelids=bms_join(frelids,childrelids);(gdb)p*frelids$25={nwords=1,words=0x12704cc}(gdb)p*frelids->words$26=2...#进入pull_up_sublinks_qual_recurse(gdb)n217newf->quals=pull_up_sublinks_qual_recurse(root,f->quals,(gdb)steppull_up_sublinks_qual_recurse(root=0x126fd48,node=0x11b40e8,jtlink1=0x7ffe830ab948,available_rels1=0x12704c8,jtlink2=0x0,available_rels2=0x0)atprepjointree.c:335335if(node==NULL)#输入参数#1.root与上述无异#2.node(gdb)p*node$35={type=T_SubLink}(gdb)p*(SubLink*)node$36={xpr={type=T_SubLink},subLinkType=ALL_SUBLINK,subLinkId=0,testexpr=0x1282e00,operName=0x11b3cf8,subselect=0x1282578,location=35}#3.jtlink1,指针数组(gdb)p*(RangeTblRef*)((FromExpr*)jtlink1[0])->fromlist->head->data->ptr_value$45={type=T_RangeTblRef,rtindex=1}#4.available_rels1,可用的Relids(gdb)p*available_rels1$47={nwords=1,words=0x12704cc}(gdb)p*available_rels1->words$48=2#5/6,NULL值(gdb)n337if(IsA(node,SubLink))(gdb)339SubLink*sublink=(SubLink*)node;(gdb)344if(sublink->subLinkType==ANY_SUBLINK)(gdb)398elseif(sublink->subLinkType==EXISTS_SUBLINK)(gdb)psublink->subLinkType$49=ALL_SUBLINK#非ANY/EXISTS链接,退出(gdb)n453returnnode;(gdb)#回到pull_up_sublinks_jointree_recurse(gdb)pull_up_sublinks_jointree_recurse(root=0x126fd48,jtnode=0x1282ea0,relids=0x7ffe830ab9b0)atprepjointree.c:230230*relids=frelids;(gdb)231jtnode=jtlink;(gdb)312returnjtnode;#返回的jtnode为RangeTblRef(gdb)p*(RangeTblRef*)((FromExpr*)jtnode)->fromlist->head->data.ptr_value$55={type=T_RangeTblRef,rtindex=1}(gdb)n313}(gdb)pull_up_sublinks(root=0x126fd48)atprepjointree.c:164164if(IsA(jtnode,FromExpr))(gdb)165root->parse->jointree=(FromExpr*)jtnode;(gdb)p*root->parse->jointree$56={type=T_FromExpr,fromlist=0x11b4870,quals=0x11b40e8}(gdb)p*root->parse->jointree->fromlist$57={type=T_List,length=1,head=0x11b4850,tail=0x11b4850}(gdb)n168}(gdb)subquery_planner(glob=0x11b4e00,parse=0x11b43d8,parent_root=0x0,hasRecursion=false,tuple_fraction=0)atplanner.c:656656inline_set_returning_functions(root);(gdb)cContinuing.#ANY类型并没有做上拉操作

感谢你能够认真阅读完这篇文章,希望小编分享的“PostgreSQL如何实现上拉子链接”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!