diff options
-rw-r--r-- | odb/common-query.cxx | 2 | ||||
-rw-r--r-- | odb/common.cxx | 38 | ||||
-rw-r--r-- | odb/common.hxx | 18 | ||||
-rw-r--r-- | odb/context.cxx | 40 | ||||
-rw-r--r-- | odb/context.hxx | 79 | ||||
-rw-r--r-- | odb/header.cxx | 8 | ||||
-rw-r--r-- | odb/inline.cxx | 31 | ||||
-rw-r--r-- | odb/pragma.cxx | 38 | ||||
-rw-r--r-- | odb/processor.cxx | 16 | ||||
-rw-r--r-- | odb/relational/common.txx | 6 | ||||
-rw-r--r-- | odb/relational/header.cxx | 10 | ||||
-rw-r--r-- | odb/relational/inline.hxx | 8 | ||||
-rw-r--r-- | odb/relational/model.hxx | 8 | ||||
-rw-r--r-- | odb/relational/mssql/source.cxx | 14 | ||||
-rw-r--r-- | odb/relational/oracle/source.cxx | 6 | ||||
-rw-r--r-- | odb/relational/pgsql/header.cxx | 2 | ||||
-rw-r--r-- | odb/relational/pgsql/source.cxx | 10 | ||||
-rw-r--r-- | odb/relational/processor.cxx | 12 | ||||
-rw-r--r-- | odb/relational/source.cxx | 76 | ||||
-rw-r--r-- | odb/relational/source.hxx | 24 | ||||
-rw-r--r-- | odb/relational/validator.cxx | 16 | ||||
-rw-r--r-- | odb/semantics/elements.hxx | 22 | ||||
-rw-r--r-- | odb/validator.cxx | 79 |
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 () |