这一节描述了一个触发器函数的接口的低层细节。只有用 C 编写触发器函数时才需要这些信息。如果你使用一种更高层的语言,那么这些细节就不需要你来处理。在大部分情况下,你应该优先考虑使用一种过程语言。每一种过程语言的文档阐述了如何使用那种语言编写一个触发器。
触发器函数必须使用“版本 1”函数管理器接口。
当一个函数被触发器管理器调用时,不会给它传递任何常规的参数,但是会有一个“context”指针传递给它,该指针指向一个TriggerData
结构。C 函数可以通过执行一个宏来检查它们是否是从触发器管理器被调用:
CALLED_AS_TRIGGER(fcinfo)
它会展开成为:
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
如果这返回真,那么将fcinfo->context
造型成类型TriggerData *
并且利用所指向的TriggerData
结构就是安全的。该函数不能修改该TriggerData
结构或者它指向的任何数据。
struct TriggerData
被定义在commands/trigger.h
中:
typedef struct TriggerData { NodeTag type; TriggerEvent tg_event; Relation tg_relation; HeapTuple tg_trigtuple; HeapTuple tg_newtuple; Trigger *tg_trigger; Buffer tg_trigtuplebuf; Buffer tg_newtuplebuf; Tuplestorestate *tg_oldtable; Tuplestorestate *tg_newtable; } TriggerData;
其中的成员被定义如下:
type
总是T_TriggerData
.
tg_event
描述该函数是为什么事件被调用的。你可以使用下列宏来检查tg_event
:
TRIGGER_FIRED_BEFORE(tg_event)
如果该触发器在操作前被引发则返回真。
TRIGGER_FIRED_AFTER(tg_event)
如果该触发器在操作后被引发则返回真。
TRIGGER_FIRED_INSTEAD(tg_event)
如果该触发器被引发替代操作则返回真。
TRIGGER_FIRED_FOR_ROW(tg_event)
如果该触发器为一个行级事件而引发则返回真。
TRIGGER_FIRED_FOR_STATEMENT(tg_event)
如果该触发器为一个语句级事件而引发则返回真。
TRIGGER_FIRED_BY_INSERT(tg_event)
如果该触发器由一个INSERT
命令引发则返回真。
TRIGGER_FIRED_BY_UPDATE(tg_event)
如果该触发器由一个UPDATE
命令引发则返回真。
TRIGGER_FIRED_BY_DELETE(tg_event)
如果该触发器由一个DELETE
命令引发则返回真。
TRIGGER_FIRED_BY_TRUNCATE(tg_event)
如果该触发器由一个TRUNCATE
命令引发则返回真。
tg_relation
一个结构指针,该结构描述该触发器为其引发的关系。关于这个结构的细节请参考utils/rel.h
。最有趣的东西是tg_relation->rd_att
(该关系元组的描述符)和tg_relation->rd_rel->relname
(关系名称,该类型不是char*
而是NameData
。如果你需要该名称的一个拷贝,可使用SPI_getrelname(tg_relation)
来得到一个char*
)。
tg_trigtuple
一个该触发器为其引发的行的指针。这是被插入、更新或删除的行。如果这个触发器是为一个INSERT
或DELETE
而引发,在你不想把该行替换成另一行(在INSERT
的情况中)或不想跳过该操作时你应该从该函数中返回它。
对于外部表上的触发器,此中的系统列值未被指定。
tg_newtuple
如果该触发器为一个UPDATE
而引发,则是一个指向该行新版本的指针。如果是为一个INSERT
或DELETE
而引发,则是NULL
。如果事件是一个UPDATE
并且你并不想用一个不同的行替换这个行或者不想跳过该操作时,你必须从函数中返回它。对于外部表上的触发器,此中的系统列值未被指定。
tg_trigger
一个指向类型为Trigger
的结构的指针,定义在utils/reltrigger.h
中:
typedef struct Trigger { Oid tgoid; char *tgname; Oid tgfoid; int16 tgtype; char tgenabled; bool tgisinternal; Oid tgconstrrelid; Oid tgconstrindid; Oid tgconstraint; bool tgdeferrable; bool tginitdeferred; int16 tgnargs; int16 tgnattr; int16 *tgattr; char **tgargs; char *tgqual; char *tgoldtable; char *tgnewtable; } Trigger;
其中tgname
是该触发器的名称,tgnargs
是tgargs
中参数的数量,而tgargs
是一个指向CREATE TRIGGER
语句中指定的参数的指针数组。其他成员只用于内部用途。
tg_trigtuplebuf
包含tg_trigtuple
的缓冲区。如果没有那个元组或者它没有被存储在一个磁盘缓冲区中,则为InvalidBuffer
。
tg_newtuplebuf
包含tg_newtuple
的缓冲区。如果没有那个元组或者它没有被存储在一个磁盘缓冲区中,则为InvalidBuffer
。
tg_oldtable
指向Tuplestorestate
类型的结构的指针,
该指针包含由tg_relation
指定的格式的零个或多个行,
如果不存在OLD TABLE
转换关系,则指向NULL
指针。
tg_newtable
指向Tuplestorestate
类型的结构的指针,
该指针包含由tg_relation
指定的格式的零个或多个行,
如果不存在NEW TABLE
转换关系,则指向NULL
指针。
要想允许通过SPI发布的查询引用转换表,请参阅 SPI_register_trigger_data。
一个触发器函数必须返回一个HeapTuple
指针或一个NULL
指针(不是一个 SQL 空值,也就是不会设置isNull
为真)。如果你不希望修改正在被操作的行,要小心地根据情况返回tg_trigtuple
或tg_newtuple
。