diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2013-05-06 12:05:39 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2013-08-14 15:19:13 +0200 |
commit | 0745f84e2d5c7133f6ee6608487089d69d7ad519 (patch) | |
tree | bcba1aee153c18ef58396c86632de35360fb5950 | |
parent | 79ccdd960976729e2d46e2d476f54b92c5348a5f (diff) |
Add support for object sections
Sections are an optimization mechanism that allows the partitioning of
data members of a persistent class into groups that can be separately
loaded and/or updated.
-rw-r--r-- | odb/pgsql/database.hxx | 14 | ||||
-rw-r--r-- | odb/pgsql/database.ixx | 14 | ||||
-rw-r--r-- | odb/pgsql/forward.hxx | 3 | ||||
-rw-r--r-- | odb/pgsql/polymorphic-object-statements.hxx | 42 | ||||
-rw-r--r-- | odb/pgsql/section-statements.hxx | 203 | ||||
-rw-r--r-- | odb/pgsql/section-statements.txx | 52 | ||||
-rw-r--r-- | odb/pgsql/simple-object-statements.hxx | 112 | ||||
-rw-r--r-- | odb/pgsql/simple-object-statements.txx | 1 |
8 files changed, 386 insertions, 55 deletions
diff --git a/odb/pgsql/database.hxx b/odb/pgsql/database.hxx index 1b456fb..2a70e96 100644 --- a/odb/pgsql/database.hxx +++ b/odb/pgsql/database.hxx @@ -125,6 +125,12 @@ namespace odb void load (const typename object_traits<T>::id_type& id, T& object); + // Load (or reload, if it is already loaded) a section of an object. + // + template <typename T> + void + load (T& object, section&); + // Reload an object. // template <typename T> @@ -195,6 +201,14 @@ namespace odb void update (const typename object_traits<T>::pointer_type& obj_ptr); + // Update a section of an object. Throws the section_not_loaded + // exception if the section is not loaded. Note also that this + // function does not clear the changed flag if it is set. + // + template <typename T> + void + update (const T& object, const section&); + // Make the object transient. Throw object_not_persistent if not // found. // diff --git a/odb/pgsql/database.ixx b/odb/pgsql/database.ixx index afc3ce7..809e4d4 100644 --- a/odb/pgsql/database.ixx +++ b/odb/pgsql/database.ixx @@ -108,6 +108,13 @@ namespace odb } template <typename T> + inline void database:: + load (T& obj, section& s) + { + return load_<T, id_pgsql> (obj, s); + } + + template <typename T> inline typename object_traits<T>::pointer_type database:: find (const typename object_traits<T>::id_type& id) { @@ -249,6 +256,13 @@ namespace odb template <typename T> inline void database:: + update (const T& obj, const section& s) + { + update_<T, id_pgsql> (obj, s); + } + + template <typename T> + inline void database:: erase (const typename object_traits<T>::id_type& id) { return erase_<T, id_pgsql> (id); diff --git a/odb/pgsql/forward.hxx b/odb/pgsql/forward.hxx index d1a5931..470462e 100644 --- a/odb/pgsql/forward.hxx +++ b/odb/pgsql/forward.hxx @@ -70,6 +70,9 @@ namespace odb template <typename T> class smart_container_statements; + template <typename T, typename ST> + class section_statements; + class query_base; } diff --git a/odb/pgsql/polymorphic-object-statements.hxx b/odb/pgsql/polymorphic-object-statements.hxx index 644a6a2..c538c49 100644 --- a/odb/pgsql/polymorphic-object-statements.hxx +++ b/odb/pgsql/polymorphic-object-statements.hxx @@ -183,8 +183,8 @@ namespace odb base_statements_type; typedef - typename object_traits::container_statement_cache_type - container_statement_cache_type; + typename object_traits::extra_statement_cache_type + extra_statement_cache_type; typedef pgsql::insert_statement insert_statement_type; typedef pgsql::select_statement select_statement_type; @@ -294,6 +294,10 @@ namespace odb binding& id_image_binding () {return root_statements_.id_image_binding ();} + binding& + optimistic_id_image_binding () { + return root_statements_.optimistic_id_image_binding ();} + // Statements. // insert_statement_type& @@ -373,35 +377,43 @@ namespace odb return *erase_; } - // Container statement cache. + // Extra (container, section) statement cache. // - container_statement_cache_type& - container_statment_cache () + extra_statement_cache_type& + extra_statement_cache () { - return container_statement_cache_.get ( + return extra_statement_cache_.get ( conn_, - root_statements_.id_image_binding (), + image_, + id_image_binding (), + &id_image_binding (), // Note, not id+version. root_statements_.id_image_native_binding (), object_traits::find_statement_types); } public: - // select = total - id + base::select + // select = total - id - separate_load + base::select // insert = total - inverse - // update = total - inverse - id - readonly + // update = total - inverse - id - readonly - separate_update // 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 + + object_traits::column_count - + id_column_count - + object_traits::separate_load_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; + 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; + static const std::size_t update_column_count = + insert_column_count - + object_traits::id_column_count - + object_traits::readonly_column_count - + object_traits::separate_update_column_count; private: polymorphic_derived_object_statements ( @@ -414,8 +426,8 @@ namespace odb root_statements_type& root_statements_; base_statements_type& base_statements_; - container_statement_cache_ptr<container_statement_cache_type> - container_statement_cache_; + extra_statement_cache_ptr<extra_statement_cache_type, image_type> + extra_statement_cache_; image_type image_; diff --git a/odb/pgsql/section-statements.hxx b/odb/pgsql/section-statements.hxx new file mode 100644 index 0000000..b2f5c7b --- /dev/null +++ b/odb/pgsql/section-statements.hxx @@ -0,0 +1,203 @@ +// file : odb/pgsql/section-statements.hxx +// copyright : Copyright (c) 2005-2013 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_SECTION_STATEMENTS_HXX +#define ODB_PGSQL_SECTION_STATEMENTS_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/forward.hxx> +#include <odb/traits.hxx> + +#include <odb/pgsql/version.hxx> +#include <odb/pgsql/binding.hxx> +#include <odb/pgsql/statement.hxx> +#include <odb/pgsql/pgsql-fwd.hxx> // Oid +#include <odb/pgsql/details/export.hxx> + +namespace odb +{ + namespace pgsql + { + class connection; + + // Template argument is the section traits type. + // + template <typename T, typename ST> + class section_statements + { + public: + typedef ST traits; + + typedef typename traits::image_type image_type; + + typedef pgsql::select_statement select_statement_type; + typedef pgsql::update_statement update_statement_type; + + typedef pgsql::connection connection_type; + + section_statements (connection_type&, + image_type&, + binding& id, + binding& idv, + native_binding& idn, + const Oid* idt); + + connection_type& + connection () {return conn_;} + + image_type& + image () {return image_;} + + const binding& + id_binding () {return id_binding_;} + + // Id and optimistic concurrency version (if any). + // + const binding& + idv_binding () {return idv_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_;} + + // 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_;} + + // + // Statements. + // + + select_statement_type& + select_statement () + { + if (select_ == 0) + select_.reset ( + new (details::shared) select_statement_type ( + conn_, + traits::select_name, + traits::select_statement, + id_types_, + id_column_count, + id_binding_, + id_native_binding_, + select_image_binding_, + false)); + + return *select_; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + conn_, + traits::update_name, + traits::update_statement, + traits::update_types, + update_column_count + id_column_count + + managed_optimistic_update_column_count, + update_image_binding_, + update_image_native_binding_, + false)); + + return *update_; + } + + public: + static const std::size_t id_column_count = traits::id_column_count; + static const std::size_t managed_optimistic_load_column_count = + traits::managed_optimistic_load_column_count; + static const std::size_t managed_optimistic_update_column_count = + traits::managed_optimistic_update_column_count; + static const std::size_t select_column_count = traits::load_column_count; + static const std::size_t update_column_count = + traits::update_column_count; + + private: + section_statements (const section_statements&); + section_statements& operator= (const section_statements&); + + protected: + connection_type& conn_; + + // These come from object_statements. + // + image_type& image_; + binding& id_binding_; + binding& idv_binding_; + native_binding& id_native_binding_; + const Oid* id_types_; + + // Select binding. + // + std::size_t select_image_version_; + + static const std::size_t select_bind_count = + select_column_count != 0 || managed_optimistic_load_column_count != 0 + ? select_column_count + managed_optimistic_load_column_count + : 1; + + binding select_image_binding_; + bind select_image_bind_[select_bind_count]; + bool select_image_truncated_[select_bind_count]; + + // Update binding. + // + std::size_t update_image_version_; + std::size_t update_id_binding_version_; + + static const std::size_t update_bind_count = + update_column_count != 0 || managed_optimistic_update_column_count != 0 + ? update_column_count + id_column_count + + managed_optimistic_update_column_count + : 1; + + binding update_image_binding_; + bind update_image_bind_[update_bind_count]; + + native_binding update_image_native_binding_; + char* update_image_values_[update_bind_count]; + int update_image_lengths_[update_bind_count]; + int update_image_formats_[update_bind_count]; + + details::shared_ptr<select_statement_type> select_; + details::shared_ptr<update_statement_type> update_; + }; + } +} + +#include <odb/pgsql/section-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_PGSQL_SECTION_STATEMENTS_HXX diff --git a/odb/pgsql/section-statements.txx b/odb/pgsql/section-statements.txx new file mode 100644 index 0000000..d4463d1 --- /dev/null +++ b/odb/pgsql/section-statements.txx @@ -0,0 +1,52 @@ +// file : odb/pgsql/section-statements.txx +// copyright : Copyright (c) 2005-2013 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstring> // std::memset + +namespace odb +{ + namespace pgsql + { + template <typename T, typename ST> + section_statements<T, ST>:: + section_statements (connection_type& conn, + image_type& im, + binding& id, + binding& idv, + native_binding& idn, + const Oid* idt) + : conn_ (conn), + image_ (im), + id_binding_ (id), + idv_binding_ (idv), + id_native_binding_ (idn), + id_types_ (idt), + select_image_binding_ (select_image_bind_, + select_column_count + + managed_optimistic_load_column_count), + update_image_binding_ (update_image_bind_, + update_column_count + id_column_count + + managed_optimistic_update_column_count), + update_image_native_binding_ (update_image_values_, + update_image_lengths_, + update_image_formats_, + update_column_count + id_column_count + + managed_optimistic_update_column_count) + { + select_image_version_ = 0; + update_image_version_ = 0; + update_id_binding_version_ = 0; + + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + std::memset ( + select_image_truncated_, 0, sizeof (select_image_truncated_)); + std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); + + for (std::size_t i (0); + i < select_column_count + managed_optimistic_load_column_count; + ++i) + select_image_bind_[i].truncated = select_image_truncated_ + i; + } + } +} diff --git a/odb/pgsql/simple-object-statements.hxx b/odb/pgsql/simple-object-statements.hxx index f7e3949..5840c26 100644 --- a/odb/pgsql/simple-object-statements.hxx +++ b/odb/pgsql/simple-object-statements.hxx @@ -29,60 +29,70 @@ namespace odb { namespace pgsql { - // The container_statement_cache class is only defined (and used) in + // The extra_statement_cache class is only defined (and used) in // the generated source file. However, object_statements may be // referenced from another source file in the case of a polymorphic - // hierarchy (though in this case the container statement cache is + // hierarchy (though in this case the extra statement cache is // not used). As a result, we cannot have a by-value member and // instead will store a pointer and lazily allocate the cache if // and when needed. We will also need to store a pointer to the // deleter function which will be initialized during allocation // (at that point we know that the cache class is defined). // - template <typename T> - struct container_statement_cache_ptr + template <typename T, typename I> + struct extra_statement_cache_ptr { + typedef I image_type; typedef pgsql::connection connection_type; - container_statement_cache_ptr (): p_ (0) {} - ~container_statement_cache_ptr () + extra_statement_cache_ptr (): p_ (0) {} + ~extra_statement_cache_ptr () { if (p_ != 0) - (this->*deleter_) (0, 0, 0, 0); + (this->*deleter_) (0, 0, 0, 0, 0, 0); } T& get (connection_type& c, - binding& id, native_binding& idn, const Oid* idt) + image_type& im, + binding& id, + binding* idv, + native_binding& idn, + const Oid* idt) { if (p_ == 0) - allocate (&c, &id, &idn, idt); + allocate (&c, &im, &id, (idv != 0 ? idv : &id), &idn, idt); return *p_; } private: void - allocate (connection_type*, binding*, native_binding*, const Oid*); + allocate (connection_type*, + image_type*, + binding*, binding*, native_binding*, const Oid*); private: T* p_; - void (container_statement_cache_ptr::*deleter_) ( - connection_type*, binding*, native_binding*, const Oid*); + void (extra_statement_cache_ptr::*deleter_) ( + connection_type*, + image_type*, + binding*, binding*, native_binding*, const Oid*); }; - template <typename T> - void container_statement_cache_ptr<T>:: + template <typename T, typename I> + void extra_statement_cache_ptr<T, I>:: allocate (connection_type* c, - binding* id, native_binding* idn, const Oid* idt) + image_type* im, + binding* id, binding* idv, native_binding* idn, const Oid* idt) { // To reduce object code size, this function acts as both allocator // and deleter. // if (p_ == 0) { - p_ = new T (*c, *id, *idn, idt); - deleter_ = &container_statement_cache_ptr<T>::allocate; + p_ = new T (*c, *im, *id, *idv, *idn, idt); + deleter_ = &extra_statement_cache_ptr<T, I>::allocate; } else delete p_; @@ -158,9 +168,18 @@ namespace odb optimistic_data (bind*, char** nv, int* nl, int* nf); + binding* + id_image_binding () {return &id_image_binding_;} + + native_binding* + id_image_native_binding () {return &id_image_native_binding_;} + + const Oid* + id_image_types () + {return object_traits::optimistic_erase_statement_types;} + // The id + optimistic column binding. // - std::size_t id_image_version_; binding id_image_binding_; native_binding id_image_native_binding_; @@ -171,6 +190,15 @@ namespace odb struct optimistic_data<T, false> { optimistic_data (bind*, char**, int*, int*) {} + + binding* + id_image_binding () {return 0;} + + native_binding* + id_image_native_binding () {return 0;} + + const Oid* + id_image_types () {return 0;} }; template <typename T> @@ -189,8 +217,8 @@ namespace odb pointer_cache_traits; typedef - typename object_traits::container_statement_cache_type - container_statement_cache_type; + typename object_traits::extra_statement_cache_type + extra_statement_cache_type; typedef pgsql::insert_statement insert_statement_type; typedef pgsql::select_statement select_statement_type; @@ -329,14 +357,10 @@ namespace odb binding& id_image_binding () {return id_image_binding_;} - // Optimistic id + managed column image binding. + // Optimistic id + managed column image binding. It points to + // the same suffix as id binding and they are always updated + // at the same time. // - 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_;} @@ -434,37 +458,44 @@ namespace odb return *od_.erase_; } - // Container statement cache. + // Extra (container, section) statement cache. // - container_statement_cache_type& - container_statment_cache () + extra_statement_cache_type& + extra_statement_cache () { - return container_statement_cache_.get ( + return extra_statement_cache_.get ( conn_, + image_, id_image_binding_, + od_.id_image_binding (), id_image_native_binding_, object_traits::find_statement_types); } public: - // select = total + // select = total - separate_load // insert = total - inverse - managed_optimistic - auto_id - // update = total - inverse - managed_optimistic - id - readonly + // update = total - inverse - managed_optimistic - id - readonly - + // separate_update // static const std::size_t select_column_count = - object_traits::column_count; + object_traits::column_count - + object_traits::separate_load_column_count; static const std::size_t id_column_count = object_traits::id_column_count; static const std::size_t insert_column_count = - object_traits::column_count - object_traits::inverse_column_count - + object_traits::column_count - + object_traits::inverse_column_count - object_traits::managed_optimistic_column_count - (object_traits::auto_id ? id_column_count : 0); - static const std::size_t update_column_count = insert_column_count - + static const std::size_t update_column_count = + insert_column_count - (object_traits::auto_id ? 0 : id_column_count) - - object_traits::readonly_column_count; + object_traits::readonly_column_count - + object_traits::separate_update_column_count; static const std::size_t managed_optimistic_column_count = object_traits::managed_optimistic_column_count; @@ -481,8 +512,11 @@ namespace odb clear_delayed_ (); protected: - container_statement_cache_ptr<container_statement_cache_type> - container_statement_cache_; + template <typename T1> + friend class polymorphic_derived_object_statements; + + extra_statement_cache_ptr<extra_statement_cache_type, image_type> + extra_statement_cache_; image_type image_; diff --git a/odb/pgsql/simple-object-statements.txx b/odb/pgsql/simple-object-statements.txx index 8a8d2a8..999dc9c 100644 --- a/odb/pgsql/simple-object-statements.txx +++ b/odb/pgsql/simple-object-statements.txx @@ -29,7 +29,6 @@ namespace odb object_traits::id_column_count + object_traits::managed_optimistic_column_count) { - id_image_version_ = 0; } // |