PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

42.6. PL/Tcl 中的触发器函数 #

触发器函数可以用 PL/Tcl 编写。 PostgreSQL 要求被当作触发器调用的函数 必须被声明为无参数且返回类型为 trigger 的函数。

来自触发器管理器的信息通过以下变量传给函数体:

$TG_name

来自 CREATE TRIGGER 语句的触发器名。

$TG_relid

导致触发器函数被调用的表的对象 ID。

$TG_table_name

导致触发器函数被调用的表的名称。

$TG_table_schema

导致触发器函数被调用的表的模式。

$TG_relatts

表列名的 Tcl 列表,前面有一个空的列表元素。 因此,用 Tcl 的 lsearch 命令在该列表中查找一个列名会返回 该元素从 1 开始的编号,与 PostgreSQL 中列的惯常编号方式 一致。 (被删除列的位置上也会出现空的列表元素,从而让它们右侧列的 属性编号保持正确。)

$TG_when

字符串 BEFORE、AFTER 或 INSTEAD OF,取决于触发器事件的类型。

$TG_level

字符串 ROW 或 STATEMENT, 取决于触发器事件的类型。

$TG_op

字符串 INSERT、UPDATE、 DELETE 或 TRUNCATE, 取决于触发器事件的类型。

$NEW

一个关联数组,包含 INSERT 或 UPDATE 动作的新表行的值, 对 DELETE 为空。 该数组以列名索引。为空的列不会出现在数组中。 对于语句级触发器,此变量不会被设置。

$OLD

一个关联数组,包含 UPDATE 或 DELETE 动作的旧表行的值, 对 INSERT 为空。 该数组以列名索引。为空的列不会出现在数组中。 对于语句级触发器,此变量不会被设置。

$args

CREATE TRIGGER 语句中给出的函数参数的 Tcl 列表。这些参数在函数体中也可以作为 $1 ... $n 访问。

触发器函数的返回值可以是字符串 OK 或 SKIP 之一,或者一个 列名/值对的列表。 如果返回值是 OK,触发该触发器的操作 (INSERT/UPDATE/DELETE) 将正常继续。 SKIP 告诉触发器管理器静默地抑制对这一行的该 操作。如果返回一个列表,它告诉 PL/Tcl 向触发器管理器返回一个被 修改的行;被修改行的内容由列表中的列名和值指定。 列表中未提到的任何列都被设为空。 返回被修改的行只对行级 BEFORE INSERT 或 UPDATE 触发器有意义——被修改的行将取代 $NEW 中给出的行被插入;或者对行级 INSTEAD OF INSERT 或 UPDATE 触发器有意义——返回的行会被用作 INSERT RETURNING 或 UPDATE RETURNING 子句的源数据。 在行级 BEFORE DELETE 或 INSTEAD OF DELETE 触发器中,返回被修改的行 与返回 OK 具有相同的效果,即操作继续进行。 触发器返回值对所有其他类型的触发器都会被忽略。

Tip

结果列表可以用 array get Tcl 命令从被修改元组 的数组表示生成。

下面是一个小型示例触发器函数,它强制表中的一个整数值跟踪对该行 执行的更新次数。对新插入的行,该值被初始化为 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 FUNCTION trigfunc_modcount('modcnt');

注意,触发器函数本身并不知道列名;列名由触发器参数提供。 这让触发器函数能够与不同的表一起复用。