本節ではトリガ関数とのインタフェースについて低レベルな詳細を説明します。 この情報はC言語でトリガ関数を作成する時にのみ必要です。 高レベルな言語で作成すれば、こうした詳細は代わりに扱ってもらえます。 たいていの場合、Cでトリガを作成する前に手続き言語を使用することを検討すべきです。 各手続き言語の文書で、その言語を使用したトリガの作成方法を説明します。
トリガ関数は「version 1」関数マネージャインタフェースを使わなくてはいけません。
関数がトリガマネージャから呼び出される時は、通常の引数が渡されるのではなく、TriggerData
構造体を指す「context」ポインタが渡されます。
C関数は、トリガマネージャから呼び出されたのかどうかを以下のマクロを実行することで検査することができます。
CALLED_AS_TRIGGER(fcinfo)
これは以下に展開されます。
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
もしこれが真を返す場合、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)
トリガが操作の前に(before)発行された場合真を返します。
TRIGGER_FIRED_AFTER(tg_event)
トリガが操作の後に(after)発行された場合真を返します。
TRIGGER_FIRED_INSTEAD(tg_event)
トリガがINSTEAD OFで発行された場合真を返します。
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
コマンドで発行された場合真を返します。
TRIGGER_FIRED_BY_TRUNCATE(tg_event)
トリガがTRUNCATE
コマンドで発行された場合真を返します。
tg_relation
トリガの発行元のリレーションを記述する構造体へのポインタです。
この構造体についての詳細は、utils/rel.h
を参照してください。
最も興味深いのは、tg_relation->rd_att
(リレーションタプルの記述子)とtg_relation->rd_rel->relname
です(リレーション名、これはchar*
ではなくNameData
です。
名前のコピーが必要な場合は、char*
を得るためにSPI_getrelname(tg_relation)
を使用してください)。
tg_trigtuple
トリガが発行された行へのポインタです。
これは挿入される、削除される、あるいは更新される行です。
もしINSERT
/DELETE
でこのトリガが発行された時、この行を別のもので置き換えたくない(INSERT
の場合)場合や、その操作を飛ばしたくない場合は、これをこの関数から返してください。
外部テーブルのトリガに対しては、システム列の値はここでは指定されません。
tg_newtuple
トリガがUPDATE
で発行された場合は、行の新しいバージョンへのポインタです。
INSERT
もしくはDELETE
の場合は、NULL
です。
UPDATE
イベントの時、この行を別のもので置き換えたくない場合や操作を飛ばしたくない場合は、これをこの関数から返してください。
外部テーブルのトリガに対しては、システム列の値はここでは指定されません。
tg_trigger
以下のようにutils/reltrigger.h
で定義された、Trigger
構造体へのポインタです。
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
tg_relation
で指定するフォーマットの0以上の行を含むTuplestorestate
型の構造体へのポインタです。
OLD TABLE
遷移リレーションが存在しない場合はNULL
ポインタです。
tg_newtable
tg_relation
で指定するフォーマットの0以上の行を含むTuplestorestate
型の構造体へのポインタです。
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のNULLではありません。
したがって、isNull
は真にはなりません)のどちらかを返さなければなりません。
操作対象の行を変更したくない場合は、注意して、tg_trigtuple
かtg_newtuple
の適切な方を返してください。