PostgreSQL 用 C 編寫觸發(fā)器函數(shù)

2021-09-03 15:51 更新

這一節(jié)描述了一個觸發(fā)器函數(shù)的接口的低層細節(jié)。只有用 C 編寫觸發(fā)器函數(shù)時才需要這些信息。如果你使用一種更高層的語言,那么這些細節(jié)就不需要你來處理。在大部分情況下,你應(yīng)該優(yōu)先考慮使用一種過程語言。每一種過程語言的文檔闡述了如何使用那種語言編寫一個觸發(fā)器。

觸發(fā)器函數(shù)必須使用版本 1函數(shù)管理器接口。

當(dāng)一個函數(shù)被觸發(fā)器管理器調(diào)用時,不會給它傳遞任何常規(guī)的參數(shù),但是會有一個context指針傳遞給它,該指針指向一個TriggerData結(jié)構(gòu)。C 函數(shù)可以通過執(zhí)行一個宏來檢查它們是否是從觸發(fā)器管理器被調(diào)用:

CALLED_AS_TRIGGER(fcinfo)

它會展開成為:

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

如果這返回真,那么將fcinfo->context造型成類型TriggerData *并且利用所指向的TriggerData結(jié)構(gòu)就是安全的。該函數(shù)不能修改該TriggerData結(jié)構(gòu)或者它指向的任何數(shù)據(jù)。

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

描述該函數(shù)是為什么事件被調(diào)用的。你可以使用下列宏來檢查tg_event

TRIGGER_FIRED_BEFORE(tg_event)

如果該觸發(fā)器在操作前被引發(fā)則返回真。

TRIGGER_FIRED_AFTER(tg_event)

如果該觸發(fā)器在操作后被引發(fā)則返回真。

TRIGGER_FIRED_INSTEAD(tg_event)

如果該觸發(fā)器被引發(fā)替代操作則返回真。

TRIGGER_FIRED_FOR_ROW(tg_event)

如果該觸發(fā)器為一個行級事件而引發(fā)則返回真。

TRIGGER_FIRED_FOR_STATEMENT(tg_event)

如果該觸發(fā)器為一個語句級事件而引發(fā)則返回真。

TRIGGER_FIRED_BY_INSERT(tg_event)

如果該觸發(fā)器由一個INSERT命令引發(fā)則返回真。

TRIGGER_FIRED_BY_UPDATE(tg_event)

如果該觸發(fā)器由一個UPDATE命令引發(fā)則返回真。

TRIGGER_FIRED_BY_DELETE(tg_event)

如果該觸發(fā)器由一個DELETE命令引發(fā)則返回真。

TRIGGER_FIRED_BY_TRUNCATE(tg_event)

如果該觸發(fā)器由一個TRUNCATE命令引發(fā)則返回真。

tg_relation

一個結(jié)構(gòu)指針,該結(jié)構(gòu)描述該觸發(fā)器為其引發(fā)的關(guān)系。關(guān)于這個結(jié)構(gòu)的細節(jié)請參考utils/rel.h。最有趣的東西是tg_relation->rd_att(該關(guān)系元組的描述符)和tg_relation->rd_rel->relname(關(guān)系名稱,該類型不是char*而是 NameData。如果你需要該名稱的一個拷貝,可使用SPI_getrelname(tg_relation)來得到一個char*)。

tg_trigtuple

一個該觸發(fā)器為其引發(fā)的行的指針。這是被插入、更新或刪除的行。如果這個觸發(fā)器是為一個INSERTDELETE而引發(fā),在你不想把該行替換成另一行(在INSERT的情況中)或不想跳過該操作時你應(yīng)該從該函數(shù)中返回它。 對于外部表上的觸發(fā)器,此中的系統(tǒng)列值未被指定。

tg_newtuple

如果該觸發(fā)器為一個UPDATE而引發(fā),則是一個指向該行新版本的指針。如果是為一個INSERTDELETE而引發(fā),則是NULL。如果事件是一個UPDATE并且你并不想用一個不同的行替換這個行或者不想跳過該操作時,你必須從函數(shù)中返回它。對于外部表上的觸發(fā)器,此中的系統(tǒng)列值未被指定。

tg_trigger

一個指向類型為Trigger的結(jié)構(gòu)的指針,定義在utils/reltrigger.h中:

typedef struct Trigger
{
    Oid         tgoid;
    char       *tgname;
    Oid         tgfoid;
    int16       tgtype;
    char        tgenabled;
    bool        tgisinternal;
    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是該觸發(fā)器的名稱,tgnargstgargs中參數(shù)的數(shù)量,而tgargs是一個指向CREATE TRIGGER語句中指定的參數(shù)的指針數(shù)組。其他成員只用于內(nèi)部用途。

tg_trigtuplebuf

包含tg_trigtuple的插槽?;蛘咭粋€NULL指針,如果沒有這樣的元組的話。

tg_newtuplebuf

包含tg_trigtuple的插槽?;蛘咭粋€NULL指針,如果沒有這樣的元組的話。

tg_oldtable

一個指向Tuplestorestate類型的結(jié)構(gòu)的指針,該結(jié)構(gòu)包含格式由tg_relation指定的零行或者多行。如果沒有OLD TABLE傳遞關(guān)系,則為NULL指針。

tg_newtable

一個指向Tuplestorestate類型的結(jié)構(gòu)的指針,該結(jié)構(gòu)包含格式由tg_relation指定的零行或者多行。如果沒有NEW TABLE傳遞關(guān)系,則為NULL指針。

tg_updatedcols

對于 UPDATE 觸發(fā)器,位圖集指示由觸發(fā)命令更新的列。 通用觸發(fā)器函數(shù)可以使用它來優(yōu)化操作,而不必處理未更改的列。

例如,要確定屬性編號為 attnum(基于 1)的列是否是此位圖集的成員,請調(diào)用 bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols))。

對于UPDATE觸發(fā)器以外的觸發(fā)器,這將是NULL。

為了允許通過SPI發(fā)出的查詢引用傳遞表,請參考SPI_register_trigger_data。

一個觸發(fā)器函數(shù)必須返回一個HeapTuple指針或一個NULL指針(不是一個 SQL 空值,也就是不會設(shè)置isNull為真)。如果你不希望修改正在被操作的行,要小心地根據(jù)情況返回tg_trigtupletg_newtuple。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號