diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-23 16:48:01 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-23 16:48:01 +0200 |
commit | 42503207920b9264e04c97cb6a5c53214fd2eff8 (patch) | |
tree | dd192b60515188e2afd6f11e7cc54aac73f571e4 | |
parent | 4d0711124bb6cdca491e33a51911d20090a1879a (diff) |
Polymorphic inheritance support
24 files changed, 1668 insertions, 577 deletions
diff --git a/odb/mysql/binding.hxx b/odb/mysql/binding.hxx index 3b467f3..10293e2 100644 --- a/odb/mysql/binding.hxx +++ b/odb/mysql/binding.hxx @@ -11,8 +11,8 @@ #include <odb/forward.hxx> -#include <odb/mysql/mysql.hxx> #include <odb/mysql/version.hxx> +#include <odb/mysql/mysql-types.hxx> #include <odb/mysql/details/export.hxx> @@ -23,6 +23,8 @@ namespace odb class LIBODB_MYSQL_EXPORT binding { public: + binding (): bind (0), count (0), version (0) {} + binding (MYSQL_BIND* b, std::size_t n) : bind (b), count (n), version (0) { diff --git a/odb/mysql/forward.hxx b/odb/mysql/forward.hxx index 53a02ff..16bdc4c 100644 --- a/odb/mysql/forward.hxx +++ b/odb/mysql/forward.hxx @@ -38,7 +38,13 @@ namespace odb class object_statements; template <typename T> - class object_statements_no_id; + class polymorphic_root_object_statements; + + template <typename T> + class polymorphic_derived_object_statements; + + template <typename T> + class no_id_object_statements; template <typename T> class view_statements; diff --git a/odb/mysql/makefile b/odb/mysql/makefile index 1aed7ac..1b14f60 100644 --- a/odb/mysql/makefile +++ b/odb/mysql/makefile @@ -4,22 +4,22 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make -cxx := \ -connection.cxx \ -connection-factory.cxx \ -database.cxx \ -enum.cxx \ -error.cxx \ -exceptions.cxx \ -object-statements.cxx \ -query.cxx \ -query-const-expr.cxx \ -statement.cxx \ -statements-base.cxx \ -tracer.cxx \ -transaction.cxx \ -transaction-impl.cxx \ -traits.cxx +cxx := \ +connection.cxx \ +connection-factory.cxx \ +database.cxx \ +enum.cxx \ +error.cxx \ +exceptions.cxx \ +query.cxx \ +query-const-expr.cxx \ +simple-object-statements.cxx \ +statement.cxx \ +statements-base.cxx \ +tracer.cxx \ +traits.cxx \ +transaction.cxx \ +transaction-impl.cxx cli_tun := details/options.cli cxx_tun := $(cxx) diff --git a/odb/mysql/no-id-object-result.hxx b/odb/mysql/no-id-object-result.hxx new file mode 100644 index 0000000..eb562bf --- /dev/null +++ b/odb/mysql/no-id-object-result.hxx @@ -0,0 +1,75 @@ +// file : odb/mysql/no-id-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_NO_ID_OBJECT_RESULT_HXX +#define ODB_MYSQL_NO_ID_OBJECT_RESULT_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/no-id-object-result.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/mysql/version.hxx> +#include <odb/mysql/forward.hxx> // query +#include <odb/mysql/statement.hxx> + +namespace odb +{ + namespace mysql + { + template <typename T> + class no_id_object_result_impl: public odb::no_id_object_result_impl<T> + { + public: + typedef odb::no_id_object_result_impl<T> base_type; + + typedef typename base_type::object_type object_type; + typedef typename base_type::object_traits object_traits; + + typedef typename base_type::pointer_type pointer_type; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename object_traits::statements_type statements_type; + + virtual + ~no_id_object_result_impl (); + + no_id_object_result_impl (const query&, + details::shared_ptr<select_statement>, + statements_type&); + + virtual void + load (object_type&); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + using base_type::current; + + private: + void + fetch (); + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + std::size_t count_; + }; + } +} + +#include <odb/mysql/no-id-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_MYSQL_NO_ID_OBJECT_RESULT_HXX diff --git a/odb/mysql/no-id-object-result.txx b/odb/mysql/no-id-object-result.txx new file mode 100644 index 0000000..864b49d --- /dev/null +++ b/odb/mysql/no-id-object-result.txx @@ -0,0 +1,158 @@ +// file : odb/mysql/no-id-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/callback.hxx> +#include <odb/exceptions.hxx> // result_not_cached + +#include <odb/mysql/no-id-object-statements.hxx> + +namespace odb +{ + namespace mysql + { + template <typename T> + no_id_object_result_impl<T>:: + ~no_id_object_result_impl () + { + if (!this->end_) + statement_->free_result (); + } + + template <typename T> + no_id_object_result_impl<T>:: + no_id_object_result_impl (const query&, + details::shared_ptr<select_statement> statement, + statements_type& statements) + : base_type (statements.connection ().database ()), + statement_ (statement), + statements_ (statements), + count_ (0) + { + } + + template <typename T> + void no_id_object_result_impl<T>:: + load (object_type& obj) + { + if (count_ > statement_->fetched ()) + fetch (); + + odb::database& db (this->database ()); + + object_traits::callback (db, obj, callback_event::pre_load); + object_traits::init (obj, statements_.image (), &db); + object_traits::callback (db, obj, callback_event::post_load); + } + + template <typename T> + void no_id_object_result_impl<T>:: + next () + { + this->current (pointer_type ()); + + // If we are cached, simply increment the position and + // postpone the actual row fetching until later. This way + // if the same object is loaded in between iteration, the + // image won't be messed up. + // + count_++; + + if (statement_->cached ()) + this->end_ = count_ > statement_->result_size (); + else + fetch (); + + if (this->end_) + statement_->free_result (); + } + + template <typename T> + void no_id_object_result_impl<T>:: + fetch () + { + // If the result is cached, the image can grow between calls + // to fetch() as a result of other statements execution. + // + if (statement_->cached ()) + { + typename object_traits::image_type& im (statements_.image ()); + + if (im.version != statements_.select_image_version ()) + { + binding& b (statements_.select_image_binding ()); + object_traits::bind (b.bind, im, statement_select); + statements_.select_image_version (im.version); + b.version++; + } + } + + while (!this->end_ && count_ > statement_->fetched ()) + { + select_statement::result r (statement_->fetch ()); + + switch (r) + { + case select_statement::truncated: + { + // Don't re-fetch data we are skipping. + // + if (count_ != statement_->fetched ()) + continue; + + typename object_traits::image_type& im (statements_.image ()); + + if (object_traits::grow ( + im, statements_.select_image_truncated ())) + im.version++; + + if (im.version != statements_.select_image_version ()) + { + binding& b (statements_.select_image_binding ()); + object_traits::bind (b.bind, im, statement_select); + statements_.select_image_version (im.version); + b.version++; + statement_->refetch (); + } + // Fall throught. + } + case select_statement::success: + { + break; + } + case select_statement::no_data: + { + this->end_ = true; + break; + } + } + } + } + + template <typename T> + void no_id_object_result_impl<T>:: + cache () + { + if (!statement_->cached ()) + { + statement_->cache (); + + if (count_ >= statement_->result_size ()) + { + statement_->free_result (); + this->end_ = true; + } + } + } + + template <typename T> + std::size_t no_id_object_result_impl<T>:: + size () + { + if (!statement_->cached ()) + throw result_not_cached (); + + return statement_->result_size (); + } + } +} diff --git a/odb/mysql/no-id-object-statements.hxx b/odb/mysql/no-id-object-statements.hxx new file mode 100644 index 0000000..89f736b --- /dev/null +++ b/odb/mysql/no-id-object-statements.hxx @@ -0,0 +1,134 @@ +// file : odb/mysql/no-id-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_NO_ID_OBJECT_STATEMENTS_HXX +#define ODB_MYSQL_NO_ID_OBJECT_STATEMENTS_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/forward.hxx> +#include <odb/traits.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/mysql/version.hxx> +#include <odb/mysql/forward.hxx> +#include <odb/mysql/mysql.hxx> +#include <odb/mysql/binding.hxx> +#include <odb/mysql/statement.hxx> +#include <odb/mysql/statements-base.hxx> + +namespace odb +{ + namespace mysql + { + // + // Implementation for objects without object id. + // + + template <typename T> + class no_id_object_statements: public statements_base + { + public: + typedef T object_type; + typedef odb::object_traits<object_type> object_traits; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::image_type image_type; + + typedef mysql::insert_statement insert_statement_type; + + public: + no_id_object_statements (connection_type&); + + virtual + ~no_id_object_statements (); + + // Object image. + // + image_type& + image () {return image_;} + + // Insert binding. + // + std::size_t + insert_image_version () const { return insert_image_version_;} + + void + insert_image_version (std::size_t v) {insert_image_version_ = v;} + + binding& + insert_image_binding () {return insert_image_binding_;} + + // Select binding (needed for query support). + // + std::size_t + select_image_version () const { return select_image_version_;} + + void + select_image_version (std::size_t v) {select_image_version_ = v;} + + binding& + select_image_binding () {return select_image_binding_;} + + my_bool* + select_image_truncated () {return select_image_truncated_;} + + // Statements. + // + insert_statement_type& + persist_statement () + { + if (persist_ == 0) + persist_.reset ( + new (details::shared) insert_statement_type ( + conn_, + object_traits::persist_statement, + insert_image_binding_, + false)); + + return *persist_; + } + + public: + // select = total + // insert = total - inverse; inverse == 0 for object without id + // + static const std::size_t select_column_count = + object_traits::column_count; + + static const std::size_t insert_column_count = + object_traits::column_count; + + private: + no_id_object_statements (const no_id_object_statements&); + no_id_object_statements& operator= (const no_id_object_statements&); + + private: + image_type image_; + + // Select binding. + // + std::size_t select_image_version_; + binding select_image_binding_; + MYSQL_BIND select_image_bind_[select_column_count]; + my_bool select_image_truncated_[select_column_count]; + + // Insert binding. + // + std::size_t insert_image_version_; + binding insert_image_binding_; + MYSQL_BIND insert_image_bind_[insert_column_count]; + + details::shared_ptr<insert_statement_type> persist_; + }; + } +} + +#include <odb/mysql/no-id-object-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_MYSQL_NO_ID_OBJECT_STATEMENTS_HXX diff --git a/odb/mysql/no-id-object-statements.txx b/odb/mysql/no-id-object-statements.txx new file mode 100644 index 0000000..f077b0b --- /dev/null +++ b/odb/mysql/no-id-object-statements.txx @@ -0,0 +1,37 @@ +// file : odb/mysql/no-id-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstring> // std::memset + +namespace odb +{ + namespace mysql + { + template <typename T> + no_id_object_statements<T>:: + ~no_id_object_statements () + { + } + + template <typename T> + no_id_object_statements<T>:: + no_id_object_statements (connection_type& conn) + : statements_base (conn), + select_image_binding_ (select_image_bind_, select_column_count), + insert_image_binding_ (insert_image_bind_, insert_column_count) + { + image_.version = 0; + select_image_version_ = 0; + insert_image_version_ = 0; + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + std::memset ( + select_image_truncated_, 0, sizeof (select_image_truncated_)); + + for (std::size_t i (0); i < select_column_count; ++i) + select_image_bind_[i].error = select_image_truncated_ + i; + } + } +} diff --git a/odb/mysql/object-result.hxx b/odb/mysql/object-result.hxx deleted file mode 100644 index 1571588..0000000 --- a/odb/mysql/object-result.hxx +++ /dev/null @@ -1,119 +0,0 @@ -// file : odb/mysql/object-result.hxx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#ifndef ODB_MYSQL_OBJECT_RESULT_HXX -#define ODB_MYSQL_OBJECT_RESULT_HXX - -#include <odb/pre.hxx> - -#include <cstddef> // std::size_t - -#include <odb/details/shared-ptr.hxx> - -#include <odb/mysql/version.hxx> -#include <odb/mysql/forward.hxx> // query, object_statements -#include <odb/mysql/result.hxx> -#include <odb/mysql/statement.hxx> - -namespace odb -{ - namespace mysql - { - template <typename T> - class object_result_impl: public odb::object_result_impl<T> - { - public: - typedef odb::object_result_impl<T> base_type; - - typedef typename base_type::object_type object_type; - typedef typename base_type::object_traits object_traits; - typedef typename base_type::id_type id_type; - - typedef typename base_type::pointer_type pointer_type; - typedef typename base_type::pointer_traits pointer_traits; - - virtual - ~object_result_impl (); - - object_result_impl (const query&, - details::shared_ptr<select_statement>, - object_statements<object_type>&); - - virtual void - load (object_type&, bool fetch); - - virtual id_type - load_id (); - - virtual void - next (); - - virtual void - cache (); - - virtual std::size_t - size (); - - using base_type::current; - - private: - void - fetch (bool next = true); - - private: - details::shared_ptr<select_statement> statement_; - object_statements<object_type>& statements_; - std::size_t count_; - }; - - template <typename T> - class object_result_impl_no_id: public odb::object_result_impl_no_id<T> - { - public: - typedef odb::object_result_impl_no_id<T> base_type; - - typedef typename base_type::object_type object_type; - typedef typename base_type::object_traits object_traits; - - typedef typename base_type::pointer_type pointer_type; - typedef typename base_type::pointer_traits pointer_traits; - - virtual - ~object_result_impl_no_id (); - - object_result_impl_no_id (const query&, - details::shared_ptr<select_statement>, - object_statements_no_id<object_type>&); - - virtual void - load (object_type&); - - virtual void - next (); - - virtual void - cache (); - - virtual std::size_t - size (); - - using base_type::current; - - private: - void - fetch (); - - private: - details::shared_ptr<select_statement> statement_; - object_statements_no_id<object_type>& statements_; - std::size_t count_; - }; - } -} - -#include <odb/mysql/object-result.txx> - -#include <odb/post.hxx> - -#endif // ODB_MYSQL_OBJECT_RESULT_HXX diff --git a/odb/mysql/polymorphic-object-result.hxx b/odb/mysql/polymorphic-object-result.hxx new file mode 100644 index 0000000..59bb74d --- /dev/null +++ b/odb/mysql/polymorphic-object-result.hxx @@ -0,0 +1,87 @@ +// file : odb/mysql/polymorphic-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_POLYMORPHIC_OBJECT_RESULT_HXX +#define ODB_MYSQL_POLYMORPHIC_OBJECT_RESULT_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/polymorphic-object-result.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/mysql/version.hxx> +#include <odb/mysql/forward.hxx> // query +#include <odb/mysql/statement.hxx> + +namespace odb +{ + namespace mysql + { + template <typename T> + class polymorphic_object_result_impl: + public odb::polymorphic_object_result_impl<T> + { + public: + typedef odb::polymorphic_object_result_impl<T> base_type; + + typedef typename base_type::object_type object_type; + typedef typename base_type::object_traits object_traits; + typedef typename base_type::id_type id_type; + + typedef typename base_type::pointer_type pointer_type; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename base_type::root_type root_type; + typedef typename base_type::root_traits root_traits; + typedef typename base_type::discriminator_type discriminator_type; + + typedef typename object_traits::statements_type statements_type; + + virtual + ~polymorphic_object_result_impl (); + + polymorphic_object_result_impl (const query&, + details::shared_ptr<select_statement>, + statements_type&); + + virtual void + load (object_type*, bool fetch); + + virtual id_type + load_id (); + + virtual discriminator_type + load_discriminator (); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + using base_type::current; + + private: + void + fetch (bool next = true); + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + std::size_t count_; + }; + } +} + +#include <odb/mysql/polymorphic-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_MYSQL_POLYMORPHIC_OBJECT_RESULT_HXX diff --git a/odb/mysql/polymorphic-object-result.txx b/odb/mysql/polymorphic-object-result.txx new file mode 100644 index 0000000..2e27677 --- /dev/null +++ b/odb/mysql/polymorphic-object-result.txx @@ -0,0 +1,344 @@ +// file : odb/mysql/polymorphic-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cassert> + +#include <odb/callback.hxx> +#include <odb/cache-traits.hxx> +#include <odb/exceptions.hxx> // result_not_cached + +#include <odb/mysql/polymorphic-object-statements.hxx> + +namespace odb +{ + namespace mysql + { + template <typename T> + polymorphic_object_result_impl<T>:: + ~polymorphic_object_result_impl () + { + if (!this->end_) + statement_->free_result (); + } + + template <typename T> + polymorphic_object_result_impl<T>:: + polymorphic_object_result_impl (const query&, + details::shared_ptr<select_statement> st, + statements_type& sts) + : base_type (sts.connection ().database ()), + statement_ (st), + statements_ (sts), + count_ (0) + { + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + load (object_type* pobj, bool f) + { + if (count_ > statement_->fetched ()) + fetch (); + else if (f && statement_->cached ()) + { + // We have to re-load the image in case it has been overwritten + // between the last time we fetched and this call to load(). + // + fetch (false); + } + + typename statements_type::root_statements_type& rsts ( + statements_.root_statements ()); + + // This is a top-level call so the statements cannot be locked. + // + assert (!rsts.locked ()); + typename statements_type::auto_lock l (rsts); + + odb::database& db (this->database ()); + typename object_traits::image_type& i (statements_.image ()); + typename root_traits::image_type& ri (rsts.image ()); + + id_type id (root_traits::id (ri)); + + // Determine this object's dynamic type. + // + typedef typename root_traits::info_type info_type; + discriminator_type d (root_traits::discriminator (ri)); + discriminator_type disc (d); + + // Use the polymorphic_info() helper to get concrete_info if + // object_type is concrete and NULL if it is abstract. + // + const info_type* spi (polymorphic_info (object_traits::info)); + const info_type& pi ( + spi != 0 && spi->discriminator == d + ? *spi + : root_traits::map->find (d)); + + typedef typename root_traits::pointer_type root_pointer_type; + typedef typename root_traits::pointer_traits root_pointer_traits; + + typename object_traits::pointer_cache_traits::insert_guard ig; + + if (pobj == 0) + { + // Need to create a new instance of the dynamic type. + // + root_pointer_type rp (pi.create ()); + pointer_type p ( + root_pointer_traits::template static_pointer_cast<object_type> (rp)); + + // Insert it as a root pointer (for non-unique pointers, rp should + // still be valid and for unique pointers this is a no-op). + // + ig.reset (object_traits::pointer_cache_traits::insert (db, id, rp)); + + pobj = &pointer_traits::get_ref (p); + current (p); + } + else + { + // We are loading into an existing instance. If the static and + // dynamic types differ, then make sure the instance is at least + // of the dynamic type. + // + if (&pi != &object_traits::info) + { + const info_type& dpi (root_traits::map->find (typeid (*pobj))); + + if (&dpi != &pi && dpi.derived (pi)) + throw object_not_persistent (); // @@ type_mismatch ? + } + } + + callback_event ce (callback_event::pre_load); + pi.dispatch (info_type::call_callback, db, pobj, &ce); + + object_traits::init (*pobj, i, &db); + + // Initialize the id image and binding and load the rest of the object + // (containers, dynamic part, etc). + // + typename object_traits::id_image_type& idi (statements_.id_image ()); + root_traits::init (idi, id); + + binding& idb (statements_.id_image_binding ()); + if (idi.version != statements_.id_image_version () || idb.version == 0) + { + object_traits::bind (idb.bind, idi); + statements_.id_image_version (idi.version); + idb.version++; + } + + object_traits::load_ (statements_, *pobj); + + // Load the dynamic part of the object unless static and dynamic + // types are the same. + // + if (&pi != &object_traits::info) + { + std::size_t d (object_traits::depth); + pi.dispatch (info_type::call_load, db, pobj, &d); + }; + + rsts.load_delayed (); + l.unlock (); + + ce = callback_event::post_load; + pi.dispatch (info_type::call_callback, db, pobj, &ce); + ig.release (); + } + + template <typename T> + typename polymorphic_object_result_impl<T>::id_type + polymorphic_object_result_impl<T>:: + load_id () + { + if (count_ > statement_->fetched ()) + fetch (); + else if (statement_->cached ()) + { + // We have to re-load the image in case it has been overwritten + // between the last time we fetched and this call to load_id(). + // + fetch (false); + } + + return root_traits::id (statements_.root_statements ().image ()); + } + + template <typename T> + typename polymorphic_object_result_impl<T>::discriminator_type + polymorphic_object_result_impl<T>:: + load_discriminator () + { + if (count_ > statement_->fetched ()) + fetch (); + else if (statement_->cached ()) + { + // We have to re-load the image in case it has been overwritten + // between the last time we fetched and this call to + // load_discriminator(). + // + fetch (false); + } + + return root_traits::discriminator ( + statements_.root_statements ().image ()); + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + next () + { + this->current (pointer_type ()); + + // If we are cached, simply increment the position and + // postpone the actual row fetching until later. This way + // if the same object is loaded in between iteration, the + // image won't be messed up. + // + count_++; + + if (statement_->cached ()) + this->end_ = count_ > statement_->result_size (); + else + fetch (); + + if (this->end_) + statement_->free_result (); + } + + template <typename T, typename R> + struct polymorphic_image_rebind + { + // Derived type version. + // + typedef object_traits<T> traits; + + static bool + rebind (typename traits::statements_type& sts) + { + typename traits::image_type& im (sts.image ()); + + if (traits::check_version (sts.select_image_versions (), im)) + { + binding& b (sts.select_image_binding (traits::depth)); + traits::bind (b.bind, 0, 0, im, statement_select); + traits::update_version ( + sts.select_image_versions (), im, sts.select_image_bindings ()); + return true; + } + + return false; + } + }; + + template <typename R> + struct polymorphic_image_rebind<R, R> + { + // Root type version. + // + typedef object_traits<R> traits; + + static bool + rebind (typename traits::statements_type& sts) + { + typename traits::image_type& im (sts.image ()); + + if (im.version != sts.select_image_version ()) + { + binding& b (sts.select_image_binding ()); + traits::bind (b.bind, im, statement_select); + sts.select_image_version (im.version); + b.version++; + return true; + } + + return false; + } + }; + + template <typename T> + void polymorphic_object_result_impl<T>:: + fetch (bool next) + { + typedef polymorphic_image_rebind<object_type, root_type> image_rebind; + + // If the result is cached, the image can grow between calls + // to fetch() as a result of other statements execution. + // + if (statement_->cached ()) + image_rebind::rebind (statements_); + + while (!this->end_ && (!next || count_ > statement_->fetched ())) + { + select_statement::result r (statement_->fetch (next)); + + switch (r) + { + case select_statement::truncated: + { + // Don't re-fetch data we are skipping. + // + if (next && count_ != statement_->fetched ()) + continue; + + typename object_traits::image_type& im (statements_.image ()); + + if (object_traits::grow (im, + statements_.select_image_truncated ())) + im.version++; + + if (image_rebind::rebind (statements_)) + statement_->refetch (); + + // Fall throught. + } + case select_statement::success: + { + break; + } + case select_statement::no_data: + { + this->end_ = true; + break; + } + } + + // If we are refetching the current row, then we are done. + // + if (!next) + break; + } + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + cache () + { + if (!statement_->cached ()) + { + statement_->cache (); + + if (count_ >= statement_->result_size ()) + { + statement_->free_result (); + this->end_ = true; + } + } + } + + template <typename T> + std::size_t polymorphic_object_result_impl<T>:: + size () + { + if (!statement_->cached ()) + throw result_not_cached (); + + return statement_->result_size (); + } + } +} diff --git a/odb/mysql/polymorphic-object-statements.hxx b/odb/mysql/polymorphic-object-statements.hxx new file mode 100644 index 0000000..75b1ae7 --- /dev/null +++ b/odb/mysql/polymorphic-object-statements.hxx @@ -0,0 +1,437 @@ +// file : odb/mysql/polymorphic-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX +#define ODB_MYSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/forward.hxx> +#include <odb/traits.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/mysql/version.hxx> +#include <odb/mysql/forward.hxx> +#include <odb/mysql/mysql.hxx> +#include <odb/mysql/binding.hxx> +#include <odb/mysql/statement.hxx> +#include <odb/mysql/statements-base.hxx> +#include <odb/mysql/simple-object-statements.hxx> + +namespace odb +{ + namespace mysql + { + // + // Implementation for polymorphic objects. + // + + template <typename T> + class polymorphic_root_object_statements: public object_statements<T> + { + public: + typedef typename object_statements<T>::connection_type connection_type; + typedef typename object_statements<T>::object_traits object_traits; + typedef typename object_statements<T>::id_image_type id_image_type; + + typedef + typename object_traits::discriminator_image_type + discriminator_image_type; + + typedef + typename object_statements<T>::select_statement_type + select_statement_type; + + public: + // Interface compatibility with derived_object_statements. + // + typedef polymorphic_root_object_statements root_statements_type; + + root_statements_type& + root_statements () + { + return *this; + } + + public: + // Discriminator binding. + // + discriminator_image_type& + discriminator_image () {return discriminator_image_;} + + std::size_t + discriminator_image_version () const + {return discriminator_image_version_;} + + void + discriminator_image_version (std::size_t v) + {discriminator_image_version_ = v;} + + binding& + discriminator_image_binding () {return discriminator_image_binding_;} + + my_bool* + discriminator_image_truncated () {return discriminator_image_truncated_;} + + // Id binding for discriminator retrieval. + // + id_image_type& + discriminator_id_image () {return discriminator_id_image_;} + + std::size_t + discriminator_id_image_version () const + {return discriminator_id_image_version_;} + + void + discriminator_id_image_version (std::size_t v) + {discriminator_id_image_version_ = v;} + + binding& + discriminator_id_image_binding () + {return discriminator_id_image_binding_;} + + // + // + select_statement_type& + find_discriminator_statement () + { + if (find_discriminator_ == 0) + find_discriminator_.reset ( + new (details::shared) select_statement_type ( + this->conn_, + object_traits::find_discriminator_statement, + discriminator_id_image_binding_, + discriminator_image_binding_, + false)); + + return *find_discriminator_; + } + + public: + polymorphic_root_object_statements (connection_type&); + + virtual + ~polymorphic_root_object_statements (); + + public: + static const std::size_t id_column_count = + object_statements<T>::id_column_count; + + static const std::size_t discriminator_column_count = + object_traits::discriminator_column_count; + + static const std::size_t managed_optimistic_column_count = + object_traits::managed_optimistic_column_count; + + private: + // Discriminator image. + // + discriminator_image_type discriminator_image_; + std::size_t discriminator_image_version_; + binding discriminator_image_binding_; + MYSQL_BIND discriminator_image_bind_[discriminator_column_count + + managed_optimistic_column_count]; + my_bool discriminator_image_truncated_[discriminator_column_count + + managed_optimistic_column_count]; + + // Id image for discriminator retrieval (only used as a parameter). + // + id_image_type discriminator_id_image_; + std::size_t discriminator_id_image_version_; + binding discriminator_id_image_binding_; + MYSQL_BIND discriminator_id_image_bind_[id_column_count]; + + details::shared_ptr<select_statement_type> find_discriminator_; + }; + + template <typename T> + class polymorphic_derived_object_statements: public 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::id_image_type id_image_type; + typedef typename object_traits::image_type image_type; + + typedef typename object_traits::root_type root_type; + typedef + polymorphic_root_object_statements<root_type> + root_statements_type; + + typedef typename object_traits::base_type base_type; + typedef + typename object_traits::base_traits::statements_type + base_statements_type; + + typedef + typename object_traits::container_statement_cache_type + container_statement_cache_type; + + typedef mysql::insert_statement insert_statement_type; + typedef mysql::select_statement select_statement_type; + typedef mysql::update_statement update_statement_type; + typedef mysql::delete_statement delete_statement_type; + + typedef typename root_statements_type::auto_lock auto_lock; + + public: + polymorphic_derived_object_statements (connection_type&); + + virtual + ~polymorphic_derived_object_statements (); + + public: + // Delayed loading. + // + static void + delayed_loader (odb::database&, const id_type&, root_type&); + + public: + // Root and immediate base statements. + // + root_statements_type& + root_statements () + { + return root_statements_; + } + + base_statements_type& + base_statements () + { + return base_statements_; + } + + public: + // Object image. + // + image_type& + image () + { + return image_; + } + + // Insert binding. + // + std::size_t + insert_image_version () const { return insert_image_version_;} + + void + insert_image_version (std::size_t v) {insert_image_version_ = v;} + + std::size_t + insert_id_binding_version () const { return insert_id_binding_version_;} + + void + insert_id_binding_version (std::size_t v) {insert_id_binding_version_ = v;} + + binding& + insert_image_binding () {return insert_image_binding_;} + + // Update binding. + // + std::size_t + update_image_version () const { return update_image_version_;} + + void + update_image_version (std::size_t v) {update_image_version_ = v;} + + std::size_t + update_id_binding_version () const { return update_id_binding_version_;} + + void + update_id_binding_version (std::size_t v) {update_id_binding_version_ = v;} + + binding& + update_image_binding () {return update_image_binding_;} + + // Select binding. + // + std::size_t* + select_image_versions () { return select_image_versions_;} + + binding* + select_image_bindings () {return select_image_bindings_;} + + binding& + select_image_binding (std::size_t d) + { + return select_image_bindings_[object_traits::depth - d]; + } + + my_bool* + select_image_truncated () {return select_image_truncated_;} + + // Object id binding (comes from the root statements). + // + id_image_type& + id_image () {return root_statements_.id_image ();} + + std::size_t + id_image_version () const {return root_statements_.id_image_version ();} + + void + id_image_version (std::size_t v) {root_statements_.id_image_version (v);} + + binding& + id_image_binding () {return root_statements_.id_image_binding ();} + + // Statements. + // + insert_statement_type& + persist_statement () + { + if (persist_ == 0) + persist_.reset ( + new (details::shared) insert_statement_type ( + conn_, + object_traits::persist_statement, + insert_image_binding_, + false)); + + return *persist_; + } + + select_statement_type& + find_statement (std::size_t d) + { + std::size_t i (object_traits::depth - d); + details::shared_ptr<select_statement_type>& p (find_[i]); + + if (p == 0) + p.reset ( + new (details::shared) select_statement_type ( + conn_, + object_traits::find_statements[i], + root_statements_.id_image_binding (), + select_image_bindings_[i], + false)); + + return *p; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + conn_, + object_traits::update_statement, + update_image_binding_, + false)); + + return *update_; + } + + delete_statement_type& + erase_statement () + { + if (erase_ == 0) + erase_.reset ( + new (details::shared) delete_statement_type ( + conn_, + object_traits::erase_statement, + root_statements_.id_image_binding (), + false)); + + return *erase_; + } + + // Container statement cache. + // + container_statement_cache_type& + container_statment_cache () + { + return container_statement_cache_; + } + + public: + // select = total - id + base::select + // insert = total - inverse + // update = total - inverse - id - readonly + // + static const std::size_t id_column_count = + object_traits::id_column_count; + + static const std::size_t select_column_count = + object_traits::column_count - id_column_count + + base_statements_type::select_column_count; + + static const std::size_t insert_column_count = + object_traits::column_count - object_traits::inverse_column_count; + + static const std::size_t update_column_count = insert_column_count - + object_traits::id_column_count - object_traits::readonly_column_count; + + private: + polymorphic_derived_object_statements ( + const polymorphic_derived_object_statements&); + + polymorphic_derived_object_statements& + operator= (const polymorphic_derived_object_statements&); + + private: + root_statements_type& root_statements_; + base_statements_type& base_statements_; + + container_statement_cache_type container_statement_cache_; + + image_type image_; + + // Select binding. Here we are have an array of statements/bindings + // one for each depth. In other words, if we have classes root, base, + // and derived, then we have the following array of statements: + // + // [0] d + b + r + // [1] d + b + // [2] d + // + // Also, because we have a chain of images bound to these statements, + // we have an array of versions, one entry for each base plus one for + // our own image. + // + // A poly-abstract class only needs the first statement and in this + // case we have only one entry in the the bindings and statements + // arrays (but not versions; we still have a chain of images). + // + std::size_t select_image_versions_[object_traits::depth]; + binding select_image_bindings_[ + object_traits::abstract ? 1 : object_traits::depth]; + MYSQL_BIND select_image_bind_[select_column_count]; + my_bool select_image_truncated_[select_column_count]; + + // Insert binding. The id binding is copied from the hierarchy root. + // + std::size_t insert_image_version_; + std::size_t insert_id_binding_version_; + binding insert_image_binding_; + MYSQL_BIND insert_image_bind_[insert_column_count]; + + // Update binding. The id suffix binding is copied from the hierarchy + // root. + // + std::size_t update_image_version_; + std::size_t update_id_binding_version_; + binding update_image_binding_; + MYSQL_BIND update_image_bind_[update_column_count + id_column_count]; + + details::shared_ptr<insert_statement_type> persist_; + details::shared_ptr<select_statement_type> find_[ + object_traits::abstract ? 1 : object_traits::depth]; + details::shared_ptr<update_statement_type> update_; + details::shared_ptr<delete_statement_type> erase_; + }; + } +} + +#include <odb/mysql/polymorphic-object-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_MYSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX diff --git a/odb/mysql/polymorphic-object-statements.txx b/odb/mysql/polymorphic-object-statements.txx new file mode 100644 index 0000000..19e5d52 --- /dev/null +++ b/odb/mysql/polymorphic-object-statements.txx @@ -0,0 +1,141 @@ +// file : odb/mysql/polymorphic-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstring> // std::memset + +#include <odb/callback.hxx> +#include <odb/exceptions.hxx> + +#include <odb/mysql/connection.hxx> +#include <odb/mysql/transaction.hxx> +#include <odb/mysql/statement-cache.hxx> + +namespace odb +{ + namespace mysql + { + // + // polymorphic_root_object_statements + // + + template <typename T> + polymorphic_root_object_statements<T>:: + ~polymorphic_root_object_statements () + { + } + + template <typename T> + polymorphic_root_object_statements<T>:: + polymorphic_root_object_statements (connection_type& conn) + : object_statements<T> (conn), + discriminator_image_binding_ (discriminator_image_bind_, + discriminator_column_count + + managed_optimistic_column_count), + discriminator_id_image_binding_ (discriminator_id_image_bind_, + id_column_count) + { + discriminator_image_.version = 0; + discriminator_id_image_.version = 0; + + discriminator_image_version_ = 0; + discriminator_id_image_version_ = 0; + + std::memset (discriminator_image_bind_, + 0, + sizeof (discriminator_image_bind_)); + std::memset (discriminator_id_image_bind_, + 0, + sizeof (discriminator_id_image_bind_)); + std::memset (discriminator_image_truncated_, + 0, + sizeof (discriminator_image_truncated_)); + + for (std::size_t i (0); + i < discriminator_column_count + managed_optimistic_column_count; + ++i) + { + discriminator_image_bind_[i].error = + discriminator_image_truncated_ + i; + } + } + + // + // polymorphic_derived_object_statements + // + + template <typename T> + polymorphic_derived_object_statements<T>:: + ~polymorphic_derived_object_statements () + { + } + + template <typename T> + polymorphic_derived_object_statements<T>:: + polymorphic_derived_object_statements (connection_type& conn) + : statements_base (conn), + root_statements_ (conn.statement_cache ().find_object<root_type> ()), + base_statements_ (conn.statement_cache ().find_object<base_type> ()), + container_statement_cache_ (conn), + insert_image_binding_ (insert_image_bind_, insert_column_count), + update_image_binding_ (update_image_bind_, + update_column_count + id_column_count) + { + image_.base = &base_statements_.image (); + image_.version = 0; + + for (std::size_t i (0); i < object_traits::depth; ++i) + select_image_versions_[i] = 0; + + for (std::size_t i (0); + i < (object_traits::abstract ? 1 : object_traits::depth); + ++i) + { + select_image_bindings_[i].bind = select_image_bind_; + select_image_bindings_[i].count = object_traits::find_column_counts[i]; + } + + insert_image_version_ = 0; + insert_id_binding_version_ = 0; + update_image_version_ = 0; + update_id_binding_version_ = 0; + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + std::memset ( + select_image_truncated_, 0, sizeof (select_image_truncated_)); + + for (std::size_t i (0); i < select_column_count; ++i) + select_image_bind_[i].error = select_image_truncated_ + i; + } + + template <typename T> + void polymorphic_derived_object_statements<T>:: + delayed_loader (odb::database& db, const id_type& id, root_type& robj) + { + connection_type& conn (transaction::current ().connection ()); + polymorphic_derived_object_statements& sts ( + conn.statement_cache ().find_object<object_type> ()); + root_statements_type& rsts (sts.root_statements ()); + + object_type& obj (static_cast<object_type&> (robj)); + + // The same code as in object_statements::load_delayed_(). + // + if (!object_traits::find_ (sts, &id)) + throw object_not_persistent (); + + object_traits::callback (db, obj, callback_event::pre_load); + object_traits::init (obj, sts.image (), &db); + object_traits::load_ (sts, obj); // Load containers, etc. + + rsts.load_delayed (); + + { + typename root_statements_type::auto_unlock u (rsts); + object_traits::callback (db, obj, callback_event::post_load); + } + } + } +} diff --git a/odb/mysql/result.hxx b/odb/mysql/result.hxx deleted file mode 100644 index 7545e76..0000000 --- a/odb/mysql/result.hxx +++ /dev/null @@ -1,25 +0,0 @@ -// file : odb/mysql/result.hxx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#ifndef ODB_MYSQL_RESULT_HXX -#define ODB_MYSQL_RESULT_HXX - -#include <odb/pre.hxx> - -#include <odb/traits.hxx> -#include <odb/result.hxx> - -#include <odb/mysql/version.hxx> -#include <odb/mysql/forward.hxx> - -#include <odb/post.hxx> - -#endif // ODB_MYSQL_RESULT_HXX - -// Include result specializations so that the user code only needs -// to include this header. -// - -#include <odb/mysql/object-result.hxx> -#include <odb/mysql/view-result.hxx> diff --git a/odb/mysql/simple-object-result.hxx b/odb/mysql/simple-object-result.hxx new file mode 100644 index 0000000..b92c5ce --- /dev/null +++ b/odb/mysql/simple-object-result.hxx @@ -0,0 +1,79 @@ +// file : odb/mysql/simple-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_SIMPLE_OBJECT_RESULT_HXX +#define ODB_MYSQL_SIMPLE_OBJECT_RESULT_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/simple-object-result.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/mysql/version.hxx> +#include <odb/mysql/forward.hxx> // query +#include <odb/mysql/statement.hxx> + +namespace odb +{ + namespace mysql + { + template <typename T> + class object_result_impl: public odb::object_result_impl<T> + { + public: + typedef odb::object_result_impl<T> base_type; + + typedef typename base_type::object_type object_type; + typedef typename base_type::object_traits object_traits; + typedef typename base_type::id_type id_type; + + typedef typename base_type::pointer_type pointer_type; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename object_traits::statements_type statements_type; + + virtual + ~object_result_impl (); + + object_result_impl (const query&, + details::shared_ptr<select_statement>, + statements_type&); + + virtual void + load (object_type&, bool fetch); + + virtual id_type + load_id (); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + using base_type::current; + + private: + void + fetch (bool next = true); + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + std::size_t count_; + }; + } +} + +#include <odb/mysql/simple-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_MYSQL_SIMPLE_OBJECT_RESULT_HXX diff --git a/odb/mysql/object-result.txx b/odb/mysql/simple-object-result.txx index 8144578..f77f83e 100644 --- a/odb/mysql/object-result.txx +++ b/odb/mysql/simple-object-result.txx @@ -1,22 +1,18 @@ -// file : odb/mysql/object-result.txx +// file : odb/mysql/simple-object-result.txx // copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cassert> #include <odb/callback.hxx> -#include <odb/exceptions.hxx> +#include <odb/exceptions.hxx> // result_not_cached -#include <odb/mysql/object-statements.hxx> +#include <odb/mysql/simple-object-statements.hxx> namespace odb { namespace mysql { - // - // object_result_impl - // - template <typename T> object_result_impl<T>:: ~object_result_impl () @@ -29,7 +25,7 @@ namespace odb object_result_impl<T>:: object_result_impl (const query&, details::shared_ptr<select_statement> statement, - object_statements<object_type>& statements) + statements_type& statements) : base_type (statements.connection ().database ()), statement_ (statement), statements_ (statements), @@ -54,7 +50,7 @@ namespace odb // This is a top-level call so the statements cannot be locked. // assert (!statements_.locked ()); - typename object_statements<object_type>::auto_lock l (statements_); + typename statements_type::auto_lock l (statements_); odb::database& db (this->database ()); object_traits::callback (db, obj, callback_event::pre_load); @@ -214,153 +210,5 @@ namespace odb return statement_->result_size (); } - - // - // object_result_impl_no_id - // - - template <typename T> - object_result_impl_no_id<T>:: - ~object_result_impl_no_id () - { - if (!this->end_) - statement_->free_result (); - } - - template <typename T> - object_result_impl_no_id<T>:: - object_result_impl_no_id (const query&, - details::shared_ptr<select_statement> statement, - object_statements_no_id<object_type>& statements) - : base_type (statements.connection ().database ()), - statement_ (statement), - statements_ (statements), - count_ (0) - { - } - - template <typename T> - void object_result_impl_no_id<T>:: - load (object_type& obj) - { - if (count_ > statement_->fetched ()) - fetch (); - - odb::database& db (this->database ()); - - object_traits::callback (db, obj, callback_event::pre_load); - object_traits::init (obj, statements_.image (), &db); - object_traits::callback (db, obj, callback_event::post_load); - } - - template <typename T> - void object_result_impl_no_id<T>:: - next () - { - this->current (pointer_type ()); - - // If we are cached, simply increment the position and - // postpone the actual row fetching until later. This way - // if the same object is loaded in between iteration, the - // image won't be messed up. - // - count_++; - - if (statement_->cached ()) - this->end_ = count_ > statement_->result_size (); - else - fetch (); - - if (this->end_) - statement_->free_result (); - } - - template <typename T> - void object_result_impl_no_id<T>:: - fetch () - { - // If the result is cached, the image can grow between calls - // to fetch() as a result of other statements execution. - // - if (statement_->cached ()) - { - typename object_traits::image_type& im (statements_.image ()); - - if (im.version != statements_.select_image_version ()) - { - binding& b (statements_.select_image_binding ()); - object_traits::bind (b.bind, im, statement_select); - statements_.select_image_version (im.version); - b.version++; - } - } - - while (!this->end_ && count_ > statement_->fetched ()) - { - select_statement::result r (statement_->fetch ()); - - switch (r) - { - case select_statement::truncated: - { - // Don't re-fetch data we are skipping. - // - if (count_ != statement_->fetched ()) - continue; - - typename object_traits::image_type& im (statements_.image ()); - - if (object_traits::grow ( - im, statements_.select_image_truncated ())) - im.version++; - - if (im.version != statements_.select_image_version ()) - { - binding& b (statements_.select_image_binding ()); - object_traits::bind (b.bind, im, statement_select); - statements_.select_image_version (im.version); - b.version++; - statement_->refetch (); - } - // Fall throught. - } - case select_statement::success: - { - break; - } - case select_statement::no_data: - { - this->end_ = true; - break; - } - } - } - } - - template <typename T> - void object_result_impl_no_id<T>:: - cache () - { - if (!statement_->cached ()) - { - statement_->cache (); - - if (count_ >= statement_->result_size ()) - { - statement_->free_result (); - this->end_ = true; - } - } - } - - template <typename T> - std::size_t object_result_impl_no_id<T>:: - size () - { - if (!statement_->cached ()) - throw result_not_cached (); - - return statement_->result_size (); - } } } diff --git a/odb/mysql/object-statements.cxx b/odb/mysql/simple-object-statements.cxx index 9ad9e99..8452b55 100644 --- a/odb/mysql/object-statements.cxx +++ b/odb/mysql/simple-object-statements.cxx @@ -1,8 +1,8 @@ -// file : odb/mysql/object-statements.cxx +// file : odb/mysql/simple-object-statements.cxx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#include <odb/mysql/object-statements.hxx> +#include <odb/mysql/simple-object-statements.hxx> namespace odb { diff --git a/odb/mysql/object-statements.hxx b/odb/mysql/simple-object-statements.hxx index 974700f..9a3e80e 100644 --- a/odb/mysql/object-statements.hxx +++ b/odb/mysql/simple-object-statements.hxx @@ -1,9 +1,9 @@ -// file : odb/mysql/object-statements.hxx +// file : odb/mysql/simple-object-statements.hxx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#ifndef ODB_MYSQL_OBJECT_STATEMENTS_HXX -#define ODB_MYSQL_OBJECT_STATEMENTS_HXX +#ifndef ODB_MYSQL_SIMPLE_OBJECT_STATEMENTS_HXX +#define ODB_MYSQL_SIMPLE_OBJECT_STATEMENTS_HXX #include <odb/pre.hxx> @@ -17,8 +17,10 @@ #include <odb/details/shared-ptr.hxx> -#include <odb/mysql/mysql.hxx> #include <odb/mysql/version.hxx> +#include <odb/mysql/forward.hxx> +#include <odb/mysql/mysql.hxx> +#include <odb/mysql/binding.hxx> #include <odb/mysql/statement.hxx> #include <odb/mysql/statements-base.hxx> @@ -28,24 +30,6 @@ namespace odb { namespace mysql { - template <typename T> - class object_statements; - - template <typename T> - class object_statements_no_id; - - template <typename T, typename ID = typename object_traits<T>::id_type> - struct object_statements_selector - { - typedef object_statements<T> type; - }; - - template <typename T> - struct object_statements_selector<T, void> - { - typedef object_statements_no_id<T> type; - }; - // // Implementation for objects with object id. // @@ -75,16 +59,6 @@ namespace odb return locked_; } - public: - virtual - ~object_statements_base (); - - protected: - object_statements_base (connection_type& conn) - : statements_base (conn), locked_ (false) - { - } - struct auto_unlock { // Unlocks the statement on construction and re-locks it on @@ -101,6 +75,16 @@ namespace odb object_statements_base& s_; }; + public: + virtual + ~object_statements_base (); + + protected: + object_statements_base (connection_type& conn) + : statements_base (conn), locked_ (false) + { + } + protected: bool locked_; }; @@ -141,7 +125,9 @@ namespace odb 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::pointer_cache_traits + pointer_cache_traits; typedef typename object_traits::container_statement_cache_type @@ -195,12 +181,16 @@ namespace odb // Delayed loading. // + typedef void (*loader_function) ( + odb::database&, const id_type&, object_type&); + void delay_load (const id_type& id, object_type& obj, - const typename object_cache_traits::position_type& p) + const typename pointer_cache_traits::position_type& p, + loader_function l = 0) { - delayed_.push_back (delayed_load (id, obj, p)); + delayed_.push_back (delayed_load (id, obj, p, l)); } void @@ -374,18 +364,7 @@ namespace odb return container_statement_cache_; } - private: - object_statements (const object_statements&); - object_statements& operator= (const object_statements&); - - private: - void - load_delayed_ (); - - void - clear_delayed_ (); - - private: + public: // select = total // insert = total - inverse - managed_optimistic // update = total - inverse - managed_optimistic - id - readonly @@ -407,6 +386,17 @@ namespace odb object_traits::managed_optimistic_column_count; 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_; @@ -458,17 +448,21 @@ namespace odb // struct delayed_load { - typedef typename object_cache_traits::position_type position_type; + typedef typename pointer_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) + delayed_load (const id_type& i, + object_type& o, + const position_type& p, + loader_function l) + : id (i), obj (&o), pos (p), loader (l) { } id_type id; object_type* obj; position_type pos; + loader_function loader; }; typedef std::vector<delayed_load> delayed_loads; @@ -496,113 +490,12 @@ namespace odb delayed_loads& dl_; }; }; - - // - // Implementation for objects without object id. - // - - template <typename T> - class object_statements_no_id: public statements_base - { - public: - typedef T object_type; - typedef odb::object_traits<object_type> object_traits; - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::image_type image_type; - - typedef mysql::insert_statement insert_statement_type; - - public: - object_statements_no_id (connection_type&); - - virtual - ~object_statements_no_id (); - - // Object image. - // - image_type& - image () {return image_;} - - // Insert binding. - // - std::size_t - insert_image_version () const { return insert_image_version_;} - - void - insert_image_version (std::size_t v) {insert_image_version_ = v;} - - binding& - insert_image_binding () {return insert_image_binding_;} - - // Select binding (needed for query support). - // - std::size_t - select_image_version () const { return select_image_version_;} - - void - select_image_version (std::size_t v) {select_image_version_ = v;} - - binding& - select_image_binding () {return select_image_binding_;} - - my_bool* - select_image_truncated () {return select_image_truncated_;} - - // Statements. - // - insert_statement_type& - persist_statement () - { - if (persist_ == 0) - persist_.reset ( - new (details::shared) insert_statement_type ( - conn_, - object_traits::persist_statement, - insert_image_binding_, - false)); - - return *persist_; - } - - private: - object_statements_no_id (const object_statements_no_id&); - object_statements_no_id& operator= (const object_statements_no_id&); - - private: - // select = total - // insert = total - inverse; inverse == 0 for object without id - // - - static const std::size_t select_column_count = - object_traits::column_count; - - static const std::size_t insert_column_count = - object_traits::column_count; - - private: - image_type image_; - - // Select binding. - // - std::size_t select_image_version_; - binding select_image_binding_; - MYSQL_BIND select_image_bind_[select_column_count]; - my_bool select_image_truncated_[select_column_count]; - - // Insert binding. - // - std::size_t insert_image_version_; - binding insert_image_binding_; - MYSQL_BIND insert_image_bind_[insert_column_count]; - - details::shared_ptr<insert_statement_type> persist_; - }; } } -#include <odb/mysql/object-statements.ixx> -#include <odb/mysql/object-statements.txx> +#include <odb/mysql/simple-object-statements.ixx> +#include <odb/mysql/simple-object-statements.txx> #include <odb/post.hxx> -#endif // ODB_MYSQL_OBJECT_STATEMENTS_HXX +#endif // ODB_MYSQL_SIMPLE_OBJECT_STATEMENTS_HXX diff --git a/odb/mysql/object-statements.ixx b/odb/mysql/simple-object-statements.ixx index 3b483dd..8cbc97b 100644 --- a/odb/mysql/object-statements.ixx +++ b/odb/mysql/simple-object-statements.ixx @@ -1,4 +1,4 @@ -// file : odb/mysql/object-statements.ixx +// file : odb/mysql/simple-object-statements.ixx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file diff --git a/odb/mysql/object-statements.txx b/odb/mysql/simple-object-statements.txx index 2ad4bc9..81f3bce 100644 --- a/odb/mysql/object-statements.txx +++ b/odb/mysql/simple-object-statements.txx @@ -1,8 +1,7 @@ -// file : odb/mysql/object-statements.txx +// file : odb/mysql/simple-object-statements.txx // copyright : Copyright (c) 2005-2012 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> @@ -85,36 +84,41 @@ namespace odb while (!dls.empty ()) { delayed_load l (dls.back ()); - typename object_cache_traits::insert_guard g (l.pos); + typename pointer_cache_traits::insert_guard g (l.pos); dls.pop_back (); - if (!object_traits::find_ (*this, l.id)) - throw object_not_persistent (); - - object_traits::callback (db, *l.obj, callback_event::pre_load); - - // Our calls to init/load below can result in additional delayed - // loads being added to the delayed_ vector. We need to process - // those before we call the post callback. - // - object_traits::init (*l.obj, image (), &db); - object_traits::load_ (*this, *l.obj); // Load containers, etc. - - if (!delayed_.empty ()) - load_delayed_ (); - - // 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). - // + if (l.loader == 0) { - auto_unlock u (*this); - object_traits::callback (db, *l.obj, callback_event::post_load); + if (!object_traits::find_ (*this, &l.id)) + throw object_not_persistent (); + + object_traits::callback (db, *l.obj, callback_event::pre_load); + + // Our calls to init/load below can result in additional delayed + // loads being added to the delayed_ vector. We need to process + // those before we call the post callback. + // + object_traits::init (*l.obj, image (), &db); + object_traits::load_ (*this, *l.obj); // Load containers, etc. + + if (!delayed_.empty ()) + load_delayed_ (); + + // 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); + } } + else + l.loader (db, l.id, *l.obj); g.release (); } @@ -131,41 +135,11 @@ namespace odb for (typename delayed_loads::iterator i (delayed_.begin ()), e (delayed_.end ()); i != e; ++i) { - object_cache_traits::erase (i->pos); + pointer_cache_traits::erase (i->pos); } } delayed_.clear (); } - - // - // object_statements - // - - template <typename T> - object_statements_no_id<T>:: - ~object_statements_no_id () - { - } - - template <typename T> - object_statements_no_id<T>:: - object_statements_no_id (connection_type& conn) - : statements_base (conn), - select_image_binding_ (select_image_bind_, select_column_count), - insert_image_binding_ (insert_image_bind_, insert_column_count) - { - image_.version = 0; - select_image_version_ = 0; - insert_image_version_ = 0; - - std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); - std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); - std::memset ( - select_image_truncated_, 0, sizeof (select_image_truncated_)); - - for (std::size_t i (0); i < select_column_count; ++i) - select_image_bind_[i].error = select_image_truncated_ + i; - } } } diff --git a/odb/mysql/statement-cache.hxx b/odb/mysql/statement-cache.hxx index e62c76c..f801972 100644 --- a/odb/mysql/statement-cache.hxx +++ b/odb/mysql/statement-cache.hxx @@ -11,11 +11,11 @@ #include <typeinfo> #include <odb/forward.hxx> +#include <odb/traits.hxx> #include <odb/mysql/version.hxx> +#include <odb/mysql/forward.hxx> #include <odb/mysql/statements-base.hxx> -#include <odb/mysql/object-statements.hxx> -#include <odb/mysql/view-statements.hxx> #include <odb/details/shared-ptr.hxx> #include <odb/details/type-info.hxx> @@ -26,49 +26,19 @@ namespace odb { namespace mysql { - class connection; - class LIBODB_MYSQL_EXPORT statement_cache { public: - statement_cache (connection& conn) - : conn_ (conn) - { - } + statement_cache (connection& conn): conn_ (conn) {} template <typename T> - typename object_statements_selector<T>::type& - find_object () - { - typedef typename object_statements_selector<T>::type object_statements; - - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast<object_statements&> (*i->second); - - details::shared_ptr<object_statements> p ( - new (details::shared) object_statements (conn_)); + typename object_traits<T>::statements_type& + find_object (); - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } template <typename T> view_statements<T>& - find_view () - { - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast<view_statements<T>&> (*i->second); - - details::shared_ptr<view_statements<T> > p ( - new (details::shared) view_statements<T> (conn_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } + find_view (); private: typedef std::map<const std::type_info*, @@ -81,6 +51,8 @@ namespace odb } } +#include <odb/mysql/statement-cache.txx> + #include <odb/post.hxx> #endif // ODB_MYSQL_STATEMENT_CACHE_HXX diff --git a/odb/mysql/statement-cache.txx b/odb/mysql/statement-cache.txx new file mode 100644 index 0000000..3acc5fe --- /dev/null +++ b/odb/mysql/statement-cache.txx @@ -0,0 +1,43 @@ +// file : odb/mysql/statement-cache.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace mysql + { + template <typename T> + typename object_traits<T>::statements_type& statement_cache:: + find_object () + { + typedef typename object_traits<T>::statements_type statements_type; + + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast<statements_type&> (*i->second); + + details::shared_ptr<statements_type> p ( + new (details::shared) statements_type (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } + + template <typename T> + view_statements<T>& statement_cache:: + find_view () + { + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast<view_statements<T>&> (*i->second); + + details::shared_ptr<view_statements<T> > p ( + new (details::shared) view_statements<T> (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } + } +} diff --git a/odb/mysql/statement.cxx b/odb/mysql/statement.cxx index 6882a27..647ec96 100644 --- a/odb/mysql/statement.cxx +++ b/odb/mysql/statement.cxx @@ -259,7 +259,8 @@ namespace odb { case 0: { - rows_++; + if (next) + rows_++; return success; } case MYSQL_NO_DATA: @@ -269,7 +270,8 @@ namespace odb } case MYSQL_DATA_TRUNCATED: { - rows_++; + if (next) + rows_++; return truncated; } default: diff --git a/odb/mysql/view-result.hxx b/odb/mysql/view-result.hxx index f63e70b..ab59f03 100644 --- a/odb/mysql/view-result.hxx +++ b/odb/mysql/view-result.hxx @@ -9,11 +9,12 @@ #include <cstddef> // std::size_t +#include <odb/view-result.hxx> + #include <odb/details/shared-ptr.hxx> #include <odb/mysql/version.hxx> #include <odb/mysql/forward.hxx> // query, view_statements -#include <odb/mysql/result.hxx> #include <odb/mysql/statement.hxx> namespace odb @@ -32,12 +33,14 @@ namespace odb typedef typename base_type::pointer_type pointer_type; typedef typename base_type::pointer_traits pointer_traits; + typedef view_statements<view_type> statements_type; + virtual ~view_result_impl (); view_result_impl (const query&, details::shared_ptr<select_statement>, - view_statements<view_type>&); + statements_type&); virtual void load (view_type&); @@ -59,7 +62,7 @@ namespace odb private: details::shared_ptr<select_statement> statement_; - view_statements<view_type>& statements_; + statements_type& statements_; std::size_t count_; }; } diff --git a/odb/mysql/view-result.txx b/odb/mysql/view-result.txx index 6f1896d..f6060ea 100644 --- a/odb/mysql/view-result.txx +++ b/odb/mysql/view-result.txx @@ -23,7 +23,7 @@ namespace odb view_result_impl<T>:: view_result_impl (const query&, details::shared_ptr<select_statement> statement, - view_statements<view_type>& statements) + statements_type& statements) : base_type (statements.connection ().database ()), statement_ (statement), statements_ (statements), |