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

例外ブロックがあるプロシージャにPostgresコミットは存在できますか?

    PL/pgSQLのエラー処理のセマンティクス それを口述する:

    これは、サブトランザクションを使用して実装されます。サブトランザクションは、基本的にセーブポイント と同じです。 。つまり、次のPL /pgSQLコードを実行すると:

    BEGIN
      PERFORM foo();
    EXCEPTION WHEN others THEN
      PERFORM handle_error();
    END
    

    ...実際に起こっていることは次のようなものです:

    BEGIN
      SAVEPOINT a;
      PERFORM foo();
      RELEASE SAVEPOINT a;
    EXCEPTION WHEN others THEN
      ROLLBACK TO SAVEPOINT a;
      PERFORM handle_error();
    END
    

    COMMIT ブロック内ではこれを完全に壊します。変更は永続的になり、セーブポイントは破棄され、例外ハンドラーはロールバックする方法がなくなります。その結果、このコンテキストではコミットは許可されず、COMMITを実行しようとします。 「サブトランザクションがアクティブな間はコミットできません」というエラーが発生します。

    そのため、raise notice 'B'を実行する代わりに、プロシージャが例外ハンドラにジャンプするのがわかります。 :commitに達したとき 、エラーをスローし、ハンドラーがそれをキャッチします。

    ただし、これを回避するのはかなり簡単です。 BEGIN ... END ブロックはネストでき、EXCEPTIONのブロックのみ 句にはセーブポイントの設定が含まれるため、コミットの前後にコマンドを独自の例外ハンドラーでラップできます。

    create or replace procedure x_transaction_try() language plpgsql
    as $$
    declare
      my_ex_state text;
      my_ex_message text;
      my_ex_detail text;
      my_ex_hint text;
      my_ex_ctx text;
    begin
      begin
        raise notice 'A';
      exception when others then
        raise notice 'C';
        GET STACKED DIAGNOSTICS
          my_ex_state   = RETURNED_SQLSTATE,
          my_ex_message = MESSAGE_TEXT,
          my_ex_detail  = PG_EXCEPTION_DETAIL,
          my_ex_hint    = PG_EXCEPTION_HINT,
          my_ex_ctx     = PG_EXCEPTION_CONTEXT
        ;
        raise notice '% % % % %', my_ex_state, my_ex_message, my_ex_detail, my_ex_hint, my_ex_ctx;
      end;
    
      commit;
    
      begin
        raise notice 'B';
      exception when others then
        raise notice 'C';
        GET STACKED DIAGNOSTICS
          my_ex_state   = RETURNED_SQLSTATE,
          my_ex_message = MESSAGE_TEXT,
          my_ex_detail  = PG_EXCEPTION_DETAIL,
          my_ex_hint    = PG_EXCEPTION_HINT,
          my_ex_ctx     = PG_EXCEPTION_CONTEXT
        ;
        raise notice '% % % % %', my_ex_state, my_ex_message, my_ex_detail, my_ex_hint, my_ex_ctx;
      end;      
    end;
    $$;
    

    残念ながら、エラーハンドラーで多くの重複が発生しますが、それを回避するための良い方法は考えられません。



    1. PostgreSQLでINSERTまたはUPDATEの影響を受けるレコードの数を取得します

    2. PostgreSQLでのcbrt()のしくみ

    3. Oracleのリテラル文字(コロン、セミコロン)を使用したSELECTクエリ

    4. mysqlの時間比較