溫馨提示×

溫馨提示×

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

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

分析PostgreSQL的CreateFunction函數(shù)

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

本篇內(nèi)容主要講解“分析PostgreSQL的CreateFunction函數(shù)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“分析PostgreSQL的CreateFunction函數(shù)”吧!

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

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

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

ArrayType

/*
 * Arrays are varlena objects, so must meet the varlena convention that
 * the first int32 of the object contains the total object size in bytes.
 * Be sure to use VARSIZE() and SET_VARSIZE() to access it, though!
 * Arrays是可變對象集,必須符合varlena約定,即對象的第一個(gè)int32包含對象的總大?。ㄒ宰止?jié)為單位)。
 * 但是,一定要確保使用VARSIZE和SET_VARSIZE函數(shù)范圍該結(jié)構(gòu)體
 *
 * CAUTION: if you change the header for ordinary arrays you will also
 * need to change the headers for oidvector and int2vector!
 */
typedef struct
{
    //可變的header
    int32       vl_len_;        /* varlena header (do not touch directly!) */
    //維度
    int         ndim;           /* # of dimensions */
    //指向數(shù)據(jù)的偏移量,如為0則表示沒有位圖
    int32       dataoffset;     /* offset to data, or 0 if no bitmap */
    //元素類型的OID
    Oid         elemtype;       /* element type OID */
} ArrayType;

二、源碼解讀

/*
 * CreateFunction
 *   Execute a CREATE FUNCTION (or CREATE PROCEDURE) utility statement.
 *   執(zhí)行CREATE FUNCTION (or CREATE PROCEDURE)語句
 */
ObjectAddress
CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
{
  char     *probin_str;
  char     *prosrc_str;
  Oid     prorettype;
  bool    returnsSet;
  char     *language;
  Oid     languageOid;
  Oid     languageValidator;
  Node     *transformDefElem = NULL;
  char     *funcname;
  Oid     namespaceId;//命名空間ID(schema ID)
  AclResult aclresult;//權(quán)限檢查
  oidvector  *parameterTypes;
  ArrayType  *allParameterTypes;
  ArrayType  *parameterModes;
  ArrayType  *parameterNames;
  List     *parameterDefaults;
  Oid     variadicArgType;
  List     *trftypes_list = NIL;
  ArrayType  *trftypes;
  Oid     requiredResultType;
  bool    isWindowFunc,
        isStrict,
        security,
        isLeakProof;
  char    volatility;
  ArrayType  *proconfig;
  float4    procost;
  float4    prorows;
  Oid     prosupport;
  HeapTuple languageTuple;
  Form_pg_language languageStruct;
  List     *as_clause;
  char    parallel;
  /* Convert list of names to a name and namespace */
  //轉(zhuǎn)換名稱列表為函數(shù)名稱和命名空間
  namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
                          &funcname);
  /* Check we have creation rights in target namespace */
  //檢查權(quán)限是否足夠(是否可以在目標(biāo)命名空間中創(chuàng)建對象)
  aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
  if (aclresult != ACLCHECK_OK)
    aclcheck_error(aclresult, OBJECT_SCHEMA,
             get_namespace_name(namespaceId));
  /* Set default attributes */
  //設(shè)置默認(rèn)的屬性
  isWindowFunc = false;//是否窗口函數(shù)
  isStrict = false;//是否嚴(yán)格的函數(shù)
  security = false;//安全性
  isLeakProof = false;//
  volatility = PROVOLATILE_VOLATILE;
  proconfig = NULL;
  procost = -1;       /* indicates not set */
  prorows = -1;       /* indicates not set */
  prosupport = InvalidOid;
  parallel = PROPARALLEL_UNSAFE;//非并行安全
  /* Extract non-default attributes from stmt->options list */
  //從stmt->options鏈表中抽取非默認(rèn)屬性
  compute_function_attributes(pstate,
                stmt->is_procedure,//是否過程?
                stmt->options,//選項(xiàng)
                &as_clause, &language, &transformDefElem,
                &isWindowFunc, &volatility,
                &isStrict, &security, &isLeakProof,
                &proconfig, &procost, &prorows,
                &prosupport, &parallel);
  /* Look up the language and validate permissions */
  //檢索語言并驗(yàn)證授權(quán)(比如pl/python這類語言,不一定會(huì)支持)
  languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
  if (!HeapTupleIsValid(languageTuple))
    ereport(ERROR,
        (errcode(ERRCODE_UNDEFINED_OBJECT),
         errmsg("language \"%s\" does not exist", language),
         (PLTemplateExists(language) ?
          errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
  //語言結(jié)構(gòu)體和OID
  languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
  languageOid = languageStruct->oid;
  if (languageStruct->lanpltrusted)
  {
    /* if trusted language, need USAGE privilege */
    //可信語言,需要USAGE權(quán)限
    AclResult aclresult;
    aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
      aclcheck_error(aclresult, OBJECT_LANGUAGE,
               NameStr(languageStruct->lanname));
  }
  else
  {
    /* if untrusted language, must be superuser */
    //非可信語言,必須是超級用戶才能創(chuàng)建
    if (!superuser())
      aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_LANGUAGE,
               NameStr(languageStruct->lanname));
  }
  languageValidator = languageStruct->lanvalidator;
  ReleaseSysCache(languageTuple);
  /*
   * Only superuser is allowed to create leakproof functions because
   * leakproof functions can see tuples which have not yet been filtered out
   * by security barrier views or row level security policies.
   * 只有超級用戶才允許創(chuàng)建leakproof函數(shù)
   */
  if (isLeakProof && !superuser())
    ereport(ERROR,
        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
         errmsg("only superuser can define a leakproof function")));
  if (transformDefElem)
  {
    ListCell   *lc;
    foreach(lc, castNode(List, transformDefElem))
    {
      //獲取類型ID
      Oid     typeid = typenameTypeId(NULL,
                        lfirst_node(TypeName, lc));
      //基礎(chǔ)類型
      Oid     elt = get_base_element_type(typeid);
      //如有基礎(chǔ)類型則用基礎(chǔ)類型,否則用類型ID
      typeid = elt ? elt : typeid;
      //
      get_transform_oid(typeid, languageOid, false);
      //寫入到trftypes_list中
      trftypes_list = lappend_oid(trftypes_list, typeid);
    }
  }
  /*
   * Convert remaining parameters of CREATE to form wanted by
   * ProcedureCreate.
   * 轉(zhuǎn)換CREATE中剩下的參數(shù),用于ProcedureCreate調(diào)用
   */
  interpret_function_parameter_list(pstate,
                    stmt->parameters,
                    languageOid,
                    stmt->is_procedure ? OBJECT_PROCEDURE : OBJECT_FUNCTION,
                    &parameterTypes,
                    &allParameterTypes,
                    &parameterModes,
                    &parameterNames,
                    &parameterDefaults,
                    &variadicArgType,
                    &requiredResultType);
  if (stmt->is_procedure)
  {
    //過程
    Assert(!stmt->returnType);
    prorettype = requiredResultType ? requiredResultType : VOIDOID;
    returnsSet = false;
  }
  else if (stmt->returnType)
  {
    //存在返回類型:顯式的RETURNS語句
    /* explicit RETURNS clause */
    //獲取返回類型
    compute_return_type(stmt->returnType, languageOid,
              &prorettype, &returnsSet);
    if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
      ereport(ERROR,
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
           errmsg("function result type must be %s because of OUT parameters",
              format_type_be(requiredResultType))));
  }
  else if (OidIsValid(requiredResultType))
  {
    /* default RETURNS clause from OUT parameters */
    //通過OUT參數(shù)作為返回參數(shù)
    prorettype = requiredResultType;
    returnsSet = false;
  }
  else
  {
    //沒有指定結(jié)果類型
    ereport(ERROR,
        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
         errmsg("function result type must be specified")));
    /* Alternative possibility: default to RETURNS VOID */
    prorettype = VOIDOID;
    returnsSet = false;
  }
  if (list_length(trftypes_list) > 0)
  {
    //處理類型鏈表
    ListCell   *lc;
    Datum    *arr;
    int     i;
    arr = palloc(list_length(trftypes_list) * sizeof(Datum));
    i = 0;
    foreach(lc, trftypes_list)
      arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
    trftypes = construct_array(arr, list_length(trftypes_list),
                   OIDOID, sizeof(Oid), true, 'i');
  }
  else
  {
    /* store SQL NULL instead of empty array */
    trftypes = NULL;
  }
  //解析AS語句
  interpret_AS_clause(languageOid, language, funcname, as_clause,
            &prosrc_str, &probin_str);
  /*
   * Set default values for COST and ROWS depending on other parameters;
   * reject ROWS if it's not returnsSet.  NB: pg_dump knows these default
   * values, keep it in sync if you change them.
   * 基于其他參數(shù)設(shè)置COST和ROWS的默認(rèn)值
   */
  if (procost < 0)
  {
    /* SQL and PL-language functions are assumed more expensive */
    //SQL和PL-XXX函數(shù)假定成本更高
    if (languageOid == INTERNALlanguageId ||
      languageOid == ClanguageId)
      procost = 1;
    else
      procost = 100;
  }
  if (prorows < 0)
  {
    if (returnsSet)
      prorows = 1000;
    else
      prorows = 0;    /* dummy value if not returnsSet */
  }
  else if (!returnsSet)
    ereport(ERROR,
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
         errmsg("ROWS is not applicable when function does not return a set")));
  /*
   * And now that we have all the parameters, and know we're permitted to do
   * so, go ahead and create the function.
   * 這時(shí)候已準(zhǔn)備好所有的參數(shù),并且已驗(yàn)證具備相應(yīng)的權(quán)限,創(chuàng)建函數(shù)
   */
  return ProcedureCreate(funcname,
               namespaceId,
               stmt->replace,
               returnsSet,
               prorettype,
               GetUserId(),
               languageOid,
               languageValidator,
               prosrc_str,  /* converted to text later */
               probin_str,  /* converted to text later */
               stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION),
               security,
               isLeakProof,
               isStrict,
               volatility,
               parallel,
               parameterTypes,
               PointerGetDatum(allParameterTypes),
               PointerGetDatum(parameterModes),
               PointerGetDatum(parameterNames),
               parameterDefaults,
               PointerGetDatum(trftypes),
               PointerGetDatum(proconfig),
               prosupport,
               procost,
               prorows);
}

三、跟蹤分析

測試腳本

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;

啟動(dòng)GDB跟蹤

(gdb) b CreateFunction 
Breakpoint 1 at 0x670b94: file functioncmds.c, line 929.
(gdb) c
Continuing.
Breakpoint 1, CreateFunction (pstate=0x2b02cb8, stmt=0x2add8f8) at functioncmds.c:929
929     Node       *transformDefElem = NULL;
(gdb) bt
#0  CreateFunction (pstate=0x2b02cb8, stmt=0x2add8f8) at functioncmds.c:929
#1  0x00000000008f61a6 in ProcessUtilitySlow (pstate=0x2b02cb8, pstmt=0x2addc78, 
    queryString=0x2adbf08 "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 :="..., context=PROCESS_UTILITY_TOPLEVEL, 
    params=0x0, queryEnv=0x0, dest=0x2addd70, completionTag=0x7fffef099ca0 "")
    at utility.c:1478
#2  0x00000000008f5069 in standard_ProcessUtility (pstmt=0x2addc78, 
    queryString=0x2adbf08 "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 :="..., context=PROCESS_UTILITY_TOPLEVEL, 
    params=0x0, queryEnv=0x0, dest=0x2addd70, completionTag=0x7fffef099ca0 "")
    at utility.c:927
#3  0x00000000008f418f in ProcessUtility (pstmt=0x2addc78, 
    queryString=0x2adbf08 "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 :="..., context=PROCESS_UTILITY_TOPLEVEL, 
    params=0x0, queryEnv=0x0, dest=0x2addd70, completionTag=0x7fffef099ca0 "")
    at utility.c:360
#4  0x00000000008f3188 in PortalRunUtility (portal=0x2b43278, pstmt=0x2addc78, 
---Type <return> to continue, or q <return> to quit---
    isTopLevel=true, setHoldSnapshot=false, dest=0x2addd70, completionTag=0x7fffef099ca0 "")
    at pquery.c:1175
#5  0x00000000008f339e in PortalRunMulti (portal=0x2b43278, isTopLevel=true, 
    setHoldSnapshot=false, dest=0x2addd70, altdest=0x2addd70, completionTag=0x7fffef099ca0 "")
    at pquery.c:1321
#6  0x00000000008f28d3 in PortalRun (portal=0x2b43278, count=9223372036854775807, 
    isTopLevel=true, run_once=true, dest=0x2addd70, altdest=0x2addd70, 
    completionTag=0x7fffef099ca0 "") at pquery.c:796
#7  0x00000000008ec882 in exec_simple_query (
    query_string=0x2adbf08 "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 :="...) at postgres.c:1215
#8  0x00000000008f0b04 in PostgresMain (argc=1, argv=0x2b09318, dbname=0x2b09160 "testdb", 
    username=0x2ad8b28 "pg12") at postgres.c:4247
#9  0x0000000000846fa8 in BackendRun (port=0x2afdb10) at postmaster.c:4437
#10 0x0000000000846786 in BackendStartup (port=0x2afdb10) at postmaster.c:4128
#11 0x00000000008429b4 in ServerLoop () at postmaster.c:1704
#12 0x000000000084226a in PostmasterMain (argc=1, argv=0x2ad6ae0) at postmaster.c:1377
#13 0x0000000000762364 in main (argc=1, argv=0x2ad6ae0) at main.c:228
(gdb) 
(gdb)

輸入?yún)?shù),pstate是ParseState結(jié)構(gòu)體,stmt類型是CreateFunctionStmt結(jié)構(gòu)體

(gdb) p *pstate
$1 = {parentParseState = 0x0, 
  p_sourcetext = 0x2adbf08 "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) p *stmt
$2 = {type = T_CreateFunctionStmt, is_procedure = false, replace = true, 
  funcname = 0x2adcb58, parameters = 0x2adcd60, returnType = 0x2add580, options = 0x2add818}

獲取namespace

(gdb) n
939     List       *trftypes_list = NIL;
(gdb) 
957     namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
(gdb) 
961     aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
(gdb) p namespaceId
$3 = 2200
(gdb)

namespace是public

[local:/data/run/pg12]:5120 pg12@testdb=# select * from pg_namespace;
  oid  |      nspname       | nspowner |         nspacl          
-------+--------------------+----------+-------------------------
    99 | pg_toast           |       10 | 
 12314 | pg_temp_1          |       10 | 
 12315 | pg_toast_temp_1    |       10 | 
    11 | pg_catalog         |       10 | {pg12=UC/pg12,=U/pg12}
  2200 | public             |       10 | {pg12=UC/pg12,=UC/pg12}
 13291 | information_schema |       10 | {pg12=UC/pg12,=U/pg12}
(6 rows)

執(zhí)行權(quán)限檢查,初始化屬性默認(rèn)值

(gdb) n
962     if (aclresult != ACLCHECK_OK)
(gdb) p aclresult
$4 = ACLCHECK_OK
(gdb) n
967     isWindowFunc = false;
(gdb) 
968     isStrict = false;
(gdb) 
969     security = false;
(gdb) 
970     isLeakProof = false;
(gdb) 
971     volatility = PROVOLATILE_VOLATILE;
(gdb) 
972     proconfig = NULL;
(gdb) 
973     procost = -1;               /* indicates not set */
(gdb) 
974     prorows = -1;               /* indicates not set */
(gdb) 
975     prosupport = InvalidOid;
(gdb) 
976     parallel = PROPARALLEL_UNSAFE;
(gdb) 
979     compute_function_attributes(pstate,

調(diào)用compute_function_attributes從stmt->options鏈表中抽取非默認(rèn)屬性

(gdb) 
989     languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
(gdb) p *language
$33 = 112 'p'
(gdb) p *transformDefElem
Cannot access memory at address 0x0
(gdb) p isWindowFunc
$34 = false
(gdb) p volatility
$35 = 118 'v'
(gdb) p isStrict
$36 = false
(gdb) p security
$37 = false
(gdb) p isLeakProof
$38 = false
(gdb) p proconfig
$39 = (ArrayType *) 0x0
(gdb) p procost
$40 = -1
(gdb) p prorows
$41 = -1
(gdb) p prosupport
$42 = 0
(gdb) p parallel
$43 = 117 'u'
(gdb) p stmt->options
$44 = (List *) 0x2add818
(gdb) p *stmt->options
$45 = {type = T_List, length = 2, head = 0x2add7f0, tail = 0x2add8d0}
(gdb) p *(Node *)stmt->options->head->data.ptr_value
$46 = {type = T_DefElem}
(gdb) p *(DefElem *)stmt->options->head->data.ptr_value
$47 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbf727 "as", arg = 0x2add760, 
  defaction = DEFELEM_UNSPEC, location = 134}
(gdb) p *((DefElem *)stmt->options->head->data.ptr_value)->arg
$48 = {type = T_List}
(gdb) p *pstate
$5 = {parentParseState = 0x0, 
  p_sourcetext = 0x2adbf08 "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) x/1024c pstate->p_sourcetext
0x2adbf08:  99 'c'  114 'r' 101 'e' 97 'a'  116 't' 101 'e' 32 ' '  111 'o'
0x2adbf10:  114 'r' 32 ' '  114 'r' 101 'e' 112 'p' 108 'l' 97 'a'  99 'c'
0x2adbf18:  101 'e' 32 ' '  102 'f' 117 'u' 110 'n' 99 'c'  116 't' 105 'i'
0x2adbf20:  111 'o' 110 'n' 32 ' '  102 'f' 117 'u' 110 'n' 99 'c'  95 '_'
0x2adbf28:  116 't' 101 'e' 115 's' 116 't' 40 '('  112 'p' 105 'i' 95 '_'
0x2adbf30:  118 'v' 49 '1'  32 ' '  105 'i' 110 'n' 32 ' '  105 'i' 110 'n'
0x2adbf38:  116 't' 44 ','  112 'p' 105 'i' 95 '_'  118 'v' 50 '2'  32 ' '
0x2adbf40:  118 'v' 97 'a'  114 'r' 99 'c'  104 'h' 97 'a'  114 'r' 44 ','
0x2adbf48:  112 'p' 105 'i' 111 'o' 95 '_'  118 'v' 51 '3'  32 ' '  105 'i'
0x2adbf50:  110 'n' 111 'o' 117 'u' 116 't' 32 ' '  118 'v' 97 'a'  114 'r'
0x2adbf58:  99 'c'  104 'h' 97 'a'  114 'r' 44 ','  112 'p' 111 'o' 95 '_'
0x2adbf60:  118 'v' 52 '4'  32 ' '  111 'o' 117 'u' 116 't' 32 ' '  105 'i'
0x2adbf68:  110 'n' 116 't' 44 ','  112 'p' 111 'o' 95 '_'  118 'v' 53 '5'
0x2adbf70:  32 ' '  111 'o' 117 'u' 116 't' 32 ' '  118 'v' 97 'a'  114 'r'
0x2adbf78:  99 'c'  104 'h' 97 'a'  114 'r' 41 ')'  10 '\n' 114 'r' 101 'e'
0x2adbf80:  116 't' 117 'u' 114 'r' 110 'n' 115 's' 32 ' '  114 'r' 101 'e'
0x2adbf88:  99 'c'  111 'o' 114 'r' 100 'd' 32 ' '  10 '\n' 97 'a'  115 's'
0x2adbf90:  10 '\n' 36 '$'  36 '$'  10 '\n' 100 'd' 101 'e' 99 'c'  108 'l'
0x2adbf98:  97 'a'  114 'r' 101 'e' 10 '\n' 98 'b'  101 'e' 103 'g' 105 'i'
0x2adbfa0:  110 'n' 10 '\n' 32 ' '  32 ' '  114 'r' 97 'a'  105 'i' 115 's'
---Type <return> to continue, or q <return> to quit---
0x2adbfa8:  101 'e' 32 ' '  110 'n' 111 'o' 116 't' 105 'i' 99 'c'  101 'e'
0x2adbfb0:  32 ' '  39 '\'' 112 'p' 105 'i' 95 '_'  118 'v' 49 '1'  32 ' '
0x2adbfb8:  58 ':'  61 '='  32 ' '  37 '%'  44 ','  112 'p' 105 'i' 95 '_'
0x2adbfc0:  118 'v' 50 '2'  32 ' '  58 ':'  61 '='  32 ' '  37 '%'  44 ','
0x2adbfc8:  112 'p' 105 'i' 95 '_'  118 'v' 51 '3'  32 ' '  58 ':'  61 '='
0x2adbfd0:  32 ' '  37 '%'  39 '\'' 44 ','  112 'p' 105 'i' 95 '_'  118 'v'
0x2adbfd8:  49 '1'  44 ','  112 'p' 105 'i' 95 '_'  118 'v' 50 '2'  44 ','
0x2adbfe0:  112 'p' 105 'i' 111 'o' 95 '_'  118 'v' 51 '3'  59 ';'  10 '\n'
0x2adbfe8:  32 ' '  32 ' '  112 'p' 105 'i' 111 'o' 95 '_'  118 'v' 51 '3'
0x2adbff0:  32 ' '  58 ':'  61 '='  32 ' '  39 '\'' 112 'p' 105 'i' 111 'o'
0x2adbff8:  95 '_'  118 'v' 51 '3'  32 ' '  105 'i' 47 '/'  111 'o' 39 '\''
0x2adc000:  59 ';'  10 '\n' 32 ' '  32 ' '  112 'p' 111 'o' 95 '_'  118 'v'
0x2adc008:  52 '4'  32 ' '  58 ':'  61 '='  32 ' '  49 '1'  48 '0'  48 '0'
0x2adc010:  59 ';'  10 '\n' 32 ' '  32 ' '  112 'p' 111 'o' 95 '_'  118 'v'
0x2adc018:  53 '5'  32 ' '  58 ':'  61 '='  32 ' '  39 '\'' 112 'p' 111 'o'
0x2adc020:  95 '_'  118 'v' 53 '5'  32 ' '  111 'o' 117 'u' 116 't' 39 '\''
0x2adc028:  59 ';'  10 '\n' 101 'e' 110 'n' 100 'd' 59 ';'  10 '\n' 36 '$'
0x2adc030:  36 '$'  32 ' '  76 'L'  65 'A'  78 'N'  71 'G'  85 'U'  65 'A'
0x2adc038:  71 'G'  69 'E'  32 ' '  112 'p' 108 'l' 112 'p' 103 'g' 115 's'
0x2adc040:  113 'q' 108 'l' 59 ';'  0 '\000'    0 '\000'    127 '\177'  127 '\1
---Type <return> to continue, or q <return> to quit---^CQuit
(gdb) 
(gdb) n

獲取language

990     if (!HeapTupleIsValid(languageTuple))
(gdb) p languageTuple
$7 = (HeapTuple) 0x7fcc407e0bf8
(gdb) p *languageTuple
$8 = {t_len = 120, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 4}, 
  t_tableOid = 2612, t_data = 0x7fcc407e0c20}
(gdb) n
997     languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
(gdb) 
998     languageOid = languageStruct->oid;
(gdb) p *languageStruct
$9 = {oid = 13581, lanname = {data = "plpgsql", '\000' <repeats 56 times>}, lanowner = 10, 
  lanispl = true, lanpltrusted = true, lanplcallfoid = 13578, laninline = 13579, 
  lanvalidator = 13580}
(gdb) n
1000        if (languageStruct->lanpltrusted)
(gdb) 
1005            aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
(gdb) 
1006            if (aclresult != ACLCHECK_OK)
(gdb) 
1018        languageValidator = languageStruct->lanvalidator;
(gdb) 
1020        ReleaseSysCache(languageTuple);
(gdb) 
1027        if (isLeakProof && !superuser())
(gdb) 
1032        if (transformDefElem)
(gdb) 
1056                                          stmt->is_procedure ? OBJECT_PROCEDURE : OBJECT_FUNCTION,
(gdb)

轉(zhuǎn)換CREATE中剩下的參數(shù),用于ProcedureCreate調(diào)用

1053        interpret_function_parameter_list(pstate,
(gdb) 
1065        if (stmt->is_procedure)
(gdb) p *pstate
$10 = {parentParseState = 0x0, 
  p_sourcetext = 0x2adbf08 "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) p *stmt
$11 = {type = T_CreateFunctionStmt, is_procedure = false, replace = true, 
  funcname = 0x2adcb58, parameters = 0x2adcd60, returnType = 0x2add580, options = 0x2add818}
(gdb) p *stmt->parameters
$12 = {type = T_List, length = 5, head = 0x2adcd38, tail = 0x2add4b0}
(gdb) p parameterTypes
$13 = (oidvector *) 0x2bed1a8
(gdb) p *parameterTypes
$14 = {vl_len_ = 144, ndim = 1, dataoffset = 0, elemtype = 26, dim1 = 3, lbound1 = 0, 
  values = 0x2bed1c0}
(gdb) x/144h 0x2bed1c0
0x2bed1c0:  23 '\027'   0 '\000'    19 '\023'   0 '\000'    19 '\023'     0 '\000'  126 '~' 127 '\177'
0x2bed1d0:  127 '\177'  127 '\177'  127 '\177'  127 '\177'  127 '\177'    127 '\177'    127 '\177'  127 '\177'
0x2bed1e0:  127 '\177'  127 '\177'  127 '\177'  127 '\177'  64 '@'  0 '\000'    0 '\000'    0 '\000'
0x2bed1f0:  44 ','  0 '\000'    0 '\000'    0 '\000'    -96 '\240'  -80 '\260'  0 '\000'    0 '\000'
0x2bed200:  -80 '\260'  0 '\000'    1 '\001'    0 '\000'    0 '\000'      0 '\000'  26 '\032'   0 '\000'
0x2bed210:  5 '\005'    0 '\000'    1 '\001'    0 '\000'    23 '\027'     0 '\000'  19 '\023'   0 '\000'
0x2bed220:  19 '\023'   0 '\000'    23 '\027'   0 '\000'    19 '\023'     0 '\000'  126 '~' 127 '\177'
0x2bed230:  127 '\177'  127 '\177'  127 '\177'  127 '\177'  127 '\177'    127 '\177'    127 '\177'  127 '\177'
0x2bed240:  32 ' '  0 '\000'    0 '\000'    0 '\000'    29 '\035'   0 '\000'    0 '\000'    0 '\000'
0x2bed250:  -96 '\240'  -80 '\260'  0 '\000'    0 '\000'    116 't' 0 '\000'    1 '\001'    0 '\000'
---Type <return> to continue, or q <return> to quit---^CQuit
(gdb) n
1071        else if (stmt->returnType)
(gdb) p *stmt->returnType
$15 = {type = T_TypeName, names = 0x2add548, typeOid = 0, setof = false, pct_type = false, 
  typmods = 0x0, typemod = -1, arrayBounds = 0x0, location = 126}
(gdb) p *stmt->returnType->names
$16 = {type = T_List, length = 1, head = 0x2add520, tail = 0x2add520}
(gdb) n
1074            compute_return_type(stmt->returnType, languageOid,
(gdb) 
1076            if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
(gdb) p *prorettype
Cannot access memory at address 0x8c9
(gdb) p prorettype
$17 = 2249
(gdb) p returnsSet
$18 = false
(gdb) p 
$19 = false
(gdb) p *allParameterTypes
$20 = {vl_len_ = 176, ndim = 1, dataoffset = 0, elemtype = 26}
(gdb) p parameterModes
$21 = (ArrayType *) 0x2bed258
(gdb) p *parameterModes
$22 = {vl_len_ = 116, ndim = 1, dataoffset = 0, elemtype = 18}
(gdb) p *parameterNames
$23 = {vl_len_ = 336, ndim = 1, dataoffset = 0, elemtype = 25}
(gdb) p *parameterDefaults
Cannot access memory at address 0x0
(gdb) p *variadicArgType
Cannot access memory at address 0x0
(gdb) p *requiredResultType
Cannot access memory at address 0x8c9
(gdb) p requiredResultType
$24 = 2249
(gdb) n
1098        if (list_length(trftypes_list) > 0)
(gdb) p trftypes_list
$25 = (List *) 0x0
(gdb) n
1114            trftypes = NULL;
(gdb) 
1117        interpret_AS_clause(languageOid, language, funcname, as_clause,
(gdb) 
1125        if (procost < 0)
(gdb) p *prosrc_str
$26 = 10 '\n'
(gdb) p *probin_str
Cannot access memory at address 0x0
(gdb) p as_clause
$27 = (List *) 0x2add760
(gdb) p *as_clause
$28 = {type = T_List, length = 1, head = 0x2add738, tail = 0x2add738}
(gdb) p *as_clause->head
$29 = {data = {ptr_value = 0x2add710, int_value = 44947216, oid_value = 44947216}, next = 0x0}
(gdb) p (Node *)as_clause->head->data.ptr_value
$30 = (Node *) 0x2add710
(gdb) p (Node **)as_clause->head->data.ptr_value
$31 = (Node **) 0x2add710
(gdb) p *as_clause->head->data.ptr_value
Attempt to dereference a generic pointer.
(gdb) p (Node *)as_clause->head->data.ptr_value
$32 = (Node *) 0x2add710
(gdb) n
1128            if (languageOid == INTERNALlanguageId ||
(gdb) 
1132                procost = 100;
(gdb) 
1134        if (prorows < 0)
(gdb) 
1136            if (returnsSet)
(gdb) 
1139                prorows = 0;        /* dummy value if not returnsSet */
(gdb) 
1150        return ProcedureCreate(funcname,
(gdb) 
1160                               stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION),
(gdb) 
1150        return ProcedureCreate(funcname,
(gdb) 
1152                               stmt->replace,
(gdb) 
1150        return ProcedureCreate(funcname,
(gdb) 
1176    }
(gdb) 
ProcessUtilitySlow (pstate=0x2b02cb8, pstmt=0x2addc78, 
    queryString=0x2adbf08 "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 :="..., context=PROCESS_UTILITY_TOPLEVEL, 
    params=0x0, queryEnv=0x0, dest=0x2addd70, completionTag=0x7fffef099ca0 "")
    at utility.c:1479
1479                    break;
(gdb)

到此,相信大家對“分析PostgreSQL的CreateFunction函數(shù)”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

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

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

AI