本節說明觸發程序函數介面的底層細節。只有在使用 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
指向觸發程序觸發的資料列。這是正在插入、更新或刪除的資料列。如果此觸發程序是針對 INSERT
或 DELETE
觸發的,如果您不想用不同的資料列替換該資料列 (在 INSERT
的情況下) 或跳過該操作,則這是您應該從該函數傳回的內容。對於外部資料表的觸發程序,此處系統欄位的值未指定。
tg_newtuple
如果觸發程序是針對 UPDATE
觸發的,則指向該資料列的新版本,如果是針對 INSERT
或 DELETE
觸發的,則為 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
是觸發程序的名稱,tgnargs
是 tgargs
中的參數數量,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_trigtuple
或 tg_newtuple
(視情況而定)。
如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用此表格來回報文件問題。