From c3248cd60418cee935508f62a3436970f9d234b2 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 2 Sep 2013 14:40:50 +0200 Subject: Handle SQLite commit failures that don't automatically rollback transaction --- odb/sqlite/transaction-impl.cxx | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'odb') 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 + #include #include #include @@ -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. // -- cgit v1.1