トリガ動作の概要

PostgreSQL 9.0.0文書
前のページ | 巻戻し | 第 36章トリガ | 早送り | 次のページ

# 36.1. トリガ動作の概要

トリガとは、データベースが、ある特定の操作が行われた時に常に自動的に実行しなければならない特定の機能に関する規定です。 トリガを、`INSERT`、`UPDATE`または`DELETE`操作の前後に、行を変更する度、あるいはSQL文ごとに実行するように定義することができます。 `UPDATE`トリガについては、特定のカラムが`UPDATE`文の`SET`句の対象になった時のみ発動するよう設定することができます。また、トリガは`TRUNCATE`文についても実行できます。 トリガイベントが起こると、トリガ関数がそのイベントを扱う適切な時点で呼び出されます。

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

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

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

また、トリガはbeforeトリガとafterトリガとに分けられます。 文レベルのbeforeトリガは、文が何かを始める前に自然に発行され、文レベルのafterトリガは文の本当に最後に発行されます。 行レベルのbeforeトリガは、特定の行が操作される直前に発行され、行レベルのafterトリガは文の終わり（ただし、全ての文レベルのafterトリガの前）に発行されます。

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

- `NULL`を返して、現在の行への操作を飛ばすことができます。 これは、エクゼキュータにトリガの元になった行レベルの操作（特定のテーブル行の挿入、更新、削除）を行わないよう指示します。

- 行レベルの`INSERT`および`UPDATE`トリガの場合のみ、返される行が挿入される、もしくは実際に更新される行になります。 これにより、トリガ関数で、挿入される行もしくは更新される行を変更することができます。

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

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

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

トリガ定義は、トリガを発動するかどうかを`WHEN`句の論理条件で指定することも可能です。行レベルトリガにおいて、`WHEN`条件は行の列の古い値と(あるいは)新しい値を検索することができます。(あまり有用ではありませんが、文レベルトリガでも`WHEN`条件で同じことができます。)BEFOREトリガでは、実質的にトリガ関数の開始時と同じ条件で検査できるように、`WHEN`条件の評価が関数の実施直前になされます。しかしAFTERトリガでは、`WHEN`条件の評価は行の更新直後に行われ、文の終わり(コミット時)にトリガを発動するためのイベントを待ち行列に入れるかどうかを決めます。そのため、あるAFTERトリガの`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`行が含まれます。 文レベルトリガには現在、文によって変更される個々の行を検査するための手段がありません。

前のページ | ホーム | 次のページ
トリガ | 上に戻る | データ変更の可視性