千家信息网

分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,这篇文章主要介绍"分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数",在日常操作中,相信很多人在分析PostgreSQL
千家信息网最后更新 2025年02月02日分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数

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

一、数据结构

Form_pg_language
plpgsql语言定义结构体

/* ---------------- *      pg_language definition.  cpp turns this into *      typedef struct FormData_pg_language * ---------------- */CATALOG(pg_language,2612,LanguageRelationId){    Oid         oid;            /* oid */    /* Language name */    NameData    lanname;    /* Language's owner */    Oid         lanowner BKI_DEFAULT(PGUID);    /* Is a procedural language */    bool        lanispl BKI_DEFAULT(f);    /* PL is trusted */    bool        lanpltrusted BKI_DEFAULT(f);    /* Call handler, if it's a PL */    Oid         lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);    /* Optional anonymous-block handler function */    Oid         laninline BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);    /* Optional validation function */    Oid         lanvalidator BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);#ifdef CATALOG_VARLEN           /* variable-length fields start here */    /* Access privileges */    aclitem     lanacl[1] BKI_DEFAULT(_null_);#endif} FormData_pg_language;/* ---------------- *      Form_pg_language corresponds to a pointer to a tuple with *      the format of pg_language relation. * ---------------- */typedef FormData_pg_language *Form_pg_language;

ArrayType

/* * Arrays are varlena objects, so must meet the varlena convention that * the first int32 of the object contains the total object size in bytes. * Be sure to use VARSIZE() and SET_VARSIZE() to access it, though! * Arrays是可变对象集,必须符合varlena约定,即对象的第一个int32包含对象的总大小(以字节为单位)。 * 但是,一定要确保使用VARSIZE和SET_VARSIZE函数范围该结构体 * * CAUTION: if you change the header for ordinary arrays you will also * need to change the headers for oidvector and int2vector! */typedef struct{    //可变的header    int32       vl_len_;        /* varlena header (do not touch directly!) */    //维度    int         ndim;           /* # of dimensions */    //指向数据的偏移量,如为0则表示没有位图    int32       dataoffset;     /* offset to data, or 0 if no bitmap */    //元素类型的OID    Oid         elemtype;       /* element type OID */} ArrayType;

DefElem

typedef struct DefElem{  NodeTag   type;  char     *defnamespace; /* NULL if unqualified name */  char     *defname;  Node     *arg;      /* a (Value *) or a (TypeName *) */  DefElemAction defaction;  /* unspecified action, or SET/ADD/DROP */  int     location;   /* token location, or -1 if unknown */} DefElem;

FunctionParameter

typedef enum FunctionParameterMode{  /* the assigned enum values appear in pg_proc, don't change 'em! */  FUNC_PARAM_IN = 'i',    /* input only */  FUNC_PARAM_OUT = 'o',   /* output only */  FUNC_PARAM_INOUT = 'b',   /* both */  FUNC_PARAM_VARIADIC = 'v',  /* variadic (always input) */  FUNC_PARAM_TABLE = 't'    /* table function output column */} FunctionParameterMode;typedef struct FunctionParameter{  NodeTag   type;  char     *name;     /* parameter name, or NULL if not given */  TypeName   *argType;    /* TypeName for parameter type */  FunctionParameterMode mode; /* IN/OUT/etc */  Node     *defexpr;    /* raw default expr, or NULL if not given */} FunctionParameter;

二、源码解读

/* * Interpret the function parameter list of a CREATE FUNCTION or * CREATE AGGREGATE statement. * 解析CREATE FUNCTON/CREATE AGGREGATE语句中的参数链表 * * Input parameters: * parameters: list of FunctionParameter structs * languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE) * objtype: needed only to determine error handling and required result type * 输入参数: * parameters:FunctionParameter结构体链表 * languageOid:语言ID * objtype:确定错误处理时需要,并且需要结果类型 * * Results are stored into output parameters.  parameterTypes must always * be created, but the other arrays are set to NULL if not needed. * variadicArgType is set to the variadic array type if there's a VARIADIC * parameter (there can be only one); or to InvalidOid if not. * requiredResultType is set to InvalidOid if there are no OUT parameters, * else it is set to the OID of the implied result type. * 结果存储在输出参数中.必须创建parameterTypes,如不需要其他数组将设置为NULL. * 如存在VARIADIC参数(有且仅有一个),variadicArgType将设置为variadic数组类型. * 如无OUT参数,则requiredResultType设置为InvalidOid,否则设置为结果类型. */voidinterpret_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;  /* default result */  *requiredResultType = InvalidOid; /* default result */  //输入参数类型  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;  /* Scan the list and extract data into work arrays */  //扫描链表,提前数据到结果数组中  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)      {        /* As above, hard error if language is SQL */        if (languageOid == SQLlanguageId)          ereport(ERROR,              (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),               errmsg("SQL function cannot accept shell type %s",                  TypeNameToString(t))));        /* We don't allow creating aggregates on shell types either */        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;  /* keep compiler quiet */    }    //权限检查    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."))));    }    /* handle input parameters */    //处理输入参数    if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)    {      //非OUT参数并且不是TABLE参数      /* other input parameters can't follow a VARIADIC parameter */      if (varCount > 0)        ereport(ERROR,            (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),             errmsg("VARIADIC parameter must be the last input parameter")));      //写入到输入类型数组中      inTypes[inCount++] = toid;      isinput = true;    }    /* handle output parameters */    //处理输出参数    if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)    {      if (objtype == OBJECT_PROCEDURE)        //存储过程:要求输出结果类型为RECORD        *requiredResultType = RECORDOID;      else if (outCount == 0) /* save first output param's type */        //第一个OID        *requiredResultType = toid;      outCount++;    }    if (fp->mode == FUNC_PARAM_VARIADIC)    {      //variadic参数      *variadicArgType = toid;      varCount++;      /* validate variadic parameter type */      //验证variadic参数类型      switch (toid)      {        case ANYARRAYOID:        case ANYOID:          /* okay */          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;      /*       * As of Postgres 9.0 we disallow using the same name for two       * input or two output function parameters.  Depending on the       * function's language, conflicting input and output names might       * be bad too, but we leave it to the PL to complain if so.       */      foreach(px, parameters)      {        //循环判断参数是否重复        FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);        if (prevfp == fp)          break;        /* pure in doesn't conflict with pure out */        //输入和输出不冲突        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);      /*       * Make sure no variables are referred to (this is probably dead       * code now that add_missing_from is history).       */      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")));      /*       * transformExpr() should have already rejected subqueries,       * aggregates, and window functions, based on the EXPR_KIND_ for a       * default expression.       *       * It can't return a set either --- but coerce_to_specific_type       * already checked that for us.       *       * Note: the point of these restrictions is to ensure that an       * expression that, on its face, hasn't got subplans, aggregates,       * etc cannot suddenly have them after function default arguments       * are inserted.       */      *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++;  }  /* Now construct the proper outputs as needed */  //如需要,构建合适的输出  *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;    /* otherwise we set requiredResultType correctly above */  }  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$$declarebegin  raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3;  pio_v3 := 'pio_v3 i/o';  po_v4 := 100;  po_v5 := 'po_v5 out';end;$$ LANGUAGE plpgsql;

启动GDB跟踪

(gdb) cContinuing.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:195195   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) n197   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;  /* default result */(gdb) 209   *requiredResultType = InvalidOid; /* default result */(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) n228     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_bits0x7ff12a2c3c57: -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_bits0x7ff12a2c3c57: -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' }, 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) n251       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) n264     if (aclresult != ACLCHECK_OK)(gdb) 267     if (t->setof)(gdb)

处理输入参数

(gdb) p t->setof$16 = false(gdb) n283     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) n334     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) n348       foreach(px, parameters)(gdb)

判断是否重名

(gdb) n350         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) n420       if (isinput && have_defaults)(gdb) 426     i++;(gdb) p *fp->defexprCannot access memory at address 0x0(gdb) n219   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) n229     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' },   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) n263     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) n350         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) n355         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) n353           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) n221     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' },   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) n252       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) /* save first output param's type */(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) n355         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) n355         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) n221     FunctionParameter *fp = (FunctionParameter *) lfirst(x);(gdb) n222     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' }, 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) n252       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) /* save first output param's type */(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) n356            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) n348       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) n436     *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) n438     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:10651065    if (stmt->is_procedure)(gdb)

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

0