summaryrefslogtreecommitdiff
path: root/odb/odb/semantics/relational
diff options
context:
space:
mode:
Diffstat (limited to 'odb/odb/semantics/relational')
-rw-r--r--odb/odb/semantics/relational/changelog.cxx187
-rw-r--r--odb/odb/semantics/relational/changelog.hxx164
-rw-r--r--odb/odb/semantics/relational/changeset.cxx56
-rw-r--r--odb/odb/semantics/relational/changeset.hxx93
-rw-r--r--odb/odb/semantics/relational/column.cxx201
-rw-r--r--odb/odb/semantics/relational/column.hxx205
-rw-r--r--odb/odb/semantics/relational/deferrable.cxx55
-rw-r--r--odb/odb/semantics/relational/deferrable.hxx41
-rw-r--r--odb/odb/semantics/relational/elements.cxx179
-rw-r--r--odb/odb/semantics/relational/elements.hxx462
-rw-r--r--odb/odb/semantics/relational/elements.txx215
-rw-r--r--odb/odb/semantics/relational/foreign-key.cxx218
-rw-r--r--odb/odb/semantics/relational/foreign-key.hxx152
-rw-r--r--odb/odb/semantics/relational/index.cxx145
-rw-r--r--odb/odb/semantics/relational/index.hxx100
-rw-r--r--odb/odb/semantics/relational/key.cxx97
-rw-r--r--odb/odb/semantics/relational/key.hxx104
-rw-r--r--odb/odb/semantics/relational/model.cxx54
-rw-r--r--odb/odb/semantics/relational/model.hxx49
-rw-r--r--odb/odb/semantics/relational/name.cxx89
-rw-r--r--odb/odb/semantics/relational/name.hxx159
-rw-r--r--odb/odb/semantics/relational/primary-key.cxx80
-rw-r--r--odb/odb/semantics/relational/primary-key.hxx62
-rw-r--r--odb/odb/semantics/relational/table.cxx183
-rw-r--r--odb/odb/semantics/relational/table.hxx115
25 files changed, 3465 insertions, 0 deletions
diff --git a/odb/odb/semantics/relational/changelog.cxx b/odb/odb/semantics/relational/changelog.cxx
new file mode 100644
index 0000000..353497f
--- /dev/null
+++ b/odb/odb/semantics/relational/changelog.cxx
@@ -0,0 +1,187 @@
+// file : odb/semantics/relational/changelog.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <vector>
+#include <sstream>
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/changelog.hxx>
+#include <odb/semantics/relational/model.hxx>
+#include <odb/semantics/relational/changeset.hxx>
+
+using namespace std;
+
+namespace semantics
+{
+ namespace relational
+ {
+ changelog::
+ changelog (xml::parser& p)
+ : contains_model_ (0)
+ {
+ using namespace xml;
+
+ p.next_expect (parser::start_element, xmlns, "changelog");
+ p.content (content::complex);
+
+ if (p.attribute<unsigned int> ("version") != 1)
+ throw parsing (p, "unsupported changelog format version");
+
+ database_ = p.attribute ("database");
+ schema_name_ = p.attribute ("schema-name", "");
+
+ // Because things are stored in the reverse order, first save the
+ // changesets as XML chunks and then re-parse them in the reverse
+ // order. We have to do it this way so that we can do lookups along
+ // the alters edges.
+ //
+ typedef vector<string> changesets;
+ changesets cs;
+
+ for (parser::event_type e (p.peek ());
+ e == parser::start_element;
+ e = p.peek ())
+ {
+ if (p.qname () != xml::qname (xmlns, "changeset"))
+ break; // Not our elements.
+
+ ostringstream os;
+ os.exceptions (ios_base::badbit | ios_base::failbit);
+ serializer s (os, "changeset", 0); // No pretty-printing.
+ size_t depth (0);
+
+ do
+ {
+ switch (p.next ())
+ {
+ case parser::start_element:
+ {
+ s.start_element (p.qname ());
+
+ if (depth == 0)
+ s.namespace_decl (xmlns, "");
+
+ typedef parser::attribute_map_type attr_map;
+ attr_map const& am (p.attribute_map ());
+
+ for (attr_map::const_iterator i (am.begin ());
+ i != am.end (); ++i)
+ s.attribute (i->first, i->second.value);
+
+ depth++;
+ break;
+ }
+ case parser::end_element:
+ {
+ depth--;
+ s.end_element ();
+ break;
+ }
+ case parser::characters:
+ {
+ s.characters (p.value ());
+ break;
+ }
+ default:
+ {
+ depth = 0;
+ break;
+ }
+ }
+ } while (depth != 0);
+
+ cs.push_back (os.str ());
+ }
+
+ // Get the model.
+ //
+ p.next_expect (parser::start_element, xmlns, "model");
+ model_type& m (new_node<model_type> (p, *this));
+ new_edge<contains_model_type> (*this, m);
+ p.next_expect (parser::end_element);
+
+ // Re-parse the changesets in reverse order.
+ //
+ qscope* base (&m);
+ for (changesets::reverse_iterator i (cs.rbegin ()); i != cs.rend (); ++i)
+ {
+ istringstream is (*i);
+ is.exceptions (ios_base::badbit | ios_base::failbit);
+ parser ip (is, p.input_name ());
+
+ ip.next_expect (parser::start_element, xmlns, "changeset");
+
+ changeset& c (new_node<changeset> (ip, *base, *this));
+ new_edge<contains_changeset> (*this, c);
+ base = &c;
+
+ ip.next_expect (parser::end_element);
+ }
+
+ p.next_expect (parser::end_element);
+ }
+
+ void changelog::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "changelog");
+ s.namespace_decl (xmlns, "");
+ s.attribute ("database", database_);
+ if (!schema_name_.empty ())
+ s.attribute ("schema-name", schema_name_);
+ s.attribute ("version", 1); // Format version.
+
+ // For better readability serialize things in reverse order so that
+ // the most recent changeset appears first.
+ //
+ for (contains_changeset_list::const_reverse_iterator i (
+ contains_changeset_.rbegin ());
+ i != contains_changeset_.rend (); ++i)
+ {
+ (*i)->changeset ().serialize (s);
+ s.characters ("\n");
+ }
+
+ model ().serialize (s);
+ s.end_element ();
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ // contains_model
+ //
+ {
+ type_info ti (typeid (contains_model));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ // contains_changeset
+ //
+ {
+ type_info ti (typeid (contains_changeset));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ // changelog
+ //
+ {
+ type_info ti (typeid (changelog));
+ ti.add_base (typeid (node));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/changelog.hxx b/odb/odb/semantics/relational/changelog.hxx
new file mode 100644
index 0000000..2398cf6
--- /dev/null
+++ b/odb/odb/semantics/relational/changelog.hxx
@@ -0,0 +1,164 @@
+// file : odb/semantics/relational/changelog.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_CHANGELOG_HXX
+#define ODB_SEMANTICS_RELATIONAL_CHANGELOG_HXX
+
+#include <odb/semantics/relational/elements.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ class model;
+ class changeset;
+ class changelog;
+
+ class contains_model: public edge
+ {
+ public:
+ typedef relational::changelog changelog_type;
+ typedef relational::model model_type;
+
+ changelog_type&
+ changelog () const {return *changelog_;}
+
+ model_type&
+ model () const {return *model_;}
+
+ public:
+ void
+ set_left_node (changelog_type& n) {changelog_ = &n;}
+
+ void
+ set_right_node (model_type& n) {model_ = &n;}
+
+ protected:
+ changelog_type* changelog_;
+ model_type* model_;
+ };
+
+ class contains_changeset: public edge
+ {
+ public:
+ typedef relational::changelog changelog_type;
+ typedef relational::changeset changeset_type;
+
+ changelog_type&
+ changelog () const {return *changelog_;}
+
+ changeset_type&
+ changeset () const {return *changeset_;}
+
+ public:
+ void
+ set_left_node (changelog_type& n) {changelog_ = &n;}
+
+ void
+ set_right_node (changeset_type& n) {changeset_ = &n;}
+
+ protected:
+ changelog_type* changelog_;
+ changeset_type* changeset_;
+ };
+
+ class changelog: public graph, public node
+ {
+ typedef std::vector<contains_changeset*> contains_changeset_list;
+
+ public:
+ typedef relational::model model_type;
+ typedef relational::contains_model contains_model_type;
+
+ model_type&
+ model () const {return contains_model_->model ();}
+
+ contains_model_type&
+ contains_model () const {return *contains_model_;}
+
+ public:
+ typedef
+ pointer_iterator<contains_changeset_list::const_iterator>
+ contains_changeset_iterator;
+
+ contains_changeset const&
+ contains_changeset_back () const
+ {
+ return *contains_changeset_.back ();
+ }
+
+ contains_changeset const&
+ contains_changeset_at (contains_changeset_list::size_type i) const
+ {
+ return *contains_changeset_[i];
+ }
+
+ contains_changeset_iterator
+ contains_changeset_begin () const
+ {
+ return contains_changeset_.begin ();
+ }
+
+ contains_changeset_iterator
+ contains_changeset_end () const
+ {
+ return contains_changeset_.end ();
+ }
+
+ contains_changeset_list::size_type
+ contains_changeset_size () const
+ {
+ return contains_changeset_.size ();
+ }
+
+ bool
+ contains_changeset_empty () const
+ {
+ return contains_changeset_.empty ();
+ }
+
+ public:
+ string const&
+ database () const {return database_;}
+
+ string const&
+ schema_name () const {return schema_name_;}
+
+ public:
+ changelog (string const& db, string const& sn)
+ : database_ (db), schema_name_ (sn), contains_model_ (0) {}
+ changelog (xml::parser&);
+
+ void
+ add_edge_left (contains_model_type& e)
+ {
+ assert (contains_model_ == 0);
+ contains_model_ = &e;
+ }
+
+ void
+ add_edge_left (contains_changeset& e)
+ {
+ contains_changeset_.push_back (&e);
+ }
+
+ virtual string
+ kind () const {return "changelog";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ private:
+ changelog (changelog const&);
+ changelog& operator= (changelog const&);
+
+ protected:
+ string database_;
+ string schema_name_;
+ contains_model_type* contains_model_;
+ contains_changeset_list contains_changeset_;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_CHANGELOG_HXX
diff --git a/odb/odb/semantics/relational/changeset.cxx b/odb/odb/semantics/relational/changeset.cxx
new file mode 100644
index 0000000..b044a0c
--- /dev/null
+++ b/odb/odb/semantics/relational/changeset.cxx
@@ -0,0 +1,56 @@
+// file : odb/semantics/relational/changeset.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/changeset.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ changeset::
+ changeset (changeset const& c, qscope& b, graph& g)
+ : qscope (c, &b, g),
+ version_ (c.version_),
+ alters_model_ (0)
+ {
+ }
+
+ changeset::
+ changeset (xml::parser& p, qscope& b, graph& g)
+ : qscope (p, &b, g),
+ version_ (p.attribute<version_type> ("version")),
+ alters_model_ (0)
+ {
+ }
+
+ void changeset::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "changeset");
+ s.attribute ("version", version_);
+ qscope::serialize_content (s);
+ s.end_element ();
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ {
+ type_info ti (typeid (changeset));
+ ti.add_base (typeid (qscope));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/changeset.hxx b/odb/odb/semantics/relational/changeset.hxx
new file mode 100644
index 0000000..efe2c61
--- /dev/null
+++ b/odb/odb/semantics/relational/changeset.hxx
@@ -0,0 +1,93 @@
+// file : odb/semantics/relational/changeset.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_CHANGESET_HXX
+#define ODB_SEMANTICS_RELATIONAL_CHANGESET_HXX
+
+#include <odb/semantics/relational/elements.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ class model;
+ class changeset;
+
+ class alters_model: public edge
+ {
+ public:
+ typedef relational::model model_type;
+ typedef relational::changeset changeset_type;
+
+ model_type&
+ model () const {return *model_;}
+
+ changeset_type&
+ changeset () const {return *changeset_;}
+
+ public:
+ alters_model () : model_ (0), changeset_ (0) {}
+
+ void
+ set_left_node (changeset_type& c)
+ {
+ assert (changeset_ == 0);
+ changeset_ = &c;
+ }
+
+ void
+ set_right_node (model_type& m)
+ {
+ assert (model_ == 0);
+ model_ = &m;
+ }
+
+ protected:
+ model_type* model_;
+ changeset_type* changeset_;
+ };
+
+ class changeset: public qscope
+ {
+ public:
+ typedef relational::version version_type;
+
+ version_type
+ version () const {return version_;}
+
+ // Returns model to which this changeset applies (as opposed to the
+ // ultimate base model). Note that it may not be set.
+ //
+ model&
+ base_model () const {return alters_model_->model ();}
+
+ public:
+ changeset (version_type v): version_ (v), alters_model_ (0) {}
+ changeset (changeset const&, qscope& base, graph&);
+ changeset (xml::parser&, qscope& base, graph&);
+
+ virtual string
+ kind () const {return "changeset";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ public:
+ virtual void
+ add_edge_left (alters_model& am)
+ {
+ assert (alters_model_ == 0);
+ alters_model_ = &am;
+ }
+
+ using qscope::add_edge_left;
+ using qscope::add_edge_right;
+
+ private:
+ version_type version_;
+ alters_model* alters_model_;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_CHANGESET_HXX
diff --git a/odb/odb/semantics/relational/column.cxx b/odb/odb/semantics/relational/column.cxx
new file mode 100644
index 0000000..9d4d6e5
--- /dev/null
+++ b/odb/odb/semantics/relational/column.cxx
@@ -0,0 +1,201 @@
+// file : odb/semantics/relational/column.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/column.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ // column
+ //
+ column::
+ column (column const& c, uscope&, graph& g)
+ : unameable (c, g),
+ type_ (c.type_),
+ null_ (c.null_),
+ default__ (c.default__),
+ options_ (c.options_)
+ {
+ }
+
+ column::
+ column (xml::parser& p, uscope&, graph& g)
+ : unameable (p, g),
+ type_ (p.attribute ("type", string ())),
+ null_ (p.attribute<bool> ("null")),
+ default__ (p.attribute ("default", string ())),
+ options_ (p.attribute ("options", string ()))
+ {
+ p.content (xml::content::empty);
+ }
+
+ column& column::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<column> (*this, s, g);
+ }
+
+ void column::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "column");
+ serialize_attributes (s);
+ s.end_element ();
+ }
+
+ void column::
+ serialize_attributes (xml::serializer& s) const
+ {
+ unameable::serialize_attributes (s);
+
+ s.attribute ("type", type ());
+ s.attribute ("null", null ()); // Output even if false.
+
+ if (!default_ ().empty ())
+ s.attribute ("default", default_ ());
+
+ if (!options ().empty ())
+ s.attribute ("options", options ());
+ }
+
+ // add_column
+ //
+ add_column& add_column::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<add_column> (*this, s, g);
+ }
+
+ void add_column::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "add-column");
+ column::serialize_attributes (s);
+ s.end_element ();
+ }
+
+ // drop_column
+ //
+ drop_column::
+ drop_column (xml::parser& p, uscope&, graph& g)
+ : unameable (p, g)
+ {
+ p.content (xml::content::empty);
+ }
+
+ drop_column& drop_column::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<drop_column> (*this, s, g);
+ }
+
+ void drop_column::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "drop-column");
+ unameable::serialize_attributes (s);
+ s.end_element ();
+ }
+
+ // alter_column
+ //
+ alter_column::
+ alter_column (alter_column const& ac, uscope& s, graph& g)
+ : column (ac, s, g),
+ alters_ (0),
+ null_altered_ (ac.null_altered_)
+ {
+ column* b (s.lookup<column, drop_column> (ac.name ()));
+ assert (b != 0);
+ g.new_edge<alters> (*this, *b);
+ }
+
+ alter_column::
+ alter_column (xml::parser& p, uscope& s, graph& g)
+ : column (p, s, g),
+ alters_ (0),
+ null_altered_ (p.attribute_present ("null"))
+ {
+ name_type n (p.attribute<name_type> ("name"));
+ column* b (s.lookup<column, drop_column> (n));
+ assert (b != 0);
+ g.new_edge<alters> (*this, *b);
+ }
+
+ alter_column& alter_column::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<alter_column> (*this, s, g);
+ }
+
+ void alter_column::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "alter-column");
+
+ // Here we override the standard column logic.
+ //
+ unameable::serialize_attributes (s);
+
+ if (null_altered_)
+ s.attribute ("null", null_);
+
+ s.end_element ();
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ unameable::parser_map& m (unameable::parser_map_);
+
+ m["column"] = &unameable::parser_impl<column>;
+ m["add-column"] = &unameable::parser_impl<add_column>;
+ m["drop-column"] = &unameable::parser_impl<drop_column>;
+ m["alter-column"] = &unameable::parser_impl<alter_column>;
+
+ using compiler::type_info;
+
+ // column
+ //
+ {
+ type_info ti (typeid (column));
+ ti.add_base (typeid (unameable));
+ insert (ti);
+ }
+
+ // add_column
+ //
+ {
+ type_info ti (typeid (add_column));
+ ti.add_base (typeid (column));
+ insert (ti);
+ }
+
+ // drop_column
+ //
+ {
+ type_info ti (typeid (drop_column));
+ ti.add_base (typeid (unameable));
+ insert (ti);
+ }
+
+ // alter_column
+ //
+ {
+ type_info ti (typeid (alter_column));
+ ti.add_base (typeid (column));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/column.hxx b/odb/odb/semantics/relational/column.hxx
new file mode 100644
index 0000000..b7a2c31
--- /dev/null
+++ b/odb/odb/semantics/relational/column.hxx
@@ -0,0 +1,205 @@
+// file : odb/semantics/relational/column.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_COLUMN_HXX
+#define ODB_SEMANTICS_RELATIONAL_COLUMN_HXX
+
+#include <odb/semantics/relational/elements.hxx>
+#include <odb/semantics/relational/table.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ class contains;
+
+ class column: public unameable
+ {
+ typedef std::vector<contains*> contained_list;
+
+ public:
+ virtual string const&
+ type () const {return type_;}
+
+ virtual bool
+ null () const {return null_;}
+
+ virtual void
+ null (bool n) {null_ = n;}
+
+ virtual string const&
+ default_ () const {return default__;}
+
+ virtual void
+ default_ (string const& d) {default__ = d;}
+
+ virtual string const&
+ options () const {return options_;}
+
+ virtual void
+ options (string const& o) {options_ = o;}
+
+ public:
+ typedef relational::table table_type;
+
+ table_type&
+ table () const {return dynamic_cast<table_type&> (scope ());}
+
+ // Key containment.
+ //
+ public:
+ typedef
+ pointer_iterator<contained_list::const_iterator>
+ contained_iterator;
+
+ contained_iterator
+ contained_begin () const {return contained_.begin ();}
+
+ contained_iterator
+ contained_end () const {return contained_.end ();}
+
+ public:
+ column (string const& id, string const& type, bool null)
+ : unameable (id), type_ (type), null_ (null)
+ {
+ }
+
+ column (column const&, uscope&, graph&);
+ column (xml::parser&, uscope&, graph&);
+
+ virtual column&
+ clone (uscope&, graph&) const;
+
+ void
+ add_edge_right (contains& e)
+ {
+ contained_.push_back (&e);
+ }
+
+ using unameable::add_edge_right;
+
+ virtual string
+ kind () const
+ {
+ return "column";
+ }
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ protected:
+ void
+ serialize_attributes (xml::serializer&) const;
+
+ protected:
+ string type_;
+ bool null_;
+ string default__;
+ string options_;
+
+ private:
+ contained_list contained_;
+ };
+
+ class add_column: public column
+ {
+ public:
+ add_column (string const& id, string const& type, bool null)
+ : column (id, type, null) {}
+ add_column (column const& c, uscope& s, graph& g): column (c, s, g) {}
+ add_column (xml::parser& p, uscope& s, graph& g): column (p, s, g) {}
+
+ virtual add_column&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const {return "add column";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+
+ class drop_column: public unameable
+ {
+ public:
+ drop_column (string const& id): unameable (id) {}
+ drop_column (drop_column const& c, uscope&, graph& g)
+ : unameable (c, g) {}
+ drop_column (xml::parser&, uscope&, graph&);
+
+ public:
+ typedef relational::table table_type;
+
+ table_type&
+ table () const {return dynamic_cast<table_type&> (scope ());}
+
+ public:
+ virtual drop_column&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const {return "drop column";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+
+ class alter_column: public column
+ {
+ public:
+ virtual string const&
+ type () const {return base ().type ();}
+
+ bool
+ null_altered () const {return null_altered_;}
+
+ virtual bool
+ null () const {return null_altered_ ? null_ : base ().null ();}
+
+ virtual void
+ null (bool n) {null_ = n; null_altered_ = true;}
+
+ virtual string const&
+ default_ () const {return base ().default_ ();}
+
+ virtual string const&
+ options () const {return base ().options ();}
+
+ public:
+ column&
+ base () const {return dynamic_cast<column&> (alters_->base ());}
+
+ public:
+ alter_column (string const& id)
+ : column (id, "", false), alters_ (0), null_altered_ (false) {}
+ alter_column (alter_column const&, uscope&, graph&);
+ alter_column (xml::parser&, uscope&, graph&);
+
+ virtual alter_column&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const
+ {
+ return "alter column";
+ }
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ virtual void
+ add_edge_left (alters& a)
+ {
+ assert (alters_ == 0);
+ alters_ = &a;
+ }
+
+ private:
+ alters* alters_;
+
+ bool null_altered_;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_COLUMN_HXX
diff --git a/odb/odb/semantics/relational/deferrable.cxx b/odb/odb/semantics/relational/deferrable.cxx
new file mode 100644
index 0000000..076ff69
--- /dev/null
+++ b/odb/odb/semantics/relational/deferrable.cxx
@@ -0,0 +1,55 @@
+// file : odb/semantics/relational/deferrable.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <ostream>
+#include <istream>
+
+#include <odb/semantics/relational/deferrable.hxx>
+
+using namespace std;
+
+namespace semantics
+{
+ namespace relational
+ {
+ static const char* deferrable_[] =
+ {
+ "NOT DEFERRABLE",
+ "IMMEDIATE",
+ "DEFERRED"
+ };
+
+ string deferrable::
+ string () const
+ {
+ return deferrable_[v_];
+ }
+
+ ostream&
+ operator<< (ostream& os, deferrable const& v)
+ {
+ return os << v.string ();
+ }
+
+ istream&
+ operator>> (istream& is, deferrable& v)
+ {
+ string s;
+ is >> s;
+
+ if (!is.fail ())
+ {
+ if (s == "not_deferrable" || s == "NOT DEFERRABLE")
+ v = deferrable::not_deferrable;
+ else if (s == "immediate" || s == "IMMEDIATE")
+ v = deferrable::immediate;
+ else if (s == "deferred" || s == "DEFERRED")
+ v = deferrable::deferred;
+ else
+ is.setstate (istream::failbit);
+ }
+
+ return is;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/deferrable.hxx b/odb/odb/semantics/relational/deferrable.hxx
new file mode 100644
index 0000000..b2f888d
--- /dev/null
+++ b/odb/odb/semantics/relational/deferrable.hxx
@@ -0,0 +1,41 @@
+// file : odb/semantics/relational/deferrable.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_DEFERRABLE_HXX
+#define ODB_SEMANTICS_RELATIONAL_DEFERRABLE_HXX
+
+#include <string>
+#include <iosfwd>
+
+namespace semantics
+{
+ namespace relational
+ {
+ struct deferrable
+ {
+ enum value
+ {
+ not_deferrable,
+ immediate,
+ deferred
+ };
+
+ deferrable (value v = value (0)) : v_ (v) {}
+ operator value () const {return v_;}
+
+ std::string
+ string () const;
+
+ private:
+ value v_;
+ };
+
+ std::ostream&
+ operator<< (std::ostream&, deferrable const&);
+
+ std::istream&
+ operator>> (std::istream&, deferrable&);
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_DEFERRABLE_HXX
diff --git a/odb/odb/semantics/relational/elements.cxx b/odb/odb/semantics/relational/elements.cxx
new file mode 100644
index 0000000..de1878a
--- /dev/null
+++ b/odb/odb/semantics/relational/elements.cxx
@@ -0,0 +1,179 @@
+// file : odb/semantics/relational/elements.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/elements.hxx>
+#include <odb/semantics/relational/column.hxx>
+#include <odb/semantics/relational/primary-key.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ string const xmlns = "http://www.codesynthesis.com/xmlns/odb/changelog";
+
+ // duplicate_name
+ //
+ template <>
+ duplicate_name::
+ duplicate_name (uscope& s, unameable& o, unameable& d)
+ : scope (s), orig (o), dup (d), name (o.name ())
+ {
+ }
+
+ template <>
+ duplicate_name::
+ duplicate_name (qscope& s, qnameable& o, qnameable& d)
+ : scope (s), orig (o), dup (d), name (o.name ().string ())
+ {
+ }
+
+ // scope<uname>
+ //
+ template <>
+ void scope<uname>::
+ add_edge_left (names_type& e)
+ {
+ nameable_type& n (e.nameable ());
+ name_type const& name (e.name ());
+
+ typename names_map::iterator i (names_map_.find (name));
+
+ if (i == names_map_.end ())
+ {
+ typename names_list::iterator i;
+
+ // We want the order to be add/alter columns first, then the
+ // primary key, then other keys, and finnally drop columns.
+ //
+ if (n.is_a<column> () ||
+ n.is_a<add_column> () ||
+ n.is_a<alter_column> ())
+ {
+ i = names_.insert (first_key_, &e);
+ }
+ else if (!n.is_a<drop_column> ())
+ {
+ if (n.is_a<primary_key> ())
+ first_key_ = i = names_.insert (
+ first_key_ != names_.end () ? first_key_ : first_drop_column_,
+ &e);
+ else
+ {
+ i = names_.insert (first_drop_column_, &e);
+
+ if (first_key_ == names_.end ())
+ first_key_ = i;
+ }
+ }
+ else
+ {
+ i = names_.insert (names_.end (), &e);
+
+ if (first_drop_column_ == names_.end ())
+ first_drop_column_ = i;
+ }
+
+ names_map_[name] = i;
+ iterator_map_[&e] = i;
+ }
+ else
+ throw duplicate_name (*this, (*i->second)->nameable (), n);
+ }
+
+ template <>
+ void scope<uname>::
+ remove_edge_left (names_type& e)
+ {
+ typename names_iterator_map::iterator i (iterator_map_.find (&e));
+ assert (i != iterator_map_.end ());
+
+ // If we are removing the first key, then move to the next key (or
+ // the end which means there are no keys).
+ //
+ if (first_key_ == i->second)
+ first_key_++;
+
+ // The same for the first drop column.
+ //
+ if (first_drop_column_ == i->second)
+ first_drop_column_++;
+
+ names_.erase (i->second);
+ names_map_.erase (e.name ());
+ iterator_map_.erase (i);
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ // node
+ //
+ insert (type_info (typeid (node)));
+
+ // edge
+ //
+ insert (type_info (typeid (edge)));
+
+ // alters
+ //
+ {
+ type_info ti (typeid (alters));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ // names
+ //
+ {
+ type_info ti (typeid (unames));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ {
+ type_info ti (typeid (qnames));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ // nameable
+ //
+ {
+ type_info ti (typeid (unameable));
+ ti.add_base (typeid (node));
+ insert (ti);
+ }
+
+ {
+ type_info ti (typeid (qnameable));
+ ti.add_base (typeid (node));
+ insert (ti);
+ }
+
+ // scope
+ //
+ {
+ type_info ti (typeid (uscope));
+ ti.add_base (typeid (node));
+ insert (ti);
+ }
+
+ {
+ type_info ti (typeid (qscope));
+ ti.add_base (typeid (node));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/elements.hxx b/odb/odb/semantics/relational/elements.hxx
new file mode 100644
index 0000000..4036942
--- /dev/null
+++ b/odb/odb/semantics/relational/elements.hxx
@@ -0,0 +1,462 @@
+// file : odb/semantics/relational/elements.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_ELEMENTS_HXX
+#define ODB_SEMANTICS_RELATIONAL_ELEMENTS_HXX
+
+#include <map>
+#include <list>
+#include <vector>
+#include <string>
+#include <cassert>
+
+#include <libcutl/container/graph.hxx>
+#include <libcutl/container/pointer-iterator.hxx>
+#include <libcutl/compiler/context.hxx>
+
+#include <libstudxml/parser.hxx>
+#include <libstudxml/serializer.hxx>
+
+#include <odb/semantics/relational/name.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ using namespace cutl;
+
+ using std::string;
+
+ using container::pointer_iterator;
+ using compiler::context;
+
+ typedef unsigned long long version;
+
+ //
+ //
+ extern string const xmlns;
+
+ //
+ //
+ class node;
+ class edge;
+
+ typedef container::graph<node, edge> graph;
+
+ //
+ //
+ class edge: public context
+ {
+ public:
+ template <typename X>
+ bool
+ is_a () const
+ {
+ return dynamic_cast<X const*> (this) != 0;
+ }
+
+ public:
+ virtual
+ ~edge () {}
+ };
+
+ //
+ //
+ class node: public context
+ {
+ // Return name of the node.
+ //
+ public:
+ virtual string
+ kind () const = 0;
+
+ public:
+ template <typename X>
+ bool
+ is_a () const
+ {
+ return dynamic_cast<X const*> (this) != 0;
+ }
+
+ public:
+ virtual
+ ~node () {}
+
+ // XML serialization.
+ //
+ virtual void
+ serialize (xml::serializer&) const = 0;
+
+ // Sink functions that allow extensions in the form of one-way
+ // edges.
+ //
+ void
+ add_edge_right (edge&) {}
+
+ void
+ remove_edge_right (edge&) {}
+ };
+
+ //
+ //
+ class alters: public edge
+ {
+ public:
+ node&
+ base () const {return *base_;}
+
+ node&
+ modifier () const {return *modifier_;}
+
+ public:
+ alters () : base_ (0), modifier_ (0) {}
+
+ void
+ set_left_node (node& m)
+ {
+ assert (modifier_ == 0);
+ modifier_ = &m;
+ }
+
+ void
+ set_right_node (node& b)
+ {
+ assert (base_ == 0);
+ base_ = &b;
+ }
+
+ void
+ clear_left_node (node& m)
+ {
+ assert (modifier_ == &m);
+ modifier_ = 0;
+ }
+
+ void
+ clear_right_node (node& b)
+ {
+ assert (base_ == &b);
+ base_ = 0;
+ }
+
+ protected:
+ node* base_;
+ node* modifier_;
+ };
+
+ //
+ //
+ template <typename N>
+ class scope;
+
+ template <typename N>
+ class nameable;
+
+ //
+ //
+ template <typename N>
+ class names: public edge
+ {
+ public:
+ typedef N name_type;
+ typedef relational::scope<N> scope_type;
+ typedef relational::nameable<N> nameable_type;
+
+ name_type const&
+ name () const
+ {
+ return name_;
+ }
+
+ scope_type&
+ scope () const
+ {
+ return *scope_;
+ }
+
+ nameable_type&
+ nameable () const
+ {
+ return *nameable_;
+ }
+
+ public:
+ names (name_type const& name): name_ (name) {}
+
+ void
+ set_left_node (scope_type& n)
+ {
+ scope_ = &n;
+ }
+
+ void
+ set_right_node (nameable_type& n)
+ {
+ nameable_ = &n;
+ }
+
+ void
+ clear_left_node (scope_type& n)
+ {
+ assert (scope_ == &n);
+ scope_ = 0;
+ }
+
+ void
+ clear_right_node (nameable_type& n)
+ {
+ assert (nameable_ == &n);
+ nameable_ = 0;
+ }
+
+ protected:
+ name_type name_;
+ scope_type* scope_;
+ nameable_type* nameable_;
+ };
+
+ typedef names<uname> unames;
+ typedef names<qname> qnames;
+
+ //
+ //
+ template <typename N>
+ class nameable: public virtual node
+ {
+ public:
+ typedef N name_type;
+ typedef relational::names<N> names_type;
+ typedef relational::scope<N> scope_type;
+
+ name_type const&
+ name () const {return named_->name ();}
+
+ scope_type&
+ scope () const {return named ().scope ();}
+
+ names_type&
+ named () const {return *named_;}
+
+ string const&
+ id () const {return id_;}
+
+ public:
+ // Id identifies the C++ node (e.g., a class or a data member) that
+ // this model node corresponds to. The ids are not necessarily unique
+ // (e.g., there can be a foreign key and an index with the same id that
+ // correspond to a container member). However, in any given scope, the
+ // {id,typeid} must be unique. This becomes important when we try to
+ // find correspondance between nodes during model diff'ing.
+ //
+ nameable (string const& id): id_ (id), named_ (0) {}
+
+ virtual nameable&
+ clone (scope_type&, graph&) const = 0;
+
+ // Virtual because we call it via nameable interface (e.g., in copy).
+ //
+ virtual void
+ add_edge_right (names_type& e)
+ {
+ assert (named_ == 0);
+ named_ = &e;
+ }
+
+ virtual void
+ remove_edge_right (names_type& e)
+ {
+ assert (named_ == &e);
+ named_ = 0;
+ }
+
+ using node::add_edge_right;
+ using node::remove_edge_right;
+
+ protected:
+ nameable (nameable const&, graph& g);
+ nameable (xml::parser&, graph& g);
+
+ void
+ serialize_attributes (xml::serializer&) const;
+
+ public:
+ typedef void (*parser_func) (xml::parser&, scope_type&, graph&);
+ typedef std::map<std::string, parser_func> parser_map;
+ static parser_map parser_map_;
+
+ template <typename T>
+ static void
+ parser_impl (xml::parser&, scope_type&, graph&);
+
+ private:
+ string id_;
+ names_type* named_;
+ };
+
+ typedef nameable<uname> unameable;
+ typedef nameable<qname> qnameable;
+
+
+ //
+ //
+ struct duplicate_name
+ {
+ template <typename N>
+ duplicate_name (relational::scope<N>&,
+ relational::nameable<N>& orig,
+ relational::nameable<N>& dup);
+
+ node& scope;
+ node& orig;
+ node& dup;
+
+ string name;
+ };
+
+ template <typename N>
+ class scope: public virtual node
+ {
+ protected:
+ typedef N name_type;
+ typedef relational::names<N> names_type;
+ typedef relational::nameable<N> nameable_type;
+
+ typedef std::list<names_type*> names_list;
+ typedef std::map<name_type, typename names_list::iterator> names_map;
+ typedef
+ std::map<names_type const*, typename names_list::iterator>
+ names_iterator_map;
+
+ public:
+ typedef pointer_iterator<typename names_list::iterator> names_iterator;
+ typedef
+ pointer_iterator<typename names_list::const_iterator>
+ names_const_iterator;
+
+ public:
+ // Iteration.
+ //
+ names_iterator
+ names_begin ()
+ {
+ return names_.begin ();
+ }
+
+ names_iterator
+ names_end ()
+ {
+ return names_.end ();
+ }
+
+ names_const_iterator
+ names_begin () const
+ {
+ return names_.begin ();
+ }
+
+ names_const_iterator
+ names_end () const
+ {
+ return names_.end ();
+ }
+
+ bool
+ names_empty () const
+ {
+ return names_.empty ();
+ }
+
+ // Find (this scope only).
+ //
+ template <typename T>
+ T*
+ find (name_type const&);
+
+ names_iterator
+ find (name_type const&);
+
+ names_const_iterator
+ find (name_type const&) const;
+
+ names_iterator
+ find (names_type const&);
+
+ names_const_iterator
+ find (names_type const&) const;
+
+ // Lookup in this and all altered scopes until we find what we are
+ // looking for or hit a stop node of type S (e.g., drop_*).
+ //
+ template <typename T, typename S>
+ T*
+ lookup (name_type const&);
+
+ public:
+ scope*
+ base () const
+ {
+ return alters_ != 0 ? &dynamic_cast<scope&> (alters_->base ()) : 0;
+ }
+
+ public:
+ scope ()
+ : first_key_ (names_.end ()),
+ first_drop_column_ (names_.end ()),
+ alters_ (0) {}
+
+ // Virtual because we call it via scope interface (e.g., in copy).
+ //
+ virtual void
+ add_edge_left (alters& a)
+ {
+ assert (alters_ == 0);
+ alters_ = &a;
+ }
+
+ virtual void
+ remove_edge_left (alters& a)
+ {
+ assert (alters_ == &a);
+ alters_ = 0;
+ }
+
+ virtual void
+ add_edge_left (names_type&);
+
+ virtual void
+ remove_edge_left (names_type&);
+
+ protected:
+ scope (scope const&, scope* base, graph&);
+ scope (xml::parser&, scope* base, graph&);
+
+ void
+ serialize_content (xml::serializer&) const;
+
+ protected:
+ names_list names_;
+ names_map names_map_;
+ names_iterator_map iterator_map_;
+
+ typename names_list::iterator first_key_;
+ typename names_list::iterator first_drop_column_;
+
+ alters* alters_;
+ };
+
+ template <>
+ void scope<uname>::
+ add_edge_left (names_type&);
+
+ template <>
+ void scope<uname>::
+ remove_edge_left (names_type&);
+
+ typedef scope<uname> uscope;
+ typedef scope<qname> qscope;
+ }
+}
+
+#include <odb/semantics/relational/elements.txx>
+
+#endif // ODB_SEMANTICS_RELATIONAL_ELEMENTS_HXX
diff --git a/odb/odb/semantics/relational/elements.txx b/odb/odb/semantics/relational/elements.txx
new file mode 100644
index 0000000..2362d48
--- /dev/null
+++ b/odb/odb/semantics/relational/elements.txx
@@ -0,0 +1,215 @@
+// file : odb/semantics/relational/elements.txx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+namespace semantics
+{
+ namespace relational
+ {
+ // nameable
+ //
+ template <typename N>
+ typename nameable<N>::parser_map nameable<N>::parser_map_;
+
+ template <typename N>
+ template <typename T>
+ void nameable<N>::
+ parser_impl (xml::parser& p, scope_type& s, graph& g)
+ {
+ name_type n (p.attribute ("name", name_type ()));
+ T& x (g.new_node<T> (p, s, g));
+ g.new_edge<names_type> (s, x, n);
+ }
+
+ template <typename N>
+ nameable<N>::
+ nameable (nameable const& n, graph&)
+ : id_ (n.id_), named_ (0)
+ {
+ }
+
+ template <typename N>
+ nameable<N>::
+ nameable (xml::parser&, graph&)
+ // : id_ (p.attribute<string> ("id"))
+ : named_ (0)
+ {
+ // The name attribute is handled in parser_impl().
+ }
+
+ template <typename N>
+ void nameable<N>::
+ serialize_attributes (xml::serializer& s) const
+ {
+ // Omit empty names (e.g., a primary key).
+ //
+ name_type const& n (name ());
+ if (!n.empty ())
+ s.attribute ("name", n);
+
+ //s.attribute ("id", id_);
+ }
+
+ // scope
+ //
+
+ template <typename N>
+ template <typename T, typename S>
+ T* scope<N>::
+ lookup (name_type const& name)
+ {
+ if (T* r = find<T> (name))
+ return r;
+
+ if (scope* b = base ())
+ {
+ if (find<S> (name) == 0)
+ return b->lookup<T, S> (name);
+ }
+
+ return 0;
+ }
+
+ template <typename N>
+ template <typename T>
+ T* scope<N>::
+ find (name_type const& name)
+ {
+ typename names_map::iterator i (names_map_.find (name));
+ return i != names_map_.end ()
+ ? dynamic_cast<T*> (&(*i->second)->nameable ())
+ : 0;
+ }
+
+ template <typename N>
+ typename scope<N>::names_iterator scope<N>::
+ find (name_type const& name)
+ {
+ typename names_map::iterator i (names_map_.find (name));
+
+ if (i == names_map_.end ())
+ return names_.end ();
+ else
+ return i->second;
+ }
+
+ template <typename N>
+ typename scope<N>::names_const_iterator scope<N>::
+ find (name_type const& name) const
+ {
+ typename names_map::const_iterator i (names_map_.find (name));
+
+ if (i == names_map_.end ())
+ return names_.end ();
+ else
+ return names_const_iterator (i->second);
+ }
+
+ template <typename N>
+ typename scope<N>::names_iterator scope<N>::
+ find (names_type const& e)
+ {
+ typename names_iterator_map::iterator i (iterator_map_.find (&e));
+ return i != iterator_map_.end () ? i->second : names_.end ();
+ }
+
+ template <typename N>
+ typename scope<N>::names_const_iterator scope<N>::
+ find (names_type const& e) const
+ {
+ typename names_iterator_map::const_iterator i (iterator_map_.find (&e));
+ return i != iterator_map_.end () ? i->second : names_.end ();
+ }
+
+ template <typename N>
+ scope<N>::
+ scope (scope const& s, scope* base, graph& g)
+ : first_key_ (names_.end ()),
+ first_drop_column_ (names_.end ()),
+ alters_ (0)
+ {
+ // Set the alters edge for lookup.
+ //
+ if (base != 0)
+ g.new_edge<alters> (*this, *base);
+
+ for (names_const_iterator i (s.names_begin ());
+ i != s.names_end (); ++i)
+ {
+ nameable_type& n (i->nameable ().clone (*this, g));
+ g.new_edge<names_type> (*this, n, i->name ());
+ }
+ }
+
+ template <typename N>
+ scope<N>::
+ scope (xml::parser& p, scope* base, graph& g)
+ : first_key_ (names_.end ()),
+ first_drop_column_ (names_.end ()),
+ alters_ (0)
+ {
+ // Set the alters edge for lookup.
+ //
+ if (base != 0)
+ g.new_edge<alters> (*this, *base);
+
+ using namespace xml;
+ p.content (content::complex);
+
+ for (parser::event_type e (p.peek ());
+ e == parser::start_element;
+ e = p.peek ())
+ {
+ typename nameable_type::parser_map::iterator i (
+ nameable_type::parser_map_.find (p.name ()));
+
+ if (p.namespace_ () != xmlns || i == nameable_type::parser_map_.end ())
+ break; // Not one of our elements.
+
+ p.next ();
+ i->second (p, *this, g);
+ p.next_expect (parser::end_element);
+ }
+ }
+
+ template <typename N>
+ void scope<N>::
+ serialize_content (xml::serializer& s) const
+ {
+ for (names_const_iterator i (names_begin ()); i != names_end (); ++i)
+ i->nameable ().serialize (s);
+ }
+
+ class column;
+ class primary_key;
+
+ template <typename N>
+ void scope<N>::
+ add_edge_left (names_type& e)
+ {
+ name_type const& name (e.name ());
+
+ typename names_map::iterator i (names_map_.find (name));
+
+ if (i == names_map_.end ())
+ {
+ typename names_list::iterator i (names_.insert (names_.end (), &e));
+ names_map_[name] = i;
+ iterator_map_[&e] = i;
+ }
+ else
+ throw duplicate_name (*this, (*i->second)->nameable (), e.nameable ());
+ }
+
+ template <typename N>
+ void scope<N>::
+ remove_edge_left (names_type& e)
+ {
+ typename names_iterator_map::iterator i (iterator_map_.find (&e));
+ assert (i != iterator_map_.end ());
+
+ names_.erase (i->second);
+ names_map_.erase (e.name ());
+ iterator_map_.erase (i);
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/foreign-key.cxx b/odb/odb/semantics/relational/foreign-key.cxx
new file mode 100644
index 0000000..0357d95
--- /dev/null
+++ b/odb/odb/semantics/relational/foreign-key.cxx
@@ -0,0 +1,218 @@
+// file : odb/semantics/relational/foreign-key.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <ostream>
+#include <istream>
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/foreign-key.hxx>
+
+using namespace std;
+
+namespace semantics
+{
+ namespace relational
+ {
+ static const char* action_str[] = {"NO ACTION", "CASCADE", "SET NULL"};
+
+ ostream&
+ operator<< (ostream& os, foreign_key::action_type v)
+ {
+ return os << action_str[v];
+ }
+
+ istream&
+ operator>> (istream& is, foreign_key::action_type& v)
+ {
+ string s;
+ getline (is, s);
+
+ if (!is.eof ())
+ is.setstate (istream::failbit);
+
+ if (!is.fail ())
+ {
+ if (s == "NO ACTION")
+ v = foreign_key::no_action;
+ else if (s == "CASCADE")
+ v = foreign_key::cascade;
+ else if (s == "SET NULL")
+ v = foreign_key::set_null;
+ else
+ is.setstate (istream::failbit);
+ }
+
+ return is;
+ }
+
+ foreign_key::
+ foreign_key (foreign_key const& k, uscope& s, graph& g)
+ : key (k, s, g),
+ referenced_table_ (k.referenced_table_),
+ referenced_columns_ (k.referenced_columns_),
+ deferrable_ (k.deferrable_),
+ on_delete_ (k.on_delete_)
+ {
+ }
+
+ foreign_key::
+ foreign_key (xml::parser& p, uscope& s, graph& g)
+ : key (p, s, g),
+ deferrable_ (p.attribute ("deferrable", deferrable_type ())),
+ on_delete_ (p.attribute ("on-delete", no_action))
+ {
+ using namespace xml;
+
+ p.next_expect (parser::start_element, xmlns, "references");
+ referenced_table_ = p.attribute<qname> ("table");
+ p.content (content::complex);
+
+ for (parser::event_type e (p.peek ());
+ e == parser::start_element;
+ e = p.peek ())
+ {
+ if (p.qname () != xml::qname (xmlns, "column"))
+ break; // Not our elements.
+
+ p.next ();
+ referenced_columns_.push_back (p.attribute<uname> ("name"));
+ p.content (content::empty);
+ p.next_expect (parser::end_element);
+ }
+
+ p.next_expect (parser::end_element);
+ }
+
+ foreign_key& foreign_key::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<foreign_key> (*this, s, g);
+ }
+
+ void foreign_key::
+ serialize_attributes (xml::serializer& s) const
+ {
+ key::serialize_attributes (s);
+
+ if (deferrable () != deferrable_type::not_deferrable)
+ s.attribute ("deferrable", deferrable ());
+
+ if (on_delete () != no_action)
+ s.attribute ("on-delete", on_delete ());
+ }
+
+ void foreign_key::
+ serialize_content (xml::serializer& s) const
+ {
+ key::serialize_content (s);
+
+ // Referenced columns.
+ //
+ s.start_element (xmlns, "references");
+ s.attribute ("table", referenced_table ());
+
+ for (columns::const_iterator i (referenced_columns_.begin ());
+ i != referenced_columns_.end (); ++i)
+ {
+ s.start_element (xmlns, "column");
+ s.attribute ("name", *i);
+ s.end_element ();
+ }
+
+ s.end_element (); // references
+ }
+
+ void foreign_key::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "foreign-key");
+ serialize_attributes (s);
+ serialize_content (s);
+ s.end_element (); // foreign-key
+ }
+
+ // add_foreign_key
+ //
+ add_foreign_key& add_foreign_key::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<add_foreign_key> (*this, s, g);
+ }
+
+ void add_foreign_key::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "add-foreign-key");
+ foreign_key::serialize_attributes (s);
+ foreign_key::serialize_content (s);
+ s.end_element ();
+ }
+
+ // drop_foreign_key
+ //
+ drop_foreign_key::
+ drop_foreign_key (xml::parser& p, uscope&, graph& g)
+ : unameable (p, g)
+ {
+ p.content (xml::content::empty);
+ }
+
+ drop_foreign_key& drop_foreign_key::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<drop_foreign_key> (*this, s, g);
+ }
+
+ void drop_foreign_key::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "drop-foreign-key");
+ unameable::serialize_attributes (s);
+ s.end_element ();
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ unameable::parser_map& m (unameable::parser_map_);
+
+ m["foreign-key"] = &unameable::parser_impl<foreign_key>;
+ m["add-foreign-key"] = &unameable::parser_impl<add_foreign_key>;
+ m["drop-foreign-key"] = &unameable::parser_impl<drop_foreign_key>;
+
+ using compiler::type_info;
+
+ // foreign_key
+ //
+ {
+ type_info ti (typeid (foreign_key));
+ ti.add_base (typeid (key));
+ insert (ti);
+ }
+
+ // add_foreign_key
+ //
+ {
+ type_info ti (typeid (add_foreign_key));
+ ti.add_base (typeid (foreign_key));
+ insert (ti);
+ }
+
+ // drop_foreign_key
+ //
+ {
+ type_info ti (typeid (drop_foreign_key));
+ ti.add_base (typeid (unameable));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/foreign-key.hxx b/odb/odb/semantics/relational/foreign-key.hxx
new file mode 100644
index 0000000..32179fa
--- /dev/null
+++ b/odb/odb/semantics/relational/foreign-key.hxx
@@ -0,0 +1,152 @@
+// file : odb/semantics/relational/foreign-key.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_FOREIGN_KEY_HXX
+#define ODB_SEMANTICS_RELATIONAL_FOREIGN_KEY_HXX
+
+#include <iosfwd>
+
+#include <odb/semantics/relational/deferrable.hxx>
+#include <odb/semantics/relational/elements.hxx>
+#include <odb/semantics/relational/key.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ class foreign_key: public key
+ {
+ public:
+ qname const&
+ referenced_table () const
+ {
+ return referenced_table_;
+ }
+
+ typedef std::vector<string> columns;
+
+ columns const&
+ referenced_columns () const
+ {
+ return referenced_columns_;
+ }
+
+ columns&
+ referenced_columns ()
+ {
+ return referenced_columns_;
+ }
+
+ public:
+ typedef relational::deferrable deferrable_type;
+
+ deferrable_type
+ deferrable () const {return deferrable_;}
+
+ bool
+ not_deferrable () const
+ {
+ return deferrable_ == deferrable_type::not_deferrable;
+ }
+
+ enum action_type
+ {
+ no_action,
+ cascade,
+ set_null
+ };
+
+ action_type
+ on_delete () const {return on_delete_;}
+
+ public:
+ foreign_key (string const& id,
+ qname const& referenced_table,
+ deferrable_type deferrable,
+ action_type on_delete = no_action)
+ : key (id),
+ referenced_table_ (referenced_table),
+ deferrable_ (deferrable),
+ on_delete_ (on_delete)
+ {
+ }
+
+ foreign_key (foreign_key const&, uscope&, graph&);
+ foreign_key (xml::parser&, uscope&, graph&);
+
+ virtual foreign_key&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const
+ {
+ return "foreign key";
+ }
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ protected:
+ void
+ serialize_attributes (xml::serializer&) const;
+
+ void
+ serialize_content (xml::serializer&) const;
+
+ private:
+ qname referenced_table_;
+ columns referenced_columns_;
+ deferrable_type deferrable_;
+ action_type on_delete_;
+ };
+
+ std::ostream&
+ operator<< (std::ostream&, foreign_key::action_type);
+
+ std::istream&
+ operator>> (std::istream&, foreign_key::action_type&);
+
+ class add_foreign_key: public foreign_key
+ {
+ public:
+ add_foreign_key (string const& id,
+ qname const& rt,
+ deferrable_type d,
+ action_type od = no_action)
+ : foreign_key (id, rt, d, od) {}
+ add_foreign_key (foreign_key const& fk, uscope& s, graph& g)
+ : foreign_key (fk, s, g) {}
+ add_foreign_key (xml::parser& p, uscope& s, graph& g)
+ : foreign_key (p, s, g) {}
+
+ virtual add_foreign_key&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const {return "add foreign key";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+
+ class drop_foreign_key: public unameable
+ {
+ public:
+ drop_foreign_key (string const& id): unameable (id) {}
+ drop_foreign_key (drop_foreign_key const& dfk, uscope&, graph& g)
+ : unameable (dfk, g) {}
+ drop_foreign_key (xml::parser&, uscope&, graph&);
+
+ virtual drop_foreign_key&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const {return "drop foreign key";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_FOREIGN_KEY_HXX
diff --git a/odb/odb/semantics/relational/index.cxx b/odb/odb/semantics/relational/index.cxx
new file mode 100644
index 0000000..2329f3a
--- /dev/null
+++ b/odb/odb/semantics/relational/index.cxx
@@ -0,0 +1,145 @@
+// file : odb/semantics/relational/index.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/index.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ // index
+ //
+ index::
+ index (index const& i, uscope& s, graph& g)
+ : key (i, s, g),
+ type_ (i.type_),
+ method_ (i.method_),
+ options_ (i.options_)
+ {
+ }
+
+ index::
+ index (xml::parser& p, uscope& s, graph& g)
+ : key (p, s, g),
+ type_ (p.attribute ("type", string ())),
+ method_ (p.attribute ("method", string ())),
+ options_ (p.attribute ("options", string ()))
+ {
+ }
+
+ index& index::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<index> (*this, s, g);
+ }
+
+ void index::
+ serialize_attributes (xml::serializer& s) const
+ {
+ key::serialize_attributes (s);
+
+ if (!type ().empty ())
+ s.attribute ("type", type ());
+
+ if (!method ().empty ())
+ s.attribute ("method", method ());
+
+ if (!options ().empty ())
+ s.attribute ("options", options ());
+ }
+
+ void index::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "index");
+ serialize_attributes (s);
+ key::serialize_content (s);
+ s.end_element ();
+ }
+
+ // add_index
+ //
+ add_index& add_index::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<add_index> (*this, s, g);
+ }
+
+ void add_index::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "add-index");
+ index::serialize_attributes (s);
+ index::serialize_content (s);
+ s.end_element ();
+ }
+
+ // drop_index
+ //
+ drop_index::
+ drop_index (xml::parser& p, uscope&, graph& g)
+ : unameable (p, g)
+ {
+ p.content (xml::content::empty);
+ }
+
+ drop_index& drop_index::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<drop_index> (*this, s, g);
+ }
+
+ void drop_index::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "drop-index");
+ unameable::serialize_attributes (s);
+ s.end_element ();
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ unameable::parser_map& m (unameable::parser_map_);
+
+ m["index"] = &unameable::parser_impl<index>;
+ m["add-index"] = &unameable::parser_impl<add_index>;
+ m["drop-index"] = &unameable::parser_impl<drop_index>;
+
+ using compiler::type_info;
+
+ // index
+ //
+ {
+ type_info ti (typeid (index));
+ ti.add_base (typeid (key));
+ insert (ti);
+ }
+
+ // add_index
+ //
+ {
+ type_info ti (typeid (add_index));
+ ti.add_base (typeid (index));
+ insert (ti);
+ }
+
+ // drop_index
+ //
+ {
+ type_info ti (typeid (drop_index));
+ ti.add_base (typeid (unameable));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/index.hxx b/odb/odb/semantics/relational/index.hxx
new file mode 100644
index 0000000..68648cb
--- /dev/null
+++ b/odb/odb/semantics/relational/index.hxx
@@ -0,0 +1,100 @@
+// file : odb/semantics/relational/index.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_INDEX_HXX
+#define ODB_SEMANTICS_RELATIONAL_INDEX_HXX
+
+#include <odb/semantics/relational/elements.hxx>
+#include <odb/semantics/relational/key.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ // Note that in our model indexes are defined in the table scope.
+ //
+ class index: public key
+ {
+ public:
+ string const&
+ type () const {return type_;}
+
+ string const&
+ method () const {return method_;}
+
+ string const&
+ options () const {return options_;}
+
+ public:
+ index (string const& id,
+ string const& t = string (),
+ string const& m = string (),
+ string const& o = string ())
+ : key (id), type_ (t), method_ (m), options_ (o) {}
+ index (index const&, uscope&, graph&);
+ index (xml::parser&, uscope&, graph&);
+
+ virtual index&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const
+ {
+ return "index";
+ }
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ protected:
+ void
+ serialize_attributes (xml::serializer&) const;
+
+ private:
+ string type_; // E.g., "UNIQUE", etc.
+ string method_; // E.g., "BTREE", etc.
+ string options_; // Database-specific index options.
+ };
+
+ class add_index: public index
+ {
+ public:
+ add_index (string const& id,
+ string const& t = string (),
+ string const& m = string (),
+ string const& o = string ())
+ : index (id, t, m, o) {}
+ add_index (index const& i, uscope& s, graph& g): index (i, s, g) {}
+ add_index (xml::parser& p, uscope& s, graph& g): index (p, s, g) {}
+
+ virtual add_index&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const {return "add index";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+
+ class drop_index: public unameable
+ {
+ public:
+ drop_index (string const& id): unameable (id) {}
+ drop_index (drop_index const& di, uscope&, graph& g)
+ : unameable (di, g) {}
+ drop_index (xml::parser&, uscope&, graph&);
+
+ virtual drop_index&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const {return "drop index";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_INDEX_HXX
diff --git a/odb/odb/semantics/relational/key.cxx b/odb/odb/semantics/relational/key.cxx
new file mode 100644
index 0000000..3511618
--- /dev/null
+++ b/odb/odb/semantics/relational/key.cxx
@@ -0,0 +1,97 @@
+// file : odb/semantics/relational/key.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/key.hxx>
+#include <odb/semantics/relational/column.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ key::
+ key (key const& k, uscope& s, graph& g)
+ : unameable (k, g)
+ {
+ for (contains_iterator i (k.contains_begin ());
+ i != k.contains_end (); ++i)
+ {
+ column* c (s.lookup<column, drop_column> (i->column ().name ()));
+ assert (c != 0);
+ g.new_edge<contains> (*this, *c, i->options ());
+ }
+ }
+
+ key::
+ key (xml::parser& p, uscope& s, graph& g)
+ : unameable (p, g)
+ {
+ using namespace xml;
+ p.content (content::complex);
+
+ for (parser::event_type e (p.peek ());
+ e == parser::start_element;
+ e = p.peek ())
+ {
+ if (p.qname () != xml::qname (xmlns, "column"))
+ break; // Not our elements.
+
+ p.next ();
+ p.content (content::empty);
+
+ uname n (p.attribute<uname> ("name"));
+ column* c (s.lookup<column, drop_column> (n));
+ if (c == 0)
+ throw parsing (p, "invalid column name in the 'name' attribute");
+
+ string o (p.attribute ("options", string ()));
+ g.new_edge<contains> (*this, *c, o);
+
+ p.next_expect (parser::end_element);
+ }
+ }
+
+ void key::
+ serialize_content (xml::serializer& s) const
+ {
+ for (contains_iterator i (contains_begin ()); i != contains_end (); ++i)
+ {
+ s.start_element (xmlns, "column");
+ s.attribute ("name", i->column ().name ());
+ if (!i->options ().empty ())
+ s.attribute ("options", i->options ());
+ s.end_element ();
+ }
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ // contains
+ //
+ {
+ type_info ti (typeid (contains));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ // key
+ //
+ {
+ type_info ti (typeid (key));
+ ti.add_base (typeid (node));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/key.hxx b/odb/odb/semantics/relational/key.hxx
new file mode 100644
index 0000000..814d2ec
--- /dev/null
+++ b/odb/odb/semantics/relational/key.hxx
@@ -0,0 +1,104 @@
+// file : odb/semantics/relational/key.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_KEY_HXX
+#define ODB_SEMANTICS_RELATIONAL_KEY_HXX
+
+#include <odb/semantics/relational/elements.hxx>
+#include <odb/semantics/relational/table.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ class key;
+ class column;
+
+ class contains: public edge
+ {
+ public:
+ typedef relational::key key_type;
+ typedef relational::column column_type;
+
+ key_type&
+ key () const {return *key_;}
+
+ column_type&
+ column () const {return *column_;}
+
+ string const&
+ options () const {return options_;}
+
+ public:
+ contains (string const& o = string ()) : options_ (o) {}
+
+ void
+ set_left_node (key_type& n)
+ {
+ key_ = &n;
+ }
+
+ void
+ set_right_node (column_type& n)
+ {
+ column_ = &n;
+ }
+
+ protected:
+ key_type* key_;
+ column_type* column_;
+ string options_;
+ };
+
+ class key: public unameable
+ {
+ typedef std::vector<contains*> contains_list;
+
+ public:
+ typedef contains_list::size_type contains_size_type;
+
+ typedef
+ pointer_iterator<contains_list::const_iterator>
+ contains_iterator;
+
+ contains_iterator
+ contains_begin () const {return contains_.begin ();}
+
+ contains_iterator
+ contains_end () const {return contains_.end ();}
+
+ contains_size_type
+ contains_size () const {return contains_.size ();}
+
+ contains&
+ contains_at (contains_size_type i) const {return *contains_[i];}
+
+ public:
+ typedef relational::table table_type;
+
+ table_type&
+ table () const {return dynamic_cast<table_type&> (scope ());}
+
+ public:
+ key (std::string const& id): unameable (id) {}
+
+ void
+ add_edge_left (contains& e)
+ {
+ contains_.push_back (&e);
+ }
+
+ protected:
+ key (key const&, uscope&, graph&);
+ key (xml::parser&, uscope&, graph&);
+
+ void
+ serialize_content (xml::serializer&) const;
+
+ private:
+ contains_list contains_;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_KEY_HXX
diff --git a/odb/odb/semantics/relational/model.cxx b/odb/odb/semantics/relational/model.cxx
new file mode 100644
index 0000000..8763045
--- /dev/null
+++ b/odb/odb/semantics/relational/model.cxx
@@ -0,0 +1,54 @@
+// file : odb/semantics/relational/model.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/model.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ model::
+ model (model const& m, graph& g)
+ : qscope (m, 0, g),
+ version_ (m.version_)
+ {
+ }
+
+ model::
+ model (xml::parser& p, graph& g)
+ : qscope (p, 0, g),
+ version_ (p.attribute<version_type> ("version"))
+ {
+ }
+
+ void model::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "model");
+ s.attribute ("version", version_);
+ qscope::serialize_content (s);
+ s.end_element ();
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ {
+ type_info ti (typeid (model));
+ ti.add_base (typeid (qscope));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/model.hxx b/odb/odb/semantics/relational/model.hxx
new file mode 100644
index 0000000..02d1863
--- /dev/null
+++ b/odb/odb/semantics/relational/model.hxx
@@ -0,0 +1,49 @@
+// file : odb/semantics/relational/model.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_MODEL_HXX
+#define ODB_SEMANTICS_RELATIONAL_MODEL_HXX
+
+#include <odb/semantics/relational/elements.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ class model: public graph, public qscope
+ {
+ public:
+ typedef relational::version version_type;
+
+ version_type
+ version () const {return version_;}
+
+ void
+ version (version_type v) {version_ = v;}
+
+ public:
+ model (version_type v): version_ (v) {}
+ model (model const&, graph&);
+ model (xml::parser&, graph&);
+
+ virtual string
+ kind () const {return "model";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ public:
+ using qscope::add_edge_left;
+ using qscope::add_edge_right;
+
+ private:
+ model (model const&);
+ model& operator= (model const&);
+
+ private:
+ version_type version_;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_MODEL_HXX
diff --git a/odb/odb/semantics/relational/name.cxx b/odb/odb/semantics/relational/name.cxx
new file mode 100644
index 0000000..6eb2e16
--- /dev/null
+++ b/odb/odb/semantics/relational/name.cxx
@@ -0,0 +1,89 @@
+// file : odb/semantics/relational/name.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <ostream>
+#include <istream>
+
+#include <odb/semantics/relational/name.hxx>
+
+using namespace std;
+
+namespace semantics
+{
+ namespace relational
+ {
+ string qname::
+ string () const
+ {
+ std::string r;
+
+ bool f (true);
+ for (iterator i (begin ()); i < end (); ++i)
+ {
+ if (i->empty ())
+ continue;
+
+ if (f)
+ f = false;
+ else
+ r += '.';
+
+ r += *i;
+ }
+
+ return r;
+ }
+
+ qname qname::
+ from_string (std::string const& s)
+ {
+ using std::string;
+
+ qname n;
+
+ string::size_type p (string::npos);
+
+ for (size_t i (0); i < s.size (); ++i)
+ {
+ char c (s[i]);
+
+ if (c == '.')
+ {
+ if (p == string::npos)
+ n.append (string (s, 0, i));
+ else
+ n.append (string (s, p + 1, i - p - 1));
+
+ p = i;
+ }
+ }
+
+ if (p == string::npos)
+ n.append (s);
+ else
+ n.append (string (s, p + 1, string::npos));
+
+ return n;
+ }
+
+ ostream&
+ operator<< (ostream& os, qname const& n)
+ {
+ return os << n.string ();
+ }
+
+ istream&
+ operator>> (istream& is, qname& n)
+ {
+ string s;
+ is >> s;
+
+ if (!is.fail ())
+ n = qname::from_string (s);
+ else
+ n.clear ();
+
+ return is;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/name.hxx b/odb/odb/semantics/relational/name.hxx
new file mode 100644
index 0000000..5268b4a
--- /dev/null
+++ b/odb/odb/semantics/relational/name.hxx
@@ -0,0 +1,159 @@
+// file : odb/semantics/relational/name.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_NAME_HXX
+#define ODB_SEMANTICS_RELATIONAL_NAME_HXX
+
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+namespace semantics
+{
+ namespace relational
+ {
+ typedef std::string uname;
+
+ class qname
+ {
+ public:
+ typedef relational::uname uname_type;
+
+ qname () {}
+
+ explicit
+ qname (uname_type const& n) {append (n);}
+
+ template <typename I>
+ qname (I begin, I end)
+ {
+ for (; begin != end; ++begin)
+ append (*begin);
+ }
+
+ qname&
+ operator= (uname_type const& n)
+ {
+ components_.resize (1);
+ components_[0] = n;
+ return *this;
+ }
+
+ void
+ append (uname_type const& n) {components_.push_back (n);}
+
+ void
+ append (qname const& n)
+ {
+ components_.insert (components_.end (),
+ n.components_.begin (),
+ n.components_.end ());
+ }
+
+ void
+ clear () {components_.clear ();}
+
+ // Append a string to the last component.
+ //
+ qname&
+ operator+= (std::string const& s)
+ {
+ if (empty ())
+ append (s);
+ else
+ uname () += s;
+
+ return *this;
+ }
+
+ friend qname
+ operator+ (qname const& n, std::string const& s)
+ {
+ qname r (n);
+
+ if (r.empty ())
+ r.append (s);
+ else
+ r.uname () += s;
+
+ return r;
+ }
+
+ void
+ swap (qname& n) {components_.swap (n.components_);}
+
+ public:
+ bool
+ empty () const {return components_.empty ();}
+
+ bool
+ qualified () const {return components_.size () > 1;}
+
+ bool
+ fully_qualified () const
+ {
+ return qualified () && components_.front ().empty ();
+ }
+
+ public:
+ typedef std::vector<uname_type> components;
+ typedef components::const_iterator iterator;
+
+ iterator
+ begin () const {return components_.begin ();}
+
+ iterator
+ end () const {return components_.end ();}
+
+ uname_type&
+ uname () {return components_.back ();}
+
+ uname_type const&
+ uname () const {return components_.back ();}
+
+ qname
+ qualifier () const
+ {
+ return empty ()
+ ? qname ()
+ : qname (components_.begin (), components_.end () - 1);
+ }
+
+ std::string
+ string () const;
+
+ static qname
+ from_string (std::string const&);
+
+ public:
+ friend bool
+ operator== (qname const& x, qname const& y)
+ {
+ return x.components_ == y.components_;
+ }
+
+ friend bool
+ operator!= (qname const& x, qname const& y)
+ {
+ return x.components_ != y.components_;
+ }
+
+ friend bool
+ operator< (qname const& x, qname const& y)
+ {
+ return x.components_ < y.components_;
+ }
+
+ private:
+ components components_;
+ };
+
+ std::ostream&
+ operator<< (std::ostream&, qname const&);
+
+ std::istream&
+ operator>> (std::istream&, qname&);
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_NAME_HXX
diff --git a/odb/odb/semantics/relational/primary-key.cxx b/odb/odb/semantics/relational/primary-key.cxx
new file mode 100644
index 0000000..235340f
--- /dev/null
+++ b/odb/odb/semantics/relational/primary-key.cxx
@@ -0,0 +1,80 @@
+// file : odb/semantics/relational/primary-key.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/primary-key.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ primary_key::
+ primary_key (primary_key const& k, uscope& s, graph& g)
+ : key (k, s, g), auto__ (k.auto__), extra_map_ (k.extra_map_)
+ {
+ }
+
+ primary_key::
+ primary_key (xml::parser& p, uscope& s, graph& g)
+ : key (p, s, g),
+ auto__ (p.attribute ("auto", false))
+ {
+ // All unhandled attributes go into the extra map.
+ //
+ typedef xml::parser::attribute_map_type attr_map;
+ attr_map const& am (p.attribute_map ());
+
+ for (attr_map::const_iterator i (am.begin ()); i != am.end (); ++i)
+ {
+ if (!i->second.handled)
+ extra_map_[i->first.name ()] = i->second.value;
+ }
+ }
+
+ primary_key& primary_key::
+ clone (uscope& s, graph& g) const
+ {
+ return g.new_node<primary_key> (*this, s, g);
+ }
+
+ void primary_key::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "primary-key");
+ key::serialize_attributes (s);
+
+ if (auto_ ())
+ s.attribute ("auto", true);
+
+ for (extra_map::const_iterator i (extra_map_.begin ());
+ i != extra_map_.end (); ++i)
+ s.attribute (i->first, i->second);
+
+ key::serialize_content (s);
+ s.end_element ();
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ unameable::parser_map_["primary-key"] =
+ &unameable::parser_impl<primary_key>;
+
+ using compiler::type_info;
+
+ {
+ type_info ti (typeid (primary_key));
+ ti.add_base (typeid (key));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/primary-key.hxx b/odb/odb/semantics/relational/primary-key.hxx
new file mode 100644
index 0000000..114f682
--- /dev/null
+++ b/odb/odb/semantics/relational/primary-key.hxx
@@ -0,0 +1,62 @@
+// file : odb/semantics/relational/primary-key.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_PRIMARY_KEY_HXX
+#define ODB_SEMANTICS_RELATIONAL_PRIMARY_KEY_HXX
+
+#include <map>
+
+#include <odb/semantics/relational/elements.hxx>
+#include <odb/semantics/relational/key.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ class primary_key: public key
+ {
+ public:
+ bool
+ auto_ () const {return auto__;}
+
+ // Extra information.
+ //
+ public:
+ typedef std::map<string, string> extra_map;
+
+ extra_map&
+ extra () {return extra_map_;}
+
+ extra_map const&
+ extra () const {return extra_map_;}
+
+ public:
+ primary_key (bool auto_)
+ : key (""), // Primary key has the implicit empty id.
+ auto__ (auto_)
+ {
+ }
+
+ primary_key (primary_key const&, uscope&, graph&);
+ primary_key (xml::parser&, uscope&, graph&);
+
+ virtual primary_key&
+ clone (uscope&, graph&) const;
+
+ virtual string
+ kind () const
+ {
+ return "primary key";
+ }
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ private:
+ bool auto__;
+ extra_map extra_map_;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_PRIMARY_KEY_HXX
diff --git a/odb/odb/semantics/relational/table.cxx b/odb/odb/semantics/relational/table.cxx
new file mode 100644
index 0000000..3bf763d
--- /dev/null
+++ b/odb/odb/semantics/relational/table.cxx
@@ -0,0 +1,183 @@
+// file : odb/semantics/relational/table.cxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <libcutl/compiler/type-info.hxx>
+
+#include <odb/semantics/relational/table.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ // table
+ //
+ table::
+ table (table const& t, qscope& s, graph& g, bool b)
+ : qnameable (t, g),
+ uscope (t, (b ? s.lookup<table, drop_table> (t.name ()) : 0), g),
+ options_ (t.options_),
+ extra_map_ (t.extra_map_)
+ {
+ }
+
+ table::
+ table (xml::parser& p, qscope& s, graph& g, bool b)
+ : qnameable (p, g),
+ uscope (
+ p,
+ (b ? s.lookup<table, drop_table> (
+ p.attribute<qnameable::name_type> ("name")) : 0),
+ g),
+ options_ (p.attribute ("options", string ()))
+ {
+ // All unhandled attributes go into the extra map.
+ //
+ typedef xml::parser::attribute_map_type attr_map;
+ attr_map const& am (p.attribute_map ());
+
+ for (attr_map::const_iterator i (am.begin ()); i != am.end (); ++i)
+ {
+ if (!i->second.handled)
+ extra_map_[i->first.name ()] = i->second.value;
+ }
+ }
+
+ table& table::
+ clone (qscope& s, graph& g) const
+ {
+ return g.new_node<table> (*this, s, g);
+ }
+
+ void table::
+ serialize_attributes (xml::serializer& s) const
+ {
+ qnameable::serialize_attributes (s);
+
+ if (!options_.empty ())
+ s.attribute ("options", options_);
+
+ for (extra_map::const_iterator i (extra_map_.begin ());
+ i != extra_map_.end (); ++i)
+ s.attribute (i->first, i->second);
+ }
+
+ void table::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "table");
+ serialize_attributes (s);
+ uscope::serialize_content (s);
+ s.end_element ();
+ }
+
+ // add_table
+ //
+ add_table& add_table::
+ clone (qscope& s, graph& g) const
+ {
+ return g.new_node<add_table> (*this, s, g);
+ }
+
+ void add_table::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "add-table");
+ table::serialize_attributes (s);
+ table::serialize_content (s);
+ s.end_element ();
+ }
+
+ // drop_table
+ //
+ drop_table::
+ drop_table (xml::parser& p, qscope&, graph& g)
+ : qnameable (p, g)
+ {
+ p.content (xml::content::empty);
+ }
+
+ drop_table& drop_table::
+ clone (qscope& s, graph& g) const
+ {
+ return g.new_node<drop_table> (*this, s, g);
+ }
+
+ void drop_table::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "drop-table");
+ qnameable::serialize_attributes (s);
+ s.end_element ();
+ }
+
+ // alter_table
+ //
+ alter_table& alter_table::
+ clone (qscope& s, graph& g) const
+ {
+ return g.new_node<alter_table> (*this, s, g);
+ }
+
+ void alter_table::
+ serialize (xml::serializer& s) const
+ {
+ s.start_element (xmlns, "alter-table");
+ table::serialize_attributes (s);
+ table::serialize_content (s);
+ s.end_element ();
+ }
+
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ qnameable::parser_map& m (qnameable::parser_map_);
+
+ m["table"] = &qnameable::parser_impl<table>;
+ m["add-table"] = &qnameable::parser_impl<add_table>;
+ m["drop-table"] = &qnameable::parser_impl<drop_table>;
+ m["alter-table"] = &qnameable::parser_impl<alter_table>;
+
+ using compiler::type_info;
+
+ // table
+ //
+ {
+ type_info ti (typeid (table));
+ ti.add_base (typeid (qnameable));
+ ti.add_base (typeid (uscope));
+ insert (ti);
+ }
+
+ // add_table
+ //
+ {
+ type_info ti (typeid (add_table));
+ ti.add_base (typeid (table));
+ insert (ti);
+ }
+
+ // drop_table
+ //
+ {
+ type_info ti (typeid (drop_table));
+ ti.add_base (typeid (qnameable));
+ insert (ti);
+ }
+
+ // alter_table
+ //
+ {
+ type_info ti (typeid (alter_table));
+ ti.add_base (typeid (table));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+ }
+}
diff --git a/odb/odb/semantics/relational/table.hxx b/odb/odb/semantics/relational/table.hxx
new file mode 100644
index 0000000..1c4efcf
--- /dev/null
+++ b/odb/odb/semantics/relational/table.hxx
@@ -0,0 +1,115 @@
+// file : odb/semantics/relational/table.hxx
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_RELATIONAL_TABLE_HXX
+#define ODB_SEMANTICS_RELATIONAL_TABLE_HXX
+
+#include <odb/semantics/relational/elements.hxx>
+
+namespace semantics
+{
+ namespace relational
+ {
+ class table: public qnameable, public uscope
+ {
+ public:
+ virtual string const&
+ options () const {return options_;}
+
+ virtual void
+ options (string const& o) {options_ = o;}
+
+ // Extra information.
+ //
+ public:
+ typedef std::map<string, string> extra_map;
+
+ extra_map&
+ extra () {return extra_map_;}
+
+ extra_map const&
+ extra () const {return extra_map_;}
+
+ public:
+ table (string const& id): qnameable (id) {}
+ table (table const&, qscope&, graph&, bool base = false);
+ table (xml::parser&, qscope&, graph&, bool base = false);
+
+ virtual table&
+ clone (qscope&, graph&) const;
+
+ virtual string
+ kind () const {return "table";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+
+ // Resolve ambiguity.
+ //
+ using qnameable::scope;
+
+ protected:
+ void
+ serialize_attributes (xml::serializer&) const;
+
+ protected:
+ string options_;
+ extra_map extra_map_;
+ };
+
+ class add_table: public table
+ {
+ public:
+ add_table (string const& id): table (id) {}
+ add_table (table const& t, qscope& s, graph& g): table (t, s, g) {}
+ add_table (xml::parser& p, qscope& s, graph& g): table (p, s, g) {}
+
+ virtual add_table&
+ clone (qscope&, graph&) const;
+
+ virtual string
+ kind () const {return "add table";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+
+ class drop_table: public qnameable
+ {
+ public:
+ drop_table (string const& id): qnameable (id) {}
+ drop_table (drop_table const& t, qscope&, graph& g): qnameable (t, g) {}
+ drop_table (xml::parser&, qscope&, graph&);
+
+ virtual drop_table&
+ clone (qscope&, graph&) const;
+
+ virtual string
+ kind () const {return "drop table";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+
+ class alter_table: public table
+ {
+ public:
+ alter_table (string const& id): table (id) {}
+ alter_table (alter_table const& at, qscope& s, graph& g)
+ : table (at, s, g, true) {}
+ alter_table (xml::parser& p, qscope& s, graph& g)
+ : table (p, s, g, true) {}
+
+ virtual alter_table&
+ clone (qscope&, graph&) const;
+
+ virtual string
+ kind () const {return "alter table";}
+
+ virtual void
+ serialize (xml::serializer&) const;
+ };
+ }
+}
+
+#endif // ODB_SEMANTICS_RELATIONAL_TABLE_HXX