diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-23 16:48:02 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-23 16:48:02 +0200 |
commit | 40267e1f40de8ea216688886ab1df1c7ec50e2b2 (patch) | |
tree | 046030dabdd352808c71cf1f2a9bfed706e86c2a | |
parent | 3405fff26a02b5bee51686c5d22200be320b87d8 (diff) |
Polymorphic inheritance support
23 files changed, 1588 insertions, 537 deletions
diff --git a/odb/pgsql/binding.hxx b/odb/pgsql/binding.hxx index 9bb8d4a..cc68723 100644 --- a/odb/pgsql/binding.hxx +++ b/odb/pgsql/binding.hxx @@ -21,7 +21,6 @@ namespace odb class LIBODB_PGSQL_EXPORT native_binding { public: - native_binding (char** v, int* l, int* f, @@ -45,6 +44,8 @@ namespace odb public: typedef pgsql::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/pgsql/forward.hxx b/odb/pgsql/forward.hxx index c56deb8..96b2266 100644 --- a/odb/pgsql/forward.hxx +++ b/odb/pgsql/forward.hxx @@ -38,7 +38,13 @@ namespace odb class object_statements; template <typename T> - class object_statements_no_id; + class polymorphic_root_object_statements; + + template <typename T> + class polymorphic_derived_object_statements; + + template <typename T> + class no_id_object_statements; template <typename T> class view_statements; diff --git a/odb/pgsql/makefile b/odb/pgsql/makefile index 37fedd8..004f061 100644 --- a/odb/pgsql/makefile +++ b/odb/pgsql/makefile @@ -4,22 +4,22 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make -cxx := \ -auto-handle.cxx \ -connection.cxx \ -connection-factory.cxx \ -database.cxx \ -error.cxx \ -exceptions.cxx \ -object-statements.cxx \ -statement.cxx \ -statements-base.cxx \ -tracer.cxx \ -traits.cxx \ -transaction.cxx \ -transaction-impl.cxx \ -query.cxx \ -query-const-expr.cxx \ +cxx := \ +auto-handle.cxx \ +connection.cxx \ +connection-factory.cxx \ +database.cxx \ +error.cxx \ +exceptions.cxx \ +query.cxx \ +query-const-expr.cxx \ +simple-object-statements.cxx \ +statement.cxx \ +statements-base.cxx \ +tracer.cxx \ +traits.cxx \ +transaction.cxx \ +transaction-impl.cxx \ details/endian-traits.cxx cli_tun := details/options.cli diff --git a/odb/pgsql/no-id-object-result.hxx b/odb/pgsql/no-id-object-result.hxx new file mode 100644 index 0000000..0bd3bee --- /dev/null +++ b/odb/pgsql/no-id-object-result.hxx @@ -0,0 +1,70 @@ +// file : odb/pgsql/no-id-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_NO_ID_OBJECT_RESULT_HXX +#define ODB_PGSQL_NO_ID_OBJECT_RESULT_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/no-id-object-result.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/pgsql/version.hxx> +#include <odb/pgsql/forward.hxx> // query +#include <odb/pgsql/statement.hxx> + +namespace odb +{ + namespace pgsql + { + template <typename T> + class no_id_object_result_impl: public odb::no_id_object_result_impl<T> + { + public: + typedef odb::no_id_object_result_impl<T> base_type; + + typedef typename base_type::object_type object_type; + typedef typename base_type::object_traits object_traits; + + typedef typename base_type::pointer_type pointer_type; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename object_traits::statements_type statements_type; + + virtual + ~no_id_object_result_impl (); + + no_id_object_result_impl (const query&, + details::shared_ptr<select_statement>, + statements_type&); + + virtual void + load (object_type&); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + using base_type::current; + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + }; + } +} + +#include <odb/pgsql/no-id-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_PGSQL_NO_ID_OBJECT_RESULT_HXX diff --git a/odb/pgsql/no-id-object-result.txx b/odb/pgsql/no-id-object-result.txx new file mode 100644 index 0000000..98e1b48 --- /dev/null +++ b/odb/pgsql/no-id-object-result.txx @@ -0,0 +1,99 @@ +// file : odb/pgsql/no-id-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/callback.hxx> + +#include <odb/pgsql/no-id-object-statements.hxx> + +namespace odb +{ + namespace pgsql + { + template <typename T> + no_id_object_result_impl<T>:: + ~no_id_object_result_impl () + { + if (!this->end_) + statement_->free_result (); + } + + template <typename T> + no_id_object_result_impl<T>:: + no_id_object_result_impl (const query&, + details::shared_ptr<select_statement> statement, + statements_type& statements) + : base_type (statements.connection ().database ()), + statement_ (statement), + statements_ (statements) + { + } + + template <typename T> + void no_id_object_result_impl<T>:: + 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 <typename T> + void no_id_object_result_impl<T>:: + next () + { + this->current (pointer_type ()); + + if (!statement_->next ()) + { + statement_->free_result (); + this->end_ = true; + } + } + + template <typename T> + void no_id_object_result_impl<T>:: + cache () + { + } + + template <typename T> + std::size_t no_id_object_result_impl<T>:: + size () + { + return statement_->result_size (); + } + } +} diff --git a/odb/pgsql/no-id-object-statements.hxx b/odb/pgsql/no-id-object-statements.hxx new file mode 100644 index 0000000..98e6a48 --- /dev/null +++ b/odb/pgsql/no-id-object-statements.hxx @@ -0,0 +1,143 @@ +// file : odb/pgsql/no-id-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_NO_ID_OBJECT_STATEMENTS_HXX +#define ODB_PGSQL_NO_ID_OBJECT_STATEMENTS_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/forward.hxx> +#include <odb/traits.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/pgsql/version.hxx> +#include <odb/pgsql/forward.hxx> +#include <odb/pgsql/pgsql-types.hxx> +#include <odb/pgsql/binding.hxx> +#include <odb/pgsql/statement.hxx> +#include <odb/pgsql/statements-base.hxx> + +namespace odb +{ + namespace pgsql + { + // + // Implementation for objects without object id. + // + + template <typename T> + class no_id_object_statements: public statements_base + { + public: + typedef T object_type; + typedef odb::object_traits<object_type> object_traits; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::image_type image_type; + + typedef pgsql::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_;} + + 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_name, + object_traits::persist_statement, + object_traits::persist_statement_types, + insert_column_count, + insert_image_binding_, + insert_image_native_binding_, + false, + 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]; + 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]; + native_binding insert_image_native_binding_; + char* insert_image_values_[insert_column_count]; + int insert_image_lengths_[insert_column_count]; + int insert_image_formats_[insert_column_count]; + + details::shared_ptr<insert_statement_type> persist_; + }; + } +} + +#include <odb/pgsql/no-id-object-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_PGSQL_NO_ID_OBJECT_STATEMENTS_HXX diff --git a/odb/pgsql/no-id-object-statements.txx b/odb/pgsql/no-id-object-statements.txx new file mode 100644 index 0000000..3fec01c --- /dev/null +++ b/odb/pgsql/no-id-object-statements.txx @@ -0,0 +1,47 @@ +// file : odb/pgsql/no-id-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstring> // std::memset + +namespace odb +{ + namespace pgsql + { + // + // no_id_object_statements + // + + template <typename T> + no_id_object_statements<T>:: + ~no_id_object_statements () + { + } + + template <typename T> + no_id_object_statements<T>:: + no_id_object_statements (connection_type& conn) + : statements_base (conn), + // select + select_image_binding_ (select_image_bind_, select_column_count), + // insert + insert_image_binding_ (insert_image_bind_, insert_column_count), + insert_image_native_binding_ (insert_image_values_, + insert_image_lengths_, + insert_image_formats_, + 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/pgsql/object-result.hxx b/odb/pgsql/object-result.hxx deleted file mode 100644 index 72d38dd..0000000 --- a/odb/pgsql/object-result.hxx +++ /dev/null @@ -1,113 +0,0 @@ -// file : odb/pgsql/object-result.hxx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#ifndef ODB_PGSQL_OBJECT_RESULT_HXX -#define ODB_PGSQL_OBJECT_RESULT_HXX - -#include <odb/pre.hxx> - -#include <cstddef> // std::size_t - -#include <odb/details/shared-ptr.hxx> - -#include <odb/pgsql/version.hxx> -#include <odb/pgsql/forward.hxx> // query, object_statements -#include <odb/pgsql/result.hxx> -#include <odb/pgsql/statement.hxx> - -namespace odb -{ - namespace pgsql - { - template <typename T> - class object_result_impl: public odb::object_result_impl<T> - { - public: - typedef odb::object_result_impl<T> base_type; - - typedef typename base_type::object_type object_type; - typedef typename base_type::object_traits object_traits; - typedef typename base_type::id_type id_type; - - typedef typename base_type::pointer_type pointer_type; - typedef typename base_type::pointer_traits pointer_traits; - - virtual - ~object_result_impl (); - - object_result_impl (const query&, - details::shared_ptr<select_statement>, - object_statements<object_type>&); - - virtual void - load (object_type&, bool fetch); - - virtual id_type - load_id (); - - virtual void - next (); - - virtual void - cache (); - - virtual std::size_t - size (); - - using base_type::current; - - private: - void - load_image (); - - private: - details::shared_ptr<select_statement> statement_; - object_statements<object_type>& statements_; - }; - - template <typename T> - class object_result_impl_no_id: public odb::object_result_impl_no_id<T> - { - public: - typedef odb::object_result_impl_no_id<T> base_type; - - typedef typename base_type::object_type object_type; - typedef typename base_type::object_traits object_traits; - - typedef typename base_type::pointer_type pointer_type; - typedef typename base_type::pointer_traits pointer_traits; - - virtual - ~object_result_impl_no_id (); - - object_result_impl_no_id (const query&, - details::shared_ptr<select_statement>, - object_statements_no_id<object_type>&); - - virtual void - load (object_type&); - - virtual void - next (); - - virtual void - cache (); - - virtual std::size_t - size (); - - using base_type::current; - - private: - details::shared_ptr<select_statement> statement_; - object_statements_no_id<object_type>& statements_; - }; - } -} - -#include <odb/pgsql/object-result.txx> - -#include <odb/post.hxx> - -#endif // ODB_PGSQL_OBJECT_RESULT_HXX diff --git a/odb/pgsql/polymorphic-object-result.hxx b/odb/pgsql/polymorphic-object-result.hxx new file mode 100644 index 0000000..9dc8dcd --- /dev/null +++ b/odb/pgsql/polymorphic-object-result.hxx @@ -0,0 +1,86 @@ +// file : odb/pgsql/polymorphic-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_POLYMORPHIC_OBJECT_RESULT_HXX +#define ODB_PGSQL_POLYMORPHIC_OBJECT_RESULT_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/polymorphic-object-result.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/pgsql/version.hxx> +#include <odb/pgsql/forward.hxx> // query +#include <odb/pgsql/statement.hxx> + +namespace odb +{ + namespace pgsql + { + template <typename T> + class polymorphic_object_result_impl: + public odb::polymorphic_object_result_impl<T> + { + public: + typedef odb::polymorphic_object_result_impl<T> base_type; + + typedef typename base_type::object_type object_type; + typedef typename base_type::object_traits object_traits; + typedef typename base_type::id_type id_type; + + typedef typename base_type::pointer_type pointer_type; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename base_type::root_type root_type; + typedef typename base_type::root_traits root_traits; + typedef typename base_type::discriminator_type discriminator_type; + + typedef typename object_traits::statements_type statements_type; + + virtual + ~polymorphic_object_result_impl (); + + polymorphic_object_result_impl (const query&, + details::shared_ptr<select_statement>, + statements_type&); + + virtual void + load (object_type*, bool fetch); + + virtual id_type + load_id (); + + virtual discriminator_type + load_discriminator (); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + using base_type::current; + + private: + void + load_image (); + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + }; + } +} + +#include <odb/pgsql/polymorphic-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_PGSQL_POLYMORPHIC_OBJECT_RESULT_HXX diff --git a/odb/pgsql/polymorphic-object-result.txx b/odb/pgsql/polymorphic-object-result.txx new file mode 100644 index 0000000..14104d0 --- /dev/null +++ b/odb/pgsql/polymorphic-object-result.txx @@ -0,0 +1,266 @@ +// file : odb/pgsql/polymorphic-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cassert> + +#include <odb/callback.hxx> +#include <odb/cache-traits.hxx> +#include <odb/exceptions.hxx> // object_not_persistent + +#include <odb/pgsql/polymorphic-object-statements.hxx> + +namespace odb +{ + namespace pgsql + { + template <typename T> + polymorphic_object_result_impl<T>:: + ~polymorphic_object_result_impl () + { + if (!this->end_) + statement_->free_result (); + } + + template <typename T> + polymorphic_object_result_impl<T>:: + polymorphic_object_result_impl (const query&, + details::shared_ptr<select_statement> st, + statements_type& sts) + : base_type (sts.connection ().database ()), + statement_ (st), + statements_ (sts) + { + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + 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<object_type> (rp)); + + // Insert it as a root pointer (for non-unique pointers, rp should + // still be valid and for unique pointers this is a no-op). + // + ig.reset (object_traits::pointer_cache_traits::insert (db, id, rp)); + + pobj = &pointer_traits::get_ref (p); + current (p); + } + else + { + // We are loading into an existing instance. If the static and + // dynamic types differ, then make sure the instance is at least + // of the dynamic type. + // + if (&pi != &object_traits::info) + { + const info_type& dpi (root_traits::map->find (typeid (*pobj))); + + if (&dpi != &pi && dpi.derived (pi)) + throw object_not_persistent (); // @@ type_mismatch ? + } + } + + callback_event ce (callback_event::pre_load); + pi.dispatch (info_type::call_callback, db, pobj, &ce); + + object_traits::init (*pobj, i, &db); + + // Initialize the id image and binding and load the rest of the object + // (containers, dynamic part, etc). + // + typename object_traits::id_image_type& idi (statements_.id_image ()); + root_traits::init (idi, id); + + binding& idb (statements_.id_image_binding ()); + if (idi.version != statements_.id_image_version () || idb.version == 0) + { + object_traits::bind (idb.bind, idi); + statements_.id_image_version (idi.version); + idb.version++; + } + + object_traits::load_ (statements_, *pobj); + + // Load the dynamic part of the object unless static and dynamic + // types are the same. + // + if (&pi != &object_traits::info) + { + std::size_t d (object_traits::depth); + pi.dispatch (info_type::call_load, db, pobj, &d); + }; + + rsts.load_delayed (); + l.unlock (); + + ce = callback_event::post_load; + pi.dispatch (info_type::call_callback, db, pobj, &ce); + ig.release (); + } + + template <typename T> + typename polymorphic_object_result_impl<T>::id_type + polymorphic_object_result_impl<T>:: + load_id () + { + load_image (); + return root_traits::id (statements_.root_statements ().image ()); + } + + template <typename T> + typename polymorphic_object_result_impl<T>::discriminator_type + polymorphic_object_result_impl<T>:: + load_discriminator () + { + load_image (); + return root_traits::discriminator ( + statements_.root_statements ().image ()); + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + next () + { + this->current (pointer_type ()); + + if (!statement_->next ()) + { + statement_->free_result (); + this->end_ = true; + } + } + + template <typename T, typename R> + struct polymorphic_image_rebind + { + // Derived type version. + // + typedef object_traits<T> traits; + + static bool + rebind (typename traits::statements_type& sts) + { + typename traits::image_type& im (sts.image ()); + + if (traits::check_version (sts.select_image_versions (), im)) + { + binding& b (sts.select_image_binding (traits::depth)); + traits::bind (b.bind, 0, 0, im, statement_select); + traits::update_version ( + sts.select_image_versions (), im, sts.select_image_bindings ()); + return true; + } + + return false; + } + }; + + template <typename R> + struct polymorphic_image_rebind<R, R> + { + // Root type version. + // + typedef object_traits<R> traits; + + static bool + rebind (typename traits::statements_type& sts) + { + typename traits::image_type& im (sts.image ()); + + if (im.version != sts.select_image_version ()) + { + binding& b (sts.select_image_binding ()); + traits::bind (b.bind, im, statement_select); + sts.select_image_version (im.version); + b.version++; + return true; + } + + return false; + } + }; + + template <typename T> + void polymorphic_object_result_impl<T>:: + load_image () + { + typedef polymorphic_image_rebind<object_type, root_type> 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 <typename T> + void polymorphic_object_result_impl<T>:: + cache () + { + } + + template <typename T> + std::size_t polymorphic_object_result_impl<T>:: + size () + { + return statement_->result_size (); + } + } +} diff --git a/odb/pgsql/polymorphic-object-statements.hxx b/odb/pgsql/polymorphic-object-statements.hxx new file mode 100644 index 0000000..43dd55e --- /dev/null +++ b/odb/pgsql/polymorphic-object-statements.hxx @@ -0,0 +1,475 @@ +// file : odb/pgsql/polymorphic-object-statements.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX +#define ODB_PGSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/forward.hxx> +#include <odb/traits.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/pgsql/version.hxx> +#include <odb/pgsql/forward.hxx> +#include <odb/pgsql/pgsql-types.hxx> +#include <odb/pgsql/binding.hxx> +#include <odb/pgsql/statement.hxx> +#include <odb/pgsql/statements-base.hxx> +#include <odb/pgsql/simple-object-statements.hxx> + +namespace odb +{ + namespace pgsql + { + // + // Implementation for polymorphic objects. + // + + template <typename T> + class polymorphic_root_object_statements: public object_statements<T> + { + public: + typedef typename object_statements<T>::connection_type connection_type; + typedef typename object_statements<T>::object_traits object_traits; + typedef typename object_statements<T>::id_image_type id_image_type; + + typedef + typename object_traits::discriminator_image_type + discriminator_image_type; + + typedef + typename object_statements<T>::select_statement_type + select_statement_type; + + public: + // Interface compatibility with derived_object_statements. + // + typedef polymorphic_root_object_statements root_statements_type; + + root_statements_type& + root_statements () + { + return *this; + } + + public: + // Discriminator binding. + // + discriminator_image_type& + discriminator_image () {return discriminator_image_;} + + std::size_t + discriminator_image_version () const + {return discriminator_image_version_;} + + void + discriminator_image_version (std::size_t v) + {discriminator_image_version_ = v;} + + binding& + discriminator_image_binding () {return discriminator_image_binding_;} + + 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_;} + + // Expose id native binding from object_statements. + // + native_binding& + id_image_native_binding () {return this->id_image_native_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_name, + object_traits::find_discriminator_statement, + object_traits::find_statement_types, // The same as find (id). + id_column_count, + discriminator_id_image_binding_, + discriminator_id_image_native_binding_, + discriminator_image_binding_, + false)); + + return *find_discriminator_; + } + + public: + polymorphic_root_object_statements (connection_type&); + + virtual + ~polymorphic_root_object_statements (); + + public: + static const std::size_t id_column_count = + object_statements<T>::id_column_count; + + static const std::size_t discriminator_column_count = + object_traits::discriminator_column_count; + + static const std::size_t managed_optimistic_column_count = + object_traits::managed_optimistic_column_count; + + private: + // Discriminator image. + // + discriminator_image_type discriminator_image_; + std::size_t discriminator_image_version_; + binding discriminator_image_binding_; + 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_; + native_binding discriminator_id_image_native_binding_; + bind discriminator_id_image_bind_[id_column_count]; + char* discriminator_id_image_values_[id_column_count]; + int discriminator_id_image_lengths_[id_column_count]; + int discriminator_id_image_formats_[id_column_count]; + + details::shared_ptr<select_statement_type> find_discriminator_; + }; + + template <typename T> + class polymorphic_derived_object_statements: public statements_base + { + public: + typedef T object_type; + typedef odb::object_traits<object_type> object_traits; + typedef typename object_traits::id_type id_type; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::id_image_type id_image_type; + typedef typename object_traits::image_type image_type; + + typedef typename object_traits::root_type root_type; + typedef + polymorphic_root_object_statements<root_type> + root_statements_type; + + typedef typename object_traits::base_type base_type; + typedef + typename object_traits::base_traits::statements_type + base_statements_type; + + typedef + typename object_traits::container_statement_cache_type + container_statement_cache_type; + + typedef pgsql::insert_statement insert_statement_type; + typedef pgsql::select_statement select_statement_type; + typedef pgsql::update_statement update_statement_type; + typedef pgsql::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_name, + object_traits::persist_statement, + object_traits::persist_statement_types, + insert_column_count, + insert_image_binding_, + insert_image_native_binding_, + object_traits::auto_id, + false)); + + return *persist_; + } + + select_statement_type& + find_statement (std::size_t d) + { + std::size_t i (object_traits::depth - d); + details::shared_ptr<select_statement_type>& p (find_[i]); + + if (p == 0) + p.reset ( + new (details::shared) select_statement_type ( + conn_, + object_traits::find_statement_names[i], + object_traits::find_statements[i], + object_traits::find_statement_types, + id_column_count, + root_statements_.id_image_binding (), + root_statements_.id_image_native_binding (), + select_image_bindings_[i], + false)); + + return *p; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + conn_, + object_traits::update_statement_name, + object_traits::update_statement, + object_traits::update_statement_types, + update_column_count + id_column_count, + update_image_binding_, + update_image_native_binding_, + false)); + + return *update_; + } + + delete_statement_type& + erase_statement () + { + if (erase_ == 0) + erase_.reset ( + new (details::shared) delete_statement_type ( + conn_, + object_traits::erase_statement_name, + object_traits::erase_statement, + object_traits::find_statement_types, // The same as find (id). + id_column_count, + root_statements_.id_image_binding (), + root_statements_.id_image_native_binding (), + false)); + + return *erase_; + } + + // Container statement cache. + // + container_statement_cache_type& + container_statment_cache () + { + return container_statement_cache_; + } + + public: + // select = total - id + base::select + // insert = total - inverse + // update = total - inverse - id - readonly + // + static const std::size_t id_column_count = + object_traits::id_column_count; + + static const std::size_t select_column_count = + object_traits::column_count - id_column_count + + base_statements_type::select_column_count; + + static const std::size_t insert_column_count = + object_traits::column_count - object_traits::inverse_column_count; + + static const std::size_t update_column_count = insert_column_count - + object_traits::id_column_count - object_traits::readonly_column_count; + + private: + polymorphic_derived_object_statements ( + const polymorphic_derived_object_statements&); + + polymorphic_derived_object_statements& + operator= (const polymorphic_derived_object_statements&); + + private: + root_statements_type& root_statements_; + base_statements_type& base_statements_; + + container_statement_cache_type container_statement_cache_; + + image_type image_; + + // Select binding. Here we are have an array of statements/bindings + // one for each depth. In other words, if we have classes root, base, + // and derived, then we have the following array of statements: + // + // [0] d + b + r + // [1] d + b + // [2] d + // + // Also, because we have a chain of images bound to these statements, + // we have an array of versions, one entry for each base plus one for + // our own image. + // + // A poly-abstract class only needs the first statement and in this + // case we have only one entry in the the bindings and statements + // arrays (but not versions; we still have a chain of images). + // + std::size_t select_image_versions_[object_traits::depth]; + binding select_image_bindings_[ + object_traits::abstract ? 1 : object_traits::depth]; + 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]; + native_binding insert_image_native_binding_; + char* insert_image_values_[insert_column_count]; + int insert_image_lengths_[insert_column_count]; + int insert_image_formats_[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]; + native_binding update_image_native_binding_; + char* update_image_values_[update_column_count + id_column_count]; + int update_image_lengths_[update_column_count + id_column_count]; + int update_image_formats_[update_column_count + id_column_count]; + + details::shared_ptr<insert_statement_type> persist_; + details::shared_ptr<select_statement_type> find_[ + object_traits::abstract ? 1 : object_traits::depth]; + details::shared_ptr<update_statement_type> update_; + details::shared_ptr<delete_statement_type> erase_; + }; + } +} + +#include <odb/pgsql/polymorphic-object-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_PGSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX diff --git a/odb/pgsql/polymorphic-object-statements.txx b/odb/pgsql/polymorphic-object-statements.txx new file mode 100644 index 0000000..2f10b22 --- /dev/null +++ b/odb/pgsql/polymorphic-object-statements.txx @@ -0,0 +1,154 @@ +// file : odb/pgsql/polymorphic-object-statements.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstring> // std::memset + +#include <odb/callback.hxx> +#include <odb/exceptions.hxx> + +#include <odb/pgsql/connection.hxx> +#include <odb/pgsql/transaction.hxx> +#include <odb/pgsql/statement-cache.hxx> + +namespace odb +{ + namespace pgsql + { + // + // polymorphic_root_object_statements + // + + template <typename T> + polymorphic_root_object_statements<T>:: + ~polymorphic_root_object_statements () + { + } + + template <typename T> + polymorphic_root_object_statements<T>:: + polymorphic_root_object_statements (connection_type& conn) + : object_statements<T> (conn), + discriminator_image_binding_ (discriminator_image_bind_, + discriminator_column_count + + managed_optimistic_column_count), + discriminator_id_image_binding_ (discriminator_id_image_bind_, + id_column_count), + discriminator_id_image_native_binding_ ( + discriminator_id_image_values_, + discriminator_id_image_lengths_, + discriminator_id_image_formats_, + 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 <typename T> + polymorphic_derived_object_statements<T>:: + ~polymorphic_derived_object_statements () + { + } + + template <typename T> + polymorphic_derived_object_statements<T>:: + polymorphic_derived_object_statements (connection_type& conn) + : statements_base (conn), + root_statements_ (conn.statement_cache ().find_object<root_type> ()), + base_statements_ (conn.statement_cache ().find_object<base_type> ()), + container_statement_cache_ (conn), + insert_image_binding_ (insert_image_bind_, insert_column_count), + insert_image_native_binding_ (insert_image_values_, + insert_image_lengths_, + insert_image_formats_, + insert_column_count), + update_image_binding_ (update_image_bind_, + update_column_count + id_column_count), + update_image_native_binding_ (update_image_values_, + update_image_lengths_, + update_image_formats_, + 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 <typename T> + void polymorphic_derived_object_statements<T>:: + delayed_loader (odb::database& db, const id_type& id, root_type& robj) + { + connection_type& conn (transaction::current ().connection ()); + polymorphic_derived_object_statements& sts ( + conn.statement_cache ().find_object<object_type> ()); + root_statements_type& rsts (sts.root_statements ()); + + object_type& obj (static_cast<object_type&> (robj)); + + // The same code as in object_statements::load_delayed_(). + // + if (!object_traits::find_ (sts, &id)) + throw object_not_persistent (); + + object_traits::callback (db, obj, callback_event::pre_load); + object_traits::init (obj, sts.image (), &db); + object_traits::load_ (sts, obj); // Load containers, etc. + + rsts.load_delayed (); + + { + typename root_statements_type::auto_unlock u (rsts); + object_traits::callback (db, obj, callback_event::post_load); + } + } + } +} diff --git a/odb/pgsql/result.hxx b/odb/pgsql/result.hxx deleted file mode 100644 index 0862f27..0000000 --- a/odb/pgsql/result.hxx +++ /dev/null @@ -1,25 +0,0 @@ -// file : odb/pgsql/result.hxx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#ifndef ODB_PGSQL_RESULT_HXX -#define ODB_PGSQL_RESULT_HXX - -#include <odb/pre.hxx> - -#include <odb/traits.hxx> -#include <odb/result.hxx> - -#include <odb/pgsql/version.hxx> -#include <odb/pgsql/forward.hxx> - -#include <odb/post.hxx> - -#endif // ODB_PGSQL_RESULT_HXX - -// Include result specializations so that the user code only needs -// to include this header. -// - -#include <odb/pgsql/object-result.hxx> -#include <odb/pgsql/view-result.hxx> diff --git a/odb/pgsql/simple-object-result.hxx b/odb/pgsql/simple-object-result.hxx new file mode 100644 index 0000000..5edee2c --- /dev/null +++ b/odb/pgsql/simple-object-result.hxx @@ -0,0 +1,78 @@ +// file : odb/pgsql/simple-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_SIMPLE_OBJECT_RESULT_HXX +#define ODB_PGSQL_SIMPLE_OBJECT_RESULT_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/simple-object-result.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/pgsql/version.hxx> +#include <odb/pgsql/forward.hxx> // query +#include <odb/pgsql/statement.hxx> + +namespace odb +{ + namespace pgsql + { + template <typename T> + class object_result_impl: public odb::object_result_impl<T> + { + public: + typedef odb::object_result_impl<T> base_type; + + typedef typename base_type::object_type object_type; + typedef typename base_type::object_traits object_traits; + typedef typename base_type::id_type id_type; + + typedef typename base_type::pointer_type pointer_type; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename object_traits::statements_type statements_type; + + virtual + ~object_result_impl (); + + object_result_impl (const query&, + details::shared_ptr<select_statement>, + statements_type&); + + virtual void + load (object_type&, bool fetch); + + virtual id_type + load_id (); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + using base_type::current; + + private: + void + load_image (); + + private: + details::shared_ptr<select_statement> statement_; + statements_type& statements_; + }; + } +} + +#include <odb/pgsql/simple-object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_PGSQL_SIMPLE_OBJECT_RESULT_HXX diff --git a/odb/pgsql/object-result.txx b/odb/pgsql/simple-object-result.txx index c5334cc..f7b2e1c 100644 --- a/odb/pgsql/object-result.txx +++ b/odb/pgsql/simple-object-result.txx @@ -1,4 +1,4 @@ -// file : odb/pgsql/object-result.txx +// file : odb/pgsql/simple-object-result.txx // copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file @@ -6,16 +6,12 @@ #include <odb/callback.hxx> -#include <odb/pgsql/object-statements.hxx> +#include <odb/pgsql/simple-object-statements.hxx> namespace odb { namespace pgsql { - // - // object_result_impl - // - template <typename T> object_result_impl<T>:: ~object_result_impl () @@ -28,7 +24,7 @@ namespace odb object_result_impl<T>:: object_result_impl (const query&, details::shared_ptr<select_statement> statement, - object_statements<object_type>& statements) + statements_type& statements) : base_type (statements.connection ().database ()), statement_ (statement), statements_ (statements) @@ -45,7 +41,7 @@ namespace odb // This is a top-level call so the statements cannot be locked. // assert (!statements_.locked ()); - typename object_statements<object_type>::auto_lock l (statements_); + typename statements_type::auto_lock l (statements_); odb::database& db (this->database ()); object_traits::callback (db, obj, callback_event::pre_load); @@ -142,95 +138,5 @@ namespace odb { return statement_->result_size (); } - - // - // object_result_impl_no_id - // - - template <typename T> - object_result_impl_no_id<T>:: - ~object_result_impl_no_id () - { - if (!this->end_) - statement_->free_result (); - } - - template <typename T> - object_result_impl_no_id<T>:: - object_result_impl_no_id (const query&, - details::shared_ptr<select_statement> statement, - object_statements_no_id<object_type>& statements) - : base_type (statements.connection ().database ()), - statement_ (statement), - statements_ (statements) - { - } - - template <typename T> - void object_result_impl_no_id<T>:: - 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 <typename T> - void object_result_impl_no_id<T>:: - next () - { - this->current (pointer_type ()); - - if (!statement_->next ()) - { - statement_->free_result (); - this->end_ = true; - } - } - - template <typename T> - void object_result_impl_no_id<T>:: - cache () - { - } - - template <typename T> - std::size_t object_result_impl_no_id<T>:: - size () - { - return statement_->result_size (); - } } } diff --git a/odb/pgsql/object-statements.cxx b/odb/pgsql/simple-object-statements.cxx index 6e07a11..4788812 100644 --- a/odb/pgsql/object-statements.cxx +++ b/odb/pgsql/simple-object-statements.cxx @@ -1,8 +1,8 @@ -// file : odb/pgsql/object-statements.cxx +// file : odb/pgsql/simple-object-statements.cxx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#include <odb/pgsql/object-statements.hxx> +#include <odb/pgsql/simple-object-statements.hxx> namespace odb { diff --git a/odb/pgsql/object-statements.hxx b/odb/pgsql/simple-object-statements.hxx index 215d5e6..37bd16c 100644 --- a/odb/pgsql/object-statements.hxx +++ b/odb/pgsql/simple-object-statements.hxx @@ -1,9 +1,9 @@ -// file : odb/pgsql/object-statements.hxx +// file : odb/pgsql/simple-object-statements.hxx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#ifndef ODB_PGSQL_OBJECT_STATEMENTS_HXX -#define ODB_PGSQL_OBJECT_STATEMENTS_HXX +#ifndef ODB_PGSQL_SIMPLE_OBJECT_STATEMENTS_HXX +#define ODB_PGSQL_SIMPLE_OBJECT_STATEMENTS_HXX #include <odb/pre.hxx> @@ -18,6 +18,8 @@ #include <odb/details/shared-ptr.hxx> #include <odb/pgsql/version.hxx> +#include <odb/pgsql/forward.hxx> +#include <odb/pgsql/pgsql-types.hxx> #include <odb/pgsql/binding.hxx> #include <odb/pgsql/statement.hxx> #include <odb/pgsql/statements-base.hxx> @@ -28,24 +30,6 @@ namespace odb { namespace pgsql { - template <typename T> - class object_statements; - - template <typename T> - class object_statements_no_id; - - template <typename T, typename ID = typename object_traits<T>::id_type> - struct object_statements_selector - { - typedef object_statements<T> type; - }; - - template <typename T> - struct object_statements_selector<T, void> - { - typedef object_statements_no_id<T> type; - }; - // // Implementation for objects with object id. // @@ -75,16 +59,6 @@ namespace odb return locked_; } - public: - virtual - ~object_statements_base (); - - protected: - object_statements_base (connection_type& conn) - : statements_base (conn), locked_ (false) - { - } - struct auto_unlock { // Unlocks the statement on construction and re-locks it on @@ -101,6 +75,16 @@ namespace odb object_statements_base& s_; }; + public: + virtual + ~object_statements_base (); + + protected: + object_statements_base (connection_type& conn) + : statements_base (conn), locked_ (false) + { + } + protected: bool locked_; }; @@ -142,7 +126,9 @@ namespace odb typedef typename object_traits::image_type image_type; typedef typename object_traits::id_image_type id_image_type; - typedef pointer_cache_traits<pointer_type> object_cache_traits; + typedef + typename object_traits::pointer_cache_traits + pointer_cache_traits; typedef typename object_traits::container_statement_cache_type @@ -196,12 +182,16 @@ namespace odb // Delayed loading. // + typedef void (*loader_function) ( + odb::database&, const id_type&, object_type&); + void delay_load (const id_type& id, object_type& obj, - const typename object_cache_traits::position_type& p) + const typename pointer_cache_traits::position_type& p, + loader_function l = 0) { - delayed_.push_back (delayed_load (id, obj, p)); + delayed_.push_back (delayed_load (id, obj, p, l)); } void @@ -298,7 +288,6 @@ namespace odb persist_statement () { if (persist_ == 0) - { persist_.reset ( new (details::shared) insert_statement_type ( conn_, @@ -310,7 +299,6 @@ namespace odb insert_image_native_binding_, object_traits::auto_id, false)); - } return *persist_; } @@ -319,7 +307,6 @@ namespace odb find_statement () { if (find_ == 0) - { find_.reset ( new (details::shared) select_statement_type ( conn_, @@ -331,7 +318,6 @@ namespace odb id_image_native_binding_, select_image_binding_, false)); - } return *find_; } @@ -340,7 +326,6 @@ namespace odb update_statement () { if (update_ == 0) - { update_.reset ( new (details::shared) update_statement_type ( conn_, @@ -351,7 +336,6 @@ namespace odb update_image_binding_, update_image_native_binding_, false)); - } return *update_; } @@ -360,18 +344,16 @@ namespace odb erase_statement () { if (erase_ == 0) - { erase_.reset ( new (details::shared) delete_statement_type ( conn_, object_traits::erase_statement_name, object_traits::erase_statement, - object_traits::erase_statement_types, + object_traits::find_statement_types, // The same as find (id). id_column_count, id_image_binding_, id_image_native_binding_, false)); - } return *erase_; } @@ -380,7 +362,6 @@ namespace odb optimistic_erase_statement () { if (od_.erase_ == 0) - { od_.erase_.reset ( new (details::shared) delete_statement_type ( conn_, @@ -391,7 +372,6 @@ namespace odb od_.id_image_binding_, od_.id_image_native_binding_, false)); - } return *od_.erase_; } @@ -404,18 +384,7 @@ namespace odb return container_statement_cache_; } - private: - object_statements (const object_statements&); - object_statements& operator= (const object_statements&); - - private: - void - load_delayed_ (); - - void - clear_delayed_ (); - - private: + public: // select = total // insert = total - inverse - managed_optimistic // update = total - inverse - managed_optimistic - id - readonly @@ -437,6 +406,17 @@ namespace odb object_traits::managed_optimistic_column_count; private: + object_statements (const object_statements&); + object_statements& operator= (const object_statements&); + + private: + void + load_delayed_ (); + + void + clear_delayed_ (); + + protected: container_statement_cache_type container_statement_cache_; image_type image_; @@ -500,17 +480,21 @@ namespace odb // struct delayed_load { - typedef typename object_cache_traits::position_type position_type; + typedef typename pointer_cache_traits::position_type position_type; delayed_load () {} - delayed_load (const id_type& i, object_type& o, const position_type& p) - : id (i), obj (&o), pos (p) + delayed_load (const id_type& i, + object_type& o, + const position_type& p, + loader_function l) + : id (i), obj (&o), pos (p), loader (l) { } id_type id; object_type* obj; position_type pos; + loader_function loader; }; typedef std::vector<delayed_load> delayed_loads; @@ -538,123 +522,12 @@ namespace odb delayed_loads& dl_; }; }; - - // - // Implementation for objects without object id. - // - - template <typename T> - class object_statements_no_id: public statements_base - { - public: - typedef T object_type; - typedef odb::object_traits<object_type> object_traits; - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::image_type image_type; - - typedef pgsql::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_;} - - 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_name, - object_traits::persist_statement, - object_traits::persist_statement_types, - insert_column_count, - insert_image_binding_, - insert_image_native_binding_, - false, - 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]; - 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]; - native_binding insert_image_native_binding_; - char* insert_image_values_[insert_column_count]; - int insert_image_lengths_[insert_column_count]; - int insert_image_formats_[insert_column_count]; - - details::shared_ptr<insert_statement_type> persist_; - }; } } -#include <odb/pgsql/object-statements.ixx> -#include <odb/pgsql/object-statements.txx> +#include <odb/pgsql/simple-object-statements.ixx> +#include <odb/pgsql/simple-object-statements.txx> #include <odb/post.hxx> -#endif // ODB_PGSQL_OBJECT_STATEMENTS_HXX +#endif // ODB_PGSQL_SIMPLE_OBJECT_STATEMENTS_HXX diff --git a/odb/pgsql/object-statements.ixx b/odb/pgsql/simple-object-statements.ixx index 5a82b42..6f2d209 100644 --- a/odb/pgsql/object-statements.ixx +++ b/odb/pgsql/simple-object-statements.ixx @@ -1,4 +1,4 @@ -// file : odb/pgsql/object-statements.ixx +// file : odb/pgsql/simple-object-statements.ixx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file diff --git a/odb/pgsql/object-statements.txx b/odb/pgsql/simple-object-statements.txx index 2b21f76..8e391d7 100644 --- a/odb/pgsql/object-statements.txx +++ b/odb/pgsql/simple-object-statements.txx @@ -1,8 +1,7 @@ -// file : odb/pgsql/object-statements.txx +// file : odb/pgsql/simple-object-statements.txx // copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#include <cstddef> // std::size_t #include <cstring> // std::memset #include <odb/session.hxx> @@ -111,36 +110,41 @@ namespace odb while (!dls.empty ()) { delayed_load l (dls.back ()); - typename object_cache_traits::insert_guard g (l.pos); + typename pointer_cache_traits::insert_guard g (l.pos); dls.pop_back (); - if (!object_traits::find_ (*this, l.id)) - throw object_not_persistent (); - - object_traits::callback (db, *l.obj, callback_event::pre_load); - - // Our calls to init/load below can result in additional delayed - // loads being added to the delayed_ vector. We need to process - // those before we call the post callback. - // - object_traits::init (*l.obj, image (), &db); - object_traits::load_ (*this, *l.obj); // Load containers, etc. - - if (!delayed_.empty ()) - load_delayed_ (); - - // Temporarily unlock the statement for the post_load call so that - // it can load objects of this type recursively. This is safe to do - // because we have completely loaded the current object. Also the - // delayed_ list is clear before the unlock and should be clear on - // re-lock (since a callback can only call public API functions - // which will make sure all the delayed loads are processed before - // returning). - // + if (l.loader == 0) { - auto_unlock u (*this); - object_traits::callback (db, *l.obj, callback_event::post_load); + if (!object_traits::find_ (*this, &l.id)) + throw object_not_persistent (); + + object_traits::callback (db, *l.obj, callback_event::pre_load); + + // Our calls to init/load below can result in additional delayed + // loads being added to the delayed_ vector. We need to process + // those before we call the post callback. + // + object_traits::init (*l.obj, image (), &db); + object_traits::load_ (*this, *l.obj); // Load containers, etc. + + if (!delayed_.empty ()) + load_delayed_ (); + + // Temporarily unlock the statement for the post_load call so that + // it can load objects of this type recursively. This is safe to do + // because we have completely loaded the current object. Also the + // delayed_ list is clear before the unlock and should be clear on + // re-lock (since a callback can only call public API functions + // which will make sure all the delayed loads are processed before + // returning). + // + { + auto_unlock u (*this); + object_traits::callback (db, *l.obj, callback_event::post_load); + } } + else + l.loader (db, l.id, *l.obj); g.release (); } @@ -157,47 +161,11 @@ namespace odb for (typename delayed_loads::iterator i (delayed_.begin ()), e (delayed_.end ()); i != e; ++i) { - object_cache_traits::erase (i->pos); + pointer_cache_traits::erase (i->pos); } } delayed_.clear (); } - - // - // object_statements_no_id - // - - template <typename T> - object_statements_no_id<T>:: - ~object_statements_no_id () - { - } - - template <typename T> - object_statements_no_id<T>:: - object_statements_no_id (connection_type& conn) - : statements_base (conn), - // select - select_image_binding_ (select_image_bind_, select_column_count), - // insert - insert_image_binding_ (insert_image_bind_, insert_column_count), - insert_image_native_binding_ (insert_image_values_, - insert_image_lengths_, - insert_image_formats_, - 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/pgsql/statement-cache.hxx b/odb/pgsql/statement-cache.hxx index dc9d171..90bc2f6 100644 --- a/odb/pgsql/statement-cache.hxx +++ b/odb/pgsql/statement-cache.hxx @@ -11,14 +11,14 @@ #include <typeinfo> #include <odb/forward.hxx> +#include <odb/traits.hxx> #include <odb/details/shared-ptr.hxx> #include <odb/details/type-info.hxx> #include <odb/pgsql/version.hxx> +#include <odb/pgsql/forward.hxx> #include <odb/pgsql/statements-base.hxx> -#include <odb/pgsql/object-statements.hxx> -#include <odb/pgsql/view-statements.hxx> #include <odb/pgsql/details/export.hxx> @@ -26,49 +26,18 @@ namespace odb { namespace pgsql { - class connection; - class LIBODB_PGSQL_EXPORT statement_cache { public: - statement_cache (connection& conn) - : conn_ (conn) - { - } + statement_cache (connection& conn): conn_ (conn) {} template <typename T> - typename object_statements_selector<T>::type& - find_object () - { - typedef typename object_statements_selector<T>::type object_statements; - - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast<object_statements&> (*i->second); - - details::shared_ptr<object_statements> p ( - new (details::shared) object_statements (conn_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } + typename object_traits<T>::statements_type& + find_object (); template <typename T> view_statements<T>& - find_view () - { - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast<view_statements<T>&> (*i->second); - - details::shared_ptr<view_statements<T> > p ( - new (details::shared) view_statements<T> (conn_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } + find_view (); private: typedef std::map<const std::type_info*, @@ -81,6 +50,8 @@ namespace odb } } +#include <odb/pgsql/statement-cache.txx> + #include <odb/post.hxx> #endif // ODB_PGSQL_STATEMENT_CACHE_HXX diff --git a/odb/pgsql/statement-cache.txx b/odb/pgsql/statement-cache.txx new file mode 100644 index 0000000..40ed170 --- /dev/null +++ b/odb/pgsql/statement-cache.txx @@ -0,0 +1,43 @@ +// file : odb/pgsql/statement-cache.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace pgsql + { + template <typename T> + typename object_traits<T>::statements_type& statement_cache:: + find_object () + { + typedef typename object_traits<T>::statements_type statements_type; + + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast<statements_type&> (*i->second); + + details::shared_ptr<statements_type> p ( + new (details::shared) statements_type (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } + + template <typename T> + view_statements<T>& statement_cache:: + find_view () + { + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast<view_statements<T>&> (*i->second); + + details::shared_ptr<view_statements<T> > p ( + new (details::shared) view_statements<T> (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } + } +} diff --git a/odb/pgsql/view-result.hxx b/odb/pgsql/view-result.hxx index 84a910d..341065d 100644 --- a/odb/pgsql/view-result.hxx +++ b/odb/pgsql/view-result.hxx @@ -9,11 +9,12 @@ #include <cstddef> // std::size_t +#include <odb/view-result.hxx> + #include <odb/details/shared-ptr.hxx> #include <odb/pgsql/version.hxx> #include <odb/pgsql/forward.hxx> // query, view_statements -#include <odb/pgsql/result.hxx> #include <odb/pgsql/statement.hxx> namespace odb @@ -32,12 +33,14 @@ namespace odb typedef typename base_type::pointer_type pointer_type; typedef typename base_type::pointer_traits pointer_traits; + typedef view_statements<view_type> statements_type; + virtual ~view_result_impl (); view_result_impl (const query&, details::shared_ptr<select_statement>, - view_statements<view_type>&); + statements_type&); virtual void load (view_type&); @@ -55,7 +58,7 @@ namespace odb private: details::shared_ptr<select_statement> statement_; - view_statements<view_type>& statements_; + statements_type& statements_; }; } } diff --git a/odb/pgsql/view-result.txx b/odb/pgsql/view-result.txx index 2219463..932d19b 100644 --- a/odb/pgsql/view-result.txx +++ b/odb/pgsql/view-result.txx @@ -22,7 +22,7 @@ namespace odb view_result_impl<T>:: view_result_impl (const query&, details::shared_ptr<select_statement> statement, - view_statements<view_type>& statements) + statements_type& statements) : base_type (statements.connection ().database ()), statement_ (statement), statements_ (statements) |