aboutsummaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-01-26 12:43:16 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-01-26 12:43:16 +0200
commitaf12ffe836de09ec84f666effa4df347eeb07a43 (patch)
treedc0aec9f8fee545c84be098414772cf2b277c30d /odb
parentc1d2ec5bbd5969332f3278f39d2a7a8f0abc0493 (diff)
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.
Diffstat (limited to 'odb')
-rw-r--r--odb/common.cxx31
-rw-r--r--odb/context.cxx117
-rw-r--r--odb/context.hxx28
-rw-r--r--odb/makefile11
-rw-r--r--odb/option-types.hxx4
-rw-r--r--odb/options.cli6
-rw-r--r--odb/parser.cxx110
-rw-r--r--odb/parser.hxx2
-rw-r--r--odb/plugin.cxx2
-rw-r--r--odb/pragma.cxx427
-rw-r--r--odb/pragma.hxx17
-rw-r--r--odb/relational/common.cxx9
-rw-r--r--odb/relational/context.cxx23
-rw-r--r--odb/relational/context.hxx5
-rw-r--r--odb/relational/context.ixx6
-rw-r--r--odb/relational/header.hxx6
-rw-r--r--odb/relational/model.cxx14
-rw-r--r--odb/relational/model.hxx26
-rw-r--r--odb/relational/mssql/context.cxx23
-rw-r--r--odb/relational/mssql/context.hxx2
-rw-r--r--odb/relational/mssql/schema.cxx32
-rw-r--r--odb/relational/mysql/context.cxx23
-rw-r--r--odb/relational/mysql/context.hxx2
-rw-r--r--odb/relational/mysql/schema.cxx22
-rw-r--r--odb/relational/oracle/context.cxx23
-rw-r--r--odb/relational/oracle/context.hxx2
-rw-r--r--odb/relational/oracle/schema.cxx20
-rw-r--r--odb/relational/pgsql/schema.cxx20
-rw-r--r--odb/relational/processor.cxx12
-rw-r--r--odb/relational/schema.cxx4
-rw-r--r--odb/relational/schema.hxx36
-rw-r--r--odb/relational/source.hxx41
-rw-r--r--odb/relational/sqlite/schema.cxx30
-rw-r--r--odb/semantics/namespace.cxx3
-rw-r--r--odb/semantics/namespace.hxx22
-rw-r--r--odb/semantics/relational/column.cxx2
-rw-r--r--odb/semantics/relational/column.hxx6
-rw-r--r--odb/semantics/relational/elements.cxx106
-rw-r--r--odb/semantics/relational/elements.hxx88
-rw-r--r--odb/semantics/relational/elements.txx94
-rw-r--r--odb/semantics/relational/foreign-key.cxx1
-rw-r--r--odb/semantics/relational/foreign-key.hxx10
-rw-r--r--odb/semantics/relational/index.cxx1
-rw-r--r--odb/semantics/relational/index.hxx5
-rw-r--r--odb/semantics/relational/key.cxx2
-rw-r--r--odb/semantics/relational/key.hxx10
-rw-r--r--odb/semantics/relational/model.cxx2
-rw-r--r--odb/semantics/relational/model.hxx6
-rw-r--r--odb/semantics/relational/name.cxx95
-rw-r--r--odb/semantics/relational/name.hxx146
-rw-r--r--odb/semantics/relational/primary-key.cxx1
-rw-r--r--odb/semantics/relational/primary-key.hxx8
-rw-r--r--odb/semantics/relational/table.cxx4
-rw-r--r--odb/semantics/relational/table.hxx4
-rw-r--r--odb/traversal/relational/elements.cxx18
-rw-r--r--odb/traversal/relational/elements.hxx25
56 files changed, 1349 insertions, 446 deletions
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<qname> ("table"));
- tp.prefix += m.get<string> ("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<qname> ("qualified-table");
+
+ qname r;
+
+ bool sf (c.count ("schema"));
if (c.count ("table"))
- name += c.get<string> ("table");
+ {
+ r = c.get<qname> ("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<location_t> ("table-location") <
+ c.get<location_t> ("schema-location");
+ }
+ }
else
- name += class_name (c);
+ r = class_name (c);
+
+ if (sf)
+ {
+ qname n (c.get<qname> ("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<namespace_*> (s));
+
+ if (ns == 0)
+ continue; // Some other scope.
+
+ if (ns->extension ())
+ ns = &ns->original ();
+
+ if (ns->count ("schema"))
+ {
+ qname n (ns->get<qname> ("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<qname> ("table"));
+
+ if (n.fully_qualified ())
+ r = n.qualifier ();
else
- name = gp;
+ {
+ r = p.prefix.qualifier ();
+ r.append (n.qualifier ());
+ }
- name += m.get<string> ("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 <odb/options.hxx>
#include <odb/cxx-token.hxx>
#include <odb/semantics.hxx>
+#include <odb/semantics/relational/name.hxx>
#include <odb/semantics/relational/model.hxx>
#include <odb/traversal.hxx>
@@ -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 <iosfwd>
+#include <odb/semantics/relational/name.hxx>
+
+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
+ {
+ "<schema>",
+ "Place database objects (tables, indexes, etc) into <schema>."
+ };
+
std::string --table-prefix
{
"<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<unit>
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<location_t, tree> 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<unit> 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<namespace_> (f, l, c, tree_node));
unit_->new_edge<defines> (*scope_, node, n);
- unit_->insert (tree_node, node);
+
+ if (namespace_* orig =
+ dynamic_cast<namespace_*> (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<semantics::unit>
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<unit> 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 ("<name>")
- // table ("<name>" [= "<alias>"] [: "<cond>"] (view only)
+ // table (<name>)
+ // table (<name> [= "<alias>"] [: "<cond>"] (view only)
+ //
+ // <name> := "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" | "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 ("<name>")
- // column ("<name>.<name>")
- // column ("<name>"."<name>")
+ // column ("<name>.<name>") (view only)
+ // column ("<name>"."<name>") (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)
- {
- // "<name>" or "<name>.<name>"
- //
- 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)
{
- // "<name>"."<name>"
- //
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 [(<identifier>)]
+ // 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 [(<identifier>)]
// view [(<identifier>)]
@@ -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<pragma>
typedef std::map<tree, pragma_list> 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_pragma> ns_loc_pragmas;
+extern ns_loc_pragmas ns_loc_pragmas_;
+
// Pragmas associated with this declaration.
//
typedef std::map<tree, pragma_set> 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 <const char* table>" << 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<semantics::node*> ("cxx-node"));
- semantics::node& d (*e.duplicate.get<semantics::node*> ("cxx-node"));
+ semantics::node& o (*e.orig.get<semantics::node*> ("cxx-node"));
+ semantics::node& d (*e.dup.get<semantics::node*> ("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<std::string> tables;
+ typedef std::set<qname> 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<semantics::node*> (&m));
- model_.new_edge<sema_rel::names> (table_, c, name);
+ model_.new_edge<sema_rel::unames> (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<sema_rel::names> (table_, pk, "");
+ model_.new_edge<sema_rel::unames> (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<sema_rel::names> (table_, fk, name + "_fk");
+ model_.new_edge<sema_rel::unames> (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<sema_rel::container_table> (id));
t.set ("cxx-node", static_cast<semantics::node*> (&m));
- model_.new_edge<sema_rel::names> (model_, t, name);
+ model_.new_edge<sema_rel::qnames> (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<sema_rel::names> (t, fk, id_name + "_fk");
+ model_.new_edge<sema_rel::unames> (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<sema_rel::names> (
- model_, i, name + '_' + id_name + "_i");
+ model_.new_edge<sema_rel::qnames> (
+ 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<sema_rel::names> (
- model_, i, name + '_' + index_name + "_i");
+ model_.new_edge<sema_rel::qnames> (
+ 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<semantics::node*> (&c));
- model_.new_edge<sema_rel::names> (model_, t, name);
+ model_.new_edge<sema_rel::qnames> (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<string> tables_; // Set of tables we have already defined.
+ set<qname> tables_; // Set of tables we have already defined.
};
entry<create_table> 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<sema_rel::table&> (fk.scope ()).name () +
- '_' + fk.name ();
+ return quote_id (
+ static_cast<sema_rel::table&> (fk.scope ()).name ().uname ()
+ + "_" + fk.name ());
}
virtual void
@@ -216,9 +216,23 @@ namespace relational
// Add foreign keys.
//
instance<add_foreign_key> 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> 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<sema_rel::table&> (fk.scope ()).name () +
- '_' + fk.name ();
+ return quote_id (
+ static_cast<sema_rel::table&> (fk.scope ()).name ().uname ()
+ + "_" + fk.name ());
}
virtual void
@@ -124,6 +126,20 @@ namespace relational
}
};
entry<create_table> 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> 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<string> tables_; // Set of tables we have already defined.
+ set<qname> tables_; // Set of tables we have already defined.
};
entry<create_table> 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<sema_rel::table&> (fk.scope ()).name () +
- '_' + fk.name ();
+ return quote_id (
+ static_cast<sema_rel::table&> (fk.scope ()).name ().uname ()
+ + "_" + fk.name ());
}
};
entry<create_foreign_key> 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<add_foreign_key> 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<string> tables_; // Set of tables we have already defined.
+ set<qname> tables_; // Set of tables we have already defined.
};
entry<create_table> create_table_;
@@ -163,9 +163,23 @@ namespace relational
// Add foreign keys.
//
instance<add_foreign_key> 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> 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<drop_model> model (*em, emos, f);
- trav_rel::names names;
+ trav_rel::qnames names;
instance<drop_table> table (*em, emos, f);
instance<drop_index> index (*em, emos, f);
@@ -70,7 +70,7 @@ namespace relational
//
{
instance<create_model> model (*em, emos, f);
- trav_rel::names names;
+ trav_rel::qnames names;
instance<create_table> table (*em, emos, f);
instance<create_index> 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<create_column> c (format_, *this);
instance<create_primary_key> pk (format_, *this);
instance<create_foreign_key> 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<schema::drop_model> drop_model_;
instance<schema::drop_table> drop_table_;
instance<schema::drop_index> drop_index_;
- trav_rel::names create_names_;
+ trav_rel::qnames create_names_;
instance<schema::create_model> create_model_;
instance<schema::create_table> create_table_;
instance<schema::create_index> 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> 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> 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> 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<contains*> 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 <cutl/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
{
- // 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<column> ())
- i = names_.insert (first_key_, &e);
- else
- {
- if (n.is_a<primary_key> ())
- 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 <cutl/container/pointer-iterator.hxx>
#include <cutl/compiler/context.hxx>
+#include <odb/semantics/relational/name.hxx>
+
namespace semantics
{
namespace relational
@@ -84,18 +86,23 @@ namespace semantics
//
//
+ template <typename N>
class scope;
+
+ template <typename N>
class nameable;
//
//
+ template <typename N>
class names: public edge
{
public:
- typedef relational::scope scope_type;
- typedef relational::nameable nameable_type;
+ typedef N name_type;
+ typedef relational::scope<N> scope_type;
+ typedef relational::nameable<N> 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<uname> unames;
+ typedef names<qname> qnames;
+
//
//
+ template <typename N>
class nameable: public virtual node
{
public:
- typedef relational::scope scope_type;
+ typedef N name_type;
+ typedef relational::names<N> names_type;
+ typedef relational::scope<N> 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<uname> unameable;
+ typedef nameable<qname> qnameable;
+
//
//
struct duplicate_name
{
- typedef relational::scope scope_type;
- typedef relational::nameable nameable_type;
+ template <typename N>
+ duplicate_name (relational::scope<N>&,
+ relational::nameable<N>& orig,
+ relational::nameable<N>& 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 <typename N>
class scope: public virtual node
{
protected:
- typedef std::list<names*> names_list;
- typedef std::map<string, names_list::iterator> names_map;
- typedef std::map<names const*, names_list::iterator> names_iterator_map;
+ 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<names_list::iterator> names_iterator;
+ typedef pointer_iterator<typename names_list::iterator> names_iterator;
typedef
- pointer_iterator<names_list::const_iterator>
+ pointer_iterator<typename names_list::const_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<uname> uscope;
+ typedef scope<qname> qscope;
}
}
+#include <odb/semantics/relational/elements.txx>
+
#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 <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+namespace semantics
+{
+ namespace relational
+ {
+ // scope
+ //
+
+ 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 ();
+ }
+
+ class column;
+ class primary_key;
+
+ template <typename N>
+ void scope<N>::
+ 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<column> ())
+ i = names_.insert (first_key_, &e);
+ else
+ {
+ if (n.is_a<primary_key> ())
+ 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 <odb/semantics/relational/elements.hxx>
+#include <odb/semantics/relational/column.hxx>
#include <odb/semantics/relational/key.hxx>
#include <odb/semantics/relational/table.hxx>
@@ -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 <odb/semantics/relational/elements.hxx>
-#include <odb/semantics/relational/column.hxx>
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*> 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<node, edge>, public scope
+ class model: public graph<node, edge>, 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 <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// 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;
+ }
+
+ 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 <boris@codesynthesis.com>
+// 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 <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;
+
+ 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 <boris@codesynthesis.com>
-// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#include <odb/traversal/relational/elements.hxx>
-
-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<semantics::relational::names>
+ template <typename N>
+ struct names: edge<semantics::relational::names<N> >
{
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<N>& e)
+ {
+ dispatch (e.nameable ());
+ }
};
+ typedef names<semantics::relational::uname> unames;
+ typedef names<semantics::relational::qname> qnames;
+
//
// Nodes
//
- struct nameable: node<semantics::relational::nameable> {};
+ template <typename N>
+ struct nameable: node<semantics::relational::nameable<N> > {};
+
+ typedef nameable<semantics::relational::uname> unameable;
+ typedef nameable<semantics::relational::qname> qnameable;
//
//
@@ -140,7 +151,11 @@ namespace traversal
}
};
- struct scope: scope_template<semantics::relational::scope> {};
+ template <typename N>
+ struct scope: scope_template<semantics::relational::scope<N> > {};
+
+ typedef scope<semantics::relational::uname> uscope;
+ typedef scope<semantics::relational::qname> qscope;
}
}