PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Czy w procedurze może istnieć postgres Commit, który ma blok wyjątków?

Semantyka obsługi błędów podyktuj to:

Jest to realizowane za pomocą podtransakcji, które są zasadniczo takie same jak punkty zapisu . Innymi słowy, gdy uruchomisz następujący kod PL/pgSQL:

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

...to, co się właściwie dzieje, wygląda mniej więcej tak:

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

COMMIT wewnątrz bloku złamałoby to całkowicie; Twoje zmiany zostaną wprowadzone na stałe, punkt zapisu zostanie odrzucony, a program obsługi wyjątków pozostanie bez możliwości przywrócenia. W rezultacie zatwierdzenia nie są dozwolone w tym kontekście i próba wykonania COMMIT spowoduje błąd „nie można zatwierdzić, gdy podtransakcja jest aktywna”.

Dlatego widzisz, że twoja procedura przeskakuje do procedury obsługi wyjątków zamiast uruchamiać raise notice 'B' :kiedy dotrze do commit , zgłasza błąd, a program obsługi go przechwytuje.

Jest to jednak dość proste do obejścia. BEGIN ... END bloki mogą być zagnieżdżane i tylko bloki z EXCEPTION Klauzule obejmują ustawianie punktów zapisu, więc możesz po prostu opakować polecenia przed i po zatwierdzeniu w ich własne programy obsługi wyjątków:

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

Niestety prowadzi to do wielu duplikatów w procedurach obsługi błędów, ale nie mogę wymyślić fajnego sposobu, aby tego uniknąć.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Usuń zduplikowane wiersze z tabeli

  2. Znajdź wszystkie wiersze używając jakiegoś zakresu Unicode (takiego jak znaki cyrylicy) za pomocą PostgreSQL?

  3. Wbudowane testy PostgreSQL dla Java JUnit

  4. Alternatywy dla array_agg()?

  5. Obcinanie postgresa jest powolne