1、背景知识
1) flex: The Fast Lexical Analyzer
2) Bison: A general-purpose parser generator
3) C语言
前二者请自行查阅文档吧,中文资料也很多,OSChina上搜索就可以看到它们的介绍
2、过程
首先,有些语言是区分函数与过程的,有些没有,但它们其实没有本质区别,还是一个东西。对于PG来讲,过程就是RETURNS VOID函数,因此CREATE PROCEDURE其实也就是创建一个同义词。我们来看CREATE FUNCTION(src/backend/paser/gram.y):
CreateFunctionStmt:
CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
RETURNS func_return createfunc_opt_list opt_definition
{
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $4;
n->parameters = $5;
n->returnType = $7;
n->options = $8;
n->withClause = $9;
$$ = (Node *)n;
}
| CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition
{
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $4;
n->parameters = mergeTableFuncParameters($5, $9);
n->returnType = TableFuncTypeName($9);
n->returnType->location = @7;
n->options = $11;
n->withClause = $12;
$$ = (Node *)n;
}
| CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
createfunc_opt_list opt_definition
{
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $4;
n->parameters = $5;
n->returnType = NULL;
n->options = $6;
n->withClause = $7;
$$ = (Node *)n;
}
;
3、函数语法说明
可以看出,我们需要做的事情很少,第一是定义PROCEDURE关键字,第二是找到VOID参数定义
1) 定义 PROCEDURE 关键字,我们可以从程序中看到它其实已经定义过了,跟FUNCTION同属于非保留关键字,印象中v9.2还无此定义。PG关键字的分类可以自行阅读文档,此外gram.y当中的定义还有很多讲究,需要注意的地方挺多;
2) 无返回值是一个特殊的系统类型:void,我们在创建函数时直接指定即可;
3) 函数语法我们只需要第一个,因为后两个都是有返回值的;
4、我们的过程语法为:
CreateProcedureStmt:
CREATE opt_or_replace PROCEDURE func_name func_args_with_defaults
createfunc_opt_list opt_definition
{
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $4;
n->parameters = $5;
n->returnType = makeTypeName("void");
n->options = $6;
n->withClause = $7;
$$ = (Node *)n;
}
;
当然还需要在stmt定义里边添加CreateProcedureStmt,在 %type<node>里边添加CreateProcedureStmt定义。
这些学习bison或者yacc语法就能知道怎么回事,最简单的是像这样找一个相似语法照葫芦画瓢。
5、make & make install,创建一个无返回值函数测试一下:
postgres=# CREATE PROCEDURE check_proc() AS
postgres-# $$
postgres$# DECLARE passed BOOLEAN;
postgres$# BEGIN
postgres$# SELECT true INTO passed;
postgres$# END;
postgres$# $$ LANGUAGE plpgsql;
CREATE FUNCTION
postgres=#
至此,作为一个语法结构,它已经可以运行了,当然很多细节还需要处理,作为一个示例到这里就足够说明问题,不再继续。