pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
对以编译语言当前“版本 1”接口以外的语言编写的函数的所有调用(包括用户自定义过程语言中的函数、用 SQL 编写的函数以及使用版本 0 编译语言接口的函数),都要经过该特定语言的调用处理器函数。调用处理器的职责是以有意义的方式执行函数,例如解释所提供的源文本。本节描述如何编写语言调用处理器。这并不是一项常见任务——事实上,在 PostgreSQL 的历史上它只被完成过寥寥几次——但这一主题自然属于本章,而且这些材料也许能让人对 PostgreSQL 系统的可扩展本质有所认识。
过程语言的调用处理器是一个“普通”函数,它必须用一种编译语言(如 C)编写,并向 PostgreSQL 注册为不带参数并返回 language_handler 类型。这一特殊伪类型把该处理器标识为调用处理器,防止它在查询中被直接调用。
在 PostgreSQL 7.1 及之后的版本中,调用处理器必须遵循“版本 1”函数管理器接口,而不是旧风格接口。
调用处理器的调用方式与其他函数相同:它收到一个指向 FunctionCallInfoData struct(包含参数值和所调用函数的信息)的指针,并应返回一个 Datum 结果(如果它想返回 SQL NULL 结果,还可以设置 FunctionCallInfoData 结构的 isnull 字段)。调用处理器与普通被调函数的区别在于,FunctionCallInfoData 结构的 flinfo->fn_oid 字段将包含要调用的实际函数的 OID,而不是调用处理器自身的 OID。调用处理器必须使用此字段来确定要执行哪个函数。此外,传递的参数列表是按照目标函数(而不是调用处理器)的声明建立的。
获取 pg_proc 条目并分析被调用过程的参数和返回类型是调用处理器的职责。过程 CREATE FUNCTION 的 AS 子句可在 pg_proc 表条目的 prosrc 属性中找到。它可能是过程语言本身的源文本(如 PL/Tcl),也可能是指向文件的路径名,或者是任何能详细告诉调用处理器该做什么的东西。
同一函数在一个 SQL 语句中往往被调用多次。调用处理器可以利用 flinfo->fn_extra 字段避免对被调用函数信息的重复查找。该字段最初为 NULL,但调用处理器可以把它设置为指向有关 PL 函数的信息。在后续调用中,如果 flinfo->fn_extra 已非 NULL,就可以直接使用它并跳过信息查找步骤。调用处理器必须小心让 flinfo->fn_extra 指向至少能存活到当前查询结束的内存,因为 FmgrInfo 数据结构可能被保存那么久。一种做法是在 flinfo->fn_mcxt 指定的内存上下文中分配这些额外数据;这样的数据通常与 FmgrInfo 本身具有相同的生存期。但处理器也可以选择使用生存期更长的上下文,以便跨查询缓存函数定义信息。
当 PL 函数作为触发器被调用时,不传递显式参数,但 FunctionCallInfoData 的 context 字段指向一个 TriggerData 结点而不是像普通函数调用那样为 NULL。语言处理器应提供让 PL 函数获取触发器信息的机制。
这是一个用 C 编写的 PL 处理器的模板:
#include "postgres.h"
#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;
}
只需再加上几千行代码代替这些省略号即可完成调用处理器。关于如何把它编译成可装载模块,参见 第 9.5 节。
下面的命令随后注册这个示例过程语言:
CREATE FUNCTION plsample_call_handler () RETURNS language_handler
AS '/usr/local/pgsql/lib/plsample'
LANGUAGE C;
CREATE LANGUAGE plsample
HANDLER plsample_call_handler;
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。