sql >> Databasteknik >  >> RDS >> PostgreSQL

Kan ett Postgres-åtagande existera i förfarandet som har ett undantagsblock?

Semantiken för PL/pgSQL:s felhantering diktera att:

Detta implementeras med hjälp av undertransaktioner, som i princip är samma som savepoints . Med andra ord, när du kör följande PL/pgSQL-kod:

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

...det som faktiskt händer är ungefär så här:

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

En COMMIT inom blocket skulle bryta detta helt; dina ändringar skulle göras permanenta, räddningspunkten skulle förkastas och undantagshanteraren skulle inte kunna rulla tillbaka. Som ett resultat är commits inte tillåtna i det här sammanhanget, och försök att köra en COMMIT kommer att resultera i felet "kan inte begå medan en deltransaktion är aktiv".

Det är därför du ser din procedur hoppa till undantagshanteraren istället för att köra raise notice 'B' :när den når commit , det ger ett fel och hanteraren fångar det.

Detta är dock ganska enkelt att komma runt. BEGIN ... END block kan kapslas, och endast block med EXCEPTION satser involverar inställning av räddningspunkter, så du kan bara linda kommandona före och efter commit i deras egna undantagshanterare:

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

Tyvärr leder det till en hel del dubbelarbete i felhanterarna, men jag kan inte komma på något bra sätt att undvika det.



  1. Hur man gör en del av texten fet från arraylist i Android

  2. Hitta antalet rader i den första tabellen som matchar id för raden i den andra tabellen med maxdatum

  3. Infoga filen i mysql Blob

  4. Allmän JDBC-inställning