受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

Chapter 38. 事件触发器

为了补充 Chapter 37 中讨论的触发器机制, PostgreSQL 还提供了事件触发器。与仅附着于单个表并且 只捕获 DML 事件的常规触发器不同,事件触发器在某个特定数据库中是全局的, 并且能够捕获 DDL 事件。

与常规触发器类似,事件触发器可以用任何支持事件触发器的过程语言编写,也可以 用 C 编写,但不能用纯 SQL 编写。

38.1. 事件触发器行为概览 #

只要与事件触发器关联的事件在其定义所在数据库中发生,事件触发器就会被触发。 目前支持的事件有 ddl_command_startddl_command_endtable_rewritesql_drop。 未来版本可能会增加对更多事件的支持。

38.1.1. ddl_command_start #

ddl_command_start 事件发生在 DDL 命令即将执行之前。 此处的 DDL 命令包括:

  • CREATE

  • ALTER

  • DROP

  • COMMENT

  • GRANT

  • IMPORT FOREIGN SCHEMA

  • REINDEX

  • REFRESH MATERIALIZED VIEW

  • REVOKE

  • SECURITY LABEL

ddl_command_start 也会在 SELECT INTO 命令即将执行之前发生,因为它等价于 CREATE TABLE AS

但有一个例外:对于以共享对象为目标的 DDL 命令,不会发生该事件:

  • 数据库

  • 角色(角色定义和角色成员关系)

  • 表空间

  • 参数权限

  • ALTER SYSTEM

针对事件触发器本身的命令也不会引发该事件。

在事件触发器触发之前,不会检查受影响对象究竟存在还是不存在。

38.1.2. ddl_command_end #

ddl_command_end 事件发生在与 ddl_command_start 相同的一组命令执行之后。 要获取这些 DDL 操作的更多细节,可在 ddl_command_end 事件触发器代码中使用集合返回函数 pg_event_trigger_ddl_commands()(见 Section 9.29)。注意,触发器是在这些动作已发生 之后(但在事务提交之前)触发的,因此读取系统目录时,看到的已是变更后的状态。

38.1.3. sql_drop #

对于任何删除数据库对象的操作,sql_drop 事件都发生在 ddl_command_end 事件触发器之前。请注意,除了显而易见的 DROP 命令外,某些 ALTER 命令也会触发 sql_drop 事件。

要列出已删除的对象,可在 sql_drop 事件触发器代码中使用 集合返回函数 pg_event_trigger_dropped_objects()(见 Section 9.29)。注意,触发器是在这些对象已经从 系统目录中删除之后执行的,因此已无法再查找它们。

38.1.4. table_rewrite #

table_rewrite 事件发生在表即将因 ALTER TABLEALTER TYPE 命令中的某些 操作而被重写之前。虽然还有其他控制语句也可以重写表,例如 CLUSTERVACUUM,但它们不会触发 table_rewrite 事件。要找出被重写表的 OID,请使用函数 pg_event_trigger_table_rewrite_oid();要找出重写的一个或多个 原因, 可使用函数 pg_event_trigger_table_rewrite_reason()(见 Section 9.29)。

38.1.5. 已中止事务中的事件触发器 #

事件触发器(与其他函数一样)不能在已中止的事务中执行。因此,如果 DDL 命令因 错误而失败,任何关联的 ddl_command_end 触发器都不会执行。 反之,如果 ddl_command_start 触发器因错误而失败,后续事 件触发器都不会触发,也不会尝试执行该命令本身。类似地,如果 ddl_command_end 触发器因错误而失败,DDL 语句的效果将被回 滚,就像包含该语句的事务在任何其他情况下中止时那样。

38.1.6. 创建事件触发器 #

事件触发器通过命令 CREATE EVENT TRIGGER 创建。 为了创建事件触发器,必须先创建一个返回类型为 event_trigger 的特殊函数。 该函数不需要(也不能)返回值;这个返回类型仅用于表明该函数要作为事件触发器 被调用。

如果为某个特定事件定义了多个事件触发器,它们将按触发器名称的字母顺序触发。

触发器定义也可以指定一个 WHEN 条件,这样,例如, ddl_command_start 触发器就可以只针对用户希望拦截的特定命 令触发。这类触发器的一个常见用途是限制用户可执行的 DDL 操作范围。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。