aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-09-02 14:40:50 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-09-02 14:40:50 +0200
commitc3248cd60418cee935508f62a3436970f9d234b2 (patch)
tree957ea8516d0faa937f3b84db873000d21041fb04
parent534da0d899b11f6ca1fac161ea8901a62e5c07dc (diff)
Handle SQLite commit failures that don't automatically rollback transaction
-rw-r--r--odb/sqlite/transaction-impl.cxx35
1 files changed, 34 insertions, 1 deletions
diff --git a/odb/sqlite/transaction-impl.cxx b/odb/sqlite/transaction-impl.cxx
index 2a06288..3df1250 100644
--- a/odb/sqlite/transaction-impl.cxx
+++ b/odb/sqlite/transaction-impl.cxx
@@ -2,6 +2,8 @@
// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <sqlite3.h>
+
#include <odb/sqlite/database.hxx>
#include <odb/sqlite/connection.hxx>
#include <odb/sqlite/statement.hxx>
@@ -64,6 +66,33 @@ namespace odb
}
}
+ // In SQLite, when a commit fails (e.g., because of the deferred
+ // foreign key constraint violation), the transaction may not
+ // be automatically rolled back. So we have to do it ourselves.
+ //
+ struct commit_guard
+ {
+ commit_guard (connection& c): c_ (&c) {}
+ void release () {c_ = 0;}
+
+ ~commit_guard ()
+ {
+ if (c_ != 0 && sqlite3_get_autocommit (c_->handle ()) == 0)
+ {
+ // This is happening while another exception is active.
+ //
+ try
+ {
+ c_->statement_cache ().rollback_statement ().execute ();
+ }
+ catch (...) {}
+ }
+ }
+
+ private:
+ connection* c_;
+ };
+
void transaction_impl::
commit ()
{
@@ -79,7 +108,11 @@ namespace odb
//
connection_->clear ();
- connection_->statement_cache ().commit_statement ().execute ();
+ {
+ commit_guard cg (*connection_);
+ connection_->statement_cache ().commit_statement ().execute ();
+ cg.release ();
+ }
// Release the connection.
//