↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 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 已结束支持。 请参阅 当前版本手册.

第 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 触发器再次触发。因此,在这种场景下,避免无限递归是触发器编写者自己的责任。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.