PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Може ли Postgres Commit да съществува в процедура, която има блок за изключение?

Семантиката на обработка на грешки<на PL/pgSQL /a> диктуват, че:

Това се реализира с помощта на подтранзакции, които по същество са същите като точки за запис . С други думи, когато изпълните следния PL/pgSQL код:

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

...това, което всъщност се случва, е нещо като това:

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

COMMIT в рамките на блока би нарушил това напълно; вашите промени ще бъдат направени постоянни, точката за запис ще бъде отхвърлена и манипулаторът на изключения ще остане без начин да се върне назад. В резултат на това ангажиментите не са разрешени в този контекст и се опитват да изпълнят COMMIT ще доведе до грешка „не може да се ангажира, докато е активна подтранзакция“.

Ето защо виждате как процедурата ви прескача към манипулатора на изключения, вместо да изпълнява raise notice 'B' :когато достигне commit , той извежда грешка и манипулаторът я хваща.

Това обаче е доста лесно да се заобиколи. BEGIN ... END блокове могат да бъдат вложени и само блокове с EXCEPTION клаузите включват задаване на точки за запис, така че можете просто да обвиете командите преди и след ангажимента в техните собствени манипулатори на изключения:

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

За съжаление, това наистина води до много дублиране в манипулаторите на грешки, но не мога да измисля добър начин да го избегна.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Използване на безакцент с SearchVector и SearchQuery в Django

  2. Редактиране на файл от Sublime Text 2 от командния ред при SSH във Vagrant Virtual Box (Linux Ubuntu Machine)

  3. групиране на всеки N стойности

  4. ClassCastException:Цяло число не може да бъде прехвърлено към Long, докато се опитвате да повторите идентификаторите на обекти

  5. Импортирайте XML файлове в PostgreSQL