aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-03-22 16:22:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-03-22 16:22:06 +0200
commitbe5909a7fc240c007bb0128353d493af947a8749 (patch)
tree84f4e6488adcde96e5e41a691c191035da6e92c1
parent878a448f86ddd60e5eb7778e88edd965003ea480 (diff)
Add object and container statement caches
-rw-r--r--odb/sqlite/container-statements.hxx179
-rw-r--r--odb/sqlite/container-statements.txx36
-rw-r--r--odb/sqlite/makefile1
-rw-r--r--odb/sqlite/object-statements.cxx17
-rw-r--r--odb/sqlite/object-statements.hxx333
-rw-r--r--odb/sqlite/object-statements.ixx54
-rw-r--r--odb/sqlite/object-statements.txx77
-rw-r--r--odb/sqlite/statement-cache.hxx10
8 files changed, 697 insertions, 10 deletions
diff --git a/odb/sqlite/container-statements.hxx b/odb/sqlite/container-statements.hxx
new file mode 100644
index 0000000..a114990
--- /dev/null
+++ b/odb/sqlite/container-statements.hxx
@@ -0,0 +1,179 @@
+// file : odb/sqlite/container-statements.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SQLITE_CONTAINER_STATEMENTS_HXX
+#define ODB_SQLITE_CONTAINER_STATEMENTS_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/forward.hxx>
+#include <odb/traits.hxx>
+
+#include <odb/sqlite/version.hxx>
+#include <odb/sqlite/binding.hxx>
+#include <odb/sqlite/statement.hxx>
+#include <odb/sqlite/details/export.hxx>
+
+namespace odb
+{
+ namespace sqlite
+ {
+ class connection;
+
+ // Template argument is the generated container traits type.
+ //
+ template <typename T>
+ class container_statements
+ {
+ public:
+ typedef T traits;
+
+ typedef typename traits::id_image_type id_image_type;
+ typedef typename traits::data_image_type data_image_type;
+ typedef typename traits::cond_image_type cond_image_type;
+
+ typedef typename traits::functions_type functions_type;
+
+ typedef sqlite::insert_statement insert_statement_type;
+ typedef sqlite::select_statement select_statement_type;
+ typedef sqlite::delete_statement delete_statement_type;
+
+ typedef sqlite::connection connection_type;
+
+ container_statements (connection_type&);
+
+ connection_type&
+ connection ()
+ {
+ return conn_;
+ }
+
+ // Functions.
+ //
+ functions_type&
+ functions ()
+ {
+ return functions_;
+ }
+
+ // Id image (external).
+ //
+ id_image_type&
+ id_image ()
+ {
+ return *id_image_;
+ }
+
+ void
+ id_image (id_image_type& i)
+ {
+ id_image_ = &i;
+ }
+
+ // Condition image.
+ //
+ cond_image_type&
+ cond_image ()
+ {
+ return cond_image_;
+ }
+
+ binding&
+ cond_image_binding ()
+ {
+ return cond_image_binding_;
+ }
+
+ // Data image.
+ //
+ data_image_type&
+ data_image ()
+ {
+ return data_image_;
+ }
+
+ binding&
+ data_image_binding ()
+ {
+ return data_image_binding_;
+ }
+
+ bool*
+ data_image_truncated ()
+ {
+ return data_image_truncation_;
+ }
+
+ //
+ // Statements.
+ //
+
+ insert_statement_type&
+ insert_one_statement ()
+ {
+ if (insert_one_ == 0)
+ insert_one_.reset (
+ new (details::shared) insert_statement_type (
+ conn_, traits::insert_one_statement, data_image_binding_));
+
+ return *insert_one_;
+ }
+
+ select_statement_type&
+ select_all_statement ()
+ {
+ if (select_all_ == 0)
+ select_all_.reset (
+ new (details::shared) select_statement_type (
+ conn_,
+ traits::select_all_statement,
+ cond_image_binding_,
+ data_image_binding_));
+
+ return *select_all_;
+ }
+
+ delete_statement_type&
+ delete_all_statement ()
+ {
+ if (delete_all_ == 0)
+ delete_all_.reset (
+ new (details::shared) delete_statement_type (
+ conn_, traits::delete_all_statement, cond_image_binding_));
+
+ return *delete_all_;
+ }
+
+ private:
+ container_statements (const container_statements&);
+ container_statements& operator= (const container_statements&);
+
+ private:
+ connection_type& conn_;
+ functions_type functions_;
+
+ id_image_type* id_image_;
+
+ cond_image_type cond_image_;
+ binding cond_image_binding_;
+ bind cond_image_bind_[traits::cond_column_count];
+
+ data_image_type data_image_;
+ binding data_image_binding_;
+ bind data_image_bind_[traits::data_column_count];
+ bool data_image_truncated_[traits::data_column_count];
+
+ details::shared_ptr<insert_statement_type> insert_one_;
+ details::shared_ptr<select_statement_type> select_all_;
+ details::shared_ptr<delete_statement_type> delete_all_;
+ };
+ }
+}
+
+#include <odb/sqlite/container-statements.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_SQLITE_CONTAINER_STATEMENTS_HXX
diff --git a/odb/sqlite/container-statements.txx b/odb/sqlite/container-statements.txx
new file mode 100644
index 0000000..23466df
--- /dev/null
+++ b/odb/sqlite/container-statements.txx
@@ -0,0 +1,36 @@
+// file : odb/sqlite/container-statements.txx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cstddef> // std::size_t
+#include <cstring> // std::memset
+
+namespace odb
+{
+ namespace sqlite
+ {
+ // container_statements
+ //
+
+ template <typename T>
+ container_statements<T>::
+ container_statements (connection_type& conn)
+ : conn_ (conn),
+ functions_ (this,
+ &traits::insert_one,
+ &traits::load_all,
+ &traits::delete_all),
+ id_image_ (0),
+ cond_image_binding_ (cond_image_bind_, traits::cond_column_count),
+ data_image_binding_ (data_image_bind_, traits::data_column_count)
+ {
+ std::memset (cond_image_bind_, 0, sizeof (cond_image_bind_));
+ std::memset (data_image_bind_, 0, sizeof (data_image_bind_));
+ std::memset (data_image_truncated_, 0, sizeof (data_image_truncated_));
+
+ for (std::size_t i (0); i < traits::data_column_count; ++i)
+ data_image_bind_[i].truncated = data_image_truncated_ + i;
+ }
+ }
+}
diff --git a/odb/sqlite/makefile b/odb/sqlite/makefile
index f46587f..3cc9d3c 100644
--- a/odb/sqlite/makefile
+++ b/odb/sqlite/makefile
@@ -11,6 +11,7 @@ connection-factory.cxx \
database.cxx \
error.cxx \
exceptions.cxx \
+object-statements.cxx \
statement-cache.cxx \
statement.cxx \
traits.cxx \
diff --git a/odb/sqlite/object-statements.cxx b/odb/sqlite/object-statements.cxx
new file mode 100644
index 0000000..fd3df50
--- /dev/null
+++ b/odb/sqlite/object-statements.cxx
@@ -0,0 +1,17 @@
+// file : odb/sqlite/object-statements.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/sqlite/object-statements.hxx>
+
+namespace odb
+{
+ namespace sqlite
+ {
+ object_statements_base::
+ ~object_statements_base ()
+ {
+ }
+ }
+}
diff --git a/odb/sqlite/object-statements.hxx b/odb/sqlite/object-statements.hxx
new file mode 100644
index 0000000..73f3162
--- /dev/null
+++ b/odb/sqlite/object-statements.hxx
@@ -0,0 +1,333 @@
+// file : odb/sqlite/object-statements.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SQLITE_OBJECT_STATEMENTS_HXX
+#define ODB_SQLITE_OBJECT_STATEMENTS_HXX
+
+#include <odb/pre.hxx>
+
+#include <vector>
+#include <cassert>
+
+#include <odb/forward.hxx>
+#include <odb/traits.hxx>
+#include <odb/cache-traits.hxx>
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/sqlite/version.hxx>
+#include <odb/sqlite/binding.hxx>
+#include <odb/sqlite/statement.hxx>
+#include <odb/sqlite/details/export.hxx>
+
+namespace odb
+{
+ namespace sqlite
+ {
+ class connection;
+
+ class LIBODB_SQLITE_EXPORT object_statements_base:
+ public details::shared_base
+ {
+ public:
+ typedef sqlite::connection connection_type;
+
+ connection_type&
+ connection ()
+ {
+ return conn_;
+ }
+
+ // Locking.
+ //
+ void
+ lock ()
+ {
+ assert (!locked_);
+ locked_ = true;
+ }
+
+ void
+ unlock ()
+ {
+ assert (locked_);
+ locked_ = false;
+ }
+
+ bool
+ locked () const
+ {
+ return locked_;
+ }
+
+ public:
+ virtual
+ ~object_statements_base ();
+
+ protected:
+ object_statements_base (connection_type& conn)
+ : conn_ (conn), locked_ (false)
+ {
+ }
+
+ protected:
+ connection_type& conn_;
+ bool locked_;
+ };
+
+ template <typename T>
+ class object_statements: public object_statements_base
+ {
+ public:
+ typedef T object_type;
+ typedef odb::object_traits<object_type> object_traits;
+ typedef typename object_traits::id_type id_type;
+ typedef typename object_traits::pointer_type pointer_type;
+ typedef typename object_traits::image_type image_type;
+ typedef typename object_traits::id_image_type id_image_type;
+
+ typedef pointer_cache_traits<pointer_type> object_cache_traits;
+
+ typedef
+ typename object_traits::container_statement_cache_type
+ container_statement_cache_type;
+
+ typedef sqlite::insert_statement persist_statement_type;
+ typedef sqlite::select_statement find_statement_type;
+ typedef sqlite::update_statement update_statement_type;
+ typedef sqlite::delete_statement erase_statement_type;
+
+ // Automatic lock.
+ //
+ struct auto_lock
+ {
+ // Lock the statements unless they are already locked in which
+ // case subsequent calls to locked() will return false.
+ //
+ auto_lock (object_statements&);
+
+ // Unlock the statemens if we are holding the lock and clear
+ // the delayed loads. This should only happen in case an
+ // exception is thrown. In normal circumstances, the user
+ // should call unlock() explicitly.
+ //
+ ~auto_lock ();
+
+ // Return true if this auto_lock instance holds the lock.
+ //
+ bool
+ locked () const;
+
+ // Unlock the statemens.
+ //
+ void
+ unlock ();
+
+ private:
+ auto_lock (const auto_lock&);
+ auto_lock& operator= (const auto_lock&);
+
+ private:
+ object_statements& s_;
+ bool locked_;
+ };
+
+ //
+ //
+ object_statements (connection_type&);
+
+ // Delayed loading.
+ //
+ void
+ delay_load (const id_type& id,
+ object_type& obj,
+ const typename object_cache_traits::position_type& p)
+ {
+ delayed_.push_back (delayed_load (id, obj, p));
+ }
+
+ void
+ load_delayed ()
+ {
+ assert (locked ());
+
+ if (!delayed_.empty ())
+ load_delayed_ ();
+ }
+
+ void
+ clear_delayed ()
+ {
+ if (!delayed_.empty ())
+ clear_delayed_ ();
+ }
+
+ // Object image.
+ //
+ image_type&
+ image ()
+ {
+ return image_;
+ }
+
+ binding&
+ in_image_binding ()
+ {
+ return in_image_binding_;
+ }
+
+ binding&
+ out_image_binding ()
+ {
+ return out_image_binding_;
+ }
+
+ bool*
+ out_image_truncated ()
+ {
+ return out_image_truncated_;
+ }
+
+ // Object id image.
+ //
+ id_image_type&
+ id_image ()
+ {
+ return id_image_;
+ }
+
+ binding&
+ id_image_binding ()
+ {
+ return id_image_binding_;
+ }
+
+ // Statements.
+ //
+ persist_statement_type&
+ persist_statement ()
+ {
+ if (persist_ == 0)
+ persist_.reset (
+ new (details::shared) persist_statement_type (
+ conn_, object_traits::persist_statement, in_image_binding_));
+
+ return *persist_;
+ }
+
+ find_statement_type&
+ find_statement ()
+ {
+ if (find_ == 0)
+ find_.reset (
+ new (details::shared) find_statement_type (
+ conn_,
+ object_traits::find_statement,
+ id_image_binding_,
+ out_image_binding_));
+
+ return *find_;
+ }
+
+ update_statement_type&
+ update_statement ()
+ {
+ if (update_ == 0)
+ update_.reset (
+ new (details::shared) update_statement_type (
+ conn_,
+ object_traits::update_statement,
+ id_image_binding_,
+ in_image_binding_));
+
+ return *update_;
+ }
+
+ erase_statement_type&
+ erase_statement ()
+ {
+ if (erase_ == 0)
+ erase_.reset (
+ new (details::shared) erase_statement_type (
+ conn_,
+ object_traits::erase_statement,
+ id_image_binding_));
+
+ return *erase_;
+ }
+
+ // Container statement cache.
+ //
+ container_statement_cache_type&
+ container_statment_cache ()
+ {
+ return container_statement_cache_;
+ }
+
+ private:
+ object_statements (const object_statements&);
+ object_statements& operator= (const object_statements&);
+
+ private:
+ void
+ load_delayed_ ();
+
+ void
+ clear_delayed_ ();
+
+ private:
+ container_statement_cache_type container_statement_cache_;
+
+ image_type image_;
+
+ // In (send) binding. The last element is the id parameter.
+ //
+ binding in_image_binding_;
+ bind in_image_bind_[object_traits::in_column_count + 1];
+
+ // Out (receive) binding.
+ //
+ binding out_image_binding_;
+ bind out_image_bind_[object_traits::out_column_count];
+ bool out_image_truncated_[object_traits::out_column_count];
+
+ // Id image binding (only in).
+ //
+ id_image_type id_image_;
+ binding id_image_binding_;
+
+ details::shared_ptr<persist_statement_type> persist_;
+ details::shared_ptr<find_statement_type> find_;
+ details::shared_ptr<update_statement_type> update_;
+ details::shared_ptr<erase_statement_type> erase_;
+
+ // Delayed loading.
+ //
+ struct delayed_load
+ {
+ typedef typename object_cache_traits::position_type position_type;
+
+ delayed_load () {}
+ delayed_load (const id_type& i, object_type& o, const position_type& p)
+ : id (i), obj (&o), pos (p)
+ {
+ }
+
+ id_type id;
+ object_type* obj;
+ position_type pos;
+ };
+
+ typedef std::vector<delayed_load> delayed_loads;
+ delayed_loads delayed_;
+ };
+ }
+}
+
+#include <odb/sqlite/object-statements.ixx>
+#include <odb/sqlite/object-statements.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_SQLITE_OBJECT_STATEMENTS_HXX
diff --git a/odb/sqlite/object-statements.ixx b/odb/sqlite/object-statements.ixx
new file mode 100644
index 0000000..e1ae3ef
--- /dev/null
+++ b/odb/sqlite/object-statements.ixx
@@ -0,0 +1,54 @@
+// file : odb/sqlite/object-statements.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace sqlite
+ {
+ //
+ // auto_lock
+ //
+ template <typename T>
+ inline object_statements<T>::auto_lock::
+ auto_lock (object_statements& s)
+ : s_ (s)
+ {
+ if (!s_.locked ())
+ {
+ s_.lock ();
+ locked_ = true;
+ }
+ else
+ locked_ = false;
+ }
+
+ template <typename T>
+ inline object_statements<T>::auto_lock::
+ ~auto_lock ()
+ {
+ if (locked_)
+ {
+ s_.unlock ();
+ s_.clear_delayed ();
+ }
+ }
+
+ template <typename T>
+ inline bool object_statements<T>::auto_lock::
+ locked () const
+ {
+ return locked_;
+ }
+
+ template <typename T>
+ inline void object_statements<T>::auto_lock::
+ unlock ()
+ {
+ assert (locked_);
+ s_.unlock ();
+ locked_ = false;
+ }
+ }
+}
diff --git a/odb/sqlite/object-statements.txx b/odb/sqlite/object-statements.txx
new file mode 100644
index 0000000..88b99e8
--- /dev/null
+++ b/odb/sqlite/object-statements.txx
@@ -0,0 +1,77 @@
+// file : odb/sqlite/object-statements.txx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cstddef> // std::size_t
+#include <cstring> // std::memset
+
+#include <odb/session.hxx>
+#include <odb/exceptions.hxx>
+
+#include <odb/sqlite/connection.hxx>
+
+namespace odb
+{
+ namespace sqlite
+ {
+ template <typename T>
+ object_statements<T>::
+ object_statements (connection_type& conn)
+ : object_statements_base (conn),
+ container_statement_cache_ (conn),
+ in_image_binding_ (in_image_bind_, object_traits::in_column_count),
+ out_image_binding_ (out_image_bind_, object_traits::out_column_count),
+ id_image_binding_ (in_image_bind_ + object_traits::in_column_count, 1)
+ {
+ std::memset (in_image_bind_, 0, sizeof (in_image_bind_));
+ std::memset (out_image_bind_, 0, sizeof (out_image_bind_));
+ std::memset (out_image_truncated_, 0, sizeof (out_image_truncated_));
+
+ for (std::size_t i (0); i < object_traits::out_column_count; ++i)
+ out_image_bind_[i].truncated = out_image_truncated_ + i;
+ }
+
+ template <typename T>
+ void object_statements<T>::
+ load_delayed_ ()
+ {
+ // We should be careful here: the delayed vector can change
+ // from under us as a result of a recursive load.
+ //
+ database& db (connection ().database ());
+
+ while (!delayed_.empty ())
+ {
+ delayed_load l (delayed_.back ());
+ typename object_cache_traits::insert_guard g (l.pos);
+ delayed_.pop_back ();
+
+ if (!object_traits::find_ (*this, l.id))
+ throw object_not_persistent ();
+
+ object_traits::init (*l.obj, image (), db);
+ object_traits::load_ (*this, *l.obj); // Load containers, etc.
+ g.release ();
+ }
+ }
+
+ template <typename T>
+ void object_statements<T>::
+ clear_delayed_ ()
+ {
+ // Remove the objects from the session cache.
+ //
+ if (session::has_current ())
+ {
+ for (typename delayed_loads::iterator i (delayed_.begin ()),
+ e (delayed_.end ()); i != e; ++i)
+ {
+ object_cache_traits::erase (i->pos);
+ }
+ }
+
+ delayed_.clear ();
+ }
+ }
+}
diff --git a/odb/sqlite/statement-cache.hxx b/odb/sqlite/statement-cache.hxx
index 9ef446d..1b3d4b2 100644
--- a/odb/sqlite/statement-cache.hxx
+++ b/odb/sqlite/statement-cache.hxx
@@ -17,10 +17,7 @@
#include <odb/sqlite/version.hxx>
#include <odb/sqlite/statement.hxx>
-/*
#include <odb/sqlite/object-statements.hxx>
-*/
-
#include <odb/sqlite/details/export.hxx>
namespace odb
@@ -52,8 +49,6 @@ namespace odb
return *rollback_;
}
-/*
- @@
template <typename T>
object_statements<T>&
find ()
@@ -69,14 +64,11 @@ namespace odb
map_.insert (map::value_type (&typeid (T), p));
return *p;
}
-*/
private:
- /*
typedef std::map<const std::type_info*,
details::shared_ptr<object_statements_base>,
details::type_info_comparator> map;
- */
connection& conn_;
@@ -84,9 +76,7 @@ namespace odb
details::shared_ptr<simple_statement> commit_;
details::shared_ptr<simple_statement> rollback_;
- /*
map map_;
- */
};
}
}