支援的版本:目前 (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 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 的槽,如果沒有此 tuple,則為 NULL 指標。

tg_newslot

包含 tg_newtuple 的槽,如果沒有此 tuple,則為 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(視情況而定)。

提交更正

如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用此表格來回報文件問題。