Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

37.3. 使用 C 编写触发器功能 #

本部分介绍触发器功能的接口的底层细节。仅在使用 C 编写触发器功能时才需要了解此信息。如果你使用的是更高级的语言,则会为你处理这些细节。大多数情况下,你应考虑在使用 C 编写触发器前使用过程语言。每个过程语言的文档会说明如何在该语言中编写触发器。

触发器功能必须使用 版本 1 函数管理器接口。

触发器管理器调用了一个函数时,不会传递任何普通的参数,但会传递一个指向 TriggerData 结构的 context 指针。C 函数可以通过执行宏

CALLED_AS_TRIGGER(fcinfo)

来检查它们是否是由触发器管理器调用的

((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))

如果这返回 true,则可将 fcinfo->context 转换为类型 TriggerData *,并使用所指向的 TriggerData 结构。该函数 不能 更改 TriggerData 结构或它指向的任何数据。

struct TriggerDatacommands/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;

其中,成员被定义如下

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(关系元组的描述符)和 tg_relation->rd_rel->relname(关系名称;类型不是 char* 而是 NameData;如果需要名称的副本,请使用 SPI_getrelname(tg_relation) 来获取 char*)。

tg_trigtuple

触发器触发所在行的指针。即待插入、更新或删除的行。如果此触发器为 INSERTDELETE 触发,那么如果你不想使用另一行替换行(在 INSERT 的情况下),或者跳过操作,则应将此从函数中返回。对于外键表上的触发器,此处系统列的值不作说明。

tg_newtuple

如果触发器为 UPDATE 触发,则指向新版本行的指针;如果为 INSERTDELETE 触发,则为 NULL。如果事件为 UPDATE 触发且你不想用另一行替换此行或跳过操作,则应将此从函数中返回。对于外键表上的触发器,此处系统列的值不作说明。

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 是触发器的名称,tgnargstgargs 中的参数数,tgargsCREATE 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 触发器,bitmap 设置,用于指示由触发命令更新的列。通用触发器函数可使用此功能优化操作,避免处理未更改的列。

例如,要确定属性编号为 attnum (1 为基) 的列是否是此 bitmap 集合的成员,请调用 bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols))

对于 UPDATE 触发器以外的触发器,此值将为 NULL

如希望通过 SPI 发出的查询能引用转换表,请参见 SPI_register_trigger_data

触发器函数必须返回 HeapTuple 指针或 NULL 指针(不是 SQL null 值,即不要将 isNull 设置为 true)。注意返回 tg_trigtupletg_newtuple(具体视情况而定),如果您不希望修改正在操作的行。