Postgresql 中文操作指南

39.3. Writing Trigger Functions in C #

本节描述了触发器功能接口的底层详细信息。仅在使用 C 编写触发器功能时需要该信息。如果您使用的是高级语言,则无需处理这些详细信息。在大多数情况下,您应该考虑在 C 中编写触发器之前使用过程语言。每个过程语言的文档都说明了如何用该语言编写触发器。

This section describes the low-level details of the interface to a trigger function. This information is only needed when writing trigger functions in C. If you are using a higher-level language then these details are handled for you. In most cases you should consider using a procedural language before writing your triggers in C. The documentation of each procedural language explains how to write a trigger in that language.

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

Trigger functions must use the “version 1” function manager interface.

当触发器管理器调用函数时,不会传递任何常规参数,但会传递一个“上下文”指针,指向 TriggerData 结构。C 函数可以通过执行宏来检查是否从触发器管理器调用了它们:

When a function is called by the trigger manager, it is not passed any normal arguments, but it is passed a “context” pointer pointing to a TriggerData structure. C functions can check whether they were called from the trigger manager or not by executing the macro:

CALLED_AS_TRIGGER(fcinfo)

它将扩展为:

which expands to:

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

如果返回 true,则可以安全地将 fcinfo→context 转换为类型 TriggerData * 并利用所指向的 TriggerData 结构。该函数必须 not 更改 TriggerData 结构或它指向的任何数据。

If this returns true, then it is safe to cast fcinfo→context to type TriggerData * and make use of the pointed-to TriggerData structure. The function must not alter the TriggerData structure or any of the data it points to.

struct TriggerData 定义在 commands/trigger.h 中:

struct TriggerData is defined in 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;

其中,成员定义如下:

where the members are defined as follows:

  • type

    • Always T_TriggerData.

  • tg_event

    • Describes the event for which the function is called. You can use the following macros to examine tg_event:

  • tg_relation

    • A pointer to a structure describing the relation that the trigger fired for. Look at utils/rel.h for details about this structure. The most interesting things are tg_relation→rd_att (descriptor of the relation tuples) and tg_relation→rd_rel→relname (relation name; the type is not char* but NameData; use SPI_getrelname(tg_relation) to get a char* if you need a copy of the name).

  • tg_trigtuple

    • A pointer to the row for which the trigger was fired. This is the row being inserted, updated, or deleted. If this trigger was fired for an INSERT or DELETE then this is what you should return from the function if you don’t want to replace the row with a different one (in the case of INSERT) or skip the operation. For triggers on foreign tables, values of system columns herein are unspecified.

  • tg_newtuple

    • A pointer to the new version of the row, if the trigger was fired for an UPDATE, and NULL if it is for an INSERT or a DELETE. This is what you have to return from the function if the event is an UPDATE and you don’t want to replace this row by a different one or skip the operation. For triggers on foreign tables, values of system columns herein are unspecified.

  • tg_trigger

    • A pointer to a structure of type Trigger, defined in 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;
  • where tgname is the trigger’s name, tgnargs is the number of arguments in tgargs, and tgargs is an array of pointers to the arguments specified in the CREATE TRIGGER statement. The other members are for internal use only.

    • tg_trigslot

  • The slot containing tg_trigtuple, or a NULL pointer if there is no such tuple.

    • tg_newslot

  • The slot containing tg_newtuple, or a NULL pointer if there is no such tuple.

    • tg_oldtable

  • A pointer to a structure of type Tuplestorestate containing zero or more rows in the format specified by tg_relation, or a NULL pointer if there is no OLD TABLE transition relation.

    • tg_newtable

  • A pointer to a structure of type Tuplestorestate containing zero or more rows in the format specified by tg_relation, or a NULL pointer if there is no NEW TABLE transition relation.

    • tg_updatedcols

  • For UPDATE triggers, a bitmap set indicating the columns that were updated by the triggering command. Generic trigger functions can use this to optimize actions by not having to deal with columns that were not changed.

  • As an example, to determine whether a column with attribute number attnum (1-based) is a member of this bitmap set, call bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata→tg_updatedcols)).

  • For triggers other than UPDATE triggers, this will be NULL.

    • TRIGGER_FIRED_BEFORE(tg_event)

  • Returns true if the trigger fired before the operation.

    • TRIGGER_FIRED_AFTER(tg_event)

  • Returns true if the trigger fired after the operation.

    • TRIGGER_FIRED_INSTEAD(tg_event)

  • Returns true if the trigger fired instead of the operation.

    • TRIGGER_FIRED_FOR_ROW(tg_event)

  • Returns true if the trigger fired for a row-level event.

    • TRIGGER_FIRED_FOR_STATEMENT(tg_event)

  • Returns true if the trigger fired for a statement-level event.

    • TRIGGER_FIRED_BY_INSERT(tg_event)

  • Returns true if the trigger was fired by an INSERT command.

    • TRIGGER_FIRED_BY_UPDATE(tg_event)

  • Returns true if the trigger was fired by an UPDATE command.

    • TRIGGER_FIRED_BY_DELETE(tg_event)

  • Returns true if the trigger was fired by a DELETE command.

    • TRIGGER_FIRED_BY_TRUNCATE(tg_event)

  • Returns true if the trigger was fired by a TRUNCATE command.

要允许通过 SPI 发出的查询引用转换表,请参阅 SPI_register_trigger_data

To allow queries issued through SPI to reference transition tables, see SPI_register_trigger_data.

触发器函数必须返回 HeapTuple 指针或 NULL 指针(not 为 SQL 空值,即不要设置 isNull 为 true)。如果你不想修改正在操作的行,请小心返回 tg_trigtupletg_newtuple(视情况而定)。

A trigger function must return either a HeapTuple pointer or a NULL pointer (not an SQL null value, that is, do not set isNull true). Be careful to return either tg_trigtuple or tg_newtuple, as appropriate, if you don’t want to modify the row being operated on.