sql >> Databáze >  >> RDS >> PostgreSQL

Může Postgres Commit existovat v proceduře, která má blok výjimky?

Sémantika zpracování chyb v PL/pgSQL /a> diktovat, že:

To je implementováno pomocí dílčích transakcí, které jsou v podstatě stejné jako savepoints . Jinými slovy, když spustíte následující kód PL/pgSQL:

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

...to, co se ve skutečnosti děje, je něco takového:

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

A COMMIT uvnitř bloku by to úplně porušilo; vaše změny by se staly trvalými, bod uložení by byl zahozen a obsluha výjimky by neměla žádný způsob, jak se vrátit zpět. V důsledku toho nejsou v tomto kontextu povoleny odevzdání a pokus o provedení COMMIT bude mít za následek chybu „nelze potvrdit, když je dílčí transakce aktivní“.

Proto vidíte, že vaše procedura skočí na obslužnou rutinu výjimky namísto spuštění raise notice 'B' :když dosáhne commit , vyvolá chybu a handler ji zachytí.

To je však docela jednoduché obejít. BEGIN ... END bloky lze vnořit a pouze bloky s EXCEPTION klauzule zahrnují nastavení bodů uložení, takže můžete jednoduše zabalit příkazy před a po odevzdání do jejich vlastních obslužných rutin výjimek:

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

Bohužel to vede ke spoustě duplicit v obslužných programech chyb, ale nenapadá mě žádný pěkný způsob, jak se tomu vyhnout.



  1. Jak zakázat všechna omezení CHECK a cizích klíčů pro tabulku na serveru SQL (příklady T-SQL)

  2. Dotaz na přeindexování primárního klíče databáze MySQL

  3. Přidejte sloupec, který představuje zřetězení dvou dalších sloupců Varchar

  4. Jak zabráním duplicitním záznamům v databázi při aktualizaci záznamů?