温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

分析PostgreSQL的CreateFunction函数

发布时间:2021-11-05 15:11:32 来源:亿速云 阅读:194 作者:iii 栏目:关系型数据库

本篇内容主要讲解“分析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)语句  */ 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;//权限检查   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, &parallel);   /* 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,                     &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参数作为返回参数     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 $$ 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) 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)

输入参数,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) 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)

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

(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,

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

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

转换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 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函数”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI