From 565ad74e164abdaaa31de146a1ef76f3d3f6734d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 16 Sep 2013 10:17:08 +0200 Subject: Implement summary soft-deletion for composite value types --- odb/context.cxx | 6 +++ odb/context.hxx | 12 +++++- odb/processor.cxx | 64 ++++++++++++++++++++++++++++++ odb/relational/mysql/source.cxx | 36 ++++++++++++++++- odb/relational/pgsql/source.cxx | 36 ++++++++++++++++- odb/relational/source.hxx | 85 +++++++++++++++++++++++++++++++++++++--- odb/relational/sqlite/source.cxx | 36 ++++++++++++++++- odb/validator.cxx | 72 ++++++++-------------------------- 8 files changed, 279 insertions(+), 68 deletions(-) (limited to 'odb') diff --git a/odb/context.cxx b/odb/context.cxx index bbde65a..4db15a0 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -2425,6 +2425,12 @@ namespace dv = 0; } + if (av != 0) + c_.added++; + + if (dv != 0) + c_.deleted++; + if (av != 0 || dv != 0) c_.soft++; } diff --git a/odb/context.hxx b/odb/context.hxx index f188a41..e0238dd 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -797,6 +797,12 @@ public: // Return the addition version or 0 if not soft-added. // static unsigned long long + added (semantics::class_& c) // Used for composite only. + { + return c.get ("added", 0); + } + + static unsigned long long added (semantics::data_member& m) { return m.get ("added", 0); @@ -1235,6 +1241,8 @@ public: readonly (0), optimistic_managed (0), discriminator (0), + added (0), + deleted (0), soft (0), separate_load (0), separate_update (0) @@ -1248,7 +1256,9 @@ public: size_t optimistic_managed; size_t discriminator; - size_t soft; // Soft-added/deleted. + size_t added; // Soft-added. + size_t deleted; // Soft-deleted. + size_t soft; // Soft-added/deleted (a column can be both). size_t separate_load; size_t separate_update; // Only readwrite. diff --git a/odb/processor.cxx b/odb/processor.cxx index 0bb9796..6730242 100644 --- a/odb/processor.cxx +++ b/odb/processor.cxx @@ -1955,6 +1955,53 @@ namespace tree container_traits_; }; + // Figure out the "summary" added/deleted version for a composite + // value type. + // + struct summary_version: object_members_base + { + summary_version (): av (0), dv (0), a_ (true), d_ (true) {} + + virtual void + traverse_simple (semantics::data_member&) + { + if (a_) + { + if (unsigned long long v = added (member_path_)) + { + if (av == 0 || av < v) + av = v; + } + else + { + av = 0; + a_ = false; + } + } + + if (d_) + { + if (unsigned long long v = deleted (member_path_)) + { + if (dv == 0 || dv > v) + dv = v; + } + else + { + dv = 0; + d_ = false; + } + } + } + + public: + unsigned long long av; + unsigned long long dv; + + bool a_; + bool d_; + }; + struct class_: traversal::class_, context { class_ () @@ -2449,7 +2496,24 @@ namespace // Figure out if we are versioned. // if (force_versioned || column_count (c).soft != 0) + { c.set ("versioned", true); + + // See if we are "summarily" added/deleted, that is, all the + // columns are added/deleted. Note: this does not include + // containers. + // + summary_version sv; + sv.traverse (c); + + // Note: there are no locations. + // + if (sv.av != 0) + c.set ("added", sv.av); + + if (sv.dv != 0) + c.set ("deleted", sv.dv); + } } // diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx index df7f19c..0df66db 100644 --- a/odb/relational/mysql/source.cxx +++ b/odb/relational/mysql/source.cxx @@ -331,11 +331,28 @@ namespace relational os << "// " << mi.m.name () << endl << "//" << endl; + semantics::class_* comp (composite (mi.t)); + // If the member is soft- added or deleted, check the version. // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + // If this is a composite member, see if it is summarily + // added/deleted. + // + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + // If the addition/deletion version is the same as the section's, // then we don't need the test. // @@ -372,10 +389,25 @@ namespace relational virtual void post (member_info& mi) { + semantics::class_* comp (composite (mi.t)); + if (var_override_.empty ()) { unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + if (user_section* s = dynamic_cast (section_)) { if (av == added (*s->member)) @@ -389,8 +421,8 @@ namespace relational os << "}"; } - if (semantics::class_* c = composite (mi.t)) - index_ += column_count (*c).total; + if (comp != 0) + index_ += column_count (*comp).total; else index_++; } diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index a287dd2..b625524 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -308,11 +308,28 @@ namespace relational os << "// " << mi.m.name () << endl << "//" << endl; + semantics::class_* comp (composite (mi.t)); + // If the member is soft- added or deleted, check the version. // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + // If this is a composite member, see if it is summarily + // added/deleted. + // + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + // If the addition/deletion version is the same as the section's, // then we don't need the test. // @@ -349,10 +366,25 @@ namespace relational virtual void post (member_info& mi) { + semantics::class_* comp (composite (mi.t)); + if (var_override_.empty ()) { unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + if (user_section* s = dynamic_cast (section_)) { if (av == added (*s->member)) @@ -366,8 +398,8 @@ namespace relational os << "}"; } - if (semantics::class_* c = composite (mi.t)) - index_ += column_count (*c).total; + if (comp != 0) + index_ += column_count (*comp).total; else index_++; } diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 642c5ac..ded4781 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -984,6 +984,8 @@ namespace relational if (section_ == 0 && separate_load (mi.m) && inverse (mi.m)) return false; + semantics::class_* comp (composite (mi.t)); + os << "// " << mi.m.name () << endl << "//" << endl; @@ -1003,11 +1005,9 @@ namespace relational // else if (!readonly (*context::top_object)) { - semantics::class_* c; - if (id (mi.m) || readonly (mi.m) || - ((c = composite (mi.t)) && readonly (*c)) || + (comp != 0 && readonly (*comp)) || (section_ == 0 && separate_update (mi.m))) os << "if (sk != statement_update)" << "{"; @@ -1018,6 +1018,21 @@ namespace relational unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + // If this is a composite member, see if it is summarily + // added/deleted. + // + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + // If the addition/deletion version is the same as the section's, // then we don't need the test. // @@ -1056,11 +1071,26 @@ namespace relational { if (var_override_.empty ()) { + semantics::class_* comp (composite (mi.t)); + // We need to increment the index even if we skipped this // member due to the schema version. // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + if (user_section* s = dynamic_cast (section_)) { if (av == added (*s->member)) @@ -1073,10 +1103,10 @@ namespace relational if (av != 0 || dv != 0) os << "}"; - if (semantics::class_* c = composite (mi.t)) + if (comp != 0) { - bool ro (readonly (*c)); - column_count_type const& cc (column_count (*c)); + bool ro (readonly (*comp)); + column_count_type const& cc (column_count (*comp)); os << "n += " << cc.total << "UL"; @@ -1391,6 +1421,21 @@ namespace relational unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + // If this is a composite member, see if it is summarily + // added/deleted. + // + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + // If the addition/deletion version is the same as the section's, // then we don't need the test. // @@ -1609,6 +1654,19 @@ namespace relational { unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + if (user_section* s = dynamic_cast (section_)) { if (av == added (*s->member)) @@ -1806,6 +1864,21 @@ namespace relational unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + // If this is a composite member, see if it is summarily + // added/deleted. + // + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + // If the addition/deletion version is the same as the section's, // then we don't need the test. // diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx index 09b5de7..78bee1d 100644 --- a/odb/relational/sqlite/source.cxx +++ b/odb/relational/sqlite/source.cxx @@ -108,11 +108,28 @@ namespace relational os << "// " << mi.m.name () << endl << "//" << endl; + semantics::class_* comp (composite (mi.t)); + // If the member is soft- added or deleted, check the version. // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + // If this is a composite member, see if it is summarily + // added/deleted. + // + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + // If the addition/deletion version is the same as the section's, // then we don't need the test. // @@ -149,10 +166,25 @@ namespace relational virtual void post (member_info& mi) { + semantics::class_* comp (composite (mi.t)); + if (var_override_.empty ()) { unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); + + if (comp != 0) + { + unsigned long long cav (added (*comp)); + unsigned long long cdv (deleted (*comp)); + + if (cav != 0 && (av == 0 || av < cav)) + av = cav; + + if (cdv != 0 && (dv == 0 || dv > cdv)) + dv = cdv; + } + if (user_section* s = dynamic_cast (section_)) { if (av == added (*s->member)) @@ -166,8 +198,8 @@ namespace relational os << "}"; } - if (semantics::class_* c = composite (mi.t)) - index_ += column_count (*c).total; + if (comp != 0) + index_ += column_count (*comp).total; else index_++; } diff --git a/odb/validator.cxx b/odb/validator.cxx index 1a025a0..2de8882 100644 --- a/odb/validator.cxx +++ b/odb/validator.cxx @@ -1016,24 +1016,6 @@ namespace // Pass 2. // - struct data_member2: traversal::data_member, context - { - data_member2 (bool& valid): valid_ (valid) {} - - virtual void - traverse (type& m) - { - if (transient (m)) - return; - - if (!deleted (m)) // Don't include deleted members in the count. - count_++; - } - - bool& valid_; - size_t count_; - }; - // Make sure soft-delete versions make sense for dependent entities. // We don't seem to need anything for soft-add since if an entity is // not added (e.g., an object), then we cannot reference it in the @@ -1198,7 +1180,7 @@ namespace struct class2: traversal::class_, context { class2 (bool& valid) - : valid_ (valid), has_lt_operator_ (0), member_ (valid) + : valid_ (valid), has_lt_operator_ (0) { // Find the has_lt_operator function template. // @@ -1236,8 +1218,6 @@ namespace if (has_lt_operator_ == 0) valid_ = false; - - *this >> names_ >> member_; } virtual void @@ -1261,21 +1241,13 @@ 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 abst (abstract (c)); bool poly (polymorphic (c)); // Make sure we have no empty or pointless sections unless we // are reuse-abstract or polymorphic. // - if (!poly && !abstract (c)) + if (!poly && !abst) { user_sections& uss (c.get ("user-sections")); @@ -1394,12 +1366,15 @@ namespace } } - // Check members. + // Allow all the members to be deleted as long as there is no + // schema for this class. // - member_.count_ = 0; - names (c); + column_count_type const& cc (column_count (c)); + size_t cont (has_a (c, test_container)); + size_t dcont (cont - has_a (c, test_container | exclude_deleted)); - if (member_.count_ == 0 && !base) + if ((cc.total == 0 && cont == 0) || + (cc.total == cc.deleted && cont == dcont && !(abst || deleted (c)))) { os << c.file () << ":" << c.line () << ":" << c.column () << ":" << " error: no persistent data members in the class" << endl; @@ -1410,12 +1385,11 @@ namespace virtual void traverse_view (type& c) { - // Check members. + // Allow all the members to be deleted. // - member_.count_ = 0; - names (c); + column_count_type const& cc (column_count (c)); - if (member_.count_ == 0) + if (cc.total == 0) { os << c.file () << ":" << c.line () << ":" << c.column () << ":" << " error: no persistent data members in the class" << endl; @@ -1426,21 +1400,12 @@ namespace virtual void 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. + // Allow all the members to be deleted. // - member_.count_ = 0; - names (c); + column_count_type const& cc (column_count (c)); + size_t cont (has_a (c, test_container)); - if (member_.count_ == 0 && !base) + if (cc.total == 0 && cont == 0) { os << c.file () << ":" << c.line () << ":" << c.column () << ":" << " error: no persistent data members in the class" << endl; @@ -1450,9 +1415,6 @@ namespace bool& valid_; tree has_lt_operator_; - - data_member2 member_; - traversal::names names_; }; } -- cgit v1.1