From af12ffe836de09ec84f666effa4df347eeb07a43 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 26 Jan 2012 12:43:16 +0200 Subject: Implement support for database schema New pragma qualifier: namespace. New pragma specifier: schema. The table specifier was extended to accept a schema prefix. New option: --default- schema. The common/schema test was extended to cover the new functionality. --- odb/common.cxx | 31 ++- odb/context.cxx | 117 +++++++-- odb/context.hxx | 28 +- odb/makefile | 11 +- odb/option-types.hxx | 4 + odb/options.cli | 6 + odb/parser.cxx | 110 +++++++- odb/parser.hxx | 2 +- odb/plugin.cxx | 2 +- odb/pragma.cxx | 427 ++++++++++++++++++++++--------- odb/pragma.hxx | 17 ++ odb/relational/common.cxx | 9 +- odb/relational/context.cxx | 23 +- odb/relational/context.hxx | 5 +- odb/relational/context.ixx | 6 + odb/relational/header.hxx | 6 +- odb/relational/model.cxx | 14 +- odb/relational/model.hxx | 26 +- odb/relational/mssql/context.cxx | 23 +- odb/relational/mssql/context.hxx | 2 +- odb/relational/mssql/schema.cxx | 32 ++- odb/relational/mysql/context.cxx | 23 +- odb/relational/mysql/context.hxx | 2 +- odb/relational/mysql/schema.cxx | 22 +- odb/relational/oracle/context.cxx | 23 +- odb/relational/oracle/context.hxx | 2 +- odb/relational/oracle/schema.cxx | 20 +- odb/relational/pgsql/schema.cxx | 20 +- odb/relational/processor.cxx | 12 +- odb/relational/schema.cxx | 4 +- odb/relational/schema.hxx | 36 ++- odb/relational/source.hxx | 41 +-- odb/relational/sqlite/schema.cxx | 30 +++ odb/semantics/namespace.cxx | 3 +- odb/semantics/namespace.hxx | 22 ++ odb/semantics/relational/column.cxx | 2 +- odb/semantics/relational/column.hxx | 6 +- odb/semantics/relational/elements.cxx | 106 +++----- odb/semantics/relational/elements.hxx | 88 ++++--- odb/semantics/relational/elements.txx | 94 +++++++ odb/semantics/relational/foreign-key.cxx | 1 + odb/semantics/relational/foreign-key.hxx | 10 +- odb/semantics/relational/index.cxx | 1 + odb/semantics/relational/index.hxx | 5 +- odb/semantics/relational/key.cxx | 2 +- odb/semantics/relational/key.hxx | 10 +- odb/semantics/relational/model.cxx | 2 +- odb/semantics/relational/model.hxx | 6 +- odb/semantics/relational/name.cxx | 95 +++++++ odb/semantics/relational/name.hxx | 146 +++++++++++ odb/semantics/relational/primary-key.cxx | 1 + odb/semantics/relational/primary-key.hxx | 8 +- odb/semantics/relational/table.cxx | 4 +- odb/semantics/relational/table.hxx | 4 +- odb/traversal/relational/elements.cxx | 18 -- odb/traversal/relational/elements.hxx | 25 +- 56 files changed, 1349 insertions(+), 446 deletions(-) create mode 100644 odb/semantics/relational/elements.txx create mode 100644 odb/semantics/relational/name.cxx create mode 100644 odb/semantics/relational/name.hxx delete mode 100644 odb/traversal/relational/elements.cxx (limited to 'odb') diff --git a/odb/common.cxx b/odb/common.cxx index 379c769..fe77b2c 100644 --- a/odb/common.cxx +++ b/odb/common.cxx @@ -120,7 +120,7 @@ traverse (semantics::class_& c) if (table_prefix_.level == 0) { table_prefix_.prefix = table_name (c); - table_prefix_.prefix += '_'; + table_prefix_.prefix += "_"; table_prefix_.level = 1; tb = true; } @@ -170,7 +170,8 @@ traverse (semantics::data_member& m) om_.member_scope_.push_back (class_inheritance_chain ()); om_.member_scope_.back ().push_back (comp); - string old_flat_prefix, old_table_prefix, old_member_prefix; + qname old_table_prefix; + string old_flat_prefix, old_member_prefix; if (om_.build_flat_prefix_) { @@ -225,15 +226,27 @@ append (semantics::data_member& m, table_prefix& tp) { context& ctx (context::current ()); - // If the user provided a table prefix, then use it verbatim. Also - // drop the top-level table prefix in this case. + // If a custom table prefix was specified, then ignore the top-level + // table prefix (this corresponds to a container directly inside an + // object) but keep the schema unless the alternative schema is fully + // qualified. // if (m.count ("table")) { - if (tp.level <= 1) - tp.prefix = ctx.options.table_prefix (); + qname p, n (m.get ("table")); - tp.prefix += m.get ("table"); + if (n.fully_qualified ()) + p = n.qualifier (); + else + { + p = tp.prefix.qualifier (); + p.append (n.qualifier ()); + } + + p.append (tp.level <= 1 ? ctx.options.table_prefix () : tp.prefix.uname ()); + p += n.uname (); + + tp.prefix.swap (p); } // Otherwise use the member name and add an underscore unless it is // already there. @@ -244,12 +257,12 @@ append (semantics::data_member& m, table_prefix& tp) size_t n (name.size ()); if (tp.prefix.empty ()) - tp.prefix = ctx.options.table_prefix (); + tp.prefix.append (ctx.options.table_prefix ()); tp.prefix += name; if (n != 0 && name[n - 1] != '_') - tp.prefix += '_'; + tp.prefix += "_"; } tp.level++; diff --git a/odb/context.cxx b/odb/context.cxx index 95b05aa..0d471cd 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -30,7 +30,7 @@ name () const if (!alias.empty ()) return alias; - return kind == object ? context::class_name (*obj) : orig_name; + return kind == object ? context::class_name (*obj) : tbl_name.string (); } // @@ -560,20 +560,93 @@ composite_ (semantics::class_& c) return r; } -string context:: +qname context:: table_name (semantics::class_& c) const { - string name (options.table_prefix ()); + if (c.count ("qualified-table")) + return c.get ("qualified-table"); + + qname r; + + bool sf (c.count ("schema")); if (c.count ("table")) - name += c.get ("table"); + { + r = c.get ("table"); + + if (sf) + { + // If we have both schema and qualified table, see which takes + // precedence based on order. If the table is unqualifed, then + // add the schema. + // + sf = !r.qualified () || + c.get ("table-location") < + c.get ("schema-location"); + } + } else - name += class_name (c); + r = class_name (c); + + if (sf) + { + qname n (c.get ("schema")); + n.append (r.uname ()); + n.swap (r); + } + + // Unless we are fully qualified, add any schemas that were + // specified on the namespaces. + // + if (!r.fully_qualified ()) + { + for (semantics::scope* s (&c.scope ());; s = &s->scope_ ()) + { + using semantics::namespace_; + + namespace_* ns (dynamic_cast (s)); + + if (ns == 0) + continue; // Some other scope. + + if (ns->extension ()) + ns = &ns->original (); + + if (ns->count ("schema")) + { + qname n (ns->get ("schema")); + n.append (r); + n.swap (r); - return name; + if (r.fully_qualified ()) + break; + } + + if (ns->global_scope ()) + break; + } + } + + // Finally, if we are still not fully qualified, add the schema + // that was specified on the command line. + // + if (!r.fully_qualified () && options.default_schema_specified ()) + { + qname n (options.default_schema ()); + n.append (r); + n.swap (r); + } + + // Add the table prefix if specified. + // + if (options.table_prefix_specified ()) + r.uname () = options.table_prefix () + r.uname (); + + c.set ("qualified-table", r); + return r; } -string context:: +qname context:: table_name (semantics::class_& obj, data_member_path const& mp) const { table_prefix tp (table_name (obj) + "_", 1); @@ -597,36 +670,44 @@ table_name (semantics::class_& obj, data_member_path const& mp) const } } -string context:: +qname context:: table_name (semantics::data_member& m, table_prefix const& p) const { // The table prefix passed as the second argument must include // the table prefix specified with the --table-prefix option. // string const& gp (options.table_prefix ()); - assert (p.prefix.compare (0, gp.size (), gp) == 0); + assert (p.prefix.uname ().compare (0, gp.size (), gp) == 0); - string name; + qname r; // If a custom table name was specified, then ignore the top-level - // table prefix. + // table prefix (this corresponds to a container directly inside an + // object) but keep the schema unless the container table is fully + // qualified. // if (m.count ("table")) { - if (p.level != 1) - name = p.prefix; + qname n (m.get ("table")); + + if (n.fully_qualified ()) + r = n.qualifier (); else - name = gp; + { + r = p.prefix.qualifier (); + r.append (n.qualifier ()); + } - name += m.get ("table"); + r.append (p.level == 1 ? gp : p.prefix.uname ()); + r += n.uname (); } else { - name = p.prefix; - name += public_name_db (m); + r = p.prefix; + r += public_name_db (m); } - return name; + return r; } string context:: diff --git a/odb/context.hxx b/odb/context.hxx index 808e18f..c63115a 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -125,11 +126,17 @@ struct default_value tree node; }; +// Database potentially-qualified name. +// +using semantics::relational::qname; + // Object or table associated with the view. // struct view_object { - // Return an alias or unqualified object name. + // Return a diagnostic name for this association. It is either the + // alias, unqualified object name, or string representation of the + // table name. // std::string name () const; @@ -137,8 +144,9 @@ struct view_object enum kind_type { object, table }; kind_type kind; - tree node; // Tree node if kind is object. - std::string orig_name; // Original name as specified in the pragma. + tree obj_node; // Tree node if kind is object. + std::string obj_name; // Name as specified in the pragma if kind is object. + qname tbl_name; // Table name if kind is table. std::string alias; tree scope; location_t loc; @@ -176,7 +184,7 @@ struct view_query // struct table_column { - std::string table; + qname table; std::string column; bool expr; // True if column is an expression, and therefore should not // be quoted. @@ -194,7 +202,7 @@ struct column_expr_part kind_type kind; std::string value; - std::string table; // Table name/alias for references. + qname table; // Table name/alias for references. data_member_path member_path; // Path to member for references. // Scope and location of this pragma. Used to resolve the member name. @@ -450,18 +458,18 @@ public: // Database names and types. // public: - string + qname table_name (semantics::class_&) const; - string + qname table_name (semantics::class_&, data_member_path const&) const; struct table_prefix { table_prefix (): level (0) {} - table_prefix (string const& p, size_t l): prefix (p), level (l) {} + table_prefix (qname const& p, size_t l): prefix (p), level (l) {} - string prefix; + qname prefix; size_t level; }; @@ -469,7 +477,7 @@ public: // second argument must include the table prefix specified with the // --table-prefix option. // - string + qname table_name (semantics::data_member&, table_prefix const&) const; string diff --git a/odb/makefile b/odb/makefile index 321b532..dbacb45 100644 --- a/odb/makefile +++ b/odb/makefile @@ -126,18 +126,17 @@ traversal/enum.cxx \ traversal/template.cxx \ traversal/union-template.cxx -# Traversal. -# -cxx_ptun += \ -traversal/relational/elements.cxx - # Driver units. # cxx_dtun := odb.cxx # Common units. # -cxx_ctun := option-types.cxx option-functions.cxx profile.cxx +cxx_ctun := \ +option-types.cxx \ +option-functions.cxx \ +profile.cxx \ +semantics/relational/name.cxx # Options file. # diff --git a/odb/option-types.hxx b/odb/option-types.hxx index b674eae..3e86d77 100644 --- a/odb/option-types.hxx +++ b/odb/option-types.hxx @@ -8,6 +8,10 @@ #include +#include + +using semantics::relational::qname; + struct database { enum value diff --git a/odb/options.cli b/odb/options.cli index c92e4aa..61cc92e 100644 --- a/odb/options.cli +++ b/odb/options.cli @@ -143,6 +143,12 @@ class options profile." }; + qname --default-schema + { + "", + "Place database objects (tables, indexes, etc) into ." + }; + std::string --table-prefix { "", diff --git a/odb/parser.cxx b/odb/parser.cxx index 474aa3d..68a3b27 100644 --- a/odb/parser.cxx +++ b/odb/parser.cxx @@ -25,7 +25,7 @@ class parser::impl public: typedef parser::failed failed; - impl (options const&, loc_pragmas const&, decl_pragmas const&); + impl (options const&, loc_pragmas&, ns_loc_pragmas&, decl_pragmas&); auto_ptr parse (tree global_scope, path const& main_file); @@ -159,8 +159,9 @@ private: private: options const& ops_; - loc_pragmas const& loc_pragmas_; - decl_pragmas const& decl_pragmas_; + loc_pragmas& loc_pragmas_; + ns_loc_pragmas& ns_loc_pragmas_; + decl_pragmas& decl_pragmas_; bool trace; ostream& ts; @@ -170,6 +171,9 @@ private: size_t error_; decl_set decls_; + + typedef map decl_map; + decl_map all_decls_; }; bool parser::impl::tree_decl:: @@ -638,9 +642,13 @@ emit_union (tree u, path const& file, size_t line, size_t clmn, bool stub) // parser::impl:: -impl (options const& ops, loc_pragmas const& lp, decl_pragmas const& dp) +impl (options const& ops, + loc_pragmas & lp, + ns_loc_pragmas& nslp, + decl_pragmas& dp) : ops_ (ops), loc_pragmas_ (lp), + ns_loc_pragmas_ (nslp), decl_pragmas_ (dp), trace (ops.trace ()), ts (cerr) @@ -652,6 +660,7 @@ parse (tree global_scope, path const& main_file) { auto_ptr u (new unit (main_file)); u->insert (global_namespace, *u); + process_named_pragmas (global_namespace, *u); unit_ = u.get (); scope_ = unit_; @@ -683,7 +692,7 @@ parse (tree global_scope, path const& main_file) // collect (global_scope); - // Add namespace-level location pragmas if any. + // Add namespace-level position pragmas if any. // { loc_pragmas::const_iterator i (loc_pragmas_.find (global_namespace)); @@ -692,9 +701,68 @@ parse (tree global_scope, path const& main_file) decls_.insert (i->second.begin (), i->second.end ()); } + // Convert position namespace pragmas to name pragmas. + // + for (ns_loc_pragmas::const_iterator i (ns_loc_pragmas_.begin ()); + i != ns_loc_pragmas_.end (); ++i) + { + pragma const& p (i->pragma); + + decl_map::const_iterator j (all_decls_.lower_bound (p.loc)); + + if (j == all_decls_.end ()) + { + error (p.loc) + << "db pragma '" << p.pragma_name << "' is not associated with a " + << "namespace declaration" << endl; + error_++; + continue; + } + + // Find the "namespace difference" between this declaration and + // the pragma's namespace. The outermost namespace in the result + // is what we are looking for. + // + tree ns (0); + + for (tree prev (j->second), scope (CP_DECL_CONTEXT (prev));; + scope = CP_DECL_CONTEXT (scope)) + { + if (scope == i->ns) + { + ns = prev; + break; + } + + if (scope == global_namespace) + break; + + prev = scope; + } + + if (ns == 0 || TREE_CODE (ns) != NAMESPACE_DECL) + { + error (p.loc) + << "db pragma '" << p.pragma_name << "' is not associated with a " + << "namespace declaration" << endl; + error_++; + continue; + } + + pragma_set& s (decl_pragmas_[ns]); + pragma_set::iterator it (s.find (p)); + + // Make sure we override only if this pragma came after the one + // already in the set. + // + if (it == s.end () || it->loc < p.loc) + s.insert (p); + } + // Construct the semantic graph. // - emit (); + if (error_ == 0) + emit (); if (error_ > 0) throw failed (); @@ -712,6 +780,8 @@ collect (tree ns) // for (; decl != NULL_TREE; decl = TREE_CHAIN (decl)) { + all_decls_[DECL_SOURCE_LOCATION (decl)] = decl; + if (DECL_IS_BUILTIN (decl)) continue; @@ -739,7 +809,7 @@ collect (tree ns) // Traverse namespaces. // - for(decl = level->namespaces; decl != NULL_TREE; decl = TREE_CHAIN (decl)) + for (decl = level->namespaces; decl != NULL_TREE; decl = TREE_CHAIN (decl)) { if (!DECL_IS_BUILTIN (decl) || DECL_NAMESPACE_STD_P (decl)) { @@ -813,7 +883,24 @@ emit () namespace_& node (unit_->new_node (f, l, c, tree_node)); unit_->new_edge (*scope_, node, n); - unit_->insert (tree_node, node); + + if (namespace_* orig = + dynamic_cast (unit_->find (tree_node))) + { + // This is an extension. + // + node.original (*orig); + } + else + { + // This is the original. Add it to the map and process any + // pragmas it might have (at this stage namespaces can only + // have name pragmas). + // + unit_->insert (tree_node, node); + process_named_pragmas (tree_node, node); + } + scope_ = &node; if (e == string::npos) @@ -2019,8 +2106,11 @@ fq_scope (tree decl) // parser:: -parser (options const& ops, loc_pragmas const& lp, decl_pragmas const& dp) - : impl_ (new impl (ops, lp, dp)) +parser (options const& ops, + loc_pragmas& lp, + ns_loc_pragmas& nslp, + decl_pragmas& dp) + : impl_ (new impl (ops, lp, nslp, dp)) { } diff --git a/odb/parser.hxx b/odb/parser.hxx index 2fbe904..5b39524 100644 --- a/odb/parser.hxx +++ b/odb/parser.hxx @@ -19,7 +19,7 @@ class parser public: class failed {}; - parser (options const&, loc_pragmas const&, decl_pragmas const&); + parser (options const&, loc_pragmas&, ns_loc_pragmas&, decl_pragmas&); std::auto_ptr parse (tree global_scope, semantics::path const& main_file); diff --git a/odb/plugin.cxx b/odb/plugin.cxx index a93fd14..6117ba6 100644 --- a/odb/plugin.cxx +++ b/odb/plugin.cxx @@ -113,7 +113,7 @@ gate_callback (void*, void*) // Parse the GCC tree to semantic graph. // - parser p (*options_, loc_pragmas_, decl_pragmas_); + parser p (*options_, loc_pragmas_, ns_loc_pragmas_, decl_pragmas_); auto_ptr u (p.parse (global_namespace, file_)); // Validate, pass 1. diff --git a/odb/pragma.cxx b/odb/pragma.cxx index 1a992d0..cbf400c 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -43,8 +43,113 @@ accumulate (compiler::context& ctx, string const& k, any const& v, location_t) // loc_pragmas loc_pragmas_; decl_pragmas decl_pragmas_; +ns_loc_pragmas ns_loc_pragmas_; pragma_name_set simple_value_pragmas_; +// Parse a qualified string. It can be in one of the following formats: +// +// "foo.bar.baz" (can have empty leading component, e.g., ".bar.baz") +// "foo"."bar"."baz" (can have empty leading component, e.g., ""."bar"."baz") +// ."foo.bar" (used to specify unqualifed names with periods) +// +// Empty leading components means fully qualified (similar to ::foo in C++). +// +static bool +parse_qname (tree& t, + cpp_ttype& tt, + string const& p, // Pragma name for diagnostic. + qname& name, + bool* expr = 0, // If specified, detect an expression + string* expr_str = 0) // and store it here. +{ + assert (tt == CPP_STRING || tt == CPP_DOT); + + // Handle the special case of unqualified name which can contain periods. + // + if (tt == CPP_DOT) + { + tt = pragma_lex (&t); + + if (tt != CPP_STRING) + { + error () << "name expected after '.' in db pragma " << p << endl; + return false; + } + + name = TREE_STRING_POINTER (t); + tt = pragma_lex (&t); + return true; + } + + name.clear (); + string str (TREE_STRING_POINTER (t)); + + // See what comes after the string. + // + tt = pragma_lex (&t); + + if (tt == CPP_DOT) + { + name.append (str); + + for (; tt == CPP_DOT; tt = pragma_lex (&t)) + { + tt = pragma_lex (&t); + + if (tt != CPP_STRING) + { + error () << "name expected after '.' in db pragma " << p << endl; + return false; + } + + name.append (TREE_STRING_POINTER (t)); + } + + return true; + } + + if (expr != 0 && tt == CPP_PLUS) + { + *expr = true; + *expr_str = str; + return true; + } + + // Scan the string looking for '.' as well as for non-identifier + // characters if we need to detect expressions. + // + string::size_type prev (string::npos); + + for (size_t i (0); i < str.size (); ++i) + { + char c (str[i]); + + if (c == '.') + { + if (prev == string::npos) + name.append (string (str, 0, i)); + else + name.append (string (str, prev + 1, i - prev - 1)); + + prev = i; + } + else if (expr != 0 && !(isalnum (c) || c == '_')) + { + *expr = true; + *expr_str = str; + return true; + } + } + + if (prev == string::npos) + name.append (str); + else + name.append (string (str, prev + 1, string::npos)); + + return true; +} + + static bool parse_expression (tree& t, cpp_ttype& tt, @@ -245,12 +350,12 @@ check_qual_decl_type (tree d, { int tc (TREE_CODE (d)); - if (p == "member") + if (p == "namespace") { - if (tc != FIELD_DECL) + if (tc != NAMESPACE_DECL) { error (l) << "name '" << name << "' in db pragma " << p << " does " - << "not refer to a data member" << endl; + << "not refer to a namespace" << endl; return false; } } @@ -273,6 +378,15 @@ check_qual_decl_type (tree d, return false; } } + else if (p == "member") + { + if (tc != FIELD_DECL) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a data member" << endl; + return false; + } + } else { error () << "unknown db pragma " << p << endl; @@ -359,7 +473,7 @@ check_spec_decl_type (tree d, } else if (p == "table") { - // Table can be used for both members (container) and types (container + // Table can be used for both members (container) and types (container, // object, or view). // if (tc != FIELD_DECL && !TYPE_P (d)) @@ -369,6 +483,17 @@ check_spec_decl_type (tree d, return false; } } + else if (p == "schema") + { + // For now schema can be used only for namespaces and objects. + // + if (tc != NAMESPACE_DECL && !CLASS_TYPE_P (d)) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a namespace or class" << endl; + return false; + } + } else if (p == "id_type") { // Id type can only be used for types. @@ -472,7 +597,7 @@ check_spec_decl_type (tree d, } static void -add_pragma (pragma const& prag, tree decl) +add_pragma (pragma const& prag, tree decl, bool ns) { if (decl) decl_pragmas_[decl].insert (prag); @@ -480,10 +605,15 @@ add_pragma (pragma const& prag, tree decl) { tree scope (current_scope ()); - if (!CLASS_TYPE_P (scope)) - scope = global_namespace; + if (!ns) + { + if (!CLASS_TYPE_P (scope)) + scope = global_namespace; - loc_pragmas_[scope].push_back (prag); + loc_pragmas_[scope].push_back (prag); + } + else + ns_loc_pragmas_.push_back (ns_loc_pragma (scope, prag)); } } @@ -492,7 +622,8 @@ handle_pragma (cpp_reader* reader, string const& p, string const& qualifier, tree decl, - string const& decl_name) + string const& decl_name, + bool ns) // True is this is a position namespace pragma. { tree t; cpp_ttype tt; @@ -504,8 +635,10 @@ handle_pragma (cpp_reader* reader, if (p == "table") { - // table ("") - // table ("" [= ""] [: ""] (view only) + // table () + // table ( [= ""] [: ""] (view only) + // + // := "name" | "name.name" | "name"."name" // // Make sure we've got the correct declaration type. @@ -521,7 +654,7 @@ handle_pragma (cpp_reader* reader, tt = pragma_lex (&t); - if (tt != CPP_STRING) + if (tt != CPP_STRING && tt != CPP_DOT) { error () << "table name expected in db pragma " << p << endl; return; @@ -536,9 +669,9 @@ handle_pragma (cpp_reader* reader, // view_object vo; vo.kind = view_object::table; - vo.orig_name = TREE_STRING_POINTER (t); - tt = pragma_lex (&t); + if (!parse_qname (t, tt, p, vo.tbl_name)) + return; // Diagnostics has already been issued. if (tt == CPP_EQ) { @@ -582,7 +715,9 @@ handle_pragma (cpp_reader* reader, // if (vo.alias.empty () && vo.cond.empty ()) add_pragma ( - pragma (p, name, vo.orig_name, loc, &check_spec_decl_type, 0), decl); + pragma (p, name, vo.tbl_name, loc, &check_spec_decl_type, 0), + decl, + ns); vo.scope = current_scope (); vo.loc = loc; @@ -592,6 +727,45 @@ handle_pragma (cpp_reader* reader, tt = pragma_lex (&t); } + else if (p == "schema") + { + // schema () + // + // := "name" | "name.name" | "name"."name" + // + + // Make sure we've got the correct declaration type. + // + if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + return; + + if (pragma_lex (&t) != CPP_OPEN_PAREN) + { + error () << "'(' expected after db pragma " << p << endl; + return; + } + + tt = pragma_lex (&t); + + if (tt != CPP_STRING && tt != CPP_DOT) + { + error () << "table name expected in db pragma " << p << endl; + return; + } + + qname s; + if (!parse_qname (t, tt, p, s)) + return; // Diagnostics has already been issued. + + if (tt != CPP_CLOSE_PAREN) + { + error () << "')' expected at the end of db pragma " << p << endl; + return; + } + + val = s; + tt = pragma_lex (&t); + } else if (p == "pointer") { // pointer (qname) @@ -838,18 +1012,18 @@ handle_pragma (cpp_reader* reader, view_object vo; vo.kind = view_object::object; - vo.node = resolve_scoped_name (t, tt, vo.orig_name, true, p); + vo.obj_node = resolve_scoped_name (t, tt, vo.obj_name, true, p); - if (vo.node == 0) + if (vo.obj_node == 0) return; // Diagnostics has already been issued. // Get the actual type if this is a TYPE_DECL. Also get the main variant. // - if (TREE_CODE (vo.node) == TYPE_DECL) - vo.node = TREE_TYPE (vo.node); + if (TREE_CODE (vo.obj_node) == TYPE_DECL) + vo.obj_node = TREE_TYPE (vo.obj_node); - if (TYPE_P (vo.node)) // Can be a template. - vo.node = TYPE_MAIN_VARIANT (vo.node); + if (TYPE_P (vo.obj_node)) // Can be a template. + vo.obj_node = TYPE_MAIN_VARIANT (vo.obj_node); if (tt == CPP_EQ) { @@ -951,8 +1125,8 @@ handle_pragma (cpp_reader* reader, else if (p == "column") { // column ("") - // column (".") - // column (""."") + // column (".") (view only) + // column (""."") (view only) // column (fq-name) (view only) // column (expr) (view only) // @@ -970,111 +1144,49 @@ handle_pragma (cpp_reader* reader, tt = pragma_lex (&t); - bool s (false); - string str; - - // String can be just the column name, a table name followed by the - // column name, or part of an expression, depending on what comes - // after the string. - // - if (tt == CPP_STRING) + bool expr (false); + string expr_str; + if (tt == CPP_STRING || tt == CPP_DOT) { - s = true; - str = TREE_STRING_POINTER (t); - tt = pragma_lex (&t); - } + qname qn; - if (tt == CPP_CLOSE_PAREN) - { - if (s) - { - // "" or "." - // - table_column tc; - tc.expr = false; - - // Scan the string and see if we have any non-identifier - // characters. If so, assume it is an expression. While - // at it also see if there is '.'. - // - string::size_type p (string::npos); - - for (size_t i (0); i < str.size (); ++i) - { - char c (str[i]); - - if (c == '.') - { - if (p != string::npos) - { - // Second '.' -- something fishy is going on. - tc.expr = true; - break; - } - - p = i; - } - else if (!(isalnum (c) || c == '_')) - { - tc.expr = true; - break; - } - } - - if (!tc.expr && p != string::npos) - { - tc.table.assign (str, 0, p); - tc.column.assign (str, p + 1, string::npos); - } - else - tc.column = str; + if (!parse_qname (t, tt, p, qn, &expr, &expr_str)) + return; // Diagnostics has already been issued. - val = tc; - } - else - { - error () << "column name expected in db pragma " << p << endl; - return; - } - } - else if (tt == CPP_DOT) - { - if (s) + if (tt == CPP_CLOSE_PAREN) { - // ""."" - // table_column tc; - tc.expr = false; + tc.expr = expr; - if (pragma_lex (&t) != CPP_STRING) + if (expr) + tc.column = expr_str; + else { - error () << "column name expected after '.' in db pragma " << p - << endl; - return; + tc.table = qn.qualifier (); + tc.column = qn.uname (); } - tc.table = str; - tc.column = TREE_STRING_POINTER (t); val = tc; - tt = pragma_lex (&t); } - else + else if (!expr) { - error () << "column name expected in db pragma " << p << endl; + error () << "column name, expression, or data member name expected " + << "in db pragma " << p << endl; return; } } - else + + if (val.empty ()) { // We have an expression. // column_expr e; - if (s) + if (expr) { e.push_back (column_expr_part ()); e.back ().kind = column_expr_part::literal; - e.back ().value = str; + e.back ().value = expr_str; if (tt != CPP_PLUS) { @@ -1124,8 +1236,8 @@ handle_pragma (cpp_reader* reader, } else { - error () << "string literal or name expected in db pragma " << p - << endl; + error () << "column name, expression, or data member name expected " + << "in db pragma " << p << endl; return; } @@ -1145,12 +1257,6 @@ handle_pragma (cpp_reader* reader, name = "column-expr"; } - if (tt != CPP_CLOSE_PAREN) - { - error () << "')' expected at the end of db pragma " << p << endl; - return; - } - tt = pragma_lex (&t); } else if (p == "value_column" || @@ -1541,13 +1647,15 @@ handle_pragma (cpp_reader* reader, // Record this pragma. // - add_pragma (pragma (p, name, val, loc, &check_spec_decl_type, adder), decl); + add_pragma ( + pragma (p, name, val, loc, &check_spec_decl_type, adder), decl, ns); // See if there are any more pragmas. // if (tt == CPP_NAME) { - handle_pragma (reader, IDENTIFIER_POINTER (t), qualifier, decl, decl_name); + handle_pragma ( + reader, IDENTIFIER_POINTER (t), qualifier, decl, decl_name, ns); } else if (tt != CPP_EOF) error () << "unexpected text after " << p << " in db pragma" << endl; @@ -1562,12 +1670,73 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) tree decl (0), orig_decl (0); string decl_name; location_t loc (input_location); + bool ns (false); // Namespace location pragma. // Pragma qualifiers. // - if (p == "object" || - p == "view" || - p == "value") + if (p == "namespace") + { + // namespace [()] + // namespace () (refers to global namespace) + // + + tt = pragma_lex (&t); + + if (tt == CPP_OPEN_PAREN) + { + tt = pragma_lex (&t); + + if (tt == CPP_NAME || tt == CPP_SCOPE) + { + decl = resolve_scoped_name (t, tt, decl_name, false, p); + + if (decl == 0) + return; // Diagnostics has already been issued. + + // Make sure we've got the correct declaration type. + // + if (!check_qual_decl_type (decl, decl_name, p, loc)) + return; + + // Resolve namespace aliases if any. + // + decl = ORIGINAL_NAMESPACE (decl); + + if (tt != CPP_CLOSE_PAREN) + { + error () << "')' expected at the end of db pragma " << p << endl; + return; + } + + tt = pragma_lex (&t); + } + else if (tt == CPP_CLOSE_PAREN) + { + decl = global_namespace; + tt = pragma_lex (&t); + } + else + { + error () << "data member name expected in db pragma " << p << endl; + return; + } + } + else + { + // Make sure we are in a namespace scope. + // + if (TREE_CODE (current_scope ()) != NAMESPACE_DECL) + { + error() << "db pragma " << p << " is not in a namespace scope" << endl; + return; + } + + ns = true; + } + } + else if (p == "object" || + p == "view" || + p == "value") { // object [()] // view [()] @@ -1688,7 +1857,7 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) p == "transient" || p == "version") { - handle_pragma (reader, p, "member", 0, ""); + handle_pragma (reader, p, "member", 0, "", false); return; } else @@ -1712,23 +1881,34 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) { tree scope (current_scope ()); - if (!CLASS_TYPE_P (scope)) - scope = global_namespace; + if (!ns) + { + if (!CLASS_TYPE_P (scope)) + scope = global_namespace; - loc_pragmas_[scope].push_back (prag); + loc_pragmas_[scope].push_back (prag); + } + else + ns_loc_pragmas_.push_back (ns_loc_pragma (scope, prag)); } // See if there are any more pragmas. // if (tt == CPP_NAME) { - handle_pragma (reader, IDENTIFIER_POINTER (t), p, decl, decl_name); + handle_pragma (reader, IDENTIFIER_POINTER (t), p, decl, decl_name, ns); } else if (tt != CPP_EOF) error () << "unexpected text after " << p << " in db pragma" << endl; } extern "C" void +handle_pragma_db_namespace (cpp_reader* r) +{ + handle_pragma_qualifier (r, "namespace"); +} + +extern "C" void handle_pragma_db_object (cpp_reader* r) { handle_pragma_qualifier (r, "object"); @@ -1980,6 +2160,7 @@ register_odb_pragmas (void*, void*) c_register_pragma_with_expansion (0, "db", handle_pragma_db); /* + c_register_pragma_with_expansion ("db", "namespace", handle_pragma_db_namespace); c_register_pragma_with_expansion ("db", "object", handle_pragma_db_object); c_register_pragma_with_expansion ("db", "view", handle_pragma_db_view); c_register_pragma_with_expansion ("db", "value", handle_pragma_db_value); diff --git a/odb/pragma.hxx b/odb/pragma.hxx index 57531ba..78cfd55 100644 --- a/odb/pragma.hxx +++ b/odb/pragma.hxx @@ -103,6 +103,23 @@ struct pragma_set: std::set typedef std::map loc_pragmas; extern loc_pragmas loc_pragmas_; +// Position pragmas for namespaces. Because re-opened namespaces do +// not have any representation in the GCC tree, these are handled in +// a special way. They are stored as a list of pragmas and their outer +// namespaces. +// +struct ns_loc_pragma +{ + typedef ::pragma pragma_type; + ns_loc_pragma (tree n, pragma_type const& p): ns (n), pragma (p) {} + + tree ns; + pragma_type pragma; +}; + +typedef std::vector ns_loc_pragmas; +extern ns_loc_pragmas ns_loc_pragmas_; + // Pragmas associated with this declaration. // typedef std::map decl_pragmas; diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx index 1ee8449..0c1ecc8 100644 --- a/odb/relational/common.cxx +++ b/odb/relational/common.cxx @@ -112,11 +112,11 @@ namespace relational } else { - // For now use column name as table alias. This will become problematic - // when we add support for composite ids. + // For now use column name as table alias. + // @@ This will become problematic when we add support for composite ids. // os << "const char " << scope_ << "::" << name << "_alias_[] = " << - strlit (column) << ";" + strlit (quote_id (column)) << ";" << endl; if (inv) @@ -299,7 +299,8 @@ namespace relational { os << "template " << endl << "const typename " << scope_ << "::" << name << "_type_" << endl - << scope_ << "::" << name << " (" << "table, " << strlit (column); + << scope_ << "::" << name << " (" << "table, " << + strlit (quote_id (column)); column_ctor_extra (m); diff --git a/odb/relational/context.cxx b/odb/relational/context.cxx index 0ebfbf4..083bfe5 100644 --- a/odb/relational/context.cxx +++ b/odb/relational/context.cxx @@ -83,13 +83,26 @@ namespace relational } string context:: - quote_id_impl (string const& id) const + quote_id_impl (qname const& id) const { string r; - r.reserve (id.size () + 2); - r += '"'; - r += id; - r += '"'; + + bool f (true); + for (qname::iterator i (id.begin ()); i < id.end (); ++i) + { + if (i->empty ()) + continue; + + if (f) + f = false; + else + r += '.'; + + r += '"'; + r += *i; + r += '"'; + } + return r; } } diff --git a/odb/relational/context.hxx b/odb/relational/context.hxx index 095f579..6970726 100644 --- a/odb/relational/context.hxx +++ b/odb/relational/context.hxx @@ -52,6 +52,9 @@ namespace relational string quote_id (string const&) const; + string + quote_id (qname const&) const; + // Quoted column and table names. // string @@ -118,7 +121,7 @@ namespace relational // The default implementation uses the ISO quoting (""). // virtual string - quote_id_impl (string const&) const; + quote_id_impl (qname const&) const; public: virtual diff --git a/odb/relational/context.ixx b/odb/relational/context.ixx index 8bc10fa..0e1268b 100644 --- a/odb/relational/context.ixx +++ b/odb/relational/context.ixx @@ -32,6 +32,12 @@ namespace relational inline context::string context:: quote_id (string const& id) const { + return current ().quote_id_impl (qname (id)); + } + + inline context::string context:: + quote_id (qname const& id) const + { return current ().quote_id_impl (id); } } diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 427b008..b358810 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -1407,11 +1407,12 @@ namespace relational semantics::class_& o (*i->obj); string const& name (alias ? i->alias : class_name (o)); string const& type (class_fq_name (o)); + qname const& table (table_name (o)); os << "// " << name << endl << "//" << endl; - if (alias && i->alias != table_name (o)) + if (alias && (table.qualified () || i->alias != table.uname ())) os << "static const char " << name << "_alias_[];" << endl << "typedef" << endl @@ -1450,8 +1451,9 @@ namespace relational bool alias (!vo->alias.empty ()); semantics::class_& o (*vo->obj); string const& type (class_fq_name (o)); + qname const& table (table_name (o)); - if (alias && vo->alias != table_name (o)) + if (alias && (table.qualified () || vo->alias != table.uname ())) os << "static const char query_alias[];" << endl << "struct query_type:" << endl diff --git a/odb/relational/model.cxx b/odb/relational/model.cxx index 9bb6070..7c66387 100644 --- a/odb/relational/model.cxx +++ b/odb/relational/model.cxx @@ -144,17 +144,17 @@ namespace relational } catch (sema_rel::duplicate_name const& e) { - semantics::node& n (*e.nameable.get ("cxx-node")); - semantics::node& d (*e.duplicate.get ("cxx-node")); + semantics::node& o (*e.orig.get ("cxx-node")); + semantics::node& d (*e.dup.get ("cxx-node")); cerr << d.file () << ":" << d.line () << ":" << d.column () - << ": error: " << e.duplicate.kind () << " name '" - << e.nameable.name () << "' conflicts with an already defined " - << e.nameable.kind () << " name" + << ": error: " << e.dup.kind () << " name '" << e.orig_name + << "' conflicts with an already defined " << e.orig.kind () + << " name" << endl; - cerr << n.file () << ":" << n.line () << ":" << n.column () - << ": info: conflicting " << e.nameable.kind () << " is " + cerr << o.file () << ":" << o.line () << ":" << o.column () + << ": info: conflicting " << e.orig.kind () << " is " << "defined here" << endl; diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx index 6fe5b0d..51e9b7c 100644 --- a/odb/relational/model.hxx +++ b/odb/relational/model.hxx @@ -21,7 +21,7 @@ namespace relational { namespace model { - typedef std::set tables; + typedef std::set tables; struct object_columns: object_columns_base, virtual context { @@ -111,7 +111,7 @@ namespace relational id, column_type (m, prefix_), context::null (m, prefix_))); c.set ("cxx-node", static_cast (&m)); - model_.new_edge (table_, c, name); + model_.new_edge (table_, c, name); // An id member cannot have a default value. // @@ -205,7 +205,7 @@ namespace relational // primary key manipulation, then the database-specific code will // have to come up with a suitable name. // - model_.new_edge (table_, pk, ""); + model_.new_edge (table_, pk, ""); } virtual void @@ -240,7 +240,7 @@ namespace relational // up-to-and-including composite member prefix? Though it can be // empty. // - model_.new_edge (table_, fk, name + "_fk"); + model_.new_edge (table_, fk, name + "_fk"); } protected: @@ -319,7 +319,7 @@ namespace relational container_kind_type ck (container_kind (ct)); type& vt (container_vt (ct)); - string const& name (table_name (m, table_prefix_)); + qname const& name (table_name (m, table_prefix_)); // Add the [] decorator to distinguish this id from non-container // ids (we don't want to ever end up comparing, for example, an @@ -331,7 +331,7 @@ namespace relational model_.new_node (id)); t.set ("cxx-node", static_cast (&m)); - model_.new_edge (model_, t, name); + model_.new_edge (model_, t, name); // object_id (simple value, for now) // @@ -369,7 +369,7 @@ namespace relational // Derive the constraint name. See the comment for the other // foreign key code above. // - model_.new_edge (t, fk, id_name + "_fk"); + model_.new_edge (t, fk, id_name + "_fk"); } // index (simple value) @@ -433,8 +433,8 @@ namespace relational //@@ Once id can be composite, we need to revise this (see // a comment for the foreign key generation above). // - model_.new_edge ( - model_, i, name + '_' + id_name + "_i"); + model_.new_edge ( + model_, i, name + "_" + id_name + "_i"); } if (ordered) @@ -447,8 +447,8 @@ namespace relational // This is always a single column (simple value). // - model_.new_edge ( - model_, i, name + '_' + index_name + "_i"); + model_.new_edge ( + model_, i, name + "_" + index_name + "_i"); } } @@ -475,7 +475,7 @@ namespace relational if (!object (c) || abstract (c)) return; - string const& name (table_name (c)); + qname const& name (table_name (c)); // If the table with this name was already created, assume the // user knows what they are doing and skip it. @@ -494,7 +494,7 @@ namespace relational t.set ("cxx-node", static_cast (&c)); - model_.new_edge (model_, t, name); + model_.new_edge (model_, t, name); sema_rel::model::names_iterator begin (--model_.names_end ()); diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx index 7832c24..c426d2e 100644 --- a/odb/relational/mssql/context.cxx +++ b/odb/relational/mssql/context.cxx @@ -108,13 +108,26 @@ namespace relational } string context:: - quote_id_impl (string const& id) const + quote_id_impl (qname const& id) const { string r; - r.reserve (130); // Max MSSQL identifier length is 128. - r += '['; - r.append (id, 0, 128); - r += ']'; + + bool f (true); + for (qname::iterator i (id.begin ()); i < id.end (); ++i) + { + if (i->empty ()) + continue; + + if (f) + f = false; + else + r += '.'; + + r += '['; + r.append (*i, 0, 128); // Max identifier length is 128. + r += ']'; + } + return r; } diff --git a/odb/relational/mssql/context.hxx b/odb/relational/mssql/context.hxx index 8f250ea..2074cc3 100644 --- a/odb/relational/mssql/context.hxx +++ b/odb/relational/mssql/context.hxx @@ -104,7 +104,7 @@ namespace relational protected: virtual string - quote_id_impl (string const&) const; + quote_id_impl (qname const&) const; protected: virtual string diff --git a/odb/relational/mssql/schema.cxx b/odb/relational/mssql/schema.cxx index 2cbeb5f..66a2278 100644 --- a/odb/relational/mssql/schema.cxx +++ b/odb/relational/mssql/schema.cxx @@ -46,15 +46,13 @@ namespace relational drop_table (base const& x): base (x) {} virtual void - drop (string const& table) + drop (sema_rel::qname const& table) { // SQL Server has no IF EXISTS conditional for dropping table. // The following approach appears to be the recommended way to // drop a table if it exists. // - string const& qt (); - - os << "IF OBJECT_ID(" << quote_string (table) << + os << "IF OBJECT_ID(" << quote_string (table.string ()) << ", " << quote_string ("U") << ") IS NOT NULL" << endl << " DROP TABLE " << quote_id (table) << endl; } @@ -88,7 +86,7 @@ namespace relational private: friend class create_foreign_key; - set tables_; // Set of tables we have already defined. + set tables_; // Set of tables we have already defined. }; entry create_table_; @@ -145,10 +143,12 @@ namespace relational name (sema_rel::foreign_key& fk) { // In SQL Server, foreign key names are schema-global. Make them - // unique by prefixing the key name with table name. + // unique by prefixing the key name with table name. Note, however, + // that they cannot have a schema. // - return static_cast (fk.scope ()).name () + - '_' + fk.name (); + return quote_id ( + static_cast (fk.scope ()).name ().uname () + + "_" + fk.name ()); } virtual void @@ -216,9 +216,23 @@ namespace relational // Add foreign keys. // instance fk (format_, *this); - trav_rel::names n (*fk); + trav_rel::unames n (*fk); names (t, n); } + + struct create_index: relational::create_index, context + { + create_index (base const& x): base (x) {} + + virtual string + name (sema_rel::index& in) + { + // In SQL Server indexes cannot have a schema. + // + return quote_id (in.name ().uname ()); + } + }; + entry create_index_; } } } diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx index e7fd790..9ee0843 100644 --- a/odb/relational/mysql/context.cxx +++ b/odb/relational/mysql/context.cxx @@ -105,13 +105,26 @@ namespace relational } string context:: - quote_id_impl (string const& id) const + quote_id_impl (qname const& id) const { string r; - r.reserve (id.size () + 2); - r += '`'; - r += id; - r += '`'; + + bool f (true); + for (qname::iterator i (id.begin ()); i < id.end (); ++i) + { + if (i->empty ()) + continue; + + if (f) + f = false; + else + r += '.'; + + r += '`'; + r += *i; + r += '`'; + } + return r; } diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx index 2615397..c88a525 100644 --- a/odb/relational/mysql/context.hxx +++ b/odb/relational/mysql/context.hxx @@ -111,7 +111,7 @@ namespace relational protected: virtual string - quote_id_impl (string const&) const; + quote_id_impl (qname const&) const; protected: virtual string diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx index 428db1c..1bdb6dd 100644 --- a/odb/relational/mysql/schema.cxx +++ b/odb/relational/mysql/schema.cxx @@ -91,10 +91,12 @@ namespace relational name (sema_rel::foreign_key& fk) { // In MySQL, foreign key names are database-global. Make them - // unique by prefixing the key name with table name. + // unique by prefixing the key name with table name. Note, + // however, that they cannot be prefixed with the database name. // - return static_cast (fk.scope ()).name () + - '_' + fk.name (); + return quote_id ( + static_cast (fk.scope ()).name ().uname () + + "_" + fk.name ()); } virtual void @@ -124,6 +126,20 @@ namespace relational } }; entry create_table_; + + struct create_index: relational::create_index, context + { + create_index (base const& x): base (x) {} + + virtual string + name (sema_rel::index& in) + { + // In MySQL an index cannot be qualified with the database name. + // + return quote_id (in.name ().uname ()); + } + }; + entry create_index_; } } } diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx index d477a19..bb76ee7 100644 --- a/odb/relational/oracle/context.cxx +++ b/odb/relational/oracle/context.cxx @@ -103,13 +103,26 @@ namespace relational } string context:: - quote_id_impl (string const& id) const + quote_id_impl (qname const& id) const { string r; - r.reserve (32); - r += '"'; - r.append (id, 0, 30); - r += '"'; + + bool f (true); + for (qname::iterator i (id.begin ()); i < id.end (); ++i) + { + if (i->empty ()) + continue; + + if (f) + f = false; + else + r += '.'; + + r += '"'; + r.append (*i, 0, 30); // Max identifier length is 30. + r += '"'; + } + return r; } diff --git a/odb/relational/oracle/context.hxx b/odb/relational/oracle/context.hxx index ea81136..e19264a 100644 --- a/odb/relational/oracle/context.hxx +++ b/odb/relational/oracle/context.hxx @@ -98,7 +98,7 @@ namespace relational protected: virtual string - quote_id_impl (string const&) const; + quote_id_impl (qname const&) const; protected: virtual string diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx index a371235..b98facc 100644 --- a/odb/relational/oracle/schema.cxx +++ b/odb/relational/oracle/schema.cxx @@ -94,7 +94,7 @@ namespace relational drop_table (base const& x): base (x) {} virtual void - drop (string const& table) + drop (sema_rel::qname const& table) { // Oracle has no IF EXISTS conditional for dropping objects. The // PL/SQL approach below seems to be the least error-prone and the @@ -142,7 +142,7 @@ namespace relational private: friend class create_foreign_key; - set tables_; // Set of tables we have already defined. + set tables_; // Set of tables we have already defined. }; entry create_table_; @@ -203,10 +203,12 @@ namespace relational name (sema_rel::foreign_key& fk) { // In Oracle, foreign key names are schema-global. Make them - // unique by prefixing the key name with table name. + // unique by prefixing the key name with table name. Note, + // however, that they cannot have a schema. // - return static_cast (fk.scope ()).name () + - '_' + fk.name (); + return quote_id ( + static_cast (fk.scope ()).name ().uname () + + "_" + fk.name ()); } }; entry create_foreign_key_; @@ -256,11 +258,11 @@ namespace relational if (pk != 0 && pk->auto_ ()) { - string const& tname (t.name ()); + qname const& tname (t.name ()); string const& cname (pk->contains_begin ()->column ().name ()); - string seq_name (tname + "_seq"); - string trg_name (tname + "_trg"); + qname seq_name (tname + "_seq"); + qname trg_name (tname + "_trg"); // Sequence. // @@ -292,7 +294,7 @@ namespace relational // Add foreign keys. // instance fk (format_, *this); - trav_rel::names n (*fk); + trav_rel::unames n (*fk); names (t, n); } } diff --git a/odb/relational/pgsql/schema.cxx b/odb/relational/pgsql/schema.cxx index c723818..fc79c00 100644 --- a/odb/relational/pgsql/schema.cxx +++ b/odb/relational/pgsql/schema.cxx @@ -29,7 +29,7 @@ namespace relational drop_table (base const& x): base (x) {} virtual void - drop (string const& table) + drop (sema_rel::qname const& table) { os << "DROP TABLE IF EXISTS " << quote_id (table) << " CASCADE" << endl; @@ -52,7 +52,7 @@ namespace relational private: friend class create_foreign_key; - set tables_; // Set of tables we have already defined. + set tables_; // Set of tables we have already defined. }; entry create_table_; @@ -163,9 +163,23 @@ namespace relational // Add foreign keys. // instance fk (format_, *this); - trav_rel::names n (*fk); + trav_rel::unames n (*fk); names (t, n); } + + struct create_index: relational::create_index, context + { + create_index (base const& x): base (x) {} + + virtual string + name (sema_rel::index& in) + { + // In PostgreSQL indexes cannot have a schema. + // + return quote_id (in.name ().uname ()); + } + }; + entry create_index_; } } } diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index 8d80df0..da817b2 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -1431,7 +1431,7 @@ namespace relational ep.kind = column_expr_part::reference; ep.table = am.vo->alias.empty () ? table_name (*am.vo->obj) - : am.vo->alias; + : qname (am.vo->alias); ep.member_path.push_back (am.m); src_m = am.m; @@ -1745,12 +1745,12 @@ namespace relational else obj_count++; - tree n (TYPE_MAIN_VARIANT (i->node)); + tree n (TYPE_MAIN_VARIANT (i->obj_node)); if (TREE_CODE (n) != RECORD_TYPE) { error (i->loc) - << "name '" << i->orig_name << "' in db pragma object does " + << "name '" << i->obj_name << "' in db pragma object does " << "not name a class" << endl; throw operation_failed (); @@ -1761,11 +1761,11 @@ namespace relational if (!object (o)) { error (i->loc) - << "name '" << i->orig_name << "' in db pragma object does " + << "name '" << i->obj_name << "' in db pragma object does " << "not name a persistent class" << endl; info (o.file (), o.line (), o.column ()) - << "class '" << i->orig_name << "' is defined here" << endl; + << "class '" << i->obj_name << "' is defined here" << endl; throw operation_failed (); } @@ -1777,7 +1777,7 @@ namespace relational if (!omap.insert (view_object_map::value_type (n, &*i)).second) { error (i->loc) - << "persistent class '" << i->orig_name << "' is used in " + << "persistent class '" << i->obj_name << "' is used in " << "the view more than once" << endl; info (i->loc) diff --git a/odb/relational/schema.cxx b/odb/relational/schema.cxx index 8a06427..a8dc70c 100644 --- a/odb/relational/schema.cxx +++ b/odb/relational/schema.cxx @@ -44,7 +44,7 @@ namespace relational { instance model (*em, emos, f); - trav_rel::names names; + trav_rel::qnames names; instance table (*em, emos, f); instance index (*em, emos, f); @@ -70,7 +70,7 @@ namespace relational // { instance model (*em, emos, f); - trav_rel::names names; + trav_rel::qnames names; instance table (*em, emos, f); instance index (*em, emos, f); diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx index 81e1453..67d9a8c 100644 --- a/odb/relational/schema.hxx +++ b/odb/relational/schema.hxx @@ -121,7 +121,7 @@ namespace relational } virtual void - drop (string const& table) + drop (sema_rel::qname const& table) { os << "DROP TABLE IF EXISTS " << quote_id (table) << endl; } @@ -161,7 +161,7 @@ namespace relational } virtual void - drop (string const& /*index*/) + drop (sema_rel::qname const& /*index*/) { // Most database systems drop indexes together with the table. // @@ -418,7 +418,7 @@ namespace relational { using sema_rel::foreign_key; - os << " CONSTRAINT " << quote_id (name (fk)) << endl + os << " CONSTRAINT " << name (fk) << endl << " FOREIGN KEY ("; for (foreign_key::contains_iterator i (fk.contains_begin ()); @@ -438,7 +438,7 @@ namespace relational } os << ")" << endl - << " REFERENCES " << quote_id (fk.referenced_table ()) << " ("; + << " REFERENCES " << table_name (fk) << " ("; foreign_key::columns const& refs (fk.referenced_columns ()); @@ -470,7 +470,13 @@ namespace relational virtual string name (sema_rel::foreign_key& fk) { - return fk.name (); + return quote_id (fk.name ()); + } + + virtual string + table_name (sema_rel::foreign_key& fk) + { + return quote_id (fk.referenced_table ()); } virtual void @@ -513,7 +519,7 @@ namespace relational } virtual void - create_pre (string const& table) + create_pre (sema_rel::qname const& table) { os << "CREATE TABLE " << quote_id (table) << " (" << endl; } @@ -539,7 +545,7 @@ namespace relational instance c (format_, *this); instance pk (format_, *this); instance fk (format_, *this); - trav_rel::names n; + trav_rel::unames n; n >> c; n >> pk; @@ -585,13 +591,25 @@ namespace relational post_statement (); } + virtual string + name (sema_rel::index& in) + { + return quote_id (in.name ()); + } + + virtual string + table_name (sema_rel::index& in) + { + return quote_id (in.table ().name ()); + } + virtual void create (sema_rel::index& in) { using sema_rel::index; - os << "CREATE INDEX " << quote_id (in.name ()) << endl - << " ON " << quote_id (in.table ().name ()) << " ("; + os << "CREATE INDEX " << name (in) << endl + << " ON " << table_name (in) << " ("; for (index::contains_iterator i (in.contains_begin ()); i != in.contains_end (); diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index d909f7b..ff62257 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -350,7 +350,7 @@ namespace relational protected: statement_columns& sc_; bool in_composite_; - string table_prefix_; // Table corresponding to column_prefix_; + qname table_prefix_; // Table corresponding to column_prefix_; }; struct object_joins: object_columns_base, virtual context @@ -411,7 +411,7 @@ namespace relational // This container is a direct member of the class so the table // prefix is just the class table name. // - string const& ct (table_name (*c)); + qname const& ct (table_name (*c)); table_prefix tp (ct + "_", 1); t = table_qname (*im, tp); string const& val (column_qname (*im, "value", "value")); @@ -2818,7 +2818,7 @@ namespace relational // table_name // os << "const char " << traits << "::table_name[] =" << endl - << strlit (table_name (c)) << ";" // Use unquoted name. + << strlit (table_qname (c)) << ";" // Use quoted name. << endl; } @@ -3682,9 +3682,13 @@ namespace relational if (i->kind != view_object::object) continue; // Skip tables. - if (!i->alias.empty () && i->alias != table_name (*i->obj)) + qname const& t (table_name (*i->obj)); + + if (!i->alias.empty () && + (t.qualified () || i->alias != t.uname ())) os << "const char " << traits << "::query_columns::" << endl - << i->alias << "_alias_[] = " << strlit (i->alias) << ";" + << i->alias << "_alias_[] = " << + strlit (quote_id (i->alias)) << ";" << endl; } } @@ -3702,9 +3706,12 @@ namespace relational vo = &*i; } - if (!vo->alias.empty () && vo->alias != table_name (*vo->obj)) + qname const& t (table_name (*vo->obj)); + + if (!vo->alias.empty () && + (t.qualified () || vo->alias != t.uname ())) os << "const char " << traits << "::" << endl - << "query_alias[] = " << strlit (vo->alias) << ";" + << "query_alias[] = " << strlit (quote_id (vo->alias)) << ";" << endl; } } @@ -3863,7 +3870,7 @@ namespace relational if (first) { l = "FROM "; - l += quote_id (i->orig_name); + l += quote_id (i->tbl_name); if (!i->alias.empty ()) l += (need_alias_as ? " AS " : " ") + quote_id (i->alias); @@ -3875,7 +3882,7 @@ namespace relational } l = "LEFT JOIN "; - l += quote_id (i->orig_name); + l += quote_id (i->tbl_name); if (!i->alias.empty ()) l += (need_alias_as ? " AS " : " ") + quote_id (i->alias); @@ -4045,13 +4052,13 @@ namespace relational // Left and right-hand side table names. // - string lt (e.vo->alias.empty () - ? table_name (*e.vo->obj) - : e.vo->alias); + qname lt (e.vo->alias.empty () + ? table_name (*e.vo->obj) + : qname (e.vo->alias)); - string rt (vo->alias.empty () - ? table_name (*vo->obj) - : vo->alias); + qname rt (vo->alias.empty () + ? table_name (*vo->obj) + : qname (vo->alias)); // First join the container table if necessary. // @@ -4532,12 +4539,12 @@ namespace relational schema_emitter emitter_; emitter_ostream stream_; - trav_rel::names drop_names_; + trav_rel::qnames drop_names_; instance drop_model_; instance drop_table_; instance drop_index_; - trav_rel::names create_names_; + trav_rel::qnames create_names_; instance create_model_; instance create_table_; instance create_index_; diff --git a/odb/relational/sqlite/schema.cxx b/odb/relational/sqlite/schema.cxx index 6562905..15d37dc 100644 --- a/odb/relational/sqlite/schema.cxx +++ b/odb/relational/sqlite/schema.cxx @@ -34,6 +34,36 @@ namespace relational } }; entry create_column_; + + struct create_foreign_key: relational::create_foreign_key, context + { + create_foreign_key (base const& x): base (x) {} + + virtual string + table_name (sema_rel::foreign_key& fk) + { + // In SQLite, the referenced table cannot be qualified with the + // database name (it has to be in the same database anyway). + // + return quote_id (fk.referenced_table ().uname ()); + } + }; + entry create_foreign_key_; + + struct create_index: relational::create_index, context + { + create_index (base const& x): base (x) {} + + virtual string + table_name (sema_rel::index& in) + { + // In SQLite, the index table cannot be qualified with the + // database name (it has to be in the same database anyway). + // + return quote_id (in.table ().name ().uname ()); + } + }; + entry create_index_; } } } diff --git a/odb/semantics/namespace.cxx b/odb/semantics/namespace.cxx index 25c1de0..ffba0e8 100644 --- a/odb/semantics/namespace.cxx +++ b/odb/semantics/namespace.cxx @@ -10,12 +10,13 @@ namespace semantics { namespace_:: namespace_ (path const& file, size_t line, size_t column, tree tn) - : node (file, line, column, tn) + : node (file, line, column, tn), original_ (0) { } namespace_:: namespace_ () + : original_ (0) { } diff --git a/odb/semantics/namespace.hxx b/odb/semantics/namespace.hxx index 7a886c5..96db4a7 100644 --- a/odb/semantics/namespace.hxx +++ b/odb/semantics/namespace.hxx @@ -13,6 +13,25 @@ namespace semantics class namespace_: public scope { public: + bool + extension () const + { + return original_ != 0; + } + + namespace_& + original () + { + return *original_; + } + + void + original (namespace_& ns) + { + original_ = &ns; + } + + public: namespace_ (path const&, size_t line, size_t column, tree); // Resolve conflict between scope::scope and nameable::scope. @@ -21,6 +40,9 @@ namespace semantics protected: namespace_ (); + + private: + namespace_* original_; }; } diff --git a/odb/semantics/relational/column.cxx b/odb/semantics/relational/column.cxx index 99df5d9..c3182eb 100644 --- a/odb/semantics/relational/column.cxx +++ b/odb/semantics/relational/column.cxx @@ -25,7 +25,7 @@ namespace semantics // { type_info ti (typeid (column)); - ti.add_base (typeid (nameable)); + ti.add_base (typeid (unameable)); insert (ti); } } diff --git a/odb/semantics/relational/column.hxx b/odb/semantics/relational/column.hxx index a1024cf..56487c6 100644 --- a/odb/semantics/relational/column.hxx +++ b/odb/semantics/relational/column.hxx @@ -15,13 +15,13 @@ namespace semantics { class contains; - class column: public nameable + class column: public unameable { typedef std::vector contained_list; public: column (string const& id, string const& type, bool null) - : nameable (id), type_ (type), null_ (null) + : unameable (id), type_ (type), null_ (null) { } @@ -96,7 +96,7 @@ namespace semantics contained_.push_back (&e); } - using nameable::add_edge_right; + using unameable::add_edge_right; virtual string kind () const diff --git a/odb/semantics/relational/elements.cxx b/odb/semantics/relational/elements.cxx index 6ab977a..42755c8 100644 --- a/odb/semantics/relational/elements.cxx +++ b/odb/semantics/relational/elements.cxx @@ -6,87 +6,27 @@ #include #include -#include -#include namespace semantics { namespace relational { - // scope + // duplicate_name // - - scope::names_iterator scope:: - find (string const& name) - { - names_map::iterator i (names_map_.find (name)); - - if (i == names_map_.end ()) - return names_.end (); - else - return i->second; - } - - scope::names_const_iterator scope:: - find (string const& name) const + template <> + duplicate_name:: + duplicate_name (uscope& s, unameable& o, unameable& d) + : scope (s), orig (o), dup (d), + orig_name (o.name ()), dup_name (d.name ()) { - names_map::const_iterator i (names_map_.find (name)); - - if (i == names_map_.end ()) - return names_.end (); - else - return names_const_iterator (i->second); } - scope::names_iterator scope:: - find (names const& e) + template <> + duplicate_name:: + duplicate_name (qscope& s, qnameable& o, qnameable& d) + : scope (s), orig (o), dup (d), + orig_name (o.name ().string ()), dup_name (d.name ().string ()) { - names_iterator_map::iterator i (iterator_map_.find (&e)); - return i != iterator_map_.end () ? i->second : names_.end (); - } - - scope::names_const_iterator scope:: - find (names const& e) const - { - names_iterator_map::const_iterator i (iterator_map_.find (&e)); - return i != iterator_map_.end () ? i->second : names_.end (); - } - - void scope:: - add_edge_left (names& e) - { - nameable& n (e.nameable ()); - string const& name (e.name ()); - - names_map::iterator i (names_map_.find (name)); - - if (i == names_map_.end ()) - { - names_list::iterator i; - - // We want the order to be columns first, then the primary key, - // and then the foreign keys. - // - if (n.is_a ()) - i = names_.insert (first_key_, &e); - else - { - if (n.is_a ()) - first_key_ = i = names_.insert (first_key_, &e); - else - { - i = names_.insert (names_.end (), &e); - - if (first_key_ == names_.end ()) - first_key_ = i; - } - } - - names_map_[name] = i; - iterator_map_[&e] = i; - } - else - throw duplicate_name (*this, (*i->second)->nameable (), n); } // type info @@ -110,7 +50,13 @@ namespace semantics // names // { - type_info ti (typeid (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); } @@ -118,7 +64,13 @@ namespace semantics // nameable // { - type_info ti (typeid (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); } @@ -126,7 +78,13 @@ namespace semantics // scope // { - type_info ti (typeid (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); } diff --git a/odb/semantics/relational/elements.hxx b/odb/semantics/relational/elements.hxx index d07902d..d8711b3 100644 --- a/odb/semantics/relational/elements.hxx +++ b/odb/semantics/relational/elements.hxx @@ -16,6 +16,8 @@ #include #include +#include + namespace semantics { namespace relational @@ -84,18 +86,23 @@ namespace semantics // // + template class scope; + + template class nameable; // // + template class names: public edge { public: - typedef relational::scope scope_type; - typedef relational::nameable nameable_type; + typedef N name_type; + typedef relational::scope scope_type; + typedef relational::nameable nameable_type; - string const& + name_type const& name () const { return name_; @@ -114,7 +121,7 @@ namespace semantics } public: - names (string const& name): name_ (name) {} + names (name_type const& name): name_ (name) {} void set_left_node (scope_type& n) @@ -129,19 +136,25 @@ namespace semantics } protected: - string name_; + name_type name_; scope_type* scope_; nameable_type* nameable_; }; + typedef names unames; + typedef names qnames; + // // + template class nameable: public virtual node { public: - typedef relational::scope scope_type; + typedef N name_type; + typedef relational::names names_type; + typedef relational::scope scope_type; - string const& + name_type const& name () const { return named_->name (); @@ -153,7 +166,7 @@ namespace semantics return named ().scope (); } - names& + names_type& named () const { return *named_; @@ -170,7 +183,7 @@ namespace semantics nameable (string const& id): id_ (id), named_ (0) {} void - add_edge_right (names& e) + add_edge_right (names_type& e) { assert (named_ == 0); named_ = &e; @@ -180,38 +193,48 @@ namespace semantics private: string id_; - names* named_; + names_type* named_; }; + typedef nameable unameable; + typedef nameable qnameable; + // // struct duplicate_name { - typedef relational::scope scope_type; - typedef relational::nameable nameable_type; + template + duplicate_name (relational::scope&, + relational::nameable& orig, + relational::nameable& dup); - duplicate_name (scope_type& s, nameable_type& n, nameable_type& d) - : scope (s), nameable (n), duplicate (d) - { - } + node& scope; + node& orig; + node& dup; - scope_type& scope; - nameable_type& nameable; - nameable_type& duplicate; + string orig_name; + string dup_name; }; + template class scope: public virtual node { protected: - typedef std::list names_list; - typedef std::map names_map; - typedef std::map names_iterator_map; + typedef N name_type; + typedef relational::names names_type; + typedef relational::nameable nameable_type; + + typedef std::list names_list; + typedef std::map names_map; + typedef + std::map + names_iterator_map; public: - typedef pointer_iterator names_iterator; + typedef pointer_iterator names_iterator; typedef - pointer_iterator + pointer_iterator names_const_iterator; public: @@ -244,16 +267,16 @@ namespace semantics // Find. // names_iterator - find (string const& name); + find (name_type const&); names_const_iterator - find (string const& name) const; + find (name_type const&) const; names_iterator - find (names const&); + find (names_type const&); names_const_iterator - find (names const&) const; + find (names_type const&) const; public: scope () @@ -262,16 +285,21 @@ namespace semantics } void - add_edge_left (names&); + add_edge_left (names_type&); private: names_list names_; names_map names_map_; names_iterator_map iterator_map_; - names_list::iterator first_key_; + typename names_list::iterator first_key_; }; + + typedef scope uscope; + typedef scope qscope; } } +#include + #endif // ODB_SEMANTICS_RELATIONAL_ELEMENTS_HXX diff --git a/odb/semantics/relational/elements.txx b/odb/semantics/relational/elements.txx new file mode 100644 index 0000000..f3d15c2 --- /dev/null +++ b/odb/semantics/relational/elements.txx @@ -0,0 +1,94 @@ +// file : odb/semantics/relational/elements.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +namespace semantics +{ + namespace relational + { + // scope + // + + template + typename scope::names_iterator scope:: + 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 scope::names_const_iterator scope:: + 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 scope::names_iterator scope:: + 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 scope::names_const_iterator scope:: + 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 (); + } + + class column; + class primary_key; + + template + void scope:: + 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 columns first, then the primary key, + // and then the foreign keys. + // + if (n.is_a ()) + i = names_.insert (first_key_, &e); + else + { + if (n.is_a ()) + first_key_ = i = names_.insert (first_key_, &e); + else + { + i = names_.insert (names_.end (), &e); + + if (first_key_ == names_.end ()) + first_key_ = i; + } + } + + names_map_[name] = i; + iterator_map_[&e] = i; + } + else + throw duplicate_name (*this, (*i->second)->nameable (), n); + } + } +} diff --git a/odb/semantics/relational/foreign-key.cxx b/odb/semantics/relational/foreign-key.cxx index eae9c5f..610466a 100644 --- a/odb/semantics/relational/foreign-key.cxx +++ b/odb/semantics/relational/foreign-key.cxx @@ -25,6 +25,7 @@ namespace semantics // { type_info ti (typeid (foreign_key)); + ti.add_base (typeid (unameable)); ti.add_base (typeid (key)); insert (ti); } diff --git a/odb/semantics/relational/foreign-key.hxx b/odb/semantics/relational/foreign-key.hxx index 4a0b543..c47c90a 100644 --- a/odb/semantics/relational/foreign-key.hxx +++ b/odb/semantics/relational/foreign-key.hxx @@ -13,7 +13,7 @@ namespace semantics { namespace relational { - class foreign_key: public key + class foreign_key: public unameable, public key { public: enum action @@ -23,10 +23,10 @@ namespace semantics }; foreign_key (string const& id, - string const& referenced_table, + qname const& referenced_table, bool deferred, action on_delete = no_action) - : key (id), + : unameable (id), referenced_table_ (referenced_table), deferred_ (deferred), on_delete_ (on_delete) @@ -34,7 +34,7 @@ namespace semantics } public: - string + qname const& referenced_table () const { return referenced_table_; @@ -76,7 +76,7 @@ namespace semantics } private: - string referenced_table_; + qname referenced_table_; columns referenced_columns_; bool deferred_; action on_delete_; diff --git a/odb/semantics/relational/index.cxx b/odb/semantics/relational/index.cxx index 376a312..407dbf8 100644 --- a/odb/semantics/relational/index.cxx +++ b/odb/semantics/relational/index.cxx @@ -25,6 +25,7 @@ namespace semantics // { type_info ti (typeid (index)); + ti.add_base (typeid (qnameable)); ti.add_base (typeid (key)); insert (ti); } diff --git a/odb/semantics/relational/index.hxx b/odb/semantics/relational/index.hxx index ee6b202..bb34742 100644 --- a/odb/semantics/relational/index.hxx +++ b/odb/semantics/relational/index.hxx @@ -7,6 +7,7 @@ #define ODB_SEMANTICS_RELATIONAL_INDEX_HXX #include +#include #include #include @@ -17,7 +18,7 @@ namespace semantics // Note that unlike other keys, indexes are defined in the model // scope, not table scope. // - class index: public key + class index: public qnameable, public key { public: relational::table& @@ -28,7 +29,7 @@ namespace semantics public: index (string const& id) - : key (id) + : qnameable (id) { } diff --git a/odb/semantics/relational/key.cxx b/odb/semantics/relational/key.cxx index 648fb26..8fb28ca 100644 --- a/odb/semantics/relational/key.cxx +++ b/odb/semantics/relational/key.cxx @@ -33,7 +33,7 @@ namespace semantics // { type_info ti (typeid (key)); - ti.add_base (typeid (nameable)); + ti.add_base (typeid (node)); insert (ti); } } diff --git a/odb/semantics/relational/key.hxx b/odb/semantics/relational/key.hxx index 7e7a847..f714876 100644 --- a/odb/semantics/relational/key.hxx +++ b/odb/semantics/relational/key.hxx @@ -7,13 +7,13 @@ #define ODB_SEMANTICS_RELATIONAL_KEY_HXX #include -#include namespace semantics { namespace relational { class key; + class column; class contains: public edge { @@ -51,7 +51,7 @@ namespace semantics column_type* column_; }; - class key: public nameable + class key: public virtual node { typedef std::vector contains_list; @@ -85,12 +85,6 @@ namespace semantics contains_.push_back (&e); } - protected: - key (string const& id) - : nameable (id) - { - } - private: contains_list contains_; }; diff --git a/odb/semantics/relational/model.cxx b/odb/semantics/relational/model.cxx index a0ac23f..d19c835 100644 --- a/odb/semantics/relational/model.cxx +++ b/odb/semantics/relational/model.cxx @@ -25,7 +25,7 @@ namespace semantics // { type_info ti (typeid (model)); - ti.add_base (typeid (scope)); + ti.add_base (typeid (qscope)); insert (ti); } } diff --git a/odb/semantics/relational/model.hxx b/odb/semantics/relational/model.hxx index 7d2f944..a761af1 100644 --- a/odb/semantics/relational/model.hxx +++ b/odb/semantics/relational/model.hxx @@ -12,7 +12,7 @@ namespace semantics { namespace relational { - class model: public graph, public scope + class model: public graph, public qscope { public: model () @@ -26,8 +26,8 @@ namespace semantics } public: - using scope::add_edge_left; - using scope::add_edge_right; + using qscope::add_edge_left; + using qscope::add_edge_right; private: model (model const&); diff --git a/odb/semantics/relational/name.cxx b/odb/semantics/relational/name.cxx new file mode 100644 index 0000000..3cfd763 --- /dev/null +++ b/odb/semantics/relational/name.cxx @@ -0,0 +1,95 @@ +// file : odb/semantics/relational/name.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include +#include + +#include + +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; + } + + ostream& + operator<< (ostream& os, qname const& n) + { + bool f (true); + for (qname::iterator i (n.begin ()); i < n.end (); ++i) + { + if (i->empty ()) + continue; + + if (f) + f = false; + else + os << '.'; + + os << *i; + } + + return os; + } + + istream& + operator>> (istream& is, qname& n) + { + n.clear (); + + string s; + is >> s; + + if (!is.fail ()) + { + 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 is; + } + } +} diff --git a/odb/semantics/relational/name.hxx b/odb/semantics/relational/name.hxx new file mode 100644 index 0000000..ae06708 --- /dev/null +++ b/odb/semantics/relational/name.hxx @@ -0,0 +1,146 @@ +// file : odb/semantics/relational/name.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_NAME_HXX +#define ODB_SEMANTICS_RELATIONAL_NAME_HXX + +#include +#include +#include + +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 + 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 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; + + public: + 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/semantics/relational/primary-key.cxx b/odb/semantics/relational/primary-key.cxx index 367013e..5794f9a 100644 --- a/odb/semantics/relational/primary-key.cxx +++ b/odb/semantics/relational/primary-key.cxx @@ -25,6 +25,7 @@ namespace semantics // { type_info ti (typeid (primary_key)); + ti.add_base (typeid (unameable)); ti.add_base (typeid (key)); insert (ti); } diff --git a/odb/semantics/relational/primary-key.hxx b/odb/semantics/relational/primary-key.hxx index a35e8f5..7402b8a 100644 --- a/odb/semantics/relational/primary-key.hxx +++ b/odb/semantics/relational/primary-key.hxx @@ -13,7 +13,7 @@ namespace semantics { namespace relational { - class primary_key: public key + class primary_key: public unameable, public key { public: bool @@ -23,10 +23,10 @@ namespace semantics } public: - // Primary key has the implicit empty id. - // primary_key (bool auto_) - : key (""), auto__ (auto_) + // Primary key has the implicit empty id. + // + : unameable (""), auto__ (auto_) { } diff --git a/odb/semantics/relational/table.cxx b/odb/semantics/relational/table.cxx index a9290c6..5b3ec68 100644 --- a/odb/semantics/relational/table.cxx +++ b/odb/semantics/relational/table.cxx @@ -25,8 +25,8 @@ namespace semantics // { type_info ti (typeid (table)); - ti.add_base (typeid (nameable)); - ti.add_base (typeid (scope)); + ti.add_base (typeid (qnameable)); + ti.add_base (typeid (uscope)); insert (ti); } diff --git a/odb/semantics/relational/table.hxx b/odb/semantics/relational/table.hxx index d2f8649..cd031b8 100644 --- a/odb/semantics/relational/table.hxx +++ b/odb/semantics/relational/table.hxx @@ -12,11 +12,11 @@ namespace semantics { namespace relational { - class table: public nameable, public scope + class table: public qnameable, public uscope { protected: table (string const& id) - : nameable (id) + : qnameable (id) { } }; diff --git a/odb/traversal/relational/elements.cxx b/odb/traversal/relational/elements.cxx deleted file mode 100644 index de9c259..0000000 --- a/odb/traversal/relational/elements.cxx +++ /dev/null @@ -1,18 +0,0 @@ -// file : odb/traversal/relational/elements.cxx -// author : Boris Kolpackov -// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -namespace traversal -{ - namespace relational - { - void names:: - traverse (type& e) - { - dispatch (e.nameable ()); - } - } -} diff --git a/odb/traversal/relational/elements.hxx b/odb/traversal/relational/elements.hxx index 72b8c39..e40a9f6 100644 --- a/odb/traversal/relational/elements.hxx +++ b/odb/traversal/relational/elements.hxx @@ -94,7 +94,8 @@ namespace traversal // Edges // - struct names: edge + template + struct names: edge > { names () { @@ -102,18 +103,28 @@ namespace traversal names (node_dispatcher& n) { - node_traverser (n); + this->node_traverser (n); } virtual void - traverse (type&); + traverse (semantics::relational::names& e) + { + dispatch (e.nameable ()); + } }; + typedef names unames; + typedef names qnames; + // // Nodes // - struct nameable: node {}; + template + struct nameable: node > {}; + + typedef nameable unameable; + typedef nameable qnameable; // // @@ -140,7 +151,11 @@ namespace traversal } }; - struct scope: scope_template {}; + template + struct scope: scope_template > {}; + + typedef scope uscope; + typedef scope qscope; } } -- cgit v1.1