千家信息网

分析PostgreSQL的CreateFunction函数

发表于:2025-01-22 作者:千家信息网编辑
千家信息网最后更新 2025年01月22日,本篇内容主要讲解"分析PostgreSQL的CreateFunction函数",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"分析PostgreSQL的Cre
千家信息网最后更新 2025年01月22日分析PostgreSQL的CreateFunction函数

本篇内容主要讲解"分析PostgreSQL的CreateFunction函数",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"分析PostgreSQL的CreateFunction函数"吧!

一、数据结构

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;

二、源码解读

/* * CreateFunction *   Execute a CREATE FUNCTION (or CREATE PROCEDURE) utility statement. *   执行CREATE FUNCTION (or CREATE PROCEDURE)语句 */ObjectAddressCreateFunction(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;//权限检查  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 */  //转换名称列表为函数名称和命名空间  namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,                          &funcname);  /* Check we have creation rights in target namespace */  //检查权限是否足够(是否可以在目标命名空间中创建对象)  aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);  if (aclresult != ACLCHECK_OK)    aclcheck_error(aclresult, OBJECT_SCHEMA,             get_namespace_name(namespaceId));  /* Set default attributes */  //设置默认的属性  isWindowFunc = false;//是否窗口函数  isStrict = false;//是否严格的函数  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链表中抽取非默认属性  compute_function_attributes(pstate,                stmt->is_procedure,//是否过程?                stmt->options,//选项                &as_clause, &language, &transformDefElem,                &isWindowFunc, &volatility,                &isStrict, &security, &isLeakProof,                &proconfig, &procost, &prorows,                &prosupport, ¶llel);  /* Look up the language and validate permissions */  //检索语言并验证授权(比如pl/python这类语言,不一定会支持)  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)));  //语言结构体和OID  languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);  languageOid = languageStruct->oid;  if (languageStruct->lanpltrusted)  {    /* if trusted language, need USAGE privilege */    //可信语言,需要USAGE权限    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 */    //非可信语言,必须是超级用户才能创建    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.   * 只有超级用户才允许创建leakproof函数   */  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));      //基础类型      Oid     elt = get_base_element_type(typeid);      //如有基础类型则用基础类型,否则用类型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.   * 转换CREATE中剩下的参数,用于ProcedureCreate调用   */  interpret_function_parameter_list(pstate,                    stmt->parameters,                    languageOid,                    stmt->is_procedure ? OBJECT_PROCEDURE : OBJECT_FUNCTION,                    ¶meterTypes,                    &allParameterTypes,                    ¶meterModes,                    ¶meterNames,                    ¶meterDefaults,                    &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参数作为返回参数    prorettype = requiredResultType;    returnsSet = false;  }  else  {    //没有指定结果类型    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.   * 基于其他参数设置COST和ROWS的默认值   */  if (procost < 0)  {    /* SQL and PL-language functions are assumed more expensive */    //SQL和PL-XXX函数假定成本更高    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.   * 这时候已准备好所有的参数,并且已验证具备相应的权限,创建函数   */  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$$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) b CreateFunction Breakpoint 1 at 0x670b94: file functioncmds.c, line 929.(gdb) cContinuing.Breakpoint 1, CreateFunction (pstate=0x2b02cb8, stmt=0x2add8f8) at functioncmds.c:929929     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  to continue, or q  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)

输入参数,pstate是ParseState结构体,stmt类型是CreateFunctionStmt结构体

(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) n939     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)

执行权限检查,初始化属性默认值

(gdb) n962     if (aclresult != ACLCHECK_OK)(gdb) p aclresult$4 = ACLCHECK_OK(gdb) n967     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,

调用compute_function_attributes从stmt->options链表中抽取非默认属性

(gdb) 989     languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));(gdb) p *language$33 = 112 'p'(gdb) p *transformDefElemCannot 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_sourcetext0x2adbf08:  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  to continue, or q  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  to continue, or q  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) n997     languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);(gdb) 998     languageOid = languageStruct->oid;(gdb) p *languageStruct$9 = {oid = 13581, lanname = {data = "plpgsql", '\000' }, lanowner = 10,   lanispl = true, lanpltrusted = true, lanplcallfoid = 13578, laninline = 13579,   lanvalidator = 13580}(gdb) n1000        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)

转换CREATE中剩下的参数,用于ProcedureCreate调用

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 0x2bed1c00x2bed1c0:  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  to continue, or q  to quit---^CQuit(gdb) n1071        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) n1074            compute_return_type(stmt->returnType, languageOid,(gdb) 1076            if (OidIsValid(requiredResultType) && prorettype != requiredResultType)(gdb) p *prorettypeCannot 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 *parameterDefaultsCannot access memory at address 0x0(gdb) p *variadicArgTypeCannot access memory at address 0x0(gdb) p *requiredResultTypeCannot access memory at address 0x8c9(gdb) p requiredResultType$24 = 2249(gdb) n1098        if (list_length(trftypes_list) > 0)(gdb) p trftypes_list$25 = (List *) 0x0(gdb) n1114            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_strCannot 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_valueAttempt to dereference a generic pointer.(gdb) p (Node *)as_clause->head->data.ptr_value$32 = (Node *) 0x2add710(gdb) n1128            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:14791479                    break;(gdb)

到此,相信大家对"分析PostgreSQL的CreateFunction函数"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0