Re: Error on failed COMMIT

From: "Haumacher, Bernhard" <haui(at)haumacher(dot)de>
To: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Error on failed COMMIT
Date: 2020-02-13 07:38:18
Message-ID: aff65d7d-7871-e899-68ae-bff0eb1b47a4@haumacher.de
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Am 12.02.2020 um 00:27 schrieb Tom Lane:
> Vik Fearing <vik(at)postgresfriends(dot)org> writes:
>> Actually, I was imagining that it would end the transaction as it does
>> today, just with an error code.
>> This is backed up by General Rule 9 which says "The current
>> SQL-transaction is terminated."
> Hm ... that would be sensible, but I'm not entirely convinced. There
> are several preceding rules that say that an exception condition is
> raised, and normally you can stop reading at that point; nothing else
> is going to happen. If COMMIT acts specially in this respect, they
> ought to say so.
>
> In any case, while this interpretation might change the calculus a bit,
> I think we still end up concluding that altering this behavior has more
> downside than upside.

Let me illustrate this issue from an application (framework) developer's
perspective:

When an application interacts with a database, it must be clearly
possible to determine, whether a commit actually succeeded (and made all
changes persistent), or the commit failed for any reason (and all of the
changes have been rolled back). If a commit succeeds, an application
must be allowed to assume that all changes it made in the preceeding
transaction are made persistent and it is valid to update its internal
state (e.g. caches) to the values updated in the transaction. This must
be possible, even if the transaction is constructed collaboratively by
multipe independent layers of the application (e.g. a framework and an
application layer). Unfortunately, this seems not to be possible with
the current implementation - at least not with default settings:

Assume the application is written in Java and sees Postgres through the
JDBC driver:

composeTransaction() {
   Connection con = getConnection(); // implicitly "begin"
   try {
      insertFrameworkLevelState(con);
      insertApplicationLevelState(con);
      con.commit();
      publishNewState();
   } catch (Throwable ex) {
      con.rollback();
   }
}

With the current implementation, it is possible, that the control flow
reaches "publishNewState()" without the changes done in
"insertFrameworkLevelState()" have been made persistent - without the
framework-level code (which is everything except
"insertApplicationLevelState()") being able to detect the problem (e.g.
if "insertApplicationLevelState()" tries add a null into a non-null
column catching the exception or any other application-level error that
is not properly handled through safepoints).

From a framework's perspective, this behavior is absolutely
unacceptable. Here, the framework-level code sees a database that
commits successfully but does not make its changes persistent.
Therefore, I don't think that altering this behavior has more downside
than upside.

Best regards

Bernhard

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Michael Paquier 2020-02-13 07:48:21 Re: pgsql: walreceiver uses a temporary replication slot by default
Previous Message Amit Langote 2020-02-13 07:31:48 Re: Identifying user-created objects