aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-03-24 14:02:16 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-03-24 14:02:16 +0200
commit7939f7972cf22ee9a74518978e4f7d4d77535e09 (patch)
treeb211e2f455ef717482370fc262a63a5f7bfeb77f
parent01e70d9a1d49bcb126adc45f85168aa7c9cbad19 (diff)
Add support for clearing connection from active and uncached statements
-rw-r--r--odb/sqlite/connection.cxx32
-rw-r--r--odb/sqlite/connection.hxx14
-rw-r--r--odb/sqlite/container-statements.hxx12
-rw-r--r--odb/sqlite/object-statements.hxx16
-rw-r--r--odb/sqlite/statement-cache.cxx3
-rw-r--r--odb/sqlite/statement.cxx57
-rw-r--r--odb/sqlite/statement.hxx140
-rw-r--r--odb/sqlite/transaction-impl.cxx13
8 files changed, 243 insertions, 44 deletions
diff --git a/odb/sqlite/connection.cxx b/odb/sqlite/connection.cxx
index 37f5e20..9af5a3b 100644
--- a/odb/sqlite/connection.cxx
+++ b/odb/sqlite/connection.cxx
@@ -9,6 +9,7 @@
#include <odb/sqlite/database.hxx>
#include <odb/sqlite/connection.hxx>
+#include <odb/sqlite/statement.hxx>
#include <odb/sqlite/statement-cache.hxx>
#include <odb/sqlite/error.hxx>
@@ -19,8 +20,17 @@ namespace odb
namespace sqlite
{
connection::
+ ~connection ()
+ {
+ statement_cache_.reset (); // Free prepared statements.
+
+ if (sqlite3_close (handle_) == SQLITE_BUSY)
+ assert (false); // Connection has outstanding prepared statements.
+ }
+
+ connection::
connection (database_type& db)
- : db_ (db)
+ : db_ (db), statements_ (0)
{
int f (db.flags ());
const string& n (db.name ());
@@ -47,13 +57,21 @@ namespace odb
statement_cache_.reset (new statement_cache_type (*this));
}
- connection::
- ~connection ()
+ void connection::
+ clear ()
{
- statement_cache_.reset (); // Free prepared statements.
-
- if (sqlite3_close (handle_) == SQLITE_BUSY)
- assert (false); // Connection has outstanding prepared statements.
+ // The current first statement will remove itself from the list
+ // and make the second statement (if any) the new first.
+ //
+ while (statement* s = statements_)
+ {
+ if (!s->cached ())
+ s->finilize ();
+ else if (s->active ())
+ s->reset ();
+ else
+ assert (false); // Statement is neither active nor unached.
+ }
}
}
}
diff --git a/odb/sqlite/connection.hxx b/odb/sqlite/connection.hxx
index 0df08b3..5390609 100644
--- a/odb/sqlite/connection.hxx
+++ b/odb/sqlite/connection.hxx
@@ -23,6 +23,7 @@ namespace odb
{
namespace sqlite
{
+ class statement;
class statement_cache;
class LIBODB_SQLITE_EXPORT connection: public details::shared_base
@@ -55,14 +56,27 @@ namespace odb
return *statement_cache_;
}
+ public:
+ // Reset active and finalize uncached statements.
+ //
+ void
+ clear ();
+
private:
connection (const connection&);
connection& operator= (const connection&);
private:
+ friend class statement;
+
database_type& db_;
sqlite3* handle_;
+ // Linked list of active and uncached statements currently associated
+ // with this connection.
+ //
+ statement* statements_;
+
std::auto_ptr<statement_cache_type> statement_cache_;
};
}
diff --git a/odb/sqlite/container-statements.hxx b/odb/sqlite/container-statements.hxx
index 5f5caef..9bff64c 100644
--- a/odb/sqlite/container-statements.hxx
+++ b/odb/sqlite/container-statements.hxx
@@ -164,10 +164,14 @@ namespace odb
insert_one_statement ()
{
if (insert_one_ == 0)
+ {
insert_one_.reset (
new (details::shared) insert_statement_type (
conn_, traits::insert_one_statement, data_image_binding_));
+ insert_one_->cached (true);
+ }
+
return *insert_one_;
}
@@ -175,6 +179,7 @@ namespace odb
select_all_statement ()
{
if (select_all_ == 0)
+ {
select_all_.reset (
new (details::shared) select_statement_type (
conn_,
@@ -182,6 +187,9 @@ namespace odb
cond_image_binding_,
data_image_binding_));
+ select_all_->cached (true);
+ }
+
return *select_all_;
}
@@ -189,10 +197,14 @@ namespace odb
delete_all_statement ()
{
if (delete_all_ == 0)
+ {
delete_all_.reset (
new (details::shared) delete_statement_type (
conn_, traits::delete_all_statement, cond_image_binding_));
+ delete_all_->cached (true);
+ }
+
return *delete_all_;
}
diff --git a/odb/sqlite/object-statements.hxx b/odb/sqlite/object-statements.hxx
index 68fd04e..3ab627d 100644
--- a/odb/sqlite/object-statements.hxx
+++ b/odb/sqlite/object-statements.hxx
@@ -246,10 +246,14 @@ namespace odb
persist_statement ()
{
if (persist_ == 0)
+ {
persist_.reset (
new (details::shared) persist_statement_type (
conn_, object_traits::persist_statement, in_image_binding_));
+ persist_->cached (true);
+ }
+
return *persist_;
}
@@ -257,6 +261,7 @@ namespace odb
find_statement ()
{
if (find_ == 0)
+ {
find_.reset (
new (details::shared) find_statement_type (
conn_,
@@ -264,6 +269,9 @@ namespace odb
id_image_binding_,
out_image_binding_));
+ find_->cached (true);
+ }
+
return *find_;
}
@@ -271,6 +279,7 @@ namespace odb
update_statement ()
{
if (update_ == 0)
+ {
update_.reset (
new (details::shared) update_statement_type (
conn_,
@@ -278,6 +287,9 @@ namespace odb
id_image_binding_,
in_image_binding_));
+ update_->cached (true);
+ }
+
return *update_;
}
@@ -285,12 +297,16 @@ namespace odb
erase_statement ()
{
if (erase_ == 0)
+ {
erase_.reset (
new (details::shared) erase_statement_type (
conn_,
object_traits::erase_statement,
id_image_binding_));
+ erase_->cached (true);
+ }
+
return *erase_;
}
diff --git a/odb/sqlite/statement-cache.cxx b/odb/sqlite/statement-cache.cxx
index 66ef266..383a78e 100644
--- a/odb/sqlite/statement-cache.cxx
+++ b/odb/sqlite/statement-cache.cxx
@@ -21,6 +21,9 @@ namespace odb
commit_ (new (shared) simple_statement (conn, "COMMIT", 7)),
rollback_ (new (shared) simple_statement (conn, "ROLLBACK", 9))
{
+ rollback_->cached (true);
+ commit_->cached (true);
+ begin_->cached (true);
}
}
}
diff --git a/odb/sqlite/statement.cxx b/odb/sqlite/statement.cxx
index fc9e780..aa87939 100644
--- a/odb/sqlite/statement.cxx
+++ b/odb/sqlite/statement.cxx
@@ -24,27 +24,11 @@ namespace odb
statement::
~statement ()
{
- sqlite3_finalize (stmt_);
+ finilize ();
}
- statement::
- statement (connection& conn, const string& s)
- : conn_ (conn)
- {
- if (int e = sqlite3_prepare_v2 (
- conn_.handle (),
- s.c_str (),
- static_cast<int> (s.size () + 1),
- &stmt_,
- 0))
- {
- translate_error (e, conn_);
- }
- }
-
- statement::
- statement (connection& conn, const char* s, std::size_t n)
- : conn_ (conn)
+ void statement::
+ init (const char* s, std::size_t n)
{
if (int e = sqlite3_prepare_v2 (
conn_.handle (),
@@ -55,6 +39,14 @@ namespace odb
{
translate_error (e, conn_);
}
+
+ active_ = false;
+ cached_ = false;
+
+ prev_ = 0;
+ next_ = this;
+
+ list_add (); // Add to the list because we are uncached.
}
void statement::
@@ -233,14 +225,19 @@ namespace odb
void select_statement::
execute ()
{
+ if (active ())
+ reset ();
+
done_ = false;
bind_param (cond_.bind, cond_.count);
+ active (true);
}
void select_statement::
free_result ()
{
- sqlite3_reset (stmt_);
+ reset ();
+ done_ = true;
}
bool select_statement::
@@ -250,23 +247,13 @@ namespace odb
{
int e (sqlite3_step (stmt_));
- switch (e)
+ if (e != SQLITE_ROW)
{
- case SQLITE_DONE:
- {
- done_ = true;
- sqlite3_reset (stmt_);
- break;
- }
- case SQLITE_ROW:
- {
- break;
- }
- default:
- {
- sqlite3_reset (stmt_);
+ reset ();
+ done_ = true;
+
+ if (e != SQLITE_DONE)
translate_error (e, conn_);
- }
}
}
diff --git a/odb/sqlite/statement.hxx b/odb/sqlite/statement.hxx
index fe541e5..2a629fe 100644
--- a/odb/sqlite/statement.hxx
+++ b/odb/sqlite/statement.hxx
@@ -12,12 +12,14 @@
#include <string>
#include <cstddef> // std::size_t
+#include <cassert>
#include <odb/forward.hxx>
#include <odb/details/shared-ptr.hxx>
#include <odb/sqlite/version.hxx>
#include <odb/sqlite/binding.hxx>
+#include <odb/sqlite/connection.hxx>
#include <odb/sqlite/details/export.hxx>
namespace odb
@@ -32,10 +34,49 @@ namespace odb
virtual
~statement () = 0;
+ sqlite3_stmt*
+ handle ()
+ {
+ return stmt_;
+ }
+
+ // Cached state (public part).
+ //
+ public:
+ bool
+ cached () const
+ {
+ return cached_;
+ }
+
+ void
+ cached (bool cached)
+ {
+ assert (cached);
+
+ if (!cached_)
+ {
+ if (!active_)
+ list_remove ();
+
+ cached_ = true;
+ }
+ }
+
protected:
- statement (connection&, const std::string& statement);
- statement (connection&, const char* statement, std::size_t n);
+ statement (connection& conn, const std::string& statement)
+ : conn_ (conn)
+ {
+ init (statement.c_str (), statement.size () + 1);
+ }
+
+ statement (connection& conn, const char* statement, std::size_t n)
+ : conn_ (conn)
+ {
+ init (statement, n);
+ }
+ protected:
void
bind_param (const bind*, std::size_t count, std::size_t start_param = 0);
@@ -47,9 +88,104 @@ namespace odb
bool
bind_result (const bind*, std::size_t count, bool truncated = false);
+ // Active state.
+ //
+ protected:
+ bool
+ active () const
+ {
+ return active_;
+ }
+
+ void
+ active (bool active)
+ {
+ assert (active);
+
+ if (!active_)
+ {
+ list_add ();
+ active_ = true;
+ }
+ }
+
+ void
+ reset ()
+ {
+ if (active_)
+ {
+ if (stmt_ != 0)
+ sqlite3_reset (stmt_);
+
+ if (cached_)
+ list_remove ();
+
+ active_ = false;
+ }
+ }
+
+ // Cached state (protected part).
+ //
+ protected:
+ void
+ finilize ()
+ {
+ list_remove ();
+
+ if (stmt_ != 0)
+ {
+ sqlite3_finalize (stmt_);
+ stmt_ = 0;
+ }
+ }
+
protected:
+ friend class connection;
+
connection& conn_;
sqlite3_stmt* stmt_;
+
+ bool active_;
+ bool cached_;
+
+ private:
+ void
+ init (const char* statement, std::size_t n);
+
+ // Doubly-linked list of active/uncached statements.
+ //
+ private:
+ void list_add ()
+ {
+ if (next_ == this)
+ {
+ next_ = conn_.statements_;
+ conn_.statements_ = this;
+ }
+ }
+
+ void list_remove ()
+ {
+ if (next_ != this)
+ {
+ if (prev_ == 0)
+ conn_.statements_ = next_;
+ else
+ {
+ prev_->next_ = next_;
+ prev_ = 0;
+ }
+
+ next_ = this;
+ }
+ }
+
+ // prev_ == 0 means we are the first element.
+ // next_ == 0 means we are the last element.
+ // next_ == this means we are not on the list (prev_ should be 0).
+ //
+ statement* prev_;
+ statement* next_;
};
class LIBODB_SQLITE_EXPORT simple_statement: public statement
diff --git a/odb/sqlite/transaction-impl.cxx b/odb/sqlite/transaction-impl.cxx
index 3730100..36d6c2b 100644
--- a/odb/sqlite/transaction-impl.cxx
+++ b/odb/sqlite/transaction-impl.cxx
@@ -28,6 +28,13 @@ namespace odb
void transaction_impl::
commit ()
{
+ // Reset active and finilize uncached statements. Active statements
+ // will prevent COMMIT from completing (write statements) or releasing
+ // the locks (read statements). Finilization of uncached statements is
+ // needed to release the connection.
+ //
+ connection_->clear ();
+
connection_->statement_cache ().commit_statement ().execute ();
// Release the connection.
@@ -38,6 +45,12 @@ namespace odb
void transaction_impl::
rollback ()
{
+ // Reset active and finilize uncached statements. Active statements
+ // will prevent ROLLBACK from completing. Finilization of uncached
+ // statements is needed to release the connection.
+ //
+ connection_->clear ();
+
connection_->statement_cache ().rollback_statement ().execute ();
// Release the connection.