本篇内容介绍了“分析PostgreSQL CreateFunction中的ProcedureCreate函数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Form_pg_language
plpgsql语言定义结构体
/* ---------------- * pg_language definition. cpp turns this into * typedef struct FormData_pg_language * ---------------- */ CATALOG(pg_language,2612,LanguageRelationId) { Oid oid; /* oid */ /* Language name */ NameData lanname; /* Language's owner */ Oid lanowner BKI_DEFAULT(PGUID); /* Is a procedural language */ bool lanispl BKI_DEFAULT(f); /* PL is trusted */ bool lanpltrusted BKI_DEFAULT(f); /* Call handler, if it's a PL */ Oid lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP(pg_proc); /* Optional anonymous-block handler function */ Oid laninline BKI_DEFAULT(0) BKI_LOOKUP(pg_proc); /* Optional validation function */ Oid lanvalidator BKI_DEFAULT(0) BKI_LOOKUP(pg_proc); #ifdef CATALOG_VARLEN /* variable-length fields start here */ /* Access privileges */ aclitem lanacl[1] BKI_DEFAULT(_null_); #endif } FormData_pg_language; /* ---------------- * Form_pg_language corresponds to a pointer to a tuple with * the format of pg_language relation. * ---------------- */ typedef FormData_pg_language *Form_pg_language;
ArrayType
/* * Arrays are varlena objects, so must meet the varlena convention that * the first int32 of the object contains the total object size in bytes. * Be sure to use VARSIZE() and SET_VARSIZE() to access it, though! * Arrays是可变对象集,必须符合varlena约定,即对象的第一个int32包含对象的总大小(以字节为单位)。 * 但是,一定要确保使用VARSIZE和SET_VARSIZE函数范围该结构体 * * CAUTION: if you change the header for ordinary arrays you will also * need to change the headers for oidvector and int2vector! */ typedef struct { //可变的header int32 vl_len_; /* varlena header (do not touch directly!) */ //维度 int ndim; /* # of dimensions */ //指向数据的偏移量,如为0则表示没有位图 int32 dataoffset; /* offset to data, or 0 if no bitmap */ //元素类型的OID Oid elemtype; /* element type OID */ } ArrayType;
DefElem
typedef struct DefElem { NodeTag type; char *defnamespace; /* NULL if unqualified name */ char *defname; Node *arg; /* a (Value *) or a (TypeName *) */ DefElemAction defaction; /* unspecified action, or SET/ADD/DROP */ int location; /* token location, or -1 if unknown */ } DefElem;
FunctionParameter
typedef enum FunctionParameterMode { /* the assigned enum values appear in pg_proc, don't change 'em! */ FUNC_PARAM_IN = 'i', /* input only */ FUNC_PARAM_OUT = 'o', /* output only */ FUNC_PARAM_INOUT = 'b', /* both */ FUNC_PARAM_VARIADIC = 'v', /* variadic (always input) */ FUNC_PARAM_TABLE = 't' /* table function output column */ } FunctionParameterMode; typedef struct FunctionParameter { NodeTag type; char *name; /* parameter name, or NULL if not given */ TypeName *argType; /* TypeName for parameter type */ FunctionParameterMode mode; /* IN/OUT/etc */ Node *defexpr; /* raw default expr, or NULL if not given */ } FunctionParameter;
/* ---------------------------------------------------------------- * ProcedureCreate * * Note: allParameterTypes, parameterModes, parameterNames, trftypes, and proconfig * are either arrays of the proper types or NULL. We declare them Datum, * not "ArrayType *", to avoid importing array.h into pg_proc.h. * 注意: allParameterTypes, parameterModes, parameterNames, trftypes, and proconfig * 要么为相应类型的数组,要么为NULL.这些变量的类型为Datum而不是ArrayType *, * 目的是为了避免引入array.h到pg_proc.h中 * ---------------------------------------------------------------- */ ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, Datum proconfig, Oid prosupport, float4 procost, float4 prorows) { Oid retval;//返回值类型 int parameterCount;//输入参数 int allParamCount;//所有参数,如无输出参数,则为0 Oid *allParams;//所有参数类型,如无输出参数,则为NULL char *paramModes = NULL;//参数类型 bool genericInParam = false; bool genericOutParam = false; bool anyrangeInParam = false; bool anyrangeOutParam = false; bool internalInParam = false; bool internalOutParam = false; Oid variadicType = InvalidOid; Acl *proacl = NULL;//ACL结构体 Relation rel;//关系 HeapTuple tup;//tuple HeapTuple oldtup;//原pg_proc tuple bool nulls[Natts_pg_proc];//是否为null Datum values[Natts_pg_proc];//值 bool replaces[Natts_pg_proc];//是否替换 NameData procname;//名称 TupleDesc tupDesc;//tuple描述符 bool is_update;//是否替换? ObjectAddress myself, referenced; int i;//临时变量 Oid trfid; /* * sanity checks */ Assert(PointerIsValid(prosrc)); //参数个数 parameterCount = parameterTypes->dim1; //#define FUNC_MAX_ARGS 100 if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("functions cannot have more than %d argument", "functions cannot have more than %d arguments", FUNC_MAX_ARGS, FUNC_MAX_ARGS))); /* note: the above is correct, we do NOT count output arguments(不计算输出参数) */ /* Deconstruct array inputs */ //重构数组输入:所有参数类型 if (allParameterTypes != PointerGetDatum(NULL)) { /* * We expect the array to be a 1-D OID array; verify that. We don't * need to use deconstruct_array() since the array data is just going * to look like a C array of OID values. * 我们期望数组是一维OID数组,需要验证这一点. * 因为数组中的数据看起来像是C语言中的OID数组,隐藏不需要使用deconstruct_array()函数 */ ArrayType *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes); //获取数组的维数 //#define ARR_DIMS(a) \ ((int *) (((char *) (a)) + sizeof(ArrayType))) //#define ARR_NDIM(a) ((a)->ndim) //#define ARR_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, "allParameterTypes is not a 1-D Oid array"); //所有参数 allParams = (Oid *) ARR_DATA_PTR(allParamArray); Assert(allParamCount >= parameterCount); /* we assume caller got the contents right */ } else { //均为输入参数,无输出参数 allParamCount = parameterCount; allParams = parameterTypes->values; } if (parameterModes != PointerGetDatum(NULL)) { //参数模式(输入/输出等) /* * We expect the array to be a 1-D CHAR array; verify that. We don't * need to use deconstruct_array() since the array data is just going * to look like a C array of char values. */ ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes); if (ARR_NDIM(modesArray) != 1 || ARR_DIMS(modesArray)[0] != allParamCount || ARR_HASNULL(modesArray) || ARR_ELEMTYPE(modesArray) != CHAROID) elog(ERROR, "parameterModes is not a 1-D char array"); paramModes = (char *) ARR_DATA_PTR(modesArray); } /* * Detect whether we have polymorphic or INTERNAL arguments. The first * loop checks input arguments, the second output arguments. * 检查是否存在多态或者INTERNAL参数. * 两趟循环:第一趟检查输入参数,第二趟检查输出参数 */ for (i = 0; i < parameterCount; i++) { switch (parameterTypes->values[i]) { case ANYARRAYOID: case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: genericInParam = true; break; case ANYRANGEOID: genericInParam = true; anyrangeInParam = true; break; case INTERNALOID: 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; /* ignore input-only params */ switch (allParams[i]) { case ANYARRAYOID: case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: genericOutParam = true; break; case ANYRANGEOID: genericOutParam = true; anyrangeOutParam = true; break; case INTERNALOID: internalOutParam = true; break; } } } /* * Do not allow polymorphic return type unless at least one input argument * is polymorphic. ANYRANGE return type is even stricter: must have an * ANYRANGE input (since we can't deduce the specific range type from * ANYELEMENT). Also, do not allow return type INTERNAL unless at least * one input argument is INTERNAL. * 至少存在一个多态输入参数的情况下才允许返回多态类型. * ANYRANGE返回类型更为严格:必须含有一个ANYRANGE输入(因为无法从ANYELEMENT中规约特殊的范围类型.) * 同时,除非至少有一个INTERNAL输入参数类型,否则不允许返回INTERNAL类型. */ if ((IsPolymorphicType(returnType) || genericOutParam) && !genericInParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine result data type"), errdetail("A function returning a polymorphic type must have at least one polymorphic argument."))); if ((returnType == ANYRANGEOID || anyrangeOutParam) && !anyrangeInParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine result data type"), errdetail("A function returning \"anyrange\" must have at least one \"anyrange\" argument."))); if ((returnType == INTERNALOID || internalOutParam) && !internalInParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("unsafe use of pseudo-type \"internal\""), errdetail("A function returning \"internal\" must have at least one \"internal\" argument."))); if (paramModes != NULL) { /* * Only the last input parameter can be variadic; if it is, save its * element type. Errors here are just elog since caller should have * checked this already. * 只有最后一个输入参数可以是variadic.如是,则存储元素类型. */ for (i = 0; i < allParamCount; i++) { switch (paramModes[i]) { case PROARGMODE_IN: case PROARGMODE_INOUT: if (OidIsValid(variadicType)) elog(ERROR, "variadic parameter must be last"); break; case PROARGMODE_OUT: case PROARGMODE_TABLE: /* okay */ break; case PROARGMODE_VARIADIC: if (OidIsValid(variadicType)) elog(ERROR, "variadic parameter must be last"); switch (allParams[i]) { case ANYOID: variadicType = ANYOID; break; case ANYARRAYOID: variadicType = ANYELEMENTOID; break; default: variadicType = get_element_type(allParams[i]); if (!OidIsValid(variadicType)) elog(ERROR, "variadic parameter is not an array"); break; } break; default: elog(ERROR, "invalid parameter mode '%c'", paramModes[i]); break; } } } /* * All seems OK; prepare the data to be inserted into pg_proc. * 检查完毕,写入到pg_proc中 */ //#define Natts_pg_proc 29 for (i = 0; i < Natts_pg_proc; ++i) { nulls[i] = false; values[i] = (Datum) 0; replaces[i] = true; } //#define Anum_pg_proc_oid 1 //#define Anum_pg_proc_proname 2 //... //#define Anum_pg_proc_proacl 29 namestrcpy(&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; else nulls[Anum_pg_proc_proallargtypes - 1] = true; if (parameterModes != PointerGetDatum(NULL)) values[Anum_pg_proc_proargmodes - 1] = parameterModes; else nulls[Anum_pg_proc_proargmodes - 1] = true; if (parameterNames != PointerGetDatum(NULL)) values[Anum_pg_proc_proargnames - 1] = parameterNames; else nulls[Anum_pg_proc_proargnames - 1] = true; if (parameterDefaults != NIL) values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults)); else nulls[Anum_pg_proc_proargdefaults - 1] = true; if (trftypes != PointerGetDatum(NULL)) values[Anum_pg_proc_protrftypes - 1] = trftypes; else nulls[Anum_pg_proc_protrftypes - 1] = true; values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); if (probin) values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin); else nulls[Anum_pg_proc_probin - 1] = true; if (proconfig != PointerGetDatum(NULL)) values[Anum_pg_proc_proconfig - 1] = proconfig; else nulls[Anum_pg_proc_proconfig - 1] = true; /* proacl will be determined later */ rel = table_open(ProcedureRelationId, RowExclusiveLock); tupDesc = RelationGetDescr(rel); /* Check for pre-existing definition */ //检查是否已存在 oldtup = SearchSysCache3(PROCNAMEARGSNSP, PointerGetDatum(procedureName), PointerGetDatum(parameterTypes), ObjectIdGetDatum(procNamespace)); if (HeapTupleIsValid(oldtup)) { //-------- 已存在 /* There is one; okay to replace it? */ //获取原记录(pg_proc记录) Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup); Datum proargnames; bool isnull; const char *dropcmd; if (!replace) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function \"%s\" already exists with same argument types", procedureName))); if (!pg_proc_ownercheck(oldproc->oid, proowner)) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, procedureName); /* Not okay to change routine kind */ //不能改变类型(如原来是proc,那么创建同名func是不行的) if (oldproc->prokind != prokind) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot change routine kind"), (oldproc->prokind == PROKIND_AGGREGATE ? errdetail("\"%s\" is an aggregate function.", procedureName) : oldproc->prokind == PROKIND_FUNCTION ? errdetail("\"%s\" is a function.", procedureName) : oldproc->prokind == PROKIND_PROCEDURE ? errdetail("\"%s\" is a procedure.", procedureName) : oldproc->prokind == PROKIND_WINDOW ? errdetail("\"%s\" is a window function.", procedureName) : 0))); dropcmd = (prokind == PROKIND_PROCEDURE ? "DROP PROCEDURE" : prokind == PROKIND_AGGREGATE ? "DROP AGGREGATE" : "DROP FUNCTION"); /* * Not okay to change the return type of the existing proc, since * existing rules, views, etc may depend on the return type. * 改变返回类型也是不行的,因为现存的规则\视图等等可能依赖返回类型. * * In case of a procedure, a changing return type means that whether * the procedure has output parameters was changed. Since there is no * user visible return type, we produce a more specific error message. * 如为存储过程,改变返回类型意味着过程已有的输出参数已改变. * 由于存在非用户可见返回类型,隐藏产生更为详尽的错误信息. */ if (returnType != oldproc->prorettype || returnsSet != oldproc->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), prokind == PROKIND_PROCEDURE ? errmsg("cannot change whether a procedure has output parameters") : errmsg("cannot change return type of existing function"), /* * translator: first %s is DROP FUNCTION, DROP PROCEDURE, or DROP * AGGREGATE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); /* * If it returns RECORD, check for possible change of record type * implied by OUT parameters * 如果返回RECORD类型,检查使用OUT参数指明的可能的record类型变化. */ if (returnType == RECORDOID) { //返回RECORD类型 TupleDesc olddesc; TupleDesc newdesc; olddesc = build_function_result_tupdesc_t(oldtup); newdesc = build_function_result_tupdesc_d(prokind, allParameterTypes, parameterModes, parameterNames); if (olddesc == NULL && newdesc == NULL) /* ok, both are runtime-defined RECORDs */ ; else if (olddesc == NULL || newdesc == NULL || !equalTupleDescs(olddesc, newdesc)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change return type of existing function"), errdetail("Row type defined by OUT parameters is different."), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); } /* * If there were any named input parameters, check to make sure the * names have not been changed, as this could break existing calls. We * allow adding names to formerly unnamed parameters, though. * 如存在已命名的输入参数,确保名称没有变更,否则会破坏现存的调用. * 但允许添加名称到未命名的参数中. */ proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargnames, &isnull); if (!isnull) { Datum proargmodes; char **old_arg_names; char **new_arg_names; int n_old_arg_names; int n_new_arg_names; int j; proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargmodes, &isnull); if (isnull) proargmodes = PointerGetDatum(NULL); /* just to be sure */ 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("cannot change name of input parameter \"%s\"", old_arg_names[j]), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); } } /* * If there are existing defaults, check compatibility: redefinition * must not remove any defaults nor change their types. (Removing a * default might cause a function to fail to satisfy an existing call. * Changing type would only be possible if the associated parameter is * polymorphic, and in such cases a change of default type might alter * the resolved output type of existing calls.) * 存在defaults(默认参数),检查兼容性: * 重新定义不应删去已有的默认定义或者改变类型,否则会破坏现存的调用. */ if (oldproc->pronargdefaults != 0) { //默认值判断 Datum proargdefaults; List *oldDefaults; ListCell *oldlc; ListCell *newlc; if (list_length(parameterDefaults) < oldproc->pronargdefaults) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot remove parameter defaults from existing function"), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", 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); /* new list can have more defaults than old, advance over '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("cannot change data type of existing parameter default value"), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); newlc = lnext(newlc); } } /* * Do not change existing oid, ownership or permissions, either. Note * dependency-update code below has to agree with this decision. * 不改变现有的oid,宿主或者权限等. * 注意下面的依赖更新代码必须遵循这一约定. */ replaces[Anum_pg_proc_oid - 1] = false; replaces[Anum_pg_proc_proowner - 1] = false; replaces[Anum_pg_proc_proacl - 1] = false; /* Okay, do it... */ tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); CatalogTupleUpdate(rel, &tup->t_self, tup); ReleaseSysCache(oldtup); is_update = true; } else { //-------------- 不存在 /* Creating a new procedure */ //创建新的过程 Oid newOid; /* First, get default permissions and set up proacl */ //首先:获取默认的权限并设置proacl proacl = get_user_default_acl(OBJECT_FUNCTION, proowner, procNamespace); if (proacl != NULL) values[Anum_pg_proc_proacl - 1] = PointerGetDatum(proacl); else nulls[Anum_pg_proc_proacl - 1] = true; //获取新的OID newOid = GetNewOidWithIndex(rel, ProcedureOidIndexId, Anum_pg_proc_oid); //设置pg_proc中的OID values[Anum_pg_proc_oid - 1] = ObjectIdGetDatum(newOid); //构造tuple tup = heap_form_tuple(tupDesc, values, nulls); //执行插入操作 CatalogTupleInsert(rel, tup); is_update = false; } //获取pg_proc结构体 retval = ((Form_pg_proc) GETSTRUCT(tup))->oid; /* * Create dependencies for the new function. If we are updating an * existing function, first delete any existing pg_depend entries. * (However, since we are not changing ownership or permissions, the * shared dependencies do *not* need to change, and we leave them alone.) * 创建新函数的依赖. * 如正在更新现存的函数,首先删除现存的pg_depend条目. */ if (is_update) //删除依赖 deleteDependencyRecordsFor(ProcedureRelationId, retval, true); myself.classId = ProcedureRelationId; myself.objectId = retval; myself.objectSubId = 0; /* dependency on namespace */ //依赖:namespace referenced.classId = NamespaceRelationId; referenced.objectId = procNamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on implementation language */ //依赖:语言 referenced.classId = LanguageRelationId; referenced.objectId = languageObjectId; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on return type */ //依赖:返回类型 referenced.classId = TypeRelationId; referenced.objectId = returnType; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on transform used by return type, if any */ //依赖:返回类型的转换规则 if ((trfid = get_transform_oid(returnType, languageObjectId, true))) { referenced.classId = TransformRelationId; referenced.objectId = trfid; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* dependency on parameter types */ //依赖:参数类型 for (i = 0; i < allParamCount; i++) { referenced.classId = TypeRelationId; referenced.objectId = allParams[i]; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on transform used by parameter type, if any */ if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) { referenced.classId = TransformRelationId; referenced.objectId = trfid; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } } /* dependency on parameter default expressions */ //依赖:默认表达式 if (parameterDefaults) recordDependencyOnExpr(&myself, (Node *) parameterDefaults, NIL, DEPENDENCY_NORMAL); /* dependency on support function, if any */ //依赖:支持的函数 if (OidIsValid(prosupport)) { referenced.classId = ProcedureRelationId; referenced.objectId = prosupport; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* dependency on owner */ //依赖:owner if (!is_update) recordDependencyOnOwner(ProcedureRelationId, retval, proowner); /* dependency on any roles mentioned in ACL */ //依赖:ACL中标明的角色 if (!is_update) recordDependencyOnNewAcl(ProcedureRelationId, retval, 0, proowner, proacl); /* dependency on extension */ //依赖:扩展 recordDependencyOnCurrentExtension(&myself, is_update); heap_freetuple(tup); /* Post creation hook for new function */ //调用对象创建后的钩子函数 InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0); //关闭pg_proc table_close(rel, RowExclusiveLock); /* Verify function body */ //验证函数body if (OidIsValid(languageValidator)) { ArrayType *set_items = NULL; int save_nestlevel = 0; /* Advance command counter so new tuple can be seen by validator */ //增加命令计数 CommandCounterIncrement(); /* * Set per-function configuration parameters so that the validation is * done with the environment the function expects. However, if * check_function_bodies is off, we don't do this, because that would * create dump ordering hazards that pg_dump doesn't know how to deal * with. (For example, a SET clause might refer to a not-yet-created * text search configuration.) This means that the validator * shouldn't complain about anything that might depend on a GUC * parameter when check_function_bodies is off. */ if (check_function_bodies) { //检查函数体 //获取函数设定的参数 set_items = (ArrayType *) DatumGetPointer(proconfig); if (set_items) /* Need a new GUC nesting level */ { 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); } return myself; }
测试脚本
create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar) returns record as $$ declare begin raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3; pio_v3 := 'pio_v3 i/o'; po_v4 := 100; po_v5 := 'po_v5 out'; end; $$ LANGUAGE plpgsql;
启动GDB跟踪
(gdb) b ProcedureCreate Breakpoint 1 at 0x5bd665: file pg_proc.c, line 99. (gdb) c Continuing. Breakpoint 1, ProcedureCreate (procedureName=0x1173ab0 "func_test", procNamespace=2200, replace=true, returnsSet=false, returnType=2249, proowner=10, languageObjectId=13581, languageValidator=13580, prosrc=0x11745c8 "\ndeclare\nbegin\n raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3;\n pio_v3 := 'pio_v3 i/o';\n po_v4 := 100;\n po_v5 := 'po_v5 out';\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) at pg_proc.c:99 99 char *paramModes = NULL; (gdb)
输入参数
[local:/data/run/pg12]:5120 pg12@testdb=# \d pg_type Table "pg_catalog.pg_type" Column | Type | Collation | Nullable | Default ----------------+--------------+-----------+----------+--------- oid | oid | | not null | typname | name | | not null | typnamespace | oid | | not null | typowner | oid | | not null | typlen | smallint | | not null | typbyval | boolean | | not null | typtype | "char" | | not null | typcategory | "char" | | not null | typispreferred | boolean | | not null | typisdefined | boolean | | not null | typdelim | "char" | | not null | typrelid | oid | | not null | typelem | oid | | not null | typarray | oid | | not null | typinput | regproc | | not null | typoutput | regproc | | not null | typreceive | regproc | | not null | [local:/data/run/pg12]:5120 pg12@testdb=# select oid,typname from pg_type where oid=2249; oid | typname ------+--------- 2249 | record (1 row) [local:/data/run/pg12]:5120 pg12@testdb=# \d pg_namespace Table "pg_catalog.pg_namespace" Column | Type | Collation | Nullable | Default ----------+-----------+-----------+----------+--------- oid | oid | | not null | nspname | name | | not null | nspowner | oid | | not null | nspacl | aclitem[] | | | Indexes: "pg_namespace_nspname_index" UNIQUE, btree (nspname) "pg_namespace_oid_index" UNIQUE, btree (oid) [local:/data/run/pg12]:5120 pg12@testdb=# select oid,nspname from pg_namespace where oid=2200; oid | nspname ------+--------- 2200 | public (1 row) [local:/data/run/pg12]:5120 pg12@testdb=# \d pg_user View "pg_catalog.pg_user" Column | Type | Collation | Nullable | Default --------------+--------------------------+-----------+----------+--------- usename | name | | | usesysid | oid | | | usecreatedb | boolean | | | usesuper | boolean | | | userepl | boolean | | | usebypassrls | boolean | | | passwd | text | | | valuntil | timestamp with time zone | | | useconfig | text[] | C | | [local:/data/run/pg12]:5120 pg12@testdb=# select usename,usesysid from pg_user where usesysid=10; usename | usesysid ---------+---------- pg12 | 10 (1 row) [local:/data/run/pg12]:5120 pg12@testdb=# \d pg_language Table "pg_catalog.pg_language" Column | Type | Collation | Nullable | Default ---------------+-----------+-----------+----------+--------- oid | oid | | not null | lanname | name | | not null | lanowner | oid | | not null | lanispl | boolean | | not null | lanpltrusted | boolean | | not null | lanplcallfoid | oid | | not null | laninline | oid | | not null | lanvalidator | oid | | not null | lanacl | aclitem[] | | | Indexes: "pg_language_name_index" UNIQUE, btree (lanname) "pg_language_oid_index" UNIQUE, btree (oid) [local:/data/run/pg12]:5120 pg12@testdb=# select oid,lanname,lanowner from pg_language where oid=13581; oid | lanname | lanowner -------+---------+---------- 13581 | plpgsql | 10 (1 row)
初始化本地临时变量
99 char *paramModes = NULL; (gdb) n 100 bool genericInParam = false; (gdb) 101 bool genericOutParam = false; (gdb) 102 bool anyrangeInParam = false; (gdb) 103 bool anyrangeOutParam = false; (gdb) 104 bool internalInParam = false; (gdb) 105 bool internalOutParam = false; (gdb) 106 Oid variadicType = InvalidOid; (gdb) 107 Acl *proacl = NULL; (gdb) 125 Assert(PointerIsValid(prosrc)); (gdb) 127 parameterCount = parameterTypes->dim1; (gdb)
获取参数个数(3个输入参数,类型为26-oid,数据类型为int4,varchar,varchar)
(gdb) n 128 if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS) (gdb) p parameterCount $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) p parameterTypes->values[1] $4 = 1043 (gdb) p parameterTypes->values[2] $5 = 1043 (gdb) ### [local:/data/run/pg12]:5120 pg12@testdb=# select oid,typname from pg_type where oid=26; oid | typname -----+--------- 26 | oid (1 row) [local:/data/run/pg12]:5120 pg12@testdb=# select oid,typname from pg_type where oid in (23,1043); oid | typname ------+--------- 23 | int4 1043 | varchar (2 rows)
重构数组输入:所有参数类型
(gdb) n 138 if (allParameterTypes != PointerGetDatum(NULL)) (gdb) 145 ArrayType *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes); (gdb) 147 allParamCount = ARR_DIMS(allParamArray)[0]; (gdb) 148 if (ARR_NDIM(allParamArray) != 1 || (gdb) 150 ARR_HASNULL(allParamArray) || (gdb) 149 allParamCount <= 0 || (gdb) 151 ARR_ELEMTYPE(allParamArray) != OIDOID) (gdb) 150 ARR_HASNULL(allParamArray) || (gdb) 153 allParams = (Oid *) ARR_DATA_PTR(allParamArray); (gdb) 154 Assert(allParamCount >= parameterCount); (gdb) p *allParamArray $6 = {vl_len_ = 176, ndim = 1, dataoffset = 0, elemtype = 26} (gdb) p allParamArray[1] $7 = {vl_len_ = 5, ndim = 1, dataoffset = 23, elemtype = 1043} (gdb) p allParamCount $8 = 5 (gdb) p *ARR_DIMS(allParamArray) $9 = 5 (gdb) p allParamArray[2] $10 = {vl_len_ = 1043, ndim = 23, dataoffset = 1043, elemtype = 2139062142} (gdb) p allParamArray[3] $11 = {vl_len_ = 2139062143, ndim = 2139062143, dataoffset = 2139062143, elemtype = 2139062143} (gdb) n 163 if (parameterModes != PointerGetDatum(NULL)) (gdb)
处理参数模式:参数模式(输入/输出等),分别是i,i,b,o,o
(gdb) n 170 ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes); (gdb) 172 if (ARR_NDIM(modesArray) != 1 || (gdb) 173 ARR_DIMS(modesArray)[0] != allParamCount || (gdb) 172 if (ARR_NDIM(modesArray) != 1 || (gdb) 174 ARR_HASNULL(modesArray) || (gdb) 173 ARR_DIMS(modesArray)[0] != allParamCount || (gdb) 175 ARR_ELEMTYPE(modesArray) != CHAROID) (gdb) 174 ARR_HASNULL(modesArray) || (gdb) 177 paramModes = (char *) ARR_DATA_PTR(modesArray); (gdb) 184 for (i = 0; i < parameterCount; i++) (gdb) p paramModes[0] $12 = 105 'i' (gdb) p paramModes[1] $13 = 105 'i' (gdb) p paramModes[2] $14 = 98 'b' (gdb) p paramModes[3] $15 = 111 'o' (gdb) p paramModes[4] $16 = 111 'o' (gdb)
检查是否存在多态或者INTERNAL参数.
两趟循环:第一趟检查输入参数,第二趟检查输出参数
(gdb) n 186 switch (parameterTypes->values[i]) (gdb) 184 for (i = 0; i < parameterCount; i++) (gdb) 186 switch (parameterTypes->values[i]) (gdb) 184 for (i = 0; i < parameterCount; i++) (gdb) 186 switch (parameterTypes->values[i]) (gdb) 184 for (i = 0; i < parameterCount; i++) (gdb) 204 if (allParameterTypes != PointerGetDatum(NULL)) (gdb) 206 for (i = 0; i < allParamCount; i++) (gdb) 208 if (paramModes == NULL || (gdb) 209 paramModes[i] == PROARGMODE_IN || (gdb) 208 if (paramModes == NULL || (gdb) 211 continue; /* ignore input-only params */ (gdb) 206 for (i = 0; i < allParamCount; i++) (gdb) 208 if (paramModes == NULL || (gdb) 209 paramModes[i] == PROARGMODE_IN || (gdb) 208 if (paramModes == NULL || (gdb) 211 continue; /* ignore input-only params */ (gdb) 206 for (i = 0; i < allParamCount; i++) (gdb) 208 if (paramModes == NULL || (gdb) 209 paramModes[i] == PROARGMODE_IN || (gdb) 208 if (paramModes == NULL || (gdb) 210 paramModes[i] == PROARGMODE_VARIADIC) (gdb) 209 paramModes[i] == PROARGMODE_IN || (gdb) 213 switch (allParams[i]) (gdb) 206 for (i = 0; i < allParamCount; i++) (gdb) 208 if (paramModes == NULL || (gdb) 209 paramModes[i] == PROARGMODE_IN || (gdb) 208 if (paramModes == NULL || (gdb) 210 paramModes[i] == PROARGMODE_VARIADIC) (gdb) 209 paramModes[i] == PROARGMODE_IN || (gdb) 213 switch (allParams[i]) (gdb) 206 for (i = 0; i < allParamCount; i++) (gdb) 208 if (paramModes == NULL || (gdb) p allParamCount $17 = 5 (gdb) n 209 paramModes[i] == PROARGMODE_IN || (gdb) 208 if (paramModes == NULL || (gdb) 210 paramModes[i] == PROARGMODE_VARIADIC) (gdb) 209 paramModes[i] == PROARGMODE_IN || (gdb) 213 switch (allParams[i]) (gdb) 206 for (i = 0; i < allParamCount; i++) (gdb) 239 if ((IsPolymorphicType(returnType) || genericOutParam) (gdb)
至少存在一个多态输入参数的情况下才允许返回多态类型.
ANYRANGE返回类型更为严格:必须含有一个ANYRANGE输入(因为无法从ANYELEMENT中规约特殊的范围类型.)
同时,除非至少有一个INTERNAL输入参数类型,否则不允许返回INTERNAL类型.
(gdb) n 246 if ((returnType == ANYRANGEOID || anyrangeOutParam) && (gdb) 253 if ((returnType == INTERNALOID || internalOutParam) && !internalInParam) (gdb) 259 if (paramModes != NULL) (gdb)
只有最后一个输入参数可以是variadic.如是,则存储元素类型.
266 for (i = 0; i < allParamCount; i++) (gdb) n 268 switch (paramModes[i]) (gdb) 272 if (OidIsValid(variadicType)) (gdb) 274 break; (gdb) 266 for (i = 0; i < allParamCount; i++) (gdb) 268 switch (paramModes[i]) (gdb) 272 if (OidIsValid(variadicType)) (gdb) 274 break; (gdb) 266 for (i = 0; i < allParamCount; i++) (gdb) 268 switch (paramModes[i]) (gdb) 272 if (OidIsValid(variadicType)) (gdb) 274 break; (gdb) 266 for (i = 0; i < allParamCount; i++) (gdb) 268 switch (paramModes[i]) (gdb) 278 break; (gdb) 266 for (i = 0; i < allParamCount; i++) (gdb) 268 switch (paramModes[i]) (gdb) 278 break; (gdb) 266 for (i = 0; i < allParamCount; i++) (gdb) 308 for (i = 0; i < Natts_pg_proc; ++i) (gdb)
检查完毕,写入到pg_proc中,初始化values
308 for (i = 0; i < Natts_pg_proc; ++i) (gdb) 310 nulls[i] = false; (gdb) 311 values[i] = (Datum) 0; (gdb) 312 replaces[i] = true; (gdb) ...
赋值
308 for (i = 0; i < Natts_pg_proc; ++i) (gdb) 315 namestrcpy(&procname, procedureName); (gdb) 316 values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname); (gdb) p procedureName $20 = 0x1173ab0 "func_test" (gdb) n 317 values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace); (gdb) 318 values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner); (gdb) 319 values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId); (gdb) 320 values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost); (gdb) 321 values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows); (gdb) 322 values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType); (gdb) 323 values[Anum_pg_proc_prosupport - 1] = ObjectIdGetDatum(prosupport); (gdb) 324 values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind); (gdb) 325 values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer); (gdb) 326 values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof); (gdb) 327 values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict); (gdb) 328 values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet); (gdb) 329 values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility); (gdb) 330 values[Anum_pg_proc_proparallel - 1] = CharGetDatum(parallel); (gdb) 331 values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount); (gdb) 332 values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults)); (gdb) 333 values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType); (gdb) 334 values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes); (gdb) 335 if (allParameterTypes != PointerGetDatum(NULL)) (gdb) 336 values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes; (gdb) 339 if (parameterModes != PointerGetDatum(NULL)) (gdb) 340 values[Anum_pg_proc_proargmodes - 1] = parameterModes; (gdb) 343 if (parameterNames != PointerGetDatum(NULL)) (gdb) 344 values[Anum_pg_proc_proargnames - 1] = parameterNames; (gdb) 347 if (parameterDefaults != NIL) (gdb) 350 nulls[Anum_pg_proc_proargdefaults - 1] = true; (gdb) 351 if (trftypes != PointerGetDatum(NULL)) (gdb) 354 nulls[Anum_pg_proc_protrftypes - 1] = true; (gdb) 355 values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); (gdb) 356 if (probin) (gdb) 359 nulls[Anum_pg_proc_probin - 1] = true; (gdb) 360 if (proconfig != PointerGetDatum(NULL)) (gdb) 363 nulls[Anum_pg_proc_proconfig - 1] = true; (gdb) 366 rel = table_open(ProcedureRelationId, RowExclusiveLock); (gdb) 367 tupDesc = RelationGetDescr(rel); (gdb)
判断是否已存在
(gdb) p values[28] $21 = 0 (gdb) p values[0] $22 = 0 (gdb) p values[2] $23 = 2200 (gdb) n 370 oldtup = SearchSysCache3(PROCNAMEARGSNSP, (gdb) p *tupDesc $24 = {natts = 29, tdtypeid = 81, tdtypmod = -1, tdrefcount = 1, constr = 0x7fbeb44493b8, attrs = 0x7fbeb44483b8} (gdb) n 375 if (HeapTupleIsValid(oldtup)) (gdb) 378 Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup); (gdb) 383 if (!replace) (gdb) p oldproc $25 = (Form_pg_proc) 0x7fbeb4388bf8 (gdb) p *oldproc $26 = {oid = 16387, proname = {data = "func_test", '\000' <repeats 54 times>}, 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) n 388 if (!pg_proc_ownercheck(oldproc->oid, proowner)) (gdb) 393 if (oldproc->prokind != prokind) (gdb) 407 dropcmd = (prokind == PROKIND_PROCEDURE ? "DROP PROCEDURE" : (gdb) 419 if (returnType != oldproc->prorettype || (gdb) 420 returnsSet != oldproc->proretset) (gdb) 419 if (returnType != oldproc->prorettype || (gdb) 439 if (returnType == RECORDOID) (gdb) 444 olddesc = build_function_result_tupdesc_t(oldtup); (gdb) 445 newdesc = build_function_result_tupdesc_d(prokind, (gdb) 449 if (olddesc == NULL && newdesc == NULL) (gdb) 451 else if (olddesc == NULL || newdesc == NULL || (gdb) 452 !equalTupleDescs(olddesc, newdesc)) (gdb) 451 else if (olddesc == NULL || newdesc == NULL || (gdb) 468 proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, (gdb) 471 if (!isnull) (gdb) 480 proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, (gdb) 483 if (isnull) (gdb) 486 n_old_arg_names = get_func_input_arg_names(proargnames, (gdb) 489 n_new_arg_names = get_func_input_arg_names(parameterNames, (gdb) 492 for (j = 0; j < n_old_arg_names; j++) (gdb) 494 if (old_arg_names[j] == NULL) (gdb) 496 if (j >= n_new_arg_names || new_arg_names[j] == NULL || (gdb) 497 strcmp(old_arg_names[j], new_arg_names[j]) != 0) (gdb) 496 if (j >= n_new_arg_names || new_arg_names[j] == NULL || (gdb) 492 for (j = 0; j < n_old_arg_names; j++) (gdb) 494 if (old_arg_names[j] == NULL) (gdb) 496 if (j >= n_new_arg_names || new_arg_names[j] == NULL || (gdb) 497 strcmp(old_arg_names[j], new_arg_names[j]) != 0) (gdb) 496 if (j >= n_new_arg_names || new_arg_names[j] == NULL || (gdb) 492 for (j = 0; j < n_old_arg_names; j++) (gdb) 494 if (old_arg_names[j] == NULL) (gdb) 496 if (j >= n_new_arg_names || new_arg_names[j] == NULL || (gdb) 497 strcmp(old_arg_names[j], new_arg_names[j]) != 0) (gdb) 496 if (j >= n_new_arg_names || new_arg_names[j] == NULL || (gdb) 492 for (j = 0; j < n_old_arg_names; j++) (gdb) 517 if (oldproc->pronargdefaults != 0) (gdb) 568 replaces[Anum_pg_proc_oid - 1] = false; (gdb) 569 replaces[Anum_pg_proc_proowner - 1] = false; (gdb) 570 replaces[Anum_pg_proc_proacl - 1] = false; (gdb) 573 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); (gdb) 574 CatalogTupleUpdate(rel, &tup->t_self, tup); (gdb
更新tuple
(gdb) n 576 ReleaseSysCache(oldtup); (gdb) 577 is_update = true; (gdb) 601 retval = ((Form_pg_proc) GETSTRUCT(tup))->oid; (gdb)
处理函数依赖
(gdb) p retval $27 = 16387 (gdb) n 610 deleteDependencyRecordsFor(ProcedureRelationId, retval, true); (gdb) 612 myself.classId = ProcedureRelationId; (gdb) 613 myself.objectId = retval; (gdb) 614 myself.objectSubId = 0; (gdb) 617 referenced.classId = NamespaceRelationId; (gdb) 618 referenced.objectId = procNamespace; (gdb) 619 referenced.objectSubId = 0; (gdb) 620 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); (gdb) 623 referenced.classId = LanguageRelationId; (gdb) 624 referenced.objectId = languageObjectId; (gdb) 625 referenced.objectSubId = 0; (gdb) 626 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); (gdb) 629 referenced.classId = TypeRelationId; (gdb) 630 referenced.objectId = returnType; (gdb) 631 referenced.objectSubId = 0; (gdb) 632 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); (gdb) 635 if ((trfid = get_transform_oid(returnType, languageObjectId, true))) (gdb) 644 for (i = 0; i < allParamCount; i++) (gdb) 646 referenced.classId = TypeRelationId; (gdb) 647 referenced.objectId = allParams[i]; (gdb) 648 referenced.objectSubId = 0; (gdb) 649 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); (gdb) 652 if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) (gdb) 644 for (i = 0; i < allParamCount; i++) (gdb) 646 referenced.classId = TypeRelationId; (gdb) 647 referenced.objectId = allParams[i]; (gdb) 648 referenced.objectSubId = 0; (gdb) 649 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); (gdb) 652 if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) (gdb) 644 for (i = 0; i < allParamCount; i++) (gdb) 646 referenced.classId = TypeRelationId; (gdb) 647 referenced.objectId = allParams[i]; (gdb) 648 referenced.objectSubId = 0; (gdb) 649 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); (gdb) 652 if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) (gdb) 644 for (i = 0; i < allParamCount; i++) (gdb) 646 referenced.classId = TypeRelationId; (gdb) 647 referenced.objectId = allParams[i]; (gdb) 648 referenced.objectSubId = 0; (gdb) 649 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); (gdb) 652 if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) (gdb) 644 for (i = 0; i < allParamCount; i++) (gdb) 646 referenced.classId = TypeRelationId; (gdb) 647 referenced.objectId = allParams[i]; (gdb) 648 referenced.objectSubId = 0; (gdb) 649 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); (gdb) 652 if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) (gdb) 644 for (i = 0; i < allParamCount; i++) (gdb) 662 if (parameterDefaults) (gdb) 667 if (OidIsValid(prosupport)) (gdb) 676 if (!is_update) (gdb) 680 if (!is_update) (gdb) 685 recordDependencyOnCurrentExtension(&myself, is_update); (gdb) 687 heap_freetuple(tup); (gdb) 690 InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0); (gdb) 692 table_close(rel, RowExclusiveLock); (gdb)
执行函数body验证
695 if (OidIsValid(languageValidator)) (gdb) 697 ArrayType *set_items = NULL; (gdb) 698 int save_nestlevel = 0; (gdb) 701 CommandCounterIncrement(); (gdb) 713 if (check_function_bodies) (gdb) (gdb) n 715 set_items = (ArrayType *) DatumGetPointer(proconfig); (gdb) 716 if (set_items) /* Need a new GUC nesting level */ (gdb) 726 OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval)); (gdb) 728 if (set_items) (gdb) 732 return myself; (gdb) 733 } (gdb)
完成调用
(gdb) 733 } (gdb) CreateFunction (pstate=0x1199c88, stmt=0x11748c8) at functioncmds.c:1176 1176 } (gdb)
“分析PostgreSQL CreateFunction中的ProcedureCreate函数”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。