On this page
38.3. 用 C 编写触发器函数
本节描述了触发功能的接口的底层细节。仅在用 C 编写触发器函数时才需要此信息。如果您使用高级语言,则将为您处理这些详细信息。在大多数情况下,您应该在使用 C 编写触发器之前考虑使用一种过程语言。每种过程语言的文档都说明了如何用该语言编写触发器。
触发功能必须使用“版本 1”功能 Management 器界面。
触发器 Management 器调用函数时,不会传递任何常规参数,而是会传递指向TriggerData
结构的“上下文”指针。 C 函数可以通过执行宏来检查是否从触发器 Management 器中调用了它们:
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;
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)
如果触发器在操作之前触发,则返回 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
(关系 Tuples 的 Descriptors)和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
- 指向
utils/reltrigger.h
中定义的Trigger
类型的结构的指针:
- 指向
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
的缓冲区(如果没有这样的 Tuples 或未将其存储在磁盘缓冲区中)。
- 包含
tg_newtuplebuf
- 包含
tg_newtuple
或InvalidBuffer
的缓冲区(如果没有这样的 Tuples 或未将其存储在磁盘缓冲区中)。
- 包含
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
* true)。如果您不想修改正在操作的行,请小心地根据需要返回tg_trigtuple
或tg_newtuple
。