43.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

可以为BEFOREAFTER或者INSTEAD OF,具体的选择取决于触发器事件的类型。

$TG_level

可以为ROW或者STATEMENT,取决于触发器事件的类型。

$TG_op

可以为INSERTUPDATEDELETE或者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 DELETEINSTEAD OF DELETE触发器中,返回修改后的行和返回OK有相同的影响, 即操作继续。所有其他类型的触发器都忽略触发器返回值。

提示

结果列表可以使用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 PROCEDURE trigfunc_modcount('modcnt');

注意触发器过程本身不知道列名,列名由触发器参数提供。这让触发器过程可以被重用于不同的表。