sql >> Database >  >> RDS >> PostgreSQL

Kan een Postgres-commit bestaan ​​in een procedure met een uitzonderingsblok?

De semantiek van PL/pgSQL's foutafhandeling dicteer dat:

Dit wordt geïmplementeerd met behulp van subtransacties, die in principe hetzelfde zijn als savepoints . Met andere woorden, wanneer u de volgende PL/pgSQL-code uitvoert:

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

...wat er feitelijk gebeurt is zoiets als dit:

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

Een COMMIT binnen het blok zou dit volledig breken; uw wijzigingen zouden permanent worden gemaakt, het opslagpunt zou worden weggegooid en de uitzonderingshandler zou geen manier meer hebben om terug te draaien. Als gevolg hiervan zijn commits niet toegestaan ​​in deze context en wordt geprobeerd een COMMIT . uit te voeren zal resulteren in een "kan niet vastleggen terwijl een subtransactie actief is" fout.

Daarom zie je je procedure naar de exception-handler springen in plaats van de raise notice 'B' uit te voeren :wanneer het de commit . bereikt , het geeft een fout en de handler vangt het op.

Dit is echter vrij eenvoudig om te omzeilen. BEGIN ... END blokken kunnen worden genest, en alleen blokken met EXCEPTION clausules omvatten het instellen van opslagpunten, dus je kunt de commando's voor en na de commit gewoon in hun eigen uitzonderingshandlers inpakken:

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

Helaas leidt het tot veel dubbel werk in de foutafhandelingen, maar ik kan geen leuke manier bedenken om het te vermijden.



  1. Mysql Like met wildcart die onverwacht resultaat geeft

  2. Rails passeren de DB Query niet op zoekformulier

  3. Session_set_save_handler niet ingesteld

  4. Laravel 4 :Hoe krijg ik geselecteerde/specifieke kolommen in een veel-op-veel relatie?