2024 年 9 月 26 日: PostgreSQL 17 发布!
支持版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持版本: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;

其中成员定义如下

类型

始终为 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。如果您不想用不同的行替换此行或跳过该操作,则应从函数中返回此行。

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,具体情况视情况而定。

提交更正

如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用 此表格 报告文档问题。