I have to process records in a stored procedure's loop, for example:
create or alter procedure process_waiting_records
as
declare v_id type of column my_table.id;
begin
for
select
t.id
from
my_table t
where
(t.status = 'WAITING_TO_PROCESS')
order by
t.created_at
into
:v_id
do
begin
execute procedure process_one_record(:v_id);
end
end ^
The problem is when the execution of process_one_record()
fails (generates any kind of exception), the whole set of modification will be rolled back from the calling code.
The goal would be to process all possible records, I don't really care at this point if some of the records can not be processed, those failed records will be logged in a log table anyway (using autonomous transaction).
I was thinking about to call the process_one_record()
stored procedure also in an autonomous transaction block with when any do (dummy code)
clause. However, I think that is not going to work, because that failed transaction will not be rolled back, but committed (referring to this topic: Firebird 2.5 exception handling within autonomous transaction).
Could some one please point me to the right direction how to solve this problem?
You don't need anonymous transactions for this. When an exception is thrown out of a stored procedure, the effects of that stored procedure is automatically undone. If a stored procedure contains
SUSPEND
, only the effects up to the lastSUSPEND
is undone (think of it as a savepoint). For any other forms of rollback, a transaction will need to be explicitly rolled back.See also Savepoints and PSQL in the Firebird 2.5 Language Reference.
In this case, as the effects of a single
process_one_record
needs to be undone, but not the whole handling inprocess_waiting_records
, you need to allow the exception to be thrown out ofprocess_one_record
, but catch it for that single procedure invocation.In short, you need to do something like: