35.3. 用 C 寫觸發器

本章描述觸發器函數的低層細節。只有當你用C書寫觸發器函數的時候才需要這些信息。 如果你用某種高級語言寫觸發器,那麼系統就會為你處理這些細節。 每種過程語言的文檔裡面有關于如何用該語言書寫觸發器的解釋。

觸發器函數必須使用"版本 1(version 1)"的函數管理器接口。

當一個函數被觸發器管理器調用時,它不會收到任何普通參數,而是收到一個指向TriggerData結構的"環境"指針。 C 函數可以通過執行實際上被擴展為

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

的宏

CALLED_AS_TRIGGER(fcinfo)

CALLED_AS_TRIGGER(fcinfo), 來判斷自己是否從觸發器管理器中調用的。 如果此宏返回真(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;
} TriggerData;

這些成員的定義如下:

type

總是 T_TriggerData

tg_event

描述調用函數的事件。你可以用下面的宏檢查 tg_event

TRIGGER_FIRED_BEFORE(tg_event)

如果觸發器是在操作前觸發,返回真。

TRIGGER_FIRED_AFTER(tg_event)

如果觸發器是在操作後觸發,返回真。

TRIGGER_FIRED_FOR_ROW(tg_event)

如果觸發器是行級別事件觸發,返回真。

TRIGGER_FIRED_FOR_STATEMENT(tg_event)

如果觸發器是語句級別事件觸發,返回真。

TRIGGER_FIRED_BY_INSERT(tg_event)

如果觸發器是由INSERT觸發,返回真。

TRIGGER_FIRED_BY_UPDATE(tg_event)

如果觸發器是由UPDATE觸發,返回真。

TRIGGER_FIRED_BY_DELETE(tg_event)

如果觸發器是由DELETE觸發,返回真。

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)或更新(UPDATE)的行。如果是 INSERTDELETE, 那麼這就是你將返回給執行者的東西--如果你不想用另一條行覆蓋此行(INSERT)或忽略操作(在DELETE的時候)。

tg_newtuple

如果是UPDATE,這是一個指向新版本的行的指針,如果是INSERTDELETE, 就是NULL。這就是你將返回給執行者的東西--如果事件是 UPDATE 並且你不想用另一條行替換這條行或忽略操作。

tg_trigger

是一個指向結構Trigger的指針,該結構在utils/rel.h裡定義:

typedef struct Trigger
{
    Oid	 tgoid;
    char       *tgname;
    Oid	 tgfoid;
    int16       tgtype;
    bool	tgenabled;
    bool	tgisconstraint;
    Oid	 tgconstrrelid;
    bool	tgdeferrable;
    bool	tginitdeferred;
    int16       tgnargs;
    int16       tgattr[FUNC_MAX_ARGS];
    char      **tgargs;
} Trigger;

tgname是觸發器的名稱,tgnargs 是在tgargs裡參數的數量, tgargs是一個指針數組,數組裡每個指針指向在 CREATE TRIGGER語句裡聲明的參數。其他成員只在內部使用。

一個觸發器函數必須返回 NULL 或者一個 HeapTuple 指針。 請注意如果你不想修改正在被操作的行,那麼要根據情況返回 tg_trigtuple 或者 tg_newtuple