本篇内容主要讲解“分析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, ¶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 $$ 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函数”有了更深的了解,不妨来实际操作一番吧!这里是捷杰建站网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
本站采用系统自动发货方式,付款后即出现下载入口,如有疑问请咨询在线客服!
售后时间:早10点 - 晚11:30点Copyright © 2024 jiecseo.com All rights reserved. 粤ICP备18085929号
欢迎光临【捷杰建站】,本站所有资源仅供学习与参考,禁止用于商业用途或从事违法行为!
技术营运:深圳市晟艺互动传媒有限公司