文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数

2024-04-02 19:55

关注

这篇文章主要介绍“分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数”,在日常操作中,相信很多人在分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、数据结构

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;

二、源码解读


void
interpret_function_parameter_list(ParseState *pstate,//解析状态
                  List *parameters,//参数链表
                  Oid languageOid,//语言OID
                  ObjectType objtype,//对象类型
                  oidvector **parameterTypes,//参数类型oid vector
                  ArrayType **allParameterTypes,//所有的参数类型
                  ArrayType **parameterModes,//参数模式,i/o/b/v/t
                  ArrayType **parameterNames,//参数名称
                  List **parameterDefaults,//参数默认值链表
                  Oid *variadicArgType,//variadic参数类型OID
                  Oid *requiredResultType)//结果类型
{
  int     parameterCount = list_length(parameters);//参数个数
  Oid      *inTypes;
  int     inCount = 0;
  Datum    *allTypes;
  Datum    *paramModes;
  Datum    *paramNames;
  int     outCount = 0;
  int     varCount = 0;
  bool    have_names = false;
  bool    have_defaults = false;
  ListCell   *x;
  int     i;
  *variadicArgType = InvalidOid;  
  *requiredResultType = InvalidOid; 
  //输入参数类型
  inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
  //所有参数的类型
  allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
  //
  paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
  //参数名称
  paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
  *parameterDefaults = NIL;
  
  //扫描链表,提前数据到结果数组中
  i = 0;
  foreach(x, parameters)
  {
    //函数参数
    FunctionParameter *fp = (FunctionParameter *) lfirst(x);
    //类型名称
    TypeName   *t = fp->argType;
    //是否输入参数
    bool    isinput = false;
    Oid     toid;
    //pg_proc元组
    Type    typtup;
    //权限检查结果
    AclResult aclresult;
    //检索type tuple
    typtup = LookupTypeName(NULL, t, NULL, false);
    if (typtup)
    {
      //
      if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
      {
        
        if (languageOid == SQLlanguageId)
          ereport(ERROR,
              (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
               errmsg("SQL function cannot accept shell type %s",
                  TypeNameToString(t))));
        
        else if (objtype == OBJECT_AGGREGATE)
          ereport(ERROR,
              (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
               errmsg("aggregate cannot accept shell type %s",
                  TypeNameToString(t))));
        else
          ereport(NOTICE,
              (errcode(ERRCODE_WRONG_OBJECT_TYPE),
               errmsg("argument type %s is only a shell",
                  TypeNameToString(t))));
      }
      //type的OID
      toid = typeTypeId(typtup);
      //释放缓存
      ReleaseSysCache(typtup);
    }
    else
    {
      //该类型不存在
      ereport(ERROR,
          (errcode(ERRCODE_UNDEFINED_OBJECT),
           errmsg("type %s does not exist",
              TypeNameToString(t))));
      toid = InvalidOid;  
    }
    //权限检查
    aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
      aclcheck_error_type(aclresult, toid);
    if (t->setof)
    {
      //存在setof
      if (objtype == OBJECT_AGGREGATE)
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
             errmsg("aggregates cannot accept set arguments")));
      else if (objtype == OBJECT_PROCEDURE)
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
             errmsg("procedures cannot accept set arguments")));
      else
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
             errmsg("functions cannot accept set arguments")));
    }
    if (objtype == OBJECT_PROCEDURE)
    {
      //过程对象,不需要OUT参数,只允许inout参数
      if (fp->mode == FUNC_PARAM_OUT)
        ereport(ERROR,
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
             (errmsg("procedures cannot have OUT arguments"),
              errhint("INOUT arguments are permitted."))));
    }
    
    //处理输入参数
    if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
    {
      //非OUT参数并且不是TABLE参数
      
      if (varCount > 0)
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
             errmsg("VARIADIC parameter must be the last input parameter")));
      //写入到输入类型数组中
      inTypes[inCount++] = toid;
      isinput = true;
    }
    
    //处理输出参数
    if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
    {
      if (objtype == OBJECT_PROCEDURE)
        //存储过程:要求输出结果类型为RECORD
        *requiredResultType = RECORDOID;
      else if (outCount == 0) 
        //第一个OID
        *requiredResultType = toid;
      outCount++;
    }
    if (fp->mode == FUNC_PARAM_VARIADIC)
    {
      //variadic参数
      *variadicArgType = toid;
      varCount++;
      
      //验证variadic参数类型
      switch (toid)
      {
        case ANYARRAYOID:
        case ANYOID:
          
          break;
        default:
          if (!OidIsValid(get_element_type(toid)))
            ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                 errmsg("VARIADIC parameter must be an array")));
          break;
      }
    }
    //转换为Datum
    allTypes[i] = ObjectIdGetDatum(toid);
    //参数类型
    paramModes[i] = CharGetDatum(fp->mode);
    if (fp->name && fp->name[0])
    {
      //检查参数名称,参数名称不能重复
      ListCell   *px;
      
      foreach(px, parameters)
      {
        //循环判断参数是否重复
        FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
        if (prevfp == fp)
          break;
        
        //输入和输出不冲突
        if ((fp->mode == FUNC_PARAM_IN ||
           fp->mode == FUNC_PARAM_VARIADIC) &&
          (prevfp->mode == FUNC_PARAM_OUT ||
           prevfp->mode == FUNC_PARAM_TABLE))
          continue;
        if ((prevfp->mode == FUNC_PARAM_IN ||
           prevfp->mode == FUNC_PARAM_VARIADIC) &&
          (fp->mode == FUNC_PARAM_OUT ||
           fp->mode == FUNC_PARAM_TABLE))
          continue;
        if (prevfp->name && prevfp->name[0] &&
          strcmp(prevfp->name, fp->name) == 0)
          ereport(ERROR,
              (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
               errmsg("parameter name \"%s\" used more than once",
                  fp->name)));
      }
      //获取Datum
      paramNames[i] = CStringGetTextDatum(fp->name);
      have_names = true;
    }
    if (fp->defexpr)
    {
      Node     *def;
      if (!isinput)
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
             errmsg("only input parameters can have default values")));
      def = transformExpr(pstate, fp->defexpr,
                EXPR_KIND_FUNCTION_DEFAULT);
      def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
      assign_expr_collations(pstate, def);
      
      if (list_length(pstate->p_rtable) != 0 ||
        contain_var_clause(def))
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
             errmsg("cannot use table references in parameter default value")));
      
      *parameterDefaults = lappend(*parameterDefaults, def);
      have_defaults = true;
    }
    else
    {
      if (isinput && have_defaults)
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
             errmsg("input parameters after one with a default value must also have defaults")));
    }
    i++;
  }
  
  //如需要,构建合适的输出
  *parameterTypes = buildoidvector(inTypes, inCount);
  if (outCount > 0 || varCount > 0)
  {
    //输出参数
    *allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
                       sizeof(Oid), true, 'i');
    *parameterModes = construct_array(paramModes, parameterCount, CHAROID,
                      1, true, 'c');
    if (outCount > 1)
      *requiredResultType = RECORDOID;
    
  }
  else
  {
    *allParameterTypes = NULL;
    *parameterModes = NULL;
  }
  if (have_names)
  {
    //指定了参数名称
    for (i = 0; i < parameterCount; i++)
    {
      if (paramNames[i] == PointerGetDatum(NULL))
        paramNames[i] = CStringGetTextDatum("");
    }
    *parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
                      -1, false, 'i');
  }
  else
    *parameterNames = NULL;
}

三、跟踪分析

测试脚本

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) c
Continuing.
Breakpoint 1, interpret_function_parameter_list (pstate=0x10edc88, parameters=0x10c7d30, 
    languageOid=13581, objtype=OBJECT_FUNCTION, parameterTypes=0x7ffec5c6ea88, 
    allParameterTypes=0x7ffec5c6ea80, parameterModes=0x7ffec5c6ea78, 
    parameterNames=0x7ffec5c6ea70, parameterDefaults=0x7ffec5c6ea68, 
    variadicArgType=0x7ffec5c6ea64, requiredResultType=0x7ffec5c6ea60) at functioncmds.c:195
195   int     parameterCount = list_length(parameters);
(gdb)

输入参数,语言为pl/pgsql,对象类型是function,存在有5个参数

(gdb) p *pstate
$1 = {parentParseState = 0x0, 
  p_sourcetext = 0x10c6ed8 "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)\nreturns record \nas\n$$\ndeclare\nbegin\n  raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 :="..., p_rtable = 0x0, p_joinexprs = 0x0, 
  p_joinlist = 0x0, p_namespace = 0x0, p_lateral_active = false, p_ctenamespace = 0x0, 
  p_future_ctes = 0x0, p_parent_cte = 0x0, p_target_relation = 0x0, 
  p_target_rangetblentry = 0x0, p_is_insert = false, p_windowdefs = 0x0, 
  p_expr_kind = EXPR_KIND_NONE, p_next_resno = 1, p_multiassign_exprs = 0x0, 
  p_locking_clause = 0x0, p_locked_from_parent = false, p_resolve_unknowns = true, 
  p_queryEnv = 0x0, p_hasAggs = false, p_hasWindowFuncs = false, p_hasTargetSRFs = false, 
  p_hasSubLinks = false, p_hasModifyingCTE = false, p_last_srf = 0x0, 
  p_pre_columnref_hook = 0x0, p_post_columnref_hook = 0x0, p_paramref_hook = 0x0, 
  p_coerce_param_hook = 0x0, p_ref_hook_state = 0x0}
(gdb) 
(gdb) p *parameters
$2 = {type = T_List, length = 5, head = 0x10c7d08, tail = 0x10c8480}
(gdb)

初始化相关变量

(gdb) n
197   int     inCount = 0;
(gdb) 
201   int     outCount = 0;
(gdb) 
202   int     varCount = 0;
(gdb) 
203   bool    have_names = false;
(gdb) 
204   bool    have_defaults = false;
(gdb) 
208   *variadicArgType = InvalidOid;  
(gdb) 
209   *requiredResultType = InvalidOid; 
(gdb) 
211   inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
(gdb) 
212   allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
(gdb) 
213   paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
(gdb) 
214   paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
(gdb) 
215   *parameterDefaults = NIL;
(gdb) 
218   i = 0;
(gdb) 
219   foreach(x, parameters)
(gdb)

开始循环,第一个参数,名称为pi_v1,参数类型为pg_catalog.int4

(gdb) 
221     FunctionParameter *fp = (FunctionParameter *) lfirst(x);
(gdb) 
222     TypeName   *t = fp->argType;
(gdb) 
223     bool    isinput = false;
(gdb) p *fp
$4 = {type = T_FunctionParameter, name = 0x10c7b60 "pi_v1", argType = 0x10c7c58, 
  mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) p *fp->argType
$5 = {type = T_TypeName, names = 0x10c7bd0, typeOid = 0, setof = false, pct_type = false, 
  typmods = 0x0, typemod = -1, arrayBounds = 0x0, location = 46}
(gdb) p *fp->argType->names
$6 = {type = T_List, length = 2, head = 0x10c7c30, tail = 0x10c7ba8}
(gdb) p *(Node *)fp->argType->names->head->data.ptr_value
$7 = {type = T_String}
(gdb) p *(Value *)fp->argType->names->head->data.ptr_value
$8 = {type = T_String, val = {ival = 12340746, str = 0xbc4e0a "pg_catalog"}}
(gdb) p *(Value *)fp->argType->names->head->next->data.ptr_value
$9 = {type = T_String, val = {ival = 12320664, str = 0xbbff98 "int4"}}
(gdb) p *t
$10 = {type = T_TypeName, names = 0x10c7bd0, typeOid = 0, setof = false, pct_type = false, 
  typmods = 0x0, typemod = -1, arrayBounds = 0x0, location = 46}
(gdb)

获取pg_type中对应type的tuple

(gdb) n
228     typtup = LookupTypeName(NULL, t, NULL, false);
(gdb) 
229     if (typtup)
(gdb) p *typtup
$11 = {t_len = 176, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 8}, 
  t_tableOid = 1247, t_data = 0x7ff12a2c3c40}
(gdb) p *typtup->t_data
$12 = {t_choice = {t_heap = {t_xmin = 1, t_xmax = 0, t_field3 = {t_cid = 0, t_xvac = 0}}, 
    t_datum = {datum_len_ = 1, datum_typmod = 0, datum_typeid = 0}}, t_ctid = {ip_blkid = {
      bi_hi = 0, bi_lo = 0}, ip_posid = 8}, t_infomask2 = 31, t_infomask = 2305, 
  t_hoff = 32 ' ', t_bits = 0x7ff12a2c3c57 "\377\377\377\017"}
(gdb) x/16c typtup->t_data->t_bits
0x7ff12a2c3c57: -1 '\377' -1 '\377' -1 '\377' 15 '\017' 0 '\000'    0 '\000'  0 '\000'  0 '\000'
0x7ff12a2c3c5f: 0 '\000'  23 '\027' 0 '\000'  0 '\000'  0 '\000'    105 'i' 110 'n' 116 't'
(gdb) x/64c typtup->t_data->t_bits
0x7ff12a2c3c57: -1 '\377' -1 '\377' -1 '\377' 15 '\017' 0 '\000'    0 '\000'  0 '\000'  0 '\000'
0x7ff12a2c3c5f: 0 '\000'  23 '\027' 0 '\000'  0 '\000'  0 '\000'    105 'i' 110 'n' 116 't'
0x7ff12a2c3c67: 52 '4'  0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'
0x7ff12a2c3c6f: 0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'    0 '\000'  0 '\000'  0 '\000'
0x7ff12a2c3c77: 0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'    0 '\000'  0 '\000'  0 '\000'
0x7ff12a2c3c7f: 0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'    0 '\000'  0 '\000'  0 '\000'
0x7ff12a2c3c87: 0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'    0 '\000'  0 '\000'  0 '\000'
0x7ff12a2c3c8f: 0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'    0 '\000'  0 '\000'  0 '\000'
(gdb) 
(gdb) p *((Form_pg_type) GETSTRUCT(typtup))
$14 = {oid = 23, typname = {data = "int4", '\000' <repeats 59 times>}, typnamespace = 11, 
  typowner = 10, typlen = 4, typbyval = true, typtype = 98 'b', typcategory = 78 'N', 
  typispreferred = false, typisdefined = true, typdelim = 44 ',', typrelid = 0, 
  typelem = 0, typarray = 1007, typinput = 42, typoutput = 43, typreceive = 2406, 
  typsend = 2407, typmodin = 0, typmodout = 0, typanalyze = 0, typalign = 105 'i', 
  typstorage = 112 'p', typnotnull = false, typbasetype = 0, typtypmod = -1, typndims = 0, 
  typcollation = 0}
(gdb)

获取type的oid

(gdb) n
251       toid = typeTypeId(typtup);
(gdb) 
252       ReleaseSysCache(typtup);
(gdb) 
263     aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb) p toid
$15 = 23
(gdb)

检查权限

263     aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb) p toid
$15 = 23
(gdb) n
264     if (aclresult != ACLCHECK_OK)
(gdb) 
267     if (t->setof)
(gdb)

处理输入参数

(gdb) p t->setof
$16 = false
(gdb) n
283     if (objtype == OBJECT_PROCEDURE)
(gdb) 
293     if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
(gdb) 
296       if (varCount > 0)
(gdb) 
300       inTypes[inCount++] = toid;
(gdb) 
301       isinput = true;
(gdb) 
305     if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
(gdb) 
314     if (fp->mode == FUNC_PARAM_VARIADIC)
(gdb) 
(gdb) n
334     allTypes[i] = ObjectIdGetDatum(toid);
(gdb) 
336     paramModes[i] = CharGetDatum(fp->mode);
(gdb) 
338     if (fp->name && fp->name[0])
(gdb) p fp->mode
$17 = FUNC_PARAM_IN
(gdb) n
348       foreach(px, parameters)
(gdb)

判断是否重名

(gdb) n
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) 
353           break;
(gdb)

如无重名,设置相关变量,把fp->name的地址写入paramNames指针数组中

373       paramNames[i] = CStringGetTextDatum(fp->name);
(gdb) 
374       have_names = true;
(gdb) 
377     if (fp->defexpr)
(gdb) p paramNames[0]
$18 = 17751776

下一个参数

(gdb) n
420       if (isinput && have_defaults)
(gdb) 
426     i++;
(gdb) p *fp->defexpr
Cannot access memory at address 0x0
(gdb) n
219   foreach(x, parameters)
(gdb) 
221     FunctionParameter *fp = (FunctionParameter *) lfirst(x);
(gdb) 
222     TypeName   *t = fp->argType;
(gdb) 
223     bool    isinput = false;
(gdb) 
228     typtup = LookupTypeName(NULL, t, NULL, false);
(gdb) 
(gdb) n
229     if (typtup)
(gdb) 
231       if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
(gdb) 
251       toid = typeTypeId(typtup);
(gdb) 
252       ReleaseSysCache(typtup);
(gdb) p *((Form_pg_type) GETSTRUCT(typtup))
$22 = {oid = 1043, typname = {data = "varchar", '\000' <repeats 56 times>}, 
  typnamespace = 11, typowner = 10, typlen = -1, typbyval = false, typtype = 98 'b', 
  typcategory = 83 'S', typispreferred = false, typisdefined = true, typdelim = 44 ',', 
  typrelid = 0, typelem = 0, typarray = 1015, typinput = 1046, typoutput = 1047, 
  typreceive = 2432, typsend = 2433, typmodin = 2915, typmodout = 2916, typanalyze = 0, 
  typalign = 105 'i', typstorage = 120 'x', typnotnull = false, typbasetype = 0, 
  typtypmod = -1, typndims = 0, typcollation = 100}
(gdb) n
263     aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb) 
264     if (aclresult != ACLCHECK_OK)
(gdb) 
267     if (t->setof)
(gdb) 
283     if (objtype == OBJECT_PROCEDURE)
(gdb) 
293     if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
(gdb) 
296       if (varCount > 0)
(gdb) 
300       inTypes[inCount++] = toid;
(gdb) 
301       isinput = true;
(gdb) 
305     if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
(gdb) 
314     if (fp->mode == FUNC_PARAM_VARIADIC)
(gdb) 
334     allTypes[i] = ObjectIdGetDatum(toid);
(gdb) 
336     paramModes[i] = CharGetDatum(fp->mode);
(gdb)

判断参数是否重复

338     if (fp->name && fp->name[0])
(gdb) 
348       foreach(px, parameters)
(gdb) p fp->name
$23 = 0x10c7d68 "pi_v2"
(gdb) p fp->name[0]
$24 = 112 'p'
(gdb) n
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) p *prevfp
$25 = {type = T_FunctionParameter, name = 0x10c7b60 "pi_v1", argType = 0x10c7c58, 
  mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) n
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
357           (prevfp->mode == FUNC_PARAM_OUT ||
(gdb) 
356            fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
358            prevfp->mode == FUNC_PARAM_TABLE))
(gdb) 
357           (prevfp->mode == FUNC_PARAM_OUT ||
(gdb) 
360         if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb) 
362           (fp->mode == FUNC_PARAM_OUT ||
(gdb) 
361            prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
363            fp->mode == FUNC_PARAM_TABLE))
(gdb) 
362           (fp->mode == FUNC_PARAM_OUT ||
(gdb) 
365         if (prevfp->name && prevfp->name[0] &&
(gdb) 
366           strcmp(prevfp->name, fp->name) == 0)
(gdb) 
365         if (prevfp->name && prevfp->name[0] &&
(gdb) 
348       foreach(px, parameters)
(gdb) 
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) p *prevfp
$26 = {type = T_FunctionParameter, name = 0x10c7d68 "pi_v2", argType = 0x10c7e60, 
  mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) p *fp
$27 = {type = T_FunctionParameter, name = 0x10c7d68 "pi_v2", argType = 0x10c7e60, 
  mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) n
353           break;
(gdb) 
373       paramNames[i] = CStringGetTextDatum(fp->name);
(gdb) 
374       have_names = true;
(gdb) 
377     if (fp->defexpr)
(gdb) 
420       if (isinput && have_defaults)
(gdb) 
426     i++;
(gdb) 
219   foreach(x, parameters)

下一参数,这时候是一个INOUT参数(在IN和OUT数组中均记录)

(gdb) n
221     FunctionParameter *fp = (FunctionParameter *) lfirst(x);
(gdb) 
222     TypeName   *t = fp->argType;
(gdb) 
223     bool    isinput = false;
(gdb) 
228     typtup = LookupTypeName(NULL, t, NULL, false);
(gdb) 
229     if (typtup)
(gdb) 
231       if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
(gdb) 
251       toid = typeTypeId(typtup);
(gdb) p *((Form_pg_type) GETSTRUCT(typtup))
$28 = {oid = 1043, typname = {data = "varchar", '\000' <repeats 56 times>}, 
  typnamespace = 11, typowner = 10, typlen = -1, typbyval = false, typtype = 98 'b', 
  typcategory = 83 'S', typispreferred = false, typisdefined = true, typdelim = 44 ',', 
  typrelid = 0, typelem = 0, typarray = 1015, typinput = 1046, typoutput = 1047, 
  typreceive = 2432, typsend = 2433, typmodin = 2915, typmodout = 2916, typanalyze = 0, 
  typalign = 105 'i', typstorage = 120 'x', typnotnull = false, typbasetype = 0, 
  typtypmod = -1, typndims = 0, typcollation = 100}
(gdb) n
252       ReleaseSysCache(typtup);
(gdb) 
263     aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb) 
264     if (aclresult != ACLCHECK_OK)
(gdb) 
267     if (t->setof)
(gdb) 
283     if (objtype == OBJECT_PROCEDURE)
(gdb) 
293     if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
(gdb) 
296       if (varCount > 0)
(gdb) 
300       inTypes[inCount++] = toid;
(gdb) 
301       isinput = true;
(gdb) 
305     if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
(gdb) 
307       if (objtype == OBJECT_PROCEDURE)
(gdb) 
309       else if (outCount == 0) 
(gdb) 
310         *requiredResultType = toid;
(gdb) 
311       outCount++;
(gdb) 
314     if (fp->mode == FUNC_PARAM_VARIADIC)
(gdb) 
334     allTypes[i] = ObjectIdGetDatum(toid);
(gdb) 
336     paramModes[i] = CharGetDatum(fp->mode);
(gdb) 
338     if (fp->name && fp->name[0])
(gdb) 
348       foreach(px, parameters)
(gdb) 
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) p *prevfp
$29 = {type = T_FunctionParameter, name = 0x10c7b60 "pi_v1", argType = 0x10c7c58, 
  mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) n
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
356            fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) p *fp
$30 = {type = T_FunctionParameter, name = 0x10c7f38 "pio_v3", argType = 0x10c8030, 
  mode = FUNC_PARAM_INOUT, defexpr = 0x0}
(gdb) n
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
360         if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb) 
362           (fp->mode == FUNC_PARAM_OUT ||
(gdb) 
361            prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
363            fp->mode == FUNC_PARAM_TABLE))
(gdb) 
362           (fp->mode == FUNC_PARAM_OUT ||
(gdb) 
365         if (prevfp->name && prevfp->name[0] &&
(gdb) 
366           strcmp(prevfp->name, fp->name) == 0)
(gdb) 
365         if (prevfp->name && prevfp->name[0] &&
(gdb) 
348       foreach(px, parameters)
(gdb) 
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) 
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
356            fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
360         if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb) 
362           (fp->mode == FUNC_PARAM_OUT ||
(gdb) 
361            prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
363            fp->mode == FUNC_PARAM_TABLE))
(gdb) 
362           (fp->mode == FUNC_PARAM_OUT ||
(gdb) 
365         if (prevfp->name && prevfp->name[0] &&
(gdb) 
366           strcmp(prevfp->name, fp->name) == 0)
(gdb) 
365         if (prevfp->name && prevfp->name[0] &&
(gdb) 
348       foreach(px, parameters)
(gdb) 
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) 
353           break;
(gdb) 
373       paramNames[i] = CStringGetTextDatum(fp->name);
(gdb) 
374       have_names = true;
(gdb) 
377     if (fp->defexpr)
(gdb) 
420       if (isinput && have_defaults)
(gdb) 
426     i++;
(gdb) 
219   foreach(x, parameters)

下一个参数,OUT参数

(gdb) n
221     FunctionParameter *fp = (FunctionParameter *) lfirst(x);
(gdb) n
222     TypeName   *t = fp->argType;
(gdb) 
223     bool    isinput = false;
(gdb) 
228     typtup = LookupTypeName(NULL, t, NULL, false);
(gdb) 
229     if (typtup)
(gdb) 
231       if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
(gdb) 
251       toid = typeTypeId(typtup);
(gdb) p *((Form_pg_type) GETSTRUCT(typtup))
$31 = {oid = 23, typname = {data = "int4", '\000' <repeats 59 times>}, typnamespace = 11, 
  typowner = 10, typlen = 4, typbyval = true, typtype = 98 'b', typcategory = 78 'N', 
  typispreferred = false, typisdefined = true, typdelim = 44 ',', typrelid = 0, 
  typelem = 0, typarray = 1007, typinput = 42, typoutput = 43, typreceive = 2406, 
  typsend = 2407, typmodin = 0, typmodout = 0, typanalyze = 0, typalign = 105 'i', 
  typstorage = 112 'p', typnotnull = false, typbasetype = 0, typtypmod = -1, typndims = 0, 
  typcollation = 0}
(gdb) n
252       ReleaseSysCache(typtup);
(gdb) 
263     aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb) 
264     if (aclresult != ACLCHECK_OK)
(gdb) 
267     if (t->setof)
(gdb) 
283     if (objtype == OBJECT_PROCEDURE)
(gdb) 
293     if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
(gdb) 
305     if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
(gdb) 
307       if (objtype == OBJECT_PROCEDURE)
(gdb) 
309       else if (outCount == 0) 
(gdb) 
311       outCount++;
(gdb) 
314     if (fp->mode == FUNC_PARAM_VARIADIC)
(gdb) 
334     allTypes[i] = ObjectIdGetDatum(toid);
(gdb) 
336     paramModes[i] = CharGetDatum(fp->mode);
(gdb) 
338     if (fp->name && fp->name[0])
(gdb) 
348       foreach(px, parameters)
(gdb) 
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) 
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) p *prevfp
$32 = {type = T_FunctionParameter, name = 0x10c7b60 "pi_v1", argType = 0x10c7c58, 
  mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) p *fp
$33 = {type = T_FunctionParameter, name = 0x10c8108 "po_v4", argType = 0x10c8200, 
  mode = FUNC_PARAM_OUT, defexpr = 0x0}
(gdb) n
356            fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
360         if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb) 
362           (fp->mode == FUNC_PARAM_OUT ||
(gdb) 
361            prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
364           continue;
(gdb) n
348       foreach(px, parameters)
(gdb) 
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) 
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
356            fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
360         if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb) 
362           (fp->mode == FUNC_PARAM_OUT ||
(gdb) 
361            prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
364           continue;
(gdb) 
348       foreach(px, parameters)
(gdb) 
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) 
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
356            fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
355         if ((fp->mode == FUNC_PARAM_IN ||
(gdb) 
360         if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb) 
361            prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) 
360         if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb) 
365         if (prevfp->name && prevfp->name[0] &&
(gdb) 
366           strcmp(prevfp->name, fp->name) == 0)
(gdb) 
365         if (prevfp->name && prevfp->name[0] &&
(gdb) 
348       foreach(px, parameters)
(gdb) 
350         FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb) 
352         if (prevfp == fp)
(gdb) 
353           break;
(gdb) 
373       paramNames[i] = CStringGetTextDatum(fp->name);
(gdb) 
374       have_names = true;
(gdb) 
377     if (fp->defexpr)
(gdb) 
420       if (isinput && have_defaults)
(gdb) 
426     i++;
(gdb) 
219   foreach(x, parameters)

下一个参数

......

完成所有参数的解析

219   foreach(x, parameters)
(gdb) 
430   *parameterTypes = buildoidvector(inTypes, inCount);
(gdb) 
432   if (outCount > 0 || varCount > 0)
(gdb) 
434     *allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
(gdb) n
436     *parameterModes = construct_array(paramModes, parameterCount, CHAROID,
(gdb) 
438     if (outCount > 1)
(gdb) 
439       *requiredResultType = RECORDOID;
(gdb) p *allTypes
$34 = 23
(gdb) p allTypes[4]
$35 = 1043
(gdb) n
438     if (outCount > 1)
(gdb) 
448   if (have_names)
(gdb) 
450     for (i = 0; i < parameterCount; i++)
(gdb) 
452       if (paramNames[i] == PointerGetDatum(NULL))
(gdb) 
450     for (i = 0; i < parameterCount; i++)
(gdb) 
452       if (paramNames[i] == PointerGetDatum(NULL))
(gdb) 
450     for (i = 0; i < parameterCount; i++)
(gdb) 
452       if (paramNames[i] == PointerGetDatum(NULL))
(gdb) 
450     for (i = 0; i < parameterCount; i++)
(gdb) 
452       if (paramNames[i] == PointerGetDatum(NULL))
(gdb) 
450     for (i = 0; i < parameterCount; i++)
(gdb) 
452       if (paramNames[i] == PointerGetDatum(NULL))
(gdb) 
450     for (i = 0; i < parameterCount; i++)
(gdb) 
455     *parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
(gdb) 
460 }
(gdb) 
CreateFunction (pstate=0x10edc88, stmt=0x10c88c8) at functioncmds.c:1065
1065    if (stmt->is_procedure)
(gdb)

到此,关于“分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯