Table of Contents
为了补充 Chapter 37 中讨论的触发器机制, PostgreSQL 还提供了事件触发器。与仅附着于单个表并且 只捕获 DML 事件的常规触发器不同,事件触发器在某个特定数据库中是全局的, 并且能够捕获 DDL 事件。
与常规触发器类似,事件触发器可以用任何支持事件触发器的过程语言编写,也可以 用 C 编写,但不能用纯 SQL 编写。
只要与事件触发器关联的事件在其定义所在数据库中发生,事件触发器就会被触发。 目前支持的事件有 ddl_command_start、 ddl_command_end、 table_rewrite 和 sql_drop。 未来版本可能会增加对更多事件的支持。
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
针对事件触发器本身的命令也不会引发该事件。
在事件触发器触发之前,不会检查受影响对象究竟存在还是不存在。
ddl_command_end 事件发生在与 ddl_command_start 相同的一组命令执行之后。 要获取这些 DDL 操作的更多细节,可在 ddl_command_end 事件触发器代码中使用集合返回函数 pg_event_trigger_ddl_commands()(见 Section 9.29)。注意,触发器是在这些动作已发生 之后(但在事务提交之前)触发的,因此读取系统目录时,看到的已是变更后的状态。
对于任何删除数据库对象的操作,sql_drop 事件都发生在 ddl_command_end 事件触发器之前。请注意,除了显而易见的 DROP 命令外,某些 ALTER 命令也会触发 sql_drop 事件。
要列出已删除的对象,可在 sql_drop 事件触发器代码中使用 集合返回函数 pg_event_trigger_dropped_objects()(见 Section 9.29)。注意,触发器是在这些对象已经从 系统目录中删除之后执行的,因此已无法再查找它们。
table_rewrite 事件发生在表即将因 ALTER TABLE 和 ALTER TYPE 命令中的某些 操作而被重写之前。虽然还有其他控制语句也可以重写表,例如 CLUSTER 和 VACUUM,但它们不会触发 table_rewrite 事件。要找出被重写表的 OID,请使用函数 pg_event_trigger_table_rewrite_oid();要找出重写的一个或多个 原因, 可使用函数 pg_event_trigger_table_rewrite_reason()(见 Section 9.29)。
事件触发器(与其他函数一样)不能在已中止的事务中执行。因此,如果 DDL 命令因 错误而失败,任何关联的 ddl_command_end 触发器都不会执行。 反之,如果 ddl_command_start 触发器因错误而失败,后续事 件触发器都不会触发,也不会尝试执行该命令本身。类似地,如果 ddl_command_end 触发器因错误而失败,DDL 语句的效果将被回 滚,就像包含该语句的事务在任何其他情况下中止时那样。
事件触发器通过命令 CREATE EVENT TRIGGER 创建。 为了创建事件触发器,必须先创建一个返回类型为 event_trigger 的特殊函数。 该函数不需要(也不能)返回值;这个返回类型仅用于表明该函数要作为事件触发器 被调用。
如果为某个特定事件定义了多个事件触发器,它们将按触发器名称的字母顺序触发。
触发器定义也可以指定一个 WHEN 条件,这样,例如, ddl_command_start 触发器就可以只针对用户希望拦截的特定命 令触发。这类触发器的一个常见用途是限制用户可执行的 DDL 操作范围。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。