sql >> データベース >  >> RDS >> PostgreSQL

トリガー機能の無限ループ

    ELSE ブランチは根本的に単純化できます。しかし、さらにいくつかのことが非効率的/不正確/危険です:

    CREATE OR REPLACE FUNCTION sample_trigger_func()
      RETURNS TRIGGER AS
    $func$
    BEGIN
       IF TG_OP = 'DELETE' THEN
          RAISE INFO 'OLD: %', OLD.name;
    
          EXECUTE format('INSERT INTO %I SELECT ($1).*', TG_TABLE_NAME || '_deletes')
          USING OLD #= hstore('{mod_op, mod_datetime}'::text[]
                             , ARRAY[left(TG_OP, 1), now()::text]);
          RETURN OLD;
       ELSE  -- insert, update
          NEW.mod_op       := left(TG_OP, 1);
          NEW.mod_datetime := now();
    
          RETURN NEW;
       END IF;
    END
    $func$  LANGUAGE plpgsql;
    
    • ELSE内 ブランチはNEWに割り当てるだけです 直接。より動的なSQLは必要ありません。同じトリガーを再度起動すると、無限ループが発生します。それが主なエラーです。

    • RETURN NEW; IFの外 コンストラクトはDELETEのトリガー関数を壊します 、 NEW以降 DELETEには割り当てられていません。

    • 重要な機能は、 hstoreの使用です。 およびhstore演算子#= よく知られている行タイプの2つの選択されたフィールドを動的に変更します -それは不明です コードを書いている時点で。このようにして、元の OLDを改ざんすることはありません。 値。これは、イベントのチェーンの下にさらにトリガーがある場合、驚くべき副作用をもたらす可能性があります。

      OLD #= hstore('{mod_op, mod_datetime}'::text[]
                   , ARRAY[left(TG_OP, 1), now()::text]);
      

      追加モジュールhstore インストールする必要があります。詳細:

      hstore(text []、text []) hstoreを構築するためのバリアント その場で複数のフィールドを持つ値。

    • plpgsqlの代入演算子は:=です。 :

    • 列名mod_datetimeを使用したことに注意してください 誤解を招くmod_dateの代わりに 、列は明らかにタイムスタンプであるため dateではありません 。

    私はそれに取り組んでいる間、他のいくつかの改善を追加しました。そして、トリガー自体は次のようになります。

    CREATE TRIGGER insupdel_bef
    BEFORE INSERT OR UPDATE OR DELETE ON table_name
    FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();
    

    SQLフィドル。




    1. java.lang.ClassNotFoundException:com.mysql.jdbc.Driver(maven + jboss)

    2. レガシーデータベースを処理するときに、欠落している行でHibernateがチョークする

    3. Oracleでディレクトリを作成する方法は?

    4. 2つの日付の間のすべての日付を一覧表示する方法