From 9715f388db714fb663b854883e4cad5f2aa3c860 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 2 Sep 2013 08:33:25 +0200 Subject: Support for versioning simple value in object --- odb/pgsql/no-id-object-result.hxx | 5 +- odb/pgsql/no-id-object-result.txx | 12 +-- odb/pgsql/polymorphic-object-result.hxx | 5 +- odb/pgsql/polymorphic-object-result.txx | 26 +++--- odb/pgsql/polymorphic-object-statements.hxx | 18 +++- odb/pgsql/polymorphic-object-statements.txx | 13 ++- odb/pgsql/simple-object-result.hxx | 6 +- odb/pgsql/simple-object-result.txx | 14 +-- odb/pgsql/simple-object-statements.hxx | 16 ++-- odb/pgsql/simple-object-statements.txx | 19 ++-- odb/pgsql/statement-cache.hxx | 5 +- odb/pgsql/statement-cache.txx | 13 +++ odb/pgsql/statement.cxx | 44 +++++----- odb/pgsql/traits-calls.hxx | 132 ++++++++++++++++++++++++++++ 14 files changed, 261 insertions(+), 67 deletions(-) create mode 100644 odb/pgsql/traits-calls.hxx diff --git a/odb/pgsql/no-id-object-result.hxx b/odb/pgsql/no-id-object-result.hxx index 0fabf9e..83f3ce9 100644 --- a/odb/pgsql/no-id-object-result.hxx +++ b/odb/pgsql/no-id-object-result.hxx @@ -16,6 +16,7 @@ #include #include // query_base #include +#include namespace odb { @@ -40,7 +41,8 @@ namespace odb no_id_object_result_impl (const query_base&, details::shared_ptr, - statements_type&); + statements_type&, + const schema_version_migration*); virtual void load (object_type&); @@ -62,6 +64,7 @@ namespace odb private: details::shared_ptr statement_; statements_type& statements_; + traits_calls tc_; std::size_t count_; }; } diff --git a/odb/pgsql/no-id-object-result.txx b/odb/pgsql/no-id-object-result.txx index c65fa56..4b3f1ab 100644 --- a/odb/pgsql/no-id-object-result.txx +++ b/odb/pgsql/no-id-object-result.txx @@ -35,10 +35,12 @@ namespace odb no_id_object_result_impl:: no_id_object_result_impl (const query_base&, details::shared_ptr statement, - statements_type& statements) + statements_type& statements, + const schema_version_migration* svm) : base_type (statements.connection ()), statement_ (statement), statements_ (statements), + tc_ (svm), count_ (0) { } @@ -55,7 +57,7 @@ namespace odb if (im.version != statements_.select_image_version ()) { binding& b (statements_.select_image_binding ()); - object_traits::bind (b.bind, im, statement_select); + tc_.bind (b.bind, im, statement_select); statements_.select_image_version (im.version); b.version++; } @@ -64,13 +66,13 @@ namespace odb if (r == select_statement::truncated) { - if (object_traits::grow (im, statements_.select_image_truncated ())) + if (tc_.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); + tc_.bind (b.bind, im, statement_select); statements_.select_image_version (im.version); b.version++; statement_->reload (); @@ -78,7 +80,7 @@ namespace odb } object_traits::callback (this->db_, obj, callback_event::pre_load); - object_traits::init (obj, im, &this->db_); + tc_.init (obj, im, &this->db_); object_traits::callback (this->db_, obj, callback_event::post_load); } diff --git a/odb/pgsql/polymorphic-object-result.hxx b/odb/pgsql/polymorphic-object-result.hxx index a7d5077..acbfd43 100644 --- a/odb/pgsql/polymorphic-object-result.hxx +++ b/odb/pgsql/polymorphic-object-result.hxx @@ -16,6 +16,7 @@ #include #include // query_base #include +#include namespace odb { @@ -47,7 +48,8 @@ namespace odb polymorphic_object_result_impl (const query_base&, details::shared_ptr, - statements_type&); + statements_type&, + const schema_version_migration*); virtual void load (object_type*, bool fetch); @@ -79,6 +81,7 @@ namespace odb private: details::shared_ptr statement_; statements_type& statements_; + traits_calls tc_; std::size_t count_; }; } diff --git a/odb/pgsql/polymorphic-object-result.txx b/odb/pgsql/polymorphic-object-result.txx index 4b956bd..233d7ce 100644 --- a/odb/pgsql/polymorphic-object-result.txx +++ b/odb/pgsql/polymorphic-object-result.txx @@ -38,10 +38,12 @@ namespace odb polymorphic_object_result_impl:: polymorphic_object_result_impl (const query_base&, details::shared_ptr st, - statements_type& sts) + statements_type& sts, + const schema_version_migration* svm) : base_type (sts.connection ()), statement_ (st), statements_ (sts), + tc_ (svm), count_ (0) { } @@ -121,7 +123,7 @@ namespace odb callback_event ce (callback_event::pre_load); pi.dispatch (info_type::call_callback, this->db_, pobj, &ce); - object_traits::init (*pobj, i, &this->db_); + tc_.init (*pobj, i, &this->db_); // Initialize the id image and binding and load the rest of the object // (containers, dynamic part, etc). @@ -148,7 +150,7 @@ namespace odb pi.dispatch (info_type::call_load, this->db_, pobj, &d); }; - rsts.load_delayed (); + rsts.load_delayed (tc_.version ()); l.unlock (); ce = callback_event::post_load; @@ -199,14 +201,16 @@ namespace odb typedef object_traits_impl traits; static bool - rebind (typename traits::statements_type& sts) + rebind (typename traits::statements_type& sts, + const schema_version_migration* svm) { 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_calls tc (svm); + tc.bind (b.bind, 0, 0, im, statement_select); traits::update_version ( sts.select_image_versions (), im, sts.select_image_bindings ()); return true; @@ -224,14 +228,16 @@ namespace odb typedef object_traits_impl traits; static bool - rebind (typename traits::statements_type& sts) + rebind (typename traits::statements_type& sts, + const schema_version_migration* svm) { 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); + traits_calls tc (svm); + tc.bind (b.bind, im, statement_select); sts.select_image_version (im.version); b.version++; return true; @@ -250,7 +256,7 @@ namespace odb // The image can grow between calls to load() as a result of other // statements execution. // - image_rebind::rebind (statements_); + image_rebind::rebind (statements_, tc_.version ()); select_statement::result r (statement_->load ()); @@ -258,10 +264,10 @@ namespace odb { typename object_traits::image_type& im (statements_.image ()); - if (object_traits::grow (im, statements_.select_image_truncated ())) + if (tc_.grow (im, statements_.select_image_truncated ())) im.version++; - if (image_rebind::rebind (statements_)) + if (image_rebind::rebind (statements_, tc_.version ())) statement_->reload (); } } diff --git a/odb/pgsql/polymorphic-object-statements.hxx b/odb/pgsql/polymorphic-object-statements.hxx index 93f711a..f5ddcea 100644 --- a/odb/pgsql/polymorphic-object-statements.hxx +++ b/odb/pgsql/polymorphic-object-statements.hxx @@ -128,6 +128,18 @@ namespace odb virtual ~polymorphic_root_object_statements (); + // Static "override" (statements type). + // + void + load_delayed (const schema_version_migration* svm) + { + assert (this->locked ()); + + if (!this->delayed_.empty ()) + this->template load_delayed_ ( + svm); + } + public: static const std::size_t id_column_count = object_statements::id_column_count; @@ -205,8 +217,10 @@ namespace odb // Delayed loading. // static void - delayed_loader (odb::database&, const id_type&, root_type&); - + delayed_loader (odb::database&, + const id_type&, + root_type&, + const schema_version_migration*); public: // Root and immediate base statements. // diff --git a/odb/pgsql/polymorphic-object-statements.txx b/odb/pgsql/polymorphic-object-statements.txx index 56a20a4..cc8d31a 100644 --- a/odb/pgsql/polymorphic-object-statements.txx +++ b/odb/pgsql/polymorphic-object-statements.txx @@ -124,7 +124,10 @@ namespace odb template void polymorphic_derived_object_statements:: - delayed_loader (odb::database& db, const id_type& id, root_type& robj) + delayed_loader (odb::database& db, + const id_type& id, + root_type& robj, + const schema_version_migration* svm) { connection_type& conn (transaction::current ().connection ()); polymorphic_derived_object_statements& sts ( @@ -135,14 +138,16 @@ namespace odb // The same code as in object_statements::load_delayed_(). // - if (!object_traits::find_ (sts, &id)) + traits_calls tc (svm); + + if (!tc.find_ (sts, &id)) throw object_not_persistent (); object_traits::callback (db, obj, callback_event::pre_load); - object_traits::init (obj, sts.image (), &db); + tc.init (obj, sts.image (), &db); object_traits::load_ (sts, obj); // Load containers, etc. - rsts.load_delayed (); + rsts.load_delayed (svm); { typename root_statements_type::auto_unlock u (rsts); diff --git a/odb/pgsql/simple-object-result.hxx b/odb/pgsql/simple-object-result.hxx index b2e04c9..e6a558b 100644 --- a/odb/pgsql/simple-object-result.hxx +++ b/odb/pgsql/simple-object-result.hxx @@ -9,6 +9,7 @@ #include // std::size_t +#include #include #include @@ -16,6 +17,7 @@ #include #include // query_base #include +#include namespace odb { @@ -41,7 +43,8 @@ namespace odb object_result_impl (const query_base&, details::shared_ptr, - statements_type&); + statements_type&, + const schema_version_migration*); virtual void load (object_type&, bool fetch); @@ -70,6 +73,7 @@ namespace odb private: details::shared_ptr statement_; statements_type& statements_; + traits_calls tc_; std::size_t count_; }; } diff --git a/odb/pgsql/simple-object-result.txx b/odb/pgsql/simple-object-result.txx index f1fdd7e..02d8e6d 100644 --- a/odb/pgsql/simple-object-result.txx +++ b/odb/pgsql/simple-object-result.txx @@ -37,10 +37,12 @@ namespace odb object_result_impl:: object_result_impl (const query_base&, details::shared_ptr statement, - statements_type& statements) + statements_type& statements, + const schema_version_migration* svm) : base_type (statements.connection ()), statement_ (statement), statements_ (statements), + tc_ (svm), count_ (0) { } @@ -60,7 +62,7 @@ namespace odb object_traits::callback (this->db_, obj, callback_event::pre_load); typename object_traits::image_type& i (statements_.image ()); - object_traits::init (obj, i, &this->db_); + tc_.init (obj, i, &this->db_); // Initialize the id image and binding and load the rest of the object // (containers, etc). @@ -77,7 +79,7 @@ namespace odb } object_traits::load_ (statements_, obj); - statements_.load_delayed (); + statements_.load_delayed (tc_.version ()); l.unlock (); object_traits::callback (this->db_, obj, callback_event::post_load); } @@ -118,7 +120,7 @@ namespace odb if (im.version != statements_.select_image_version ()) { binding& b (statements_.select_image_binding ()); - object_traits::bind (b.bind, im, statement_select); + tc_.bind (b.bind, im, statement_select); statements_.select_image_version (im.version); b.version++; } @@ -127,13 +129,13 @@ namespace odb if (r == select_statement::truncated) { - if (object_traits::grow (im, statements_.select_image_truncated ())) + if (tc_.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); + tc_.bind (b.bind, im, statement_select); statements_.select_image_version (im.version); b.version++; statement_->reload (); diff --git a/odb/pgsql/simple-object-statements.hxx b/odb/pgsql/simple-object-statements.hxx index a8d7ce3..afa869a 100644 --- a/odb/pgsql/simple-object-statements.hxx +++ b/odb/pgsql/simple-object-statements.hxx @@ -268,9 +268,10 @@ namespace odb // Delayed loading. // - typedef void (*loader_function) ( - odb::database&, const id_type&, object_type&); - + typedef void (*loader_function) (odb::database&, + const id_type&, + object_type&, + const schema_version_migration*); void delay_load (const id_type& id, object_type& obj, @@ -281,12 +282,12 @@ namespace odb } void - load_delayed () + load_delayed (const schema_version_migration* svm) { assert (locked ()); if (!delayed_.empty ()) - load_delayed_ (); + load_delayed_ (svm); } void @@ -508,9 +509,10 @@ namespace odb object_statements (const object_statements&); object_statements& operator= (const object_statements&); - private: + protected: + template void - load_delayed_ (); + load_delayed_ (const schema_version_migration*); void clear_delayed_ (); diff --git a/odb/pgsql/simple-object-statements.txx b/odb/pgsql/simple-object-statements.txx index 999dc9c..5933aa5 100644 --- a/odb/pgsql/simple-object-statements.txx +++ b/odb/pgsql/simple-object-statements.txx @@ -8,6 +8,7 @@ #include #include +#include namespace odb { @@ -96,8 +97,9 @@ namespace odb } template + template void object_statements:: - load_delayed_ () + load_delayed_ (const schema_version_migration* svm) { database& db (connection ().database ()); @@ -112,7 +114,9 @@ namespace odb if (l.loader == 0) { - if (!object_traits::find_ (*this, &l.id)) + traits_calls tc (svm); + + if (!tc.find_ (static_cast (*this), &l.id)) throw object_not_persistent (); object_traits::callback (db, *l.obj, callback_event::pre_load); @@ -121,11 +125,14 @@ namespace odb // 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. + tc.init (*l.obj, image (), &db); + + // Load containers, etc. + // + object_traits::load_ (static_cast (*this), *l.obj); if (!delayed_.empty ()) - load_delayed_ (); + load_delayed_ (svm); // Temporarily unlock the statement for the post_load call so that // it can load objects of this type recursively. This is safe to do @@ -141,7 +148,7 @@ namespace odb } } else - l.loader (db, l.id, *l.obj); + l.loader (db, l.id, *l.obj, svm); pointer_cache_traits::load (ig.position ()); ig.release (); diff --git a/odb/pgsql/statement-cache.hxx b/odb/pgsql/statement-cache.hxx index 6a4c645..3ad4644 100644 --- a/odb/pgsql/statement-cache.hxx +++ b/odb/pgsql/statement-cache.hxx @@ -29,7 +29,9 @@ namespace odb class LIBODB_PGSQL_EXPORT statement_cache { public: - statement_cache (connection& conn): conn_ (conn) {} + statement_cache (connection& conn) + : conn_ (conn), + version_seq_ (conn.database ().schema_version_sequence ()) {} template typename object_traits_impl::statements_type& @@ -45,6 +47,7 @@ namespace odb details::type_info_comparator> map; connection& conn_; + unsigned int version_seq_; map map_; }; } diff --git a/odb/pgsql/statement-cache.txx b/odb/pgsql/statement-cache.txx index 1a35d38..48bc9da 100644 --- a/odb/pgsql/statement-cache.txx +++ b/odb/pgsql/statement-cache.txx @@ -15,6 +15,16 @@ namespace odb typename object_traits_impl::statements_type statements_type; + // Clear the cache if the database version has changed. This + // makes sure we don't re-use statements that correspond to + // the old schema. + // + if (version_seq_ != conn_.database ().schema_version_sequence ()) + { + map_.clear (); + version_seq_ = conn_.database ().schema_version_sequence (); + } + map::iterator i (map_.find (&typeid (T))); if (i != map_.end ()) @@ -31,6 +41,9 @@ namespace odb view_statements& statement_cache:: find_view () { + // We don't cache any statements for views so no need to clear + // the cache. + map::iterator i (map_.find (&typeid (T))); if (i != map_.end ()) diff --git a/odb/pgsql/statement.cxx b/odb/pgsql/statement.cxx index feebe06..b65eb5b 100644 --- a/odb/pgsql/statement.cxx +++ b/odb/pgsql/statement.cxx @@ -228,7 +228,8 @@ namespace odb n.formats[i] = 1; - if (current_bind.is_null != 0 && *current_bind.is_null) + if (current_bind.buffer == 0 || // Skip NULL entries. + (current_bind.is_null != 0 && *current_bind.is_null)) { n.values[i] = 0; n.lengths[i] = 0; @@ -312,19 +313,18 @@ namespace odb bool truncated) { bool r (true); - int int_row (static_cast (row)); + int col_count (PQnfields (result)); - // Make sure that the number of columns in the result returned by - // the database matches the number that we expect. A common cause - // of this assertion is a native view with a number of data members - // not matching the number of columns in the SELECT-list. - // - assert (static_cast (PQnfields (result)) == count); - - for (int i (0); i < static_cast (count); ++i) + int col (0); + for (size_t i (0); i != count && col != col_count; ++i) { const bind& b (p[i]); + if (b.buffer == 0) // Skip NULL entries. + continue; + + int c (col++); + if (truncated && (b.truncated == 0 || !*b.truncated)) continue; @@ -335,13 +335,13 @@ namespace odb // if (!truncated) { - *b.is_null = PQgetisnull (result, int_row, i) == 1; + *b.is_null = PQgetisnull (result, static_cast (row), c) == 1; if (*b.is_null) continue; } - const char* v (PQgetvalue (result, int_row, i)); + const char* v (PQgetvalue (result, static_cast (row), c)); switch (b.type) { @@ -349,47 +349,40 @@ namespace odb { *static_cast (b.buffer) = *reinterpret_cast (v); - break; } case bind::smallint: { *static_cast (b.buffer) = *reinterpret_cast (v); - break; } case bind::integer: { *static_cast (b.buffer) = *reinterpret_cast (v); - break; } case bind::bigint: { *static_cast (b.buffer) = *reinterpret_cast (v); - break; } case bind::real: { *static_cast (b.buffer) = *reinterpret_cast (v); - break; } case bind::double_: { *static_cast (b.buffer) = *reinterpret_cast (v); - break; } case bind::date: { *static_cast (b.buffer) = *reinterpret_cast (v); - break; } case bind::time: @@ -397,7 +390,6 @@ namespace odb { *static_cast (b.buffer) = *reinterpret_cast (v); - break; } case bind::numeric: @@ -406,7 +398,8 @@ namespace odb case bind::bit: case bind::varbit: { - *b.size = static_cast (PQgetlength (result, int_row, i)); + *b.size = static_cast ( + PQgetlength (result, static_cast (row), c)); if (b.capacity < *b.size) { @@ -418,18 +411,23 @@ namespace odb } memcpy (b.buffer, v, *b.size); - break; } case bind::uuid: { memcpy (b.buffer, v, 16); - break; } } } + // Make sure that the number of columns in the result returned by + // the database matches the number that we expect. A common cause + // of this assertion is a native view with a number of data members + // not matching the number of columns in the SELECT-list. + // + assert (col == col_count); + return r; } diff --git a/odb/pgsql/traits-calls.hxx b/odb/pgsql/traits-calls.hxx new file mode 100644 index 0000000..5f2e11b --- /dev/null +++ b/odb/pgsql/traits-calls.hxx @@ -0,0 +1,132 @@ +// file : odb/pgsql/traits-calls.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_TRAITS_CALLS_HXX +#define ODB_PGSQL_TRAITS_CALLS_HXX + +#include + +#include // std::size_t + +#include +#include +#include + +#include +#include + +namespace odb +{ + namespace pgsql + { + template ::versioned> + struct traits_calls; + + template + struct traits_calls + { + typedef object_traits_impl traits; + typedef typename traits::image_type image_type; + typedef pgsql::bind bind_type; + + traits_calls (const schema_version_migration*) {} + + const schema_version_migration* + version () const {return 0;} + + static bool + grow (image_type& i, bool* t) + { + return traits::grow (i, t); + } + + static void + bind (bind_type* b, image_type& i, statement_kind sk) + { + traits::bind (b, i, sk); + } + + // Poly-derived version. + // + static void + bind (bind_type* b, + const bind_type* id, std::size_t id_size, + image_type& i, + statement_kind sk) + { + traits::bind (b, id, id_size, i, sk); + } + + static void + init (T& o, const image_type& i, odb::database* db) + { + traits::init (o, i, db); + } + + static bool + find_ (typename traits::statements_type& sts, + const typename traits::id_type* id) + { + return traits::find_ (sts, id); + } + }; + + template + struct traits_calls + { + typedef object_traits_impl traits; + typedef typename traits::image_type image_type; + typedef pgsql::bind bind_type; + + traits_calls (const schema_version_migration* svm): svm_ (*svm) {} + + const schema_version_migration* + version () const {return &svm_;} + + bool + grow (image_type& i, bool* t) const + { + return traits::grow (i, t, svm_); + } + + void + bind (bind_type* b, image_type& i, statement_kind sk) const + { + traits::bind (b, i, sk, svm_); + } + + // Poly-derived version. + // + void + bind (bind_type* b, + const bind_type* id, std::size_t id_size, + image_type& i, + statement_kind sk) const + { + traits::bind (b, id, id_size, i, sk, svm_); + } + + void + init (T& o, const image_type& i, odb::database* db) const + { + traits::init (o, i, db, svm_); + } + + bool + find_ (typename traits::statements_type& sts, + const typename traits::id_type* id) const + { + return traits::find_ (sts, id, svm_); + } + + private: + const schema_version_migration& svm_; + }; + } +} + +#include + +#endif // ODB_PGSQL_TRAITS_CALLS_HXX -- cgit v1.1