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.