web-dev-qa-db-ja.com

postgresqlトリガーのデバッグ

私はPostgresqlにこのトリガーを持っていますが、それはただ仕事に取り掛かることができません(何もしません)。理解するために、私がそれをどのように定義したかがあります:

CREATE TABLE documents (
    ...
    modification_time timestamp with time zone DEFAULT now()
);

CREATE FUNCTION documents_update_mod_time() RETURNS trigger
AS $$
    begin
    new.modification_time := now();
    return new;
    end
$$
    LANGUAGE plpgsql;

CREATE TRIGGER documents_modification_time
    BEFORE INSERT OR UPDATE ON documents
    FOR EACH ROW
    EXECUTE PROCEDURE documents_update_mod_time();

もう少し面白くするために..トリガーをどのようにデバッグしますか?

26
Dave Vogt
  1. トリガー関数内で次のコードを使用してから、pgAdmin3の[メッセージ]タブまたはpsqlの出力を確認します。

    RAISE NOTICE 'myplpgsqlval is currently %', myplpgsqlval;       -- either this
    RAISE EXCEPTION 'failed';  -- or that
    
  2. どのトリガーが実際に呼び出されるか、何回呼び出されるかなどを確認するには、次のステートメントが命の恩人として選択されます。

    EXPLAIN ANALYZE UPDATE table SET foo='bar'; -- shows the called triggers
    

    トリガーが呼び出されず、継承を使用する場合は、親テーブルでのみトリガーを定義したのに対し、トリガーは子テーブルによって自動的に継承されない可能性があることに注意してください。

  3. 関数をステップスルーするには、pgAdmin3に組み込まれているデバッガーを使用できます。このデバッガーはWindowsではデフォルトで有効になっています。あなたがしなければならないのは、デバッグしているデータベースに対して...\8.3\share\contrib\pldbgapi.sqlにあるコードを実行し、pgAdmin3を再起動し、トリガー関数を右クリックして、 'Set Breakpoint'を実行してから、上記のUPDATEステートメントなど、トリガーを起動するステートメントを実行します。

53
Kev

上記の問題で継承を使用していたことが判明し、それについて言及するのを忘れました。これに遭遇する可能性のあるすべての人のために、ここにいくつかのデバッグのヒントがあります:

次のコードを使用して、トリガーの実行内容をデバッグします。

RAISE NOTICE 'test';       -- either this
RAISE EXCEPTION 'failed';  -- or that

どのトリガーが実際に呼び出されるか、何回呼び出されるかなどを確認するには、次のステートメントが命の恩人として選択されます。

EXPLAIN ANALYZE UPDATE table SET foo='bar'; -- shows the called triggers

次に、私が以前に知らなかったことが1つあります。トリガーは、定義されている正確なテーブルを更新するときにのみ起動します。継承を使用する場合は、子テーブルでも定義する必要があります!

3
Dave Vogt

トリガー関数内で「raisenotice」ステートメントを使用してデバッグできます。トリガーがまったく呼び出されないことをデバッグすることは別の話です。

トリガー関数内に「発生例外」を追加した場合でも、挿入/更新を実行できますか?

また、更新テストが挿入テストと同じトランザクションで発生した場合、now()は同じになり(トランザクションごとに1回しか計算されないため)、更新は何もしないように見えます。その場合は、別々のトランザクションで実行するか、これが単体テストであり、それができない場合は、clock_timestamp()を使用します。

トランザクション間の時間に依存する単体テストがあるので、単体テストの開始時に次のようなものがあります。

ALTER TABLE documents
   ALTER COLUMN modification_time SET DEFAULT clock_timestamp();

次に、トリガーで「setmodification_time = default」を使用します。

したがって、通常は追加の計算は行いませんが、単体テスト中にpg_sleepを挟んで挿入を実行し、時間の経過をシミュレートして、実際にデータに反映させることができます。

3
Kev