PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bisakah Komit Postgres Ada dalam Prosedur yang memiliki Blok Pengecualian?

Semantik PL/pgSQL penanganan kesalahan tentukan bahwa:

Ini diimplementasikan menggunakan subtransaksi, yang pada dasarnya sama dengan savepoints . Dengan kata lain, ketika Anda menjalankan kode PL/pgSQL berikut:

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

...yang sebenarnya terjadi adalah seperti ini:

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

Sebuah COMMIT di dalam blok akan menghancurkan ini sepenuhnya; perubahan Anda akan dibuat permanen, savepoint akan dibuang, dan handler pengecualian akan dibiarkan tanpa cara untuk memutar kembali. Akibatnya, komit tidak diizinkan dalam konteks ini, dan mencoba menjalankan COMMIT akan menghasilkan kesalahan "tidak dapat melakukan saat subtransaksi aktif".

Itulah mengapa Anda melihat prosedur Anda melompat ke handler pengecualian alih-alih menjalankan raise notice 'B' :ketika mencapai commit , itu melempar kesalahan, dan pawang menangkapnya.

Ini cukup mudah untuk diatasi. BEGIN ... END blok dapat disarangkan, dan hanya blok dengan EXCEPTION klausa melibatkan pengaturan savepoints, jadi Anda bisa membungkus perintah sebelum dan sesudah komit di penangan pengecualian mereka sendiri:

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;
$$;

Sayangnya, hal itu menyebabkan banyak duplikasi pada penangan kesalahan, tetapi saya tidak dapat memikirkan cara yang baik untuk menghindarinya.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pilih Query untuk memeriksa keduanya atau salah satu atau kondisi

  2. Bagaimana cara melakukan kueri pemilihan di blok DO?

  3. Gabung luar kiri bertindak seperti gabung dalam

  4. Bagaimana cara menjalankan SQL mentah dalam migrasi Django

  5. Tugas Rake Heroku Rails untuk Menyinkronkan Produksi &DB Lokal