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