aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/cache-traits.hxx152
-rw-r--r--odb/database.hxx70
-rw-r--r--odb/database.ixx177
-rw-r--r--odb/database.txx115
-rw-r--r--odb/exceptions.cxx18
-rw-r--r--odb/exceptions.hxx24
-rw-r--r--odb/makefile1
-rw-r--r--odb/result.hxx43
-rw-r--r--odb/result.txx72
-rw-r--r--odb/session.cxx72
-rw-r--r--odb/session.hxx159
-rw-r--r--odb/session.ixx65
-rw-r--r--odb/session.txx116
-rw-r--r--odb/traits.hxx61
14 files changed, 1103 insertions, 42 deletions
diff --git a/odb/cache-traits.hxx b/odb/cache-traits.hxx
new file mode 100644
index 0000000..5d32624
--- /dev/null
+++ b/odb/cache-traits.hxx
@@ -0,0 +1,152 @@
+// file : odb/cache-traits.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_CACHE_TRAITS_HXX
+#define ODB_CACHE_TRAITS_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/traits.hxx>
+#include <odb/session.hxx>
+#include <odb/pointer-traits.hxx>
+
+namespace odb
+{
+ // Caching traits for objects passed by pointer.
+ //
+ template <typename P, pointer_kind = pointer_traits<P>::kind>
+ struct pointer_cache_traits
+ {
+ typedef P pointer_type;
+ typedef typename pointer_traits<pointer_type>::element_type element_type;
+ typedef typename object_traits<element_type>::id_type id_type;
+ typedef session::object_position<element_type> position_type;
+
+ struct insert_guard
+ {
+ insert_guard (const position_type& pos): pos_ (pos) {}
+
+ ~insert_guard ()
+ {
+ if (pos_.map_ != 0)
+ session::current ().erase<element_type> (pos_);
+ }
+
+ void
+ release () {pos_.map_ = 0;}
+
+ private:
+ position_type pos_;
+ };
+
+ static position_type
+ insert (database& db, const id_type& id, const pointer_type& p)
+ {
+ if (session::has_current ())
+ return session::current ().insert<element_type> (db, id, p);
+ else
+ return position_type ();
+ }
+
+ static pointer_type
+ find (database& db, const id_type& id)
+ {
+ if (session::has_current ())
+ return session::current ().find<element_type> (db, id);
+ else
+ return pointer_type ();
+ }
+
+ static void
+ erase (database& db, const id_type& id)
+ {
+ if (session::has_current ())
+ session::current ().erase<element_type> (db, id);
+ }
+ };
+
+ // Unique pointers don't work with the object cache.
+ //
+ template <typename P>
+ struct pointer_cache_traits<P, pk_unique>
+ {
+ typedef P pointer_type;
+ typedef typename pointer_traits<pointer_type>::element_type element_type;
+ typedef typename object_traits<element_type>::id_type id_type;
+ struct position_type {};
+
+ struct insert_guard
+ {
+ insert_guard (const position_type&) {}
+ void release () {}
+ };
+
+ static position_type
+ insert (database&, const id_type&, const pointer_type&)
+ {
+ return position_type ();
+ }
+
+ static pointer_type
+ find (database&, const id_type&) { return pointer_type (); }
+
+ static void
+ erase (database&, const id_type&) {}
+ };
+
+ // Caching traits for objects passed by reference. Only if the object
+ // pointer kind is naked do we add the object to the session.
+ //
+ template <typename T,
+ pointer_kind =
+ pointer_traits<typename object_traits<T>::pointer_type>::kind>
+ struct reference_cache_traits
+ {
+ typedef T element_type;
+ typedef typename object_traits<element_type>::pointer_type pointer_type;
+ typedef typename object_traits<element_type>::id_type id_type;
+
+ struct position_type {};
+
+ struct insert_guard
+ {
+ insert_guard (const position_type&) {}
+ void release () {}
+ };
+
+ static position_type
+ insert (database&, const id_type&, element_type&)
+ {
+ return position_type ();
+ }
+ };
+
+ template <typename T>
+ struct reference_cache_traits<T, pk_naked>
+ {
+ typedef T element_type;
+ typedef typename object_traits<element_type>::pointer_type pointer_type;
+ typedef typename object_traits<element_type>::id_type id_type;
+
+ typedef
+ typename pointer_cache_traits<pointer_type>::position_type
+ position_type;
+
+ typedef
+ typename pointer_cache_traits<pointer_type>::insert_guard
+ insert_guard;
+
+ static position_type
+ insert (database& db, const id_type& id, element_type& obj)
+ {
+ pointer_type p (&obj);
+ return pointer_cache_traits<pointer_type>::insert (db, id, p);
+ }
+ };
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_CACHE_TRAITS_HXX
diff --git a/odb/database.hxx b/odb/database.hxx
index 7db04c8..e7ea91a 100644
--- a/odb/database.hxx
+++ b/odb/database.hxx
@@ -36,11 +36,23 @@ namespace odb
//
template <typename T>
typename object_traits<T>::id_type
- persist (const T& object);
+ persist (T& object);
template <typename T>
typename object_traits<T>::id_type
- persist (T& object);
+ persist (T* obj_ptr);
+
+ template <typename T, template <typename> class P>
+ typename object_traits<T>::id_type
+ persist (const P<T>& obj_ptr);
+
+ template <typename T, template <typename> class P>
+ typename object_traits<T>::id_type
+ persist (P<T>& obj_ptr);
+
+ template <typename T>
+ typename object_traits<T>::id_type
+ persist (const typename object_traits<T>::pointer_type& obj_ptr);
// Throw object_not_persistent if not found.
//
@@ -66,18 +78,50 @@ namespace odb
//
template <typename T>
void
- update (const T& object);
+ update (T& object);
+
+ template <typename T>
+ void
+ update (T* obj_ptr);
+
+ template <typename T, template <typename> class P>
+ void
+ update (const P<T>& obj_ptr);
+
+ template <typename T, template <typename> class P>
+ void
+ update (P<T>& obj_ptr);
+
+ template <typename T>
+ void
+ update (const typename object_traits<T>::pointer_type& obj_ptr);
// Make the object transient. Throw object_not_persistent if not
// found.
//
template <typename T>
void
- erase (const T& object);
+ erase (const typename object_traits<T>::id_type& id);
template <typename T>
void
- erase (const typename object_traits<T>::id_type& id);
+ erase (T& object);
+
+ template <typename T>
+ void
+ erase (T* obj_ptr);
+
+ template <typename T, template <typename> class P>
+ void
+ erase (const P<T>& obj_ptr);
+
+ template <typename T, template <typename> class P>
+ void
+ erase (P<T>& obj_ptr);
+
+ template <typename T>
+ void
+ erase (const typename object_traits<T>::pointer_type& obj_ptr);
// Query API.
//
@@ -95,7 +139,8 @@ namespace odb
template <typename T>
result<T>
- query (const odb::query<T>&, bool cache = true);
+ query (const odb::query<typename object_traits<T>::object_type>&,
+ bool cache = true);
// Transaction API.
//
@@ -106,6 +151,19 @@ namespace odb
protected:
database ();
+ protected:
+ template <typename T>
+ typename object_traits<T>::id_type
+ persist_ (const typename object_traits<T>::pointer_type&);
+
+ template <typename T>
+ void
+ update_ (const typename object_traits<T>::pointer_type&);
+
+ template <typename T>
+ void
+ erase_ (const typename object_traits<T>::pointer_type&);
+
private:
database (const database&);
database& operator= (const database&);
diff --git a/odb/database.ixx b/odb/database.ixx
index 8085210..86ccd15 100644
--- a/odb/database.ixx
+++ b/odb/database.ixx
@@ -11,30 +11,197 @@ namespace odb
}
template <typename T>
+ inline typename object_traits<T>::id_type database::
+ persist (T* p)
+ {
+ typedef typename object_traits<T>::pointer_type object_pointer;
+
+ // The passed pointer should be the same or implicit-convertible
+ // to the object pointer. This way we make sure the object pointer
+ // does not assume ownership of the passed object.
+ //
+ const object_pointer& pobj (p);
+
+ return persist_<T> (pobj);
+ }
+
+ template <typename T, template <typename> class P>
+ inline typename object_traits<T>::id_type database::
+ persist (const P<T>& p)
+ {
+ typedef typename object_traits<T>::pointer_type object_pointer;
+
+ // The passed pointer should be the same or implicit-convertible
+ // to the object pointer. This way we make sure the object pointer
+ // does not assume ownership of the passed object.
+ //
+ const object_pointer& pobj (p);
+
+ return persist_<T> (pobj);
+ }
+
+ template <typename T, template <typename> class P>
+ inline typename object_traits<T>::id_type database::
+ persist (P<T>& p)
+ {
+ const P<T>& cr (p);
+ return persist<T, P> (cr);
+ }
+
+ template <typename T>
+ inline typename object_traits<T>::id_type database::
+ persist (const typename object_traits<T>::pointer_type& pobj)
+ {
+ return persist_<T> (pobj);
+ }
+
+ template <typename T>
inline void database::
- erase (const T& obj)
+ update (T* p)
{
- erase<T> (object_traits<T>::id (obj));
+ typedef typename object_traits<T>::pointer_type object_pointer;
+
+ // The passed pointer should be the same or implicit-convertible
+ // to the object pointer. This way we make sure the object pointer
+ // does not assume ownership of the passed object.
+ //
+ const object_pointer& pobj (p);
+
+ update_<T> (pobj);
+ }
+
+ template <typename T, template <typename> class P>
+ inline void database::
+ update (const P<T>& p)
+ {
+ typedef typename object_traits<T>::pointer_type object_pointer;
+
+ // The passed pointer should be the same or implicit-convertible
+ // to the object pointer. This way we make sure the object pointer
+ // does not assume ownership of the passed object.
+ //
+ const object_pointer& pobj (p);
+
+ update_<T> (pobj);
+ }
+
+ template <typename T, template <typename> class P>
+ inline void database::
+ update (P<T>& p)
+ {
+ const P<T>& cr (p);
+ update<T, P> (cr);
+ }
+
+ template <typename T>
+ inline void database::
+ update (const typename object_traits<T>::pointer_type& pobj)
+ {
+ update_<T> (pobj);
+ }
+
+ template <typename T>
+ inline void database::
+ erase (T& obj)
+ {
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ erase<T> (object_traits::id (obj));
+ }
+
+ template <typename T>
+ inline void database::
+ erase (T* p)
+ {
+ typedef typename object_traits<T>::pointer_type object_pointer;
+
+ // The passed pointer should be the same or implicit-convertible
+ // to the object pointer. This way we make sure the object pointer
+ // does not assume ownership of the passed object.
+ //
+ const object_pointer& pobj (p);
+
+ erase_<T> (pobj);
+ }
+
+ template <typename T, template <typename> class P>
+ inline void database::
+ erase (const P<T>& p)
+ {
+ typedef typename object_traits<T>::pointer_type object_pointer;
+
+ // The passed pointer should be the same or implicit-convertible
+ // to the object pointer. This way we make sure the object pointer
+ // does not assume ownership of the passed object.
+ //
+ const object_pointer& pobj (p);
+
+ erase_<T> (pobj);
+ }
+
+ template <typename T, template <typename> class P>
+ inline void database::
+ erase (P<T>& p)
+ {
+ const P<T>& cr (p);
+ erase<T, P> (cr);
+ }
+
+ template <typename T>
+ inline void database::
+ erase (const typename object_traits<T>::pointer_type& pobj)
+ {
+ erase_<T> (pobj);
+ }
+
+ template <typename T>
+ inline void database::
+ erase_ (const typename object_traits<T>::pointer_type& pobj)
+ {
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ typedef typename odb::object_traits<T>::pointer_type pointer_type;
+ typedef odb::pointer_traits<pointer_type> pointer_traits;
+
+ erase<T> (object_traits::id (pointer_traits::get_ref (pobj)));
}
template <typename T>
inline result<T> database::
query (bool cache)
{
- return query (odb::query<T> (), cache);
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+
+ return query<T> (odb::query<object_type> (), cache);
}
template <typename T>
inline result<T> database::
query (const char* q, bool cache)
{
- return query (odb::query<T> (q), cache);
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+
+ return query<T> (odb::query<object_type> (q), cache);
}
template <typename T>
inline result<T> database::
query (const std::string& q, bool cache)
{
- return query (odb::query<T> (q), cache);
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+
+ return query<T> (odb::query<object_type> (q), cache);
}
}
diff --git a/odb/database.txx b/odb/database.txx
index 31e9153..d98028d 100644
--- a/odb/database.txx
+++ b/odb/database.txx
@@ -5,43 +5,62 @@
#include <odb/exceptions.hxx>
#include <odb/transaction.hxx>
+#include <odb/session.hxx>
+#include <odb/cache-traits.hxx>
+#include <odb/pointer-traits.hxx>
namespace odb
{
template <typename T>
typename object_traits<T>::id_type database::
- persist (const T& obj)
+ persist (T& obj)
{
- typedef object_traits<T> traits;
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
if (!transaction::has_current ())
throw not_in_transaction ();
- traits::persist (*this, obj);
- return traits::id (obj);
+ object_traits::persist (*this, obj);
+ const typename object_traits::id_type& id (object_traits::id (obj));
+ reference_cache_traits<T>::insert (*this, id, obj);
+ return id;
}
template <typename T>
typename object_traits<T>::id_type database::
- persist (T& obj)
+ persist_ (const typename object_traits<T>::pointer_type& pobj)
{
- typedef object_traits<T> traits;
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ typedef typename odb::object_traits<T>::pointer_type pointer_type;
+ typedef odb::pointer_traits<pointer_type> pointer_traits;
if (!transaction::has_current ())
throw not_in_transaction ();
- traits::persist (*this, obj);
- return traits::id (obj);
+ T& obj (pointer_traits::get_ref (pobj));
+ object_traits::persist (*this, obj);
+ const typename object_traits::id_type& id (object_traits::id (obj));
+ pointer_cache_traits<pointer_type>::insert (*this, id, pobj);
+ return id;
}
template <typename T>
typename object_traits<T>::pointer_type database::
load (const typename object_traits<T>::id_type& id)
{
- typedef object_traits<T> traits;
- typename traits::pointer_type r (find<T> (id));
+ typedef typename object_traits<T>::pointer_type pointer_type;
+ typedef odb::pointer_traits<pointer_type> pointer_traits;
+
+ pointer_type r (find<T> (id));
- if (traits::pointer_traits::null_ptr (r))
+ if (pointer_traits::null_ptr (r))
throw object_not_persistent ();
return r;
@@ -59,53 +78,113 @@ namespace odb
typename object_traits<T>::pointer_type database::
find (const typename object_traits<T>::id_type& id)
{
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ typedef typename odb::object_traits<T>::pointer_type pointer_type;
+ typedef odb::pointer_traits<pointer_type> pointer_traits;
+
+ // First check the session.
+ //
+ {
+ pointer_type p (
+ pointer_cache_traits<pointer_type>::find (*this, id));
+
+ if (!pointer_traits::null_ptr (p))
+ return p;
+ }
+
if (!transaction::has_current ())
throw not_in_transaction ();
// Compiler error pointing here? Perhaps the object doesn't have the
// default constructor?
//
- return object_traits<T>::find (*this, id);
+ return pointer_type (object_traits::find (*this, id));
}
template <typename T>
bool database::
find (const typename object_traits<T>::id_type& id, T& obj)
{
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ if (!transaction::has_current ())
+ throw not_in_transaction ();
+
+ return object_traits::find (*this, id, obj);
+ }
+
+ template <typename T>
+ void database::
+ update (T& obj)
+ {
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
if (!transaction::has_current ())
throw not_in_transaction ();
- return object_traits<T>::find (*this, id, obj);
+ object_traits::update (*this, obj);
}
template <typename T>
void database::
- update (const T& obj)
+ update_ (const typename object_traits<T>::pointer_type& pobj)
{
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ typedef typename odb::object_traits<T>::pointer_type pointer_type;
+ typedef odb::pointer_traits<pointer_type> pointer_traits;
+
if (!transaction::has_current ())
throw not_in_transaction ();
- object_traits<T>::update (*this, obj);
+ object_traits::update (*this, pointer_traits::get_ref (pobj));
}
template <typename T>
void database::
erase (const typename object_traits<T>::id_type& id)
{
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ typedef typename odb::object_traits<T>::pointer_type pointer_type;
+
if (!transaction::has_current ())
throw not_in_transaction ();
- object_traits<T>::erase (*this, id);
+ object_traits::erase (*this, id);
+ pointer_cache_traits<pointer_type>::erase (*this, id);
}
template <typename T>
result<T> database::
- query (const odb::query<T>& q, bool cache)
+ query (const odb::query<typename object_traits<T>::object_type>& q,
+ bool cache)
{
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
if (!transaction::has_current ())
throw not_in_transaction ();
- result<T> r (object_traits<T>::query (*this, q));
+ result<T> r (object_traits::template query<T> (*this, q));
if (cache)
r.cache ();
diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx
index c480125..a41f719 100644
--- a/odb/exceptions.cxx
+++ b/odb/exceptions.cxx
@@ -25,6 +25,24 @@ namespace odb
return "transaction already committed or rolled back";
}
+ const char* already_in_session::
+ what () const throw ()
+ {
+ return "session already in effect in this thread";
+ }
+
+ const char* not_in_session::
+ what () const throw ()
+ {
+ return "session not in effect in this thread";
+ }
+
+ const char* const_object::
+ what () const throw ()
+ {
+ return "object cached in session is const";
+ }
+
const char* deadlock::
what () const throw ()
{
diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx
index 91fa5ab..26550cb 100644
--- a/odb/exceptions.hxx
+++ b/odb/exceptions.hxx
@@ -14,6 +14,8 @@
namespace odb
{
+ // Transaction exceptions.
+ //
struct LIBODB_EXPORT already_in_transaction: odb::exception
{
virtual const char*
@@ -32,6 +34,28 @@ namespace odb
what () const throw ();
};
+ // Session exceptions.
+ //
+ struct LIBODB_EXPORT already_in_session: odb::exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct LIBODB_EXPORT not_in_session: odb::exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct LIBODB_EXPORT const_object: odb::exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ // Database operations exceptions.
+ //
struct LIBODB_EXPORT deadlock: odb::exception
{
virtual const char*
diff --git a/odb/makefile b/odb/makefile
index 6e8790f..2569de5 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -8,6 +8,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
cxx := \
exceptions.cxx \
database.cxx \
+session.cxx \
transaction.cxx
# Implementation details.
diff --git a/odb/result.hxx b/odb/result.hxx
index 42acb0e..e87374e 100644
--- a/odb/result.hxx
+++ b/odb/result.hxx
@@ -30,15 +30,30 @@ namespace odb
public:
virtual
~result_impl ();
- result_impl () : end_ (false), current_ () {}
protected:
friend class result<T>;
friend class result_iterator<T>;
- typedef object_traits<T> traits;
- typedef typename traits::pointer_type pointer_type;
- typedef typename traits::pointer_traits pointer_traits;
+ typedef odb::database database_type;
+
+ typedef typename odb::object_traits<T>::pointer_type pointer_type;
+ typedef odb::pointer_traits<pointer_type> pointer_traits;
+
+ typedef typename odb::object_traits<T>::object_type object_type;
+ typedef typename odb::object_traits<T>::id_type id_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ result_impl (database_type& db)
+ : end_ (false), db_ (db), current_ ()
+ {
+ }
+
+ database_type&
+ database () const
+ {
+ return db_;
+ }
// To make this work with all kinds of pointers (naked, std::auto_ptr,
// shared), we need to make sure we don't make any copies of the
@@ -62,7 +77,10 @@ namespace odb
protected:
virtual void
- current (T&) = 0;
+ current (object_type&) = 0;
+
+ virtual id_type
+ current_id () = 0;
virtual void
next () = 0;
@@ -84,6 +102,7 @@ namespace odb
bool end_;
private:
+ database_type& db_;
pointer_type current_;
typename pointer_traits::guard_type guard_;
};
@@ -98,6 +117,11 @@ namespace odb
typedef std::ptrdiff_t difference_type;
typedef std::input_iterator_tag iterator_category;
+ // T might be const T, but object_type is always T.
+ //
+ typedef typename object_traits<T>::object_type object_type;
+ typedef typename object_traits<T>::id_type id_type;
+
public:
explicit
result_iterator (result_impl<T>* res = 0)
@@ -150,10 +174,7 @@ namespace odb
}
void
- load (T& x)
- {
- res_->current (x);
- }
+ load (object_type&);
public:
bool
@@ -163,7 +184,9 @@ namespace odb
}
private:
- typedef typename object_traits<T>::pointer_traits pointer_traits;
+ typedef
+ odb::pointer_traits<typename object_traits<T>::pointer_type>
+ pointer_traits;
result_impl<T>* res_;
};
diff --git a/odb/result.txx b/odb/result.txx
index 3068890..603ee54 100644
--- a/odb/result.txx
+++ b/odb/result.txx
@@ -3,6 +3,9 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <odb/session.hxx>
+#include <odb/cache-traits.hxx>
+
namespace odb
{
template <typename T>
@@ -15,12 +18,77 @@ namespace odb
typename result_impl<T>::pointer_type& result_impl<T>::
current ()
{
+ typedef typename object_traits::pointer_type unrestricted_pointer_type;
+ typedef typename object_traits::pointer_traits unrestricted_pointer_traits;
+
if (pointer_traits::null_ptr (current_) && !end_)
{
- current (traits::create ());
- current (pointer_traits::get_ref (current_));
+ if (!session::has_current ())
+ {
+ // Non-const pointer.
+ //
+ unrestricted_pointer_type p (object_traits::create ());
+ object_type& r (unrestricted_pointer_traits::get_ref (p));
+
+ current (pointer_type (p));
+ current (r);
+ }
+ else
+ {
+ const id_type& id (current_id ());
+
+ // First check the session.
+ //
+ pointer_type p (
+ pointer_cache_traits<pointer_type>::find (database (), id));
+
+ if (!pointer_traits::null_ptr (p))
+ current (p);
+ else
+ {
+ unrestricted_pointer_type up (object_traits::create ());
+
+ typename
+ pointer_cache_traits<unrestricted_pointer_type>::insert_guard ig (
+ pointer_cache_traits<unrestricted_pointer_type>::insert (
+ database (), id, up));
+
+ object_type& r (unrestricted_pointer_traits::get_ref (up));
+
+ current (pointer_type (up));
+ current (r);
+
+ ig.release ();
+ }
+ }
}
return current_;
}
+
+ //
+ // result_iterator
+ //
+
+ template <typename T>
+ void result_iterator<T>::
+ load (object_type& x)
+ {
+ if (res_->end ())
+ return;
+
+ if (!session::has_current ())
+ res_->current (x);
+ else
+ {
+ const id_type& id (res_->current_id ());
+
+ typename reference_cache_traits<object_type>::insert_guard ig (
+ reference_cache_traits<object_type>::insert (
+ res_->database (), id, x));
+
+ res_->current (x);
+ ig.release ();
+ }
+ }
}
diff --git a/odb/session.cxx b/odb/session.cxx
new file mode 100644
index 0000000..b34c1d7
--- /dev/null
+++ b/odb/session.cxx
@@ -0,0 +1,72 @@
+// file : odb/session.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/exceptions.hxx>
+#include <odb/session.hxx>
+
+#include <odb/details/tls.hxx>
+
+namespace odb
+{
+ using namespace details;
+
+ static ODB_TLS_POINTER (session) current_session;
+
+ session::
+ session ()
+ {
+ if (has_current ())
+ throw already_in_session ();
+
+ current (*this);
+ }
+
+ session::
+ ~session ()
+ {
+ // If we are the current thread's session, reset it.
+ //
+ if (has_current () && &current () == this)
+ reset_current ();
+ }
+
+ bool session::
+ has_current ()
+ {
+ return tls_get (current_session) != 0;
+ }
+
+ session& session::
+ current ()
+ {
+ session* cur (tls_get (current_session));
+
+ if (cur == 0)
+ throw not_in_session ();
+
+ return *cur;
+ }
+
+ void session::
+ current (session& s)
+ {
+ tls_set (current_session, &s);
+ }
+
+ void session::
+ reset_current ()
+ {
+ session* s (0);
+ tls_set (current_session, s);
+ }
+
+ //
+ // object_map_base
+ //
+ session::object_map_base::
+ ~object_map_base ()
+ {
+ }
+}
diff --git a/odb/session.hxx b/odb/session.hxx
new file mode 100644
index 0000000..033934a
--- /dev/null
+++ b/odb/session.hxx
@@ -0,0 +1,159 @@
+// file : odb/session.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SESSION_HXX
+#define ODB_SESSION_HXX
+
+#include <odb/pre.hxx>
+
+#include <map>
+#include <typeinfo>
+
+#include <odb/traits.hxx>
+#include <odb/forward.hxx>
+
+#include <odb/details/shared-ptr.hxx>
+#include <odb/details/type-info.hxx>
+
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ class LIBODB_EXPORT session
+ {
+ public:
+ typedef odb::database database_type;
+
+ // Set the current thread's session to this session. If another
+ // session is already in effect, throw the already_in_session
+ // exception.
+ //
+ session ();
+
+ // Reset the current thread's session if it is this session.
+ //
+ ~session ();
+
+ // Current session.
+ //
+ public:
+ // Return true if there is a session in effect in the current
+ // thread.
+ //
+ static bool
+ has_current ();
+
+ // Get current thread's session. Throw if no session is in effect.
+ //
+ static session&
+ current ();
+
+ // Set current thread's session.
+ //
+ static void
+ current (session&);
+
+ // Revert to the no session in effect state for the current thread.
+ //
+ static void
+ reset_current ();
+
+ // Copying or assignment of sessions is not supported.
+ //
+ private:
+ session (const session&);
+ session& operator= (const session&);
+
+ protected:
+ template <typename T>
+ struct object_pointers
+ {
+ typedef typename object_traits<T>::pointer_type pointer_type;
+ typedef typename object_traits<T>::const_pointer_type const_pointer_type;
+
+ object_pointers ();
+
+ void
+ set (const pointer_type&);
+
+ void
+ set (const const_pointer_type&);
+
+ void
+ get (pointer_type& p) const;
+
+ void
+ get (const_pointer_type& cp) const;
+
+ private:
+ pointer_type p_;
+ const_pointer_type cp_;
+ };
+
+ struct LIBODB_EXPORT object_map_base: details::shared_base
+ {
+ virtual
+ ~object_map_base ();
+ };
+
+ template <typename T>
+ struct object_map:
+ object_map_base,
+ std::map< typename object_traits<T>::id_type, object_pointers<T> >
+ {
+ };
+
+ // Object cache.
+ //
+ public:
+ template <typename T>
+ struct object_position
+ {
+ typedef typename object_traits<T>::object_type object_type;
+ typedef object_map<object_type> map;
+ typedef typename map::iterator iterator;
+
+ object_position (): map_ (0) {}
+ object_position (map& m, const iterator& p): map_ (&m), pos_ (p) {}
+
+ map* map_;
+ iterator pos_;
+ };
+
+ template <typename T>
+ object_position<T>
+ insert (database_type&,
+ const typename object_traits<T>::id_type&,
+ const typename object_traits<T>::pointer_type&);
+
+ template <typename T>
+ typename object_traits<T>::pointer_type
+ find (database_type&, const typename object_traits<T>::id_type&) const;
+
+ template <typename T>
+ void
+ erase (database_type&, const typename object_traits<T>::id_type&);
+
+ template <typename T>
+ void
+ erase (const object_position<T>&);
+
+ protected:
+ typedef std::map<const std::type_info*,
+ details::shared_ptr<object_map_base>,
+ details::type_info_comparator> type_map;
+
+ typedef std::map<database_type*, type_map> database_map;
+
+ database_map db_map_;
+ };
+}
+
+#include <odb/session.ixx>
+#include <odb/session.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_SESSION_HXX
diff --git a/odb/session.ixx b/odb/session.ixx
new file mode 100644
index 0000000..0be6bfa
--- /dev/null
+++ b/odb/session.ixx
@@ -0,0 +1,65 @@
+// file : odb/session.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/exceptions.hxx>
+
+namespace odb
+{
+ template <typename T>
+ inline void session::
+ erase (const object_position<T>& p)
+ {
+ // @@ Empty maps are not cleaned up by this version of erase.
+ //
+ p.map_->erase (p.pos_);
+ }
+
+ //
+ // object_pointers
+ //
+ template <typename T>
+ inline session::object_pointers<T>::
+ object_pointers () : p_ (), cp_ () {}
+
+ template <typename T>
+ inline void session::object_pointers<T>::
+ set (const pointer_type& p)
+ {
+ p_ = p;
+ cp_ = const_pointer_type ();
+ }
+
+ template <typename T>
+ inline void session::object_pointers<T>::
+ set (const const_pointer_type& cp)
+ {
+ p_ = pointer_type ();
+ cp_ = cp;
+ }
+
+ template <typename T>
+ inline void session::object_pointers<T>::
+ get (pointer_type& p) const
+ {
+ if (!pointer_traits<pointer_type>::null_ptr (p_))
+ p = p_;
+ else if (!pointer_traits<const_pointer_type>::null_ptr (cp_))
+ throw const_object ();
+ else
+ p = pointer_type ();
+ }
+
+ template <typename T>
+ inline void session::object_pointers<T>::
+ get (const_pointer_type& cp) const
+ {
+ if (!pointer_traits<pointer_type>::null_ptr (p_))
+ cp = const_pointer_type (p_);
+ else if (!pointer_traits<const_pointer_type>::null_ptr (cp_))
+ cp = cp_;
+ else
+ cp = const_pointer_type ();
+ }
+}
diff --git a/odb/session.txx b/odb/session.txx
new file mode 100644
index 0000000..1e3ba96
--- /dev/null
+++ b/odb/session.txx
@@ -0,0 +1,116 @@
+// file : odb/session.txx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/pointer-traits.hxx>
+
+namespace odb
+{
+ template <typename T>
+ typename session::object_position<T> session::
+ insert (database_type& db,
+ const typename object_traits<T>::id_type& id,
+ const typename object_traits<T>::pointer_type& obj)
+ {
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename object_traits<T>::object_type object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ typedef typename odb::object_traits<T>::pointer_type pointer_type;
+ typedef odb::pointer_traits<pointer_type> pointer_traits;
+
+ type_map& tm (db_map_[&db]);
+ details::shared_ptr<object_map_base>& pom (tm[&typeid (object_type)]);
+
+ if (!pom)
+ pom.reset (new (details::shared) object_map<object_type>);
+
+ object_map<object_type>& om (
+ static_cast<object_map<object_type>&> (*pom));
+
+ typename object_map<object_type>::value_type vt (
+ id, object_pointers<object_type> ());
+ vt.second.set (obj);
+ std::pair<typename object_map<object_type>::iterator, bool> r (
+ om.insert (vt));
+
+ // In what situation may we possibly attempt to reinsert the object?
+ // For example, when the user loads the same object in to different
+ // instances (i.e., load into a pre-allocated object). In this case
+ // we should probably update our entries accordingly.
+ //
+ if (!r.second)
+ r.first->second.set (obj);
+
+ return object_position<T> (om, r.first);
+ }
+
+ template <typename T>
+ typename object_traits<T>::pointer_type session::
+ find (database_type& db, const typename object_traits<T>::id_type& id) const
+ {
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename object_traits<T>::object_type object_type;
+ typedef typename object_traits<T>::pointer_type pointer_type;
+
+ database_map::const_iterator di (db_map_.find (&db));
+
+ if (di == db_map_.end ())
+ return pointer_type ();
+
+ const type_map& tm (di->second);
+ type_map::const_iterator ti (tm.find (&typeid (object_type)));
+
+ if (ti == tm.end ())
+ return pointer_type ();
+
+ const object_map<object_type>& om (
+ static_cast<const object_map<object_type>&> (*ti->second));
+ typename object_map<object_type>::const_iterator oi (om.find (id));
+
+ if (oi == om.end ())
+ return pointer_type ();
+
+ pointer_type r;
+ oi->second.get (r);
+ return r;
+ }
+
+ template <typename T>
+ void session::
+ erase (database_type& db, const typename object_traits<T>::id_type& id)
+ {
+ // T can be const T while object_type will always be T.
+ //
+ typedef typename object_traits<T>::object_type object_type;
+
+ database_map::iterator di (db_map_.find (&db));
+
+ if (di == db_map_.end ())
+ return;
+
+ type_map& tm (di->second);
+ type_map::iterator ti (tm.find (&typeid (object_type)));
+
+ if (ti == tm.end ())
+ return;
+
+ object_map<object_type>& om (
+ static_cast<object_map<object_type>&> (*ti->second));
+ typename object_map<object_type>::iterator oi (om.find (id));
+
+ if (oi == om.end ())
+ return;
+
+ om.erase (oi);
+
+ if (om.empty ())
+ tm.erase (ti);
+
+ if (tm.empty ())
+ db_map_.erase (di);
+ }
+}
diff --git a/odb/traits.hxx b/odb/traits.hxx
index bc25dcb..87fcec5 100644
--- a/odb/traits.hxx
+++ b/odb/traits.hxx
@@ -72,15 +72,74 @@ namespace odb
};
template <typename T>
- struct object_traits: access::object_traits<T>,
+ struct object_traits:
+ access::object_traits<T>,
access::object_factory<T, typename access::object_traits<T>::pointer_type>
{
+ //
+ // If a C++ compiler issues an error pointing to this struct and
+ // saying that it is incomplete, then you are most likely trying to
+ // perform a database operation on a C++ type that is not a persistent
+ // object. Or you forgot to include the corresponding -odb.hxx file.
+ //
+
+ typedef
+ odb::pointer_traits<typename access::object_traits<T>::pointer_type>
+ pointer_traits;
+
typedef typename access::object_traits<T>::object_type object_type;
typedef typename access::object_traits<T>::pointer_type pointer_type;
+ typedef typename pointer_traits::const_pointer_type const_pointer_type;
+ };
+ // Specialization for const objects. It only defines the id, object,
+ // pointer, and const_pointer types with pointer and const_pointer
+ // being the same. The idea is to only use this specialization in the
+ // interfaces, with the implementations detecting this situation and
+ // using the non-const object_traits version.
+ //
+ template <typename T>
+ struct object_traits<const T>
+ {
+ private:
typedef
odb::pointer_traits<typename access::object_traits<T>::pointer_type>
pointer_traits;
+
+ public:
+ typedef typename access::object_traits<T>::id_type id_type;
+ typedef typename access::object_traits<T>::object_type object_type;
+ typedef typename pointer_traits::const_pointer_type const_pointer_type;
+ typedef const_pointer_type pointer_type;
+ };
+
+ // Specializations for pointer types to allow the C++ compiler to
+ // instantiate persist(), etc., signatures in class database. The
+ // overloads that use these specializations would never actually
+ // be selected by the compiler.
+ //
+ template <typename T>
+ struct object_traits<T*>
+ {
+ struct id_type {};
+ };
+
+ template <typename T>
+ struct object_traits<T* const>
+ {
+ struct id_type {};
+ };
+
+ template <typename T, template <typename> class P>
+ struct object_traits< P<T> >
+ {
+ struct id_type {};
+ };
+
+ template <typename T, template <typename> class P>
+ struct object_traits< const P<T> >
+ {
+ struct id_type {};
};
template <typename T>