本篇内容介绍了“怎么使用PostgreSQ中的ExecMaterial函数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、数据结构

SubPlanState
子计划运行期状态

/*----------------*SubPlanStatenode*----------------*/typedefstructSubPlanState{NodeTagtype;SubPlan*subplan;/*expressionplannode*/structPlanState*planstate;/*subselectplan'sstatetree*/structPlanState*parent;/*parentplannode'sstatetree*/ExprState*testexpr;/*组合表达式状态;stateofcombiningexpression*/List*args;/*参数表达式状态;statesofargumentexpression(s)*/HeapTuplecurTuple;/*subplan最近的元组;copyofmostrecenttuplefromsubplan*/DatumcurArray;/*mostrecentarrayfromARRAY()subplan*//*theseareusedwhenhashingthesubselect'soutput:*/TupleDescdescRight;/*投影后的子查询描述符;subselectdescafterprojection*/ProjectionInfo*projLeft;/*forprojectinglefthandexprs*/ProjectionInfo*projRight;/*forprojectingsubselectoutput*/TupleHashTablehashtable;/*hashtableforno-nullssubselectrows*/TupleHashTablehashnulls;/*hashtableforrowswithnull(s)*/boolhavehashrows;/*trueifhashtableisnotempty*/boolhavenullrows;/*trueifhashnullsisnotempty*/MemoryContexthashtablecxt;/*memorycontextcontaininghashtables*/MemoryContexthashtempcxt;/*tempmemorycontextforhashtables*/ExprContext*innerecontext;/*econtextforcomputinginnertuples*/AttrNumber*keyColIdx;/*controldataforhashtables*/Oid*tab_eq_funcoids;/*equalityfuncoidsfortable*datatype(s)*/Oid*tab_collations;/*collationsforhashandcomparison*/FmgrInfo*tab_hash_funcs;/*hashfunctionsfortabledatatype(s)*/FmgrInfo*tab_eq_funcs;/*equalityfunctionsfortabledatatype(s)*/FmgrInfo*lhs_hash_funcs;/*hashfunctionsforlefthanddatatype(s)*/FmgrInfo*cur_eq_funcs;/*equalityfunctionsforLHSvs.table*/ExprState*cur_eq_comp;/*equalitycomparatorforLHSvs.table*/}SubPlanState;

SubPlan
子查询计划

/**SubPlan-executableexpressionnodeforasubplan(sub-SELECT)**TheplannerreplacesSubLinknodesinexpressiontreeswithSubPlan*nodesafterithasfinishedplanningthesubquery.SubPlanreferences*asub-plantreestoredinthesubplanslistofthetoplevelPlannedStmt.*(Weavoidadirectlinktomakeiteasiertocopyexpressiontrees*withoutcausingmultipleprocessingofthesubplan.)*查询规划器在完成子查询的规划后使用SubPlan节点替换表达式树中的SubLink节点。*SubPlan引用了存储在高层PlannedStmt中的subplans链表中的sub-plantree。*(避免使用直接链接,从而使得拷贝表达式树相对比较简单)**Inanordinarysubplan,testexprpointstoanexecutableexpression*(OpExpr,anAND/ORtreeofOpExprs,orRowCompareExpr)forthecombining*operator(s);theleft-handargumentsaretheoriginallefthandexpressions,*andtheright-handargumentsarePARAM_EXECParamnodesrepresentingthe*outputsofthesub-select.(NOTE:runtimecoercionfunctionsmaybe*insertedaswell.)Thisisjustthesameexpressiontreeastestexprin*theoriginalSubLinknode,butthePARAM_SUBLINKnodesarereplacedby*suitablynumberedPARAM_EXECnodes.*常规情况下,testexpr指向用于组合操作的可执行表达式(OpExpr、OpExprs的AND/OR树或者RowCompareExpr);*左参数是原始的左表达式,右参数是PARAM_EXEC参数节点用以表示子查询的输出。*与原始SubLink节点的testexpr具有相同的表达式树,但PARAM_SUBLINK节点则使用合适的已编号PARAM_EXEC节点替代。**Ifthesub-selectbecomesaninitplanratherthanasubplan,theexecutable*expressionispartoftheouterplan'sexpressiontree(andtheSubPlan*nodeitselfisnot,butratherisfoundintheouterplan'sinitPlan*list).InthiscasetestexprisNULLtoavoidduplication.*如果子查询成了initplan而不是subplan,可执行的表达式是外层plan表达式树的一部分。*这种情况下,testexpr为NULL以避免重复。**Theplanneralsoderiveslistsofthevaluesthatneedtobepassedinto*andoutofthesubplan.Inputvaluesarerepresentedasalist"args"of*expressionstobeevaluatedintheouter-querycontext(currentlythese*argsarealwaysjustVars,butinprincipletheycouldbeanyexpression).*ThevaluesareassignedtotheglobalPARAM_EXECparamsindexedbyparParam*(theparParamandargslistsmusthavethesameordering).setParamisa*listofthePARAM_EXECparamsthatarecomputedbythesub-select,ifit*isaninitplan;theyarelistedinorderbysub-selectoutputcolumn*position.(parParamandsetParamareintegerLists,notBitmapsets,*becausetheirorderingissignificant.)*规划器还派生了需要传入和传出子计划的值的链表。*输入值标识位表达式的“args”链表,在外层查询上下文中进行解析。*(这些args通常是Vars,但原则上它们可以是任意表达式)*这些值以parParam为索引给全局PARAM_EXEC参数赋值。*setParam是PARAM_EXEC参数链表,通过子查询(如为initplan)计算所得。*它们按子查询输出列的位置进行排序组织为链表形式。*(parParam和setParam是整型链表,而不是Bitmapsets链表)**Also,theplannercomputesstartupandper-callcostsforuseofthe*SubPlan.Notethattheseincludethecostofthesubqueryproper,*evaluationofthetestexprifany,andanyhashtablemanagementoverhead.*同时,规划器计算SubPlan启动和每次调用的成本。注意:包括子查询正常解析testexpr的成本以及哈希表管理成本。*/typedefstructSubPlan{Exprxpr;//表达式/*FieldscopiedfromoriginalSubLink:*///从SubLink中拷贝而来SubLinkTypesubLinkType;/*seeabove*//*Thecombiningoperators,transformedtoanexecutableexpression:*///组合操作符,转换为可执行的表达式Node*testexpr;/*OpExprorRowCompareExprexpressiontree*/List*paramIds;/*参数IDs;IDsofParamsembeddedintheabove*//*IdentificationofthePlantreetouse:*///Plantree标识intplan_id;/*Index(from1)inPlannedStmt.subplans*//*IdentificationoftheSubPlanforEXPLAINanddebuggingpurposes:*///EXPLAIN和debug目的的SubPlan标识char*plan_name;/*Anameassignedduringplanning*//*Extradatausefulfordeterminingsubplan'soutputtype:*///用于确定subplan输出类型的额外信息OidfirstColType;/*subplan结果的第一个列类型;Typeoffirstcolumnofsubplanresult*/int32firstColTypmod;/*第一列的Typmod;Typmodoffirstcolumnofsubplanresult*/OidfirstColCollation;/*第一列的Collation;Collationoffirstcolumnofsubplan*result*//*Informationaboutexecutionstrategy:*///执行阶段的相关信息booluseHashTable;/*是否使用哈希表存储子查询输出;truetostoresubselectoutputinahash*table(implieswearedoing"IN")*/boolunknownEqFalse;/*如OK为T,如为未知则为F;快速处理null值;trueifit'sokaytoreturnFALSEwhenthe*specresultisUNKNOWN;thisallowsmuch*simplerhandlingofnullvalues*/boolparallel_safe;/*是否并行安全?isthesubplanparallel-safe?*//*Note:parallel_safedoesnotconsidercontentsoftestexprorargs*//*Informationforpassingparamsintoandoutofthesubselect:*///用于给子查询传入和传出参数的信息/*setParamandparParamarelistsofintegers(paramIDs)*///setParam和parParam是整型链表(paramIDs)List*setParam;/*initplansubquerieshavetosetthese*Paramsforparentplan*/List*parParam;/*indicesofinputParamsfromparentplan*/List*args;/*以parParam值进行传递的表达式;exprstopassasparParamvalues*//*Estimatedexecutioncosts:*///估算执行成本Coststartup_cost;/*one-timesetupcost*/Costper_call_cost;/*costforeachsubplanevaluation*/}SubPlan;

SubLinkType
SubLink类型

/**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.**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;

SubLink
SubLink结构体

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;

MaterialState
Material状态

/*----------------*MaterialStateinformation**materializenodesareusedtomaterializetheresults*ofasubplanintoatemporaryfile.*materialize节点用于物化subplan的结果为临时文件。**ss.ss_ScanTupleSlotreferstooutputofunderlyingplan.*ss.ss_ScanTupleSlot指向underlylingplan的输出(subplan)*----------------*/typedefstructMaterialState{ScanStatess;/*itsfirstfieldisNodeTag*/inteflags;/*传递给tuplestore的capability标记;capabilityflagstopasstotuplestore*/booleof_underlying;/*已经到达underlyingplan的末尾?reachedendofunderlyingplan?*/Tuplestorestate*tuplestorestate;}MaterialState;二、源码解读


/*----------------------------------------------------------------*ExecMaterial**Aslongasweareattheendofthedatacollectedinthetuplestore,*wecollectonenewrowfromthesubplanoneachcall,andstashit*asideinthetuplestorebeforereturningit.Thetuplestoreis*onlyreadifweareaskedtoscanbackwards,rescan,ormark/restore.*只要在tuplestore中数据收集结束时,就会在每次调用时从subplan中收集一条新行,*并在返回之前将其保存在tuplestore中。*只要在往后扫描、重新扫描或标记/恢复时tuplestore才会读取。**----------------------------------------------------------------*/staticTupleTableSlot*/*从subplan中返回的结果;resulttuplefromsubplan*/ExecMaterial(PlanState*pstate){MaterialState*node=castNode(MaterialState,pstate);//物化节点EState*estate;//运行期状态ScanDirectiondir;//扫描方向boolforward;//是否往前扫描Tuplestorestate*tuplestorestate;//Tuplestorestate结构体指针booleof_tuplestore;//是否完成?TupleTableSlot*slot;//存储元组的slotCHECK_FOR_INTERRUPTS();/**getstateinfofromnode*从物化节点中获取相关信息*/estate=node->ss.ps.state;dir=estate->es_direction;//方向forward=ScanDirectionIsForward(dir);//是否往前扫描tuplestorestate=node->tuplestorestate;/**Iffirsttimethrough,andweneedatuplestore,initializeit.*第一次,需要tuplestore并初始化*/if(tuplestorestate==NULL&&node->eflags!=0){tuplestorestate=tuplestore_begin_heap(true,false,work_mem);tuplestore_set_eflags(tuplestorestate,node->eflags);if(node->eflags&EXEC_FLAG_MARK){/**Allocateasecondreadpointertoserveasthemark.Weknowit*musthaveindex1,soneedn'tstorethat.*分配用于mark的读指针*/intptrnoPG_USED_FOR_ASSERTS_ONLY;ptrno=tuplestore_alloc_read_pointer(tuplestorestate,node->eflags);Assert(ptrno==1);}node->tuplestorestate=tuplestorestate;}/**Ifwearenotattheendofthetuplestore,oraregoingbackwards,try*tofetchatuplefromtuplestore.*如果不在tuplestore的末尾或者正在往后扫描,尝试从tuplestore中提取一个元组*/eof_tuplestore=(tuplestorestate==NULL)||tuplestore_ateof(tuplestorestate);if(!forward&&eof_tuplestore){if(!node->eof_underlying){/**WhenreversingdirectionattuplestoreEOF,thefirst*gettupleslotcallwillfetchthelast-addedtuple;butwewant*toreturntheonebeforethat,ifpossible.Sodoanextra*fetch.*在EOF处反转方向,第一次的gettupleslot调用会提取最后添加的元组;*但如可能,希望返回在此之前的元组,执行额外的提取操作。*/if(!tuplestore_advance(tuplestorestate,forward))returnNULL;/*thetuplestoremustbeempty*/}eof_tuplestore=false;}/**Ifwecanfetchanothertuplefromthetuplestore,returnit.*如能从tuplestore中提取另外一个tuple,返回*/slot=node->ss.ps.ps_ResultTupleSlot;if(!eof_tuplestore){if(tuplestore_gettupleslot(tuplestorestate,forward,false,slot))returnslot;if(forward)eof_tuplestore=true;}/**Ifnecessary,trytofetchanotherrowfromthesubplan.*如需要(tuplestore末尾),尝试从subplan中提取另外一行**Note:theeof_underlyingstatevariableexiststoshort-circuitfurther*subplancalls.It'snotoptional,unfortunately,becausesomeplan*nodetypesarenotrobustaboutbeingcalledagainwhenthey'vealready*returnedNULL.*/if(eof_tuplestore&&!node->eof_underlying){PlanState*outerNode;TupleTableSlot*outerslot;/**Wecanonlygetherewithforward==true,sononeedtoworryabout*whichdirectionthesubplanwillgo.*/outerNode=outerPlanState(node);outerslot=ExecProcNode(outerNode);if(TupIsNull(outerslot)){node->eof_underlying=true;returnNULL;}/**Appendacopyofthereturnedtupletotuplestore.NOTE:because*thetuplestoreiscertainlyinEOFstate,itsreadpositionwill*moveforwardovertheaddedtuple.Thisiswhatwewant.*追加返回的元组到tuplestore中。*注意:因为tuplestore当前处于EOF状态,读取的位置会前移至已添加的tuple前面,这是我们希望看到的。*/if(tuplestorestate)tuplestore_puttupleslot(tuplestorestate,outerslot);ExecCopySlot(slot,outerslot);returnslot;}/**Nothingleft...*/returnExecClearTuple(slot);}三、跟踪分析

执行SQL:

[pg12@localhost~]$psql-dtestdbTimingison.Expandeddisplayisusedautomatically.psql(12.0)Type"help"forhelp.[local]:5432pg12@testdb=#[local]:5432pg12@testdb=#select*fromtbl;id|value----+-------1|2(1row)Time:2.678ms[local]:5432pg12@testdb=#selectcount(*)fromt_big_null;count----------10000001(1row)Time:679.972ms[local]:5432pg12@testdb=#analyzetbl;ANALYZETime:64.442ms[local]:5432pg12@testdb=#analyzet_big_null;ANALYZETime:434.702ms[local]:5432pg12@testdb=#[local]:5432pg12@testdb=#selectpg_backend_pid();pg_backend_pid----------------18758(1row)Time:1.990ms[local]:5432pg12@testdb=#select*fromtblawherea.idnotin(selectb.idfromt_big_nullb);

启动gdb跟踪

(gdb)bExecMaterialBreakpoint1at0x720edb:filenodeMaterial.c,line41.(gdb)cContinuing.Breakpoint1,ExecMaterial(pstate=0x1230128)atnodeMaterial.c:4141MaterialState*node=castNode(MaterialState,pstate);(gdb)

输入参数

(gdb)p*pstate$4={type=T_MaterialState,plan=0x1211858,state=0x122fe88,ExecProcNode=0x720ecf<ExecMaterial>,ExecProcNodeReal=0x720ecf<ExecMaterial>,instrument=0x0,worker_instrument=0x0,worker_jit_instrument=0x0,qual=0x0,lefttree=0x1230240,righttree=0x0,initPlan=0x0,subPlan=0x0,chgParam=0x0,ps_ResultTupleDesc=0x1230660,ps_ResultTupleSlot=0x1230778,ps_ExprContext=0x0,ps_ProjInfo=0x0,scandesc=0x1230548,scanops=0xc3e720<TTSOpsMinimalTuple>,outerops=0x0,innerops=0x0,resultops=0xc3e720<TTSOpsMinimalTuple>,scanopsfixed=true,outeropsfixed=false,inneropsfixed=false,resultopsfixed=true,scanopsset=true,outeropsset=false,inneropsset=false,resultopsset=true}(gdb)

MaterialState结构体指针数据

(gdb)p*node$1={ss={ps={type=T_MaterialState,plan=0x1211858,state=0x122fe88,ExecProcNode=0x720ecf<ExecMaterial>,ExecProcNodeReal=0x720ecf<ExecMaterial>,instrument=0x0,worker_instrument=0x0,worker_jit_instrument=0x0,qual=0x0,lefttree=0x1230240,righttree=0x0,initPlan=0x0,subPlan=0x0,chgParam=0x0,ps_ResultTupleDesc=0x1230660,ps_ResultTupleSlot=0x1230778,ps_ExprContext=0x0,ps_ProjInfo=0x0,scandesc=0x1230548,scanops=0xc3e720<TTSOpsMinimalTuple>,outerops=0x0,innerops=0x0,resultops=0xc3e720<TTSOpsMinimalTuple>,scanopsfixed=true,outeropsfixed=false,inneropsfixed=false,resultopsfixed=true,scanopsset=true,outeropsset=false,inneropsset=false,resultopsset=true},ss_currentRelation=0x0,ss_currentScanDesc=0x0,ss_ScanTupleSlot=0x1230838},eflags=2,eof_underlying=false,tuplestorestate=0x0}(gdb)p*node->ss->ps->plan$2={type=T_Material,startup_cost=0,total_cost=233310.685,plan_rows=9999979,plan_width=4,parallel_aware=false,parallel_safe=true,plan_node_id=1,targetlist=0x1257600,qual=0x0,lefttree=0x1210f58,righttree=0x0,initPlan=0x0,extParam=0x0,allParam=0x0}(gdb)

运行期信息和方向

(gdb)p*estate$5={type=T_EState,es_direction=ForwardScanDirection,es_snapshot=0x1164d50,es_crosscheck_snapshot=0x0,es_range_table=0x1257328,es_range_table_array=0x12300d8,es_range_table_size=2,es_relations=0x1230100,es_rowmarks=0x0,es_plannedstmt=0x1257748,es_sourceText=0x113cd88"select*fromtblawherea.idnotin(selectb.idfromt_big_nullb);",es_junkFilter=0x0,es_output_cid=0,es_result_relations=0x0,es_num_result_relations=0,es_result_relation_info=0x0,es_root_result_relations=0x0,es_num_root_result_relations=0,es_partition_directory=0x0,es_tuple_routing_result_relations=0x0,es_trig_target_relations=0x0,es_param_list_info=0x0,es_param_exec_vals=0x12300a0,es_queryEnv=0x0,es_query_cxt=0x122fd70,es_tupleTable=0x1230510,es_processed=0,es_top_eflags=16,es_instrument=0,es_finished=false,es_exprcontexts=0x1230418,es_subplanstates=0x1230920,es_auxmodifytables=0x0,es_per_tuple_exprcontext=0x0,es_epq_active=0x0,es_use_parallel_mode=false,es_query_dsa=0x0,es_jit_flags=25,es_jit=0x0,es_jit_worker_instr=0x0}(gdb)pdir$6=ForwardScanDirection(gdb)

初始化tuplestore

(gdb)n64tuplestorestate=tuplestore_begin_heap(true,false,work_mem);(gdb)n65tuplestore_set_eflags(tuplestorestate,node->eflags);(gdb)p*tuplestorestate$7={status=TSS_INMEM,eflags=6,backward=false,interXact=false,truncated=false,availMem=4177896,allowedMem=4194304,tuples=0,myfile=0x0,context=0x122fd70,resowner=0x116e308,copytup=0xaba7bd<copytup_heap>,writetup=0xaba811<writetup_heap>,readtup=0xaba9d9<readtup_heap>,memtuples=0x1219e60,memtupdeleted=0,memtupcount=0,memtupsize=2048,growmemtuples=true,readptrs=0x123ca50,activeptr=0,readptrcount=1,readptrsize=8,writepos_file=0,writepos_offset=0}(gdb)n66if(node->eflags&EXEC_FLAG_MARK)(gdb)78node->tuplestorestate=tuplestorestate;(gdb)85eof_tuplestore=(tuplestorestate==NULL)||(gdb)p*tuplestorestate$8={status=TSS_INMEM,eflags=2,backward=false,interXact=false,truncated=false,availMem=4177896,allowedMem=4194304,tuples=0,myfile=0x0,context=0x122fd70,resowner=0x116e308,copytup=0xaba7bd<copytup_heap>,writetup=0xaba811<writetup_heap>,readtup=0xaba9d9<readtup_heap>,memtuples=0x1219e60,memtupdeleted=0,memtupcount=0,memtupsize=2048,growmemtuples=true,readptrs=0x123ca50,activeptr=0,readptrcount=1,readptrsize=8,writepos_file=0,writepos_offset=0}(gdb)

既不是往后扫描也没有到达EOF

(gdb)n86tuplestore_ateof(tuplestorestate);(gdb)85eof_tuplestore=(tuplestorestate==NULL)||(gdb)88if(!forward&&eof_tuplestore)(gdb)peof_tuplestore$9=false(gdb)pforward$10=true(gdb)

如能从tuplestore中提取另外一个tuple,则返回此slot

(gdb)n107slot=node->ss.ps.ps_ResultTupleSlot;(gdb)108if(!eof_tuplestore)(gdb)p*slot$11={type=T_TupleTableSlot,tts_flags=18,tts_nvalid=0,tts_ops=0xc3e720<TTSOpsMinimalTuple>,tts_tupleDescriptor=0x1230660,tts_values=0x12307e8,tts_isnull=0x12307f0,tts_mcxt=0x122fd70,tts_tid={ip_blkid={bi_hi=65535,bi_lo=65535},ip_posid=0},tts_tableOid=0}(gdb)pslot->tts_values[0]$12=0(gdb)n110if(tuplestore_gettupleslot(tuplestorestate,forward,false,slot))(gdb)

如扫描方向为往前,则设置eof_tuplestore为T,填充tuple到tuplestore中

112if(forward)(gdb)113eof_tuplestore=true;(gdb)

如需要(处于tuplestore末尾),尝试从subplan(扫描t_big_null)中提取另外一行

124if(eof_tuplestore&&!node->eof_underlying)(gdb)pnode->eof_underlying$13=false(gdb)n133outerNode=outerPlanState(node);(gdb)n134outerslot=ExecProcNode(outerNode);(gdb)135if(TupIsNull(outerslot))(gdb)p*outerNode$14={type=T_SeqScanState,plan=0x1210f58,state=0x122fe88,ExecProcNode=0x72b904<ExecSeqScan>,ExecProcNodeReal=0x72b904<ExecSeqScan>,instrument=0x0,worker_instrument=0x0,worker_jit_instrument=0x0,qual=0x0,lefttree=0x0,righttree=0x0,initPlan=0x0,subPlan=0x0,chgParam=0x0,ps_ResultTupleDesc=0x1230548,ps_ResultTupleSlot=0x0,ps_ExprContext=0x1230358,ps_ProjInfo=0x0,scandesc=0x7f6ec53386a8,scanops=0xc3e780<TTSOpsBufferHeapTuple>,outerops=0x0,innerops=0x0,resultops=0xc3e780<TTSOpsBufferHeapTuple>,scanopsfixed=true,outeropsfixed=false,inneropsfixed=false,resultopsfixed=true,scanopsset=true,outeropsset=false,inneropsset=false,resultopsset=true}(gdb)p*outerslot$15={type=T_TupleTableSlot,tts_flags=16,tts_nvalid=0,tts_ops=0xc3e780<TTSOpsBufferHeapTuple>,tts_tupleDescriptor=0x7f6ec53386a8,tts_values=0x12304c0,tts_isnull=0x12304c8,tts_mcxt=0x122fd70,tts_tid={ip_blkid={bi_hi=0,bi_lo=44240},ip_posid=1},tts_tableOid=49155}(gdb)pouterslot->tts_values[0]$16=0(gdb)pouterslot->tts_values[1]$17=0(gdb)###[local]:5432pg12@testdb=#selectoid,relnamefrompg_classwhereoid=49155;oid|relname-------+------------49155|t_big_null(1row)###

拷贝到tuplestore中,返回slot

(gdb)n146if(tuplestorestate)(gdb)147tuplestore_puttupleslot(tuplestorestate,outerslot);(gdb)149ExecCopySlot(slot,outerslot);(gdb)150returnslot;(gdb)p*slot$18={type=T_TupleTableSlot,tts_flags=20,tts_nvalid=0,tts_ops=0xc3e720<TTSOpsMinimalTuple>,tts_tupleDescriptor=0x1230660,tts_values=0x12307e8,tts_isnull=0x12307f0,tts_mcxt=0x122fd70,tts_tid={ip_blkid={bi_hi=65535,bi_lo=65535},ip_posid=0},tts_tableOid=0}(gdb)p*slot->tts_values$19=0(gdb)

继续执行

...(gdb)pslot->tts_values[0]$24=9998243(gdb)cContinuing.Breakpoint1,ExecMaterial(pstate=0x1230128)atnodeMaterial.c:4141MaterialState*node=castNode(MaterialState,pstate);(gdb)n49CHECK_FOR_INTERRUPTS();(gdb)54estate=node->ss.ps.state;(gdb)55dir=estate->es_direction;(gdb)56forward=ScanDirectionIsForward(dir);(gdb)57tuplestorestate=node->tuplestorestate;(gdb)62if(tuplestorestate==NULL&&node->eflags!=0)(gdb)85eof_tuplestore=(tuplestorestate==NULL)||(gdb)86tuplestore_ateof(tuplestorestate);(gdb)85eof_tuplestore=(tuplestorestate==NULL)||(gdb)88if(!forward&&eof_tuplestore)(gdb)107slot=node->ss.ps.ps_ResultTupleSlot;(gdb)108if(!eof_tuplestore)(gdb)124if(eof_tuplestore&&!node->eof_underlying)(gdb)133outerNode=outerPlanState(node);(gdb)134outerslot=ExecProcNode(outerNode);(gdb)135if(TupIsNull(outerslot))(gdb)146if(tuplestorestate)(gdb)147tuplestore_puttupleslot(tuplestorestate,outerslot);(gdb)149ExecCopySlot(slot,outerslot);(gdb)150returnslot;(gdb)pslot->tts_values[0]$25=9998244(gdb)...

“怎么使用PostgreSQ中的ExecMaterial函数”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!