PostgreSQL 9.2.4文書 | ||||
---|---|---|---|---|
前のページ | 上に戻る | 第 36章トリガ | 次のページ |
トリガとは、データベースが、ある特定の操作が行われた時に常に自動的に実行しなければならない特定の機能に関する規定です。 トリガはテーブルとビューの双方に付与することができます。
テーブル上では、トリガを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型の値)を返すように選択することができます。 操作前に発行された行レベルのトリガでは以下の選択肢があります。
NULLを返して、現在の行への操作を飛ばすことができます。 これは、エクゼキュータにトリガの元になった行レベルの操作(特定のテーブル行の挿入、更新、削除)を行わないよう指示します。
行レベルのINSERTおよびUPDATEトリガの場合のみ、返される行が挿入される、もしくは実際に更新される行になります。 これにより、トリガ関数で、挿入される行もしくは更新される行を変更することができます。
これらの動作をさせたくない行レベルの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行が含まれます。 文レベルトリガには現在、文によって変更される個々の行を検査するための手段がありません。