aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-08-18 11:38:40 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-08-18 11:38:40 +0200
commit7391841a063328828621c8b70e02a81674686c97 (patch)
treedd76ccec9aa962461acc9a8e64d12fe75d2313c4
parent206f2b922531a6a2222145aae3ae90041c3c7ffe (diff)
Fix custom recursive loading in post_load callback
Before we called the callback while holding the statements locked. As a result, if the callback tried to load another object of this type, it failed. Now we unlock the statements (since we have completely loaded the object from ODB's point of view) and then call the callback. The callback test has been updated to test this situation.
-rw-r--r--odb/pgsql/object-statements.hxx16
-rw-r--r--odb/pgsql/object-statements.ixx16
-rw-r--r--odb/pgsql/object-statements.txx13
-rw-r--r--odb/pgsql/result.txx3
4 files changed, 45 insertions, 3 deletions
diff --git a/odb/pgsql/object-statements.hxx b/odb/pgsql/object-statements.hxx
index 32ea24b..ca5aecd 100644
--- a/odb/pgsql/object-statements.hxx
+++ b/odb/pgsql/object-statements.hxx
@@ -74,6 +74,22 @@ namespace odb
{
}
+ struct auto_unlock
+ {
+ // Unlocks the statement on construction and re-locks it on
+ // destruction.
+ //
+ auto_unlock (object_statements_base&);
+ ~auto_unlock ();
+
+ private:
+ auto_unlock (const auto_unlock&);
+ auto_unlock& operator= (const auto_unlock&);
+
+ private:
+ object_statements_base& s_;
+ };
+
protected:
connection_type& conn_;
bool locked_;
diff --git a/odb/pgsql/object-statements.ixx b/odb/pgsql/object-statements.ixx
index ea19baa..3955bf6 100644
--- a/odb/pgsql/object-statements.ixx
+++ b/odb/pgsql/object-statements.ixx
@@ -8,6 +8,22 @@ namespace odb
namespace pgsql
{
//
+ // auto_unlock
+ //
+ inline object_statements_base::auto_unlock::
+ auto_unlock (object_statements_base& s)
+ : s_ (s)
+ {
+ s_.unlock ();
+ }
+
+ inline object_statements_base::auto_unlock::
+ ~auto_unlock ()
+ {
+ s_.lock ();
+ }
+
+ //
// auto_lock
//
template <typename T>
diff --git a/odb/pgsql/object-statements.txx b/odb/pgsql/object-statements.txx
index b64d5b8..c568ca7 100644
--- a/odb/pgsql/object-statements.txx
+++ b/odb/pgsql/object-statements.txx
@@ -80,7 +80,18 @@ namespace odb
if (!delayed_.empty ())
load_delayed_ ();
- object_traits::callback (db, *l.obj, callback_event::post_load);
+ // Temporarily unlock the statement for the post_load call so that
+ // it can load objects of this type recursively. This is safe to do
+ // because we have completely loaded the current object. Also the
+ // delayed_ list is clear before the unlock and should be clear on
+ // re-lock (since a callback can only call public API functions
+ // which will make sure all the delayed loads are processed before
+ // returning).
+ //
+ {
+ auto_unlock u (*this);
+ object_traits::callback (db, *l.obj, callback_event::post_load);
+ }
g.release ();
}
diff --git a/odb/pgsql/result.txx b/odb/pgsql/result.txx
index edea595..a0dc2f8 100644
--- a/odb/pgsql/result.txx
+++ b/odb/pgsql/result.txx
@@ -60,9 +60,8 @@ namespace odb
object_traits::load_ (statements_, obj);
statements_.load_delayed ();
- object_traits::callback (db, obj, callback_event::post_load);
-
l.unlock ();
+ object_traits::callback (db, obj, callback_event::post_load);
}
template <typename T>