aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-09-12 06:56:02 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-09-12 06:56:02 +0200
commitc3c42b69ee9cda9634573497c4476a05c1f3d049 (patch)
treeecdfa79a83653b4f8286fb3c0ca4b249a51c8129
parent5ecb61d9ee61a53ddbba6b9dea93e7a4adc448b8 (diff)
Make sure that soft-add/delete version is current version
-rw-r--r--odb/context.hxx47
-rw-r--r--odb/relational/changelog.cxx135
-rw-r--r--odb/relational/model.cxx1
-rw-r--r--odb/relational/model.hxx47
4 files changed, 202 insertions, 28 deletions
diff --git a/odb/context.hxx b/odb/context.hxx
index 416c7c6..f188a41 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -136,9 +136,10 @@ struct default_value
};
};
-// Database potentially-qualified name.
+// Database potentially-qualified and unqualifed names.
//
using semantics::relational::qname;
+using semantics::relational::uname;
// Object or table associated with the view.
//
@@ -771,6 +772,28 @@ public:
return r;
}
+ static semantics::data_member*
+ deleted_member (data_member_path const& mp)
+ {
+ semantics::data_member* m (0);
+
+ // Find the earliest version since this member was deleted.
+ //
+ unsigned long long r (0);
+ for (data_member_path::const_reverse_iterator i (mp.rbegin ());
+ i != mp.rend (); ++i)
+ {
+ unsigned long long v ((*i)->get<unsigned long long> ("deleted", 0));
+ if (v != 0 && (r == 0 || v < r))
+ {
+ r = v;
+ m = *i;
+ }
+ }
+
+ return m;
+ }
+
// Return the addition version or 0 if not soft-added.
//
static unsigned long long
@@ -797,6 +820,28 @@ public:
return r;
}
+ static semantics::data_member*
+ added_member (data_member_path const& mp)
+ {
+ semantics::data_member* m (0);
+
+ // Find the latest version since this member was added.
+ //
+ unsigned long long r (0);
+ for (data_member_path::const_reverse_iterator i (mp.rbegin ());
+ i != mp.rend (); ++i)
+ {
+ unsigned long long v ((*i)->get<unsigned long long> ("added", 0));
+ if (v != 0 && v > r)
+ {
+ r = v;
+ m = *i;
+ }
+ }
+
+ return m;
+ }
+
static bool
id (semantics::data_member& m)
{
diff --git a/odb/relational/changelog.cxx b/odb/relational/changelog.cxx
index 63ea44f..7235882 100644
--- a/odb/relational/changelog.cxx
+++ b/odb/relational/changelog.cxx
@@ -2,6 +2,8 @@
// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <map>
+
#include <odb/diagnostics.hxx>
#include <odb/semantics/relational.hxx>
@@ -20,6 +22,9 @@ namespace relational
using sema_rel::model;
using sema_rel::changelog;
+ typedef std::map<qname, semantics::node*> deleted_table_map;
+ typedef std::map<uname, semantics::data_member*> deleted_column_map;
+
namespace
{
//
@@ -33,8 +38,12 @@ namespace relational
{
enum mode_type {mode_add, mode_drop};
- diff_table (table& o, mode_type m, alter_table& a, graph& gr)
- : other (o), mode (m), at (a), g (gr) {}
+ diff_table (table& o,
+ mode_type m,
+ alter_table& a,
+ graph& gr,
+ unsigned long long v)
+ : other (o), mode (m), at (a), g (gr), current (v) {}
virtual void
traverse (sema_rel::column& c)
@@ -71,6 +80,23 @@ namespace relational
}
else
{
+ if (current != 0)
+ {
+ data_member_path const& mp (
+ c.get<data_member_path> ("member-path"));
+
+ // Make sure the addition version is the current version.
+ //
+ semantics::data_member* m (context::added_member (mp));
+ if (m != 0 && context::added (*m) != current)
+ {
+ location l (m->get<location_t> ("added-location"));
+ error (l) << "member addition version is not the same " <<
+ "as the current model version" << endl;
+ throw operation_failed ();
+ }
+ }
+
add_column& ac (g.new_node<add_column> (c, at, g));
g.new_edge<unames> (at, ac, c.name ());
}
@@ -79,6 +105,24 @@ namespace relational
{
if (other.find<column> (c.name ()) == 0)
{
+ if (current != 0)
+ {
+ // See if we have an entry for this column in the soft-
+ // deleted map.
+ //
+ deleted_column_map const& dm (
+ other.get<deleted_column_map> ("deleted-map"));
+ deleted_column_map::const_iterator i (dm.find (c.name ()));
+
+ if (i != dm.end () && context::deleted (*i->second) != current)
+ {
+ location l (i->second->get<location_t> ("deleted-location"));
+ error (l) << "member deletion version is not the same " <<
+ "as the current model version" << endl;
+ throw operation_failed ();
+ }
+ }
+
drop_column& dc (g.new_node<drop_column> (c.id ()));
g.new_edge<unames> (at, dc, c.name ());
}
@@ -346,14 +390,19 @@ namespace relational
mode_type mode;
alter_table& at;
graph& g;
+ unsigned long long current;
};
struct diff_model: trav_rel::table
{
enum mode_type {mode_add, mode_drop};
- diff_model (model& o, mode_type m, changeset& s, graph& gr)
- : other (o), mode (m), cs (s), g (gr) {}
+ diff_model (model& o,
+ mode_type m,
+ changeset& s,
+ graph& gr,
+ unsigned long long c)
+ : other (o), mode (m), cs (s), g (gr), current (c) {}
virtual void
traverse (sema_rel::table& t)
@@ -380,7 +429,7 @@ namespace relational
{
trav_rel::table table;
trav_rel::unames names;
- diff_table dtable (*ot, diff_table::mode_add, at, g);
+ diff_table dtable (*ot, diff_table::mode_add, at, g, current);
table >> names >> dtable;
table.traverse (t);
}
@@ -388,7 +437,7 @@ namespace relational
{
trav_rel::table table;
trav_rel::unames names;
- diff_table dtable (t, diff_table::mode_drop, at, g);
+ diff_table dtable (t, diff_table::mode_drop, at, g, current);
table >> names >> dtable;
table.traverse (*ot);
}
@@ -403,8 +452,25 @@ namespace relational
}
else
{
- // New table.
+ // Soft-add is only applicable to containers.
//
+ if (current != 0 && t.count ("member-path"))
+ {
+ data_member_path const& mp (
+ t.get<data_member_path> ("member-path"));
+
+ // Make sure the addition version is the current version.
+ //
+ semantics::data_member* m (context::added_member (mp));
+ if (m != 0 && context::added (*m) != current)
+ {
+ location l (m->get<location_t> ("added-location"));
+ error (l) << "member addition version is not the same " <<
+ "as the current model version" << endl;
+ throw operation_failed ();
+ }
+ }
+
add_table& at (g.new_node<add_table> (t, cs, g));
g.new_edge<qnames> (cs, at, t.name ());
}
@@ -413,6 +479,42 @@ namespace relational
{
if (other.find<table> (t.name ()) == 0)
{
+ if (current != 0)
+ {
+ // See if we have an entry for this table in the soft-
+ // deleted map.
+ //
+ deleted_table_map const& dm (
+ other.get<deleted_table_map> ("deleted-map"));
+ deleted_table_map::const_iterator i (dm.find (t.name ()));
+
+ if (i != dm.end ())
+ {
+ // This table could be derived either from a class (object)
+ // or data member (container).
+ //
+ semantics::class_* c (
+ dynamic_cast<semantics::class_*> (i->second));
+ if (c != 0 && context::deleted (*c) != current)
+ {
+ location l (c->get<location_t> ("deleted-location"));
+ error (l) << "class deletion version is not the same " <<
+ "as the current model version" << endl;
+ throw operation_failed ();
+ }
+
+ semantics::data_member* m (
+ dynamic_cast<semantics::data_member*> (i->second));
+ if (m != 0 && context::deleted (*m) != current)
+ {
+ location l (m->get<location_t> ("deleted-location"));
+ error (l) << "member deletion version is not the same " <<
+ "as the current model version" << endl;
+ throw operation_failed ();
+ }
+ }
+ }
+
drop_table& dt (g.new_node<drop_table> (t.id ()));
g.new_edge<qnames> (cs, dt, t.name ());
}
@@ -449,12 +551,15 @@ namespace relational
mode_type mode;
changeset& cs;
graph& g;
+ unsigned long long current;
};
- // Assumes the new model has cxx-location set.
+ // Assumes the new model has cxx-location set. If current is not 0,
+ // then assume it is the current model version and the new model is
+ // the current model which has member paths and deleted maps set.
//
changeset&
- diff (model& o, model& n, changelog& l)
+ diff (model& o, model& n, changelog& l, unsigned long long current)
{
changeset& r (l.new_node<changeset> (n.version ()));
@@ -483,7 +588,7 @@ namespace relational
{
trav_rel::model model;
trav_rel::qnames names;
- diff_model dmodel (o, diff_model::mode_add, r, l);
+ diff_model dmodel (o, diff_model::mode_add, r, l, current);
model >> names >> dmodel;
model.traverse (n);
}
@@ -491,7 +596,7 @@ namespace relational
{
trav_rel::model model;
trav_rel::qnames names;
- diff_model dmodel (n, diff_model::mode_drop, r, l);
+ diff_model dmodel (n, diff_model::mode_drop, r, l, current);
model >> names >> dmodel;
model.traverse (o);
}
@@ -753,7 +858,7 @@ namespace relational
model& nm (g.new_node<model> (mv.base));
g.new_edge<contains_model> (*cl, nm);
- changeset& c (diff (nm, m, *cl));
+ changeset& c (diff (nm, m, *cl, mv.current));
if (!c.names_empty ())
{
@@ -834,7 +939,7 @@ namespace relational
base = &g.new_node<model> (mv.base);
g.new_edge<contains_model> (*cl, *base);
- changeset& c (diff (*base, *last, *cl));
+ changeset& c (diff (*base, *last, *cl, 0));
if (!c.names_empty ())
{
g.new_edge<alters_model> (c, *base);
@@ -895,7 +1000,7 @@ namespace relational
om = &patch (*last, c, g);
}
- changeset& c (diff (*om, m, *cl));
+ changeset& c (diff (*om, m, *cl, mv.current));
if (!c.names_empty ())
{
@@ -914,7 +1019,7 @@ namespace relational
//
if (mv.base != mv.current)
{
- changeset& c (diff (*last, m, *cl));
+ changeset& c (diff (*last, m, *cl, mv.current));
if (!c.names_empty ())
{
diff --git a/odb/relational/model.cxx b/odb/relational/model.cxx
index 981aff2..6a65803 100644
--- a/odb/relational/model.cxx
+++ b/odb/relational/model.cxx
@@ -71,6 +71,7 @@ namespace relational
cutl::shared_ptr<sema_rel::model> m (
new (shared) sema_rel::model (
ctx.versioned () ? ctx.version ().current : 0));
+ m->set ("deleted-map", deleted_table_map ());
traversal::unit unit;
traversal::defines unit_defines;
diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx
index e345f83..8920825 100644
--- a/odb/relational/model.hxx
+++ b/odb/relational/model.hxx
@@ -5,6 +5,7 @@
#ifndef ODB_RELATIONAL_MODEL_HXX
#define ODB_RELATIONAL_MODEL_HXX
+#include <map>
#include <set>
#include <cassert>
#include <sstream>
@@ -19,6 +20,8 @@ namespace relational
namespace model
{
typedef std::set<qname> tables;
+ typedef std::map<qname, semantics::node*> deleted_table_map;
+ typedef std::map<uname, semantics::data_member*> deleted_column_map;
struct object_columns: object_columns_base, virtual context
{
@@ -102,8 +105,11 @@ namespace relational
virtual bool
traverse_column (semantics::data_member& m, string const& name, bool)
{
- if (deleted (member_path_))
+ if (semantics::data_member* m = deleted_member (member_path_))
+ {
+ table_.get<deleted_column_map> ("deleted-map")[name] = m;
return false;
+ }
string col_id (id_prefix_ +
(key_prefix_.empty () ? m.name () : key_prefix_));
@@ -112,6 +118,7 @@ namespace relational
model_.new_node<sema_rel::column> (
col_id, column_type (), null (m)));
c.set ("cxx-location", m.location ());
+ c.set ("member-path", member_path_);
model_.new_edge<sema_rel::unames> (table_, c, name);
// An id member cannot have a default value.
@@ -233,14 +240,20 @@ namespace relational
using sema_rel::column;
using sema_rel::foreign_key;
- if (deleted (member_path_))
- return;
-
// Ignore inverse object pointers.
//
if (inverse (m, key_prefix_))
return;
+ if (deleted (member_path_))
+ {
+ // Still traverse it as columns so that we can populate the
+ // deleted map.
+ //
+ object_columns_base::traverse_pointer (m, c);
+ return;
+ }
+
string id (id_prefix_ +
(key_prefix_.empty () ? m.name () : key_prefix_));
@@ -494,18 +507,22 @@ namespace relational
using sema_rel::column;
- if (deleted (member_path_))
- return;
-
// Ignore inverse containers of object pointers.
//
if (inverse (m, "value"))
return;
container_kind_type ck (container_kind (ct));
-
qname const& name (table_name (m, table_prefix_));
+ // Ignore deleted container members.
+ //
+ if (semantics::data_member* m = deleted_member (member_path_))
+ {
+ model_.get<deleted_table_map> ("deleted-map")[name] = m;
+ return;
+ }
+
// Add the [] decorator to distinguish this id from non-container
// ids (we don't want to ever end up comparing, for example, an
// object table to a container table).
@@ -514,6 +531,8 @@ namespace relational
sema_rel::table& t (model_.new_node<sema_rel::table> (id));
t.set ("cxx-location", m.location ());
+ t.set ("member-path", member_path_);
+ t.set ("deleted-map", deleted_column_map ());
model_.new_edge<sema_rel::qnames> (model_, t, name);
t.options (table_options (m, ct));
@@ -718,21 +737,25 @@ namespace relational
if (abstract (c) && !polymorphic (c))
return;
- if (deleted (c))
- return;
-
qname const& name (table_name (c));
- // If the table with this name was already created, assume the
+ // If the table with this name was already seen, assume the
// user knows what they are doing and skip it.
//
if (tables_.count (name))
return;
+ if (deleted (c))
+ {
+ model_.get<deleted_table_map> ("deleted-map")[name] = &c;
+ return;
+ }
+
string id (class_fq_name (c), 2); // Remove leading '::'.
sema_rel::table& t (model_.new_node<sema_rel::table> (id));
t.set ("cxx-location", c.location ());
+ t.set ("deleted-map", deleted_column_map ());
model_.new_edge<sema_rel::qnames> (model_, t, name);
t.options (table_options (c));