Chapter 13. Triggers

Table of Contents
トリガーの生成
トリガーマネージャとの関係
データ変更時の可視性

Postgres は 2 つの 手続き言語 ( PL )の他、Perl、Tcl、Python、 C といった各種のインタフェースを持っています。またトリガーアクショ ンとして C の関数を呼ぶこともできます。現バージョンでは、STATEMENT レベルのトリガーイベントはサポートされていませんので注意して下さい。 現在はタプルの INSERT、DELETE、UPDATEの前( BEFORE )または後( AFTER )をトリガーイベントとして指定できます。

トリガーの生成

トリガーイベントが発生すると、(エグゼキュータによって呼び出され る)トリガーマネージャは(後述の)大域構造体 TriggerData *CurrentTriggerData を初期化し、そのイベントを扱うト リガー関数を呼び出します。

トリガーが生成される前に、トリガー関数は、引数をとらない、 opaque 型を返す関数として作成されていなければなりません。

トリガーを生成するための構文は次の通りです。

   CREATE TRIGGER <トリガー名> <BEFORE|AFTER> <INSERT|DELETE|UPDATE>
       ON <リレーション名> FOR EACH <ROW|STATEMENT>
       EXECUTE PROCEDURE <プロシージャ名> (<関数の引数>);

トリガー名は、トリガーを削除する必要になった時にも使われます。 DROP TRIGGER コマンドの引数として使われます。

次の単語は、関数がイベントが発生する前に呼ばれるのか後に呼ばれ るのかを決定します。

次の要素は、どのコマンドのイベント(複数可)で関数を呼び出すか を決定します。複数のイベントを OR で区切って指定できます。

リレーション名はどのテーブルにイベントを適用するかを決定します。

FOR EACH 文はトリガーを行が影響を受ける度に発行するか、文全体が 終了する前(または後)に発行するかを決定します。

プロシージャ名は呼び出される C の関数を示します。

関数の引数は、関数に CurrentTriggerData 構造体の中に格納され て渡されます。引数を関数に渡す目的は、同一関数の呼び出しによ って要求仕様が似ている異なるトリガーを扱えるようにすることで す。

また、関数は異なるリレーションのトリガーに使うこともできます。 (こういった関数は "汎用トリガー関数" と呼ばれます。)

上記の両機能を使う例として、片方に現在のユーザを、もう片方に現 時刻を格納した 2 つのフィールドの名前を引数としてとる汎用関数が あります。例えば、この関数を INSERT イベント時に使用すれば、ト ランザクションテーブル内のレコードの作成を検出して、自動的に書 き込みを行なわせることができます。または、UPDATE イベント時に使 用すれば、"最終更新" 機能を行なわせることもできます。

トリガー関数は呼び出したエグゼキュータに HeapTuple を返します。 これは INSERT、DELETE、UPDATE の後に発行されるトリガー( AFTER ) では無視されますが、BEFORE のトリガーでは、以下を行なうことがで きます。 - NULL を返して、現タプルへの操作をとばします。(そして、このタ プルの挿入、更新、削除は行なわれなくなります。) - 本来のタプルではなく他のタプルのポインタを返して、それを( UPDATE の場合は更新されたタプルの新しいバージョンとして)挿入 させます。( INSERT と UPDATE のみ)

CREATE TRIGGER ハンドラによって初期化は行なわれないことに注意 して下さい。このことは今後変更する予定です。また、同一リレーシ ョンの同一イベントに対して複数トリガーが定義された場合は、トリ ガーの発行順は予測できません。これも今後変更されるかもしれませ ん。

トリガー関数が( SPI を使用して)SQL 問い合わせを処理する場合、こ れらの問い合わせがトリガーを再度発行することがあります。これはカス ケードされたトリガーと呼ばれます。カスケードの段数に明確な制限はあ りません。

INSERT によって発行されたトリガーが同じリレーションに新しいタプル を挿入する場合、このトリガーが再度発行されます。現状、この場合の 同期(などの)機能は提供されていませんが、これも変更される可能性 があります。現段階では、レグレッションテストの中に、自身への再帰 (カスケーディング)を停止させるための数個のテクニックを使用した funny_dup17() という関数があります。