本節介紹觸發器函式的介面的底層細節。這些資訊僅在用 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 的槽,如果沒有這樣的元組,則為 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_trigtuple 或 tg_newtuple。
如果您在文件中發現任何不正確的內容,與您對特定功能的體驗不符,或者需要進一步澄清,請使用 此表單 報告文件問題。