From f039726a9d756dff85607d89bf4ba5fd1ef42edf Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 23 Apr 2012 16:48:02 +0200 Subject: Polymorphic inheritance support --- odb/oracle/binding.hxx | 2 + odb/oracle/forward.hxx | 8 +- odb/oracle/makefile | 36 +- odb/oracle/no-id-object-result.hxx | 78 ++++ odb/oracle/no-id-object-result.txx | 144 +++++++ odb/oracle/no-id-object-statements.hxx | 133 ++++++ odb/oracle/no-id-object-statements.txx | 34 ++ odb/oracle/object-result.hxx | 125 ------ odb/oracle/object-result.txx | 311 -------------- odb/oracle/object-statements.cxx | 16 - odb/oracle/object-statements.hxx | 602 --------------------------- odb/oracle/object-statements.ixx | 69 --- odb/oracle/object-statements.txx | 166 -------- odb/oracle/oracle-types.hxx | 3 +- odb/oracle/polymorphic-object-result.hxx | 91 ++++ odb/oracle/polymorphic-object-result.txx | 322 ++++++++++++++ odb/oracle/polymorphic-object-statements.hxx | 426 +++++++++++++++++++ odb/oracle/polymorphic-object-statements.txx | 133 ++++++ odb/oracle/result.hxx | 25 -- odb/oracle/simple-object-result.hxx | 82 ++++ odb/oracle/simple-object-result.txx | 181 ++++++++ odb/oracle/simple-object-statements.cxx | 16 + odb/oracle/simple-object-statements.hxx | 497 ++++++++++++++++++++++ odb/oracle/simple-object-statements.ixx | 69 +++ odb/oracle/simple-object-statements.txx | 143 +++++++ odb/oracle/statement-cache.hxx | 45 +- odb/oracle/statement-cache.txx | 43 ++ odb/oracle/statement.cxx | 2 +- odb/oracle/view-result.hxx | 11 +- odb/oracle/view-result.txx | 11 +- 30 files changed, 2443 insertions(+), 1381 deletions(-) create mode 100644 odb/oracle/no-id-object-result.hxx create mode 100644 odb/oracle/no-id-object-result.txx create mode 100644 odb/oracle/no-id-object-statements.hxx create mode 100644 odb/oracle/no-id-object-statements.txx delete mode 100644 odb/oracle/object-result.hxx delete mode 100644 odb/oracle/object-result.txx delete mode 100644 odb/oracle/object-statements.cxx delete mode 100644 odb/oracle/object-statements.hxx delete mode 100644 odb/oracle/object-statements.ixx delete mode 100644 odb/oracle/object-statements.txx create mode 100644 odb/oracle/polymorphic-object-result.hxx create mode 100644 odb/oracle/polymorphic-object-result.txx create mode 100644 odb/oracle/polymorphic-object-statements.hxx create mode 100644 odb/oracle/polymorphic-object-statements.txx delete mode 100644 odb/oracle/result.hxx create mode 100644 odb/oracle/simple-object-result.hxx create mode 100644 odb/oracle/simple-object-result.txx create mode 100644 odb/oracle/simple-object-statements.cxx create mode 100644 odb/oracle/simple-object-statements.hxx create mode 100644 odb/oracle/simple-object-statements.ixx create mode 100644 odb/oracle/simple-object-statements.txx create mode 100644 odb/oracle/statement-cache.txx 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 - class object_statements_no_id; + class polymorphic_root_object_statements; + + template + class polymorphic_derived_object_statements; + + template + class no_id_object_statements; template 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 + +#include // std::size_t + +#include + +#include + +#include +#include // query +#include + +namespace odb +{ + namespace oracle + { + template + class no_id_object_result_impl: public odb::no_id_object_result_impl + { + public: + typedef odb::no_id_object_result_impl 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, + 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 statement_; + statements_type& statements_; + bool use_copy_; + typename object_traits::image_type* image_copy_; + }; + } +} + +#include + +#include + +#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 +#include // result_not_cached + +#include + +namespace odb +{ + namespace oracle + { + template + no_id_object_result_impl:: + ~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 + no_id_object_result_impl:: + no_id_object_result_impl (const query&, + details::shared_ptr statement, + statements_type& statements) + : base_type (statements.connection ().database ()), + statement_ (statement), + statements_ (statements), + use_copy_ (false), + image_copy_ (0) + { + } + + template + void no_id_object_result_impl:: + 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 + void no_id_object_result_impl:: + 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 + void no_id_object_result_impl:: + cache () + { + } + + template + std::size_t no_id_object_result_impl:: + size () + { + throw result_not_cached (); + } + + template + void no_id_object_result_impl:: + change_callback (void* c, binding* b) + { + no_id_object_result_impl* r ( + static_cast*> (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 + +#include // std::size_t + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace odb +{ + namespace oracle + { + // + // Implementation for objects without object id. + // + + template + class no_id_object_statements: public statements_base + { + public: + typedef T object_type; + typedef odb::object_traits 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 persist_; + }; + } +} + +#include + +#include + +#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 // std::memset + +namespace odb +{ + namespace oracle + { + template + no_id_object_statements:: + ~no_id_object_statements () + { + } + + template + no_id_object_statements:: + 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 - -#include // std::size_t - -#include - -#include -#include // query, object_statements -#include -#include - -namespace odb -{ - namespace oracle - { - template - class object_result_impl: public odb::object_result_impl - { - public: - typedef odb::object_result_impl 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, - object_statements&); - - 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 statement_; - object_statements& statements_; - bool use_copy_; - typename object_traits::image_type* image_copy_; - }; - - template - class object_result_impl_no_id: public odb::object_result_impl_no_id - { - public: - typedef odb::object_result_impl_no_id 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, - object_statements_no_id&); - - 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 statement_; - object_statements_no_id& statements_; - bool use_copy_; - typename object_traits::image_type* image_copy_; - }; - } -} - -#include - -#include - -#endif // ODB_ORACLE_OBJECT_RESULT_HXX diff --git a/odb/oracle/object-result.txx b/odb/oracle/object-result.txx deleted file mode 100644 index ddc9783..0000000 --- a/odb/oracle/object-result.txx +++ /dev/null @@ -1,311 +0,0 @@ -// file : odb/oracle/object-result.txx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -#include -#include - -#include - -namespace odb -{ - namespace oracle - { - // - // object_result_impl - // - - template - object_result_impl:: - ~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 - object_result_impl:: - object_result_impl (const query&, - details::shared_ptr statement, - object_statements& statements) - : base_type (statements.connection ().database ()), - statement_ (statement), - statements_ (statements), - use_copy_ (false), - image_copy_ (0) - { - } - - template - void object_result_impl:: - load (object_type& obj, bool) - { - // This is a top-level call so the statements cannot be locked. - // - assert (!statements_.locked ()); - typename object_statements::auto_lock l (statements_); - - odb::database& db (this->database ()); - object_traits::callback (db, obj, callback_event::pre_load); - - typename object_traits::image_type& i ( - use_copy_ ? *image_copy_ : statements_.image ()); - - object_traits::init (obj, 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, etc). - // - typename object_traits::id_image_type& idi (statements_.id_image ()); - object_traits::init (idi, object_traits::id (i)); - - 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_, obj); - statements_.load_delayed (); - l.unlock (); - object_traits::callback (db, obj, callback_event::post_load); - } - - template - typename object_result_impl::id_type - object_result_impl:: - load_id () - { - return object_traits::id ( - use_copy_ ? *image_copy_ : statements_.image ()); - } - - template - void object_result_impl:: - 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 - void object_result_impl:: - cache () - { - } - - template - std::size_t object_result_impl:: - size () - { - throw result_not_cached (); - } - - template - void object_result_impl:: - change_callback (void* c) - { - object_result_impl* r (static_cast*> (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. - // - 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 - object_result_impl_no_id:: - ~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 - object_result_impl_no_id:: - object_result_impl_no_id (const query&, - details::shared_ptr statement, - object_statements_no_id& statements) - : base_type (statements.connection ().database ()), - statement_ (statement), - statements_ (statements), - use_copy_ (false), - image_copy_ (0) - { - } - - template - void object_result_impl_no_id:: - 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 - void object_result_impl_no_id:: - 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 - void object_result_impl_no_id:: - cache () - { - } - - template - std::size_t object_result_impl_no_id:: - size () - { - throw result_not_cached (); - } - - template - void object_result_impl_no_id:: - change_callback (void* c) - { - object_result_impl_no_id* r ( - static_cast*> (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. - // - r->statements_.select_image_binding ().version++; - - im.change_callback_.callback = 0; - im.change_callback_.context = 0; - - r->use_copy_ = true; - } - } -} diff --git a/odb/oracle/object-statements.cxx b/odb/oracle/object-statements.cxx deleted file mode 100644 index 8000f48..0000000 --- a/odb/oracle/object-statements.cxx +++ /dev/null @@ -1,16 +0,0 @@ -// file : odb/oracle/object-statements.cxx -// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -namespace odb -{ - namespace oracle - { - object_statements_base:: - ~object_statements_base () - { - } - } -} diff --git a/odb/oracle/object-statements.hxx b/odb/oracle/object-statements.hxx deleted file mode 100644 index 2fb829d..0000000 --- a/odb/oracle/object-statements.hxx +++ /dev/null @@ -1,602 +0,0 @@ -// file : odb/oracle/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 - -#include - -#include -#include -#include // std::size_t - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -namespace odb -{ - namespace oracle - { - template - class object_statements; - - template - class object_statements_no_id; - - template ::id_type> - struct object_statements_selector - { - typedef object_statements type; - }; - - template - struct object_statements_selector - { - typedef object_statements_no_id type; - }; - - // - // Implementation for objects with object id. - // - - class LIBODB_ORACLE_EXPORT object_statements_base: public statements_base - { - // Locking. - // - public: - void - lock () - { - assert (!locked_); - locked_ = true; - } - - void - unlock () - { - assert (locked_); - locked_ = false; - } - - bool - locked () const - { - return locked_; - } - - public: - virtual - ~object_statements_base (); - - protected: - object_statements_base (connection_type& conn) - : statements_base (conn), locked_ (false) - { - } - - struct auto_unlock - { - // Unlocks the statement on construction and re-locks it on - // destruction. - // - auto_unlock (object_statements_base&); - ~auto_unlock (); - - private: - auto_unlock (const auto_unlock&); - auto_unlock& operator= (const auto_unlock&); - - private: - object_statements_base& s_; - }; - - protected: - bool locked_; - }; - - template - struct optimistic_data; - - template - struct optimistic_data - { - typedef T object_type; - typedef odb::object_traits object_traits; - - optimistic_data (bind*); - - // The id + optimistic column binding. - // - std::size_t id_image_version_; - binding id_image_binding_; - - details::shared_ptr erase_; - }; - - template - struct optimistic_data - { - optimistic_data (bind*) {} - }; - - template - class object_statements: public object_statements_base - { - public: - typedef T object_type; - typedef odb::object_traits object_traits; - typedef typename object_traits::id_type id_type; - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::image_type image_type; - typedef typename object_traits::id_image_type id_image_type; - - typedef pointer_cache_traits object_cache_traits; - - 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; - - // Automatic lock. - // - struct auto_lock - { - // Lock the statements unless they are already locked in which - // case subsequent calls to locked() will return false. - // - auto_lock (object_statements&); - - // Unlock the statements if we are holding the lock and clear - // the delayed loads. This should only happen in case an - // exception is thrown. In normal circumstances, the user - // should call unlock() explicitly. - // - ~auto_lock (); - - // Return true if this auto_lock instance holds the lock. - // - bool - locked () const; - - // Unlock the statements. - // - void - unlock (); - - private: - auto_lock (const auto_lock&); - auto_lock& operator= (const auto_lock&); - - private: - object_statements& s_; - bool locked_; - }; - - public: - object_statements (connection_type&); - - virtual - ~object_statements (); - - // Delayed loading. - // - void - delay_load (const id_type& id, - object_type& obj, - const typename object_cache_traits::position_type& p) - { - delayed_.push_back (delayed_load (id, obj, p)); - } - - void - load_delayed () - { - assert (locked ()); - - if (!delayed_.empty ()) - load_delayed_ (); - } - - void - clear_delayed () - { - if (!delayed_.empty ()) - clear_delayed_ (); - } - - // Object image. - // - image_type& - 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_;} - - // 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_image_version () const { return update_id_image_version_;} - - void - update_id_image_version (std::size_t v) {update_id_image_version_ = v;} - - binding& - update_image_binding () {return update_image_binding_;} - - // Select binding. - // - 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_;} - - // Object id image and binding. - // - id_image_type& - id_image () {return id_image_;} - - std::size_t - id_image_version () const {return id_image_version_;} - - void - id_image_version (std::size_t v) {id_image_version_ = v;} - - binding& - id_image_binding () {return id_image_binding_;} - - // Optimistic id + managed column image binding. - // - std::size_t - optimistic_id_image_version () const {return od_.id_image_version_;} - - void - optimistic_id_image_version (std::size_t v) {od_.id_image_version_ = v;} - - binding& - optimistic_id_image_binding () {return od_.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_, - object_traits::auto_id)); - - return *persist_; - } - - select_statement_type& - find_statement () - { - if (find_ == 0) - find_.reset ( - new (details::shared) select_statement_type ( - conn_, - object_traits::find_statement, - id_image_binding_, - select_image_binding_, - 4096)); // Hardcode a 4kB LOB prefetch size. - - return *find_; - } - - 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, - id_image_binding_)); - - return *erase_; - } - - delete_statement_type& - optimistic_erase_statement () - { - if (od_.erase_ == 0) - { - od_.erase_.reset ( - new (details::shared) delete_statement_type ( - conn_, - object_traits::optimistic_erase_statement, - od_.id_image_binding_)); - } - - return *od_.erase_; - } - - // Container statement cache. - // - container_statement_cache_type& - container_statment_cache () - { - return container_statement_cache_; - } - - private: - object_statements (const object_statements&); - object_statements& operator= (const object_statements&); - - private: - void - load_delayed_ (); - - void - clear_delayed_ (); - - private: - // select = total - // insert = total - inverse - managed_optimistic - // update = total - inverse - managed_optimistic - id - readonly - // - static const std::size_t select_column_count = - object_traits::column_count; - - static const std::size_t insert_column_count = - object_traits::column_count - object_traits::inverse_column_count - - object_traits::managed_optimistic_column_count; - - static const std::size_t update_column_count = insert_column_count - - object_traits::id_column_count - object_traits::readonly_column_count; - - static const std::size_t id_column_count = - object_traits::id_column_count; - - static const std::size_t managed_optimistic_column_count = - object_traits::managed_optimistic_column_count; - - private: - container_statement_cache_type container_statement_cache_; - - 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]; - - // Update binding. Note that the id suffix is bound to id_image_ - // below instead of image_ which makes this binding effectively - // bound to two images. As a result, we have to track versions - // for both of them. If this object uses optimistic concurrency, - // then the binding for the managed column (version, timestamp, - // etc) comes after the id and the image for such a column is - // stored as part of the id image. - // - std::size_t update_image_version_; - std::size_t update_id_image_version_; - binding update_image_binding_; - bind update_image_bind_[update_column_count + id_column_count + - managed_optimistic_column_count]; - - // Id image binding (only used as a parameter). Uses the suffix in - // the update bind. - // - id_image_type id_image_; - std::size_t id_image_version_; - binding id_image_binding_; - - // Extra data for objects with optimistic concurrency support. - // - optimistic_data od_; - - details::shared_ptr persist_; - details::shared_ptr find_; - details::shared_ptr update_; - details::shared_ptr erase_; - - // Delayed loading. - // - struct delayed_load - { - typedef typename object_cache_traits::position_type position_type; - - delayed_load () {} - delayed_load (const id_type& i, object_type& o, const position_type& p) - : id (i), obj (&o), pos (p) - { - } - - id_type id; - object_type* obj; - position_type pos; - }; - - typedef std::vector delayed_loads; - delayed_loads delayed_; - - // Delayed vectors swap guard. See the load_delayed_() function for - // details. - // - struct swap_guard - { - swap_guard (object_statements& os, delayed_loads& dl) - : os_ (os), dl_ (dl) - { - dl_.swap (os_.delayed_); - } - - ~swap_guard () - { - os_.clear_delayed (); - dl_.swap (os_.delayed_); - } - - private: - object_statements& os_; - delayed_loads& dl_; - }; - }; - - // - // Implementation for objects without object id. - // - - template - class object_statements_no_id: public statements_base - { - public: - typedef T object_type; - typedef odb::object_traits 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 persist_; - }; - } -} - -#include -#include - -#include - -#endif // ODB_ORACLE_OBJECT_STATEMENTS_HXX diff --git a/odb/oracle/object-statements.ixx b/odb/oracle/object-statements.ixx deleted file mode 100644 index e4eb6d7..0000000 --- a/odb/oracle/object-statements.ixx +++ /dev/null @@ -1,69 +0,0 @@ -// file : odb/oracle/object-statements.ixx -// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC -// license : ODB NCUEL; see accompanying LICENSE file - -namespace odb -{ - namespace oracle - { - // - // auto_unlock - // - inline object_statements_base::auto_unlock:: - auto_unlock (object_statements_base& s) - : s_ (s) - { - s_.unlock (); - } - - inline object_statements_base::auto_unlock:: - ~auto_unlock () - { - s_.lock (); - } - - // - // auto_lock - // - template - inline object_statements::auto_lock:: - auto_lock (object_statements& s) - : s_ (s) - { - if (!s_.locked ()) - { - s_.lock (); - locked_ = true; - } - else - locked_ = false; - } - - template - inline object_statements::auto_lock:: - ~auto_lock () - { - if (locked_) - { - s_.unlock (); - s_.clear_delayed (); - } - } - - template - inline bool object_statements::auto_lock:: - locked () const - { - return locked_; - } - - template - inline void object_statements::auto_lock:: - unlock () - { - assert (locked_); - s_.unlock (); - locked_ = false; - } - } -} diff --git a/odb/oracle/object-statements.txx b/odb/oracle/object-statements.txx deleted file mode 100644 index 65fcf46..0000000 --- a/odb/oracle/object-statements.txx +++ /dev/null @@ -1,166 +0,0 @@ -// file : odb/oracle/object-statements.txx -// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::size_t -#include // std::memset - -#include -#include -#include - -#include - -namespace odb -{ - namespace oracle - { - // - // optimistic_data - // - - template - optimistic_data:: - optimistic_data (bind* b) - : id_image_binding_ ( - b, - object_traits::id_column_count + - object_traits::managed_optimistic_column_count) - { - id_image_version_ = 0; - } - - // - // object_statements - // - - template - object_statements:: - ~object_statements () - { - } - - template - object_statements:: - object_statements (connection_type& conn) - : object_statements_base (conn), - container_statement_cache_ (conn), - select_image_binding_ (select_image_bind_, select_column_count), - insert_image_binding_ (insert_image_bind_, insert_column_count), - update_image_binding_ (update_image_bind_, - update_column_count + id_column_count + - managed_optimistic_column_count), - id_image_binding_ (update_image_bind_ + update_column_count, - id_column_count), - od_ (update_image_bind_ + update_column_count) - { - image_.version = 0; - select_image_version_ = 0; - insert_image_version_ = 0; - update_image_version_ = 0; - update_id_image_version_ = 0; - - id_image_.version = 0; - id_image_version_ = 0; - - select_image_binding_.change_callback = image_.change_callback (); - - 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 - void object_statements:: - load_delayed_ () - { - database& db (connection ().database ()); - - delayed_loads dls; - swap_guard sg (*this, dls); - - while (!dls.empty ()) - { - delayed_load l (dls.back ()); - typename object_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). - // - { - auto_unlock u (*this); - object_traits::callback (db, *l.obj, callback_event::post_load); - } - - g.release (); - } - } - - template - void object_statements:: - clear_delayed_ () - { - // Remove the objects from the session cache. - // - if (session::has_current ()) - { - for (typename delayed_loads::iterator i (delayed_.begin ()), - e (delayed_.end ()); i != e; ++i) - { - object_cache_traits::erase (i->pos); - } - } - - delayed_.clear (); - } - - // - // object_statements_no_id - // - - template - object_statements_no_id:: - ~object_statements_no_id () - { - } - - template - object_statements_no_id:: - 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/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 #include +#include // binding #include #include @@ -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 + +#include // std::size_t + +#include + +#include + +#include +#include // query +#include + +namespace odb +{ + namespace oracle + { + template + class polymorphic_object_result_impl: + public odb::polymorphic_object_result_impl + { + public: + typedef odb::polymorphic_object_result_impl 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, + 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 statement_; + statements_type& statements_; + bool use_copy_; + image_type* image_copy_; + }; + } +} + +#include + +#include + +#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 + +#include +#include +#include // result_not_cached + +#include + +namespace odb +{ + namespace oracle + { + template + polymorphic_object_result_impl:: + ~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 + polymorphic_object_result_impl:: + polymorphic_object_result_impl (const query&, + details::shared_ptr st, + statements_type& sts) + : base_type (sts.connection ().database ()), + statement_ (st), + statements_ (sts), + use_copy_ (false), + image_copy_ (0) + { + } + + template + void polymorphic_object_result_impl:: + 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 (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 polymorphic_object_result_impl::id_type + polymorphic_object_result_impl:: + 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 polymorphic_object_result_impl::discriminator_type + polymorphic_object_result_impl:: + 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 + struct polymorphic_image_rebind + { + // Derived type version. + // + typedef object_traits 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 + struct polymorphic_image_rebind + { + // Root type version. + // + typedef object_traits 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 + void polymorphic_object_result_impl:: + 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::rebind (statements_); + + if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); + this->end_ = true; + } + else + { + cc.callback = &change_callback; + cc.context = this; + } + } + + template + void polymorphic_object_result_impl:: + cache () + { + } + + template + std::size_t polymorphic_object_result_impl:: + size () + { + throw result_not_cached (); + } + + template + void polymorphic_object_result_impl:: + change_callback (void* c, binding* b) + { + polymorphic_object_result_impl* r ( + static_cast*> (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::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 + +#include // std::size_t + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace odb +{ + namespace oracle + { + // + // Implementation for polymorphic objects. + // + + template + class polymorphic_root_object_statements: public object_statements + { + public: + typedef typename object_statements::connection_type connection_type; + typedef typename object_statements::object_traits object_traits; + typedef typename object_statements::id_image_type id_image_type; + + typedef + typename object_traits::discriminator_image_type + discriminator_image_type; + + typedef + typename object_statements::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::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 find_discriminator_; + }; + + template + class polymorphic_derived_object_statements: public statements_base + { + public: + typedef T object_type; + typedef odb::object_traits 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_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& 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 persist_; + details::shared_ptr find_[ + object_traits::abstract ? 1 : object_traits::depth]; + details::shared_ptr update_; + details::shared_ptr erase_; + }; + } +} + +#include + +#include + +#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 // std::memset + +#include +#include + +#include +#include +#include + +namespace odb +{ + namespace oracle + { + // + // polymorphic_root_object_statements + // + + template + polymorphic_root_object_statements:: + ~polymorphic_root_object_statements () + { + } + + template + polymorphic_root_object_statements:: + polymorphic_root_object_statements (connection_type& conn) + : object_statements (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 + polymorphic_derived_object_statements:: + ~polymorphic_derived_object_statements () + { + } + + template + polymorphic_derived_object_statements:: + polymorphic_derived_object_statements (connection_type& conn) + : statements_base (conn), + root_statements_ (conn.statement_cache ().find_object ()), + base_statements_ (conn.statement_cache ().find_object ()), + 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 + void polymorphic_derived_object_statements:: + 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 ()); + root_statements_type& rsts (sts.root_statements ()); + + object_type& obj (static_cast (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 - -#include -#include - -#include -#include - -#include - -#endif // ODB_ORACLE_RESULT_HXX - -// Include result specializations so that the user code only needs -// to include this header. -// - -#include -#include 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 + +#include // std::size_t + +#include + +#include + +#include +#include // query +#include + +namespace odb +{ + namespace oracle + { + template + class object_result_impl: public odb::object_result_impl + { + public: + typedef odb::object_result_impl 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, + 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 statement_; + statements_type& statements_; + bool use_copy_; + typename object_traits::image_type* image_copy_; + }; + } +} + +#include + +#include + +#endif // ODB_ORACLE_SIMPLE_OBJECT_RESULT_HXX diff --git a/odb/oracle/simple-object-result.txx b/odb/oracle/simple-object-result.txx new file mode 100644 index 0000000..ec0d1f5 --- /dev/null +++ b/odb/oracle/simple-object-result.txx @@ -0,0 +1,181 @@ +// file : odb/oracle/simple-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +#include +#include // result_not_cached + +#include + +namespace odb +{ + namespace oracle + { + template + object_result_impl:: + ~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 + object_result_impl:: + object_result_impl (const query&, + details::shared_ptr statement, + statements_type& statements) + : base_type (statements.connection ().database ()), + statement_ (statement), + statements_ (statements), + use_copy_ (false), + image_copy_ (0) + { + } + + template + void object_result_impl:: + load (object_type& obj, bool) + { + // This is a top-level call so the statements cannot be locked. + // + assert (!statements_.locked ()); + typename statements_type::auto_lock l (statements_); + + odb::database& db (this->database ()); + object_traits::callback (db, obj, callback_event::pre_load); + + typename object_traits::image_type& i ( + use_copy_ ? *image_copy_ : statements_.image ()); + + object_traits::init (obj, 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, etc). + // + typename object_traits::id_image_type& idi (statements_.id_image ()); + object_traits::init (idi, object_traits::id (i)); + + 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_, obj); + statements_.load_delayed (); + l.unlock (); + object_traits::callback (db, obj, callback_event::post_load); + } + + template + typename object_result_impl::id_type + object_result_impl:: + load_id () + { + return object_traits::id ( + use_copy_ ? *image_copy_ : statements_.image ()); + } + + template + void object_result_impl:: + 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 + void object_result_impl:: + cache () + { + } + + template + std::size_t object_result_impl:: + size () + { + throw result_not_cached (); + } + + template + void object_result_impl:: + change_callback (void* c, binding* b) + { + object_result_impl* r (static_cast*> (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 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. + // + // @@ Would be good to only do this if we actually have descriptors. + // + 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/simple-object-statements.cxx b/odb/oracle/simple-object-statements.cxx new file mode 100644 index 0000000..51be556 --- /dev/null +++ b/odb/oracle/simple-object-statements.cxx @@ -0,0 +1,16 @@ +// file : odb/oracle/simple-object-statements.cxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace oracle + { + object_statements_base:: + ~object_statements_base () + { + } + } +} diff --git a/odb/oracle/simple-object-statements.hxx b/odb/oracle/simple-object-statements.hxx new file mode 100644 index 0000000..2a007b2 --- /dev/null +++ b/odb/oracle/simple-object-statements.hxx @@ -0,0 +1,497 @@ +// 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_SIMPLE_OBJECT_STATEMENTS_HXX +#define ODB_ORACLE_SIMPLE_OBJECT_STATEMENTS_HXX + +#include + +#include +#include +#include // std::size_t + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace odb +{ + namespace oracle + { + // + // Implementation for objects with object id. + // + + class LIBODB_ORACLE_EXPORT object_statements_base: public statements_base + { + // Locking. + // + public: + void + lock () + { + assert (!locked_); + locked_ = true; + } + + void + unlock () + { + assert (locked_); + locked_ = false; + } + + bool + locked () const + { + return locked_; + } + + struct auto_unlock + { + // Unlocks the statement on construction and re-locks it on + // destruction. + // + auto_unlock (object_statements_base&); + ~auto_unlock (); + + private: + auto_unlock (const auto_unlock&); + auto_unlock& operator= (const auto_unlock&); + + private: + object_statements_base& s_; + }; + + public: + virtual + ~object_statements_base (); + + protected: + object_statements_base (connection_type& conn) + : statements_base (conn), locked_ (false) + { + } + + protected: + bool locked_; + }; + + template + struct optimistic_data; + + template + struct optimistic_data + { + typedef T object_type; + typedef odb::object_traits object_traits; + + optimistic_data (bind*); + + // The id + optimistic column binding. + // + std::size_t id_image_version_; + binding id_image_binding_; + + details::shared_ptr erase_; + }; + + template + struct optimistic_data + { + optimistic_data (bind*) {} + }; + + template + class object_statements: public object_statements_base + { + public: + typedef T object_type; + typedef odb::object_traits object_traits; + typedef typename object_traits::id_type id_type; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::image_type image_type; + typedef typename object_traits::id_image_type id_image_type; + + typedef + typename object_traits::pointer_cache_traits + pointer_cache_traits; + + 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; + + // Automatic lock. + // + struct auto_lock + { + // Lock the statements unless they are already locked in which + // case subsequent calls to locked() will return false. + // + auto_lock (object_statements&); + + // Unlock the statements if we are holding the lock and clear + // the delayed loads. This should only happen in case an + // exception is thrown. In normal circumstances, the user + // should call unlock() explicitly. + // + ~auto_lock (); + + // Return true if this auto_lock instance holds the lock. + // + bool + locked () const; + + // Unlock the statements. + // + void + unlock (); + + private: + auto_lock (const auto_lock&); + auto_lock& operator= (const auto_lock&); + + private: + object_statements& s_; + bool locked_; + }; + + public: + object_statements (connection_type&); + + virtual + ~object_statements (); + + // 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 pointer_cache_traits::position_type& p, + loader_function l = 0) + { + delayed_.push_back (delayed_load (id, obj, p, l)); + } + + void + load_delayed () + { + assert (locked ()); + + if (!delayed_.empty ()) + load_delayed_ (); + } + + void + clear_delayed () + { + if (!delayed_.empty ()) + clear_delayed_ (); + } + + // 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_;} + + // 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_image_version () const { return update_id_image_version_;} + + void + update_id_image_version (std::size_t v) {update_id_image_version_ = v;} + + binding& + update_image_binding () {return update_image_binding_;} + + // Select binding. + // + 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_;} + + // Object id image and binding. + // + id_image_type& + id_image () {return id_image_;} + + std::size_t + id_image_version () const {return id_image_version_;} + + void + id_image_version (std::size_t v) {id_image_version_ = v;} + + binding& + id_image_binding () {return id_image_binding_;} + + // Optimistic id + managed column image binding. + // + std::size_t + optimistic_id_image_version () const {return od_.id_image_version_;} + + void + optimistic_id_image_version (std::size_t v) {od_.id_image_version_ = v;} + + binding& + optimistic_id_image_binding () {return od_.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_, + object_traits::auto_id)); + + return *persist_; + } + + select_statement_type& + find_statement () + { + if (find_ == 0) + find_.reset ( + new (details::shared) select_statement_type ( + conn_, + object_traits::find_statement, + id_image_binding_, + select_image_binding_, + 4096)); // Hardcode a 4kB LOB prefetch size. + + return *find_; + } + + 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, + id_image_binding_)); + + return *erase_; + } + + delete_statement_type& + optimistic_erase_statement () + { + if (od_.erase_ == 0) + { + od_.erase_.reset ( + new (details::shared) delete_statement_type ( + conn_, + object_traits::optimistic_erase_statement, + od_.id_image_binding_)); + } + + return *od_.erase_; + } + + // Container statement cache. + // + container_statement_cache_type& + container_statment_cache () + { + return container_statement_cache_; + } + + public: + // select = total + // insert = total - inverse - managed_optimistic + // update = total - inverse - managed_optimistic - id - readonly + // + static const std::size_t select_column_count = + object_traits::column_count; + + static const std::size_t insert_column_count = + object_traits::column_count - object_traits::inverse_column_count - + object_traits::managed_optimistic_column_count; + + static const std::size_t update_column_count = insert_column_count - + object_traits::id_column_count - object_traits::readonly_column_count; + + static const std::size_t id_column_count = + object_traits::id_column_count; + + static const std::size_t managed_optimistic_column_count = + 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_; + + // 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]; + + // Update binding. Note that the id suffix is bound to id_image_ + // below instead of image_ which makes this binding effectively + // bound to two images. As a result, we have to track versions + // for both of them. If this object uses optimistic concurrency, + // then the binding for the managed column (version, timestamp, + // etc) comes after the id and the image for such a column is + // stored as part of the id image. + // + std::size_t update_image_version_; + std::size_t update_id_image_version_; + binding update_image_binding_; + bind update_image_bind_[update_column_count + id_column_count + + managed_optimistic_column_count]; + + // Id image binding (only used as a parameter). Uses the suffix in + // the update bind. + // + id_image_type id_image_; + std::size_t id_image_version_; + binding id_image_binding_; + + // Extra data for objects with optimistic concurrency support. + // + optimistic_data od_; + + details::shared_ptr persist_; + details::shared_ptr find_; + details::shared_ptr update_; + details::shared_ptr erase_; + + // Delayed loading. + // + struct delayed_load + { + typedef typename pointer_cache_traits::position_type position_type; + + delayed_load () {} + 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_loads; + delayed_loads delayed_; + + // Delayed vectors swap guard. See the load_delayed_() function for + // details. + // + struct swap_guard + { + swap_guard (object_statements& os, delayed_loads& dl) + : os_ (os), dl_ (dl) + { + dl_.swap (os_.delayed_); + } + + ~swap_guard () + { + os_.clear_delayed (); + dl_.swap (os_.delayed_); + } + + private: + object_statements& os_; + delayed_loads& dl_; + }; + }; + } +} + +#include +#include + +#include + +#endif // ODB_ORACLE_SIMPLE_OBJECT_STATEMENTS_HXX diff --git a/odb/oracle/simple-object-statements.ixx b/odb/oracle/simple-object-statements.ixx new file mode 100644 index 0000000..3e399f6 --- /dev/null +++ b/odb/oracle/simple-object-statements.ixx @@ -0,0 +1,69 @@ +// file : odb/oracle/simple-object-statements.ixx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace oracle + { + // + // auto_unlock + // + inline object_statements_base::auto_unlock:: + auto_unlock (object_statements_base& s) + : s_ (s) + { + s_.unlock (); + } + + inline object_statements_base::auto_unlock:: + ~auto_unlock () + { + s_.lock (); + } + + // + // auto_lock + // + template + inline object_statements::auto_lock:: + auto_lock (object_statements& s) + : s_ (s) + { + if (!s_.locked ()) + { + s_.lock (); + locked_ = true; + } + else + locked_ = false; + } + + template + inline object_statements::auto_lock:: + ~auto_lock () + { + if (locked_) + { + s_.unlock (); + s_.clear_delayed (); + } + } + + template + inline bool object_statements::auto_lock:: + locked () const + { + return locked_; + } + + template + inline void object_statements::auto_lock:: + unlock () + { + assert (locked_); + s_.unlock (); + locked_ = false; + } + } +} diff --git a/odb/oracle/simple-object-statements.txx b/odb/oracle/simple-object-statements.txx new file mode 100644 index 0000000..83aff45 --- /dev/null +++ b/odb/oracle/simple-object-statements.txx @@ -0,0 +1,143 @@ +// file : odb/oracle/simple-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::memset + +#include +#include +#include + +#include + +namespace odb +{ + namespace oracle + { + // + // optimistic_data + // + + template + optimistic_data:: + optimistic_data (bind* b) + : id_image_binding_ ( + b, + object_traits::id_column_count + + object_traits::managed_optimistic_column_count) + { + id_image_version_ = 0; + } + + // + // object_statements + // + + template + object_statements:: + ~object_statements () + { + } + + template + object_statements:: + object_statements (connection_type& conn) + : object_statements_base (conn), + container_statement_cache_ (conn), + select_image_binding_ (select_image_bind_, select_column_count), + insert_image_binding_ (insert_image_bind_, insert_column_count), + update_image_binding_ (update_image_bind_, + update_column_count + id_column_count + + managed_optimistic_column_count), + id_image_binding_ (update_image_bind_ + update_column_count, + id_column_count), + od_ (update_image_bind_ + update_column_count) + { + image_.version = 0; + select_image_version_ = 0; + insert_image_version_ = 0; + update_image_version_ = 0; + update_id_image_version_ = 0; + + id_image_.version = 0; + id_image_version_ = 0; + + select_image_binding_.change_callback = image_.change_callback (); + + 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 + void object_statements:: + load_delayed_ () + { + database& db (connection ().database ()); + + delayed_loads dls; + swap_guard sg (*this, dls); + + while (!dls.empty ()) + { + delayed_load l (dls.back ()); + typename pointer_cache_traits::insert_guard g (l.pos); + dls.pop_back (); + + if (l.loader == 0) + { + 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 (); + } + } + + template + void object_statements:: + clear_delayed_ () + { + // Remove the objects from the session cache. + // + if (session::has_current ()) + { + for (typename delayed_loads::iterator i (delayed_.begin ()), + e (delayed_.end ()); i != e; ++i) + { + pointer_cache_traits::erase (i->pos); + } + } + + delayed_.clear (); + } + } +} 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 #include +#include #include +#include #include -#include -#include #include #include @@ -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 object_statements_selector::type& - find_object () - { - typedef typename object_statements_selector::type object_statements; - - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast (*i->second); - - details::shared_ptr p ( - new (details::shared) object_statements (conn_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } + typename object_traits::statements_type& + find_object (); template view_statements& - find_view () - { - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast&> (*i->second); - - details::shared_ptr > p ( - new (details::shared) view_statements (conn_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } + find_view (); private: typedef std::map + #include #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 object_traits::statements_type& statement_cache:: + find_object () + { + typedef typename object_traits::statements_type statements_type; + + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast (*i->second); + + details::shared_ptr p ( + new (details::shared) statements_type (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } + + template + view_statements& statement_cache:: + find_view () + { + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast&> (*i->second); + + details::shared_ptr > p ( + new (details::shared) view_statements (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 // std::size_t +#include + #include #include #include // query, view_statements -#include #include 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 statements_type; + virtual ~view_result_impl (); view_result_impl (const query&, details::shared_ptr, - view_statements&); + 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 statement_; - view_statements& 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:: view_result_impl (const query&, details::shared_ptr statement, - view_statements& statements) + statements_type& statements) : base_type (statements.connection ().database ()), statement_ (statement), statements_ (statements), @@ -116,7 +116,7 @@ namespace odb template void view_result_impl:: - change_callback (void* c) + change_callback (void* c, binding*) { view_result_impl* r (static_cast*> (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++; -- cgit v1.1