37.6. PL/Tcl 中的触发器函数 #
可以用 PL/Tcl 编写触发器函数。PostgreSQL 要求作为触发器调用的函数必须声明为无参数、返回类型为 trigger 的函数。
触发器管理器的信息通过下列变量传入过程体:
$TG_nameCREATE TRIGGER语句中触发器的名称。$TG_relid导致触发器过程被调用的表的对象 ID。
$TG_relatts表列名构成的 Tcl 列表,其前面带有一个空列表元素。因此,使用 Tcl 的
lsearch命令在该列表中查找列名时,返回的元素编号会从 1 开始表示第一列,这与 PostgreSQL 中列的惯常编号方式一致。(空列表元素也会出现在已删除列的位置上,这样其右侧列的属性编号仍然正确。)$TG_when根据触发器事件的类型,为字符串
BEFORE或AFTER。$TG_level根据触发器事件的类型,为字符串
ROW或STATEMENT。$TG_op字符串
INSERT、UPDATE或DELETE,取决于触发器事件的类型。$NEW对于
INSERT或UPDATE动作,这是一个包含新表行值的关联数组;对于DELETE则为空。该数组以列名为索引。值为空值的列不会出现在数组中。对于语句级触发器,不会设置这个变量。$OLD对于
UPDATE或DELETE动作,这是一个包含旧表行值的关联数组;对于INSERT则为空。该数组以列名为索引。值为空值的列不会出现在数组中。对于语句级触发器,不会设置这个变量。$args一个 Tcl 列表,包含
CREATE TRIGGER语句中给出的过程参数。这些参数也可以在过程体中以$1...$的形式访问。n
触发器过程的返回值可以是字符串 OK 或
SKIP,也可以是 array get Tcl 命令返回的列表。如果返回值为 OK,触发该触发的操作(INSERT/UPDATE/DELETE)将正常进行。SKIP 告诉触发器管理器静默地取消针对该行的操作。如果返回的是列表,则告诉 PL/Tcl 向触发器管理器返回一个修改后的行,用该行代替 $NEW 中给出的行被插入。(这只对 INSERT 和
UPDATE 有效。)不用说,所有这些只在触发器是
BEFORE 且为 FOR EACH ROW 时才有意义;否则返回值会被忽略。
下面是一个简单的触发器函数示例,强制用表中的一个整数值记录该行的更新次数。新插入的行将此值初始化为 0,以后每次更新操作都将其递增。
CREATE FUNCTION trigfunc_modcount() RETURNS trigger AS $$
switch $TG_op {
INSERT {
set NEW($1) 0
}
UPDATE {
set NEW($1) $OLD($1)
incr NEW($1)
}
default {
return OK
}
}
return [array get NEW]
$$ LANGUAGE pltcl;
CREATE TABLE mytab (num integer, description text, modcnt integer);
CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
FOR EACH ROW EXECUTE PROCEDURE trigfunc_modcount('modcnt');注意,触发器函数本身不知道列名,列名通过触发器参数提供。这样,同一个触发器函数就可以在不同表上复用。