千家信息网

分析PostgreSQL CreateFunction中的ProcedureCreate函数

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,本篇内容介绍了"分析PostgreSQL CreateFunction中的ProcedureCreate函数"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一
千家信息网最后更新 2026年11月02日分析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安全错误 数据库的锁怎样保障安全 科技互联网企业 互联网科技保险 互联网属科技 互联网科技开发公司 青岛互联网科技公司 互联网科技网站 互联网科技公司需要的职位 创业天下互联网科技有限公司 阿里互联网科技公司 青岛科技大学互联网大赛研究生 深圳市优智互联网科技有限公司 呼和浩特新华互联网科技学院 科技类公司包括互联网吗 河南住房之家互联网科技 深圳市罗太互联网科技有限公司 互联网领先科技宣传片 抖集互联网科技技术咨询 科技互联网行业投资研究 长沙渺峰互联网科技有限公司 互联网金融金融科技 科技股互联网 厦门中拓互联网络科技有限公司 互联网与科技发展 中国互联网科技发展 碳银互联网科技 科技互联网创业计划书 阿里巴巴算科技企业还是互联网 青岛科技大学互联网大赛研究生 米聚互联网科技南京有限公司排面 山东星卡互联网科技有限公司官网
0