無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

36.1. トリガ動作の概要

トリガとは、データベースが、ある特定の操作が行われた時に常に自動的に実行しなければならない特定の機能に関する規定です。 トリガはテーブルとビューの双方に付与することができます。

テーブル上では、トリガを INSERT UPDATE または DELETE 操作の前後に、行を変更する度、あるいは SQL 文ごとに実行するように定義することができます。 UPDATE トリガについては、特定のカラムが UPDATE 文の SET 句の対象になった時のみ発動するよう設定することができます。また、トリガは TRUNCATE 文についても実行できます。 トリガイベントが起こると、トリガ関数がそのイベントを扱う適切な時点で呼び出されます。

ビュー上では、トリガを INSERT UPDATE または DELETE 操作の代わりに実行するものとして定義できます。 INSTEAD OF トリガは、ビュー内の変更を行うために必要となる行それぞれに対して一度発行されます。 元になっているテーブルへの必要な変更の実施、そして必要に応じて、ビュー上で見えるであろう変更された行を返却するのは、トリガ関数の責任です。ビューへのトリガは、 SQL 文ごとに、 INSERT UPDATE または DELETE 操作の前後で実行させるよう定義することができます。

トリガ関数は、トリガ自体が作成される前までに定義しておく必要があります。 トリガ関数は、引数を取らない、 trigger 型を返す関数として宣言される必要があります (トリガ関数は、通常の関数で使用される引数という形ではなく、 TriggerData 構造体で入力を受け取ります)。

適切なトリガ関数が作成されると、 CREATE TRIGGER を使用してトリガを構築することができます。 同一のトリガ関数を複数のトリガに使用することができます。

PostgreSQL は、 行単位の トリガと 文単位の トリガの両方を提供します。 行単位のトリガでは、トリガを発行した文によって影響を受ける行ごとにトリガ関数が呼び出されます。 反対に、文単位のトリガでは、適切な文が実行された時に、その文で何行が影響を受けたかどうかは関係なく、一度だけ呼び出されます。 特に、行に影響を与えない文であっても、適切な文単位のトリガがあれば実行されます。 この2種類のトリガはそれぞれ 行レベル トリガと 文レベル トリガ<と呼ばれることがあります。 TRUNCATE に対するトリガは文レベルトリガのみに定義することができます。 ビューでは、文レベルでのみ、処理の前後での実行をするよう定義することができるでしょう。一方、 INSERT UPDATE または DELETE の代わりに実行するトリガは行レベルでのみ定義できるでしょう。

また、トリガはそれらが操作の または 代わり のどれで実行されるかに応じて分けられます。これらはそれぞれ BEFORE トリガ、 AFTER トリガ、そして INSTEAD OF トリガと呼ばれます。 文レベルの BEFORE トリガは、文が何かを始める前に自然に発行され、文レベルの AFTER トリガは文の本当に最後に発行されます。これらのタイプのトリガはテーブルまたはビューで定義されるでしょう。 行レベルの BEFORE トリガは、特定の行が操作される直前に発行され、行レベルの AFTER トリガは文の終わり(ただし、全ての文レベルの AFTER トリガの前)に発行されます。これらのタイプのトリガはテーブルにのみ定義されるでしょう。 行レベルの INSTEAD OF トリガはビューにのみ定義され、ビュー上の行ごとに操作が必要と判断された場合に即座に発行されます。

文単位のトリガによって呼び出されるトリガ関数は常に NULL を返さなければなりません。 行単位のトリガによって呼び出されるトリガ関数は呼び出し元のエクゼキュータにテーブル行( HeapTuple 型の値)を返すように選択することができます。 操作前に発行された行レベルのトリガでは以下の選択肢があります。

これらの動作をさせたくない行レベルの BEFORE トリガについては、渡された行(つまり、 INSERT および UPDATE トリガでは NEW 行、 DELETE の場合は OLD 行)と同じ行結果を返すように気を付ける必要があります。

行レベルの INSTEAD OF トリガは、ビューの元となった元テーブルのデータをまったく変更しないことを表す NULL 、または、渡されたビューの行( INSERT UPDATE 操作の場合 NEW 行、 DELETE 操作の場合 OLD 行)を返さなければなりません。 非NULLの戻り値は、そのトリガがビューにおいて必要なデータ変更を実行したことを通知するために使用されます。 これにより影響を受けた行数を数えるカウンタは増加されます。 INSERT UPDATE 操作では、トリガは戻す前に NEW 行を変更することができます。 これは INSERT RETURNING または UPDATE RETURNING で返されるデータを変更しますので、ビューが提供されたデータと正確に同じ結果を返さない場合に有益です。

操作の後に発生する行レベルトリガでは戻り値は無視されますので、これらは NULL を返すことができます。

同一リレーション、同一イベントに対して1つ以上のトリガが定義された場合、トリガはその名前のアルファベット順に発生します。 BEFORE トリガと INSTEAD OF トリガの場合では、各トリガで返される、変更された可能性がある行が次のトリガの入力となります。 もし、ある BEFORE トリガや INSTEAD OF トリガが NULL を返したら、(いまのところ)操作はその行で中断し、残りのトリガは発生しません。

トリガ定義は、トリガを発動するかどうかを WHEN 句の論理条件で指定することも可能です。行レベルトリガにおいて、 WHEN 条件は行の列の古い値と(あるいは)新しい値を検索することができます。(あまり有用ではありませんが、文レベルトリガでも WHEN 条件で同じことができます。) BEFORE トリガでは、実質的にトリガ関数の開始時と同じ条件で検査できるように、 WHEN 条件の評価が関数の実施直前になされます。しかし AFTER トリガでは、 WHEN 条件の評価は行の更新直後に行われ、文の終わり(コミット時)にトリガを発動するためのイベントを待ち行列に入れるかどうかを決めます。そのため、ある AFTER トリガの WHEN 条件が真を返さなかった場合は、イベントを待ち行列に入れる必要も文の終わりに行を再取得する必要もありません。これは、大量の行の変更が発生するけれども、トリガがその内の少数の行に対してのみ発動させる必要がある、といった文の処理速度を大幅に上げる効果があります。 INSTEAD OF トリガは WHEN 条件をサポートしていません。

通常、行レベルの BEFORE トリガは、挿入あるいは更新される予定のデータの検査や変更のために使用されます。 例えば、 BEFORE トリガは、 timestamp 型の列に現在時刻を挿入するために、あるいは行の2つの要素の整合性を検査するために使用される可能性があります。 行レベルの AFTER トリガは、ほとんど常識的に他のテーブルに更新を伝播させるために、あるいは他のテーブルとの整合性を検査するために使用されます。 こうした仕事の切り分け理由は、 AFTER トリガは行の最終値を見ることができ、 BEFORE トリガは見ることができないという点です。 トリガを BEFORE にするか AFTER にするかを決める時に特別な理由がないのであれば、操作の情報を行が終わるまで保持する必要がない分、 BEFORE を使う方が効率的です。

トリガ関数がSQLコマンドを処理する場合、これらの問い合わせがトリガを再度発行することがあります。 これはカスケードされたトリガと呼ばれます。 カスケードの段数に直接的な制限はありません。 カスケードの場合、同じトリガを再帰的に呼び出すことが可能です。 例えば、 INSERT トリガで同じテーブルに追加の行を挿入する問い合わせが実行された場合、その結果として INSERT トリガが再度発行されます。 こうした状況で無限再帰を防ぐのは、トリガプログラマの責任です。

トリガを定義する時、そのトリガ用の引数を指定することができます。 トリガ定義に引数を含めた目的は、似たような要求の異なるトリガに同じ関数を呼び出すことができるようにすることです。 例えば、2つの列名を引数とし、片方に現在のユーザをもう片方に現在のタイムスタンプを取る、汎化トリガ関数があるとします。 適切に作成すれば、この関数が特定のトリガの発行元となるテーブルに依存することはなくなります。 同じ関数を使用して、例えば、トランザクションテーブルに作成記録を自動的に登録させるために、適切な列を持つ任意のテーブルの INSERT イベントに使用することができます。 また、 UPDATE として定義すれば、最終更新イベントを追跡するために使用することも可能です。

トリガをサポートするプログラミング言語はそれぞれ独自の方法で、トリガ関数で利用できるトリガの入力データを作成します。 この入力データにはトリガイベント種類(例えば INSERT UPDATE など、 CREATE TRIGGER で指定された全ての引数)が含まれます。 行レベルトリガの入力データには、 INSERT および UPDATE トリガの場合は NEW 行が、 UPDATE および DELETE トリガの場合は OLD 行が含まれます。 文レベルトリガには現在、文によって変更される個々の行を検査するための手段がありません。


powered by SEO.CUG.NET