受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

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

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

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

$TG_name #

CREATE TRIGGER语句中触发器的名称。

$TG_relid #

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

$TG_table_name #

触发器函数因其而被调用的表的名称。

$TG_table_schema #

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

$TG_relatts #

表列名构成的 Tcl 列表,其前面带有一个空列表元素。因此,使用Tcllsearch命令在该列表中查找列名时,返回的元素编号会从 1 开始表示第一列,这与PostgreSQL中列的惯常编号方式一致。(空列表元素也会出现在已删除列的位置上,这样其右侧列的属性编号仍然正确。)

$TG_when #

其值为字符串BEFOREAFTERINSTEAD OF,具体取决于触发器事件的类型。

$TG_level #

其值为字符串ROWSTATEMENT,取决于触发器事件的类型。

$TG_op #

其值为字符串INSERTUPDATEDELETETRUNCATE,取决于触发器事件的类型。

$NEW #

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

$OLD #

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

$args #

CREATE TRIGGER语句中传给函数的参数组成的 Tcl 列表。在函数体中也可以通过$1 ... $n访问这些参数。

触发器函数的返回值可以是字符串OKSKIP,也可以是一个“列名/值”对列表。如果返回值是OK,引发该触发器的操作(INSERT/UPDATE/DELETE)会正常继续。SKIP告诉触发器管理器静默抑制针对这一行的该操作。如果返回的是列表,则表示 PL/Tcl 要向触发器管理器返回一个修改后的行;该修改后行的内容由列表中的列名和值指定。凡是未在列表中提及的列,都会被设为空值。返回修改后的行只对行级BEFORE INSERTUPDATE触发器有意义;对于这类触发器,插入的将是修改后的行,而不是$NEW中给出的那一行。返回修改后的行对行级INSTEAD OF INSERTUPDATE触发器也有意义,在这种情况下,返回的行将被用作INSERT RETURNINGUPDATE RETURNING子句的源数据。对于行级BEFORE DELETEINSTEAD OF DELETE触发器,返回修改后的行与返回OK效果相同,也就是操作继续。对于所有其他类型的触发器,返回值都会被忽略。

Tip

可使用 Tcl 的array get命令,根据修改后元组的数组表示构造结果列表。

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

注意,触发器函数本身并不知道列名;列名是通过触发器参数提供的。这使得该触发器函数可以在不同的表上重用。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。