溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

分析PostgreSQL CreateFunction中的ProcedureCreate函數(shù)

發(fā)布時間:2021-11-05 15:06:23 來源:億速云 閱讀:186 作者:iii 欄目:關(guān)系型數(shù)據(jù)庫

本篇內(nèi)容介紹了“分析PostgreSQL CreateFunction中的ProcedureCreate函數(shù)”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

一、數(shù)據(jù)結(jié)構(gòu)

Form_pg_language
plpgsql語言定義結(jié)構(gòu)體

/* ----------------
 *      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包含對象的總大?。ㄒ宰止?jié)為單位)。
 * 但是,一定要確保使用VARSIZE和SET_VARSIZE函數(shù)范圍該結(jié)構(gòu)體
 *
 * 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 */
    //指向數(shù)據(jù)的偏移量,如為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
 *      要么為相應(yīng)類型的數(shù)組,要么為NULL.這些變量的類型為Datum而不是ArrayType *,
 *      目的是為了避免引入array.h到pg_proc.h中
 * ----------------------------------------------------------------
 */
ObjectAddress
ProcedureCreate(const char *procedureName,
        Oid procNamespace,
        bool replace,
        bool returnsSet,
        Oid returnType,
        Oid proowner,
        Oid languageObjectId,
        Oid languageValidator,
        const char *prosrc,
        const char *probin,
        char prokind,
        bool security_definer,
        bool isLeakProof,
        bool isStrict,
        char volatility,
        char parallel,
        oidvector *parameterTypes,
        Datum allParameterTypes,
        Datum parameterModes,
        Datum parameterNames,
        List *parameterDefaults,
        Datum trftypes,
        Datum proconfig,
        Oid prosupport,
        float4 procost,
        float4 prorows)
{
  Oid     retval;//返回值類型
  int     parameterCount;//輸入?yún)?shù)
  int     allParamCount;//所有參數(shù),如無輸出參數(shù),則為0
  Oid      *allParams;//所有參數(shù)類型,如無輸出參數(shù),則為NULL
  char     *paramModes = NULL;//參數(shù)類型
  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結(jié)構(gòu)體
  Relation  rel;//關(guān)系
  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));
  //參數(shù)個數(shù)
  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(不計(jì)算輸出參數(shù)) */
  /* Deconstruct array inputs */
  //重構(gòu)數(shù)組輸入:所有參數(shù)類型
  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.
     * 我們期望數(shù)組是一維OID數(shù)組,需要驗(yàn)證這一點(diǎn).
     * 因?yàn)閿?shù)組中的數(shù)據(jù)看起來像是C語言中的OID數(shù)組,隱藏不需要使用deconstruct_array()函數(shù)
     */
    ArrayType  *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes);
    //獲取數(shù)組的維數(shù)
    //#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");
    //所有參數(shù)
    allParams = (Oid *) ARR_DATA_PTR(allParamArray);
    Assert(allParamCount >= parameterCount);
    /* we assume caller got the contents right */
  }
  else
  {
    //均為輸入?yún)?shù),無輸出參數(shù)
    allParamCount = parameterCount;
    allParams = parameterTypes->values;
  }
  if (parameterModes != PointerGetDatum(NULL))
  {
    //參數(shù)模式(輸入/輸出等)
    /*
     * 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.
   * 檢查是否存在多態(tài)或者INTERNAL參數(shù).
   * 兩趟循環(huán):第一趟檢查輸入?yún)?shù),第二趟檢查輸出參數(shù)
   */
  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.
   * 至少存在一個多態(tài)輸入?yún)?shù)的情況下才允許返回多態(tài)類型.
   * ANYRANGE返回類型更為嚴(yán)格:必須含有一個ANYRANGE輸入(因?yàn)闊o法從ANYELEMENT中規(guī)約特殊的范圍類型.)
   * 同時,除非至少有一個INTERNAL輸入?yún)?shù)類型,否則不允許返回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.
     * 只有最后一個輸入?yún)?shù)可以是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,那么創(chuàng)建同名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.
     * 改變返回類型也是不行的,因?yàn)楝F(xiàn)存的規(guī)則\視圖等等可能依賴返回類型.
     *
     * 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.
     * 如為存儲過程,改變返回類型意味著過程已有的輸出參數(shù)已改變.
     * 由于存在非用戶可見返回類型,隱藏產(chǎn)生更為詳盡的錯誤信息.
     */
    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參數(shù)指明的可能的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.
     * 如存在已命名的輸入?yún)?shù),確保名稱沒有變更,否則會破壞現(xiàn)存的調(diào)用.
     * 但允許添加名稱到未命名的參數(shù)中.
     */
    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(默認(rèn)參數(shù)),檢查兼容性:
     * 重新定義不應(yīng)刪去已有的默認(rèn)定義或者改變類型,否則會破壞現(xiàn)存的調(diào)用.
     */
    if (oldproc->pronargdefaults != 0)
    {
      //默認(rèn)值判斷
      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.
     * 不改變現(xiàn)有的oid,宿主或者權(quán)限等.
     * 注意下面的依賴更新代碼必須遵循這一約定.
     */
    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 */
    //創(chuàng)建新的過程
    Oid     newOid;
    /* First, get default permissions and set up proacl */
    //首先:獲取默認(rèn)的權(quán)限并設(shè)置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);
    //設(shè)置pg_proc中的OID
    values[Anum_pg_proc_oid - 1] = ObjectIdGetDatum(newOid);
    //構(gòu)造tuple
    tup = heap_form_tuple(tupDesc, values, nulls);
    //執(zhí)行插入操作
    CatalogTupleInsert(rel, tup);
    is_update = false;
  }
  //獲取pg_proc結(jié)構(gòu)體
  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.)
   * 創(chuàng)建新函數(shù)的依賴.
   * 如正在更新現(xiàn)存的函數(shù),首先刪除現(xiàn)存的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 */
  //依賴:返回類型的轉(zhuǎn)換規(guī)則
  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 */
  //依賴:參數(shù)類型
  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 */
  //依賴:默認(rèn)表達(dá)式
  if (parameterDefaults)
    recordDependencyOnExpr(&myself, (Node *) parameterDefaults,
                 NIL, DEPENDENCY_NORMAL);
  /* dependency on support function, if any */
  //依賴:支持的函數(shù)
  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中標(biāo)明的角色
  if (!is_update)
    recordDependencyOnNewAcl(ProcedureRelationId, retval, 0,
                 proowner, proacl);
  /* dependency on extension */
  //依賴:擴(kuò)展
  recordDependencyOnCurrentExtension(&myself, is_update);
  heap_freetuple(tup);
  /* Post creation hook for new function */
  //調(diào)用對象創(chuàng)建后的鉤子函數(shù)
  InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
  //關(guān)閉pg_proc
  table_close(rel, RowExclusiveLock);
  /* Verify function body */
  //驗(yàn)證函數(shù)body
  if (OidIsValid(languageValidator))
  {
    ArrayType  *set_items = NULL;
    int     save_nestlevel = 0;
    /* Advance command counter so new tuple can be seen by validator */
    //增加命令計(jì)數(shù)
    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)
    {
      //檢查函數(shù)體
      //獲取函數(shù)設(shè)定的參數(shù)
      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);
      }
    }
    //調(diào)用語言校驗(yàn)器
    OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
    if (set_items)
      AtEOXact_GUC(true, save_nestlevel);
  }
  return myself;
}

三、跟蹤分析

測試腳本

create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar)
returns record 
as
$$
declare
begin
  raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3;
  pio_v3 := 'pio_v3 i/o';
  po_v4 := 100;
  po_v5 := 'po_v5 out';
end;
$$ LANGUAGE plpgsql;

啟動GDB跟蹤

(gdb) b ProcedureCreate
Breakpoint 1 at 0x5bd665: file pg_proc.c, line 99.
(gdb) c
Continuing.
Breakpoint 1, ProcedureCreate (procedureName=0x1173ab0 "func_test", procNamespace=2200, 
    replace=true, returnsSet=false, returnType=2249, proowner=10, languageObjectId=13581, 
    languageValidator=13580, 
    prosrc=0x11745c8 "\ndeclare\nbegin\n  raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3;\n  pio_v3 := 'pio_v3 i/o';\n  po_v4 := 100;\n  po_v5 := 'po_v5 out';\nend;\n", 
    probin=0x0, prokind=102 'f', security_definer=false, isLeakProof=false, isStrict=false, 
    volatility=118 'v', parallel=117 'u', parameterTypes=0x119a3d0, 
    allParameterTypes=18458616, parameterModes=18457432, parameterNames=18456792, 
    parameterDefaults=0x0, trftypes=0, proconfig=0, prosupport=0, procost=100, prorows=0)
    at pg_proc.c:99
99    char     *paramModes = NULL;
(gdb)

輸入?yún)?shù)

[local:/data/run/pg12]:5120 pg12@testdb=# \d pg_type
                   Table "pg_catalog.pg_type"
     Column     |     Type     | Collation | Nullable | Default 
----------------+--------------+-----------+----------+---------
 oid            | oid          |           | not null | 
 typname        | name         |           | not null | 
 typnamespace   | oid          |           | not null | 
 typowner       | oid          |           | not null | 
 typlen         | smallint     |           | not null | 
 typbyval       | boolean      |           | not null | 
 typtype        | "char"       |           | not null | 
 typcategory    | "char"       |           | not null | 
 typispreferred | boolean      |           | not null | 
 typisdefined   | boolean      |           | not null | 
 typdelim       | "char"       |           | not null | 
 typrelid       | oid          |           | not null | 
 typelem        | oid          |           | not null | 
 typarray       | oid          |           | not null | 
 typinput       | regproc      |           | not null | 
 typoutput      | regproc      |           | not null | 
 typreceive     | regproc      |           | not null | 
[local:/data/run/pg12]:5120 pg12@testdb=# select oid,typname from pg_type where oid=2249;
 oid  | typname 
------+---------
 2249 | record
(1 row)
[local:/data/run/pg12]:5120 pg12@testdb=# \d pg_namespace
            Table "pg_catalog.pg_namespace"
  Column  |   Type    | Collation | Nullable | Default 
----------+-----------+-----------+----------+---------
 oid      | oid       |           | not null | 
 nspname  | name      |           | not null | 
 nspowner | oid       |           | not null | 
 nspacl   | aclitem[] |           |          | 
Indexes:
    "pg_namespace_nspname_index" UNIQUE, btree (nspname)
    "pg_namespace_oid_index" UNIQUE, btree (oid)
[local:/data/run/pg12]:5120 pg12@testdb=# select oid,nspname from pg_namespace where oid=2200;
 oid  | nspname 
------+---------
 2200 | public
(1 row)
[local:/data/run/pg12]:5120 pg12@testdb=# \d pg_user
                        View "pg_catalog.pg_user"
    Column    |           Type           | Collation | Nullable | Default 
--------------+--------------------------+-----------+----------+---------
 usename      | name                     |           |          | 
 usesysid     | oid                      |           |          | 
 usecreatedb  | boolean                  |           |          | 
 usesuper     | boolean                  |           |          | 
 userepl      | boolean                  |           |          | 
 usebypassrls | boolean                  |           |          | 
 passwd       | text                     |           |          | 
 valuntil     | timestamp with time zone |           |          | 
 useconfig    | text[]                   | C         |          | 
[local:/data/run/pg12]:5120 pg12@testdb=# select usename,usesysid from pg_user where usesysid=10;
 usename | usesysid 
---------+----------
 pg12    |       10
(1 row)
[local:/data/run/pg12]:5120 pg12@testdb=# \d pg_language
               Table "pg_catalog.pg_language"
    Column     |   Type    | Collation | Nullable | Default 
---------------+-----------+-----------+----------+---------
 oid           | oid       |           | not null | 
 lanname       | name      |           | not null | 
 lanowner      | oid       |           | not null | 
 lanispl       | boolean   |           | not null | 
 lanpltrusted  | boolean   |           | not null | 
 lanplcallfoid | oid       |           | not null | 
 laninline     | oid       |           | not null | 
 lanvalidator  | oid       |           | not null | 
 lanacl        | aclitem[] |           |          | 
Indexes:
    "pg_language_name_index" UNIQUE, btree (lanname)
    "pg_language_oid_index" UNIQUE, btree (oid)
[local:/data/run/pg12]:5120 pg12@testdb=# select oid,lanname,lanowner from pg_language where oid=13581;
  oid  | lanname | lanowner 
-------+---------+----------
 13581 | plpgsql |       10
(1 row)

初始化本地臨時變量

99    char     *paramModes = NULL;
(gdb) n
100   bool    genericInParam = false;
(gdb) 
101   bool    genericOutParam = false;
(gdb) 
102   bool    anyrangeInParam = false;
(gdb) 
103   bool    anyrangeOutParam = false;
(gdb) 
104   bool    internalInParam = false;
(gdb) 
105   bool    internalOutParam = false;
(gdb) 
106   Oid     variadicType = InvalidOid;
(gdb) 
107   Acl      *proacl = NULL;
(gdb) 
125   Assert(PointerIsValid(prosrc));
(gdb) 
127   parameterCount = parameterTypes->dim1;
(gdb)

獲取參數(shù)個數(shù)(3個輸入?yún)?shù),類型為26-oid,數(shù)據(jù)類型為int4,varchar,varchar)

(gdb) n
128   if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
(gdb) p parameterCount
$1 = 3
(gdb) p *parameterTypes
$2 = {vl_len_ = 144, ndim = 1, dataoffset = 0, elemtype = 26, dim1 = 3, lbound1 = 0, 
  values = 0x119a3e8}
(gdb) 
(gdb) p *parameterTypes->values
$3 = 23
(gdb) p parameterTypes->values[1]
$4 = 1043
(gdb) p parameterTypes->values[2]
$5 = 1043
(gdb) 
###
[local:/data/run/pg12]:5120 pg12@testdb=# select oid,typname from pg_type where oid=26;
 oid | typname 
-----+---------
  26 | oid
(1 row)
[local:/data/run/pg12]:5120 pg12@testdb=# select oid,typname from pg_type where oid in (23,1043);
 oid  | typname 
------+---------
   23 | int4
 1043 | varchar
(2 rows)

重構(gòu)數(shù)組輸入:所有參數(shù)類型

(gdb) n
138   if (allParameterTypes != PointerGetDatum(NULL))
(gdb) 
145     ArrayType  *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes);
(gdb) 
147     allParamCount = ARR_DIMS(allParamArray)[0];
(gdb) 
148     if (ARR_NDIM(allParamArray) != 1 ||
(gdb) 
150       ARR_HASNULL(allParamArray) ||
(gdb) 
149       allParamCount <= 0 ||
(gdb) 
151       ARR_ELEMTYPE(allParamArray) != OIDOID)
(gdb) 
150       ARR_HASNULL(allParamArray) ||
(gdb) 
153     allParams = (Oid *) ARR_DATA_PTR(allParamArray);
(gdb) 
154     Assert(allParamCount >= parameterCount);
(gdb) p *allParamArray
$6 = {vl_len_ = 176, ndim = 1, dataoffset = 0, elemtype = 26}
(gdb) p allParamArray[1]
$7 = {vl_len_ = 5, ndim = 1, dataoffset = 23, elemtype = 1043}
(gdb) p allParamCount
$8 = 5
(gdb) p *ARR_DIMS(allParamArray)
$9 = 5
(gdb) p allParamArray[2]
$10 = {vl_len_ = 1043, ndim = 23, dataoffset = 1043, elemtype = 2139062142}
(gdb) p allParamArray[3]
$11 = {vl_len_ = 2139062143, ndim = 2139062143, dataoffset = 2139062143, 
  elemtype = 2139062143}
(gdb) n
163   if (parameterModes != PointerGetDatum(NULL))
(gdb)

處理參數(shù)模式:參數(shù)模式(輸入/輸出等),分別是i,i,b,o,o

(gdb) n
170     ArrayType  *modesArray = (ArrayType *) DatumGetPointer(parameterModes);
(gdb) 
172     if (ARR_NDIM(modesArray) != 1 ||
(gdb) 
173       ARR_DIMS(modesArray)[0] != allParamCount ||
(gdb) 
172     if (ARR_NDIM(modesArray) != 1 ||
(gdb) 
174       ARR_HASNULL(modesArray) ||
(gdb) 
173       ARR_DIMS(modesArray)[0] != allParamCount ||
(gdb) 
175       ARR_ELEMTYPE(modesArray) != CHAROID)
(gdb) 
174       ARR_HASNULL(modesArray) ||
(gdb) 
177     paramModes = (char *) ARR_DATA_PTR(modesArray);
(gdb) 
184   for (i = 0; i < parameterCount; i++)
(gdb) p paramModes[0]
$12 = 105 'i'
(gdb) p paramModes[1]
$13 = 105 'i'
(gdb) p paramModes[2]
$14 = 98 'b'
(gdb) p paramModes[3]
$15 = 111 'o'
(gdb) p paramModes[4]
$16 = 111 'o'
(gdb)

檢查是否存在多態(tài)或者INTERNAL參數(shù).
兩趟循環(huán):第一趟檢查輸入?yún)?shù),第二趟檢查輸出參數(shù)

(gdb) n
186     switch (parameterTypes->values[i])
(gdb) 
184   for (i = 0; i < parameterCount; i++)
(gdb) 
186     switch (parameterTypes->values[i])
(gdb) 
184   for (i = 0; i < parameterCount; i++)
(gdb) 
186     switch (parameterTypes->values[i])
(gdb) 
184   for (i = 0; i < parameterCount; i++)
(gdb) 
204   if (allParameterTypes != PointerGetDatum(NULL))
(gdb) 
206     for (i = 0; i < allParamCount; i++)
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
209         paramModes[i] == PROARGMODE_IN ||
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
211         continue;   /* ignore input-only params */
(gdb) 
206     for (i = 0; i < allParamCount; i++)
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
209         paramModes[i] == PROARGMODE_IN ||
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
211         continue;   /* ignore input-only params */
(gdb) 
206     for (i = 0; i < allParamCount; i++)
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
209         paramModes[i] == PROARGMODE_IN ||
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
210         paramModes[i] == PROARGMODE_VARIADIC)
(gdb) 
209         paramModes[i] == PROARGMODE_IN ||
(gdb) 
213       switch (allParams[i])
(gdb) 
206     for (i = 0; i < allParamCount; i++)
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
209         paramModes[i] == PROARGMODE_IN ||
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
210         paramModes[i] == PROARGMODE_VARIADIC)
(gdb) 
209         paramModes[i] == PROARGMODE_IN ||
(gdb) 
213       switch (allParams[i])
(gdb) 
206     for (i = 0; i < allParamCount; i++)
(gdb) 
208       if (paramModes == NULL ||
(gdb) p allParamCount
$17 = 5
(gdb) n
209         paramModes[i] == PROARGMODE_IN ||
(gdb) 
208       if (paramModes == NULL ||
(gdb) 
210         paramModes[i] == PROARGMODE_VARIADIC)
(gdb) 
209         paramModes[i] == PROARGMODE_IN ||
(gdb) 
213       switch (allParams[i])
(gdb) 
206     for (i = 0; i < allParamCount; i++)
(gdb) 
239   if ((IsPolymorphicType(returnType) || genericOutParam)
(gdb)

至少存在一個多態(tài)輸入?yún)?shù)的情況下才允許返回多態(tài)類型.
ANYRANGE返回類型更為嚴(yán)格:必須含有一個ANYRANGE輸入(因?yàn)闊o法從ANYELEMENT中規(guī)約特殊的范圍類型.)
同時,除非至少有一個INTERNAL輸入?yún)?shù)類型,否則不允許返回INTERNAL類型.

(gdb) n
246   if ((returnType == ANYRANGEOID || anyrangeOutParam) &&
(gdb) 
253   if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
(gdb) 
259   if (paramModes != NULL)
(gdb)

只有最后一個輸入?yún)?shù)可以是variadic.如是,則存儲元素類型.

266     for (i = 0; i < allParamCount; i++)
(gdb) n
268       switch (paramModes[i])
(gdb) 
272           if (OidIsValid(variadicType))
(gdb) 
274           break;
(gdb) 
266     for (i = 0; i < allParamCount; i++)
(gdb) 
268       switch (paramModes[i])
(gdb) 
272           if (OidIsValid(variadicType))
(gdb) 
274           break;
(gdb) 
266     for (i = 0; i < allParamCount; i++)
(gdb) 
268       switch (paramModes[i])
(gdb) 
272           if (OidIsValid(variadicType))
(gdb) 
274           break;
(gdb) 
266     for (i = 0; i < allParamCount; i++)
(gdb) 
268       switch (paramModes[i])
(gdb) 
278           break;
(gdb) 
266     for (i = 0; i < allParamCount; i++)
(gdb) 
268       switch (paramModes[i])
(gdb) 
278           break;
(gdb) 
266     for (i = 0; i < allParamCount; i++)
(gdb) 
308   for (i = 0; i < Natts_pg_proc; ++i)
(gdb)

檢查完畢,寫入到pg_proc中,初始化values

308   for (i = 0; i < Natts_pg_proc; ++i)
(gdb) 
310     nulls[i] = false;
(gdb) 
311     values[i] = (Datum) 0;
(gdb) 
312     replaces[i] = true;
(gdb) 
...

賦值

308   for (i = 0; i < Natts_pg_proc; ++i)
(gdb) 
315   namestrcpy(&procname, procedureName);
(gdb) 
316   values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname);
(gdb) p procedureName
$20 = 0x1173ab0 "func_test"
(gdb) n
317   values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
(gdb) 
318   values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner);
(gdb) 
319   values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
(gdb) 
320   values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
(gdb) 
321   values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
(gdb) 
322   values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
(gdb) 
323   values[Anum_pg_proc_prosupport - 1] = ObjectIdGetDatum(prosupport);
(gdb) 
324   values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind);
(gdb) 
325   values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
(gdb) 
326   values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
(gdb) 
327   values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
(gdb) 
328   values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
(gdb) 
329   values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
(gdb) 
330   values[Anum_pg_proc_proparallel - 1] = CharGetDatum(parallel);
(gdb) 
331   values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount);
(gdb) 
332   values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults));
(gdb) 
333   values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
(gdb) 
334   values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
(gdb) 
335   if (allParameterTypes != PointerGetDatum(NULL))
(gdb) 
336     values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes;
(gdb) 
339   if (parameterModes != PointerGetDatum(NULL))
(gdb) 
340     values[Anum_pg_proc_proargmodes - 1] = parameterModes;
(gdb) 
343   if (parameterNames != PointerGetDatum(NULL))
(gdb) 
344     values[Anum_pg_proc_proargnames - 1] = parameterNames;
(gdb) 
347   if (parameterDefaults != NIL)
(gdb) 
350     nulls[Anum_pg_proc_proargdefaults - 1] = true;
(gdb) 
351   if (trftypes != PointerGetDatum(NULL))
(gdb) 
354     nulls[Anum_pg_proc_protrftypes - 1] = true;
(gdb) 
355   values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
(gdb) 
356   if (probin)
(gdb) 
359     nulls[Anum_pg_proc_probin - 1] = true;
(gdb) 
360   if (proconfig != PointerGetDatum(NULL))
(gdb) 
363     nulls[Anum_pg_proc_proconfig - 1] = true;
(gdb) 
366   rel = table_open(ProcedureRelationId, RowExclusiveLock);
(gdb) 
367   tupDesc = RelationGetDescr(rel);
(gdb)

判斷是否已存在

(gdb) p values[28]
$21 = 0
(gdb) p values[0]
$22 = 0
(gdb) p values[2]
$23 = 2200
(gdb) n
370   oldtup = SearchSysCache3(PROCNAMEARGSNSP,
(gdb) p *tupDesc
$24 = {natts = 29, tdtypeid = 81, tdtypmod = -1, tdrefcount = 1, constr = 0x7fbeb44493b8, 
  attrs = 0x7fbeb44483b8}
(gdb) n
375   if (HeapTupleIsValid(oldtup))
(gdb) 
378     Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
(gdb) 
383     if (!replace)
(gdb) p oldproc
$25 = (Form_pg_proc) 0x7fbeb4388bf8
(gdb) p *oldproc
$26 = {oid = 16387, proname = {data = "func_test", '\000' <repeats 54 times>}, 
  pronamespace = 2200, proowner = 10, prolang = 13581, procost = 100, prorows = 0, 
  provariadic = 0, prosupport = 0, prokind = 102 'f', prosecdef = false, 
  proleakproof = false, proisstrict = false, proretset = false, provolatile = 118 'v', 
  proparallel = 117 'u', pronargs = 3, pronargdefaults = 0, prorettype = 2249, proargtypes = {
    vl_len_ = 144, ndim = 1, dataoffset = 0, elemtype = 26, dim1 = 3, lbound1 = 0, 
    values = 0x7fbeb4388c80}}
(gdb)

執(zhí)行相關(guān)判斷:如返回類型,參數(shù)類型,參數(shù)個數(shù)等

(gdb) n
388     if (!pg_proc_ownercheck(oldproc->oid, proowner))
(gdb) 
393     if (oldproc->prokind != prokind)
(gdb) 
407     dropcmd = (prokind == PROKIND_PROCEDURE ? "DROP PROCEDURE" :
(gdb) 
419     if (returnType != oldproc->prorettype ||
(gdb) 
420       returnsSet != oldproc->proretset)
(gdb) 
419     if (returnType != oldproc->prorettype ||
(gdb) 
439     if (returnType == RECORDOID)
(gdb) 
444       olddesc = build_function_result_tupdesc_t(oldtup);
(gdb) 
445       newdesc = build_function_result_tupdesc_d(prokind,
(gdb) 
449       if (olddesc == NULL && newdesc == NULL)
(gdb) 
451       else if (olddesc == NULL || newdesc == NULL ||
(gdb) 
452            !equalTupleDescs(olddesc, newdesc))
(gdb) 
451       else if (olddesc == NULL || newdesc == NULL ||
(gdb) 
468     proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
(gdb) 
471     if (!isnull)
(gdb) 
480       proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
(gdb) 
483       if (isnull)
(gdb) 
486       n_old_arg_names = get_func_input_arg_names(proargnames,
(gdb) 
489       n_new_arg_names = get_func_input_arg_names(parameterNames,
(gdb) 
492       for (j = 0; j < n_old_arg_names; j++)
(gdb) 
494         if (old_arg_names[j] == NULL)
(gdb) 
496         if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
(gdb) 
497           strcmp(old_arg_names[j], new_arg_names[j]) != 0)
(gdb) 
496         if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
(gdb) 
492       for (j = 0; j < n_old_arg_names; j++)
(gdb) 
494         if (old_arg_names[j] == NULL)
(gdb) 
496         if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
(gdb) 
497           strcmp(old_arg_names[j], new_arg_names[j]) != 0)
(gdb) 
496         if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
(gdb) 
492       for (j = 0; j < n_old_arg_names; j++)
(gdb) 
494         if (old_arg_names[j] == NULL)
(gdb) 
496         if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
(gdb) 
497           strcmp(old_arg_names[j], new_arg_names[j]) != 0)
(gdb) 
496         if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
(gdb) 
492       for (j = 0; j < n_old_arg_names; j++)
(gdb) 
517     if (oldproc->pronargdefaults != 0)
(gdb) 
568     replaces[Anum_pg_proc_oid - 1] = false;
(gdb) 
569     replaces[Anum_pg_proc_proowner - 1] = false;
(gdb) 
570     replaces[Anum_pg_proc_proacl - 1] = false;
(gdb) 
573     tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
(gdb) 
574     CatalogTupleUpdate(rel, &tup->t_self, tup);
(gdb

更新tuple

(gdb) n
576     ReleaseSysCache(oldtup);
(gdb) 
577     is_update = true;
(gdb) 
601   retval = ((Form_pg_proc) GETSTRUCT(tup))->oid;
(gdb)

處理函數(shù)依賴

(gdb) p retval
$27 = 16387
(gdb) n
610     deleteDependencyRecordsFor(ProcedureRelationId, retval, true);
(gdb) 
612   myself.classId = ProcedureRelationId;
(gdb) 
613   myself.objectId = retval;
(gdb) 
614   myself.objectSubId = 0;
(gdb) 
617   referenced.classId = NamespaceRelationId;
(gdb) 
618   referenced.objectId = procNamespace;
(gdb) 
619   referenced.objectSubId = 0;
(gdb) 
620   recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
(gdb) 
623   referenced.classId = LanguageRelationId;
(gdb) 
624   referenced.objectId = languageObjectId;
(gdb) 
625   referenced.objectSubId = 0;
(gdb) 
626   recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
(gdb) 
629   referenced.classId = TypeRelationId;
(gdb) 
630   referenced.objectId = returnType;
(gdb) 
631   referenced.objectSubId = 0;
(gdb) 
632   recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
(gdb) 
635   if ((trfid = get_transform_oid(returnType, languageObjectId, true)))
(gdb) 
644   for (i = 0; i < allParamCount; i++)
(gdb) 
646     referenced.classId = TypeRelationId;
(gdb) 
647     referenced.objectId = allParams[i];
(gdb) 
648     referenced.objectSubId = 0;
(gdb) 
649     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
(gdb) 
652     if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
(gdb) 
644   for (i = 0; i < allParamCount; i++)
(gdb) 
646     referenced.classId = TypeRelationId;
(gdb) 
647     referenced.objectId = allParams[i];
(gdb) 
648     referenced.objectSubId = 0;
(gdb) 
649     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
(gdb) 
652     if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
(gdb) 
644   for (i = 0; i < allParamCount; i++)
(gdb) 
646     referenced.classId = TypeRelationId;
(gdb) 
647     referenced.objectId = allParams[i];
(gdb) 
648     referenced.objectSubId = 0;
(gdb) 
649     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
(gdb) 
652     if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
(gdb) 
644   for (i = 0; i < allParamCount; i++)
(gdb) 
646     referenced.classId = TypeRelationId;
(gdb) 
647     referenced.objectId = allParams[i];
(gdb) 
648     referenced.objectSubId = 0;
(gdb) 
649     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
(gdb) 
652     if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
(gdb) 
644   for (i = 0; i < allParamCount; i++)
(gdb) 
646     referenced.classId = TypeRelationId;
(gdb) 
647     referenced.objectId = allParams[i];
(gdb) 
648     referenced.objectSubId = 0;
(gdb) 
649     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
(gdb) 
652     if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
(gdb) 
644   for (i = 0; i < allParamCount; i++)
(gdb) 
662   if (parameterDefaults)
(gdb) 
667   if (OidIsValid(prosupport))
(gdb) 
676   if (!is_update)
(gdb) 
680   if (!is_update)
(gdb) 
685   recordDependencyOnCurrentExtension(&myself, is_update);
(gdb) 
687   heap_freetuple(tup);
(gdb) 
690   InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
(gdb) 
692   table_close(rel, RowExclusiveLock);
(gdb)

執(zhí)行函數(shù)body驗(yàn)證

695   if (OidIsValid(languageValidator))
(gdb) 
697     ArrayType  *set_items = NULL;
(gdb) 
698     int     save_nestlevel = 0;
(gdb) 
701     CommandCounterIncrement();
(gdb) 
713     if (check_function_bodies)
(gdb) 
(gdb) n
715       set_items = (ArrayType *) DatumGetPointer(proconfig);
(gdb) 
716       if (set_items)    /* Need a new GUC nesting level */
(gdb) 
726     OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
(gdb) 
728     if (set_items)
(gdb) 
732   return myself;
(gdb) 
733 }
(gdb)

完成調(diào)用

(gdb) 
733 }
(gdb) 
CreateFunction (pstate=0x1199c88, stmt=0x11748c8) at functioncmds.c:1176
1176  }
(gdb)

“分析PostgreSQL CreateFunction中的ProcedureCreate函數(shù)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI