2025年9月25日: PostgreSQL 18 釋出!
支援版本: 當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 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 TriggerData 定義在 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;

其成員定義如下:

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-based)的列是否是此點陣圖集中的成員,請呼叫 bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols))

對於 UPDATE 觸發器以外的觸發器,此欄位將為 NULL

要允許透過 SPI 發出的查詢引用轉換表,請參閱 SPI_register_trigger_data

觸發器函式必須返回 HeapTuple 指標或 NULL 指標(不是 SQL null 值,即不要將 isNull 設定為 true)。如果您不希望修改正在操作的行,請務必根據情況返回 tg_trigtupletg_newtuple

提交更正

如果您在文件中發現任何不正確的內容,與您對特定功能的體驗不符,或者需要進一步澄清,請使用 此表單 報告文件問題。