24.3. トリガプロシージャ

PL/pgSQL はトリガプロシージャの定義に使用できます。トリガプロシージャ は、普通の CREATE FUNCTION コマンドを使って、引数無し、OPAQUEという 戻り値の型をもった関数として作成されます。

トリガプロシージャとして使われる関数には、 Postgres特有なことがいくつかあります。

まず、最上位ブロックの宣言部に自動的に特別な変数がいくつか作成され ることです。次のものがあります。

NEW

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

OLD

レコードデータ型。この変数は、行レベルのトリガでの 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

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

TG_ARGV[]

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

次は、 NULL または、トリガの発行元になったテーブルの構造を正確にもっ たレコード/行を返さなければならない点です。AFTER として発行された トリガは、常に、何も影響しない NULL を返すでしょう。 BEFORE として 発行されたトリガが NULL を返す場合には、トリガマネージャに実際の行 への操作を取りやめるように通知します。さもなければ、レコード/行を 返す場合には、その操作で挿入/更新された行をその戻り値に置き換えま す。 NEW の個々の値を直接置き換え、その NEW を返すことも、新しいレ コード/行を完全に作成して返すことも可能です。

Example 24-1. PL/pgSQL トリガ手続きの例

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

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

CREATE FUNCTION emp_stamp () RETURNS OPAQUE AS '
    BEGIN
        -- Check that empname and salary are given
        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;

        -- Who works for us when she must pay for?
        IF NEW.salary < 0 THEN
            RAISE EXCEPTION ''% cannot have a negative salary'', NEW.empname;
        END IF;

        -- Remember who changed the payroll when
        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();