From 654826cdafaac4199c8a8c90ef3396e312f0944f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 5 Sep 2013 13:02:10 +0200 Subject: Versioned section support --- odb/context.cxx | 66 ++++++++++-- odb/context.hxx | 18 +++- odb/processor.cxx | 114 ++++++++++++++++++-- odb/relational/header.hxx | 47 +++++++-- odb/relational/inline.hxx | 41 +++++++- odb/relational/pgsql/source.cxx | 26 ++++- odb/relational/processor.cxx | 6 ++ odb/relational/source.cxx | 172 +++++++++++++++++++++++++----- odb/relational/source.hxx | 226 ++++++++++++++++++++++++++++++++++------ odb/validator.cxx | 116 ++++++++++----------- 10 files changed, 685 insertions(+), 147 deletions(-) (limited to 'odb') diff --git a/odb/context.cxx b/odb/context.cxx index ad0b889..bbde65a 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -342,6 +342,13 @@ count (unsigned short f) const (f & count_special_version) == 0) continue; + // Skip non-versioned sections if we are only interested in the + // versioned ones. + // + if ((f & count_versioned_only) != 0 && + !context::added (*i->member) && !context::deleted (*i->member)) + continue; + bool ovd (i->base != 0 && poly_derived); if (i->load != user_section::load_eager) @@ -2402,8 +2409,25 @@ namespace if (discriminator (m)) c_.discriminator++; - if (added (member_path_) || deleted (member_path_)) - c_.soft++; + { + unsigned long long av (added (member_path_)); + unsigned long long dv (deleted (member_path_)); + + // If the addition/deletion version is the same as the section's, + // then don't count. + // + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + + if (av != 0 || dv != 0) + c_.soft++; + } if (separate_load (member_path_)) c_.separate_load++; @@ -2482,8 +2506,7 @@ namespace // Ignore added/deleted members if so requested. // - if (((flags_ & exclude_added) != 0 && added (member_path_)) || - ((flags_ & exclude_deleted) != 0 && deleted (member_path_))) + if (check_soft ()) return; if (context::is_a (member_path_, member_scope_, flags_)) @@ -2497,8 +2520,7 @@ namespace { // Ignore added/deleted members if so requested. // - if (((flags_ & exclude_added) != 0 && added (member_path_)) || - ((flags_ & exclude_deleted) != 0 && deleted (member_path_))) + if (check_soft ()) return; if (context::is_a (member_path_, member_scope_, flags_)) @@ -2510,8 +2532,7 @@ namespace { // Ignore added/deleted members if so requested. // - if (((flags_ & exclude_added) != 0 && added (member_path_)) || - ((flags_ & exclude_deleted) != 0 && deleted (member_path_))) + if (check_soft ()) return; // Ignore versioned containers if so requested. @@ -2546,6 +2567,35 @@ namespace } private: + bool + check_soft () + { + if ((flags_ & exclude_added) != 0 || (flags_ & exclude_deleted) != 0) + { + unsigned long long av (added (member_path_)); + unsigned long long dv (deleted (member_path_)); + + // If the addition/deletion version is the same as the section's, + // then don't exclude. + // + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + + if ((av != 0 && (flags_ & exclude_added) != 0) || + (dv != 0 && (flags_ & exclude_deleted) != 0)) + return true; + } + + return false; + } + + private: size_t r_; unsigned short flags_; }; diff --git a/odb/context.hxx b/odb/context.hxx index 9bd0057..9e7ac0a 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -347,8 +347,9 @@ struct user_section: object_section special_type s = special_ordinary) : member (&m), object (&o), base (0), index (i), load (l), update (u), special (s), - total (0), inverse (0), readonly (0), - containers (false), readwrite_containers (false) {} + total (0), inverse (0), readonly (0), versioned (false), + containers (false), readwrite_containers (false), + versioned_containers (false), readwrite_versioned_containers (false) {} virtual bool compare (object_section const& s) const; @@ -399,9 +400,14 @@ struct user_section: object_section std::size_t inverse; std::size_t readonly; + bool versioned; + bool containers; bool readwrite_containers; + bool versioned_containers; + bool readwrite_versioned_containers; + // Total counts across overrides. // std::size_t @@ -475,10 +481,18 @@ struct user_sections: std::list // static unsigned short const count_optimistic = 0x10; + // Modifiers: + // + // Don't exclude fake optimistic version update section from the count. // static unsigned short const count_special_version = 0x20; + // Only count versioned sections. + // + static unsigned short const count_versioned_only = 0x40; + + // Count all sections, including special. // static unsigned short const count_all = count_update | diff --git a/odb/processor.cxx b/odb/processor.cxx index 14370c4..adf1b87 100644 --- a/odb/processor.cxx +++ b/odb/processor.cxx @@ -738,7 +738,7 @@ namespace // If the section is in the base, handle polymorphic inheritance. // class_& b (dynamic_cast (us.scope ())); - object_section* s (0); + user_section* s (0); if (&c != &b && poly_derived) { @@ -789,7 +789,80 @@ namespace else s = &process_user_section (us, c); - m.set ("section", s); // Insert as object_section. + // Mark the member as added/deleted if the section is added/deleted. + // Also check that the version ordering is correct. + // + if (unsigned long long sav = added (*s->member)) + { + location_t sl (s->member->get ("added-location")); + + if (unsigned long long mav = added (m)) + { + location_t ml (m.get ("added-location")); + + if (mav < sav) + { + error (ml) << "member addition version is less than the " << + "section addition version" << endl; + info (sl) << "section addition version is specified here" << + endl; + throw operation_failed (); + } + + if (mav == sav) + { + error (ml) << "member addition version is the same as " << + "section addition version" << endl; + info (sl) << "section addition version is specified here" << + endl; + info (ml) << "delete this pragma" << endl; + throw operation_failed (); + } + } + else + { + m.set ("added", sav); + m.set ("added-location", sl); + } + } + + if (unsigned long long sdv = deleted (*s->member)) + { + location_t sl (s->member->get ("deleted-location")); + + if (unsigned long long mdv = deleted (m)) + { + location_t ml (m.get ("deleted-location")); + + if (mdv > sdv) + { + error (ml) << "member deletion version is greater than the " << + "section deletion version" << endl; + info (sl) << "section deletion version is specified here" << + endl; + throw operation_failed (); + } + + if (mdv == sdv) + { + error (ml) << "member deletion version is the same as " << + "section deletion version" << endl; + info (sl) << "section deletion version is specified here" << + endl; + info (ml) << "delete this pragma" << endl; + throw operation_failed (); + } + } + else + { + m.set ("deleted", sdv); + m.set ("deleted-location", sl); + } + } + + // Insert as object_section. + // + m.set ("section", static_cast (s)); } catch (semantics::unresolved const& e) { @@ -2203,8 +2276,33 @@ namespace i->inverse = cc.inverse; i->readonly = cc.readonly; - if ((i->containers = has_a (c, test_container, &*i))) - i->readwrite_containers = has_a (c, test_readwrite_container, &*i); + // Figure out if we are versioned. We are versioned if we have + // soft-added/deleted columns ourselves or our poly-base is + // versioned. + // + if (force_versioned || cc.soft != 0 || + (poly_derived && i->base != 0 && i->base->versioned)) + i->versioned = true; + + if (size_t n = has_a (c, test_container, &*i)) + { + i->containers = true; + i->versioned_containers = + n != has_a (c, + test_container | + exclude_deleted | exclude_added | exclude_versioned, + &*i); + + if ((n = has_a (c, test_readwrite_container, &*i))) + { + i->readwrite_containers = true; + i->readwrite_versioned_containers = + n != has_a (c, + test_readwrite_container | + exclude_deleted | exclude_added | exclude_versioned, + &*i); + } + } } } @@ -2325,12 +2423,10 @@ namespace virtual void traverse_view_post (type& c) { - // Figure out if we are versioned. When versioning is forced, ignore - // it for native views. + // Figure out if we are versioned. Forced versioning is handled + // in relational/processing. // - if ((force_versioned && - c.get ("query").kind == view_query::condition) || - column_count (c).soft != 0) + if (column_count (c).soft != 0) c.set ("versioned", true); } diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 3a4d244..12ed8ab 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -999,13 +999,21 @@ namespace relational // copied at the end (update). // if (load || load_opt || update || update_opt) + { os << "static std::size_t" << endl << "bind (" << bind_vector << "," << endl << "const " << bind_vector << " id," << endl << "std::size_t id_size," << endl << "image_type&," << endl - << db << "::statement_kind);" + << db << "::statement_kind"; + + if (s.versioned) + os << "," << endl + << "const schema_version_migration&"; + + os << ");" << endl; + } // grow () // @@ -1013,23 +1021,51 @@ namespace relational // will have different number of elements. // if (generate_grow && (load || load_opt)) + { os << "static bool" << endl - << "grow (image_type&, " << truncated_vector << ");" + << "grow (image_type&," << endl + << truncated_vector; + + if (s.versioned) + os << "," << endl + << "const schema_version_migration&"; + + os << ");" << endl; + } // init (object, image) // if (load) + { os << "static void" << endl - << "init (object_type&, const image_type&, database*);" + << "init (object_type&," << endl + << "const image_type&," << endl + << "database*"; + + if (s.versioned) + os << "," << endl + << "const schema_version_migration&"; + + os << ");" << endl; + } // init (image, object) // if (update) + { os << "static " << (generate_grow ? "bool" : "void") << endl - << "init (image_type&, const object_type&);" + << "init (image_type&," << endl + << "const object_type&"; + + if (s.versioned) + os << "," << endl + << "const schema_version_migration&"; + + os << ");" << endl; + } // The rest does not apply to reuse-abstract sections. // @@ -1043,7 +1079,6 @@ namespace relational // column_count // column_count_type const& cc (column_count (poly ? *poly_root : c_)); - bool versioned (force_versioned); // Generate load and update column counts even when they are zero so // that we can instantiate section_statements. @@ -1061,7 +1096,7 @@ namespace relational (update ? s.total - s.inverse - s.readonly : 0) << "UL;" << endl; - os << "static const bool versioned = " << versioned << ";" + os << "static const bool versioned = " << s.versioned << ";" << endl; // Statements. diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx index f5c5102..ed5081d 100644 --- a/odb/relational/inline.hxx +++ b/odb/relational/inline.hxx @@ -224,6 +224,12 @@ namespace relational bool versioned (context::versioned (c)); + // Schema name as a string literal or empty. + // + string schema_name (options.schema_name ()[db]); + if (!schema_name.empty ()) + schema_name = strlit (schema_name); + string const& type (class_fq_name (c)); string traits ("access::object_traits_impl< " + type + ", id_" + db.string () + " >"); @@ -413,18 +419,23 @@ namespace relational { os << "inline" << endl << "void " << traits << "::" << endl - << "load_ (statements_type&," << endl + << "load_ (statements_type& sts," << endl << "object_type& obj," << endl << "bool"; if (versioned) os << "," << endl - << "const schema_version_migration&"; + << "const schema_version_migration& svm"; os << ")" << "{" - << "ODB_POTENTIALLY_UNUSED (obj);" - << endl; + << "ODB_POTENTIALLY_UNUSED (sts);" + << "ODB_POTENTIALLY_UNUSED (obj);"; + + if (versioned) + os << "ODB_POTENTIALLY_UNUSED (svm);"; + + os << endl; // Mark eager sections as loaded. // @@ -437,6 +448,28 @@ namespace relational data_member& m (*i->member); + // If the section is soft- added or deleted, check the version. + // We can only end up here if the object itself is versioned + // (simple value section). + // + unsigned long long av (added (m)); + unsigned long long dv (deleted (m)); + if (av != 0 || dv != 0) + { + os << "if ("; + + if (av != 0) + os << "svm >= schema_version_migration (" << av << "ULL, true)"; + + if (av != 0 && dv != 0) + os << " &&" << endl; + + if (dv != 0) + os << "svm <= schema_version_migration (" << dv << "ULL, true)"; + + os << ")" << endl; + } + // Section access is always by reference. // member_access& ma (m.get ("get")); diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index 8a11914..a287dd2 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -312,6 +312,19 @@ namespace relational // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + // If the addition/deletion version is the same as the section's, + // then we don't need the test. + // + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + if (av != 0 || dv != 0) { os << "if ("; @@ -338,7 +351,18 @@ namespace relational { if (var_override_.empty ()) { - if (added (mi.m) || deleted (mi.m)) + unsigned long long av (added (mi.m)); + unsigned long long dv (deleted (mi.m)); + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + + if (av != 0 || dv != 0) os << "}"; } diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index 3efeec4..231e4f0 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -1427,6 +1427,12 @@ namespace relational } } + // Handle forced versioning. When versioning is forced, ignore + // it for native views. + // + if (force_versioned && vq.kind == view_query::condition) + c.set ("versioned", true); + // Handle data members. // { diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 4008661..93b1035 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -1137,7 +1137,12 @@ traverse_object (type& c) << "throw abstract_class ();" << endl; - if (versioned || persist_versioned_containers) + if (versioned || + persist_versioned_containers || + uss.count (user_sections::count_new | + user_sections::count_update | + user_sections::count_update_empty | + user_sections::count_versioned_only) != 0) os << "const schema_version_migration& svm (" << "db.schema_version_migration (" << schema_name << "));"; @@ -1346,6 +1351,26 @@ traverse_object (type& c) data_member& m (*i->member); + // If the section is soft- added or deleted, check the version. + // + unsigned long long av (added (m)); + unsigned long long dv (deleted (m)); + if (av != 0 || dv != 0) + { + os << "if ("; + + if (av != 0) + os << "svm >= schema_version_migration (" << av << "ULL, true)"; + + if (av != 0 && dv != 0) + os << " &&" << endl; + + if (dv != 0) + os << "svm <= schema_version_migration (" << dv << "ULL, true)"; + + os << ")" << endl; + } + // Section access is always by reference. // member_access& ma (m.get ("get")); @@ -1387,12 +1412,28 @@ traverse_object (type& c) // See if we have any sections that we might have to update. // bool sections (false); + bool versioned_sections (false); for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) { // This test will automatically skip the special version update section. // - if (!i->update_empty () && i->update != user_section::update_manual) - sections = true; + if (i->update_empty () || i->update == user_section::update_manual) + continue; + + sections = true; + + if (added (*i->member) || deleted (*i->member)) + versioned_sections = true; + + // For change-updated sections, also check if we have any + // versioned smart containers. + // + if (i->update != user_section::update_change) + continue; + + if (has_a (c, test_smart_container, &*i) != + has_a (c, test_smart_container | exclude_deleted | exclude_added, &*i)) + versioned_sections = true; } os << "void " << traits << "::" << endl @@ -1449,14 +1490,16 @@ traverse_object (type& c) << endl; } - if ((versioned && update_columns) || update_versioned_containers) + if ((versioned && update_columns) || + update_versioned_containers || + versioned_sections) os << "const schema_version_migration& svm (" << "db.schema_version_migration (" << schema_name << "));" << endl; // If we have change-updated sections that contain change-tracking // containers, then mark such sections as changed if any of the - // containers was changed. Do this before calling the base so that + // containers were changed. Do this before calling the base so that // we account for the whole hierarchy before we actually start // updating any sections (important for optimistic concurrency // version). @@ -1474,11 +1517,29 @@ traverse_object (type& c) data_member& m (*s.member); os << "// " << m.name () << endl - << "//" << endl + << "//" << endl; - //@@ TODO version check. + // If the section is soft- added or deleted, check the version. + // + unsigned long long av (added (m)); + unsigned long long dv (deleted (m)); + if (av != 0 || dv != 0) + { + os << "if ("; - << "{"; + if (av != 0) + os << "svm >= schema_version_migration (" << av << "ULL, true)"; + + if (av != 0 && dv != 0) + os << " &&" << endl; + + if (dv != 0) + os << "svm <= schema_version_migration (" << dv << "ULL, true)"; + + os << ")"; + } + + os << "{"; // Section access is always by reference. // @@ -1852,6 +1913,27 @@ traverse_object (type& c) // data_member& m (*i->member); + // If the section is soft- added or deleted, check the version. + // + unsigned long long av (added (m)); + unsigned long long dv (deleted (m)); + if (av != 0 || dv != 0) + { + os << "if ("; + + if (av != 0) + os << "svm >= schema_version_migration (" << av << "ULL, true)"; + + if (av != 0 && dv != 0) + os << " &&" << endl; + + if (dv != 0) + os << "svm <= schema_version_migration (" << dv << "ULL, true)"; + + os << ")" + << "{"; + } + // Section access is always by reference. // member_access& ma (m.get ("get")); @@ -1938,6 +2020,9 @@ traverse_object (type& c) } os << "}"; + + if (av != 0 || dv != 0) + os << "}"; } // Call callback (post_update). @@ -3258,19 +3343,19 @@ traverse_object (type& c) size_t load_containers ( has_a (c, test_container | include_eager_load, &main_section)); - bool load_versioned_containers ( - load_containers > - has_a (c, - test_container | include_eager_load | - exclude_deleted | exclude_added | exclude_versioned, - &main_section)); - if (poly_derived || load_containers || uss.count (user_sections::count_new | user_sections::count_load | (poly ? user_sections::count_load_empty : 0)) != 0) { + bool load_versioned_containers ( + load_containers > + has_a (c, + test_container | include_eager_load | + exclude_deleted | exclude_added | exclude_versioned, + &main_section)); + os << "void " << traits << "::" << endl << "load_ (statements_type& sts," << endl << "object_type& obj," << endl @@ -3304,13 +3389,21 @@ traverse_object (type& c) os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());" << endl; - if (load_containers) + if (!versioned && ( + load_versioned_containers || + uss.count (user_sections::count_new | + user_sections::count_load | + user_sections::count_load_empty | + user_sections::count_versioned_only) != 0)) { - if (load_versioned_containers && !versioned) - os << "const schema_version_migration& svm (" << endl - << "sts.connection ().database ().schema_version_migration (" << - schema_name << "));"; + os << "const schema_version_migration& svm (" << endl + << "sts.connection ().database ().schema_version_migration (" << + schema_name << "));" + << endl; + } + if (load_containers) + { instance t (container_calls::load_call, &main_section); t->traverse (c); } @@ -3329,6 +3422,27 @@ traverse_object (type& c) data_member& m (*i->member); + // If the section is soft- added or deleted, check the version. + // + unsigned long long av (added (m)); + unsigned long long dv (deleted (m)); + if (av != 0 || dv != 0) + { + os << "if ("; + + if (av != 0) + os << "svm >= schema_version_migration (" << av << "ULL, true)"; + + if (av != 0 && dv != 0) + os << " &&" << endl; + + if (dv != 0) + os << "svm <= schema_version_migration (" << dv << "ULL, true)"; + + os << ")" + << "{"; + } + // Section access is always by reference. // member_access& ma (m.get ("get")); @@ -3370,8 +3484,12 @@ traverse_object (type& c) << "}" << "else" << endl // Reset to unloaded, unchanged state. - << ma.translate ("obj") << ".reset ();" - << endl; + << ma.translate ("obj") << ".reset ();"; + + if (av != 0 || dv != 0) + os << "}"; + else + os << endl; } os << "}"; @@ -3398,17 +3516,17 @@ traverse_object (type& c) << "d = depth - d;" // Convert to distance from derived. << endl; + if (versioned) + os << "const schema_version_migration& svm (" << + "db.schema_version_migration (" << schema_name << "));" + << endl; + // Avoid trying to execute an empty SELECT statement. // if (empty_depth != 0) os << "if (d > " << (poly_depth - empty_depth) << "UL)" << "{"; - if (versioned) - os << "const schema_version_migration& svm (" << - "db.schema_version_migration (" << schema_name << "));" - << endl; - os << "if (!find_ (sts, 0" << (versioned ? ", svm" : "") << ", d))" << endl << "throw object_not_persistent ();" // Database inconsistency. << endl; diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 06d781f..1ea6d3f 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -1017,6 +1017,19 @@ namespace relational // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + // If the addition/deletion version is the same as the section's, + // then we don't need the test. + // + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + if (av != 0 || dv != 0) { os << "if ("; @@ -1046,7 +1059,18 @@ namespace relational // We need to increment the index even if we skipped this // member due to the schema version. // - if (added (mi.m) || deleted (mi.m)) + unsigned long long av (added (mi.m)); + unsigned long long dv (deleted (mi.m)); + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + + if (av != 0 || dv != 0) os << "}"; if (semantics::class_* c = composite (mi.t)) @@ -1366,6 +1390,19 @@ namespace relational // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + // If the addition/deletion version is the same as the section's, + // then we don't need the test. + // + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + if (av != 0 || dv != 0) { os << "if ("; @@ -1570,7 +1607,18 @@ namespace relational if (member_override_.empty ()) { - if (added (mi.m) || deleted (mi.m)) + unsigned long long av (added (mi.m)); + unsigned long long dv (deleted (mi.m)); + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + + if (av != 0 || dv != 0) os << "}"; } } @@ -1757,6 +1805,19 @@ namespace relational // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + // If the addition/deletion version is the same as the section's, + // then we don't need the test. + // + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + if (av != 0 || dv != 0) { os << "if ("; @@ -3862,6 +3923,19 @@ namespace relational // unsigned long long av (added (member_path_)); unsigned long long dv (deleted (member_path_)); + + // If the addition/deletion version is the same as the section's, + // then we don't need the test. + // + if (user_section* s = dynamic_cast (section_)) + { + if (av == added (*s->member)) + av = 0; + + if (dv == deleted (*s->member)) + dv = 0; + } + if (av != 0 || dv != 0) { os << "if ("; @@ -4157,10 +4231,20 @@ namespace relational << "const " << bind_vector << (reuse_abst ? "," : " id,") << endl << "std::size_t" << (reuse_abst ? "," : " id_size,") << endl << "image_type& i," << endl - << db << "::statement_kind sk)" + << db << "::statement_kind sk"; + + if (s.versioned) + os << "," << endl + << "const schema_version_migration& svm"; + + os << ")" << "{" - << "ODB_POTENTIALLY_UNUSED (sk);" - << endl + << "ODB_POTENTIALLY_UNUSED (sk);"; + + if (s.versioned) + os << "ODB_POTENTIALLY_UNUSED (svm);"; + + os << endl << "using namespace " << db << ";" << endl << "std::size_t n (0);" @@ -4184,7 +4268,7 @@ namespace relational << "n += object_traits_impl< " << class_fq_name (*b.object) << ", id_" << db << " >::" << public_name (*b.member) << "_traits::bind (" << endl - << "b, 0, 0, i, sk);" + << "b, 0, 0, i, sk" << (b.versioned ? ", svm" : "") << ");" << endl; } @@ -4228,7 +4312,8 @@ namespace relational << "n += object_traits_impl< " << class_fq_name (*b->object) << ", id_" << db << " >::" << public_name (*b->member) << "_traits::bind (" << endl - << "b + n, 0, 0, *i" << acc << ", sk);" + << "b + n, 0, 0, *i" << acc << ", sk" << + (b->versioned ? ", svm" : "") << ");" << endl; } @@ -4249,11 +4334,22 @@ namespace relational if (generate_grow && (load || load_opt)) { os << "bool " << scope << "::" << endl - << "grow (image_type& i, " << truncated_vector << " t)" + << "grow (image_type& i," << endl + << truncated_vector << " t"; + + if (s.versioned) + os << "," << endl + << "const schema_version_migration& svm"; + + os << ")" << "{" << "ODB_POTENTIALLY_UNUSED (i);" - << "ODB_POTENTIALLY_UNUSED (t);" - << endl + << "ODB_POTENTIALLY_UNUSED (t);"; + + if (s.versioned) + os << "ODB_POTENTIALLY_UNUSED (svm);"; + + os << endl << "bool grew (false);" << endl; @@ -4272,7 +4368,7 @@ namespace relational << "//" << endl << "grew = object_traits_impl< " << class_fq_name (*b.object) << ", id_" << db << " >::" << public_name (*b.member) << - "_traits::grow (i, t);" + "_traits::grow (i, t" << (b.versioned ? ", svm" : "") << ");" << endl; index += b.total + (load_opt ? 1 : 0); @@ -4319,7 +4415,8 @@ namespace relational << "if (object_traits_impl< " << class_fq_name (*b->object) << ", id_" << db << " >::" << public_name (*b->member) << "_traits::grow (" << endl - << "*i" << acc << ", t + " << cols << "UL))" << endl + << "*i" << acc << ", t + " << cols << "UL" << + (b->versioned ? ", svm" : "") << "))" << endl << "i" << acc << "->version++;" << endl; } @@ -4333,10 +4430,22 @@ namespace relational if (load) { os << "void " << scope << "::" << endl - << "init (object_type& o, const image_type& i, database* db)" + << "init (object_type& o," << endl + << "const image_type& i," << endl + << "database* db"; + + if (s.versioned) + os << "," << endl + << "const schema_version_migration& svm"; + + os << ")" << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << endl; + << "ODB_POTENTIALLY_UNUSED (db);"; + + if (s.versioned) + os << "ODB_POTENTIALLY_UNUSED (svm);"; + + os << endl; if (s.base != 0) { @@ -4351,7 +4460,8 @@ namespace relational << "//" << endl << "object_traits_impl< " << class_fq_name (*b.object) << ", id_" << db << " >::" << public_name (*b.member) << - "_traits::init (o, i, db);" + "_traits::init (o, i, db" << + (b.versioned ? ", svm" : "") << ");" << endl; } else @@ -4383,7 +4493,8 @@ namespace relational << "object_traits_impl< " << class_fq_name (*b->object) << ", id_" << db << " >::" << public_name (*b->member) << "_traits::init (" << endl - << "o, *i" << acc << ", db);" + << "o, *i" << acc << ", db" << + (b->versioned ? ", svm" : "") << ");" << endl; } } @@ -4402,9 +4513,21 @@ namespace relational if (update) { os << (generate_grow ? "bool " : "void ") << scope << "::" << endl - << "init (image_type& i, const object_type& o)" - << "{" - << "using namespace " << db << ";" + << "init (image_type& i," << endl + << "const object_type& o"; + + if (s.versioned) + os << "," << endl + << "const schema_version_migration& svm"; + + os << ")" + << "{"; + + if (s.versioned) + os << "ODB_POTENTIALLY_UNUSED (svm);" + << endl; + + os << "using namespace " << db << ";" << endl << "statement_kind sk (statement_insert);" << "ODB_POTENTIALLY_UNUSED (sk);" @@ -4430,7 +4553,7 @@ namespace relational << (generate_grow ? "grew = " : "") << "object_traits_impl< " << class_fq_name (*b.object) << ", id_" << db << " >::" << public_name (*b.member) << - "_traits::init (i, o);" + "_traits::init (i, o" << (b.versioned ? ", svm" : "") << ");" << endl; } @@ -4454,8 +4577,13 @@ namespace relational return; } - bool versioned (force_versioned); - string sep (versioned ? "\n" : " "); + string sep (s.versioned ? "\n" : " "); + + // Schema name as a string literal or empty. + // + string schema_name (options.schema_name ()[db]); + if (!schema_name.empty ()) + schema_name = strlit (schema_name); // Statements. // @@ -4613,6 +4741,12 @@ namespace relational os << "ODB_POTENTIALLY_UNUSED (top);" << endl; + if (s.versioned || s.versioned_containers) + os << "const schema_version_migration& svm (" << endl + << "esc." << m.name () << ".connection ().database ()." << + "schema_version_migration (" << schema_name << "));" + << endl; + // Load values, if any. // if (load || load_opt) @@ -4683,15 +4817,23 @@ namespace relational os << "if (" << ver << " != sts.select_image_version () ||" << endl << "imb.version == 0)" << "{" - << "bind (imb.bind, 0, 0, im, statement_select);" + << "bind (imb.bind, 0, 0, im, statement_select" << + (s.versioned ? ", svm" : "") << ");" << "sts.select_image_version (" << ver << ");" << "imb.version++;" << "}"; // Id binding is assumed initialized and bound. // - os << "select_statement& st (sts.select_statement ());" - << "st.execute ();" + os << "select_statement& st (sts.select_statement ());"; + + // The statement can be dynamically empty. + // + if (s.versioned) + os << "if (!st.empty ())" + << "{"; + + os << "st.execute ();" << "auto_result ar (st);" << "select_statement::result r (st.fetch ());" << endl; @@ -4704,7 +4846,8 @@ namespace relational { os << "if (r == select_statement::truncated)" << "{" - << "if (grow (im, sts.select_image_truncated ()))" << endl + << "if (grow (im, sts.select_image_truncated ()" << + (s.versioned ? ", svm" : "") << "))" << endl << "im.version++;" << endl; @@ -4716,7 +4859,8 @@ namespace relational os << "if (" << ver << " != sts.select_image_version ())" << "{" - << "bind (imb.bind, 0, 0, im, statement_select);" + << "bind (imb.bind, 0, 0, im, statement_select" << + (s.versioned ? ", svm" : "") << ");" << "sts.select_image_version (" << ver << ");" << "imb.version++;" << "st.refetch ();" @@ -4752,11 +4896,15 @@ namespace relational if (load) { - os << "init (obj, im, &sts.connection ().database ());"; + os << "init (obj, im, &sts.connection ().database ()" << + (s.versioned ? ", svm" : "") << ");"; init_value_extra (); // Stream results, etc. os << endl; } + if (s.versioned) + os << "}"; // if (!st.empty ()) + if (poly) os << "}"; // if (top) } @@ -4870,11 +5018,18 @@ namespace relational << endl; } + if (s.versioned || s.readwrite_versioned_containers) + os << "const schema_version_migration& svm (" << endl + << "esc." << m.name () << ".connection ().database ()." << + "schema_version_migration (" << schema_name << "));" + << endl; + // Update values, if any. // if (update || update_opt) { os << "using namespace " << db << ";" + << "using " << db << "::update_statement;" // Conflicts. << endl << "statements_type& sts (esc." << m.name () << ");" << endl @@ -4888,7 +5043,7 @@ namespace relational if (generate_grow) os << "if ("; - os << "init (im, obj)"; + os << "init (im, obj" << (s.versioned ? ", svm" : "") << ")"; if (generate_grow) os << ")" << endl @@ -4902,13 +5057,20 @@ namespace relational << "id.version != sts.update_id_binding_version () ||" << endl << "imb.version == 0)" << "{" - << "bind (imb.bind, id.bind, id.count, im, statement_update);" + << "bind (imb.bind, id.bind, id.count, im, statement_update" << + (s.versioned ? ", svm" : "") << ");" << "sts.update_image_version (im.version);" << "sts.update_id_binding_version (id.version);" << "imb.version++;" << "}"; - os << "if (sts.update_statement ().execute () == 0)" << endl; + os << "update_statement& st (sts.update_statement ());" + << "if ("; + + if (s.versioned) + os << "!st.empty () && "; + + os << "st.execute () == 0)" << endl; if (opt == 0) os << "throw object_not_persistent ();"; diff --git a/odb/validator.cxx b/odb/validator.cxx index 86fcf55..6059bc8 100644 --- a/odb/validator.cxx +++ b/odb/validator.cxx @@ -178,12 +178,6 @@ namespace valid_ = false; } - if (section) - { - error (l) << "section cannod be soft-added" << endl; - valid_ = false; - } - if (!versioned ()) { error (l) << "added data member in a non-versioned object " << @@ -231,12 +225,6 @@ namespace valid_ = false; } - if (section) - { - error (l) << "section cannod be soft-deleted" << endl; - valid_ = false; - } - if (!versioned ()) { error (l) << "deleted data member in a non-versioned object " << @@ -279,8 +267,8 @@ namespace valid_ = false; } - if (dv == 0) - count_++; // Don't include deleted members in the count. + if (section) + return; // Section data member is transient. // Resolve null overrides. // @@ -289,7 +277,6 @@ namespace } bool& valid_; - size_t count_; }; // Find special members (id, version). @@ -525,7 +512,6 @@ namespace // Check bases. // - bool base (false); type* poly_root (0); for (type::inherits_iterator i (c.inherits_begin ()); @@ -536,8 +522,6 @@ namespace if (object (b)) { - base = true; - if (type* r = polymorphic (b)) { if (poly_root == 0) @@ -590,17 +574,8 @@ namespace // Check members. // - member_.count_ = 0; names (c); - if (member_.count_ == 0 && !base) - { - os << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: no persistent data members in the class" << endl; - - valid_ = false; - } - // Check special members. // semantics::data_member* id (0); @@ -906,17 +881,8 @@ namespace // Check members. // - member_.count_ = 0; names (c); - if (member_.count_ == 0) - { - os << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: no persistent data members in the class" << endl; - - valid_ = false; - } - // Check id. // semantics::data_member* id (0); @@ -957,17 +923,13 @@ namespace virtual void traverse_composite (type& c) { - bool base (false); - for (type::inherits_iterator i (c.inherits_begin ()); i != c.inherits_end (); ++i) { type& b (i->base ()); - if (composite (b)) - base = true; - else if (object (b) || view (b)) + if (object (b) || view (b)) { // @@ Should we use hint here? // @@ -991,17 +953,8 @@ namespace // Check members. // - member_.count_ = 0; names (c); - if (member_.count_ == 0 && !base) - { - os << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: no persistent data members in the class" << endl; - - valid_ = false; - } - // Check id. // semantics::data_member* id (0); @@ -1068,12 +1021,17 @@ namespace data_member2 (bool& valid): valid_ (valid) {} virtual void - traverse (type&) + traverse (type& m) { - // Enable the names() calls below if adding any tests here. + if (transient (m)) + return; + + if (!deleted (m)) // Don't include deleted members in the count. + count_++; } bool& valid_; + size_t count_; }; struct class2: traversal::class_, context @@ -1135,6 +1093,15 @@ namespace virtual void traverse_object (type& c) { + bool base (false); + for (type::inherits_iterator i (c.inherits_begin ()); + !base && i != c.inherits_end (); + ++i) + { + if (object (i->base ())) + base = true; + } + bool poly (polymorphic (c)); // Make sure we have no empty or pointless sections unless we @@ -1261,29 +1228,62 @@ namespace // Check members. // - //names (c); + member_.count_ = 0; + names (c); + + if (member_.count_ == 0 && !base) + { + os << c.file () << ":" << c.line () << ":" << c.column () << ":" + << " error: no persistent data members in the class" << endl; + valid_ = false; + } } virtual void - traverse_view (type&) + traverse_view (type& c) { // Check members. // - //names (c); + member_.count_ = 0; + names (c); + + if (member_.count_ == 0) + { + os << c.file () << ":" << c.line () << ":" << c.column () << ":" + << " error: no persistent data members in the class" << endl; + valid_ = false; + } } virtual void - traverse_composite (type&) + traverse_composite (type& c) { + bool base (false); + for (type::inherits_iterator i (c.inherits_begin ()); + !base && i != c.inherits_end (); + ++i) + { + if (composite (i->base ())) + base = true; + } + // Check members. // - //names (c); + member_.count_ = 0; + names (c); + + if (member_.count_ == 0 && !base) + { + os << c.file () << ":" << c.line () << ":" << c.column () << ":" + << " error: no persistent data members in the class" << endl; + valid_ = false; + } } bool& valid_; tree has_lt_operator_; - data_member1 member_; + data_member2 member_; traversal::names names_; }; } -- cgit v1.1