summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/common-query.cxx2
-rw-r--r--odb/common.cxx38
-rw-r--r--odb/common.hxx18
-rw-r--r--odb/context.cxx40
-rw-r--r--odb/context.hxx79
-rw-r--r--odb/header.cxx8
-rw-r--r--odb/inline.cxx31
-rw-r--r--odb/pragma.cxx38
-rw-r--r--odb/processor.cxx16
-rw-r--r--odb/relational/common.txx6
-rw-r--r--odb/relational/header.cxx10
-rw-r--r--odb/relational/inline.hxx8
-rw-r--r--odb/relational/model.hxx8
-rw-r--r--odb/relational/mssql/source.cxx14
-rw-r--r--odb/relational/oracle/source.cxx6
-rw-r--r--odb/relational/pgsql/header.cxx2
-rw-r--r--odb/relational/pgsql/source.cxx10
-rw-r--r--odb/relational/processor.cxx12
-rw-r--r--odb/relational/source.cxx76
-rw-r--r--odb/relational/source.hxx24
-rw-r--r--odb/relational/validator.cxx16
-rw-r--r--odb/semantics/elements.hxx22
-rw-r--r--odb/validator.cxx79
23 files changed, 407 insertions, 156 deletions
diff --git a/odb/common-query.cxx b/odb/common-query.cxx
index 25007a0..ade621a 100644
--- a/odb/common-query.cxx
+++ b/odb/common-query.cxx
@@ -678,7 +678,7 @@ traverse_pointer (semantics::data_member& m, semantics::class_& c)
string name (public_name (m));
- semantics::data_member& id (*id_member (c));
+ data_member_path& id (*id_member (c));
semantics::names* hint;
semantics::type& t (utype (id, hint));
diff --git a/odb/common.cxx b/odb/common.cxx
index 8dc995d..6d341b8 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -288,6 +288,42 @@ traverse_post (semantics::nameable&)
}
void object_columns_base::
+traverse (semantics::data_member& m)
+{
+ traverse_pre (m);
+
+ semantics::type& t (utype (m));
+ semantics::class_* c (object_pointer (t));
+ semantics::type* rt (c == 0 ? &t : &utype (*id_member (*c)));
+
+ root_ = &m;
+
+ // It would seem natural to add m to member_path_ so that we don't
+ // have these two cases. However, for member path to work correctly
+ // with readonly() we also have to have corresponding member_scope,
+ // which is a whole different level of complexity.
+ //
+ root_id_ = member_path_.empty ()
+ ? context::id (m)
+ : context::id (member_path_) != 0;
+ root_op_ = (c != 0);
+ root_null_ = context::null (m);
+
+
+ if (root_op_)
+ traverse_pointer (m, *c);
+ else
+ traverse_member (m, *rt);
+
+ if (!first_ && composite_wrapper (*rt))
+ flush ();
+
+ root_ = 0;
+
+ traverse_post (m);
+}
+
+void object_columns_base::
traverse (semantics::data_member& m,
semantics::type& t,
std::string const& kp,
@@ -305,7 +341,7 @@ traverse (semantics::data_member& m,
semantics::type* rt (c == 0 ? &t : &utype (*id_member (*c)));
root_ = &m;
- root_id_ = (kp.empty () ? context::id (m) : kp == "id");
+ root_id_ = (kp == "id");
root_op_ = (c != 0);
root_null_ = context::null (m, kp);
diff --git a/odb/common.hxx b/odb/common.hxx
index 104351a..ef85a4b 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -278,10 +278,7 @@ public:
// value type, or an object pointer (with a simple or composite id).
//
virtual void
- traverse (semantics::data_member& m)
- {
- traverse (m, utype (m), string (), string ());
- }
+ traverse (semantics::data_member&);
virtual void
traverse (semantics::data_member& m, column_prefix const& cp)
@@ -293,6 +290,17 @@ public:
}
virtual void
+ traverse (data_member_path& mp)
+ {
+ data_member_path op (member_path_);
+ member_path_ = mp;
+ traverse (*mp.back (), column_prefix (mp));
+ member_path_ = op;
+ }
+
+ // Should only be used for containers.
+ //
+ virtual void
traverse (semantics::data_member&,
semantics::type&,
string const& key_prefix,
@@ -333,7 +341,7 @@ protected:
}
else
return context::column_type (
- member_path_, key_prefix_, (root_ != 0 && (root_id_ || root_op_)));
+ member_path_, key_prefix_, root_ != 0 && (root_id_ || root_op_));
}
bool
diff --git a/odb/context.cxx b/odb/context.cxx
index 4e354d8..59058ba 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -1001,14 +1001,25 @@ context* context::current_;
semantics::data_member* context::
id (data_member_path const& mp)
{
- for (data_member_path::const_reverse_iterator i (mp.rbegin ());
- i != mp.rend (); ++i)
- {
- if (id (**i))
- return *i;
- }
+ semantics::data_member* idf (mp.front ());
- return 0;
+ if (!id (*idf))
+ return 0;
+
+ // This is for special ids, such as polymorphic-ref, which
+ // don't have "id-member" set (and we want to keep it that
+ // way since it is not really a full-fledged id).
+ //
+ if (idf->get<string> ("id").empty ()) // Not a nested id.
+ return idf;
+
+ const data_member_path& id (
+ *id_member (
+ dynamic_cast<semantics::class_&> (idf->scope ())));
+
+ // Now we need to make sure id is a prefix of mp;
+ //
+ return mp.sub (id) ? idf : 0;
}
semantics::data_member* context::
@@ -1696,8 +1707,9 @@ inc_member (semantics::data_member& m,
}
}
-data_member_path context::
-resolve_data_members (semantics::class_& c,
+void context::
+resolve_data_members (data_member_path& r,
+ semantics::class_& c,
const string& name,
const location& l,
cxx_string_lexer& lex)
@@ -1705,8 +1717,6 @@ resolve_data_members (semantics::class_& c,
using semantics::class_;
using semantics::data_member;
- data_member_path r;
-
// The name was already verified to be syntactically correct so
// we don't need to do any extra error checking in this area.
//
@@ -1722,7 +1732,7 @@ resolve_data_members (semantics::class_& c,
r.push_back (&m);
if (container (m))
- return r;
+ return;
// Resolve nested members if any.
//
@@ -1749,7 +1759,7 @@ resolve_data_members (semantics::class_& c,
r.push_back (&nm);
if (container (nm))
- return r;
+ return;
}
}
catch (semantics::unresolved const& e)
@@ -1775,8 +1785,6 @@ resolve_data_members (semantics::class_& c,
throw operation_failed ();
}
-
- return r;
}
bool context::
@@ -2177,7 +2185,7 @@ column_name (semantics::data_member& m, column_prefix const& cp) const
string n (column_name (m, d));
n = compose_name (cp.prefix, n);
- // If any component is derived, the run it through the SQL name regex.
+ // If any component is derived, then run it through the SQL name regex.
//
if (d || cp.derived)
n = transform_name (n, sql_name_column);
diff --git a/odb/context.hxx b/odb/context.hxx
index 5eef193..6398a5f 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -95,6 +95,24 @@ struct data_member_path: std::vector<semantics::data_member*>
explicit
data_member_path (semantics::data_member& m) {push_back (&m);}
+
+ // Return true if this is a sub-path of (or equal to) the
+ // specified path.
+ //
+ bool
+ sub (const data_member_path& p) const
+ {
+ size_t n (p.size ());
+
+ if (n > size ())
+ return false;
+
+ for (size_t i (0); i != n; ++i)
+ if ((*this)[i] != p[i])
+ return false;
+
+ return true;
+ }
};
// Class inheritance chain, from the most derived to base.
@@ -276,6 +294,11 @@ struct table_column
std::string column;
bool expr; // True if column is an expression, and therefore should not
// be quoted.
+
+ table_column () {}
+
+ explicit
+ table_column (const std::string& c): column (c), expr (false) {}
};
//
@@ -655,6 +678,29 @@ public:
string const& key_prefix = string (),
const custom_cxx_type** translation = 0);
+ static semantics::type&
+ utype (const data_member_path& mp, const custom_cxx_type** translation = 0)
+ {
+ return utype (*mp.back (), translation);
+ }
+
+ static semantics::type&
+ utype (const data_member_path& mp,
+ string const& key_prefix,
+ const custom_cxx_type** translation = 0)
+ {
+ return utype (*mp.back (), key_prefix, translation);
+ }
+
+ static semantics::type&
+ utype (const data_member_path& mp,
+ semantics::names*& hint,
+ string const& key_prefix = string (),
+ const custom_cxx_type** translation = 0)
+ {
+ return utype (*mp.back (), hint, key_prefix, translation);
+ }
+
// For arrays this function returns true if the (innermost) element
// type is const.
//
@@ -725,12 +771,24 @@ public:
// This function stops if it encounters a container leaving lex usable
// to continue parsing.
//
- data_member_path
- resolve_data_members (semantics::class_& scope,
+ void
+ resolve_data_members (data_member_path& append,
+ semantics::class_& scope,
const std::string& name,
const location&,
cxx_string_lexer&);
+ data_member_path
+ resolve_data_members (semantics::class_& scope,
+ const std::string& name,
+ const location& l,
+ cxx_string_lexer& lex)
+ {
+ data_member_path r;
+ resolve_data_members (r, scope, name, l, lex);
+ return r;
+ }
+
// Predicates.
//
public:
@@ -1015,7 +1073,16 @@ public:
static bool
auto_ (semantics::data_member& m)
{
- return m.count ("auto");
+ return id (m) && m.count ("auto");
+ }
+
+ // Must be a path returned by id(). In other words, it assumes
+ // the path is to the id member.
+ //
+ static bool
+ auto_ (data_member_path& mp)
+ {
+ return mp.front ()->count ("auto");
}
// The member scope is used to override readonly status when a readonly
@@ -1438,13 +1505,13 @@ public:
static column_count_type
column_count (semantics::class_&, object_section* = 0);
- static semantics::data_member*
+ static data_member_path*
id_member (semantics::class_& c)
{
- // Set by the validator. May not be there for reuse-abstract
+ // Set by the processor. May not be there for reuse-abstract
// classes or classes without object id.
//
- return c.get<semantics::data_member*> ("id-member", 0);
+ return c.count ("id-member") ? &c.get<data_member_path> ("id-member") : 0;
}
// Object pointer information.
diff --git a/odb/header.cxx b/odb/header.cxx
index 0a01311..2155ed8 100644
--- a/odb/header.cxx
+++ b/odb/header.cxx
@@ -60,9 +60,10 @@ traverse_object (type& c)
{
using semantics::data_member;
- data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
+ data_member* idf (id ? id->front () : 0);
bool auto_id (id && auto_ (*id));
- bool base_id (id && &id->scope () != &c); // Comes from base.
+ bool base_id (id && &idf->scope () != &c); // Comes from base.
data_member* opt (context::optimistic (c));
@@ -157,8 +158,7 @@ traverse_object (type& c)
{
if (base_id)
{
- semantics::class_& b (
- dynamic_cast<semantics::class_&> (id->scope ()));
+ semantics::class_& b (dynamic_cast<semantics::class_&> (idf->scope ()));
string const& type (class_fq_name (b));
os << "typedef object_traits< " << type << " >::id_type id_type;";
diff --git a/odb/inline.cxx b/odb/inline.cxx
index 1af84b6..87f1f5f 100644
--- a/odb/inline.cxx
+++ b/odb/inline.cxx
@@ -112,15 +112,16 @@ traverse_object (type& c)
{
using semantics::data_member;
- data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
+ data_member* idf (id ? id->front () : 0);
bool auto_id (id && auto_ (*id));
- bool base_id (id && &id->scope () != &c); // Comes from base.
+ bool base_id (id && &idf->scope () != &c); // Comes from base.
data_member* opt (context::optimistic (c));
// Base class that contains the object id.
//
- type* base (id != 0 && base_id ? dynamic_cast<type*> (&id->scope ()) : 0);
+ type* base (base_id ? dynamic_cast<type*> (&idf->scope ()) : 0);
bool poly (polymorphic (c));
bool abst (abstract (c));
@@ -152,16 +153,26 @@ traverse_object (type& c)
" >::id (o);";
else
{
- // Get the id using the accessor expression. If this is not
- // a synthesized expression, then output its location for
- // easier error tracking.
+ // Get the id using the accessor expressions.
//
- member_access& ma (id->get<member_access> ("get"));
+ string r ("o");
- if (!ma.synthesized)
- os << "// From " << location_string (ma.loc, true) << endl;
+ for (data_member_path::const_iterator b (id->begin ()), i (b);
+ i != id->end ();
+ ++i)
+ {
+ member_access& ma ((*i)->get<member_access> ("get"));
- os << "return " << ma.translate ("o") << ";";
+ // If this is not a synthesized expression, then output its
+ // location for easier error tracking.
+ //
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ r = ma.translate (r);
+ }
+
+ os << "return " << r << ";";
}
}
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 549a0f6..046140e 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -1893,12 +1893,50 @@ handle_pragma (cxx_lexer& l,
}
else if (p == "id")
{
+ // id[(member-path)]
+ //
+
// Make sure we've got the correct declaration type.
//
if (decl && !check_spec_decl_type (decl, decl_name, p, loc))
return;
+ string name;
+
tt = l.next (tl, &tn);
+ if (tt == CPP_OPEN_PAREN)
+ {
+ if (l.next (tl, &tn) != CPP_NAME)
+ {
+ error (l) << "data member name expected in db pragma " << p
+ << endl;
+ return;
+ }
+
+ name = tl;
+
+ for (tt = l.next (tl, &tn); tt == CPP_DOT; tt = l.next (tl, &tn))
+ {
+ if (l.next (tl, &tn) != CPP_NAME)
+ {
+ error (l) << "name expected after '.' in db pragma " << p << endl;
+ return;
+ }
+
+ name += '.';
+ name += tl;
+ }
+
+ if (tt != CPP_CLOSE_PAREN)
+ {
+ error (l) << "')' expected at the end of db pragma " << p << endl;
+ return;
+ }
+
+ tt = l.next (tl, &tn);
+ }
+
+ val = name;
}
else if (p == "no_id")
{
diff --git a/odb/processor.cxx b/odb/processor.cxx
index f7a2be2..5dc49f9 100644
--- a/odb/processor.cxx
+++ b/odb/processor.cxx
@@ -46,7 +46,7 @@ namespace
id_tree_type (semantics::names*& hint)
{
context& c (context::current ());
- semantics::data_member& id (*context::id_member (*c.top_object));
+ data_member_path& id (*context::id_member (*c.top_object));
return &c.utype (id, hint);
}
@@ -2109,7 +2109,10 @@ namespace
virtual void
traverse_object_pre (type& c)
{
- semantics::class_* poly_root (polymorphic (c));
+ using semantics::class_;
+ using semantics::data_member;
+
+ class_* poly_root (polymorphic (c));
// Sections.
//
@@ -2199,7 +2202,8 @@ namespace
using namespace semantics;
using semantics::data_member;
- data_member* idm (id_member (*poly_root));
+ data_member_path& id (*id_member (*poly_root));
+ data_member* idm (id.front ());
if (poly_root != &c)
{
@@ -2248,8 +2252,12 @@ namespace
// Mark it as a special kind of id.
//
- m.set ("id", true);
+ m.set ("id", string ());
m.set ("polymorphic-ref", true);
+
+ // Make sure we also use the same column name as the root.
+ //
+ m.set ("column", table_column (column_name (id)));
}
else
{
diff --git a/odb/relational/common.txx b/odb/relational/common.txx
index 5e5c5ac..116cfc2 100644
--- a/odb/relational/common.txx
+++ b/odb/relational/common.txx
@@ -36,9 +36,9 @@ namespace relational
{
// A pointer in view might point to an object without id.
//
- semantics::data_member* idm (id_member (*c));
- semantics::type& t (utype (idm != 0 ? *idm : m, &ct));
- semantics::class_* comp (idm != 0 ? composite_wrapper (t) : 0);
+ data_member_path* id (id_member (*c));
+ semantics::type& t (id != 0 ? utype (*id, &ct) : utype (m, &ct));
+ semantics::class_* comp (id != 0 ? composite_wrapper (t) : 0);
member_info mi (m,
(comp != 0 ? *comp : t),
diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx
index 4b8b193..b64ab2a 100644
--- a/odb/relational/header.cxx
+++ b/odb/relational/header.cxx
@@ -12,9 +12,11 @@ traverse_object (type& c)
{
using semantics::data_member;
- data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
+ data_member* idf (id ? id->front () : 0);
+ data_member* idb (id ? id->back () : 0);
bool auto_id (id && auto_ (*id));
- bool base_id (id && &id->scope () != &c); // Comes from base.
+ bool base_id (id && &idf->scope () != &c); // Comes from base.
data_member* opt (context::optimistic (c));
@@ -120,7 +122,7 @@ traverse_object (type& c)
else
{
semantics::class_& b (
- dynamic_cast<semantics::class_&> (id->scope ()));
+ dynamic_cast<semantics::class_&> (idf->scope ()));
os << "typedef object_traits_impl< " << class_fq_name (b) << ", " <<
"id_" << db << " >::id_image_type id_image_type;"
@@ -132,7 +134,7 @@ traverse_object (type& c)
os << "struct id_image_type"
<< "{";
- id_image_member_->traverse (*id);
+ id_image_member_->traverse (*idb);
if (opt != 0)
version_image_member_->traverse (*opt);
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 090779f..583cb13 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -214,16 +214,16 @@ namespace relational
{
using semantics::data_member;
- data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
+ data_member* idf (id ? id->front () : 0);
bool auto_id (id && auto_ (*id));
- bool base_id (id && &id->scope () != &c); // Comes from base.
+ bool base_id (id && &idf->scope () != &c); // Comes from base.
data_member* optimistic (context::optimistic (c));
// Base class that contains the object id and version for optimistic
// concurrency.
//
- type* base (
- id != 0 && base_id ? dynamic_cast<type*> (&id->scope ()) : 0);
+ type* base (base_id ? dynamic_cast<type*> (&idf->scope ()) : 0);
type* poly_root (context::polymorphic (c));
bool poly (poly_root != 0);
diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx
index 00b3b46..13c67d7 100644
--- a/odb/relational/model.hxx
+++ b/odb/relational/model.hxx
@@ -342,10 +342,10 @@ namespace relational
// Get referenced columns.
//
{
- semantics::data_member& idm (*id_member (c));
+ data_member_path& id (*id_member (c));
instance<object_columns_list> ocl;
- ocl->traverse (idm);
+ ocl->traverse (id);
for (object_columns_list::iterator i (ocl->begin ());
i != ocl->end (); ++i)
@@ -634,10 +634,10 @@ namespace relational
// Get referenced columns.
//
{
- data_member& idm (*id_member (*context::top_object));
+ data_member_path& id (*id_member (*context::top_object));
instance<object_columns_list> ocl;
- ocl->traverse (idm);
+ ocl->traverse (id);
for (object_columns_list::iterator i (ocl->begin ());
i != ocl->end (); ++i)
diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx
index 89b5702..42c29a7 100644
--- a/odb/relational/mssql/source.cxx
+++ b/odb/relational/mssql/source.cxx
@@ -44,10 +44,9 @@ namespace relational
string const& column)
{
// Don't add a column for auto id in the INSERT statement.
+ // Only simple, direct id can be auto.
//
- if (sk_ == statement_insert &&
- key_prefix_.empty () &&
- context::id (m) && auto_(m)) // Only simple id can be auto.
+ if (sk_ == statement_insert && key_prefix_.empty () && auto_ (m))
return false;
// Don't update the ROWVERSION column explicitly.
@@ -987,7 +986,7 @@ namespace relational
// See if we have auto id or ROWVERSION version.
//
- semantics::data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
semantics::data_member* ver (optimistic (c));
if (id != 0 && !auto_ (*id))
@@ -1047,7 +1046,8 @@ namespace relational
throw operation_failed ();
}
- r = "; SELECT " + convert_from ("SCOPE_IDENTITY()", *id);
+ r = "; SELECT " +
+ convert_from ("SCOPE_IDENTITY()", *id->back ());
}
return r;
@@ -1061,8 +1061,8 @@ namespace relational
// Top-level auto id column.
//
if (id != 0)
- r += "INSERTED." + convert_from (
- column_qname (*id, column_prefix ()), *id);
+ r += "INSERTED." +
+ convert_from (column_qname (*id), *id->back ());
// Top-level version column.
//
diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx
index 310eac6..802bc99 100644
--- a/odb/relational/oracle/source.cxx
+++ b/odb/relational/oracle/source.cxx
@@ -604,16 +604,16 @@ namespace relational
if (p == persist_after_values)
{
- semantics::data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
type* poly_root (polymorphic (c));
bool poly_derived (poly_root != 0 && poly_root != &c);
// Top-level auto id.
//
- if (id != 0 && !poly_derived && id->count ("auto"))
+ if (id != 0 && !poly_derived && auto_ (*id))
r = "RETURNING " +
- convert_from (column_qname (*id, column_prefix ()), *id) +
+ convert_from (column_qname (*id), *id->back ()) +
" INTO " + qp.next ();
}
diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx
index 19fa573..b3566d8 100644
--- a/odb/relational/pgsql/header.cxx
+++ b/odb/relational/pgsql/header.cxx
@@ -31,7 +31,7 @@ namespace relational
if (abst && !poly)
return;
- semantics::data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
semantics::data_member* optimistic (context::optimistic (c));
column_count_type const& cc (column_count (c));
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index 2bbe232..b8270ac 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -583,16 +583,16 @@ namespace relational
if (p == persist_after_values)
{
- semantics::data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
type* poly_root (polymorphic (c));
bool poly_derived (poly_root != 0 && poly_root != &c);
// Top-level auto id.
//
- if (id != 0 && !poly_derived && id->count ("auto"))
+ if (id != 0 && !poly_derived && auto_ (*id))
r = "RETURNING " +
- convert_from (column_qname (*id, column_prefix ()), *id);
+ convert_from (column_qname (*id), *id->back ());
}
return r;
@@ -610,7 +610,7 @@ namespace relational
if (abst && !poly)
return;
- semantics::data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
semantics::data_member* optimistic (context::optimistic (c));
column_count_type const& cc (column_count (c));
@@ -706,7 +706,7 @@ namespace relational
statement_oids st (statement_insert);
st.traverse (c);
- // Empty array are not portable. So add a dummy member if we
+ // Empty array is not portable. So add a dummy member if we
// are not sending anything with the insert statement.
//
if (cc.total == cc.inverse + cc.optimistic_managed +
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
index 2979a34..48ddba4 100644
--- a/odb/relational/processor.cxx
+++ b/odb/relational/processor.cxx
@@ -27,8 +27,8 @@ namespace relational
id_column_type ()
{
context& c (context::current ());
- semantics::data_member& id (*context::id_member (*c.top_object));
- return id.get<string> ("column-type");
+ data_member_path& id (*context::id_member (*c.top_object));
+ return id.back ()->get<string> ("column-id-type");
}
struct data_member: traversal::data_member, context
@@ -85,7 +85,7 @@ namespace relational
// This is an object pointer. The column type is the pointed-to
// object id type.
//
- semantics::data_member& id (*id_member (*c));
+ semantics::data_member& id (*id_member (*c)->back ());
semantics::names* idhint;
semantics::type& idt (utype (id, idhint));
@@ -220,7 +220,7 @@ namespace relational
//
{
semantics::class_& r (*object_pointer (t));
- semantics::data_member& id (*id_member (r));
+ semantics::data_member& id (*id_member (r)->front ());
if (id.count ("column"))
m.set ("column", id.get<table_column> ("column"));
@@ -306,7 +306,7 @@ namespace relational
// This is an object pointer. The column type is the pointed-to
// object id type.
//
- semantics::data_member& id (*id_member (*c));
+ semantics::data_member& id (*id_member (*c)->back ());
semantics::names* idhint;
semantics::type& idt (utype (id, idhint));
@@ -824,7 +824,7 @@ namespace relational
m.set ("column-type", src_m->get<string> ("column-type"));
else if (semantics::class_* c = object_pointer (utype (*src_m)))
{
- semantics::data_member& id (*id_member (*c));
+ semantics::data_member& id (*id_member (*c)->back ());
if (id.count ("type"))
m.set ("column-type", id.get<string> ("column-type"));
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 83e3c40..3b96ab5 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -19,9 +19,11 @@ traverse_object (type& c)
{
using semantics::data_member;
- data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
+ data_member* idf (id ? id->front () : 0);
+ data_member* idb (id ? id->back () : 0);
bool auto_id (id && auto_ (*id));
- bool base_id (id && &id->scope () != &c); // Comes from base.
+ bool base_id (id && &idf->scope () != &c); // Comes from base.
data_member* opt (optimistic (c));
@@ -42,7 +44,7 @@ traverse_object (type& c)
if (generate_grow)
{
grow = context::grow (c);
- grow_id = (id ? context::grow (*id) : false) ||
+ grow_id = (id ? context::grow (*idb) : false) ||
(opt ? context::grow (*opt) : false);
}
@@ -188,7 +190,7 @@ traverse_object (type& c)
<< "ODB_POTENTIALLY_UNUSED (db);"
<< endl
<< "id_type id;";
- init_id_value_member_id_image_->traverse (*id);
+ init_id_value_member_id_image_->traverse (*idb);
os << "return id;"
<< "}";
}
@@ -205,7 +207,35 @@ traverse_object (type& c)
<< "ODB_POTENTIALLY_UNUSED (db);"
<< endl
<< "id_type id;";
- init_id_value_member_->traverse (*id);
+
+ // Handle nested id.
+ //
+ if (id->size () > 1)
+ {
+ string var;
+
+ for (data_member_path::const_iterator i (id->begin ());
+ i != id->end ();
+ ++i)
+ {
+ // The same logic as in member_base.
+ //
+ if (!var.empty ())
+ var += "value."; // Composite.
+
+ string const& name ((*i)->name ());
+ var += name;
+
+ if (name[name.size () - 1] != '_')
+ var += '_';
+ }
+
+ instance<init_value_member> t ("id", var);
+ t->traverse (*idb);
+ }
+ else
+ init_id_value_member_->traverse (*idb);
+
os << "return id;"
<< "}";
}
@@ -339,7 +369,7 @@ traverse_object (type& c)
{
// The id reference comes first in the insert statement.
//
- os << "// " << id->name () << endl
+ os << "// " << idf->name () << endl
<< "//" << endl
<< "if (sk == statement_insert)"
<< "{"
@@ -358,7 +388,7 @@ traverse_object (type& c)
// The id reference comes last in the update statement.
//
if (!readonly)
- os << "// " << id->name () << endl
+ os << "// " << idf->name () << endl
<< "//" << endl
<< "if (sk == statement_update)"
<< "{"
@@ -398,7 +428,7 @@ traverse_object (type& c)
if (composite_wrapper (utype (*id)))
os << db << "::statement_kind sk (" << db << "::statement_select);";
- bind_id_member_->traverse (*id);
+ bind_id_member_->traverse (*idb);
if (opt != 0)
{
@@ -516,7 +546,7 @@ traverse_object (type& c)
if (composite_wrapper (utype (*id)))
os << db << "::statement_kind sk (" << db << "::statement_select);";
- init_id_image_member_->traverse (*id);
+ init_id_image_member_->traverse (*idb);
if (opt != 0)
{
@@ -1222,9 +1252,9 @@ traverse_object (type& c)
if (!poly_derived && auto_id && insert_send_auto_id)
{
- string const& n (id->name ());
+ string const& n (idf->name ());
string var ("im." + n + (n[n.size () - 1] == '_' ? "" : "_"));
- init_auto_id (*id, var);
+ init_auto_id (*idf, var); // idf == idb, since auto
os << endl;
}
@@ -1278,9 +1308,9 @@ traverse_object (type& c)
<< "throw object_already_persistent ();"
<< endl;
- if (!poly_derived && auto_id)
+ if (!poly_derived && auto_id) // idf == idb since auto
{
- set_member (*id, "obj", "id (sts.id_image ())", "db", "id_type");
+ set_member (*idf, "obj", "id (sts.id_image ())", "db", "id_type");
os << endl;
}
@@ -1486,9 +1516,9 @@ traverse_object (type& c)
// Extract auto id.
//
- if (auto_id)
+ if (auto_id) // idb == idf, since auto
{
- set_member (*id, "obj", "id (sts.id_image (i))", "db", "id_type");
+ set_member (*idf, "obj", "id (sts.id_image (i))", "db", "id_type");
os << endl;
}
@@ -4867,7 +4897,7 @@ traverse_view (type& c)
{
// container.value = pointer.id
//
- semantics::data_member& id (*id_member (*e.vo->obj));
+ data_member_path& id (*id_member (*e.vo->obj));
c_cols->traverse (imb, utype (id), "value", "value");
o_cols->traverse (id);
@@ -4877,7 +4907,7 @@ traverse_view (type& c)
{
// container.id = pointed-to.id
//
- semantics::data_member& id (*id_member (*vo->obj));
+ data_member_path& id (*id_member (*vo->obj));
c_cols->traverse (imb, utype (id), "id", "object_id", vo->obj);
o_cols->traverse (id);
@@ -4890,7 +4920,7 @@ traverse_view (type& c)
{
// container.id = pointer.id
//
- semantics::data_member& id (*id_member (*e.vo->obj));
+ data_member_path& id (*id_member (*e.vo->obj));
c_cols->traverse (
m, utype (id), "id", "object_id", e.vo->obj);
@@ -4901,7 +4931,7 @@ traverse_view (type& c)
{
// container.value = pointed-to.id
//
- semantics::data_member& id (*id_member (*vo->obj));
+ data_member_path& id (*id_member (*vo->obj));
c_cols->traverse (m, utype (id), "value", "value");
o_cols->traverse (id);
@@ -4961,7 +4991,7 @@ traverse_view (type& c)
{
// container.id = pointed-to.id
//
- semantics::data_member& id (*id_member (*vo->obj));
+ data_member_path& id (*id_member (*vo->obj));
c_cols->traverse (imb, utype (id), "id", "object_id", vo->obj);
o_cols->traverse (id);
@@ -4971,7 +5001,7 @@ traverse_view (type& c)
{
// container.value = pointer.id
//
- semantics::data_member& id (*id_member (*e.vo->obj));
+ data_member_path& id (*id_member (*e.vo->obj));
c_cols->traverse (imb, utype (id), "value", "value");
o_cols->traverse (id);
@@ -4984,7 +5014,7 @@ traverse_view (type& c)
{
// container.value = pointed-to.id
//
- semantics::data_member& id (*id_member (*vo->obj));
+ data_member_path& id (*id_member (*vo->obj));
c_cols->traverse (m, utype (id), "value", "value");
o_cols->traverse (id);
@@ -4994,7 +5024,7 @@ traverse_view (type& c)
{
// container.id = pointer.id
//
- semantics::data_member& id (*id_member (*e.vo->obj));
+ data_member_path& id (*id_member (*e.vo->obj));
c_cols->traverse (m, utype (id), "id", "object_id", e.vo->obj);
o_cols->traverse (id);
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index e67931f..f495cef 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -211,7 +211,7 @@ namespace relational
semantics::class_& imc (
poly ? dynamic_cast<semantics::class_&> (imf.scope ()) : c);
- semantics::data_member& id (*id_member (imc));
+ data_member_path& id (*id_member (imc));
semantics::type& idt (utype (id));
if (container (imb))
@@ -484,7 +484,7 @@ namespace relational
instance<object_columns_list> l_cols; // Our id columns.
instance<object_columns_list> r_cols; // Other side id columns.
- semantics::data_member& id (*id_member (*us.obj));
+ data_member_path& id (*id_member (*us.obj));
l_cols->traverse (id);
@@ -1018,7 +1018,7 @@ namespace relational
dt = quote_id (table);
da = quote_id (poly ? alias + "_" + table.uname () : alias);
- semantics::data_member& id (*id_member (c));
+ data_member_path& id (*id_member (c));
instance<object_columns_list> oid_cols, cid_cols;
oid_cols->traverse (id);
@@ -1171,7 +1171,7 @@ namespace relational
bool query_;
size_t depth_;
string table_;
- semantics::data_member& id_;
+ data_member_path& id_;
instance<object_columns_list> id_cols_;
};
@@ -1391,7 +1391,7 @@ namespace relational
// Order of these tests is important.
//
- if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m))
+ if (!insert_send_auto_id && auto_ (mi.m))
os << "if (sk != statement_insert && sk != statement_update)"
<< "{";
else if (section_ == 0 && separate_load (mi.m))
@@ -1567,7 +1567,7 @@ namespace relational
// The same logic as in pre().
//
- if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m))
+ if (!insert_send_auto_id && auto_ (mi.m))
block = true;
else if (section_ == 0 && separate_load (mi.m))
block = true;
@@ -1673,7 +1673,7 @@ namespace relational
size_t insert (cc.total - cc.inverse - cc.optimistic_managed);
size_t update (insert - cc.id - cc.readonly - cc.separate_update);
- semantics::data_member* id;
+ data_member_path* id;
if (!insert_send_auto_id && (id = id_member (c)) != 0 && auto_ (*id))
insert -= cc.id;
@@ -2041,7 +2041,7 @@ namespace relational
// If we don't send auto id in INSERT statement, ignore this
// member altogether (we never send auto id in UPDATE).
//
- if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m))
+ if (!insert_send_auto_id && auto_ (mi.m))
return false;
os << "// " << mi.m.name () << endl
@@ -2985,7 +2985,7 @@ namespace relational
bool poly_derived (poly && poly_root != &c);
size_t poly_depth (poly_derived ? polymorphic_depth (c) : 1);
- semantics::data_member* idm (id_member (poly ? *poly_root : c));
+ data_member_path* idm (id_member (poly ? *poly_root : c));
os << "// " << mi.m.name () << (pre_ ? " pre" : " post") << endl
<< "//" << endl;
@@ -3084,7 +3084,7 @@ namespace relational
for (size_t i (0); i < poly_depth - 1; ++i)
id_im += (i == 0 ? ".base" : "->base");
- string const& n (idm->name ());
+ string const& n (idm->front ()->name ());
id_var = id_im + (poly_derived ? "->" : ".") + n +
(n[n.size () - 1] == '_' ? "" : "_");
@@ -3563,7 +3563,7 @@ namespace relational
if (polymorphic (*c))
c = &dynamic_cast<semantics::class_&> (imf.scope ());
- semantics::data_member& inv_id (*id_member (*c));
+ data_member_path& inv_id (*id_member (*c));
qname inv_table; // Other table name.
string inv_qtable;
@@ -6456,7 +6456,7 @@ namespace relational
if (version (m))
p = version_value (m);
- else if (context::id (m) && auto_ (m)) // Only simple id can be auto.
+ else if (auto_ (m)) // Only simple, direct id can be auto.
p = qp_.auto_id ();
else
p = qp_.next ();
diff --git a/odb/relational/validator.cxx b/odb/relational/validator.cxx
index 5dea25f..f78c145 100644
--- a/odb/relational/validator.cxx
+++ b/odb/relational/validator.cxx
@@ -325,20 +325,20 @@ namespace relational
virtual void
traverse_object (type& c)
{
- semantics::data_member* id (id_member (c));
+ data_member_path* id (id_member (c));
if (id != 0)
{
if (semantics::class_* cm = composite_wrapper (utype (*id)))
{
+ location idl (id->front ()->location ());
+
// Composite id cannot be auto.
//
if (auto_ (*id))
{
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: composite id cannot be automatically assigned"
- << endl;
-
+ error (idl) << "composite id cannot be automatically assigned"
+ << endl;
valid_ = false;
}
@@ -350,8 +350,7 @@ namespace relational
composite_id_members_.traverse (*cm);
if (!valid_)
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": info: composite id is defined here" << endl;
+ info (idl) << "composite id is defined here" << endl;
}
// Check that the composite value type is default-constructible.
@@ -366,8 +365,7 @@ namespace relational
<< ": info: provide default constructor for this value type"
<< endl;
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": info: composite id is defined here" << endl;
+ info (idl) << "composite id is defined here" << endl;
valid_ = false;
}
diff --git a/odb/semantics/elements.hxx b/odb/semantics/elements.hxx
index b52acc3..d0156dd 100644
--- a/odb/semantics/elements.hxx
+++ b/odb/semantics/elements.hxx
@@ -114,11 +114,12 @@ namespace semantics
public:
template <typename X>
- bool
- is_a () const
- {
- return dynamic_cast<X const*> (this) != 0;
- }
+ X*
+ is_a () {return dynamic_cast<X*> (this);}
+
+ template <typename X>
+ const X*
+ is_a () const {return dynamic_cast<const X*> (this);}
};
//
@@ -165,11 +166,12 @@ namespace semantics
public:
template <typename X>
- bool
- is_a () const
- {
- return dynamic_cast<X const*> (this) != 0;
- }
+ X*
+ is_a () {return dynamic_cast<X*> (this);}
+
+ template <typename X>
+ const X*
+ is_a () const {return dynamic_cast<const X*> (this);}
public:
node (path const& file, size_t line, size_t column, tree);
diff --git a/odb/validator.cxx b/odb/validator.cxx
index a76848f..c1d82c6 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -12,6 +12,7 @@
#include <odb/context.hxx>
#include <odb/diagnostics.hxx>
#include <odb/validator.hxx>
+#include <odb/cxx-lexer.hxx>
#include <odb/relational/validator.hxx>
@@ -346,7 +347,7 @@ namespace
virtual void
traverse (semantics::data_member& m)
{
- if (id (m))
+ if (m.count ("id"))
{
if (id_ == 0)
id_ = &m;
@@ -605,8 +606,10 @@ namespace
// Check special members.
//
- semantics::data_member* id (0);
- semantics::data_member* optimistic (0);
+ using semantics::data_member;
+
+ data_member* id (0);
+ data_member* optimistic (0);
{
special_members t (class_object, valid_, id, optimistic);
t.traverse (c);
@@ -636,39 +639,75 @@ namespace
}
else
{
- c.set ("id-member", id);
+ // Convert id to a member path. This has to happen early since
+ // a lot of code that runs next (e.g., processor, pass 1) depends
+ // on this information being available.
+ //
+ data_member_path& idp (c.set ("id-member", data_member_path ()));
+ idp.push_back (id);
+
+ // See if we have a member path that we need to resolve.
+ //
+ const string& name (id->get<string> ("id"));
+ location_t l (id->get<location_t> ("id-location"));
+
+ if (!name.empty ())
+ {
+ if (id->count ("auto"))
+ {
+ error (l) << "nested id cannot be automatically assigned" << endl;
+ valid_ = false;
+ }
+
+ if (semantics::class_* comp = utype (*id).is_a<semantics::class_> ())
+ {
+ try
+ {
+ resolve_data_members (idp, *comp, name, l, lex_);
+ }
+ catch (const operation_failed&) {valid_ = false;}
+ }
+ else
+ {
+ error (l) << "nested id requires composite member" << endl;
+ valid_ = false;
+ }
+
+ // Mark the whole member as readonly.
+ //
+ id->set ("readonly", true);
+ }
+
+ data_member* idf (idp.front ());
+ data_member* idb (idp.back ());
// Complain if an id member has a default value (default value
// for the id's type is ok -- we will ignore it).
//
- if (id->count ("default"))
+ if (idb->count ("default"))
{
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot have default value" << endl;
+ error (l) << "object id member cannot have default value" << endl;
valid_ = false;
}
// Complain if an id member is in a section.
//
- if (id->count ("section-member"))
+ if (idf->count ("section-member"))
{
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot be in a section" << endl;
+ error (l) << "object id member cannot be in a section" << endl;
valid_ = false;
}
// Automatically mark the id member as not null. If we already have
// an explicit null pragma for this member, issue an error.
//
- if (id->count ("null"))
+ if (idb->count ("null"))
{
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot be null" << endl;
-
+ error (l) << "object id member cannot be null" << endl;
valid_ = false;
}
else
- id->set ("not-null", true);
+ idf->set ("not-null", true);
}
if (optimistic != 0)
@@ -1021,6 +1060,8 @@ namespace
value_type vt_;
data_member1 member_;
traversal::names names_member_;
+
+ cxx_string_lexer lex_;
};
//
@@ -1080,7 +1121,7 @@ namespace
// Make sure the pointed-to class has object id unless it is in a
// view where we can load no-id objects.
//
- if (semantics::data_member* id = id_member (*c))
+ if (data_member_path* id = id_member (*c))
{
semantics::type& idt (utype (*id));
@@ -1437,7 +1478,7 @@ namespace
}
}
- if (semantics::data_member* id = id_member (c))
+ if (data_member_path* id = id_member (c))
{
semantics::type& t (utype (*id));
@@ -1478,6 +1519,8 @@ namespace
if (!v)
{
+ semantics::data_member& idm (*id->front ());
+
os << t.file () << ":" << t.line () << ":" << t.column ()
<< ": error: value type that is used as object id in "
<< "persistent class with session support does not define "
@@ -1486,7 +1529,7 @@ namespace
os << t.file () << ":" << t.line () << ":" << t.column ()
<< ": info: provide operator< for this value type" << endl;
- os << id->file () << ":" << id->line () << ":" << id->column ()
+ os << idm.file () << ":" << idm.line () << ":" << idm.column ()
<< ": info: id member is defined here" << endl;
os << c.file () << ":" << c.line () << ":" << c.column ()