分析PostgreSQL CreateFunction中的ProcedureCreate函数
本篇内容介绍了“分析PostgreSQL CreateFunction中的ProcedureCreate函数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一、数据结构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;二、源码解读
/*----------------------------------------------------------------*ProcedureCreate**Note:allParameterTypes,parameterModes,parameterNames,trftypes,andproconfig*areeitherarraysofthepropertypesorNULL.WedeclarethemDatum,*not"ArrayType*",toavoidimportingarray.hintopg_proc.h.*注意:allParameterTypes,parameterModes,parameterNames,trftypes,andproconfig*要么为相应类型的数组,要么为NULL.这些变量的类型为Datum而不是ArrayType*,*目的是为了避免引入array.h到pg_proc.h中*----------------------------------------------------------------*/ObjectAddressProcedureCreate(constchar*procedureName,OidprocNamespace,boolreplace,boolreturnsSet,OidreturnType,Oidproowner,OidlanguageObjectId,OidlanguageValidator,constchar*prosrc,constchar*probin,charprokind,boolsecurity_definer,boolisLeakProof,boolisStrict,charvolatility,charparallel,oidvector*parameterTypes,DatumallParameterTypes,DatumparameterModes,DatumparameterNames,List*parameterDefaults,Datumtrftypes,Datumproconfig,Oidprosupport,float4procost,float4prorows){Oidretval;//返回值类型intparameterCount;//输入参数intallParamCount;//所有参数,如无输出参数,则为0Oid*allParams;//所有参数类型,如无输出参数,则为NULLchar*paramModes=NULL;//参数类型boolgenericInParam=false;boolgenericOutParam=false;boolanyrangeInParam=false;boolanyrangeOutParam=false;boolinternalInParam=false;boolinternalOutParam=false;OidvariadicType=InvalidOid;Acl*proacl=NULL;//ACL结构体Relationrel;//关系HeapTupletup;//tupleHeapTupleoldtup;//原pg_proctupleboolnulls[Natts_pg_proc];//是否为nullDatumvalues[Natts_pg_proc];//值boolreplaces[Natts_pg_proc];//是否替换NameDataprocname;//名称TupleDesctupDesc;//tuple描述符boolis_update;//是否替换?ObjectAddressmyself,referenced;inti;//临时变量Oidtrfid;/**sanitychecks*/Assert(PointerIsValid(prosrc));//参数个数parameterCount=parameterTypes->dim1;//#defineFUNC_MAX_ARGS100if(parameterCount<0||parameterCount>FUNC_MAX_ARGS)ereport(ERROR,(errcode(ERRCODE_TOO_MANY_ARGUMENTS),errmsg_plural("functionscannothavemorethan%dargument","functionscannothavemorethan%darguments",FUNC_MAX_ARGS,FUNC_MAX_ARGS)));/*note:theaboveiscorrect,wedoNOTcountoutputarguments(不计算输出参数)*//*Deconstructarrayinputs*///重构数组输入:所有参数类型if(allParameterTypes!=PointerGetDatum(NULL)){/**Weexpectthearraytobea1-DOIDarray;verifythat.Wedon't*needtousedeconstruct_array()sincethearraydataisjustgoing*tolooklikeaCarrayofOIDvalues.*我们期望数组是一维OID数组,需要验证这一点.*因为数组中的数据看起来像是C语言中的OID数组,隐藏不需要使用deconstruct_array()函数*/ArrayType*allParamArray=(ArrayType*)DatumGetPointer(allParameterTypes);//获取数组的维数//#defineARR_DIMS(a)\((int*)(((char*)(a))+sizeof(ArrayType)))//#defineARR_NDIM(a)((a)->ndim)//#defineARR_HASNULL(a)((a)->dataoffset!=0)allParamCount=ARR_DIMS(allParamArray)[0];if(ARR_NDIM(allParamArray)!=1||allParamCount<=0||ARR_HASNULL(allParamArray)||ARR_ELEMTYPE(allParamArray)!=OIDOID)elog(ERROR,"allParameterTypesisnota1-DOidarray");//所有参数allParams=(Oid*)ARR_DATA_PTR(allParamArray);Assert(allParamCount>=parameterCount);/*weassumecallergotthecontentsright*/}else{//均为输入参数,无输出参数allParamCount=parameterCount;allParams=parameterTypes->values;}if(parameterModes!=PointerGetDatum(NULL)){//参数模式(输入/输出等)/**Weexpectthearraytobea1-DCHARarray;verifythat.Wedon't*needtousedeconstruct_array()sincethearraydataisjustgoing*tolooklikeaCarrayofcharvalues.*/ArrayType*modesArray=(ArrayType*)DatumGetPointer(parameterModes);if(ARR_NDIM(modesArray)!=1||ARR_DIMS(modesArray)[0]!=allParamCount||ARR_HASNULL(modesArray)||ARR_ELEMTYPE(modesArray)!=CHAROID)elog(ERROR,"parameterModesisnota1-Dchararray");paramModes=(char*)ARR_DATA_PTR(modesArray);}/**DetectwhetherwehavepolymorphicorINTERNALarguments.Thefirst*loopchecksinputarguments,thesecondoutputarguments.*检查是否存在多态或者INTERNAL参数.*两趟循环:第一趟检查输入参数,第二趟检查输出参数*/for(i=0;i<parameterCount;i++){switch(parameterTypes->values[i]){caseANYARRAYOID:caseANYELEMENTOID:caseANYNONARRAYOID:caseANYENUMOID:genericInParam=true;break;caseANYRANGEOID:genericInParam=true;anyrangeInParam=true;break;caseINTERNALOID:internalInParam=true;break;}}if(allParameterTypes!=PointerGetDatum(NULL)){for(i=0;i<allParamCount;i++){if(paramModes==NULL||paramModes[i]==PROARGMODE_IN||paramModes[i]==PROARGMODE_VARIADIC)continue;/*ignoreinput-onlyparams*/switch(allParams[i]){caseANYARRAYOID:caseANYELEMENTOID:caseANYNONARRAYOID:caseANYENUMOID:genericOutParam=true;break;caseANYRANGEOID:genericOutParam=true;anyrangeOutParam=true;break;caseINTERNALOID:internalOutParam=true;break;}}}/**Donotallowpolymorphicreturntypeunlessatleastoneinputargument*ispolymorphic.ANYRANGEreturntypeisevenstricter:musthavean*ANYRANGEinput(sincewecan'tdeducethespecificrangetypefrom*ANYELEMENT).Also,donotallowreturntypeINTERNALunlessatleast*oneinputargumentisINTERNAL.*至少存在一个多态输入参数的情况下才允许返回多态类型.*ANYRANGE返回类型更为严格:必须含有一个ANYRANGE输入(因为无法从ANYELEMENT中规约特殊的范围类型.)*同时,除非至少有一个INTERNAL输入参数类型,否则不允许返回INTERNAL类型.*/if((IsPolymorphicType(returnType)||genericOutParam)&&!genericInParam)ereport(ERROR,(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),errmsg("cannotdetermineresultdatatype"),errdetail("Afunctionreturningapolymorphictypemusthaveatleastonepolymorphicargument.")));if((returnType==ANYRANGEOID||anyrangeOutParam)&&!anyrangeInParam)ereport(ERROR,(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),errmsg("cannotdetermineresultdatatype"),errdetail("Afunctionreturning\"anyrange\"musthaveatleastone\"anyrange\"argument.")));if((returnType==INTERNALOID||internalOutParam)&&!internalInParam)ereport(ERROR,(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),errmsg("unsafeuseofpseudo-type\"internal\""),errdetail("Afunctionreturning\"internal\"musthaveatleastone\"internal\"argument.")));if(paramModes!=NULL){/**Onlythelastinputparametercanbevariadic;ifitis,saveits*elementtype.Errorsherearejustelogsincecallershouldhave*checkedthisalready.*只有最后一个输入参数可以是variadic.如是,则存储元素类型.*/for(i=0;i<allParamCount;i++){switch(paramModes[i]){casePROARGMODE_IN:casePROARGMODE_INOUT:if(OidIsValid(variadicType))elog(ERROR,"variadicparametermustbelast");break;casePROARGMODE_OUT:casePROARGMODE_TABLE:/*okay*/break;casePROARGMODE_VARIADIC:if(OidIsValid(variadicType))elog(ERROR,"variadicparametermustbelast");switch(allParams[i]){caseANYOID:variadicType=ANYOID;break;caseANYARRAYOID:variadicType=ANYELEMENTOID;break;default:variadicType=get_element_type(allParams[i]);if(!OidIsValid(variadicType))elog(ERROR,"variadicparameterisnotanarray");break;}break;default:elog(ERROR,"invalidparametermode'%c'",paramModes[i]);break;}}}/**AllseemsOK;preparethedatatobeinsertedintopg_proc.*检查完毕,写入到pg_proc中*///#defineNatts_pg_proc29for(i=0;i<Natts_pg_proc;++i){nulls[i]=false;values[i]=(Datum)0;replaces[i]=true;}//#defineAnum_pg_proc_oid1//#defineAnum_pg_proc_proname2//...//#defineAnum_pg_proc_proacl29namestrcpy(&procname,procedureName);values[Anum_pg_proc_proname-1]=NameGetDatum(&procname);values[Anum_pg_proc_pronamespace-1]=ObjectIdGetDatum(procNamespace);values[Anum_pg_proc_proowner-1]=ObjectIdGetDatum(proowner);values[Anum_pg_proc_prolang-1]=ObjectIdGetDatum(languageObjectId);values[Anum_pg_proc_procost-1]=Float4GetDatum(procost);values[Anum_pg_proc_prorows-1]=Float4GetDatum(prorows);values[Anum_pg_proc_provariadic-1]=ObjectIdGetDatum(variadicType);values[Anum_pg_proc_prosupport-1]=ObjectIdGetDatum(prosupport);values[Anum_pg_proc_prokind-1]=CharGetDatum(prokind);values[Anum_pg_proc_prosecdef-1]=BoolGetDatum(security_definer);values[Anum_pg_proc_proleakproof-1]=BoolGetDatum(isLeakProof);values[Anum_pg_proc_proisstrict-1]=BoolGetDatum(isStrict);values[Anum_pg_proc_proretset-1]=BoolGetDatum(returnsSet);values[Anum_pg_proc_provolatile-1]=CharGetDatum(volatility);values[Anum_pg_proc_proparallel-1]=CharGetDatum(parallel);values[Anum_pg_proc_pronargs-1]=UInt16GetDatum(parameterCount);values[Anum_pg_proc_pronargdefaults-1]=UInt16GetDatum(list_length(parameterDefaults));values[Anum_pg_proc_prorettype-1]=ObjectIdGetDatum(returnType);values[Anum_pg_proc_proargtypes-1]=PointerGetDatum(parameterTypes);if(allParameterTypes!=PointerGetDatum(NULL))values[Anum_pg_proc_proallargtypes-1]=allParameterTypes;elsenulls[Anum_pg_proc_proallargtypes-1]=true;if(parameterModes!=PointerGetDatum(NULL))values[Anum_pg_proc_proargmodes-1]=parameterModes;elsenulls[Anum_pg_proc_proargmodes-1]=true;if(parameterNames!=PointerGetDatum(NULL))values[Anum_pg_proc_proargnames-1]=parameterNames;elsenulls[Anum_pg_proc_proargnames-1]=true;if(parameterDefaults!=NIL)values[Anum_pg_proc_proargdefaults-1]=CStringGetTextDatum(nodeToString(parameterDefaults));elsenulls[Anum_pg_proc_proargdefaults-1]=true;if(trftypes!=PointerGetDatum(NULL))values[Anum_pg_proc_protrftypes-1]=trftypes;elsenulls[Anum_pg_proc_protrftypes-1]=true;values[Anum_pg_proc_prosrc-1]=CStringGetTextDatum(prosrc);if(probin)values[Anum_pg_proc_probin-1]=CStringGetTextDatum(probin);elsenulls[Anum_pg_proc_probin-1]=true;if(proconfig!=PointerGetDatum(NULL))values[Anum_pg_proc_proconfig-1]=proconfig;elsenulls[Anum_pg_proc_proconfig-1]=true;/*proaclwillbedeterminedlater*/rel=table_open(ProcedureRelationId,RowExclusiveLock);tupDesc=RelationGetDescr(rel);/*Checkforpre-existingdefinition*///检查是否已存在oldtup=SearchSysCache3(PROCNAMEARGSNSP,PointerGetDatum(procedureName),PointerGetDatum(parameterTypes),ObjectIdGetDatum(procNamespace));if(HeapTupleIsValid(oldtup)){//--------已存在/*Thereisone;okaytoreplaceit?*///获取原记录(pg_proc记录)Form_pg_procoldproc=(Form_pg_proc)GETSTRUCT(oldtup);Datumproargnames;boolisnull;constchar*dropcmd;if(!replace)ereport(ERROR,(errcode(ERRCODE_DUPLICATE_FUNCTION),errmsg("function\"%s\"alreadyexistswithsameargumenttypes",procedureName)));if(!pg_proc_ownercheck(oldproc->oid,proowner))aclcheck_error(ACLCHECK_NOT_OWNER,OBJECT_FUNCTION,procedureName);/*Notokaytochangeroutinekind*///不能改变类型(如原来是proc,那么创建同名func是不行的)if(oldproc->prokind!=prokind)ereport(ERROR,(errcode(ERRCODE_WRONG_OBJECT_TYPE),errmsg("cannotchangeroutinekind"),(oldproc->prokind==PROKIND_AGGREGATE?errdetail("\"%s\"isanaggregatefunction.",procedureName):oldproc->prokind==PROKIND_FUNCTION?errdetail("\"%s\"isafunction.",procedureName):oldproc->prokind==PROKIND_PROCEDURE?errdetail("\"%s\"isaprocedure.",procedureName):oldproc->prokind==PROKIND_WINDOW?errdetail("\"%s\"isawindowfunction.",procedureName):0)));dropcmd=(prokind==PROKIND_PROCEDURE?"DROPPROCEDURE":prokind==PROKIND_AGGREGATE?"DROPAGGREGATE":"DROPFUNCTION");/**Notokaytochangethereturntypeoftheexistingproc,since*existingrules,views,etcmaydependonthereturntype.*改变返回类型也是不行的,因为现存的规则\视图等等可能依赖返回类型.**Incaseofaprocedure,achangingreturntypemeansthatwhether*theprocedurehasoutputparameterswaschanged.Sincethereisno*uservisiblereturntype,weproduceamorespecificerrormessage.*如为存储过程,改变返回类型意味着过程已有的输出参数已改变.*由于存在非用户可见返回类型,隐藏产生更为详尽的错误信息.*/if(returnType!=oldproc->prorettype||returnsSet!=oldproc->proretset)ereport(ERROR,(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),prokind==PROKIND_PROCEDURE?errmsg("cannotchangewhetheraprocedurehasoutputparameters"):errmsg("cannotchangereturntypeofexistingfunction"),/**translator:first%sisDROPFUNCTION,DROPPROCEDURE,orDROP*AGGREGATE*/errhint("Use%s%sfirst.",dropcmd,format_procedure(oldproc->oid))));/**IfitreturnsRECORD,checkforpossiblechangeofrecordtype*impliedbyOUTparameters*如果返回RECORD类型,检查使用OUT参数指明的可能的record类型变化.*/if(returnType==RECORDOID){//返回RECORD类型TupleDescolddesc;TupleDescnewdesc;olddesc=build_function_result_tupdesc_t(oldtup);newdesc=build_function_result_tupdesc_d(prokind,allParameterTypes,parameterModes,parameterNames);if(olddesc==NULL&&newdesc==NULL)/*ok,bothareruntime-definedRECORDs*/;elseif(olddesc==NULL||newdesc==NULL||!equalTupleDescs(olddesc,newdesc))ereport(ERROR,(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),errmsg("cannotchangereturntypeofexistingfunction"),errdetail("RowtypedefinedbyOUTparametersisdifferent."),/*translator:first%sisDROPFUNCTIONorDROPPROCEDURE*/errhint("Use%s%sfirst.",dropcmd,format_procedure(oldproc->oid))));}/**Iftherewereanynamedinputparameters,checktomakesurethe*nameshavenotbeenchanged,asthiscouldbreakexistingcalls.We*allowaddingnamestoformerlyunnamedparameters,though.*如存在已命名的输入参数,确保名称没有变更,否则会破坏现存的调用.*但允许添加名称到未命名的参数中.*/proargnames=SysCacheGetAttr(PROCNAMEARGSNSP,oldtup,Anum_pg_proc_proargnames,&isnull);if(!isnull){Datumproargmodes;char**old_arg_names;char**new_arg_names;intn_old_arg_names;intn_new_arg_names;intj;proargmodes=SysCacheGetAttr(PROCNAMEARGSNSP,oldtup,Anum_pg_proc_proargmodes,&isnull);if(isnull)proargmodes=PointerGetDatum(NULL);/*justtobesure*/n_old_arg_names=get_func_input_arg_names(proargnames,proargmodes,&old_arg_names);n_new_arg_names=get_func_input_arg_names(parameterNames,parameterModes,&new_arg_names);for(j=0;j<n_old_arg_names;j++){if(old_arg_names[j]==NULL)continue;if(j>=n_new_arg_names||new_arg_names[j]==NULL||strcmp(old_arg_names[j],new_arg_names[j])!=0)ereport(ERROR,(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),errmsg("cannotchangenameofinputparameter\"%s\"",old_arg_names[j]),/*translator:first%sisDROPFUNCTIONorDROPPROCEDURE*/errhint("Use%s%sfirst.",dropcmd,format_procedure(oldproc->oid))));}}/**Ifthereareexistingdefaults,checkcompatibility:redefinition*mustnotremoveanydefaultsnorchangetheirtypes.(Removinga*defaultmightcauseafunctiontofailtosatisfyanexistingcall.*Changingtypewouldonlybepossibleiftheassociatedparameteris*polymorphic,andinsuchcasesachangeofdefaulttypemightalter*theresolvedoutputtypeofexistingcalls.)*存在defaults(默认参数),检查兼容性:*重新定义不应删去已有的默认定义或者改变类型,否则会破坏现存的调用.*/if(oldproc->pronargdefaults!=0){//默认值判断Datumproargdefaults;List*oldDefaults;ListCell*oldlc;ListCell*newlc;if(list_length(parameterDefaults)<oldproc->pronargdefaults)ereport(ERROR,(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),errmsg("cannotremoveparameterdefaultsfromexistingfunction"),/*translator:first%sisDROPFUNCTIONorDROPPROCEDURE*/errhint("Use%s%sfirst.",dropcmd,format_procedure(oldproc->oid))));proargdefaults=SysCacheGetAttr(PROCNAMEARGSNSP,oldtup,Anum_pg_proc_proargdefaults,&isnull);Assert(!isnull);oldDefaults=castNode(List,stringToNode(TextDatumGetCString(proargdefaults)));Assert(list_length(oldDefaults)==oldproc->pronargdefaults);/*newlistcanhavemoredefaultsthanold,advanceover'em*/newlc=list_head(parameterDefaults);for(i=list_length(parameterDefaults)-oldproc->pronargdefaults;i>0;i--)newlc=lnext(newlc);foreach(oldlc,oldDefaults){Node*oldDef=(Node*)lfirst(oldlc);Node*newDef=(Node*)lfirst(newlc);if(exprType(oldDef)!=exprType(newDef))ereport(ERROR,(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),errmsg("cannotchangedatatypeofexistingparameterdefaultvalue"),/*translator:first%sisDROPFUNCTIONorDROPPROCEDURE*/errhint("Use%s%sfirst.",dropcmd,format_procedure(oldproc->oid))));newlc=lnext(newlc);}}/**Donotchangeexistingoid,ownershiporpermissions,either.Note*dependency-updatecodebelowhastoagreewiththisdecision.*不改变现有的oid,宿主或者权限等.*注意下面的依赖更新代码必须遵循这一约定.*/replaces[Anum_pg_proc_oid-1]=false;replaces[Anum_pg_proc_proowner-1]=false;replaces[Anum_pg_proc_proacl-1]=false;/*Okay,doit...*/tup=heap_modify_tuple(oldtup,tupDesc,values,nulls,replaces);CatalogTupleUpdate(rel,&tup->t_self,tup);ReleaseSysCache(oldtup);is_update=true;}else{//--------------不存在/*Creatinganewprocedure*///创建新的过程OidnewOid;/*First,getdefaultpermissionsandsetupproacl*///首先:获取默认的权限并设置proaclproacl=get_user_default_acl(OBJECT_FUNCTION,proowner,procNamespace);if(proacl!=NULL)values[Anum_pg_proc_proacl-1]=PointerGetDatum(proacl);elsenulls[Anum_pg_proc_proacl-1]=true;//获取新的OIDnewOid=GetNewOidWithIndex(rel,ProcedureOidIndexId,Anum_pg_proc_oid);//设置pg_proc中的OIDvalues[Anum_pg_proc_oid-1]=ObjectIdGetDatum(newOid);//构造tupletup=heap_form_tuple(tupDesc,values,nulls);//执行插入操作CatalogTupleInsert(rel,tup);is_update=false;}//获取pg_proc结构体retval=((Form_pg_proc)GETSTRUCT(tup))->oid;/**Createdependenciesforthenewfunction.Ifweareupdatingan*existingfunction,firstdeleteanyexistingpg_dependentries.*(However,sincewearenotchangingownershiporpermissions,the*shareddependenciesdo*not*needtochange,andweleavethemalone.)*创建新函数的依赖.*如正在更新现存的函数,首先删除现存的pg_depend条目.*/if(is_update)//删除依赖deleteDependencyRecordsFor(ProcedureRelationId,retval,true);myself.classId=ProcedureRelationId;myself.objectId=retval;myself.objectSubId=0;/*dependencyonnamespace*///依赖:namespacereferenced.classId=NamespaceRelationId;referenced.objectId=procNamespace;referenced.objectSubId=0;recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);/*dependencyonimplementationlanguage*///依赖:语言referenced.classId=LanguageRelationId;referenced.objectId=languageObjectId;referenced.objectSubId=0;recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);/*dependencyonreturntype*///依赖:返回类型referenced.classId=TypeRelationId;referenced.objectId=returnType;referenced.objectSubId=0;recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);/*dependencyontransformusedbyreturntype,ifany*///依赖:返回类型的转换规则if((trfid=get_transform_oid(returnType,languageObjectId,true))){referenced.classId=TransformRelationId;referenced.objectId=trfid;referenced.objectSubId=0;recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);}/*dependencyonparametertypes*///依赖:参数类型for(i=0;i<allParamCount;i++){referenced.classId=TypeRelationId;referenced.objectId=allParams[i];referenced.objectSubId=0;recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);/*dependencyontransformusedbyparametertype,ifany*/if((trfid=get_transform_oid(allParams[i],languageObjectId,true))){referenced.classId=TransformRelationId;referenced.objectId=trfid;referenced.objectSubId=0;recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);}}/*dependencyonparameterdefaultexpressions*///依赖:默认表达式if(parameterDefaults)recordDependencyOnExpr(&myself,(Node*)parameterDefaults,NIL,DEPENDENCY_NORMAL);/*dependencyonsupportfunction,ifany*///依赖:支持的函数if(OidIsValid(prosupport)){referenced.classId=ProcedureRelationId;referenced.objectId=prosupport;referenced.objectSubId=0;recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);}/*dependencyonowner*///依赖:ownerif(!is_update)recordDependencyOnOwner(ProcedureRelationId,retval,proowner);/*dependencyonanyrolesmentionedinACL*///依赖:ACL中标明的角色if(!is_update)recordDependencyOnNewAcl(ProcedureRelationId,retval,0,proowner,proacl);/*dependencyonextension*///依赖:扩展recordDependencyOnCurrentExtension(&myself,is_update);heap_freetuple(tup);/*Postcreationhookfornewfunction*///调用对象创建后的钩子函数InvokeObjectPostCreateHook(ProcedureRelationId,retval,0);//关闭pg_proctable_close(rel,RowExclusiveLock);/*Verifyfunctionbody*///验证函数bodyif(OidIsValid(languageValidator)){ArrayType*set_items=NULL;intsave_nestlevel=0;/*Advancecommandcountersonewtuplecanbeseenbyvalidator*///增加命令计数CommandCounterIncrement();/**Setper-functionconfigurationparameterssothatthevalidationis*donewiththeenvironmentthefunctionexpects.However,if*check_function_bodiesisoff,wedon'tdothis,becausethatwould*createdumporderinghazardsthatpg_dumpdoesn'tknowhowtodeal*with.(Forexample,aSETclausemightrefertoanot-yet-created*textsearchconfiguration.)Thismeansthatthevalidator*shouldn'tcomplainaboutanythingthatmightdependonaGUC*parameterwhencheck_function_bodiesisoff.*/if(check_function_bodies){//检查函数体//获取函数设定的参数set_items=(ArrayType*)DatumGetPointer(proconfig);if(set_items)/*NeedanewGUCnestinglevel*/{save_nestlevel=NewGUCNestLevel();ProcessGUCArray(set_items,(superuser()?PGC_SUSET:PGC_USERSET),PGC_S_SESSION,GUC_ACTION_SAVE);}}//调用语言校验器OidFunctionCall1(languageValidator,ObjectIdGetDatum(retval));if(set_items)AtEOXact_GUC(true,save_nestlevel);}returnmyself;}三、跟踪分析
测试脚本
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)bProcedureCreateBreakpoint1at0x5bd665:filepg_proc.c,line99.(gdb)cContinuing.Breakpoint1,ProcedureCreate(procedureName=0x1173ab0"func_test",procNamespace=2200,replace=true,returnsSet=false,returnType=2249,proowner=10,languageObjectId=13581,languageValidator=13580,prosrc=0x11745c8"\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=0x119a3d0,allParameterTypes=18458616,parameterModes=18457432,parameterNames=18456792,parameterDefaults=0x0,trftypes=0,proconfig=0,prosupport=0,procost=100,prorows=0)atpg_proc.c:9999char*paramModes=NULL;(gdb)
输入参数
[local:/data/run/pg12]:5120pg12@testdb=#\dpg_typeTable"pg_catalog.pg_type"Column|Type|Collation|Nullable|Default----------------+--------------+-----------+----------+---------oid|oid||notnull|typname|name||notnull|typnamespace|oid||notnull|typowner|oid||notnull|typlen|smallint||notnull|typbyval|boolean||notnull|typtype|"char"||notnull|typcategory|"char"||notnull|typispreferred|boolean||notnull|typisdefined|boolean||notnull|typdelim|"char"||notnull|typrelid|oid||notnull|typelem|oid||notnull|typarray|oid||notnull|typinput|regproc||notnull|typoutput|regproc||notnull|typreceive|regproc||notnull|[local:/data/run/pg12]:5120pg12@testdb=#selectoid,typnamefrompg_typewhereoid=2249;oid|typname------+---------2249|record(1row)[local:/data/run/pg12]:5120pg12@testdb=#\dpg_namespaceTable"pg_catalog.pg_namespace"Column|Type|Collation|Nullable|Default----------+-----------+-----------+----------+---------oid|oid||notnull|nspname|name||notnull|nspowner|oid||notnull|nspacl|aclitem[]|||Indexes:"pg_namespace_nspname_index"UNIQUE,btree(nspname)"pg_namespace_oid_index"UNIQUE,btree(oid)[local:/data/run/pg12]:5120pg12@testdb=#selectoid,nspnamefrompg_namespacewhereoid=2200;oid|nspname------+---------2200|public(1row)[local:/data/run/pg12]:5120pg12@testdb=#\dpg_userView"pg_catalog.pg_user"Column|Type|Collation|Nullable|Default--------------+--------------------------+-----------+----------+---------usename|name|||usesysid|oid|||usecreatedb|boolean|||usesuper|boolean|||userepl|boolean|||usebypassrls|boolean|||passwd|text|||valuntil|timestampwithtimezone|||useconfig|text[]|C||[local:/data/run/pg12]:5120pg12@testdb=#selectusename,usesysidfrompg_userwhereusesysid=10;usename|usesysid---------+----------pg12|10(1row)[local:/data/run/pg12]:5120pg12@testdb=#\dpg_languageTable"pg_catalog.pg_language"Column|Type|Collation|Nullable|Default---------------+-----------+-----------+----------+---------oid|oid||notnull|lanname|name||notnull|lanowner|oid||notnull|lanispl|boolean||notnull|lanpltrusted|boolean||notnull|lanplcallfoid|oid||notnull|laninline|oid||notnull|lanvalidator|oid||notnull|lanacl|aclitem[]|||Indexes:"pg_language_name_index"UNIQUE,btree(lanname)"pg_language_oid_index"UNIQUE,btree(oid)[local:/data/run/pg12]:5120pg12@testdb=#selectoid,lanname,lanownerfrompg_languagewhereoid=13581;oid|lanname|lanowner-------+---------+----------13581|plpgsql|10(1row)
初始化本地临时变量
99char*paramModes=NULL;(gdb)n100boolgenericInParam=false;(gdb)101boolgenericOutParam=false;(gdb)102boolanyrangeInParam=false;(gdb)103boolanyrangeOutParam=false;(gdb)104boolinternalInParam=false;(gdb)105boolinternalOutParam=false;(gdb)106OidvariadicType=InvalidOid;(gdb)107Acl*proacl=NULL;(gdb)125Assert(PointerIsValid(prosrc));(gdb)127parameterCount=parameterTypes->dim1;(gdb)
获取参数个数(3个输入参数,类型为26-oid,数据类型为int4,varchar,varchar)
(gdb)n128if(parameterCount<0||parameterCount>FUNC_MAX_ARGS)(gdb)pparameterCount$1=3(gdb)p*parameterTypes$2={vl_len_=144,ndim=1,dataoffset=0,elemtype=26,dim1=3,lbound1=0,values=0x119a3e8}(gdb)(gdb)p*parameterTypes->values$3=23(gdb)pparameterTypes->values[1]$4=1043(gdb)pparameterTypes->values[2]$5=1043(gdb)###[local:/data/run/pg12]:5120pg12@testdb=#selectoid,typnamefrompg_typewhereoid=26;oid|typname-----+---------26|oid(1row)[local:/data/run/pg12]:5120pg12@testdb=#selectoid,typnamefrompg_typewhereoidin(23,1043);oid|typname------+---------23|int41043|varchar(2rows)
重构数组输入:所有参数类型
(gdb)n138if(allParameterTypes!=PointerGetDatum(NULL))(gdb)145ArrayType*allParamArray=(ArrayType*)DatumGetPointer(allParameterTypes);(gdb)147allParamCount=ARR_DIMS(allParamArray)[0];(gdb)148if(ARR_NDIM(allParamArray)!=1||(gdb)150ARR_HASNULL(allParamArray)||(gdb)149allParamCount<=0||(gdb)151ARR_ELEMTYPE(allParamArray)!=OIDOID)(gdb)150ARR_HASNULL(allParamArray)||(gdb)153allParams=(Oid*)ARR_DATA_PTR(allParamArray);(gdb)154Assert(allParamCount>=parameterCount);(gdb)p*allParamArray$6={vl_len_=176,ndim=1,dataoffset=0,elemtype=26}(gdb)pallParamArray[1]$7={vl_len_=5,ndim=1,dataoffset=23,elemtype=1043}(gdb)pallParamCount$8=5(gdb)p*ARR_DIMS(allParamArray)$9=5(gdb)pallParamArray[2]$10={vl_len_=1043,ndim=23,dataoffset=1043,elemtype=2139062142}(gdb)pallParamArray[3]$11={vl_len_=2139062143,ndim=2139062143,dataoffset=2139062143,elemtype=2139062143}(gdb)n163if(parameterModes!=PointerGetDatum(NULL))(gdb)
处理参数模式:参数模式(输入/输出等),分别是i,i,b,o,o
(gdb)n170ArrayType*modesArray=(ArrayType*)DatumGetPointer(parameterModes);(gdb)172if(ARR_NDIM(modesArray)!=1||(gdb)173ARR_DIMS(modesArray)[0]!=allParamCount||(gdb)172if(ARR_NDIM(modesArray)!=1||(gdb)174ARR_HASNULL(modesArray)||(gdb)173ARR_DIMS(modesArray)[0]!=allParamCount||(gdb)175ARR_ELEMTYPE(modesArray)!=CHAROID)(gdb)174ARR_HASNULL(modesArray)||(gdb)177paramModes=(char*)ARR_DATA_PTR(modesArray);(gdb)184for(i=0;i<parameterCount;i++)(gdb)pparamModes[0]$12=105'i'(gdb)pparamModes[1]$13=105'i'(gdb)pparamModes[2]$14=98'b'(gdb)pparamModes[3]$15=111'o'(gdb)pparamModes[4]$16=111'o'(gdb)
检查是否存在多态或者INTERNAL参数.
两趟循环:第一趟检查输入参数,第二趟检查输出参数
(gdb)n186switch(parameterTypes->values[i])(gdb)184for(i=0;i<parameterCount;i++)(gdb)186switch(parameterTypes->values[i])(gdb)184for(i=0;i<parameterCount;i++)(gdb)186switch(parameterTypes->values[i])(gdb)184for(i=0;i<parameterCount;i++)(gdb)204if(allParameterTypes!=PointerGetDatum(NULL))(gdb)206for(i=0;i<allParamCount;i++)(gdb)208if(paramModes==NULL||(gdb)209paramModes[i]==PROARGMODE_IN||(gdb)208if(paramModes==NULL||(gdb)211continue;/*ignoreinput-onlyparams*/(gdb)206for(i=0;i<allParamCount;i++)(gdb)208if(paramModes==NULL||(gdb)209paramModes[i]==PROARGMODE_IN||(gdb)208if(paramModes==NULL||(gdb)211continue;/*ignoreinput-onlyparams*/(gdb)206for(i=0;i<allParamCount;i++)(gdb)208if(paramModes==NULL||(gdb)209paramModes[i]==PROARGMODE_IN||(gdb)208if(paramModes==NULL||(gdb)210paramModes[i]==PROARGMODE_VARIADIC)(gdb)209paramModes[i]==PROARGMODE_IN||(gdb)213switch(allParams[i])(gdb)206for(i=0;i<allParamCount;i++)(gdb)208if(paramModes==NULL||(gdb)209paramModes[i]==PROARGMODE_IN||(gdb)208if(paramModes==NULL||(gdb)210paramModes[i]==PROARGMODE_VARIADIC)(gdb)209paramModes[i]==PROARGMODE_IN||(gdb)213switch(allParams[i])(gdb)206for(i=0;i<allParamCount;i++)(gdb)208if(paramModes==NULL||(gdb)pallParamCount$17=5(gdb)n209paramModes[i]==PROARGMODE_IN||(gdb)208if(paramModes==NULL||(gdb)210paramModes[i]==PROARGMODE_VARIADIC)(gdb)209paramModes[i]==PROARGMODE_IN||(gdb)213switch(allParams[i])(gdb)206for(i=0;i<allParamCount;i++)(gdb)239if((IsPolymorphicType(returnType)||genericOutParam)(gdb)
至少存在一个多态输入参数的情况下才允许返回多态类型.
ANYRANGE返回类型更为严格:必须含有一个ANYRANGE输入(因为无法从ANYELEMENT中规约特殊的范围类型.)
同时,除非至少有一个INTERNAL输入参数类型,否则不允许返回INTERNAL类型.
(gdb)n246if((returnType==ANYRANGEOID||anyrangeOutParam)&&(gdb)253if((returnType==INTERNALOID||internalOutParam)&&!internalInParam)(gdb)259if(paramModes!=NULL)(gdb)
只有最后一个输入参数可以是variadic.如是,则存储元素类型.
266for(i=0;i<allParamCount;i++)(gdb)n268switch(paramModes[i])(gdb)272if(OidIsValid(variadicType))(gdb)274break;(gdb)266for(i=0;i<allParamCount;i++)(gdb)268switch(paramModes[i])(gdb)272if(OidIsValid(variadicType))(gdb)274break;(gdb)266for(i=0;i<allParamCount;i++)(gdb)268switch(paramModes[i])(gdb)272if(OidIsValid(variadicType))(gdb)274break;(gdb)266for(i=0;i<allParamCount;i++)(gdb)268switch(paramModes[i])(gdb)278break;(gdb)266for(i=0;i<allParamCount;i++)(gdb)268switch(paramModes[i])(gdb)278break;(gdb)266for(i=0;i<allParamCount;i++)(gdb)308for(i=0;i<Natts_pg_proc;++i)(gdb)
检查完毕,写入到pg_proc中,初始化values
308for(i=0;i<Natts_pg_proc;++i)(gdb)310nulls[i]=false;(gdb)311values[i]=(Datum)0;(gdb)312replaces[i]=true;(gdb)...
赋值
308for(i=0;i<Natts_pg_proc;++i)(gdb)315namestrcpy(&procname,procedureName);(gdb)316values[Anum_pg_proc_proname-1]=NameGetDatum(&procname);(gdb)pprocedureName$20=0x1173ab0"func_test"(gdb)n317values[Anum_pg_proc_pronamespace-1]=ObjectIdGetDatum(procNamespace);(gdb)318values[Anum_pg_proc_proowner-1]=ObjectIdGetDatum(proowner);(gdb)319values[Anum_pg_proc_prolang-1]=ObjectIdGetDatum(languageObjectId);(gdb)320values[Anum_pg_proc_procost-1]=Float4GetDatum(procost);(gdb)321values[Anum_pg_proc_prorows-1]=Float4GetDatum(prorows);(gdb)322values[Anum_pg_proc_provariadic-1]=ObjectIdGetDatum(variadicType);(gdb)323values[Anum_pg_proc_prosupport-1]=ObjectIdGetDatum(prosupport);(gdb)324values[Anum_pg_proc_prokind-1]=CharGetDatum(prokind);(gdb)325values[Anum_pg_proc_prosecdef-1]=BoolGetDatum(security_definer);(gdb)326values[Anum_pg_proc_proleakproof-1]=BoolGetDatum(isLeakProof);(gdb)327values[Anum_pg_proc_proisstrict-1]=BoolGetDatum(isStrict);(gdb)328values[Anum_pg_proc_proretset-1]=BoolGetDatum(returnsSet);(gdb)329values[Anum_pg_proc_provolatile-1]=CharGetDatum(volatility);(gdb)330values[Anum_pg_proc_proparallel-1]=CharGetDatum(parallel);(gdb)331values[Anum_pg_proc_pronargs-1]=UInt16GetDatum(parameterCount);(gdb)332values[Anum_pg_proc_pronargdefaults-1]=UInt16GetDatum(list_length(parameterDefaults));(gdb)333values[Anum_pg_proc_prorettype-1]=ObjectIdGetDatum(returnType);(gdb)334values[Anum_pg_proc_proargtypes-1]=PointerGetDatum(parameterTypes);(gdb)335if(allParameterTypes!=PointerGetDatum(NULL))(gdb)336values[Anum_pg_proc_proallargtypes-1]=allParameterTypes;(gdb)339if(parameterModes!=PointerGetDatum(NULL))(gdb)340values[Anum_pg_proc_proargmodes-1]=parameterModes;(gdb)343if(parameterNames!=PointerGetDatum(NULL))(gdb)344values[Anum_pg_proc_proargnames-1]=parameterNames;(gdb)347if(parameterDefaults!=NIL)(gdb)350nulls[Anum_pg_proc_proargdefaults-1]=true;(gdb)351if(trftypes!=PointerGetDatum(NULL))(gdb)354nulls[Anum_pg_proc_protrftypes-1]=true;(gdb)355values[Anum_pg_proc_prosrc-1]=CStringGetTextDatum(prosrc);(gdb)356if(probin)(gdb)359nulls[Anum_pg_proc_probin-1]=true;(gdb)360if(proconfig!=PointerGetDatum(NULL))(gdb)363nulls[Anum_pg_proc_proconfig-1]=true;(gdb)366rel=table_open(ProcedureRelationId,RowExclusiveLock);(gdb)367tupDesc=RelationGetDescr(rel);(gdb)
判断是否已存在
(gdb)pvalues[28]$21=0(gdb)pvalues[0]$22=0(gdb)pvalues[2]$23=2200(gdb)n370oldtup=SearchSysCache3(PROCNAMEARGSNSP,(gdb)p*tupDesc$24={natts=29,tdtypeid=81,tdtypmod=-1,tdrefcount=1,constr=0x7fbeb44493b8,attrs=0x7fbeb44483b8}(gdb)n375if(HeapTupleIsValid(oldtup))(gdb)378Form_pg_procoldproc=(Form_pg_proc)GETSTRUCT(oldtup);(gdb)383if(!replace)(gdb)poldproc$25=(Form_pg_proc)0x7fbeb4388bf8(gdb)p*oldproc$26={oid=16387,proname={data="func_test",'\000'<repeats54times>},pronamespace=2200,proowner=10,prolang=13581,procost=100,prorows=0,provariadic=0,prosupport=0,prokind=102'f',prosecdef=false,proleakproof=false,proisstrict=false,proretset=false,provolatile=118'v',proparallel=117'u',pronargs=3,pronargdefaults=0,prorettype=2249,proargtypes={vl_len_=144,ndim=1,dataoffset=0,elemtype=26,dim1=3,lbound1=0,values=0x7fbeb4388c80}}(gdb)
执行相关判断:如返回类型,参数类型,参数个数等
(gdb)n388if(!pg_proc_ownercheck(oldproc->oid,proowner))(gdb)393if(oldproc->prokind!=prokind)(gdb)407dropcmd=(prokind==PROKIND_PROCEDURE?"DROPPROCEDURE":(gdb)419if(returnType!=oldproc->prorettype||(gdb)420returnsSet!=oldproc->proretset)(gdb)419if(returnType!=oldproc->prorettype||(gdb)439if(returnType==RECORDOID)(gdb)444olddesc=build_function_result_tupdesc_t(oldtup);(gdb)445newdesc=build_function_result_tupdesc_d(prokind,(gdb)449if(olddesc==NULL&&newdesc==NULL)(gdb)451elseif(olddesc==NULL||newdesc==NULL||(gdb)452!equalTupleDescs(olddesc,newdesc))(gdb)451elseif(olddesc==NULL||newdesc==NULL||(gdb)468proargnames=SysCacheGetAttr(PROCNAMEARGSNSP,oldtup,(gdb)471if(!isnull)(gdb)480proargmodes=SysCacheGetAttr(PROCNAMEARGSNSP,oldtup,(gdb)483if(isnull)(gdb)486n_old_arg_names=get_func_input_arg_names(proargnames,(gdb)489n_new_arg_names=get_func_input_arg_names(parameterNames,(gdb)492for(j=0;j<n_old_arg_names;j++)(gdb)494if(old_arg_names[j]==NULL)(gdb)496if(j>=n_new_arg_names||new_arg_names[j]==NULL||(gdb)497strcmp(old_arg_names[j],new_arg_names[j])!=0)(gdb)496if(j>=n_new_arg_names||new_arg_names[j]==NULL||(gdb)492for(j=0;j<n_old_arg_names;j++)(gdb)494if(old_arg_names[j]==NULL)(gdb)496if(j>=n_new_arg_names||new_arg_names[j]==NULL||(gdb)497strcmp(old_arg_names[j],new_arg_names[j])!=0)(gdb)496if(j>=n_new_arg_names||new_arg_names[j]==NULL||(gdb)492for(j=0;j<n_old_arg_names;j++)(gdb)494if(old_arg_names[j]==NULL)(gdb)496if(j>=n_new_arg_names||new_arg_names[j]==NULL||(gdb)497strcmp(old_arg_names[j],new_arg_names[j])!=0)(gdb)496if(j>=n_new_arg_names||new_arg_names[j]==NULL||(gdb)492for(j=0;j<n_old_arg_names;j++)(gdb)517if(oldproc->pronargdefaults!=0)(gdb)568replaces[Anum_pg_proc_oid-1]=false;(gdb)569replaces[Anum_pg_proc_proowner-1]=false;(gdb)570replaces[Anum_pg_proc_proacl-1]=false;(gdb)573tup=heap_modify_tuple(oldtup,tupDesc,values,nulls,replaces);(gdb)574CatalogTupleUpdate(rel,&tup->t_self,tup);(gdb
更新tuple
(gdb)n576ReleaseSysCache(oldtup);(gdb)577is_update=true;(gdb)601retval=((Form_pg_proc)GETSTRUCT(tup))->oid;(gdb)
处理函数依赖
(gdb)pretval$27=16387(gdb)n610deleteDependencyRecordsFor(ProcedureRelationId,retval,true);(gdb)612myself.classId=ProcedureRelationId;(gdb)613myself.objectId=retval;(gdb)614myself.objectSubId=0;(gdb)617referenced.classId=NamespaceRelationId;(gdb)618referenced.objectId=procNamespace;(gdb)619referenced.objectSubId=0;(gdb)620recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);(gdb)623referenced.classId=LanguageRelationId;(gdb)624referenced.objectId=languageObjectId;(gdb)625referenced.objectSubId=0;(gdb)626recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);(gdb)629referenced.classId=TypeRelationId;(gdb)630referenced.objectId=returnType;(gdb)631referenced.objectSubId=0;(gdb)632recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);(gdb)635if((trfid=get_transform_oid(returnType,languageObjectId,true)))(gdb)644for(i=0;i<allParamCount;i++)(gdb)646referenced.classId=TypeRelationId;(gdb)647referenced.objectId=allParams[i];(gdb)648referenced.objectSubId=0;(gdb)649recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);(gdb)652if((trfid=get_transform_oid(allParams[i],languageObjectId,true)))(gdb)644for(i=0;i<allParamCount;i++)(gdb)646referenced.classId=TypeRelationId;(gdb)647referenced.objectId=allParams[i];(gdb)648referenced.objectSubId=0;(gdb)649recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);(gdb)652if((trfid=get_transform_oid(allParams[i],languageObjectId,true)))(gdb)644for(i=0;i<allParamCount;i++)(gdb)646referenced.classId=TypeRelationId;(gdb)647referenced.objectId=allParams[i];(gdb)648referenced.objectSubId=0;(gdb)649recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);(gdb)652if((trfid=get_transform_oid(allParams[i],languageObjectId,true)))(gdb)644for(i=0;i<allParamCount;i++)(gdb)646referenced.classId=TypeRelationId;(gdb)647referenced.objectId=allParams[i];(gdb)648referenced.objectSubId=0;(gdb)649recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);(gdb)652if((trfid=get_transform_oid(allParams[i],languageObjectId,true)))(gdb)644for(i=0;i<allParamCount;i++)(gdb)646referenced.classId=TypeRelationId;(gdb)647referenced.objectId=allParams[i];(gdb)648referenced.objectSubId=0;(gdb)649recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);(gdb)652if((trfid=get_transform_oid(allParams[i],languageObjectId,true)))(gdb)644for(i=0;i<allParamCount;i++)(gdb)662if(parameterDefaults)(gdb)667if(OidIsValid(prosupport))(gdb)676if(!is_update)(gdb)680if(!is_update)(gdb)685recordDependencyOnCurrentExtension(&myself,is_update);(gdb)687heap_freetuple(tup);(gdb)690InvokeObjectPostCreateHook(ProcedureRelationId,retval,0);(gdb)692table_close(rel,RowExclusiveLock);(gdb)
执行函数body验证
695if(OidIsValid(languageValidator))(gdb)697ArrayType*set_items=NULL;(gdb)698intsave_nestlevel=0;(gdb)701CommandCounterIncrement();(gdb)713if(check_function_bodies)(gdb)(gdb)n715set_items=(ArrayType*)DatumGetPointer(proconfig);(gdb)716if(set_items)/*NeedanewGUCnestinglevel*/(gdb)726OidFunctionCall1(languageValidator,ObjectIdGetDatum(retval));(gdb)728if(set_items)(gdb)732returnmyself;(gdb)733}(gdb)
完成调用
(gdb)733}(gdb)CreateFunction(pstate=0x1199c88,stmt=0x11748c8)atfunctioncmds.c:11761176}(gdb)
“分析PostgreSQL CreateFunction中的ProcedureCreate函数”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。