aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-11-26 13:24:00 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-11-26 13:24:00 +0200
commitba8430c002627705d559b5dd9d78ae7611476520 (patch)
treed629a51b81ed279a40172869a9130ce3ddbbe09c
parentfba7f7853b4a9485fa2ee29189e4445252ccac97 (diff)
Add support for recursive object loading
If an object of a type needs to be loaded recursively, then it is addded to the delayed loading list which is processed once the statements are unlocked.
-rw-r--r--odb/mysql/object-statements.hxx128
-rw-r--r--odb/mysql/object-statements.ixx54
-rw-r--r--odb/mysql/object-statements.txx49
-rw-r--r--odb/mysql/result.hxx4
-rw-r--r--odb/mysql/result.txx16
5 files changed, 241 insertions, 10 deletions
diff --git a/odb/mysql/object-statements.hxx b/odb/mysql/object-statements.hxx
index 4c81a76..ae49e08 100644
--- a/odb/mysql/object-statements.hxx
+++ b/odb/mysql/object-statements.hxx
@@ -8,8 +8,12 @@
#include <odb/pre.hxx>
+#include <vector>
+#include <cassert>
+
#include <odb/forward.hxx>
#include <odb/traits.hxx>
+#include <odb/cache-traits.hxx>
#include <odb/mysql/mysql.hxx>
#include <odb/mysql/version.hxx>
@@ -37,27 +41,56 @@ namespace odb
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)
+ : conn_ (conn), locked_ (false)
{
}
protected:
connection_type& conn_;
+ bool locked_;
};
template <typename T>
class object_statements: public object_statements_base
{
public:
- typedef odb::object_traits<T> object_traits;
+ 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;
@@ -67,8 +100,71 @@ namespace odb
typedef mysql::update_statement update_statement_type;
typedef mysql::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&
@@ -210,6 +306,13 @@ namespace odb
object_statements& operator= (const object_statements&);
private:
+ void
+ load_delayed_ ();
+
+ void
+ clear_delayed_ ();
+
+ private:
container_statement_cache_type container_statement_cache_;
image_type image_;
@@ -238,10 +341,31 @@ namespace odb
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/mysql/object-statements.ixx>
#include <odb/mysql/object-statements.txx>
#include <odb/post.hxx>
diff --git a/odb/mysql/object-statements.ixx b/odb/mysql/object-statements.ixx
new file mode 100644
index 0000000..891499b
--- /dev/null
+++ b/odb/mysql/object-statements.ixx
@@ -0,0 +1,54 @@
+// file : odb/mysql/object-statements.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace mysql
+ {
+ //
+ // 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/mysql/object-statements.txx b/odb/mysql/object-statements.txx
index 32d67f1..750fec2 100644
--- a/odb/mysql/object-statements.txx
+++ b/odb/mysql/object-statements.txx
@@ -6,13 +6,15 @@
#include <cstddef> // std::size_t
#include <cstring> // std::memset
+#include <odb/session.hxx>
+#include <odb/exceptions.hxx>
+
+#include <odb/mysql/connection.hxx>
+
namespace odb
{
namespace mysql
{
- // object_statements
- //
-
template <typename T>
object_statements<T>::
object_statements (connection_type& conn)
@@ -36,5 +38,46 @@ namespace odb
for (std::size_t i (0); i < object_traits::out_column_count; ++i)
out_image_bind_[i].error = out_image_error_ + 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);
+ 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/mysql/result.hxx b/odb/mysql/result.hxx
index 336d46c..ec232a5 100644
--- a/odb/mysql/result.hxx
+++ b/odb/mysql/result.hxx
@@ -39,10 +39,10 @@ namespace odb
object_statements<object_type>& statements);
virtual void
- current (object_type&);
+ load (object_type&);
virtual id_type
- current_id ();
+ load_id ();
virtual void
next ();
diff --git a/odb/mysql/result.txx b/odb/mysql/result.txx
index bb1fe01..4b18abc 100644
--- a/odb/mysql/result.txx
+++ b/odb/mysql/result.txx
@@ -3,6 +3,8 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <odb/cache-traits.hxx>
+
namespace odb
{
namespace mysql
@@ -26,14 +28,22 @@ namespace odb
template <typename T>
void result_impl<T>::
- current (object_type& x)
+ load (object_type& obj)
{
- object_traits::init (x, statements_.image (), this->database ());
+ // This is a top-level call so the statements cannot be locked.
+ //
+ assert (!statements_.locked ());
+ typename object_statements<object_type>::auto_lock l (statements_);
+
+ object_traits::init (obj, statements_.image (), this->database ());
+
+ statements_.load_delayed ();
+ l.unlock ();
}
template <typename T>
typename result_impl<T>::id_type result_impl<T>::
- current_id ()
+ load_id ()
{
return object_traits::id (statements_.image ());
}