分析PostgreSQL CreateFunction中的ProcedureCreate函数
发表于:2025-01-27 作者:千家信息网编辑
千家信息网最后更新 2025年01月27日,本篇内容介绍了"分析PostgreSQL CreateFunction中的ProcedureCreate函数"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一
千家信息网最后更新 2025年01月27日分析PostgreSQL CreateFunction中的ProcedureCreate函数
本篇内容介绍了"分析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中 * ---------------------------------------------------------------- */ObjectAddressProcedureCreate(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$$declarebegin 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 ProcedureCreateBreakpoint 1 at 0x5bd665: file pg_proc.c, line 99.(gdb) cContinuing.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:9999 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) n100 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) n128 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) n138 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) n163 if (parameterModes != PointerGetDatum(NULL))(gdb)
处理参数模式:参数模式(输入/输出等),分别是i,i,b,o,o
(gdb) n170 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) n186 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) n209 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) n246 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) n268 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) n317 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) n370 oldtup = SearchSysCache3(PROCNAMEARGSNSP,(gdb) p *tupDesc$24 = {natts = 29, tdtypeid = 81, tdtypmod = -1, tdrefcount = 1, constr = 0x7fbeb44493b8, attrs = 0x7fbeb44483b8}(gdb) n375 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'}, 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) n388 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) n576 ReleaseSysCache(oldtup);(gdb) 577 is_update = true;(gdb) 601 retval = ((Form_pg_proc) GETSTRUCT(tup))->oid;(gdb)
处理函数依赖
(gdb) p retval$27 = 16387(gdb) n610 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) n715 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:11761176 }(gdb)
"分析PostgreSQL CreateFunction中的ProcedureCreate函数"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
参数
类型
输入
函数
检查
输出
数组
多态
结构
对象
数据
语言
过程
分析
个数
元素
变量
名称
情况
模式
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
深耕网络技术教学
上位机软件开发工程师QT
服务器系统在u盘怎么看
东北方言数据库
软件开发身体
无法识别服务器的原因
服务器内存功耗
关系数据库主要特点的叙述
网络技术部有哪些部门
中国矿业大学网络安全系官网
知了云云服务器是真的吗
苏州市服务器包装公司价格
域名解析服务器ip
少女回战服务器互通吗
2021年网络安全周
勒索病毒网络安全人才培养
交易所软件开发 深圳
中国软件开发公司是国企吗
小学网络安全自查总结博客
服务器内存条怎么看内存大小
雅昌数据库图书
数据库执行崩溃
织梦调用外部数据库
茂名配方管理软件开发
互联网软件开发企业法律问题
小学 网络安全 反思
学习软件开发需要具备什么素质
上半年网络安全工作情况报告
虹口区口碑好的软件开发有哪些
在数据库中插入图片的代码