From 851cbe3927b987ec992bbbb69bd62224bf4a0dc3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 23 Apr 2012 16:48:01 +0200 Subject: Polymorphic inheritance support --- odb/sqlite/binding.hxx | 2 + odb/sqlite/forward.hxx | 8 +- odb/sqlite/makefile | 32 +- odb/sqlite/no-id-object-result.hxx | 71 +++ odb/sqlite/no-id-object-result.txx | 100 +++++ odb/sqlite/no-id-object-statements.hxx | 137 ++++++ odb/sqlite/no-id-object-statements.txx | 37 ++ odb/sqlite/object-result.hxx | 113 ----- odb/sqlite/object-result.txx | 237 ---------- odb/sqlite/object-statements.cxx | 16 - odb/sqlite/object-statements.hxx | 624 --------------------------- odb/sqlite/object-statements.ixx | 69 --- odb/sqlite/object-statements.txx | 171 -------- odb/sqlite/polymorphic-object-result.hxx | 87 ++++ odb/sqlite/polymorphic-object-result.txx | 266 ++++++++++++ odb/sqlite/polymorphic-object-statements.hxx | 452 +++++++++++++++++++ odb/sqlite/polymorphic-object-statements.txx | 141 ++++++ odb/sqlite/result.hxx | 10 - odb/sqlite/simple-object-result.hxx | 79 ++++ odb/sqlite/simple-object-result.txx | 143 ++++++ odb/sqlite/simple-object-statements.cxx | 16 + odb/sqlite/simple-object-statements.hxx | 515 ++++++++++++++++++++++ odb/sqlite/simple-object-statements.ixx | 69 +++ odb/sqlite/simple-object-statements.txx | 145 +++++++ odb/sqlite/statement-cache.hxx | 40 +- odb/sqlite/statement-cache.txx | 43 ++ odb/sqlite/view-result.hxx | 9 +- odb/sqlite/view-result.txx | 2 +- 28 files changed, 2340 insertions(+), 1294 deletions(-) create mode 100644 odb/sqlite/no-id-object-result.hxx create mode 100644 odb/sqlite/no-id-object-result.txx create mode 100644 odb/sqlite/no-id-object-statements.hxx create mode 100644 odb/sqlite/no-id-object-statements.txx delete mode 100644 odb/sqlite/object-result.hxx delete mode 100644 odb/sqlite/object-result.txx delete mode 100644 odb/sqlite/object-statements.cxx delete mode 100644 odb/sqlite/object-statements.hxx delete mode 100644 odb/sqlite/object-statements.ixx delete mode 100644 odb/sqlite/object-statements.txx create mode 100644 odb/sqlite/polymorphic-object-result.hxx create mode 100644 odb/sqlite/polymorphic-object-result.txx create mode 100644 odb/sqlite/polymorphic-object-statements.hxx create mode 100644 odb/sqlite/polymorphic-object-statements.txx create mode 100644 odb/sqlite/simple-object-result.hxx create mode 100644 odb/sqlite/simple-object-result.txx create mode 100644 odb/sqlite/simple-object-statements.cxx create mode 100644 odb/sqlite/simple-object-statements.hxx create mode 100644 odb/sqlite/simple-object-statements.ixx create mode 100644 odb/sqlite/simple-object-statements.txx create mode 100644 odb/sqlite/statement-cache.txx (limited to 'odb') diff --git a/odb/sqlite/binding.hxx b/odb/sqlite/binding.hxx index cb5e24c..f55d48a 100644 --- a/odb/sqlite/binding.hxx +++ b/odb/sqlite/binding.hxx @@ -23,6 +23,8 @@ namespace odb public: typedef sqlite::bind bind_type; + binding (): bind (0), count (0), version (0) {} + binding (bind_type* b, std::size_t n) : bind (b), count (n), version (0) { diff --git a/odb/sqlite/forward.hxx b/odb/sqlite/forward.hxx index 2084ffb..9be506f 100644 --- a/odb/sqlite/forward.hxx +++ b/odb/sqlite/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/sqlite/makefile b/odb/sqlite/makefile index 7c74807..8674e4a 100644 --- a/odb/sqlite/makefile +++ b/odb/sqlite/makefile @@ -4,22 +4,22 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make -cxx := \ -connection.cxx \ -connection-factory.cxx \ -database.cxx \ -error.cxx \ -exceptions.cxx \ -object-statements.cxx \ -query.cxx \ -query-const-expr.cxx \ -result.cxx \ -statement-cache.cxx \ -statement.cxx \ -statements-base.cxx \ -tracer.cxx \ -traits.cxx \ -transaction.cxx \ +cxx := \ +connection.cxx \ +connection-factory.cxx \ +database.cxx \ +error.cxx \ +exceptions.cxx \ +query.cxx \ +query-const-expr.cxx \ +result.cxx \ +simple-object-statements.cxx \ +statement.cxx \ +statements-base.cxx \ +statement-cache.cxx \ +tracer.cxx \ +traits.cxx \ +transaction.cxx \ transaction-impl.cxx cli_tun := details/options.cli diff --git a/odb/sqlite/no-id-object-result.hxx b/odb/sqlite/no-id-object-result.hxx new file mode 100644 index 0000000..84a7265 --- /dev/null +++ b/odb/sqlite/no-id-object-result.hxx @@ -0,0 +1,71 @@ +// file : odb/sqlite/no-id-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_NO_ID_OBJECT_RESULT_HXX +#define ODB_SQLITE_NO_ID_OBJECT_RESULT_HXX + +#include + +#include // std::size_t + +#include + +#include + +#include +#include // query +#include +#include + +namespace odb +{ + namespace sqlite + { + template + class no_id_object_result_impl: public odb::no_id_object_result_impl, + public result_impl_base + { + public: + typedef odb::no_id_object_result_impl base_type; + + typedef typename base_type::object_traits object_traits; + typedef typename base_type::object_type object_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 + ~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: + statements_type& statements_; + }; + } +} + +#include + +#include + +#endif // ODB_SQLITE_NO_ID_OBJECT_RESULT_HXX diff --git a/odb/sqlite/no-id-object-result.txx b/odb/sqlite/no-id-object-result.txx new file mode 100644 index 0000000..8519c47 --- /dev/null +++ b/odb/sqlite/no-id-object-result.txx @@ -0,0 +1,100 @@ +// file : odb/sqlite/no-id-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include // result_not_cached + +#include + +namespace odb +{ + namespace sqlite + { + template + no_id_object_result_impl:: + ~no_id_object_result_impl () + { + if (!this->end_) + statement_->free_result (); + } + + template + no_id_object_result_impl:: + no_id_object_result_impl (const query& q, + details::shared_ptr statement, + statements_type& statements) + : base_type (statements.connection ().database ()), + result_impl_base (q, statement), + statements_ (statements) + { + } + + template + void no_id_object_result_impl:: + load (object_type& obj) + { + // The image can grow between calls to load() as a result of other + // statements execution. + // + typename object_traits::image_type& im (statements_.image ()); + + if (im.version != statements_.select_image_version ()) + { + binding& b (statements_.select_image_binding ()); + object_traits::bind (b.bind, im, statement_select); + statements_.select_image_version (im.version); + b.version++; + } + + select_statement::result r (statement_->load ()); + + if (r == select_statement::truncated) + { + if (object_traits::grow (im, statements_.select_image_truncated ())) + im.version++; + + if (im.version != statements_.select_image_version ()) + { + binding& b (statements_.select_image_binding ()); + object_traits::bind (b.bind, im, statement_select); + statements_.select_image_version (im.version); + b.version++; + statement_->reload (); + } + } + + odb::database& db (this->database ()); + + object_traits::callback (db, obj, callback_event::pre_load); + object_traits::init (obj, im, &db); + object_traits::callback (db, obj, callback_event::post_load); + } + + template + void no_id_object_result_impl:: + next () + { + this->current (pointer_type ()); + + if (!statement_->next ()) + { + statement_->free_result (); + this->end_ = true; + } + } + + template + void no_id_object_result_impl:: + cache () + { + } + + template + std::size_t no_id_object_result_impl:: + size () + { + throw result_not_cached (); + } + } +} diff --git a/odb/sqlite/no-id-object-statements.hxx b/odb/sqlite/no-id-object-statements.hxx new file mode 100644 index 0000000..04d46ce --- /dev/null +++ b/odb/sqlite/no-id-object-statements.hxx @@ -0,0 +1,137 @@ +// file : odb/sqlite/no-id-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_NO_ID_OBJECT_STATEMENTS_HXX +#define ODB_SQLITE_NO_ID_OBJECT_STATEMENTS_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace odb +{ + namespace sqlite + { + // + // 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 sqlite::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. + // + 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_;} + + bool* + select_image_truncated () {return select_image_truncated_;} + + // Statements. + // + insert_statement_type& + persist_statement () + { + if (persist_ == 0) + { + persist_.reset ( + new (details::shared) insert_statement_type ( + conn_, + object_traits::persist_statement, + insert_image_binding_)); + + persist_->cached (true); + } + + 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]; + bool select_image_truncated_[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_SQLITE_NO_ID_OBJECT_STATEMENTS_HXX diff --git a/odb/sqlite/no-id-object-statements.txx b/odb/sqlite/no-id-object-statements.txx new file mode 100644 index 0000000..9b531f6 --- /dev/null +++ b/odb/sqlite/no-id-object-statements.txx @@ -0,0 +1,37 @@ +// file : odb/sqlite/no-id-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // std::memset + +namespace odb +{ + namespace sqlite + { + 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; + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + std::memset ( + select_image_truncated_, 0, sizeof (select_image_truncated_)); + + for (std::size_t i (0); i < select_column_count; ++i) + select_image_bind_[i].truncated = select_image_truncated_ + i; + } + } +} diff --git a/odb/sqlite/object-result.hxx b/odb/sqlite/object-result.hxx deleted file mode 100644 index 9dcdca0..0000000 --- a/odb/sqlite/object-result.hxx +++ /dev/null @@ -1,113 +0,0 @@ -// file : odb/sqlite/object-result.hxx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#ifndef ODB_SQLITE_OBJECT_RESULT_HXX -#define ODB_SQLITE_OBJECT_RESULT_HXX - -#include - -#include // std::size_t - -#include - -#include -#include // query, object_statements -#include -#include - -namespace odb -{ - namespace sqlite - { - template - class object_result_impl: public odb::object_result_impl, - public result_impl_base - { - public: - typedef odb::object_result_impl base_type; - - typedef typename base_type::object_traits object_traits; - typedef typename base_type::object_type object_type; - 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: - void - load_image (); - - private: - object_statements& statements_; - }; - - template - class object_result_impl_no_id: public odb::object_result_impl_no_id, - public result_impl_base - { - public: - typedef odb::object_result_impl_no_id base_type; - - typedef typename base_type::object_traits object_traits; - typedef typename base_type::object_type object_type; - - 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: - object_statements_no_id& statements_; - }; - } -} - -#include - -#include - -#endif // ODB_SQLITE_OBJECT_RESULT_HXX diff --git a/odb/sqlite/object-result.txx b/odb/sqlite/object-result.txx deleted file mode 100644 index 39dcdd7..0000000 --- a/odb/sqlite/object-result.txx +++ /dev/null @@ -1,237 +0,0 @@ -// file : odb/sqlite/object-result.txx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#include - -#include -#include - -#include - -namespace odb -{ - namespace sqlite - { - // - // object_result_impl - // - - template - object_result_impl:: - ~object_result_impl () - { - if (!this->end_) - statement_->free_result (); - } - - template - object_result_impl:: - object_result_impl (const query& q, - details::shared_ptr statement, - object_statements& statements) - : base_type (statements.connection ().database ()), - result_impl_base (q, statement), - statements_ (statements) - { - } - - template - void object_result_impl:: - load (object_type& obj, bool fetch) - { - if (fetch) - load_image (); - - // 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 (statements_.image ()); - object_traits::init (obj, i, &db); - - // 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 () - { - load_image (); - return object_traits::id (statements_.image ()); - } - - template - void object_result_impl:: - next () - { - this->current (pointer_type ()); - - if (!statement_->next ()) - { - statement_->free_result (); - this->end_ = true; - } - } - - template - void object_result_impl:: - load_image () - { - // The image can grow between calls to load() as a result of other - // statements execution. - // - typename object_traits::image_type& im (statements_.image ()); - - if (im.version != statements_.select_image_version ()) - { - binding& b (statements_.select_image_binding ()); - object_traits::bind (b.bind, im, statement_select); - statements_.select_image_version (im.version); - b.version++; - } - - select_statement::result r (statement_->load ()); - - if (r == select_statement::truncated) - { - if (object_traits::grow (im, statements_.select_image_truncated ())) - im.version++; - - if (im.version != statements_.select_image_version ()) - { - binding& b (statements_.select_image_binding ()); - object_traits::bind (b.bind, im, statement_select); - statements_.select_image_version (im.version); - b.version++; - statement_->reload (); - } - } - } - - template - void object_result_impl:: - cache () - { - } - - template - std::size_t object_result_impl:: - size () - { - throw result_not_cached (); - } - - // - // object_result_impl_no_id - // - - template - object_result_impl_no_id:: - ~object_result_impl_no_id () - { - if (!this->end_) - statement_->free_result (); - } - - template - object_result_impl_no_id:: - object_result_impl_no_id (const query& q, - details::shared_ptr statement, - object_statements_no_id& statements) - : base_type (statements.connection ().database ()), - result_impl_base (q, statement), - statements_ (statements) - { - } - - template - void object_result_impl_no_id:: - load (object_type& obj) - { - // The image can grow between calls to load() as a result of other - // statements execution. - // - typename object_traits::image_type& im (statements_.image ()); - - if (im.version != statements_.select_image_version ()) - { - binding& b (statements_.select_image_binding ()); - object_traits::bind (b.bind, im, statement_select); - statements_.select_image_version (im.version); - b.version++; - } - - select_statement::result r (statement_->load ()); - - if (r == select_statement::truncated) - { - if (object_traits::grow (im, statements_.select_image_truncated ())) - im.version++; - - if (im.version != statements_.select_image_version ()) - { - binding& b (statements_.select_image_binding ()); - object_traits::bind (b.bind, im, statement_select); - statements_.select_image_version (im.version); - b.version++; - statement_->reload (); - } - } - - odb::database& db (this->database ()); - - object_traits::callback (db, obj, callback_event::pre_load); - object_traits::init (obj, im, &db); - object_traits::callback (db, obj, callback_event::post_load); - } - - template - void object_result_impl_no_id:: - next () - { - this->current (pointer_type ()); - - if (!statement_->next ()) - { - statement_->free_result (); - this->end_ = true; - } - } - - template - void object_result_impl_no_id:: - cache () - { - } - - template - std::size_t object_result_impl_no_id:: - size () - { - throw result_not_cached (); - } - } -} diff --git a/odb/sqlite/object-statements.cxx b/odb/sqlite/object-statements.cxx deleted file mode 100644 index 6ae631e..0000000 --- a/odb/sqlite/object-statements.cxx +++ /dev/null @@ -1,16 +0,0 @@ -// file : odb/sqlite/object-statements.cxx -// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#include - -namespace odb -{ - namespace sqlite - { - object_statements_base:: - ~object_statements_base () - { - } - } -} diff --git a/odb/sqlite/object-statements.hxx b/odb/sqlite/object-statements.hxx deleted file mode 100644 index 0628222..0000000 --- a/odb/sqlite/object-statements.hxx +++ /dev/null @@ -1,624 +0,0 @@ -// file : odb/sqlite/object-statements.hxx -// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#ifndef ODB_SQLITE_OBJECT_STATEMENTS_HXX -#define ODB_SQLITE_OBJECT_STATEMENTS_HXX - -#include - -#include -#include -#include // std::size_t - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -namespace odb -{ - namespace sqlite - { - 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_SQLITE_EXPORT object_statements_base: public statements_base - { - public: - // Locking. - // - 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 sqlite::insert_statement insert_statement_type; - typedef sqlite::select_statement select_statement_type; - typedef sqlite::update_statement update_statement_type; - typedef sqlite::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 statemens 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 statemens. - // - 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_;} - - bool* - select_image_truncated () {return select_image_truncated_;} - - // 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_)); - - persist_->cached (true); - } - - 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_)); - - find_->cached (true); - } - - 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_)); - - update_->cached (true); - } - - 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_)); - - erase_->cached (true); - } - - 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_)); - - od_.erase_->cached (true); - } - - 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]; - bool select_image_truncated_[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 sqlite::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. - // - 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_;} - - bool* - select_image_truncated () {return select_image_truncated_;} - - // Statements. - // - insert_statement_type& - persist_statement () - { - if (persist_ == 0) - { - persist_.reset ( - new (details::shared) insert_statement_type ( - conn_, - object_traits::persist_statement, - insert_image_binding_)); - - persist_->cached (true); - } - - 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]; - bool select_image_truncated_[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_SQLITE_OBJECT_STATEMENTS_HXX diff --git a/odb/sqlite/object-statements.ixx b/odb/sqlite/object-statements.ixx deleted file mode 100644 index 399185a..0000000 --- a/odb/sqlite/object-statements.ixx +++ /dev/null @@ -1,69 +0,0 @@ -// file : odb/sqlite/object-statements.ixx -// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -namespace odb -{ - namespace sqlite - { - // - // 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/sqlite/object-statements.txx b/odb/sqlite/object-statements.txx deleted file mode 100644 index a880ceb..0000000 --- a/odb/sqlite/object-statements.txx +++ /dev/null @@ -1,171 +0,0 @@ -// file : odb/sqlite/object-statements.txx -// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#include // std::size_t -#include // std::memset - -#include -#include -#include - -#include - -namespace odb -{ - namespace sqlite - { - // - // 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; - - std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); - std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); - std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); - std::memset ( - select_image_truncated_, 0, sizeof (select_image_truncated_)); - - for (std::size_t i (0); i < select_column_count; ++i) - select_image_bind_[i].truncated = select_image_truncated_ + i; - } - - 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); - 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; - - std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); - std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); - std::memset ( - select_image_truncated_, 0, sizeof (select_image_truncated_)); - - for (std::size_t i (0); i < select_column_count; ++i) - select_image_bind_[i].truncated = select_image_truncated_ + i; - } - } -} diff --git a/odb/sqlite/polymorphic-object-result.hxx b/odb/sqlite/polymorphic-object-result.hxx new file mode 100644 index 0000000..54f4092 --- /dev/null +++ b/odb/sqlite/polymorphic-object-result.hxx @@ -0,0 +1,87 @@ +// file : odb/sqlite/polymorphic-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_POLYMORPHIC_OBJECT_RESULT_HXX +#define ODB_SQLITE_POLYMORPHIC_OBJECT_RESULT_HXX + +#include + +#include // std::size_t + +#include + +#include + +#include +#include // query +#include +#include + +namespace odb +{ + namespace sqlite + { + template + class polymorphic_object_result_impl: + public odb::polymorphic_object_result_impl, + public result_impl_base + { + 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::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: + void + load_image (); + + private: + statements_type& statements_; + }; + } +} + +#include + +#include + +#endif // ODB_SQLITE_POLYMORPHIC_OBJECT_RESULT_HXX diff --git a/odb/sqlite/polymorphic-object-result.txx b/odb/sqlite/polymorphic-object-result.txx new file mode 100644 index 0000000..a8cd1f0 --- /dev/null +++ b/odb/sqlite/polymorphic-object-result.txx @@ -0,0 +1,266 @@ +// file : odb/sqlite/polymorphic-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +#include +#include +#include // result_not_cached + +#include + +namespace odb +{ + namespace sqlite + { + template + polymorphic_object_result_impl:: + ~polymorphic_object_result_impl () + { + if (!this->end_) + statement_->free_result (); + } + + template + polymorphic_object_result_impl:: + polymorphic_object_result_impl (const query& q, + details::shared_ptr st, + statements_type& sts) + : base_type (sts.connection ().database ()), + result_impl_base (q, st), + statements_ (sts) + { + } + + template + void polymorphic_object_result_impl:: + load (object_type* pobj, bool fetch) + { + if (fetch) + load_image (); + + typename statements_type::root_statements_type& rsts ( + statements_.root_statements ()); + + // This is a top-level call so the statements cannot be locked. + // + assert (!rsts.locked ()); + typename statements_type::auto_lock l (rsts); + + odb::database& db (this->database ()); + typename object_traits::image_type& i (statements_.image ()); + typename root_traits::image_type& ri (rsts.image ()); + + id_type id (root_traits::id (ri)); + + // Determine this object's dynamic type. + // + typedef typename root_traits::info_type info_type; + discriminator_type d (root_traits::discriminator (ri)); + discriminator_type disc (d); + + // Use the polymorphic_info() helper to get concrete_info if + // object_type is concrete and NULL if it is abstract. + // + const info_type* spi (polymorphic_info (object_traits::info)); + const info_type& pi ( + spi != 0 && spi->discriminator == d + ? *spi + : root_traits::map->find (d)); + + typedef typename root_traits::pointer_type root_pointer_type; + typedef typename root_traits::pointer_traits root_pointer_traits; + + typename object_traits::pointer_cache_traits::insert_guard ig; + + if (pobj == 0) + { + // Need to create a new instance of the dynamic type. + // + root_pointer_type rp (pi.create ()); + pointer_type p ( + root_pointer_traits::template static_pointer_cast (rp)); + + // Insert it as a root pointer (for non-unique pointers, rp should + // still be valid and for unique pointers this is a no-op). + // + ig.reset (object_traits::pointer_cache_traits::insert (db, id, rp)); + + pobj = &pointer_traits::get_ref (p); + current (p); + } + else + { + // We are loading into an existing instance. If the static and + // dynamic types differ, then make sure the instance is at least + // of the dynamic type. + // + if (&pi != &object_traits::info) + { + const info_type& dpi (root_traits::map->find (typeid (*pobj))); + + if (&dpi != &pi && dpi.derived (pi)) + throw object_not_persistent (); // @@ type_mismatch ? + } + } + + callback_event ce (callback_event::pre_load); + pi.dispatch (info_type::call_callback, db, pobj, &ce); + + object_traits::init (*pobj, i, &db); + + // Initialize the id image and binding and load the rest of the object + // (containers, dynamic part, etc). + // + typename object_traits::id_image_type& idi (statements_.id_image ()); + root_traits::init (idi, id); + + binding& idb (statements_.id_image_binding ()); + if (idi.version != statements_.id_image_version () || idb.version == 0) + { + object_traits::bind (idb.bind, idi); + statements_.id_image_version (idi.version); + idb.version++; + } + + object_traits::load_ (statements_, *pobj); + + // Load the dynamic part of the object unless static and dynamic + // types are the same. + // + if (&pi != &object_traits::info) + { + std::size_t d (object_traits::depth); + pi.dispatch (info_type::call_load, db, pobj, &d); + }; + + rsts.load_delayed (); + l.unlock (); + + ce = callback_event::post_load; + pi.dispatch (info_type::call_callback, db, pobj, &ce); + ig.release (); + } + + template + typename polymorphic_object_result_impl::id_type + polymorphic_object_result_impl:: + load_id () + { + load_image (); + return root_traits::id (statements_.root_statements ().image ()); + } + + template + typename polymorphic_object_result_impl::discriminator_type + polymorphic_object_result_impl:: + load_discriminator () + { + load_image (); + return root_traits::discriminator ( + statements_.root_statements ().image ()); + } + + template + void polymorphic_object_result_impl:: + next () + { + this->current (pointer_type ()); + + if (!statement_->next ()) + { + statement_->free_result (); + this->end_ = true; + } + } + + template + struct polymorphic_image_rebind + { + // Derived type version. + // + typedef object_traits traits; + + static bool + rebind (typename traits::statements_type& sts) + { + typename traits::image_type& im (sts.image ()); + + if (traits::check_version (sts.select_image_versions (), im)) + { + binding& b (sts.select_image_binding (traits::depth)); + traits::bind (b.bind, 0, 0, im, statement_select); + traits::update_version ( + sts.select_image_versions (), im, sts.select_image_bindings ()); + return true; + } + + return false; + } + }; + + template + struct polymorphic_image_rebind + { + // Root type version. + // + typedef object_traits traits; + + static bool + rebind (typename traits::statements_type& sts) + { + typename traits::image_type& im (sts.image ()); + + if (im.version != sts.select_image_version ()) + { + binding& b (sts.select_image_binding ()); + traits::bind (b.bind, im, statement_select); + sts.select_image_version (im.version); + b.version++; + return true; + } + + return false; + } + }; + + template + void polymorphic_object_result_impl:: + load_image () + { + typedef polymorphic_image_rebind image_rebind; + + // The image can grow between calls to load() as a result of other + // statements execution. + // + image_rebind::rebind (statements_); + + select_statement::result r (statement_->load ()); + + if (r == select_statement::truncated) + { + typename object_traits::image_type& im (statements_.image ()); + + if (object_traits::grow (im, statements_.select_image_truncated ())) + im.version++; + + if (image_rebind::rebind (statements_)) + statement_->reload (); + } + } + + template + void polymorphic_object_result_impl:: + cache () + { + } + + template + std::size_t polymorphic_object_result_impl:: + size () + { + throw result_not_cached (); + } + } +} diff --git a/odb/sqlite/polymorphic-object-statements.hxx b/odb/sqlite/polymorphic-object-statements.hxx new file mode 100644 index 0000000..1212176 --- /dev/null +++ b/odb/sqlite/polymorphic-object-statements.hxx @@ -0,0 +1,452 @@ +// file : odb/sqlite/polymorphic-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_POLYMORPHIC_OBJECT_STATEMENTS_HXX +#define ODB_SQLITE_POLYMORPHIC_OBJECT_STATEMENTS_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace odb +{ + namespace sqlite + { + // + // 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_;} + + bool* + discriminator_image_truncated () {return discriminator_image_truncated_;} + + // Id binding for discriminator retrieval. + // + id_image_type& + discriminator_id_image () {return discriminator_id_image_;} + + std::size_t + discriminator_id_image_version () const + {return discriminator_id_image_version_;} + + void + discriminator_id_image_version (std::size_t v) + {discriminator_id_image_version_ = v;} + + binding& + discriminator_id_image_binding () + {return discriminator_id_image_binding_;} + + // + // + select_statement_type& + find_discriminator_statement () + { + if (find_discriminator_ == 0) + { + find_discriminator_.reset ( + new (details::shared) select_statement_type ( + this->conn_, + object_traits::find_discriminator_statement, + discriminator_id_image_binding_, + discriminator_image_binding_)); + + find_discriminator_->cached (true); + } + + 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]; + bool discriminator_image_truncated_[discriminator_column_count + + managed_optimistic_column_count]; + + // Id image for discriminator retrieval (only used as a parameter). + // + id_image_type discriminator_id_image_; + std::size_t discriminator_id_image_version_; + binding discriminator_id_image_binding_; + 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 sqlite::insert_statement insert_statement_type; + typedef sqlite::select_statement select_statement_type; + typedef sqlite::update_statement update_statement_type; + typedef sqlite::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]; + } + + bool* + select_image_truncated () {return select_image_truncated_;} + + // Object id binding (comes from the root statements). + // + id_image_type& + id_image () {return root_statements_.id_image ();} + + std::size_t + id_image_version () const {return root_statements_.id_image_version ();} + + void + id_image_version (std::size_t v) {root_statements_.id_image_version (v);} + + binding& + id_image_binding () {return root_statements_.id_image_binding ();} + + // Statements. + // + insert_statement_type& + persist_statement () + { + if (persist_ == 0) + { + persist_.reset ( + new (details::shared) insert_statement_type ( + conn_, + object_traits::persist_statement, + insert_image_binding_)); + + persist_->cached (true); + } + + 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])); + + p->cached (true); + } + + 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_)); + + update_->cached (true); + } + + 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 ())); + + erase_->cached (true); + } + + 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]; + bool select_image_truncated_[select_column_count]; + + // Insert binding. The id binding is copied from the hierarchy root. + // + std::size_t insert_image_version_; + std::size_t insert_id_binding_version_; + binding insert_image_binding_; + 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_SQLITE_POLYMORPHIC_OBJECT_STATEMENTS_HXX diff --git a/odb/sqlite/polymorphic-object-statements.txx b/odb/sqlite/polymorphic-object-statements.txx new file mode 100644 index 0000000..5a7efe0 --- /dev/null +++ b/odb/sqlite/polymorphic-object-statements.txx @@ -0,0 +1,141 @@ +// file : odb/sqlite/polymorphic-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // std::memset + +#include +#include + +#include +#include +#include + +namespace odb +{ + namespace sqlite + { + // + // 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_)); + std::memset (discriminator_image_truncated_, + 0, + sizeof (discriminator_image_truncated_)); + + for (std::size_t i (0); + i < discriminator_column_count + managed_optimistic_column_count; + ++i) + { + discriminator_image_bind_[i].truncated = + discriminator_image_truncated_ + i; + } + } + + // + // 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]; + } + + insert_image_version_ = 0; + insert_id_binding_version_ = 0; + update_image_version_ = 0; + update_id_binding_version_ = 0; + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + std::memset ( + select_image_truncated_, 0, sizeof (select_image_truncated_)); + + for (std::size_t i (0); i < select_column_count; ++i) + select_image_bind_[i].truncated = select_image_truncated_ + i; + } + + 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); + 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/sqlite/result.hxx b/odb/sqlite/result.hxx index 2d6574f..92c1bb1 100644 --- a/odb/sqlite/result.hxx +++ b/odb/sqlite/result.hxx @@ -7,9 +7,6 @@ #include -#include -#include - #include #include @@ -40,10 +37,3 @@ namespace odb #include #endif // ODB_SQLITE_RESULT_HXX - -// Include result specializations so that the user code only needs -// to include this header. -// - -#include -#include diff --git a/odb/sqlite/simple-object-result.hxx b/odb/sqlite/simple-object-result.hxx new file mode 100644 index 0000000..8c748bc --- /dev/null +++ b/odb/sqlite/simple-object-result.hxx @@ -0,0 +1,79 @@ +// file : odb/sqlite/simple-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_SIMPLE_OBJECT_RESULT_HXX +#define ODB_SQLITE_SIMPLE_OBJECT_RESULT_HXX + +#include + +#include // std::size_t + +#include + +#include + +#include +#include // query +#include +#include + +namespace odb +{ + namespace sqlite + { + template + class object_result_impl: public odb::object_result_impl, + public result_impl_base + { + public: + typedef odb::object_result_impl base_type; + + typedef typename base_type::object_traits object_traits; + typedef typename base_type::object_type object_type; + 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: + void + load_image (); + + private: + statements_type& statements_; + }; + } +} + +#include + +#include + +#endif // ODB_SQLITE_SIMPLE_OBJECT_RESULT_HXX diff --git a/odb/sqlite/simple-object-result.txx b/odb/sqlite/simple-object-result.txx new file mode 100644 index 0000000..2152a21 --- /dev/null +++ b/odb/sqlite/simple-object-result.txx @@ -0,0 +1,143 @@ +// file : odb/sqlite/simple-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +#include +#include // result_not_cached + +#include + +namespace odb +{ + namespace sqlite + { + template + object_result_impl:: + ~object_result_impl () + { + if (!this->end_) + statement_->free_result (); + } + + template + object_result_impl:: + object_result_impl (const query& q, + details::shared_ptr statement, + statements_type& statements) + : base_type (statements.connection ().database ()), + result_impl_base (q, statement), + statements_ (statements) + { + } + + template + void object_result_impl:: + load (object_type& obj, bool fetch) + { + if (fetch) + load_image (); + + // 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 (statements_.image ()); + object_traits::init (obj, i, &db); + + // 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 () + { + load_image (); + return object_traits::id (statements_.image ()); + } + + template + void object_result_impl:: + next () + { + this->current (pointer_type ()); + + if (!statement_->next ()) + { + statement_->free_result (); + this->end_ = true; + } + } + + template + void object_result_impl:: + load_image () + { + // The image can grow between calls to load() as a result of other + // statements execution. + // + typename object_traits::image_type& im (statements_.image ()); + + if (im.version != statements_.select_image_version ()) + { + binding& b (statements_.select_image_binding ()); + object_traits::bind (b.bind, im, statement_select); + statements_.select_image_version (im.version); + b.version++; + } + + select_statement::result r (statement_->load ()); + + if (r == select_statement::truncated) + { + if (object_traits::grow (im, statements_.select_image_truncated ())) + im.version++; + + if (im.version != statements_.select_image_version ()) + { + binding& b (statements_.select_image_binding ()); + object_traits::bind (b.bind, im, statement_select); + statements_.select_image_version (im.version); + b.version++; + statement_->reload (); + } + } + } + + template + void object_result_impl:: + cache () + { + } + + template + std::size_t object_result_impl:: + size () + { + throw result_not_cached (); + } + } +} diff --git a/odb/sqlite/simple-object-statements.cxx b/odb/sqlite/simple-object-statements.cxx new file mode 100644 index 0000000..110795a --- /dev/null +++ b/odb/sqlite/simple-object-statements.cxx @@ -0,0 +1,16 @@ +// file : odb/sqlite/simple-object-statements.cxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace sqlite + { + object_statements_base:: + ~object_statements_base () + { + } + } +} diff --git a/odb/sqlite/simple-object-statements.hxx b/odb/sqlite/simple-object-statements.hxx new file mode 100644 index 0000000..2cdb16c --- /dev/null +++ b/odb/sqlite/simple-object-statements.hxx @@ -0,0 +1,515 @@ +// file : odb/sqlite/simple-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_SIMPLE_OBJECT_STATEMENTS_HXX +#define ODB_SQLITE_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 sqlite + { + // + // Implementation for objects with object id. + // + + class LIBODB_SQLITE_EXPORT object_statements_base: public statements_base + { + public: + // Locking. + // + 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 sqlite::insert_statement insert_statement_type; + typedef sqlite::select_statement select_statement_type; + typedef sqlite::update_statement update_statement_type; + typedef sqlite::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 statemens 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 statemens. + // + 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_;} + + bool* + select_image_truncated () {return select_image_truncated_;} + + // 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_)); + + persist_->cached (true); + } + + 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_)); + + find_->cached (true); + } + + 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_)); + + update_->cached (true); + } + + 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_)); + + erase_->cached (true); + } + + 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_)); + + od_.erase_->cached (true); + } + + 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]; + bool select_image_truncated_[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_SQLITE_SIMPLE_OBJECT_STATEMENTS_HXX diff --git a/odb/sqlite/simple-object-statements.ixx b/odb/sqlite/simple-object-statements.ixx new file mode 100644 index 0000000..11d4fbc --- /dev/null +++ b/odb/sqlite/simple-object-statements.ixx @@ -0,0 +1,69 @@ +// file : odb/sqlite/simple-object-statements.ixx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace sqlite + { + // + // 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/sqlite/simple-object-statements.txx b/odb/sqlite/simple-object-statements.txx new file mode 100644 index 0000000..ea0b89b --- /dev/null +++ b/odb/sqlite/simple-object-statements.txx @@ -0,0 +1,145 @@ +// file : odb/sqlite/simple-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // std::memset + +#include +#include +#include + +#include + +namespace odb +{ + namespace sqlite + { + // + // 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; + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + std::memset ( + select_image_truncated_, 0, sizeof (select_image_truncated_)); + + for (std::size_t i (0); i < select_column_count; ++i) + select_image_bind_[i].truncated = select_image_truncated_ + i; + } + + 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); + 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/sqlite/statement-cache.hxx b/odb/sqlite/statement-cache.hxx index 8281b22..5d94296 100644 --- a/odb/sqlite/statement-cache.hxx +++ b/odb/sqlite/statement-cache.hxx @@ -11,15 +11,15 @@ #include #include +#include #include #include #include +#include #include #include -#include -#include #include @@ -27,8 +27,6 @@ namespace odb { namespace sqlite { - class connection; - class LIBODB_SQLITE_EXPORT statement_cache { public: @@ -71,38 +69,12 @@ namespace odb } 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: void @@ -129,6 +101,8 @@ namespace odb } } +#include + #include #endif // ODB_SQLITE_STATEMENT_CACHE_HXX diff --git a/odb/sqlite/statement-cache.txx b/odb/sqlite/statement-cache.txx new file mode 100644 index 0000000..b702712 --- /dev/null +++ b/odb/sqlite/statement-cache.txx @@ -0,0 +1,43 @@ +// file : odb/sqlite/statement-cache.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace sqlite + { + 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/sqlite/view-result.hxx b/odb/sqlite/view-result.hxx index fb26e39..82910db 100644 --- a/odb/sqlite/view-result.hxx +++ b/odb/sqlite/view-result.hxx @@ -9,11 +9,12 @@ #include // std::size_t +#include + #include #include #include // query, view_statements -#include #include namespace odb @@ -33,12 +34,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&); @@ -55,7 +58,7 @@ namespace odb using base_type::current; private: - view_statements& statements_; + statements_type& statements_; }; } } diff --git a/odb/sqlite/view-result.txx b/odb/sqlite/view-result.txx index 49d0e68..f2170c9 100644 --- a/odb/sqlite/view-result.txx +++ b/odb/sqlite/view-result.txx @@ -23,7 +23,7 @@ namespace odb view_result_impl:: view_result_impl (const query& q, details::shared_ptr statement, - view_statements& statements) + statements_type& statements) : base_type (statements.connection ().database ()), result_impl_base (q, statement), statements_ (statements) -- cgit v1.1