分析PostgreSQL创建函数的过程
本篇内容主要讲解“分析PostgreSQL创建函数的过程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析PostgreSQL创建函数的过程”吧!
一、数据结构Form_pg_language
plpgsql语言定义结构体
/*----------------*pg_languagedefinition.cppturnsthisinto*typedefstructFormData_pg_language*----------------*/CATALOG(pg_language,2612,LanguageRelationId){Oidoid;/*oid*//*Languagename*/NameDatalanname;/*Language'sowner*/OidlanownerBKI_DEFAULT(PGUID);/*Isaprocedurallanguage*/boollanisplBKI_DEFAULT(f);/*PListrusted*/boollanpltrustedBKI_DEFAULT(f);/*Callhandler,ifit'saPL*/OidlanplcallfoidBKI_DEFAULT(0)BKI_LOOKUP(pg_proc);/*Optionalanonymous-blockhandlerfunction*/OidlaninlineBKI_DEFAULT(0)BKI_LOOKUP(pg_proc);/*Optionalvalidationfunction*/OidlanvalidatorBKI_DEFAULT(0)BKI_LOOKUP(pg_proc);#ifdefCATALOG_VARLEN/*variable-lengthfieldsstarthere*//*Accessprivileges*/aclitemlanacl[1]BKI_DEFAULT(_null_);#endif}FormData_pg_language;/*----------------*Form_pg_languagecorrespondstoapointertoatuplewith*theformatofpg_languagerelation.*----------------*/typedefFormData_pg_language*Form_pg_language;
ArrayType
/**Arraysarevarlenaobjects,somustmeetthevarlenaconventionthat*thefirstint32oftheobjectcontainsthetotalobjectsizeinbytes.*BesuretouseVARSIZE()andSET_VARSIZE()toaccessit,though!*Arrays是可变对象集,必须符合varlena约定,即对象的第一个int32包含对象的总大小(以字节为单位)。*但是,一定要确保使用VARSIZE和SET_VARSIZE函数范围该结构体**CAUTION:ifyouchangetheheaderforordinaryarraysyouwillalso*needtochangetheheadersforoidvectorandint2vector!*/typedefstruct{//可变的headerint32vl_len_;/*varlenaheader(donottouchdirectly!)*///维度intndim;/*#ofdimensions*///指向数据的偏移量,如为0则表示没有位图int32dataoffset;/*offsettodata,or0ifnobitmap*///元素类型的OIDOidelemtype;/*elementtypeOID*/}ArrayType;
DefElem
typedefstructDefElem{NodeTagtype;char*defnamespace;/*NULLifunqualifiedname*/char*defname;Node*arg;/*a(Value*)ora(TypeName*)*/DefElemActiondefaction;/*unspecifiedaction,orSET/ADD/DROP*/intlocation;/*tokenlocation,or-1ifunknown*/}DefElem;
FunctionParameter
typedefenumFunctionParameterMode{/*theassignedenumvaluesappearinpg_proc,don'tchange'em!*/FUNC_PARAM_IN='i',/*inputonly*/FUNC_PARAM_OUT='o',/*outputonly*/FUNC_PARAM_INOUT='b',/*both*/FUNC_PARAM_VARIADIC='v',/*variadic(alwaysinput)*/FUNC_PARAM_TABLE='t'/*tablefunctionoutputcolumn*/}FunctionParameterMode;typedefstructFunctionParameter{NodeTagtype;char*name;/*parametername,orNULLifnotgiven*/TypeName*argType;/*TypeNameforparametertype*/FunctionParameterModemode;/*IN/OUT/etc*/Node*defexpr;/*rawdefaultexpr,orNULLifnotgiven*/}FunctionParameter;
CatCache
/*functioncomputingadatum'shash*/typedefuint32(*CCHashFN)(Datumdatum);/*functioncomputingequalityoftwodatums*/typedefbool(*CCFastEqualFN)(Datuma,Datumb);typedefstructcatcache{//cacheIDintid;/*cacheidentifier---seesyscache.h*///cache的hash槽intcc_nbuckets;/*#ofhashbucketsinthiscache*///元组描述符TupleDesccc_tupdesc;/*tupledescriptor(copiedfromreldesc)*///hash桶dlist_head*cc_bucket;/*hashbuckets*///每个key的hash函数CCHashFNcc_hashfunc[CATCACHE_MAXKEYS];/*hashfunctionforeachkey*///每个key的快速等值函数CCFastEqualFNcc_fastequal[CATCACHE_MAXKEYS];/*fastequalfunctionfor*eachkey*///每个key的属性编号intcc_keyno[CATCACHE_MAXKEYS];/*AttrNumberofeachkey*///CatCList结构体链表dlist_headcc_lists;/*listofCatCListstructs*///cache中元组数intcc_ntup;/*#oftuplescurrentlyinthiscache*///keys数intcc_nkeys;/*#ofkeys(1..CATCACHE_MAXKEYS)*///cache元组相关的relationconstchar*cc_relname;/*nameofrelationthetuplescomefrom*///relationOIDOidcc_reloid;/*OIDofrelationthetuplescomefrom*///匹配缓存keys的索引OIDOidcc_indexoid;/*OIDofindexmatchingcachekeys*///是否可跨库共享?boolcc_relisshared;/*isrelationsharedacrossdatabases?*///链表链接slist_nodecc_next;/*listlink*///用于heap扫描的预计算key信息ScanKeyDatacc_skey[CATCACHE_MAXKEYS];/*precomputedkeyinfoforheap*scans*//**Keeptheseattheend,sothatcompilingcatcache.cwithCATCACHE_STATS*doesn'tbreakABIforothermodules*这些项放在最后面,以便使用CATCACHE_STATS选项编译catcache.c时不需要终止其他模块的ABI*/#ifdefCATCACHE_STATS//检索次数longcc_searches;/*total#searchesagainstthiscache*///匹配次数longcc_hits;/*#ofmatchesagainstexistingentry*///未命中次数longcc_neg_hits;/*#ofmatchesagainstnegativeentry*///未命中成功加载次数longcc_newloads;/*#ofsuccessfulloadsofnewentry*//**cc_searches-(cc_hits+cc_neg_hits+cc_newloads)isnumberoffailed*searches,eachofwhichwillresultinloadinganegativeentry\\*cc_searches-(cc_hits+cc_neg_hits+cc_newloads)是cache检索失败次数*///验证失效次数longcc_invals;/*#ofentriesinvalidatedfromcache*///链表检索次数longcc_lsearches;/*total#list-searches*///longcc_lhits;/*#ofmatchesagainstexistinglists*/#endif}CatCache;二、源码解读
HeapTupleSearchSysCache3(intcacheId,Datumkey1,Datumkey2,Datumkey3){//执行检查Assert(cacheId>=0&&cacheId<SysCacheSize&&PointerIsValid(SysCache[cacheId]));Assert(SysCache[cacheId]->cc_nkeys==3);//直接调用SearchCatCache3returnSearchCatCache3(SysCache[cacheId],key1,key2,key3);}HeapTupleSearchCatCache3(CatCache*cache,Datumv1,Datumv2,Datumv3){//直接调用SearchCatCacheInternalreturnSearchCatCacheInternal(cache,3,v1,v2,v3,0);}/**Work-horseforSearchCatCache/SearchCatCacheN.*通用函数:SearchCatCache/SearchCatCacheN调用*/staticinlineHeapTupleSearchCatCacheInternal(CatCache*cache,intnkeys,Datumv1,Datumv2,Datumv3,Datumv4){//#defineCATCACHE_MAXKEYS4Datumarguments[CATCACHE_MAXKEYS];uint32hashValue;IndexhashIndex;dlist_iteriter;dlist_head*bucket;CatCTup*ct;/*Makesurewe'reinanxact,evenifthisendsupbeingacachehit*///确保处于事务中Assert(IsTransactionState());Assert(cache->cc_nkeys==nkeys);/**one-timestartupoverheadforeachcache*/if(unlikely(cache->cc_tupdesc==NULL))CatalogCacheInitializeCache(cache);#ifdefCATCACHE_STATScache->cc_searches++;#endif/*Initializelocalparameterarray*///初始化本地参数数组arguments[0]=v1;arguments[1]=v2;arguments[2]=v3;arguments[3]=v4;/**findthehashbucketinwhichtolookforthetuple*检索hash桶*/hashValue=CatalogCacheComputeHashValue(cache,nkeys,v1,v2,v3,v4);hashIndex=HASH_INDEX(hashValue,cache->cc_nbuckets);/**scanthehashbucketuntilwefindamatchorexhaustourtuples*扫描hash桶**Note:it'sokaytousedlist_foreachhere,eventhoughwemodifythe*dlistwithintheloop,becausewedon'tcontinuetheloopafterwards.*就算在循环过程中更新了dlist也可以用dlist_foreach,因为不再往后循环了*/bucket=&cache->cc_bucket[hashIndex];dlist_foreach(iter,bucket){ct=dlist_container(CatCTup,cache_elem,iter.cur);if(ct->dead)//忽略已废弃的条目continue;/*ignoredeadentries*/if(ct->hash_value!=hashValue)//跳过hash不同的项continue;/*quicklyskipentryifwronghashval*///不同的元组,跳过if(!CatalogCacheCompareTuple(cache,nkeys,ct->keys,arguments))continue;/**Wefoundamatchinthecache.Moveittothefrontofthelist*foritshashbucket,inordertospeedsubsequentsearches.(The*mostfrequentlyaccessedelementsinanyhashbucketwilltendtobe*nearthefrontofthehashbucket'slist.)*命中,放在链表的头部*/dlist_move_head(bucket,&ct->cache_elem);/**Ifit'sapositiveentry,bumpitsrefcountandreturnit.Ifit's*negative,wecanreportfailuretothecaller.*正向项,增加refcount并返回*/if(!ct->negative){ResourceOwnerEnlargeCatCacheRefs(CurrentResourceOwner);ct->refcount++;ResourceOwnerRememberCatCacheRef(CurrentResourceOwner,&ct->tuple);CACHE_elog(DEBUG2,"SearchCatCache(%s):foundinbucket%d",cache->cc_relname,hashIndex);#ifdefCATCACHE_STATScache->cc_hits++;#endifreturn&ct->tuple;}else{CACHE_elog(DEBUG2,"SearchCatCache(%s):foundnegentryinbucket%d",cache->cc_relname,hashIndex);#ifdefCATCACHE_STATScache->cc_neg_hits++;#endifreturnNULL;}}returnSearchCatCacheMiss(cache,nkeys,hashValue,hashIndex,v1,v2,v3,v4);}/**Searchtheactualcatalogs,ratherthanthecache.**ThisiskeptseparatefromSearchCatCacheInternal()tokeepthefast-path*assmallaspossible.Toavoidthateffortbeingundonebyahelpful*compiler,trytoexplicitlyforbidinlining.*/staticpg_noinlineHeapTupleSearchCatCacheMiss(CatCache*cache,intnkeys,uint32hashValue,IndexhashIndex,Datumv1,Datumv2,Datumv3,Datumv4){ScanKeyDatacur_skey[CATCACHE_MAXKEYS];Relationrelation;SysScanDescscandesc;HeapTuplentp;CatCTup*ct;Datumarguments[CATCACHE_MAXKEYS];/*Initializelocalparameterarray*/arguments[0]=v1;arguments[1]=v2;arguments[2]=v3;arguments[3]=v4;/**Ok,needtomakealookupintherelation,copythescankeyandfill*outanyper-callfields.*/memcpy(cur_skey,cache->cc_skey,sizeof(ScanKeyData)*nkeys);cur_skey[0].sk_argument=v1;cur_skey[1].sk_argument=v2;cur_skey[2].sk_argument=v3;cur_skey[3].sk_argument=v4;/**Tuplewasnotfoundincache,sowehavetotrytoretrieveitdirectly*fromtherelation.Iffound,wewilladdittothecache;ifnot*found,wewilladdanegativecacheentryinstead.**NOTE:itispossibleforrecursivecachelookupstooccurwhilereading*therelation---forexample,duetoshared-cache-invalmessagesbeing*processedduringtable_open().ThisisOK.It'sevenpossibleforone*ofthoselookupstofindandentertheverysametuplewearetryingto*fetchhere.Ifthathappens,wewillenterasecondcopyofthetuple*intothecache.Thefirstcopywillneverbereferencedagain,and*willeventuallyageoutofthecache,sothere'snofunctionalproblem.*Thiscaseisrareenoughthatit'snotworthexpendingextracyclesto*detect.*/relation=table_open(cache->cc_reloid,AccessShareLock);scandesc=systable_beginscan(relation,cache->cc_indexoid,IndexScanOK(cache,cur_skey),NULL,nkeys,cur_skey);ct=NULL;while(HeapTupleIsValid(ntp=systable_getnext(scandesc))){ct=CatalogCacheCreateEntry(cache,ntp,arguments,hashValue,hashIndex,false);/*immediatelysettherefcountto1*/ResourceOwnerEnlargeCatCacheRefs(CurrentResourceOwner);ct->refcount++;ResourceOwnerRememberCatCacheRef(CurrentResourceOwner,&ct->tuple);break;/*assumeonlyonematch*/}systable_endscan(scandesc);table_close(relation,AccessShareLock);/**Iftuplewasnotfound,weneedtobuildanegativecacheentry*containingafaketuple.Thefaketuplehasthecorrectkeycolumns,*butnullseverywhereelse.**Inbootstrapmode,wedon'tbuildnegativeentries,becausethecache*invalidationmechanismisn'taliveandcan'tclearthemifthetuple*getscreatedlater.(Bootstrapdoesn'tdoUPDATEs,soitdoesn'tneed*cacheinvalforthat.)*/if(ct==NULL){if(IsBootstrapProcessingMode())returnNULL;ct=CatalogCacheCreateEntry(cache,NULL,arguments,hashValue,hashIndex,true);CACHE_elog(DEBUG2,"SearchCatCache(%s):Contains%d/%dtuples",cache->cc_relname,cache->cc_ntup,CacheHdr->ch_ntup);CACHE_elog(DEBUG2,"SearchCatCache(%s):putnegentryinbucket%d",cache->cc_relname,hashIndex);/**Wearenotreturningthenegativeentrytothecaller,soleaveits*refcountzero.*/returnNULL;}CACHE_elog(DEBUG2,"SearchCatCache(%s):Contains%d/%dtuples",cache->cc_relname,cache->cc_ntup,CacheHdr->ch_ntup);CACHE_elog(DEBUG2,"SearchCatCache(%s):putinbucket%d",cache->cc_relname,hashIndex);#ifdefCATCACHE_STATScache->cc_newloads++;#endifreturn&ct->tuple;}三、跟踪分析
测试脚本
[local:/data/run/pg12]:5120pg12@testdb=#selectoid,proname,pronargs,proargtypes,proallargtypesfrompg_procwhereproname='func_test';oid|proname|pronargs|proargtypes|proallargtypes-------+-----------+----------+--------------+------------------------16387|func_test|3|2310431043|{23,1043,1043,23,1043}(1row)createorreplacefunctionfunc_test(pi_v1inint,pi_v2varchar,pio_v3inoutvarchar,po_v4outint,po_v5outvarchar)returnsrecordas$$declarebeginraisenotice'pi_v1:=%,pi_v2:=%,pi_v3:=%',pi_v1,pi_v2,pio_v3;pio_v3:='pio_v3i/o';po_v4:=100;po_v5:='po_v5out';end;$$LANGUAGEplpgsql;
启动GDB跟踪
(gdb)bpg_proc.c:367Breakpoint1at0x5be038:filepg_proc.c,line367.(gdb)(gdb)cContinuing.Breakpoint1,ProcedureCreate(procedureName=0x15e3ab0"func_test",procNamespace=2200,replace=true,returnsSet=false,returnType=2249,proowner=10,languageObjectId=13581,languageValidator=13580,prosrc=0x15e45c8"\ndeclare\nbegin\nraisenotice'pi_v1:=%,pi_v2:=%,pi_v3:=%',pi_v1,pi_v2,pio_v3;\npio_v3:='pio_v3i/o';\npo_v4:=100;\npo_v5:='po_v5out';\nend;\n",probin=0x0,prokind=102'f',security_definer=false,isLeakProof=false,isStrict=false,volatility=118'v',parallel=117'u',parameterTypes=0x16ce398,allParameterTypes=23913456,parameterModes=23913544,parameterNames=23913600,parameterDefaults=0x0,trftypes=0,proconfig=0,prosupport=0,procost=100,prorows=0)atpg_proc.c:367367tupDesc=RelationGetDescr(rel);(gdb)
进入SearchSysCache3
(gdb)n370oldtup=SearchSysCache3(PROCNAMEARGSNSP,(gdb)stepSearchSysCache3(cacheId=42,key1=22952624,key2=23913368,key3=2200)atsyscache.c:11491149Assert(cacheId>=0&&cacheId<SysCacheSize&&(gdb)
输入参数:cacheId=42, key1=22952624, key2=23913368, key3=2200
其中key1->procedureName,key2->parameterTypes,key3->procNamespace
输入参数类型有3个,分别是23/1043/1043(inout参数)
(gdb)p(char*)22952624$3=0x15e3ab0"func_test"(gdb)p((oidvector*)23913368)[0]$4={vl_len_=144,ndim=1,dataoffset=0,elemtype=26,dim1=3,lbound1=0,values=0x16ce3b0}(gdb)p((oidvector*)23913368)[0]->values$7=0x16ce3b0(gdb)p*((oidvector*)23913368)[0]->values$8=23(gdb)p((oidvector*)23913368)[0]->values[0]$9=23(gdb)p((oidvector*)23913368)[0]->values[1]$10=1043(gdb)p((oidvector*)23913368)[0]->values[2]$11=1043(gdb)
进入SearchCatCache3
(gdb)n1151Assert(SysCache[cacheId]->cc_nkeys==3);(gdb)n1153returnSearchCatCache3(SysCache[cacheId],key1,key2,key3);(gdb)stepSearchCatCache3(cache=0x1639c80,v1=22952624,v2=23913368,v3=2200)atcatcache.c:11831183returnSearchCatCacheInternal(cache,3,v1,v2,v3,0);(gdb)
进入SearchCatCacheInternal
(gdb)stepSearchCatCacheInternal(cache=0x1639c80,nkeys=3,v1=22952624,v2=23913368,v3=2200,v4=0)atcatcache.c:12131213Assert(IsTransactionState());(gdb)
cache信息
(gdb)n1215Assert(cache->cc_nkeys==nkeys);(gdb)p*cache$13={id=42,cc_nbuckets=128,cc_tupdesc=0x7f8159216ef8,cc_bucket=0x163a160,cc_hashfunc={0xa48129<namehashfast>,0xa48257<oidvectorhashfast>,0xa481b0<int4hashfast>,0x0},cc_fastequal={0xa480ea<nameeqfast>,0xa48222<oidvectoreqfast>,0xa48193<int4eqfast>,0x0},cc_keyno={2,20,3,0},cc_lists={head={prev=0x7f81591cad60,next=0x7f81591aab18}},cc_ntup=29,cc_nkeys=3,cc_relname=0x7f8159217f10"pg_proc",cc_reloid=1255,cc_indexoid=2691,cc_relisshared=false,cc_next={next=0x1639698},cc_skey={{sk_flags=0,sk_attno=2,sk_strategy=3,sk_subtype=0,sk_collation=950,sk_func={fn_addr=0x9a1cf3<nameeq>,fn_oid=62,fn_nargs=2,fn_strict=true,fn_retset=false,fn_stats=2'\002',fn_extra=0x0,fn_mcxt=0x16280d0,fn_expr=0x0},sk_argument=0},{sk_flags=0,sk_attno=20,sk_strategy=3,sk_subtype=0,sk_collation=950,sk_func={fn_addr=0x9be7e8<oidvectoreq>,fn_oid=679,fn_nargs=2,fn_strict=true,fn_retset=false,fn_stats=2'\002',fn_extra=0x0,fn_mcxt=0x16280d0,fn_expr=0x0},sk_argument=0},{sk_flags=0,sk_attno=3,sk_strategy=3,sk_subtype=0,sk_collation=950,sk_func={fn_addr=0x9be650<oideq>,fn_oid=184,fn_nargs=2,fn_strict=true,fn_retset=false,fn_stats=2'\002',fn_extra=0x0,fn_mcxt=0x16280d0,fn_expr=0x0},sk_argument=0},{sk_flags=0,sk_attno=0,sk_strategy=0,sk_subtype=0,sk_collation=0,sk_func={fn_addr=0x0,fn_oid=0,fn_nargs=0,---Type<return>tocontinue,orq<return>toquit---fn_strict=false,fn_retset=false,fn_stats=0'\000',fn_extra=0x0,fn_mcxt=0x0,fn_expr=0x0},sk_argument=0}}}(gdb)
pg_proc tuple描述符
(gdb)p*cache->cc_tupdesc$14={natts=29,tdtypeid=81,tdtypmod=-1,tdrefcount=-1,constr=0x7f8159216b90,attrs=0x7f8159216f10}(gdb)p*cache->cc_tupdesc->constr$15={defval=0x0,check=0x0,missing=0x0,num_defval=0,num_check=0,has_not_null=true,has_generated_stored=false}(gdb)p*cache->cc_tupdesc->attrs$16={attrelid=1255,attname={data="oid",'\000'<repeats60times>},atttypid=26,attstattarget=-1,attlen=4,attnum=1,attndims=0,attcacheoff=0,atttypmod=-1,attbyval=true,attstorage=112'p',attalign=105'i',attnotnull=true,atthasdef=false,atthasmissing=false,attidentity=0'\000',attgenerated=0'\000',attisdropped=false,attislocal=true,attinhcount=0,attcollation=0}(gdb)pcache->cc_tupdesc->attrs[1]$17={attrelid=1255,attname={data="proname",'\000'<repeats56times>},atttypid=19,attstattarget=-1,attlen=64,attnum=2,attndims=0,attcacheoff=4,atttypmod=-1,attbyval=false,attstorage=112'p',attalign=99'c',attnotnull=true,atthasdef=false,atthasmissing=false,attidentity=0'\000',attgenerated=0'\000',attisdropped=false,attislocal=true,attinhcount=0,attcollation=950}(gdb)
获取hash桶
(gdb)n1220if(unlikely(cache->cc_tupdesc==NULL))(gdb)1228arguments[0]=v1;(gdb)1229arguments[1]=v2;(gdb)1230arguments[2]=v3;(gdb)1231arguments[3]=v4;(gdb)1236hashValue=CatalogCacheComputeHashValue(cache,nkeys,v1,v2,v3,v4);(gdb)1237hashIndex=HASH_INDEX(hashValue,cache->cc_nbuckets);(gdb)1245bucket=&cache->cc_bucket[hashIndex];(gdb)phashValue$18=3879045281(gdb)phashIndex$19=33(gdb)(gdb)n1246dlist_foreach(iter,bucket)(gdb)p*bucket$20={head={prev=0x7f815919d688,next=0x7f815919d688}}(gdb)
沿着hash桶中的链表查找
(gdb)n1248ct=dlist_container(CatCTup,cache_elem,iter.cur);(gdb)1250if(ct->dead)(gdb)1253if(ct->hash_value!=hashValue)(gdb)1254continue;/*quicklyskipentryifwronghashval*/(gdb)1246dlist_foreach(iter,bucket)(gdb)1299returnSearchCatCacheMiss(cache,nkeys,hashValue,hashIndex,v1,v2,v3,v4);(gdb)stepSearchCatCacheMiss(cache=0x1639c80,nkeys=3,hashValue=3879045281,hashIndex=33,v1=22952624,v2=23913368,v3=2200,v4=0)atcatcache.c:13271327arguments[0]=v1;(gdb)
如没有找到,则调用SearchCatCacheMiss,构建扫描键
(gdb)n1328arguments[1]=v2;(gdb)1329arguments[2]=v3;(gdb)1330arguments[3]=v4;(gdb)1336memcpy(cur_skey,cache->cc_skey,sizeof(ScanKeyData)*nkeys);(gdb)1337cur_skey[0].sk_argument=v1;(gdb)1338cur_skey[1].sk_argument=v2;(gdb)1339cur_skey[2].sk_argument=v3;(gdb)1340cur_skey[3].sk_argument=v4;(gdb)1357relation=table_open(cache->cc_reloid,AccessShareLock);(gdb)p*cur_skey$21={sk_flags=0,sk_attno=2,sk_strategy=3,sk_subtype=0,sk_collation=950,sk_func={fn_addr=0x9a1cf3<nameeq>,fn_oid=62,fn_nargs=2,fn_strict=true,fn_retset=false,fn_stats=2'\002',fn_extra=0x0,fn_mcxt=0x16280d0,fn_expr=0x0},sk_argument=22952624}(gdb)pcur_skey[1]$22={sk_flags=0,sk_attno=20,sk_strategy=3,sk_subtype=0,sk_collation=950,sk_func={fn_addr=0x9be7e8<oidvectoreq>,fn_oid=679,fn_nargs=2,fn_strict=true,fn_retset=false,fn_stats=2'\002',fn_extra=0x0,fn_mcxt=0x16280d0,fn_expr=0x0},sk_argument=23913368}(gdb)pcur_skey[2]$23={sk_flags=0,sk_attno=3,sk_strategy=3,sk_subtype=0,sk_collation=950,sk_func={fn_addr=0x9be650<oideq>,fn_oid=184,fn_nargs=2,fn_strict=true,fn_retset=false,fn_stats=2'\002',fn_extra=0x0,fn_mcxt=0x16280d0,fn_expr=0x0},sk_argument=2200}(gdb)pcur_skey[4]$24={sk_flags=0,sk_attno=0,sk_strategy=0,sk_subtype=0,sk_collation=2691234902,sk_func={fn_addr=0x1639c98,fn_oid=16681376,fn_nargs=-30559,fn_strict=53,fn_retset=231,fn_stats=96'`',fn_extra=0xa4a825<SearchCatCacheInternal+572>,fn_mcxt=0x898,fn_expr=0x0},sk_argument=0}(gdb)
开始扫描
(gdb)n1361IndexScanOK(cache,cur_skey),(gdb)1359scandesc=systable_beginscan(relation,(gdb)1366ct=NULL;(gdb)1368while(HeapTupleIsValid(ntp=systable_getnext(scandesc)))(gdb)1370ct=CatalogCacheCreateEntry(cache,ntp,arguments,(gdb)1374ResourceOwnerEnlargeCatCacheRefs(CurrentResourceOwner);(gdb)1375ct->refcount++;(gdb)1376ResourceOwnerRememberCatCacheRef(CurrentResourceOwner,&ct->tuple);(gdb)1377break;/*assumeonlyonematch*/(gdb)1380systable_endscan(scandesc);(gdb)1382table_close(relation,AccessShareLock);(gdb)1394if(ct==NULL)(gdb)
成功,返回tuple
1425return&ct->tuple;(gdb)(gdb)p*ct$25={ct_magic=1462113538,hash_value=3879045281,keys={140193522567236,140193522567344,2200,0},cache_elem={prev=0x163a370,next=0x7f815919d688},refcount=1,dead=false,negative=false,tuple={t_len=488,t_self={ip_blkid={bi_hi=0,bi_lo=42},ip_posid=20},t_tableOid=1255,t_data=0x7f81591cc820},c_list=0x0,my_cache=0x1639c80}(gdb)pct->tuple$26={t_len=488,t_self={ip_blkid={bi_hi=0,bi_lo=42},ip_posid=20},t_tableOid=1255,t_data=0x7f81591cc820}(gdb)
到此,相信大家对“分析PostgreSQL创建函数的过程”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。