支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: 开发版
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

37.3. 用 C 编写触发器函数 #

本节介绍触发器函数的接口的底层细节。只有在用 C 编写触发器函数时才需要这些信息。如果您使用更高级别的语言,这些细节将为您处理。在大多数情况下,您应该考虑在使用 C 编写触发器之前使用过程语言。每种过程语言的文档都解释了如何用该语言编写触发器。

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

当函数被触发器管理器调用时,它不会传递任何常规参数,而是传递一个指向 TriggerData 结构的上下文指针。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 中的参数数量,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_trigtupletg_newtuple

提交更正

如果您发现文档中的任何内容不正确,与您使用特定功能的经验不符或需要进一步澄清,请使用 此表单报告文档问题。