aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-09-05 13:02:10 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-09-05 13:02:10 +0200
commit654826cdafaac4199c8a8c90ef3396e312f0944f (patch)
tree5fb40bdbca960c426fe9d20a4450d89fc6250a7d
parent7e922ee487bad99ce3cad3a2b2bec8ac2b381c92 (diff)
Versioned section support
-rw-r--r--odb/context.cxx66
-rw-r--r--odb/context.hxx18
-rw-r--r--odb/processor.cxx114
-rw-r--r--odb/relational/header.hxx47
-rw-r--r--odb/relational/inline.hxx41
-rw-r--r--odb/relational/pgsql/source.cxx26
-rw-r--r--odb/relational/processor.cxx6
-rw-r--r--odb/relational/source.cxx172
-rw-r--r--odb/relational/source.hxx226
-rw-r--r--odb/validator.cxx116
10 files changed, 685 insertions, 147 deletions
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<user_section*> (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<user_section*> (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<user_section>
//
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<class_&> (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<location_t> ("added-location"));
+
+ if (unsigned long long mav = added (m))
+ {
+ location_t ml (m.get<location_t> ("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<location_t> ("deleted-location"));
+
+ if (unsigned long long mdv = deleted (m))
+ {
+ location_t ml (m.get<location_t> ("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<object_section*> (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<view_query> ("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<member_access> ("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<user_section*> (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<user_section*> (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<member_access> ("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<member_access> ("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<container_calls> 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<member_access> ("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<user_section*> (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<user_section*> (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<user_section*> (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<user_section*> (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<user_section*> (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<user_section*> (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_;
};
}