[11/15開催: PostgreSQL Conference Japan 2019 参加受付中] 
他のバージョンの文書 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

23.9. トリガプロシージャ

PL/pgSQL はトリガプロシージャの定義に使用できます。トリガプロシージャは、普通の CREATE FUNCTION コマンドを使って、引数無し、OPAQUEという戻り値の型をもった関数として作成されます。その関数は、たとえ、CREATE TRIGGER にて引数をとるものとしていたとしても、引数を持たないものと宣言しなければなりません。トリガの引数は、後述する通り、TG_ARGV 経由で渡されます。

PL/pgSQL 関数がトリガとして呼び出された場合、いくつかの特殊な変数が自動的に最上位レベルのブロックで作成されます。以下に示します。

NEW

RECORD データ型。この変数は行レベルのトリガでの INSERT/UPDATE 操作によって更新されたデータベースの行を保持します。

OLD

RECORD データ型。この変数は、行レベルのトリガでの INSERT/UPDATE 操作によって更新される前のデータベースの行を保持します。

TG_NAME

nameデータ型。実際に発行されたトリガの名前を持つ変数。

TG_WHEN

textデータ型。トリガの定義に依存した BEFORE または AFTER という文字列。

TG_LEVEL

textデータ型。トリガの定義に依存した ROW または STATEMENT という文字列。

TG_OP

textデータ型。トリガを発行した操作を示す、 INSERT, UPDATEまたは DELETE という文字列。

TG_RELID

oidデータ型。このトリガの呼び出し元になるテーブルのオブジェクトID.

TG_RELNAME

nameデータ型。このトリガの呼び出し元になるテーブルの名前。

TG_NARGS

integer型。CREATE TRIGGER文におけるトリガプロシージャに与えられる引数の数。

TG_ARGV[]

text型の配列型。CREATE TRIGGER 文での引数。このインデックスは 0 から始まり、またインデックスを式で与えることもできます。無効なインデックス (< 0 or >= tg_nargs) は NULL 値という結果になります。

NULL または、トリガの発行元になったテーブルの構造を正確にもったレコード/行を返さなければならない点です。BEFORE として発行されたトリガが NULL を返す場合には、トリガマネージャに実際の行への操作を取りやめるように通知します(つまり、その後にトリガが発行されず、その INSERT/UPDATE/DELETE はその行に対して実行されません)。非NULL値を返す場合には、その操作はその戻り値で処理されます。元のNEW の値と異なる行の値を返すことは、挿入、更新される値を変更することに注意して下さい。NEW の個々の値を直接置き換え、その NEW を返すことも、新しいレコード/行を完全に作成して返すことも可能です。

AFTER として発行されたトリガの戻り値は無視されます。常にNULL値を返すことと同様です。しかし、AFTER トリガはエラーを発生させることで操作を中断することができます。

Example 23-1. PL/pgSQL トリガプロシージャの例

このトリガの例では、テーブルの行が挿入または更新された時にはかならず、現在のユーザ名と時刻がその行に入っていることを確実にします。そして、従業員名が与えられていることとその給料が正の値であることを確実にします。

CREATE TABLE emp (
    empname text,
    salary integer,
    last_date timestamp,
    last_user text
);

CREATE FUNCTION emp_stamp () RETURNS OPAQUE AS '
    BEGIN
        -- empname とsalary が与えられていることをチェック
        IF NEW.empname ISNULL THEN
            RAISE EXCEPTION ''empname cannot be NULL value'';
        END IF;
        IF NEW.salary ISNULL THEN
            RAISE EXCEPTION ''% cannot have NULL salary'', NEW.empname;
        END IF;

        -- salary が負の値になっていないかをチェック
        IF NEW.salary < 0 THEN
            RAISE EXCEPTION ''% cannot have a negative salary'', NEW.empname;
        END IF;

        -- 誰がいつ変更したかを記録
        NEW.last_date := ''now'';
        NEW.last_user := current_user;
        RETURN NEW;
    END;
' LANGUAGE 'plpgsql';

CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
    FOR EACH ROW EXECUTE PROCEDURE emp_stamp();