Here’s below my procedure. Inside u find a loop. Target is if any of single loop execution will throw exception i don’t want to stop the process and want to continue and commit
each loop query which was executed succesfully. Therefore i placed exception catch inside loop. As u can see i also got a commit
at the end and some begin/end
blocks. My question is whether did i correctly or maybe i should put additional commit
inside begin/end
inside the loop (just after execute mysql
;)? Thank you in advance.
CREATE OR REPLACE PROCEDURE myProc()
LANGUAGE plpgsql
AS $procedure$
declare
mysql text;
tb_name text;
myTables CURSOR for
SELECT table_name
FROM information_schema.tables
WHERE table_type='BASE TABLE'
AND table_schema='dist';
begin
begin
call DoSomeJob();
for tb in myTables loop
tb_name := tb;
begin
mysql := format('delete from %I where somecol=2', tb_name);
execute mysql;
exception
when others then
raise notice '% %', SQLERRM, SQLSTATE;
end ;
end loop;
call doOtherJob();
exception
when others then
raise notice 'The transaction is in an uncommittable state. '
'Transaction was rolled back';
raise notice '%: %', SQLSTATE, sqlerrm;
end ;
commit;
end;
$procedure$
;
UPDATE:
CREATE OR REPLACE PROCEDURE myProc()
LANGUAGE plpgsql
AS $procedure$
declare
mysql text;
tb_name text;
myTables CURSOR for
SELECT table_name
FROM information_schema.tables
WHERE table_type='BASE TABLE'
AND table_schema='dist';
begin
begin
call DoSomeJob();
exception
when others then
raise notice 'The transaction is in an uncommittable state. '
'Transaction was rolled back';
raise notice '%: %', SQLSTATE, sqlerrm;
end;
RAISE EXCEPTION 'ERROR test';
for tb in myTables loop
tb_name := tb;
begin
mysql := format('delete from %I where somecol=2', tb_name);
execute mysql;
exception
when others then
raise notice '% %', SQLERRM, SQLSTATE;
end ;
end loop;
begin
call doOtherJob();
exception
when others then
raise notice 'The transaction is in an uncommittable state. '
'Transaction was rolled back';
raise notice '%: %', SQLSTATE, sqlerrm;
end;
commit;
end;
$procedure$;
2
Answers
I explain you how to works PostgreSQL transactions in procedures.
Firstly
And when you using transaction in another transaction (sub transactions) when your first level transaction rollbacked then all sub transactions also will be rollbacked.
For example:
Here when
call2
failed thencall1
also be failed. Because blockcall1
is in the blockcall2
And on your procedure – when
doOtherJob()
will be fail then all your inserted data will fail to. For solving this problem you can write your procedure as below:You can set for block
DoSomeJob()
to the same logic.When using procedures in PostgreSQL, especially about transactions, you need to know and understand some details well. I will now explain to you the important details and you will understand how it works.
begin – this is start transaction (always)
exception
end – this is not always
commit-transaction
, because if exception is created thenend
will berollback-transaction
if elseend
will becommit-transaction
And remember that: each block
end
affects only its own blockbegin
At the same time, pay attention to this:
During rollback process, all other
begin-exception-end
blocks which is under between thebegin
block and theexception
block will be rollback.Please execute this block and view result:
select * from table test1
block 1
– success execute (success insert 1) – commitblock 2
– execute with error (no inserted record) – rollbackblock 3
– execute success (success insert 3) – commitblock 5
– execute success (success insert 5) – commitblock 4
– execute with error (no inserted record) – rollbackSince
block 5
is insideblock 4
soblock 5
already rollbacked