diff options
Diffstat (limited to 'odb/odb/semantics/relational')
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 |