web-dev-qa-db-ja.com

パラメータ付きのPostgresqlトリガー関数

Postgresqlでtakesというテーブルにトリガーを作成して、studentという別のテーブルの値を更新したいのですが、次のようにしています。しかし、「OLD」の近くに構文エラーがあるというエラーが出ます。何が悪いのか分かりません。これは私のコードです:

CREATE OR REPLACE FUNCTION upd8_cred_func
      (id1 VARCHAR, gr1 VARCHAR,id2 VARCHAR, gr2 VARCHAR) 
      RETURNS void AS $$
 BEGIN
    IF  (id1=id2 and gr1 is null and gr2 is not null) THEN 
        update student set tot_cred = tot_cred + 6 where id = id1;
    END IF;
    RETURN;
 END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER upd8_cred
    AFTER UPDATE ON takes
    FOR EACH ROW
    EXECUTE PROCEDURE upd8_cred_func(OLD.id,OLD.grade,NEW.id,NEW.grade);
29
user975474

NEWおよびOLDをパラメーターとしてトリガー関数に渡す必要はありません。それらはそこに自動的に利用できます:

http://www.postgresql.org/docs/9.1/interactive/trigger-definition.html

トリガー関数は、引数をとらず、トリガーの型を返す関数として宣言する必要があります。 (トリガー関数は、通常の関数引数の形式ではなく、特別に渡されたTriggerData構造体を介して入力を受け取ります。)

トリガープロシージャに渡されるレコードについては、 http://www.postgresql.org/docs/9.1/interactive/plpgsql-trigger.html を参照してください。

PL/pgSQL関数がトリガーとして呼び出されると、いくつかの特殊変数がトップレベルのブロックに自動的に作成されます。それらは:[...]新しい、[...]古い[...]

以下のコメントでSeldomNeedyが指摘しているように、トリガー関数にパラメーターを渡して使用することができます。あなたは関数をパラメータなしとして宣言しますが、定義トリガーを(CREATE TRIGGERによって)追加すると、いくつか。

これらは、TG_NARG(そのようなパラメーターの数)、およびTG_ARGV[]text値の配列)としてトリガーに使用できます。

29
Arsen7

Greg で述べたように、トリガー関数は引数を取ることができますが、関数自体は宣言されたパラメーターを持つことができません。次に、plpgsqlの簡単な例を示します。

CREATE TABLE my_table ( ID SERIAL PRIMARY KEY ); -- onelined for compactness

CREATE OR REPLACE FUNCTION raise_a_notice() RETURNS TRIGGER AS
$$
DECLARE
    arg TEXT;
BEGIN
    FOREACH arg IN ARRAY TG_ARGV LOOP
        RAISE NOTICE 'Why would you pass in ''%''?',arg;
    END LOOP;
    RETURN NEW; -- in plpgsql you must return OLD, NEW, or another record of table's type
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER no_inserts_without_notices BEFORE INSERT ON my_table
FOR EACH ROW EXECUTE PROCEDURE raise_a_notice('spoiled fish','stunned parrots');

INSERT INTO my_table DEFAULT VALUES;

-- the above kicks out the following:
--
-- NOTICE:  Why would you pass in 'spoiled fish'?
-- NOTICE:  Why would you pass in 'stunned parrots'?
--

the docs で説明されているTG_NARGS(ループを行わずに取得した引数の数を知る)など、他にもいくつかの便利な機能があります。また、複数のテーブルにまたがる1つのトリガー関数のロジックがほぼ完全に共有されている場合に、トリガーテーブルの名前を取得する方法に関する情報もあります。

15
SeldomNeedy

トリガー関数canにはパラメーターがありますが、これらのパラメーターを通常の関数のように渡すことはできません(たとえば、関数定義の引数)。同じ結果が得られます... pythonでは、上記の回答で説明されているように、古いデータと新しいデータにアクセスできます。たとえば、TD ['new'] ['column_name '] in python column_nameの新しいデータを参照します。特別な変数TD [' args ']にもアクセスできます。したがって、次のようにします。

create function te() returns trigger language plpython2u as $function$
    plpy.log("argument passed 1:%s 2:%s" %(TD['args'][0], TD['args'][1], ))
$function$

create constraint trigger ta after update of ttable
for each for execute procedure te('myarg1','myarg2');

確かに、これらの引数は静的ですが、複数のトリガー宣言から共通のトリガー関数を呼び出すときに役立ちます。他のストアドプロシージャ言語でも同じ変数を使用できると確信しています。 (コードが逐語的に機能しない場合は申し訳ありませんが、私はこの手法を実践しているので、引数を渡すことができます!).

13
Greg