diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-23 16:48:02 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-23 16:48:02 +0200 |
commit | f039726a9d756dff85607d89bf4ba5fd1ef42edf (patch) | |
tree | a422c8d57733d29d2ecab92b39a0b3bef8d6fc1d | |
parent | d2fc34834f0b7660374f78d4409e24a165950c2c (diff) |
Polymorphic inheritance support
25 files changed, 1637 insertions, 575 deletions
diff --git a/odb/oracle/binding.hxx b/odb/oracle/binding.hxx index b4bafd7..8d4e670 100644 --- a/odb/oracle/binding.hxx +++ b/odb/oracle/binding.hxx @@ -24,6 +24,8 @@ namespace odb typedef oracle::bind bind_type; typedef oracle::change_callback change_callback_type; + binding (): bind (0), count (0), version (0), change_callback (0) {} + binding (bind_type* b, std::size_t n) : bind (b), count (n), version (0), change_callback (0) { diff --git a/odb/oracle/forward.hxx b/odb/oracle/forward.hxx index 72550ac..484fbfc 100644 --- a/odb/oracle/forward.hxx +++ b/odb/oracle/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/oracle/makefile b/odb/oracle/makefile index a5bb515..0a49b0f 100644 --- a/odb/oracle/makefile +++ b/odb/oracle/makefile @@ -4,24 +4,24 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make -cxx := \ -auto-descriptor.cxx \ -auto-handle.cxx \ -connection.cxx \ -connection-factory.cxx \ -database.cxx \ -error.cxx \ -exceptions.cxx \ -object-statements.cxx \ -oracle-types.cxx \ -query.cxx \ -query-const-expr.cxx \ -statement.cxx \ -statements-base.cxx \ -tracer.cxx \ -traits.cxx \ -transaction.cxx \ -transaction-impl.cxx \ +cxx := \ +auto-descriptor.cxx \ +auto-handle.cxx \ +connection.cxx \ +connection-factory.cxx \ +database.cxx \ +error.cxx \ +exceptions.cxx \ +oracle-types.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 \ details/number.cxx cli_tun := details/options.cli diff --git a/odb/oracle/no-id-object-result.hxx b/odb/oracle/no-id-object-result.hxx new file mode 100644 index 0000000..bd00b15 --- /dev/null +++ b/odb/oracle/no-id-object-result.hxx @@ -0,0 +1,78 @@ +// file : odb/oracle/no-id-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_ORACLE_NO_ID_OBJECT_RESULT_HXX +#define ODB_ORACLE_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/oracle/version.hxx> +#include <odb/oracle/forward.hxx> // query +#include <odb/oracle/statement.hxx> + +namespace odb +{ + namespace oracle + { + 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: + typedef oracle::change_callback change_callback_type; + + static void + change_callback (void* context, binding*); + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + bool use_copy_; + typename object_traits::image_type* image_copy_; + }; + } +} + +#include <odb/oracle/no-id-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_ORACLE_NO_ID_OBJECT_RESULT_HXX diff --git a/odb/oracle/no-id-object-result.txx b/odb/oracle/no-id-object-result.txx new file mode 100644 index 0000000..3d1f63b --- /dev/null +++ b/odb/oracle/no-id-object-result.txx @@ -0,0 +1,144 @@ +// file : odb/oracle/no-id-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include <odb/callback.hxx> +#include <odb/exceptions.hxx> // result_not_cached + +#include <odb/oracle/no-id-object-statements.hxx> + +namespace odb +{ + namespace oracle + { + template <typename T> + no_id_object_result_impl<T>:: + ~no_id_object_result_impl () + { + change_callback_type& cc (statements_.image ().change_callback_); + + if (cc.context == this) + { + cc.context = 0; + cc.callback = 0; + } + + delete image_copy_; + + 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), + use_copy_ (false), + image_copy_ (0) + { + } + + template <typename T> + void no_id_object_result_impl<T>:: + load (object_type& obj) + { + odb::database& db (this->database ()); + + object_traits::callback (db, obj, callback_event::pre_load); + + object_traits::init (obj, + use_copy_ ? *image_copy_ : statements_.image (), + &db); + + // If we are using a copy, make sure the callback information for + // LOB data also comes from the copy. + // + statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); + + object_traits::callback (db, obj, callback_event::post_load); + } + + template <typename T> + void no_id_object_result_impl<T>:: + next () + { + this->current (pointer_type ()); + + typename object_traits::image_type& im (statements_.image ()); + change_callback_type& cc (im.change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + use_copy_ = false; + + 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++; + } + + if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); + this->end_ = true; + } + else + { + cc.callback = &change_callback; + cc.context = this; + } + } + + template <typename T> + void no_id_object_result_impl<T>:: + cache () + { + } + + template <typename T> + std::size_t no_id_object_result_impl<T>:: + size () + { + throw result_not_cached (); + } + + template <typename T> + void no_id_object_result_impl<T>:: + change_callback (void* c, binding* b) + { + no_id_object_result_impl<T>* r ( + static_cast<no_id_object_result_impl<T>*> (c)); + + typename object_traits::image_type im (r->statements_.image ()); + + if (r->image_copy_ == 0) + r->image_copy_ = new typename object_traits::image_type (im); + else + *r->image_copy_ = im; + + // See comment in simple object_result for details on what's going + // on here. + // + im.version++; + if (b != 0) + b->version++; + + im.change_callback_.callback = 0; + im.change_callback_.context = 0; + + r->use_copy_ = true; + } + } +} diff --git a/odb/oracle/no-id-object-statements.hxx b/odb/oracle/no-id-object-statements.hxx new file mode 100644 index 0000000..0aa5cf0 --- /dev/null +++ b/odb/oracle/no-id-object-statements.hxx @@ -0,0 +1,133 @@ +// file : odb/oracle/no-id-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_ORACLE_NO_ID_OBJECT_STATEMENTS_HXX +#define ODB_ORACLE_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/oracle/version.hxx> +#include <odb/oracle/forward.hxx> +#include <odb/oracle/oracle-types.hxx> +#include <odb/oracle/binding.hxx> +#include <odb/oracle/statement.hxx> +#include <odb/oracle/statements-base.hxx> + +namespace odb +{ + namespace oracle + { + // + // 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 oracle::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_;} + + // 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 insert_column_count = + object_traits::column_count; + + static const std::size_t select_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_; + bind select_image_bind_[select_column_count]; + + // Insert binding. + // + std::size_t insert_image_version_; + binding insert_image_binding_; + bind insert_image_bind_[insert_column_count]; + + details::shared_ptr<insert_statement_type> persist_; + }; + } +} + +#include <odb/oracle/no-id-object-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_ORACLE_NO_ID_OBJECT_STATEMENTS_HXX diff --git a/odb/oracle/no-id-object-statements.txx b/odb/oracle/no-id-object-statements.txx new file mode 100644 index 0000000..b5576a0 --- /dev/null +++ b/odb/oracle/no-id-object-statements.txx @@ -0,0 +1,34 @@ +// file : odb/oracle/no-id-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include <cstring> // std::memset + +namespace odb +{ + namespace oracle + { + 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; + + select_image_binding_.change_callback = image_.change_callback (); + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + } + } +} diff --git a/odb/oracle/object-result.hxx b/odb/oracle/object-result.hxx deleted file mode 100644 index 94885e5..0000000 --- a/odb/oracle/object-result.hxx +++ /dev/null @@ -1,125 +0,0 @@ -// file : odb/oracle/object-result.hxx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_ORACLE_OBJECT_RESULT_HXX -#define ODB_ORACLE_OBJECT_RESULT_HXX - -#include <odb/pre.hxx> - -#include <cstddef> // std::size_t - -#include <odb/details/shared-ptr.hxx> - -#include <odb/oracle/version.hxx> -#include <odb/oracle/forward.hxx> // query, object_statements -#include <odb/oracle/result.hxx> -#include <odb/oracle/statement.hxx> - -namespace odb -{ - namespace oracle - { - 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: - typedef oracle::change_callback change_callback_type; - - static void - change_callback (void* context); - - private: - details::shared_ptr<select_statement> statement_; - object_statements<object_type>& statements_; - bool use_copy_; - typename object_traits::image_type* image_copy_; - }; - - 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: - typedef oracle::change_callback change_callback_type; - - static void - change_callback (void* context); - - private: - details::shared_ptr<select_statement> statement_; - object_statements_no_id<object_type>& statements_; - bool use_copy_; - typename object_traits::image_type* image_copy_; - }; - } -} - -#include <odb/oracle/object-result.txx> - -#include <odb/post.hxx> - -#endif // ODB_ORACLE_OBJECT_RESULT_HXX diff --git a/odb/oracle/oracle-types.hxx b/odb/oracle/oracle-types.hxx index 5b87220..693be5c 100644 --- a/odb/oracle/oracle-types.hxx +++ b/odb/oracle/oracle-types.hxx @@ -10,6 +10,7 @@ #include <odb/details/buffer.hxx> #include <odb/oracle/version.hxx> +#include <odb/oracle/forward.hxx> // binding #include <odb/oracle/oracle-fwd.hxx> #include <odb/oracle/details/export.hxx> @@ -131,7 +132,7 @@ namespace odb { change_callback (): callback (0), context (0) {}; - void (*callback) (void*); + void (*callback) (void*, binding*); void* context; }; diff --git a/odb/oracle/polymorphic-object-result.hxx b/odb/oracle/polymorphic-object-result.hxx new file mode 100644 index 0000000..2137c1d --- /dev/null +++ b/odb/oracle/polymorphic-object-result.hxx @@ -0,0 +1,91 @@ +// file : odb/oracle/polymorphic-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_ORACLE_POLYMORPHIC_OBJECT_RESULT_HXX +#define ODB_ORACLE_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/oracle/version.hxx> +#include <odb/oracle/forward.hxx> // query +#include <odb/oracle/statement.hxx> + +namespace odb +{ + namespace oracle + { + 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::image_type image_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: + typedef oracle::change_callback change_callback_type; + + static void + change_callback (void* context, binding*); + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + bool use_copy_; + image_type* image_copy_; + }; + } +} + +#include <odb/oracle/polymorphic-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_ORACLE_POLYMORPHIC_OBJECT_RESULT_HXX diff --git a/odb/oracle/polymorphic-object-result.txx b/odb/oracle/polymorphic-object-result.txx new file mode 100644 index 0000000..f371258 --- /dev/null +++ b/odb/oracle/polymorphic-object-result.txx @@ -0,0 +1,322 @@ +// file : odb/oracle/polymorphic-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include <cassert> + +#include <odb/callback.hxx> +#include <odb/cache-traits.hxx> +#include <odb/exceptions.hxx> // result_not_cached + +#include <odb/oracle/polymorphic-object-statements.hxx> + +namespace odb +{ + namespace oracle + { + template <typename T> + polymorphic_object_result_impl<T>:: + ~polymorphic_object_result_impl () + { + change_callback_type& cc ( + statements_.root_statements ().image ().change_callback_); + + if (cc.context == this) + { + cc.context = 0; + cc.callback = 0; + } + + if (image_copy_ != 0) + object_traits::free_image (image_copy_); + + 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), + use_copy_ (false), + image_copy_ (0) + { + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + load (object_type* pobj, bool) + { + 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 ()); + image_type& i (use_copy_ ? *image_copy_ : statements_.image ()); + typename root_traits::image_type& ri ( + use_copy_ ? object_traits::root_image (i) : 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)); + + // 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); + + // If we are using a copy, make sure the callback information for + // LOB data also comes from the copy. + // + statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); + + // 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 () + { + typename root_traits::image_type& i ( + use_copy_ + ? object_traits::root_image (*image_copy_) + : statements_.root_statements ().image ()); + + return root_traits::id (i); + } + + template <typename T> + typename polymorphic_object_result_impl<T>::discriminator_type + polymorphic_object_result_impl<T>:: + load_discriminator () + { + typename root_traits::image_type& i ( + use_copy_ + ? object_traits::root_image (*image_copy_) + : statements_.root_statements ().image ()); + + return root_traits::discriminator (i); + } + + template <typename T, typename R> + struct polymorphic_image_rebind + { + // Derived type version. + // + typedef object_traits<T> traits; + + static void + 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 ()); + } + } + + static void + inc_version (typename traits::image_type& i) + { + polymorphic_image_rebind< + typename traits::base_type, + typename traits::root_type>::inc_version (*i.base); + + i.version++; + } + }; + + template <typename R> + struct polymorphic_image_rebind<R, R> + { + // Root type version. + // + typedef object_traits<R> traits; + + static void + 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++; + } + } + + static void + inc_version (typename traits::image_type& i) + { + i.version++; + } + }; + + template <typename T> + void polymorphic_object_result_impl<T>:: + next () + { + this->current (pointer_type ()); + + change_callback_type& cc ( + statements_.root_statements ().image ().change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + use_copy_ = false; + polymorphic_image_rebind<object_type, root_type>::rebind (statements_); + + if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); + this->end_ = true; + } + else + { + cc.callback = &change_callback; + cc.context = this; + } + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + cache () + { + } + + template <typename T> + std::size_t polymorphic_object_result_impl<T>:: + size () + { + throw result_not_cached (); + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + change_callback (void* c, binding* b) + { + polymorphic_object_result_impl<T>* r ( + static_cast<polymorphic_object_result_impl<T>*> (c)); + image_type& im (r->statements_.image ()); + + if (r->image_copy_ == 0) + r->image_copy_ = object_traits::clone_image (im); + else + object_traits::copy_image (*r->image_copy_, im); + + typename root_traits::image_type& rim ( + r->statements_.root_statements ().image ()); + + // See comment in simple object_result for details on what's going + // on here. + // + polymorphic_image_rebind<object_type, root_type>::inc_version (im); + if (b != 0) + b->version++; + + rim.change_callback_.callback = 0; + rim.change_callback_.context = 0; + + r->use_copy_ = true; + } + } +} diff --git a/odb/oracle/polymorphic-object-statements.hxx b/odb/oracle/polymorphic-object-statements.hxx new file mode 100644 index 0000000..0b8ddcb --- /dev/null +++ b/odb/oracle/polymorphic-object-statements.hxx @@ -0,0 +1,426 @@ +// file : odb/oracle/polymorphic-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_ORACLE_POLYMORPHIC_OBJECT_STATEMENTS_HXX +#define ODB_ORACLE_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/oracle/version.hxx> +#include <odb/oracle/forward.hxx> +#include <odb/oracle/oracle-types.hxx> +#include <odb/oracle/binding.hxx> +#include <odb/oracle/statement.hxx> +#include <odb/oracle/statements-base.hxx> +#include <odb/oracle/simple-object-statements.hxx> + +namespace odb +{ + namespace oracle + { + // + // 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_;} + + // 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_, + 0)); // No LOB prefetch (discriminator cannot be LOB). + + 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_; + bind discriminator_image_bind_[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_; + 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 oracle::insert_statement insert_statement_type; + typedef oracle::select_statement select_statement_type; + typedef oracle::update_statement update_statement_type; + typedef oracle::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]; + } + + // 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], + 4096)); // Hardcode a 4kB LOB prefetch size. + + 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_)); + + 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 ())); + + 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]; + bind select_image_bind_[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_; + 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_; + 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/oracle/polymorphic-object-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_ORACLE_POLYMORPHIC_OBJECT_STATEMENTS_HXX diff --git a/odb/oracle/polymorphic-object-statements.txx b/odb/oracle/polymorphic-object-statements.txx new file mode 100644 index 0000000..e997662 --- /dev/null +++ b/odb/oracle/polymorphic-object-statements.txx @@ -0,0 +1,133 @@ +// file : odb/oracle/polymorphic-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include <cstring> // std::memset + +#include <odb/callback.hxx> +#include <odb/exceptions.hxx> + +#include <odb/oracle/connection.hxx> +#include <odb/oracle/transaction.hxx> +#include <odb/oracle/statement-cache.hxx> + +namespace odb +{ + namespace oracle + { + // + // 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_)); + } + + // + // 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]; + select_image_bindings_[i].change_callback = 0; + } + + // Statements other than the first one (which goes all the way to + // the root) can never override the image because they are used to + // load up the dynamic part of the object only after the static + // part has been loaded (and triggered the callback if necessary). + // + select_image_bindings_[0].change_callback = + root_statements_.image ().change_callback (); + + 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_)); + } + + 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); + sts.find_[0]->stream_result (); + 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/oracle/result.hxx b/odb/oracle/result.hxx deleted file mode 100644 index ff89b30..0000000 --- a/odb/oracle/result.hxx +++ /dev/null @@ -1,25 +0,0 @@ -// file : odb/oracle/result.hxx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_ORACLE_RESULT_HXX -#define ODB_ORACLE_RESULT_HXX - -#include <odb/pre.hxx> - -#include <odb/traits.hxx> -#include <odb/result.hxx> - -#include <odb/oracle/version.hxx> -#include <odb/oracle/forward.hxx> - -#include <odb/post.hxx> - -#endif // ODB_ORACLE_RESULT_HXX - -// Include result specializations so that the user code only needs -// to include this header. -// - -#include <odb/oracle/object-result.hxx> -#include <odb/oracle/view-result.hxx> diff --git a/odb/oracle/simple-object-result.hxx b/odb/oracle/simple-object-result.hxx new file mode 100644 index 0000000..cbfe8c5 --- /dev/null +++ b/odb/oracle/simple-object-result.hxx @@ -0,0 +1,82 @@ +// file : odb/oracle/simple-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_ORACLE_SIMPLE_OBJECT_RESULT_HXX +#define ODB_ORACLE_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/oracle/version.hxx> +#include <odb/oracle/forward.hxx> // query +#include <odb/oracle/statement.hxx> + +namespace odb +{ + namespace oracle + { + 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: + typedef oracle::change_callback change_callback_type; + + static void + change_callback (void* context, binding*); + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + bool use_copy_; + typename object_traits::image_type* image_copy_; + }; + } +} + +#include <odb/oracle/simple-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_ORACLE_SIMPLE_OBJECT_RESULT_HXX diff --git a/odb/oracle/object-result.txx b/odb/oracle/simple-object-result.txx index ddc9783..ec0d1f5 100644 --- a/odb/oracle/object-result.txx +++ b/odb/oracle/simple-object-result.txx @@ -1,22 +1,18 @@ -// file : odb/oracle/object-result.txx +// file : odb/oracle/simple-object-result.txx // copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC // license : ODB NCUEL; see accompanying LICENSE file #include <cassert> #include <odb/callback.hxx> -#include <odb/exceptions.hxx> +#include <odb/exceptions.hxx> // result_not_cached -#include <odb/oracle/object-statements.hxx> +#include <odb/oracle/simple-object-statements.hxx> namespace odb { namespace oracle { - // - // object_result_impl - // - template <typename T> object_result_impl<T>:: ~object_result_impl () @@ -39,7 +35,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), @@ -55,7 +51,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); @@ -153,7 +149,7 @@ namespace odb template <typename T> void object_result_impl<T>:: - change_callback (void* c) + change_callback (void* c, binding* b) { object_result_impl<T>* r (static_cast<object_result_impl<T>*> (c)); typename object_traits::image_type& im (r->statements_.image ()); @@ -163,144 +159,18 @@ namespace odb else *r->image_copy_ = im; - // Increment binding version since we may have "stolen" some - // descriptors (LOB, date-time) from the image. Re-bind will - // reallocate them and update the binding. - // - r->statements_.select_image_binding ().version++; - - im.change_callback_.callback = 0; - im.change_callback_.context = 0; - - r->use_copy_ = true; - } - - // - // object_result_impl_no_id - // - - template <typename T> - object_result_impl_no_id<T>:: - ~object_result_impl_no_id () - { - change_callback_type& cc (statements_.image ().change_callback_); - - if (cc.context == this) - { - cc.context = 0; - cc.callback = 0; - } - - delete image_copy_; - - 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), - use_copy_ (false), - image_copy_ (0) - { - } - - template <typename T> - void object_result_impl_no_id<T>:: - load (object_type& obj) - { - odb::database& db (this->database ()); - - object_traits::callback (db, obj, callback_event::pre_load); - - object_traits::init (obj, - use_copy_ ? *image_copy_ : statements_.image (), - &db); - - // If we are using a copy, make sure the callback information for - // LOB data also comes from the copy. + // Increment image version since we may have "stolen" descriptors + // (LOB, date-time) from the image. This will trigger re-bind which + // will reallocate them and update the binding. In case this callback + // was triggeted as part of a select statement fetch, then it is too + // late to update the image version and we also need to update the + // image binding. // - statement_->stream_result ( - use_copy_ ? &statements_.image () : 0, - use_copy_ ? image_copy_ : 0); - - object_traits::callback (db, obj, callback_event::post_load); - } - - template <typename T> - void object_result_impl_no_id<T>:: - next () - { - this->current (pointer_type ()); - - typename object_traits::image_type& im (statements_.image ()); - change_callback_type& cc (im.change_callback_); - - if (cc.context == this) - { - cc.callback = 0; - cc.context = 0; - } - - use_copy_ = false; - - 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++; - } - - if (statement_->fetch () == select_statement::no_data) - { - statement_->free_result (); - this->end_ = true; - } - else - { - cc.callback = &change_callback; - cc.context = this; - } - } - - template <typename T> - void object_result_impl_no_id<T>:: - cache () - { - } - - template <typename T> - std::size_t object_result_impl_no_id<T>:: - size () - { - throw result_not_cached (); - } - - template <typename T> - void object_result_impl_no_id<T>:: - change_callback (void* c) - { - object_result_impl_no_id<T>* r ( - static_cast<object_result_impl_no_id<T>*> (c)); - - typename object_traits::image_type im (r->statements_.image ()); - - if (r->image_copy_ == 0) - r->image_copy_ = new typename object_traits::image_type (im); - else - *r->image_copy_ = im; - - // Increment binding version since we may have "stolen" some - // descriptors (LOB, date-time) from the image. Re-bind will - // reallocate them and update the binding. + // @@ Would be good to only do this if we actually have descriptors. // - r->statements_.select_image_binding ().version++; + im.version++; + if (b != 0) + b->version++; im.change_callback_.callback = 0; im.change_callback_.context = 0; diff --git a/odb/oracle/object-statements.cxx b/odb/oracle/simple-object-statements.cxx index 8000f48..51be556 100644 --- a/odb/oracle/object-statements.cxx +++ b/odb/oracle/simple-object-statements.cxx @@ -1,8 +1,8 @@ -// file : odb/oracle/object-statements.cxx +// file : odb/oracle/simple-object-statements.cxx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : ODB NCUEL; see accompanying LICENSE file -#include <odb/oracle/object-statements.hxx> +#include <odb/oracle/simple-object-statements.hxx> namespace odb { diff --git a/odb/oracle/object-statements.hxx b/odb/oracle/simple-object-statements.hxx index 2fb829d..2a007b2 100644 --- a/odb/oracle/object-statements.hxx +++ b/odb/oracle/simple-object-statements.hxx @@ -1,9 +1,9 @@ -// file : odb/oracle/object-statements.hxx +// file : odb/oracle/simple-object-statements.hxx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : ODB NCUEL; see accompanying LICENSE file -#ifndef ODB_ORACLE_OBJECT_STATEMENTS_HXX -#define ODB_ORACLE_OBJECT_STATEMENTS_HXX +#ifndef ODB_ORACLE_SIMPLE_OBJECT_STATEMENTS_HXX +#define ODB_ORACLE_SIMPLE_OBJECT_STATEMENTS_HXX #include <odb/pre.hxx> @@ -18,7 +18,9 @@ #include <odb/details/shared-ptr.hxx> #include <odb/oracle/version.hxx> +#include <odb/oracle/forward.hxx> #include <odb/oracle/oracle-types.hxx> +#include <odb/oracle/binding.hxx> #include <odb/oracle/statement.hxx> #include <odb/oracle/statements-base.hxx> @@ -28,24 +30,6 @@ namespace odb { namespace oracle { - 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 @@ -371,18 +361,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 @@ -404,6 +383,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_; @@ -454,17 +444,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; @@ -492,111 +486,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 oracle::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_;} - - // 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 insert_column_count = - object_traits::column_count; - - static const std::size_t select_column_count = - object_traits::column_count; - - private: - image_type image_; - - // Select binding. - // - std::size_t select_image_version_; - binding select_image_binding_; - bind select_image_bind_[select_column_count]; - - // Insert binding. - // - std::size_t insert_image_version_; - binding insert_image_binding_; - bind insert_image_bind_[insert_column_count]; - - details::shared_ptr<insert_statement_type> persist_; - }; } } -#include <odb/oracle/object-statements.ixx> -#include <odb/oracle/object-statements.txx> +#include <odb/oracle/simple-object-statements.ixx> +#include <odb/oracle/simple-object-statements.txx> #include <odb/post.hxx> -#endif // ODB_ORACLE_OBJECT_STATEMENTS_HXX +#endif // ODB_ORACLE_SIMPLE_OBJECT_STATEMENTS_HXX diff --git a/odb/oracle/object-statements.ixx b/odb/oracle/simple-object-statements.ixx index e4eb6d7..3e399f6 100644 --- a/odb/oracle/object-statements.ixx +++ b/odb/oracle/simple-object-statements.ixx @@ -1,4 +1,4 @@ -// file : odb/oracle/object-statements.ixx +// file : odb/oracle/simple-object-statements.ixx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : ODB NCUEL; see accompanying LICENSE file @@ -6,7 +6,7 @@ namespace odb { namespace oracle { - // + // // auto_unlock // inline object_statements_base::auto_unlock:: diff --git a/odb/oracle/object-statements.txx b/odb/oracle/simple-object-statements.txx index 65fcf46..83aff45 100644 --- a/odb/oracle/object-statements.txx +++ b/odb/oracle/simple-object-statements.txx @@ -1,8 +1,7 @@ -// file : odb/oracle/object-statements.txx +// file : odb/oracle/simple-object-statements.txx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : ODB NCUEL; see accompanying LICENSE file -#include <cstddef> // std::size_t #include <cstring> // std::memset #include <odb/session.hxx> @@ -82,37 +81,42 @@ 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); - find_->stream_result (); - 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); + find_->stream_result (); + 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 (); } @@ -129,38 +133,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_no_id - // - - 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; - - select_image_binding_.change_callback = image_.change_callback (); - - std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); - std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); - } } } diff --git a/odb/oracle/statement-cache.hxx b/odb/oracle/statement-cache.hxx index 549251a..d4d65ca 100644 --- a/odb/oracle/statement-cache.hxx +++ b/odb/oracle/statement-cache.hxx @@ -11,11 +11,11 @@ #include <typeinfo> #include <odb/forward.hxx> +#include <odb/traits.hxx> #include <odb/oracle/version.hxx> +#include <odb/oracle/forward.hxx> #include <odb/oracle/statements-base.hxx> -#include <odb/oracle/object-statements.hxx> -#include <odb/oracle/view-statements.hxx> #include <odb/details/shared-ptr.hxx> #include <odb/details/type-info.hxx> @@ -26,49 +26,18 @@ namespace odb { namespace oracle { - class connection; - class LIBODB_ORACLE_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_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } + typename object_traits<T>::statements_type& + find_object (); 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 +50,8 @@ namespace odb } } +#include <odb/oracle/statement-cache.txx> + #include <odb/post.hxx> #endif // ODB_ORACLE_STATEMENT_CACHE_HXX diff --git a/odb/oracle/statement-cache.txx b/odb/oracle/statement-cache.txx new file mode 100644 index 0000000..6f62b8f --- /dev/null +++ b/odb/oracle/statement-cache.txx @@ -0,0 +1,43 @@ +// file : odb/oracle/statement-cache.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace oracle + { + 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/oracle/statement.cxx b/odb/oracle/statement.cxx index 8cf2452..309a5ce 100644 --- a/odb/oracle/statement.cxx +++ b/odb/oracle/statement.cxx @@ -1389,7 +1389,7 @@ namespace odb change_callback* cc (result_.change_callback); if (cc != 0 && cc->callback != 0) - (cc->callback) (cc->context); + (cc->callback) (cc->context, &result_); if (result_version_ != result_.version) { diff --git a/odb/oracle/view-result.hxx b/odb/oracle/view-result.hxx index 3eb4e2a..f44911a 100644 --- a/odb/oracle/view-result.hxx +++ b/odb/oracle/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/oracle/version.hxx> #include <odb/oracle/forward.hxx> // query, view_statements -#include <odb/oracle/result.hxx> #include <odb/oracle/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&); @@ -57,11 +60,11 @@ namespace odb typedef oracle::change_callback change_callback_type; static void - change_callback (void* context); + change_callback (void* context, binding*); private: details::shared_ptr<select_statement> statement_; - view_statements<view_type>& statements_; + statements_type& statements_; bool use_copy_; typename view_traits::image_type* image_copy_; }; diff --git a/odb/oracle/view-result.txx b/odb/oracle/view-result.txx index 64d949e..dc5cd6a 100644 --- a/odb/oracle/view-result.txx +++ b/odb/oracle/view-result.txx @@ -33,7 +33,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), @@ -116,7 +116,7 @@ namespace odb template <typename T> void view_result_impl<T>:: - change_callback (void* c) + change_callback (void* c, binding*) { view_result_impl<T>* r (static_cast<view_result_impl<T>*> (c)); @@ -127,9 +127,10 @@ namespace odb else *r->image_copy_ = im; - // Increment binding version since we may have "stolen" some - // descriptors (LOB, date-time) from the image. Re-bind will - // reallocate them and update the binding. + // See comment in simple object_result for details on what's going + // on here. Except for views, there is nothing else other than the + // select binding, so just incrementing the binding version will + // be sufficient. // r->statements_.image_binding ().version++; |