返回顶部
首页 > 资讯 > 数据库 >分析PostgreSQL CreateFunction中的ProcedureCreate函数
  • 385
分享到

分析PostgreSQL CreateFunction中的ProcedureCreate函数

2024-04-02 19:04:59 385人浏览 泡泡鱼
摘要

本篇内容介绍了“分析postgresql CreateFunction中的ProcedureCreate函数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何

本篇内容介绍了“分析postgresql CreateFunction中的ProcedureCreate函数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、数据结构

Form_pg_language
plpgsql语言定义结构体


CATALOG(pg_language,2612,LanguageRelationId)
{
    Oid         oid;            
    
    NameData    lanname;
    
    Oid         lanowner BKI_DEFAULT(PGUID);
    
    bool        lanispl BKI_DEFAULT(f);
    
    bool        lanpltrusted BKI_DEFAULT(f);
    
    Oid         lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
    
    Oid         laninline BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
    
    Oid         lanvalidator BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
#ifdef CATALOG_VARLEN           
    
    aclitem     lanacl[1] BKI_DEFAULT(_null_);
#endif
} FORMData_pg_language;

typedef FormData_pg_language *Form_pg_language;

ArrayType


typedef struct
{
    //可变的header
    int32       vl_len_;        
    //维度
    int         ndim;           
    //指向数据的偏移量,如为0则表示没有位图
    int32       dataoffset;     
    //元素类型的OID
    Oid         elemtype;       
} ArrayType;

DefElem

typedef struct DefElem
{
  nodeTag   type;
  char     *defnamespace; 
  char     *defname;
  Node     *arg;      
  DefEleMaction defaction;  
  int     location;   
} DefElem;

FunctionParameter

typedef enum FunctionParameterMode
{
  
  FUNC_PARAM_IN = 'i',    
  FUNC_PARAM_OUT = 'o',   
  FUNC_PARAM_INOUT = 'b',   
  FUNC_PARAM_VARIADIC = 'v',  
  FUNC_PARAM_TABLE = 't'    
} FunctionParameterMode;
typedef struct FunctionParameter
{
  NodeTag   type;
  char     *name;     
  TypeName   *argType;    
  FunctionParameterMode mode; 
  Node     *defexpr;    
} FunctionParameter;

二、源码解读


ObjectAddress
ProcedureCreate(const char *procedureName,
        Oid procNamespace,
        bool replace,
        bool returnsSet,
        Oid returnType,
        Oid proowner,
        Oid languageObjectId,
        Oid languageValidator,
        const char *prosrc,
        const char *probin,
        char prokind,
        bool security_definer,
        bool isLeakProof,
        bool isStrict,
        char volatility,
        char parallel,
        oidvector *parameterTypes,
        Datum allParameterTypes,
        Datum parameterModes,
        Datum parameterNames,
        List *parameterDefaults,
        Datum trftypes,
        Datum proconfig,
        Oid prosupport,
        float4 procost,
        float4 prorows)
{
  Oid     retval;//返回值类型
  int     parameterCount;//输入参数
  int     allParamCount;//所有参数,如无输出参数,则为0
  Oid      *allParams;//所有参数类型,如无输出参数,则为NULL
  char     *paramModes = NULL;//参数类型
  bool    genericInParam = false;
  bool    genericOutParam = false;
  bool    anyrangeInParam = false;
  bool    anyrangeOutParam = false;
  bool    internalInParam = false;
  bool    internalOutParam = false;
  Oid     variadicType = InvalidOid;
  Acl      *proacl = NULL;//ACL结构体
  Relation  rel;//关系
  HeapTuple tup;//tuple
  HeapTuple oldtup;//原pg_proc tuple
  bool    nulls[Natts_pg_proc];//是否为null
  Datum   values[Natts_pg_proc];//值
  bool    replaces[Natts_pg_proc];//是否替换
  NameData  procname;//名称
  TupleDesc tupDesc;//tuple描述符
  bool    is_update;//是否替换?
  ObjectAddress myself,
        referenced;
  int     i;//临时变量
  Oid     trfid;
  
  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)));
  
  
  //重构数组输入:所有参数类型
  if (allParameterTypes != PointerGetDatum(NULL))
  {
    
    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);
    
  }
  else
  {
    //均为输入参数,无输出参数
    allParamCount = parameterCount;
    allParams = parameterTypes->values;
  }
  if (parameterModes != PointerGetDatum(NULL))
  {
    //参数模式(输入/输出等)
    
    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);
  }
  
  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;   
      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;
      }
    }
  }
  
  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)
  {
    
    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:
          
          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;
      }
    }
  }
  
  //#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;
  
  rel = table_open(ProcedureRelationId, RowExclusiveLock);
  tupDesc = RelationGetDescr(rel);
  
  //检查是否已存在
  oldtup = SearchSysCache3(PROCNAMEARGSNSP,
               PointerGetDatum(procedureName),
               PointerGetDatum(parameterTypes),
               ObjectIdGetDatum(procNamespace));
  if (HeapTupleIsValid(oldtup))
  {
    //-------- 已存在
    
    //获取原记录(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);
    
    //不能改变类型(如原来是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");
    
    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"),
      
           errhint("Use %s %s first.",
               dropcmd,
               format_procedure(oldproc->oid))));
    
    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)
          ;
      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."),
        
             errhint("Use %s %s first.",
                 dropcmd,
                 format_procedure(oldproc->oid))));
    }
    
    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);  
      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]),
          
               errhint("Use %s %s first.",
                   dropcmd,
                   format_procedure(oldproc->oid))));
      }
    }
    
    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"),
        
             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);
      
      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"),
          
               errhint("Use %s %s first.",
                   dropcmd,
                   format_procedure(oldproc->oid))));
        newlc = lnext(newlc);
      }
    }
    
    replaces[Anum_pg_proc_oid - 1] = false;
    replaces[Anum_pg_proc_proowner - 1] = false;
    replaces[Anum_pg_proc_proacl - 1] = false;
    
    tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
    CatalogTupleUpdate(rel, &tup->t_self, tup);
    ReleaseSysCache(oldtup);
    is_update = true;
  }
  else
  {
    //-------------- 不存在
    
    //创建新的过程
    Oid     newOid;
    
    //首先:获取默认的权限并设置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;
  
  if (is_update)
    //删除依赖
    deleteDependencyRecordsFor(ProcedureRelationId, retval, true);
  myself.classId = ProcedureRelationId;
  myself.objectId = retval;
  myself.objectSubId = 0;
  
  //依赖:namespace
  referenced.classId = NamespaceRelationId;
  referenced.objectId = procNamespace;
  referenced.objectSubId = 0;
  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  
  //依赖:语言
  referenced.classId = LanguageRelationId;
  referenced.objectId = languageObjectId;
  referenced.objectSubId = 0;
  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  
  //依赖:返回类型
  referenced.classId = TypeRelationId;
  referenced.objectId = returnType;
  referenced.objectSubId = 0;
  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  
  //依赖:返回类型的转换规则
  if ((trfid = get_transform_oid(returnType, languageObjectId, true)))
  {
    referenced.classId = TransformRelationId;
    referenced.objectId = trfid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  }
  
  //依赖:参数类型
  for (i = 0; i < allParamCount; i++)
  {
    referenced.classId = TypeRelationId;
    referenced.objectId = allParams[i];
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    
    if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
    {
      referenced.classId = TransformRelationId;
      referenced.objectId = trfid;
      referenced.objectSubId = 0;
      recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }
  }
  
  //依赖:默认表达式
  if (parameterDefaults)
    recordDependencyOnExpr(&myself, (Node *) parameterDefaults,
                 NIL, DEPENDENCY_NORMAL);
  
  //依赖:支持的函数
  if (OidIsValid(prosupport))
  {
    referenced.classId = ProcedureRelationId;
    referenced.objectId = prosupport;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  }
  
  //依赖:owner
  if (!is_update)
    recordDependencyOnOwner(ProcedureRelationId, retval, proowner);
  
  //依赖:ACL中标明的角色
  if (!is_update)
    recordDependencyOnNewAcl(ProcedureRelationId, retval, 0,
                 proowner, proacl);
  
  //依赖:扩展
  recordDependencyOnCurrentExtension(&myself, is_update);
  heap_freetuple(tup);
  
  //调用对象创建后的钩子函数
  InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
  //关闭pg_proc
  table_close(rel, RowExclusiveLock);
  
  //验证函数body
  if (OidIsValid(languageValidator))
  {
    ArrayType  *set_items = NULL;
    int     save_nestlevel = 0;
    
    //增加命令计数
    CommandCounterIncrement();
    
    if (check_function_bodies)
    {
      //检查函数体
      //获取函数设定的参数
      set_items = (ArrayType *) DatumGetPointer(proconfig);
      if (set_items)    
      {
        save_nestlevel = NewGUCNestLevel();
        ProcessGUCArray(set_items,
                (superuser() ? PGC_SUSET : PGC_USERSET),
                PGC_S_SESSION,
                GUC_ACTION_SAVE);
      }
    }
    //调用语言校验器
    OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
    if (set_items)
      AtEOXact_GUC(true, save_nestlevel);
  }
  return myself;
}

三、跟踪分析

测试脚本

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

启动GDB跟踪

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

输入参数

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

初始化本地临时变量

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

获取参数个数(3个输入参数,类型为26-oid,数据类型为int4,varchar,varchar)

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

重构数组输入:所有参数类型

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

处理参数模式:参数模式(输入/输出等),分别是i,i,b,o,o

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

检查是否存在多态或者INTERNAL参数.
两趟循环:第一趟检查输入参数,第二趟检查输出参数

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

至少存在一个多态输入参数的情况下才允许返回多态类型.
ANYRANGE返回类型更为严格:必须含有一个ANYRANGE输入(因为无法从ANYELEMENT中规约特殊的范围类型.)
同时,除非至少有一个INTERNAL输入参数类型,否则不允许返回INTERNAL类型.

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

只有最后一个输入参数可以是variadic.如是,则存储元素类型.

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

检查完毕,写入到pg_proc中,初始化values

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

赋值

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

判断是否已存在

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

执行相关判断:如返回类型,参数类型,参数个数等

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

更新tuple

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

处理函数依赖

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

执行函数body验证

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

完成调用

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

“分析PostgreSQL CreateFunction中的ProcedureCreate函数”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

您可能感兴趣的文档:

--结束END--

本文标题: 分析PostgreSQL CreateFunction中的ProcedureCreate函数

本文链接: https://lsjlt.com/news/63030.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 分析PostgreSQL CreateFunction中的ProcedureCreate函数
    本篇内容介绍了“分析PostgreSQL CreateFunction中的ProcedureCreate函数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何...
    99+
    2024-04-02
  • 分析PostgreSQL的CreateFunction函数
    本篇内容主要讲解“分析PostgreSQL的CreateFunction函数”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析PostgreSQL的CreateFunction函数”吧!一、数据...
    99+
    2023-05-31
  • 分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数
    这篇文章主要介绍“分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数”,在日常操作中,相信很多人在分析PostgreSQL Cr...
    99+
    2024-04-02
  • PostgreSQL中的ProcessRepliesIfAny函数分析
    本篇内容主要讲解“PostgreSQL中的ProcessRepliesIfAny函数分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中的P...
    99+
    2024-04-02
  • PostgreSQL中hash_inner_and_outer函数分析
    这篇文章主要讲解了“PostgreSQL中hash_inner_and_outer函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL...
    99+
    2024-04-02
  • PostgreSQL中sort_inner_and_outer函数分析
    这篇文章主要讲解了“PostgreSQL中sort_inner_and_outer函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL...
    99+
    2024-04-02
  • PostgreSQL中match_unsorted_outer函数分析
    这篇文章主要讲解了“PostgreSQL中match_unsorted_outer函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL...
    99+
    2024-04-02
  • PostgreSQL中make_rel_from_joinlist函数分析
    这篇文章主要介绍“PostgreSQL中make_rel_from_joinlist函数分析”,在日常操作中,相信很多人在PostgreSQL中make_rel_from_joinlist函数分析问题上存在...
    99+
    2024-04-02
  • PostgreSQL的set_base_rel_sizes函数分析
    这篇文章主要讲解了“PostgreSQL的set_base_rel_sizes函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL的s...
    99+
    2024-04-02
  • PostgreSQL中heap_insert->XLogInsert函数分析
    本篇内容介绍了“PostgreSQL中heap_insert->XLogInsert函数分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情...
    99+
    2024-04-02
  • PostgreSQL的vacuum过程中heap_vacuum_rel函数分析
    这篇文章主要介绍“PostgreSQL的vacuum过程中heap_vacuum_rel函数分析”,在日常操作中,相信很多人在PostgreSQL的vacuum过程中heap_vacuum_rel函数分析问...
    99+
    2024-04-02
  • PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析
    本篇内容主要讲解“PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“P...
    99+
    2024-04-02
  • PostgreSQL的set_base_rel_pathlists函数及其子函数分析
    这篇文章主要讲解了“PostgreSQL的set_base_rel_pathlists函数及其子函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Pos...
    99+
    2024-04-02
  • PostgreSQL中query_planner函数的处理逻辑分析
    这篇文章主要介绍“PostgreSQL中query_planner函数的处理逻辑分析”,在日常操作中,相信很多人在PostgreSQL中query_planner函数的处理逻辑分析问题上存在疑惑,小编查阅了...
    99+
    2024-04-02
  • PostgreSQL中set_base_rel_sizes函数及其子函数案例分析
    本篇内容介绍了“PostgreSQL中set_base_rel_sizes函数及其子函数案例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况...
    99+
    2024-04-02
  • 分析PostgreSQL创建函数的过程
    本篇内容主要讲解“分析PostgreSQL创建函数的过程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析PostgreSQL创建函数的过程”吧!一、数据结构F...
    99+
    2024-04-02
  • 分析PostgreSQL中的synchronous_commit参数
    本篇内容主要讲解“分析PostgreSQL中的synchronous_commit参数”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析PostgreSQL中的...
    99+
    2024-04-02
  • PostgreSQL物理优化中的create_index_paths->generate_bitmap_or_paths函数分析
    这篇文章主要讲解了“PostgreSQL物理优化中的create_index_paths->generate_bitmap_or_paths函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大...
    99+
    2024-04-02
  • PostgreSQL物理优化中的create_index_paths->choose_bitmap_and函数分析
    这篇文章主要讲解了“PostgreSQL物理优化中的create_index_paths->choose_bitmap_and函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思...
    99+
    2024-04-02
  • PostgreSQL索引扫描成本估算中的函数分析
    这篇文章主要介绍“PostgreSQL索引扫描成本估算中的函数分析”,在日常操作中,相信很多人在PostgreSQL索引扫描成本估算中的函数分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作