本节简单介绍了PostgreSQL创建函数的过程,其实现函数是CreateFunction。
一、数据结构
Form_pg_language
plpgsql语言定义结构体
CATALOG(pg_language,2612,LanguageRelationId)
{
Oid oid;
NameData lanname;
Oid lanowner BKI_DEFAULT(PGUID);
bool lanispl BKI_DEFAULT(f);
bool lanpltrusted BKI_DEFAULT(f);
Oid lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
Oid laninline BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
Oid lanvalidator BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
#ifdef CATALOG_VARLEN
aclitem lanacl[1] BKI_DEFAULT(_null_);
#endif
} FormData_pg_language;
typedef FormData_pg_language *Form_pg_language;
ArrayType
typedef struct
{
//可变的header
int32 vl_len_;
//维度
int ndim;
//指向数据的偏移量,如为0则表示没有位图
int32 dataoffset;
//元素类型的OID
Oid elemtype;
} ArrayType;
DefElem
typedef struct DefElem
{
NodeTag type;
char *defnamespace;
char *defname;
Node *arg;
DefElemAction defaction;
int location;
} DefElem;
二、源码解读
static void
compute_function_attributes(ParseState *pstate,//解析状态结构体
bool is_procedure,//是否过程?
List *options,//选项链表(stmt->options)
List **as,//as语句
char **language,//语言
Node **transform,//
bool *windowfunc_p,//是否窗口函数
char *volatility_p,//是否易变函数
bool *strict_p,//是否严格
bool *security_definer,//安全定义
bool *leakproof_p,//是否leakproof
ArrayType **proconfig,//过程配置信息
float4 *procost,//过程成本
float4 *prorows,//涉及的行数
Oid *prosupport,//
char *parallel_p)
{
ListCell *option;//临时变量
DefElem *as_item = NULL;
DefElem *language_item = NULL;
DefElem *transform_item = NULL;
DefElem *windowfunc_item = NULL;
DefElem *volatility_item = NULL;
DefElem *strict_item = NULL;
DefElem *security_item = NULL;
DefElem *leakproof_item = NULL;
List *set_items = NIL;
DefElem *cost_item = NULL;
DefElem *rows_item = NULL;
DefElem *support_item = NULL;
DefElem *parallel_item = NULL;
foreach(option, options)//循环处理
{
//获取定义的元素信息
DefElem *defel = (DefElem *) lfirst(option);
if (strcmp(defel->defname, "as") == 0)
{
//as
if (as_item)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"),
parser_errposition(pstate, defel->location)));
as_item = defel;
}
else if (strcmp(defel->defname, "language") == 0)
{
//language
if (language_item)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"),
parser_errposition(pstate, defel->location)));
language_item = defel;
}
else if (strcmp(defel->defname, "transform") == 0)
{
//transform
if (transform_item)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"),
parser_errposition(pstate, defel->location)));
transform_item = defel;
}
else if (strcmp(defel->defname, "window") == 0)
{
//窗口函数
if (windowfunc_item)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"),
parser_errposition(pstate, defel->location)));
if (is_procedure)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("invalid attribute in procedure definition"),
parser_errposition(pstate, defel->location)));
windowfunc_item = defel;
}
else if (compute_common_attribute(pstate,
is_procedure,
defel,
&volatility_item,
&strict_item,
&security_item,
&leakproof_item,
&set_items,
&cost_item,
&rows_item,
&support_item,
¶llel_item))//普通属性
{
//识别可以同时传递给CREATE FUNCTION和ALTER FUNCTION的选项,并通过out参数返回
continue;
}
else
elog(ERROR, "option \"%s\" not recognized",
defel->defname);
}
if (as_item)
//必选项:函数体
*as = (List *) as_item->arg;
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("no function body specified")));
*as = NIL;
}
if (language_item)
//必选项:语言
*language = strVal(language_item->arg);
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("no language specified")));
*language = NULL;
}
//可选项
if (transform_item)
*transform = transform_item->arg;
if (windowfunc_item)
*windowfunc_p = intVal(windowfunc_item->arg);
if (volatility_item)
*volatility_p = interpret_func_volatility(volatility_item);
if (strict_item)
*strict_p = intVal(strict_item->arg);
if (security_item)
*security_definer = intVal(security_item->arg);
if (leakproof_item)
*leakproof_p = intVal(leakproof_item->arg);
if (set_items)
*proconfig = update_proconfig_value(NULL, set_items);
if (cost_item)
{
*procost = defGetNumeric(cost_item);
if (*procost <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("COST must be positive")));
}
if (rows_item)
{
*prorows = defGetNumeric(rows_item);
if (*prorows <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ROWS must be positive")));
}
if (support_item)
*prosupport = interpret_func_support(support_item);
if (parallel_item)
*parallel_p = interpret_func_parallel(parallel_item);
}
static bool
compute_common_attribute(ParseState *pstate,
bool is_procedure,
DefElem *defel,
DefElem **volatility_item,
DefElem **strict_item,
DefElem **security_item,
DefElem **leakproof_item,
List **set_items,
DefElem **cost_item,
DefElem **rows_item,
DefElem **support_item,
DefElem **parallel_item)
{
//----------- 逐个判断赋值
if (strcmp(defel->defname, "volatility") == 0)
{
if (is_procedure)
goto procedure_error;
if (*volatility_item)
goto duplicate_error;
*volatility_item = defel;
}
else if (strcmp(defel->defname, "strict") == 0)
{
if (is_procedure)
goto procedure_error;
if (*strict_item)
goto duplicate_error;
*strict_item = defel;
}
else if (strcmp(defel->defname, "security") == 0)
{
if (*security_item)
goto duplicate_error;
*security_item = defel;
}
else if (strcmp(defel->defname, "leakproof") == 0)
{
if (is_procedure)
goto procedure_error;
if (*leakproof_item)
goto duplicate_error;
*leakproof_item = defel;
}
else if (strcmp(defel->defname, "set") == 0)
{
*set_items = lappend(*set_items, defel->arg);
}
else if (strcmp(defel->defname, "cost") == 0)
{
if (is_procedure)
goto procedure_error;
if (*cost_item)
goto duplicate_error;
*cost_item = defel;
}
else if (strcmp(defel->defname, "rows") == 0)
{
if (is_procedure)
goto procedure_error;
if (*rows_item)
goto duplicate_error;
*rows_item = defel;
}
else if (strcmp(defel->defname, "support") == 0)
{
if (is_procedure)
goto procedure_error;
if (*support_item)
goto duplicate_error;
*support_item = defel;
}
else if (strcmp(defel->defname, "parallel") == 0)
{
if (is_procedure)
goto procedure_error;
if (*parallel_item)
goto duplicate_error;
*parallel_item = defel;
}
else
return false;
return true;
duplicate_error:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"),
parser_errposition(pstate, defel->location)));
return false;
procedure_error:
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("invalid attribute in procedure definition"),
parser_errposition(pstate, defel->location)));
return false;
}
三、跟踪分析
测试脚本
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 compute_function_attributes
Breakpoint 1 at 0x6702b7: file functioncmds.c, line 711.
(gdb) c
Continuing.
Breakpoint 1, compute_function_attributes (pstate=0x1dd4c88, is_procedure=false,
options=0x1daf7e8, as=0x7ffd231851d8, language=0x7ffd23185240,
transform=0x7ffd23185238, windowfunc_p=0x7ffd231851ff, volatility_p=0x7ffd231851fb "v",
strict_p=0x7ffd231851fe, security_definer=0x7ffd231851fd, leakproof_p=0x7ffd231851fc,
proconfig=0x7ffd231851f0, procost=0x7ffd231851ec, prorows=0x7ffd231851e8,
prosupport=0x7ffd231851e4, parallel_p=0x7ffd231851d7 "u") at functioncmds.c:711
711 DefElem *as_item = NULL;
输入参数
(gdb) p *pstate
$1 = {parentParseState = 0x0,
p_sourcetext = 0x1daded8 "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 is_procedure
$2 = false
SQL语句的选项#1(as语句)
(gdb) p *options
$3 = {type = T_List, length = 2, head = 0x1daf7c0, tail = 0x1daf8a0}
(gdb) p *(Node *)options->head->data.ptr_value
$4 = {type = T_DefElem}
(gdb) p *(DefElem *)options->head->data.ptr_value
$5 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbf727 "as", arg = 0x1daf730,
defaction = DEFELEM_UNSPEC, location = 134}
(gdb) set $defelem=(DefElem *)options->head->data.ptr_value
(gdb) p $defelem->arg
$6 = (Node *) 0x1daf730
(gdb) p *(Node *)$defelem->arg
$7 = {type = T_List}
(gdb) p *(List *)$defelem->arg
$8 = {type = T_List, length = 1, head = 0x1daf708, tail = 0x1daf708}
(gdb) set $arg=(List *)$defelem->arg
(gdb) p *(Node *)$arg->head->data.ptr_value
$9 = {type = T_String}
(gdb) p *(Value *)$arg->head->data.ptr_value
$11 = {type = T_String, val = {ival = 31126984,
str = 0x1daf5c8 "\ndeclare\nbegin\n raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3;\n pio_v3 := 'pio_v3 i/o';\n po_v4 := 100;\n po_v5 := 'po_v5 out';\nend;\n"}}
SQL语句的选项#2(语言)
(gdb) set $defelem2=(DefElem *)options->head->next->data.ptr_value
(gdb) p *$defelem2
$13 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbfcbe "language",
arg = 0x1daf820, defaction = DEFELEM_UNSPEC, location = 298}
(gdb) p *$defelem2->arg
$14 = {type = T_String}
(gdb) p *(Value *)$defelem2->arg
$15 = {type = T_String, val = {ival = 31126952, str = 0x1daf5a8 "plpgsql"}}
(gdb)
提取as_item和language_item
(gdb) n
712 DefElem *language_item = NULL;
(gdb) n
713 DefElem *transform_item = NULL;
(gdb)
714 DefElem *windowfunc_item = NULL;
(gdb)
715 DefElem *volatility_item = NULL;
(gdb)
716 DefElem *strict_item = NULL;
(gdb)
717 DefElem *security_item = NULL;
(gdb)
718 DefElem *leakproof_item = NULL;
(gdb)
719 List *set_items = NIL;
(gdb)
720 DefElem *cost_item = NULL;
(gdb)
721 DefElem *rows_item = NULL;
(gdb)
722 DefElem *support_item = NULL;
(gdb)
723 DefElem *parallel_item = NULL;
(gdb)
725 foreach(option, options)
(gdb)
727 DefElem *defel = (DefElem *) lfirst(option);
(gdb)
729 if (strcmp(defel->defname, "as") == 0)
(gdb)
731 if (as_item)
(gdb)
736 as_item = defel;
(gdb)
725 foreach(option, options)
(gdb) p *as_item
$16 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbf727 "as", arg = 0x1daf730,
defaction = DEFELEM_UNSPEC, location = 134}
(gdb) n
727 DefElem *defel = (DefElem *) lfirst(option);
(gdb)
729 if (strcmp(defel->defname, "as") == 0)
(gdb)
738 else if (strcmp(defel->defname, "language") == 0)
(gdb)
740 if (language_item)
(gdb)
745 language_item = defel;
(gdb)
725 foreach(option, options)
(gdb) p *language_item
$17 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbfcbe "language",
arg = 0x1daf820, defaction = DEFELEM_UNSPEC, location = 298}
(gdb) n
792 if (as_item)
提取item中的arg
(gdb) n
793 *as = (List *) as_item->arg;
(gdb)
802 if (language_item)
(gdb) p *as
$18 = (List *) 0x1daf730
(gdb) n
803 *language = strVal(language_item->arg);
(gdb)
813 if (transform_item)
(gdb) p *language
$19 = 0x1daf5a8 "plpgsql"
(gdb) n
815 if (windowfunc_item)
(gdb)
817 if (volatility_item)
(gdb)
819 if (strict_item)
(gdb)
821 if (security_item)
(gdb)
823 if (leakproof_item)
(gdb)
825 if (set_items)
(gdb)
827 if (cost_item)
(gdb)
835 if (rows_item)
(gdb)
843 if (support_item)
(gdb)
845 if (parallel_item)
(gdb)
847 }
(gdb)
CreateFunction (pstate=0x1dd4c88, stmt=0x1daf8c8) at functioncmds.c:989
989 languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
DONE!
四、参考资料
N/A
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
软考中级精品资料免费领
- 历年真题答案解析
- 备考技巧名师总结
- 高频考点精准押题
- 资料下载
- 历年真题
193.9 KB下载数265
191.63 KB下载数245
143.91 KB下载数1148
183.71 KB下载数642
644.84 KB下载数2756
相关文章
发现更多好内容- Java 中 Arrays 类的常用方法有哪些?(java中arrays类的方法有哪些)
- 在 Java 中遇到“无法解析为类型”的问题该如何解决?(java中无法解析为类型怎么解决)
- Java Thread 类的构造方法究竟是什么?(java thread类的构造方法是什么)
- Java 中 int 数组如何实现拷贝?(java int数组拷贝怎么实现)
- Java FX 在可访问性方面都有哪些重要的考虑呢?(java javafx在可访问性方面有哪些考虑 )
- Java 的 domain 具体有哪些合法的格式呢?(Java的domain有哪些合法格式)
- Java 中 shuffle 函数的参数该如何设置?(Java中shuffle函数的参数设置)
- Java 重构到底有哪些作用呢?(Java重构有什么用)
- 在 Java 中如何利用 Vector 来定义二维数组?(java中怎么用vector定义二维数组)
- 为何 Java 环境变量配置总是难以成功?(java环境变量配置为什么不成功)
猜你喜欢
AI推送时光机PostgreSQL 源码解读(219)- Locks(Overview)
数据库2024-04-02
PostgreSQL 源码解读(218)- spinlock的实现
数据库2024-04-02
PostgreSQL 源码解读(248)- HTAB动态扩展图解#2
数据库2023-05-31
PostgreSQL 源码解读(247)- HTAB动态扩展图解#1
数据库2024-04-02
咦!没有更多了?去看看其它编程学习网 内容吧