I’m using Npgsql 2.0.11 under .NET 4.0 to modify a PostgreSQL 9.0 database. The program makes many modifications to the database, all within a single transaction.
Just before committing, I run SELECT statement, which sometimes fails (eg. with a timeout). I swallow the exception and go ahead and commit the transaction anyway. There is no error, so it appears as if everything worked, but in actual fact the database was not modified at all!
My guess is that the failed SELECT rolled back the entire transaction. Can I either prevent this (ie. have the transaction still committed) or at least detect this situation and throw an exception, so the user knows the commit failed?
I know that in this specific case I could just move the SELECT outside the transaction, but I’m more concerned about solving this for the general case. Having a commit not commit is a pretty serious problem and I want to make sure it doesn’t go undetected.
I know nothing about Npgsql, but I can speak to the behavior of PostgreSQL. When any error occurs within a PostgreSQL transaction, the transaction is marked invalid until it is closed. (Their term is “aborted”, which I think is misleading.) Furthermore, and this is IMHO insane, if you
COMMITan invalid transaction, it “succeeds” but has the same effect asROLLBACK. You can observe this in thepsqlREPL; it will printROLLBACKin response to yourCOMMITcommand, but it won’t signal an error.You can create a
SAVEPOINTright before your finalSELECT. If it fails, thenROLLBACKto the savepoint name; that will get you out of the invalid state and allow you to commit the previous part of the transaction.