分析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, ---Typeto 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'---Typeto 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'---Typeto 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函数"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
类型
函数
参数
结构
语言
分析
对象
属性
权限
基础
空间
语句
检查
安全
内容
可信
名称
数据
用户
过程
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全周郑州参加公司
网络安全有什么安全隐患
网络安全观新闻
阿里巴巴网络安全 王芳
陕西一点通互联网科技有限公司
网络技术聚合后可用地址数
网络安全我知道幼儿
企业微信审批数据库
网络安全意识共享美好生活
ipv6网络安全配置
广州美屋互联网科技
exe快速拆分数据库
网络安全和信息化分别范围
重庆办公系统软件开发价钱是多少
跳一跳扫雷网络安全宣传
学python炒股软件开发
苏州鸿涛网络技术有限公司怎么样
通信软件开发专业学校
宇洋互联网科技有限公司
我的世界在服务器里添加金币系统
金融软件开发 守则
河北政企软件开发
贵州师范大学思政课数据库
软件开发流程细化分工
服务器一被连接网络就断了
开发app 需要服务器吗
显示服务器文件
软件开发要关注什么
拾柒网络技术北京有限公司官网
上海软件开发外包 每人年