Chapter 21. 触发器

Table of Contents
21.1. 创建触发器
21.2. 与触发器管理器交互
21.3. 数据改变的可视性
21.4. 例子

Postgres 拥有服务器端函数接口. 服务器端函数可以用 SQL,PLPGSQL,TCL,或者C写. 触发器函数可以用除SQL以外的任何这些语言书写. 要注意当前版本还不支持语句级(STATEMENT-level)的触发器事件. 目前你可以在 INSERT, DELETE 或 UPDATE 一条元组上声明 BEFORE 或 AFTER (之前或之后)作为触发器事件.

21.1. 创建触发器

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

触发器函数必须作为一个没有参数并且返回 opaque 的函数在创建触发器之前创建. 如果你用C写这个函数,它必须使用 "版本 1" 的函数管理器接口.

创建触发器的语法如下:

CREATE TRIGGER trigger [ BEFORE | AFTER ] [ INSERT | DELETE | UPDATE [ OR ... ] ]
    ON relation FOR EACH [ ROW | STATEMENT ]
    EXECUTE PROCEDURE procedure
     (args);
    
这里的参数是:

trigger

如果你想删除触发器,那么这是所使用的触发器的名称. 它被用做 DROP TRIGGER 命令的一个参数.

BEFORE, AFTER

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

INSERT, DELETE, UPDATE

命令的下一元素决定在什么事件上触发该函数.多个事件可以用 OR 分隔声明.

relation

关系名,决定该事件应用于哪个表.

ROW, STATEMENT

FOR EACH 子句决定该触发器是为每个受影响的行触发还是在整个语句完成之前 (或之后)触发.

procedure

过程名就是调用的函数.

args

放在 TriggerData 结构里面传给函数的参数. 传递参数给函数的目的是为了允许类似要求的不同的触发器调用同样的函数.

同样,procedure还 可以用于触发不同的关系(这些函数被命名为"通用触发器函数")。

做为使用上面两个特性的例子,可以有一个通用函数把两个字段名称作为参数: 把当前用户作为一个参数而把当前时标做为另一个参数. 这样就允许我们在 INSERT 事件上写一个触发器来自动跟踪 一个事务表里的元组的创建.如果用于一个 UPDATE 事件, 同样我们可以当做 "最后更新"(last updated)函数来用.

触发器函数返回 HeapTuple 给调用它的执行器. 这个返回在那些在 INSERT,DELETE 或 UPDATE 操作之后 执行的触发器上被忽略,但它允许那些 BEFORE 触发器用来:

注意,CREATE TRIGGER 句柄将不进行任何初始化工作. 这一点将在以后进行修改.同样, 如果多于一个触发器为同样的事件定义在同样的关系上, 触发器触发的顺序将不可预料.这一点以后也会修改.

如果一个触发器函数执行 SQL-查询(使用 SPI) 那么这些查询可能再次触发触发器. 这就是所谓的嵌套触发器.对嵌套触发器的嵌套深度没有明确的限制.

如果一个触发器是被 INSERT 触发并且插入一个新行到同一关系中, 然后该触发器将被再次触发.目前对这种情况没有提供任何同步(等)的措施, 这一点也可能会修改. 目前,回归测试里有一个函数 funny_dup17() 使用了一些技巧避 免对自身的递归(嵌套)调用...