[subxacts] Aborting a function - Mailing list pgsql-hackers

From Alvaro Herrera
Subject [subxacts] Aborting a function
Date
Msg-id 20040708194226.GA10855@dcc.uchile.cl
Whole thread Raw
Responses Re: [subxacts] Aborting a function
Re: [subxacts] Aborting a function
List pgsql-hackers
[Note: my ISP is having problems with email, so probably a duplicate
of this will be published as soon as their SMTP starts working again]


There's a point that hasn't been raised in discussion of subtransactions
here and it's what to do when a function aborts.

If I have a plpgsql function that goes like

subbegin; ... do work ...;
subcommit;

and then the "work" causes a subtransaction abort, what should happen?
Currently the system remains inside the subtransaction that the function
created --- the "subcommit" is never executed and thus the
subtransaction is never closed.  This is wrong.

(We could talk about exception support in plpgsql or other language
handlers but I don't think this is going to happen for 7.5.)


I think the right thing to do is close all subtransactions that the
function may have created, abort the (sub)transaction that created the
function itself, and return control to the application in an aborted
state.

Furthermore, suppose a function is called which creates subtransactions,
and inside that function there's another function which creates more
subtransactions, and inside one of those inner subtransactions there is
an error.  In this case, the right thing to do is abort all
subtransactions created in the second function, and all subtransactions
created in the first function, and then return control to the
application, in an aborted state.

As a simple example, consider this:


create function crashme2() returns int strict language plpgsql as '
begin  subbegin;     select foo;         -- aborts the transaction                         -- did not close the
subxact
end;';

create function crashme5() returns int strict language plpgsql as 'begin subbegin; perform crashme2(); subabort; end;
';


begin; subbegin;   select crashme5(); subabort; subcommit;            -- WARNING: there is no subxact in progress
commit;


The point here is to observe that the transaction is taken back to the
correct nesting level after the function aborts.  The server reacts with
the following error report:

alvherre=#     select crashme5();
ERROR:  no existe la columna "foo"
CONTEXT:  SQL query "SELECT  foo"
PL/pgSQL function "crashme2" line 1 at SQL statement
SQL query "SELECT  crashme2()"
PL/pgSQL function "crashme5" line 1 at perform


This is working with a patch I'm testing now, modelled after an idea of
Bruce.  It works by setting an "abort level" when the function is going
to be called, and unsetting it when the function is done executing.  If
there is a transaction abort, the unset won't happen, and the aborting
code will see the marker defined, close all the levels up to the marker,
and then put that transaction in aborted state.

I have tested it using functions in the targetlist (modifying
ExecEvalFunc) and as rangevars (ExecInitFunctionScan and
ExecEndFunctionScan).  Maybe ExecEvalOper needs to do the same, if an
operator can be defined as dependant on a function which uses subxacts.

Comments, opinions please?

-- 
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
"Use it up, wear it out, make it do, or do without"


pgsql-hackers by date:

Previous
From: Alvaro Herrera
Date:
Subject: Re: Nested Transactions, Abort All
Next
From: Barry Lind
Date:
Subject: Re: Nested Transactions, Abort All