中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

分析PostgreSQL CreateFunction中的interpret_function_parameter_list函數

發布時間:2021-11-05 15:08:38 來源:億速云 閱讀:174 作者:iii 欄目:關系型數據庫

這篇文章主要介紹“分析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,否則設置為結果類型.
 */
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;  /* 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
$$
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;  /* 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) 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) /* 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) 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) /* 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) 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函數”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

安福县| 景宁| 兰溪市| 绍兴县| 灵台县| 河曲县| 新巴尔虎左旗| 武清区| 江达县| 孟连| 汤原县| 蕉岭县| 司法| 铁岭市| 聊城市| 临桂县| 剑阁县| 定结县| 浦县| 桐庐县| 喀喇沁旗| 无极县| 祁连县| 朔州市| 墨玉县| 三穗县| 新巴尔虎右旗| 平谷区| 美姑县| 石狮市| 隆德县| 胶州市| 陕西省| 孝义市| 邵东县| 澎湖县| 响水县| 德昌县| 吴旗县| 德清县| 抚顺市|