sql >> Database teknologi >  >> RDS >> PostgreSQL

Kan der eksistere en Postgres-forpligtelse i en procedure, der har en undtagelsesblok?

Semantikken i PL/pgSQL's fejlhåndtering diktere at:

Dette er implementeret ved hjælp af undertransaktioner, som grundlæggende er det samme som savepoints . Med andre ord, når du kører følgende PL/pgSQL-kode:

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

...hvad der rent faktisk sker er sådan noget her:

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

En COMMIT inden for blokken ville bryde dette fuldstændigt; dine ændringer ville blive gjort permanente, savepunktet ville blive kasseret, og undtagelsesbehandleren ville ikke kunne rulle tilbage. Som et resultat er commits ikke tilladt i denne sammenhæng, og forsøg på at udføre en COMMIT vil resultere i fejlen "kan ikke foretage, mens en undertransaktion er aktiv".

Det er derfor, du ser din procedure springe til undtagelsesbehandleren i stedet for at køre raise notice 'B' :når den når commit , det kaster en fejl, og handleren fanger den.

Dette er dog ret ligetil at omgås. BEGIN ... END blokke kan indlejres, og kun blokke med EXCEPTION klausuler involverer indstilling af savepoints, så du bare kan pakke kommandoerne før og efter commit i deres egne undtagelsesbehandlere:

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

Desværre fører det til en masse dobbeltarbejde i fejlbehandlerne, men jeg kan ikke komme i tanke om en god måde at undgå det på.



  1. Postgresql enum hvad er fordelene og ulemperne?

  2. Efter Windows 10 opdatering 1803 kan mit program ikke åbne en socket, når det kører fra netværksdeling

  3. SQL Server:Filteroutput af sp_who2

  4. Tæller antallet af sammenføjede rækker i venstre sammenføjning