Re: Error on failed COMMIT

2020-02-26 Thread Haumacher, Bernhard

Am 24.02.2020 um 13:34 schrieb Robert Haas:

As I said upthread, I think one of the things that would be pretty
badly broken by this is psql -f something.sql, where something.sql
contains a series of blocks of the form "begin; something; something;
something; commit;". Right now whichever transactions succeed get
committed. With the proposed change, if one transaction block fails,
it'll merge with all of the following blocks.



No, that's *not* true.

The only difference with the proposed change would be another error in 
the logs for the commit following the block with the failed insert. 
Note: Nobody has suggested that the commit that returns with an error 
should not end the transaction. Do just the same as with any other 
commit error in response to a constraint violation!



Am 24.02.2020 um 18:53 schrieb David Fetter:

On Mon, Feb 24, 2020 at 06:40:16PM +0100, Vik Fearing wrote:

On 24/02/2020 18:37, David Fetter wrote:

If we'd done this from a clean sheet of paper, it would have been the
right decision. We're not there, and haven't been for decades.

OTOH, it's never too late to do the right thing.

Some right things take a lot of prep work in order to actually be
right things. This is one of them.  Defaulting to SERIALIZABLE
isolation is another.



Here the proposed changes is really much much less noticable - please 
report the error (again) instead of giving an incomprehensible status 
code. Nothing else must be changed - the failing commit should do the 
rollback and end the transaction - but it should report this situation 
as an error!


Regards Bernhard






Re: Error on failed COMMIT

2020-02-19 Thread Haumacher, Bernhard

Am 17.02.2020 um 23:12 schrieb Dave Cramer:
On Mon, 17 Feb 2020 at 13:02, Haumacher, Bernhard <mailto:h...@haumacher.de>> wrote:


... would be an appropriate solution. PostgreSQL reports the
"unsuccessful" commit through the "ROLLBACK" status code and the
driver
translates this into a Java SQLException, because this is the only
way
to communicate the "non-successfullness" from the void commit()
method.
Since the commit() was not successful, from the API point of view
this
is an error and it is fine to report this using an exception.


Well it doesn't always report the unsuccessful commit as a rollback 
sometimes it says

"there is no transaction" depending on what happened in the transaction

even worse...


Also when there is an error there is also a status provided by the 
backend.
Since this is not an error to the backend there is no status that the 
exception can provide.

be free to choose/define one...


Doing this in a (non-default) driver setting is not ideal, because I
expect do be notified *by default* from a database (driver) if a
commit
was not successful (and since the API is void, the only notification
path is an exception). We already have a non-default option named
"autosafe", which fixes the problem somehow.


The challenge with making this the default, is as Tom noted, many 
other people don't expect this.


Nobody expects a database reporting a successful commit, while it 
internally rolled back.


If there is code out there depending on this bug, it is fair to provide 
a backwards-compatible option to re-activate this unexpected behavior.



What many other frameworks do is have vendor specific behaviour.
Perhaps writing a proxying driver might solve the problem?


That's exactly what we do - extending our database abstraction layer to 
work around database-specific interpretations of the JDBC API.


But of cause, the abstraction layer is not able to reconstruct an error 
from a commit() call, that has been dropped by the driver. Of cause, I 
could try to insert another dummy entry into a dummy table immediately 
before each commit to get again the exception reporting that the 
transaction is in rollback-only-mode... but this does not sound 
reasonable to me.



If we really need both behaviors ("silently ignore failed commits"
and
"notify about failed commits") I would prefer adding a
backwards-compatible option
"silently-ignore-failed-commit-due-to-auto-rollback" (since it is a
really aburd setting from my point of view, since consistency is
at risk
if this happens - the worst thing to expect from a database).


The error has been reported to the client. At this point the client is 
expected to do a rollback.


As I explained, there is not "the client" but there are several software 
layers - and the error only has been reported to some of these layers 
that may decide not to communicate the problem down the road. Therefore, 
the final commit() must report the problem again.


Best regard, Bernhard



Re: Error on failed COMMIT

2020-02-17 Thread Haumacher, Bernhard

Am 14.02.2020 um 20:36 schrieb Robert Haas:

On Fri, Feb 14, 2020 at 2:08 PM Dave Cramer  wrote:

Well now you are asking the driver to re-interpret the results in a different 
way than the server which is not what we tend to do.

The server throws an error we throw an error. We really aren't in the business 
of re-interpreting the servers responses.

I don't really see a reason why the driver has to throw an exception
if and only if there is an ERROR on the PostgreSQL side. But even if
you want to make that rule for some reason, it doesn't preclude
correct behavior here. All you really need is to have con.commit()
return some indication of what the command tag was, just as, say, psql
would do.


I think, this would be an appropriate solution. PostgreSQL reports the 
"unsuccessful" commit through the "ROLLBACK" status code and the driver 
translates this into a Java SQLException, because this is the only way 
to communicate the "non-successfullness" from the void commit() method. 
Since the commit() was not successful, from the API point of view this 
is an error and it is fine to report this using an exception.


Am 14.02.2020 um 21:07 schrieb Tom Lane:

Dave Cramer  writes:

We have the same blast radius.
I have offered to make the behaviour requested dependent on a configuration
parameter but apparently this is not sufficient.

Nope, that is absolutely not happening.  We learned very painfully, back
around 7.3 when we tried to put in autocommit on/off, that if server
behaviors like this are configurable then most client code has to be
prepared to work with every possible setting.  The argument that "you can
just set it to work the way you expect" is a dangerous falsehood.  I see
no reason to think that a change like this wouldn't suffer the same sort
of embarrassing and expensive failure that autocommit did.


Doing this in a (non-default) driver setting is not ideal, because I 
expect do be notified *by default* from a database (driver) if a commit 
was not successful (and since the API is void, the only notification 
path is an exception). We already have a non-default option named 
"autosafe", which fixes the problem somehow.


If we really need both behaviors ("silently ignore failed commits" and 
"notify about failed commits") I would prefer adding a 
backwards-compatible option 
"silently-ignore-failed-commit-due-to-auto-rollback" (since it is a 
really aburd setting from my point of view, since consistency is at risk 
if this happens - the worst thing to expect from a database).


Regards,  Bernhard





Re: Error on failed COMMIT

2020-02-12 Thread Haumacher, Bernhard

Am 12.02.2020 um 00:27 schrieb Tom Lane:

Vik Fearing  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