CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE 'langname' HANDLER call_handler LANCOMPILER 'comment'
TRUSTED 说明对该语言的调用句柄是安全的; 也就是说,它不会提供给非特权用户绕过访问限制的功能. 如果忽略这个关键字,只有具有 Postgres 超级用户权限的人可以使用这个语言创建新的函数.
新的过程化语言的名称.语言名是大小写无关的. 一个过程化语言不能覆盖 Postgres内建的语言.
call_handler 是预先注册过的函数名,它将被调用于执行 PL 过程.
LANCOMPILER 参数是将被插入 pg_language表 LANCOMPILER 字段的字串. 目前 Postgres不使用这个字段.
使用 CREATE LANGUAGE, Postgres 用户可以在 Postgres里注册一个新的语言. 因而,函数和触发器过程可以用这种新语言定义.要注册新 语言用户必须具有 Postgres 超级用户权限.
注意: 到 Postgres 7.1 以及更新的版本, 调用句柄必须与"版本 1(version 1)"的函数管理器接口结合在一起, 而不是旧风格的.
过程语言的调用句柄必须用一种编译语言,比如说 'C',并且在 Postgres 里注册成一个无参数输入,返回值是 opaque 类型(一个用于未声明或未定 义类型的容器)的函数.这就避免了调用句柄直接被查询当作函数调用. (当然,当一个此句柄提供的语言的PL(编程语言)函数要执行的时候, 会在调用时提供参数的)
调用句柄和其他新风格函数是通过同样的方法调用的: 它收到一个指向一个 FunctionCallInfoData 结构的指针, 该指针包含参数值和关于被调用函数的信息,并且它(调用句柄) 期望收到一个 Datum 结果(如果调用句柄期望返回一个SQL NULL结果 时,可能设置 FunctionCallInfoData 结构的isnull域.)调用句柄和普通被调函数的 区别是: FunctionCallInfoData 的flinfo->fn_oid 域将包含被调PL函数的 OID,而不是调用句柄本身的. 调用句柄必须用这个域判断要执行哪个函数.还有,传入的参数列表 是按照目标 PL 函数的声明设置的,而不是调用句柄的.
取得 pg_proc 表和分析被调过程参数和返回值类型的任务属于调用句柄. 过程中的 CREATE FUNCTION 的 AS 子句可在 prosrc 表的 pg_proc 字段里找到.这里有可能是过程语言的源文件本身 (像 PL/Tcl), 或者是一指向一个文件的路径或是其他任何一个告诉调用句柄如何处理 细节的东西.
通常,每条SQL语句都要调用同一个函数若干次. 调用句柄可以利用 flinfo->fn_extra字段 避免重复查找关于被调函数的信息的动作. 这个域初始时是 NULL,但是可以被调用句柄设置为指向有关PL函数 的信息.在随后的调用中,如果 flinfo->fn_extra 已经是非空了,那么 就可以使用这里的信息而忽略查找步骤.调用句柄必须注意的是 flinfo->fn_extra 是用于指向一片至少会保存到 本次查询结束的内存的,因为一个FmgrInfo数据结构可以保留那么长时间. 实现这个目地的方法之一是在 flinfo->fn_mcxt 声明的存储器环境里分配额外的书局;这样的书局通常将和 FmgrInfo 本身有相同的生存周期.但是句柄也可以选择使用一个更长生存期 的环境,这样它就可以跨查询缓存函数定义信息.
当一个PL函数被当做触发器调用时,不明确传递参数,只有 FunctionCallInfoData的 context 域指向一个 TriggerData 节点, 而不是象一次简单函数调用中那样是NULL. 一个PL句柄应该提供让PL函数获取触发器信息的机制.
使用 CREATE FUNCTION 创建函数.
使用 DROP LANGUAGE 删除一种过程语言.
请参考表 pg_language 获取更多信息:
Table "pg_language" Attribute | Type | Modifier ---------------+---------+---------- lanname | name | lanispl | boolean | lanpltrusted | boolean | lanplcallfoid | oid | lancompiler | text | lanname | lanispl | lanpltrusted | lanplcallfoid | lancompiler -------------+---------+--------------+---------------+------------- internal | f | f | 0 | n/a C | f | f | 0 | /bin/cc sql | f | f | 0 | postgres
过程语言的调用句柄通常都必须用 C 写,并且注册成 'internal' 或者 'C' 语言--取决于你是把它和后端链接起来还是作为动态库动态装载. 调用句柄不能使用老风格的 'C' 函数接口.
目前,过程语言的定义一旦建立就不能更改.
下面是一个用 'C' 写的PL 句柄的模板.
#include "executor/spi.h" #include "commands/trigger.h" #include "utils/elog.h" #include "fmgr.h" #include "access/heapam.h" #include "utils/syscache.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" PG_FUNCTION_INFO_V1(plsample_call_handler); Datum plsample_call_handler(PG_FUNCTION_ARGS) { Datum retval; if (CALLED_AS_TRIGGER(fcinfo)) { /* * Called as a trigger procedure */ TriggerData *trigdata = (TriggerData *) fcinfo->context; retval = ... } else { /* * Called as a function */ retval = ... } return retval; }
只需要在打点的地方添加几千行代码就可以完成 PL 调用句柄. 参考 CREATE FUNCTION 获取如何将其编译到一个可装载模块里面去.
下面的命令用于注册例子过程语言:
CREATE FUNCTION plsample_call_handler () RETURNS opaque AS '/usr/local/pgsql/lib/plsample.so' LANGUAGE 'C'; CREATE PROCEDURAL LANGUAGE 'plsample' HANDLER plsample_call_handler LANCOMPILER 'PL/Sample';