本节介绍触发器函数接口的低级细节。只有在用 C 编写触发器函数时才需要这些信息。如果您使用的是更高级的语言,那么这些细节将由您代劳。在大多数情况下,您应该考虑使用过程语言,然后再用 C 编写触发器。每个过程语言的文档都解释了如何在该语言中编写触发器。
触发器函数必须使用 “版本 1” 函数管理器接口。
当函数被触发器管理器调用时,它不会传递任何正常参数,但会传递一个指向 TriggerData
结构的 “上下文” 指针。C 函数可以通过执行宏来检查它们是否是从触发器管理器调用的
CALLED_AS_TRIGGER(fcinfo)
它扩展为
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
如果返回 true,那么可以安全地将 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; TupleTableSlot *tg_trigslot; TupleTableSlot *tg_newslot; Tuplestorestate *tg_oldtable; Tuplestorestate *tg_newtable; const Bitmapset *tg_updatedcols; } TriggerData;
其中成员定义如下
类型
始终为 T_TriggerData
。
tg_event
描述调用函数的事件。您可以使用以下宏来检查 tg_event
TRIGGER_FIRED_BEFORE(tg_event)
如果触发器在操作之前触发,则返回 true。
TRIGGER_FIRED_AFTER(tg_event)
如果触发器在操作之后触发,则返回 true。
TRIGGER_FIRED_INSTEAD(tg_event)
如果触发器代替操作触发,则返回 true。
TRIGGER_FIRED_FOR_ROW(tg_event)
如果触发器针对行级事件触发,则返回 true。
TRIGGER_FIRED_FOR_STATEMENT(tg_event)
如果触发器针对语句级事件触发,则返回 true。
TRIGGER_FIRED_BY_INSERT(tg_event)
如果触发器由 INSERT
命令触发,则返回 true。
TRIGGER_FIRED_BY_UPDATE(tg_event)
如果触发器由 UPDATE
命令触发,则返回 true。
TRIGGER_FIRED_BY_DELETE(tg_event)
如果触发器由 DELETE
命令触发,则返回 true。
TRIGGER_FIRED_BY_TRUNCATE(tg_event)
如果触发器由 TRUNCATE
命令触发,则返回 true。
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
。如果您不想用不同的行替换此行或跳过该操作,则应从函数中返回此行。
tg_trigger
指向 Trigger
类型的结构的指针,在 utils/reltrigger.h
中定义
typedef struct Trigger { Oid tgoid; char *tgname; Oid tgfoid; int16 tgtype; char tgenabled; bool tgisinternal; bool tgisclone; 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_trigslot
包含 tg_trigtuple
的槽,如果没有这样的元组,则为 NULL
指针。
tg_newslot
包含 tg_newtuple
的槽,如果没有这样的元组,则为 NULL
指针。
tg_oldtable
指向 Tuplestorestate
类型的结构的指针,其中包含由 tg_relation
指定的格式的零个或多个行,如果没有 OLD TABLE
过渡关系,则为 NULL
指针。
tg_newtable
指向 Tuplestorestate
类型的结构的指针,其中包含由 tg_relation
指定的格式的零个或多个行,如果没有 NEW TABLE
过渡关系,则为 NULL
指针。
tg_updatedcols
对于 UPDATE
触发器,它是一个位图集,指示触发命令更新的列。通用触发器函数可以使用此来优化操作,而不必处理未更改的列。
例如,要确定具有属性编号 attnum
(从 1 开始)的列是否为该位图集的成员,请调用 bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols))
。
对于除 UPDATE
触发器以外的触发器,这将为 NULL
。
要允许通过 SPI 发出的查询引用过渡表,请参阅 SPI_register_trigger_data。
触发器函数必须返回一个 HeapTuple
指针或一个 NULL
指针(不是 SQL 空值,即,不要设置 isNull
为 true)。如果不想修改正在操作的行,请注意返回 tg_trigtuple
或 tg_newtuple
,具体情况视情况而定。
如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用 此表格 报告文档问题。