千家信息网

分析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函数"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0