diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2011-08-18 11:38:40 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2011-08-18 11:38:40 +0200 |
commit | e4420208045f1bfb1a9c1fc726b4f6d1ae268f92 (patch) | |
tree | 48a0659705d8e6af14e6eb1b992ce500518f6818 | |
parent | 58c30a12b89a0c5dcaf93b142f4a781cb9363add (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/mysql/object-statements.hxx | 16 | ||||
-rw-r--r-- | odb/mysql/object-statements.ixx | 16 | ||||
-rw-r--r-- | odb/mysql/object-statements.txx | 13 | ||||
-rw-r--r-- | odb/mysql/result.txx | 3 |
4 files changed, 45 insertions, 3 deletions
diff --git a/odb/mysql/object-statements.hxx b/odb/mysql/object-statements.hxx index c341352..3f3196d 100644 --- a/odb/mysql/object-statements.hxx +++ b/odb/mysql/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/mysql/object-statements.ixx b/odb/mysql/object-statements.ixx index 9dc772b..713a09f 100644 --- a/odb/mysql/object-statements.ixx +++ b/odb/mysql/object-statements.ixx @@ -8,6 +8,22 @@ namespace odb namespace mysql { // + // 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/mysql/object-statements.txx b/odb/mysql/object-statements.txx index f98f11d..7cf1baa 100644 --- a/odb/mysql/object-statements.txx +++ b/odb/mysql/object-statements.txx @@ -70,7 +70,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/mysql/result.txx b/odb/mysql/result.txx index 84eb723..a010458 100644 --- a/odb/mysql/result.txx +++ b/odb/mysql/result.txx @@ -62,9 +62,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> |