Chapter 16. 触发器

Table of Contents
16.1. 创建触发器
16.2. 与触发器管理器交互
16.3. 数据改变的可视性
16.4. 例子

PostgreSQL 拥有服务器端函数接口. 服务器端函数可以用SQL,C 或者任意已定义的过程语言写. 触发器函数可以用除SQL以外的任何这些语言书写. 语句级和行一级的触发器现在都支持了。 目前你可以在INSERTDELETEUPDATE上 BEFORE 或 AFTER (之前或之后)执行一个触发器过程,不管是没修改一行一次还是 每个 SQL 语句一次都行。

16.1. 创建触发器

如果发生了触发器事件,触发器管理器(由执行器调用)初始化 信息结构TriggerData(下面描述)并调用触发器函数来操作事件.

触发器函数必须在创建触发器之前,作为一个没有参数并且返回trigger类型 的函数定义. (触发器函数通过 TriggerData 结构接收其输入, 而不是用普通函数参数那种形式。) 如果你用C写这个函数,它必须使用"版本 1"的函数管理器接口.

创建触发器的语法如下在 PostgreSQL 7.3 参考手册 里描述。

触发器函数返回HeapTuple给调用它的执行者. 这个返回值在那些 AFTER 的 触发器上被忽略,但它允许那些 BEFORE 触发器用来:

注意,CREATE TRIGGER句柄将不进行任何初始化工作. 这一点将在以后进行修改.

如果多于一个触发器为同样的事件定义在同样的关系上, 触发器将按照由名字的字母顺序排序的顺序触发。 如果是 BEFORE 触发器,每个触发器返回的可能已经被修改过的元组 成为下一个触发器的输入。如果 BEFORE 触发器返回 NULL, 那么其操作被丢弃并且随后的触发器不会被触发。

如果一个触发器函数执行 SQL-查询(使用 SPI) 那么这些查询可能再次触发触发器. 这就是所谓的级联触发器.对级联触发器的级联深度没有明确的限制. 有可能出现级联触发器导致同一个触发器的递归调用的情况 --- 比如,一个 INSERT 触发器可能执行一个查询, 把一个额外的元组插入同一个表中,导致 INSERT 触发器 再次击发。避免这样的无穷递归的问题是触发器程序员的责任。

在定义一个触发器的时候,我们可以声明一些参数。 在触发器定义里面包含参数的目的是允许类似需求的不同触发器 调用同一个函数。比如,我们可能有一个通用的触发器函数, 接受两个字段名字,把当前用户放在第一个,而当前时间戳在第二个。 只要我们写得恰当,那么这个触发器函数就可以和触发它的特定表无关。 这样同一个函数就可以用于有着合适字段的任何表的 INSERT 时间,实现自动跟踪交易表中的记录创建之类的问题。如果定义成一个 UPDATE 触发器,我们还可以用它跟踪最后更新的事件。