↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4
历史版本PostgreSQL 7.4 已于 2010 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

第 47 章 编写过程语言调用处理器

凡是不是使用当前针对编译型语言的“版本 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 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。