本篇内容主要讲解“分析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函数”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:http://blog.itpub.net/6906/viewspace-2676266/