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

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 / 7.3 / 7.2 / 7.1 / 7.0 / 6.5 / 6.4
历史版本PostgreSQL 7.3 已于 2007 年 11 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

第 16 章 触发器

PostgreSQL 有多种服务器端函数接口。 服务器端函数可以用 SQL、C 或任何已定义的过程语言编写。触发器 函数可以用 C 和大多数过程语言编写,但不能用 SQL 编写。注意, 当前版本不支持语句级触发器事件。目前可以把 BEFORE 或 AFTER 指定在一个元组的 INSERT、DELETE 或 UPDATE 上作为触发器事件。

16.1. 触发器定义 #

一旦触发器事件发生,触发器管理器(由执行器调用)就会建立一个 TriggerData 信息结构(下文描述),并调用触发器 函数来处理该事件。

必须先定义触发器函数,之后才能创建触发器本身。触发器函数必须 声明为不接受参数并返回类型 trigger 的函数。 (触发器函数通过一个 TriggerData 结构接收输入,而不是以普通函数参数的形式。)如果函数用 C 编写, 它必须使用“版本 1”函数管理器接口。

创建触发器的语法是:

CREATE TRIGGER trigger [ BEFORE | AFTER ] [ INSERT | DELETE | UPDATE [ OR ... ] ]
    ON relation FOR EACH [ ROW | STATEMENT ]
    EXECUTE PROCEDURE procedure
     (args);

其中各个参数为:

trigger

触发器的名称必须与同一表上的所有其他触发器不同。如果将来 需要删除该触发器,就要用到这个名称。

BEFORE
AFTER

决定函数是在事件之前还是之后被调用。

INSERT
DELETE
UPDATE

命令的下一个元素决定哪些事件会触发该函数。可以用 OR 分隔 指定多个事件。

relation

关系名指出该事件作用于哪个表。

ROW
STATEMENT

FOR EACH 子句决定触发器是针对每个受影响的行触发,还是在 整条语句完成之前(或之后)触发。目前只支持 ROW 的情形。

procedure

过程名是要被调用的函数。

args

通过 TriggerData 结构传给函数的参数。它要么 为空,要么是一个由一个或多个简单字面常量组成的列表(它们将 作为字符串传给函数)。

在触发器定义中包含参数,是为了让需求相似的不同触发器能够 调用同一个函数。举例来说,可以有一个通用触发器函数,它接受 两个列名作为参数,把当前用户写入其中一个列,把当前时间戳写入 另一个列。只要编写得当,这个触发器函数就应独立于它所作用的 具体表。因此,同一个函数可用于任何具有适当字段的表上的 INSERT 事件,例如自动跟踪某个事务表中记录的创建。如果把它 定义成 UPDATE 触发器,还可以用来跟踪最近更新事件。

触发器函数向调用它的执行器返回一个 HeapTuple。 该返回值对于在操作之后(AFTER)触发的触发器会被忽略,但它 允许 BEFORE 触发器:

  • 返回一个 NULL 指针,以跳过对当前元组的操作 (这样该元组就不会被插入/更新/删除)。

  • 仅对于 INSERT 和 UPDATE 触发器,返回的元组会成为将要插入 的元组,或替换正在更新的元组。这使得触发器函数可以修改 即将插入或更新的行。

不打算引发上述任何一种行为的 BEFORE 触发器,必须注意把传给 它的同一个 NEW 元组原样返回。

注意,CREATE TRIGGER 处理器不执行任何初始化。这一点将来可能 会改变。

如果为同一关系上的同一事件定义了多个触发器,它们会按名称的 字母顺序触发。对于 BEFORE 触发器,每个触发器返回的、可能已经 被修改过的元组都会成为下一个触发器的输入。如果任何 BEFORE 触发器返回 NULL,则会放弃该操作,并且后续触发器 不会再触发。

如果触发器函数执行 SQL 查询(使用 SPI),那么这些查询可能 会再次触发触发器。这就是所谓的级联触发器。对级联层数没有 直接限制。级联还有可能导致同一个触发器被递归调用 —— 例如, 一个 INSERT 触发器可能执行一条向同一个表再插入一个元组的 查询,从而导致该 INSERT 触发器再次触发。因此,在这种场景下, 避免无限递归是触发器编写者自己的责任。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。