From 1f777ed4b8cc816817e1ce6cb8d9af970ad9b423 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 2 Nov 2012 12:18:43 +0200 Subject: Rework query alias tag system Now each object pointer or view-associated object with alias gets its own unique tag. --- odb/relational/common.cxx | 205 +++++++++++++++++++++++----------------------- odb/relational/common.hxx | 27 +++--- odb/relational/header.cxx | 48 ++++++++++- odb/relational/header.hxx | 87 ++++++++++++++++---- odb/relational/source.cxx | 53 +++++++++++- 5 files changed, 283 insertions(+), 137 deletions(-) diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx index e9b3485..b8d2c60 100644 --- a/odb/relational/common.cxx +++ b/odb/relational/common.cxx @@ -17,6 +17,15 @@ namespace relational // query_alias_traits // + query_alias_traits:: + query_alias_traits (semantics::class_& c, bool decl) + : decl_ (decl) + { + scope_ = "access::"; + scope_ += (object (c) ? "object_traits_impl" : "view_traits_impl"); + scope_ += "< " + class_fq_name (c) + ", id_" + db.string () + " >"; + } + void query_alias_traits:: traverse_object (semantics::class_& c) { @@ -26,101 +35,110 @@ namespace relational } void query_alias_traits:: - traverse_pointer (semantics::data_member& m, semantics::class_& c) + traverse_composite (semantics::data_member* m, semantics::class_& c) { - // Ignore polymorphic id references. - // - if (m.count ("polymorphic-ref")) - return; - - // Come up with a table alias. Generally, we want it to be based - // on the column name. This is straightforward for single-column - // references. In case of a composite id, we will need to use the - // column prefix which is based on the data member name, unless - // overridden by the user. In the latter case the prefix can be - // empty, in which case we will just fall back on the member's - // public name. + // Base type. // - string alias; + if (m == 0) { - string n; - - if (composite_wrapper (utype (*id_member (c)))) - { - n = column_prefix (m, key_prefix_, default_name_); + object_columns_base::traverse_composite (m, c); + return; + } - if (n.empty ()) - n = public_name_db (m); - else - n.resize (n.size () - 1); // Remove trailing underscore. - } - else - n = column_name (m, key_prefix_, default_name_); + string old_scope (scope_); + scope_ += "::" + public_name (*m) + "_tag"; - alias = compose_name (column_prefix_, n); - } + object_columns_base::traverse_composite (m, c); - generate (alias, c); + scope_ = old_scope; } void query_alias_traits:: - generate (string const& alias, semantics::class_& c) + traverse_pointer (semantics::data_member& m, semantics::class_& c) { - string tag (escape (alias + "_alias_tag")); + // Ignore polymorphic id references. + // + if (m.count ("polymorphic-ref")) + return; - if (tags_.find (tag) == tags_.end ()) + if (decl_) + generate_decl (public_name (m), c); + else { - os << "class " << tag << ";" - << endl; + // Come up with a table alias. Generally, we want it to be based + // on the column name. This is straightforward for single-column + // references. In case of a composite id, we will need to use the + // column prefix which is based on the data member name, unless + // overridden by the user. In the latter case the prefix can be + // empty, in which case we will just fall back on the member's + // public name. + // + string alias; + { + string n; - tags_.insert (tag); - } + if (composite_wrapper (utype (*id_member (c)))) + { + n = column_prefix (m, key_prefix_, default_name_); - // Generate the alias_traits specialization. - // - generate_specialization (alias, tag, c); + if (n.empty ()) + n = public_name_db (m); + else + n.resize (n.size () - 1); // Remove trailing underscore. + } + else + n = column_name (m, key_prefix_, default_name_); + + alias = compose_name (column_prefix_, n); + } + + generate_def (public_name (m), c, alias); + } } void query_alias_traits:: - generate_specialization (string const& alias, - string const& tag, - semantics::class_& c) + generate_decl (string const& tag, semantics::class_& c) { - string const& fq_name (class_fq_name (c)); - string guard ( - make_guard ("ODB_" + string (db.string ()) + "_ALIAS_TRAITS_" + - alias + "_FOR_" + flat_name (fq_name))); - - if (specs_.find (guard) != specs_.end ()) - return; - else - specs_.insert (guard); - semantics::class_* poly_root (polymorphic (c)); bool poly_derived (poly_root != 0 && poly_root != &c); semantics::class_* poly_base (poly_derived ? &polymorphic_base (c) : 0); if (poly_derived) - generate_specialization (alias, tag, *poly_base); - - os << "#ifndef " << guard << endl - << "#define " << guard << endl; + generate_decl (tag, *poly_base); - os << "template " << endl - << "struct alias_traits< " << fq_name << ", id_" << db << ", " << - tag << ", d >" + os << "template <>" << endl + << "struct alias_traits<" << endl + << " " << class_fq_name (c) << "," << endl + << " id_" << db << "," << endl + << " " << scope_ << "::" << tag << "_tag>" << "{" << "static const char table_name[];"; if (poly_derived) - os << "typedef alias_traits< " << class_fq_name (*poly_base) << ", " << - "id_" << db << ", " << tag << " > base_traits;"; + os << endl + << "typedef alias_traits<" << endl + << " " << class_fq_name (*poly_base) << "," << endl + << " id_" << db << "," << endl + << " " << scope_ << "::" << tag << "_tag>" << endl + << "base_traits;"; os << "};"; + } + + void query_alias_traits:: + generate_def (string const& tag, semantics::class_& c, string const& alias) + { + semantics::class_* poly_root (polymorphic (c)); + bool poly_derived (poly_root != 0 && poly_root != &c); + semantics::class_* poly_base (poly_derived ? &polymorphic_base (c) : 0); - os << "template " << endl - << "const char alias_traits< " << fq_name << ", id_" << db << ", " << - tag << ", d >::" << endl + if (poly_derived) + generate_def (tag, *poly_base, alias); + + os << "const char alias_traits<" + << " " << class_fq_name (c) << "," << endl + << " id_" << db << "," << endl + << " " << scope_ << "::" << tag << "_tag>::" << endl << "table_name[] = "; if (poly_root != 0) @@ -129,25 +147,22 @@ namespace relational os << strlit (quote_id (alias)); os << ";" - << "#endif // " << guard << endl << endl; } - // query_columns_base // query_columns_base:: - query_columns_base () - : decl_ (true) + query_columns_base (semantics::class_& c, bool decl) + : decl_ (decl) { - } + string const& n (class_fq_name (c)); - query_columns_base:: - query_columns_base (semantics::class_& c) //@@ context::{cur,top}_object - : decl_ (false) - { - scope_ = "query_columns_base< " + class_fq_name (c) + ", id_" + + if (!decl) + scope_ = "query_columns_base< " + n + ", id_" + db.string () + " >"; + + tag_scope_ = "access::object_traits_impl< " + n + ", id_" + db.string () + " >"; } @@ -184,17 +199,25 @@ namespace relational << "struct " << name << "_base_" << "{"; + string old_tag_scope (tag_scope_); + tag_scope_ += "::" + name + "_tag"; + object_columns_base::traverse_composite (m, c); + tag_scope_ = old_tag_scope; + os << "};"; } else { string old_scope (scope_); + string old_tag_scope (tag_scope_); scope_ += "::" + name + "_base_"; + tag_scope_ += "::" + name + "_tag"; object_columns_base::traverse_composite (m, c); + tag_scope_ = old_tag_scope; scope_ = old_scope; } } @@ -215,39 +238,13 @@ namespace relational os << "// " << name << endl << "//" << endl; - // Come up with a table alias. Generally, we want it to be based - // on the column name. This is straightforward for single-column - // references. In case of a composite id, we will need to use the - // column prefix which is based on the data member name, unless - // overridden by the user. In the latter case the prefix can be - // empty, in which case we will just fall back on the member's - // public name. - // - string alias; - { - string n; - - if (composite_wrapper (utype (*id_member (c)))) - { - n = column_prefix (m, key_prefix_, default_name_); - - if (n.empty ()) - n = public_name_db (m); - else - n.resize (n.size () - 1); // Remove trailing underscore. - } - else - n = column_name (m, key_prefix_, default_name_); - - alias = compose_name (column_prefix_, n); - } - - string tag (escape (alias + "_alias_tag")); string const& fq_name (class_fq_name (c)); os << "typedef" << endl - << "odb::alias_traits< " << fq_name << ", id_" << db << ", " << - tag << " >" << endl + << "odb::alias_traits<" << endl + << " " << fq_name << "," << endl + << " id_" << db << "," << endl + << " " << tag_scope_ << "::" << name << "_tag>" << endl << name << "_alias_;" << endl; diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx index b951d15..1e7143f 100644 --- a/odb/relational/common.hxx +++ b/odb/relational/common.hxx @@ -222,33 +222,32 @@ namespace relational } }; - // Generate alias tags and alias_traits specializations for pointers - // in this objects. + // Generate alias_traits specializations for pointers in this objects. // struct query_alias_traits: object_columns_base, virtual context { typedef query_alias_traits base; - query_alias_traits (std::set& tags, std::set& specs) - : tags_ (tags), specs_ (specs) {} + query_alias_traits (semantics::class_&, bool decl); virtual void traverse_object (semantics::class_&); virtual void + traverse_composite (semantics::data_member*, semantics::class_&); + + virtual void traverse_pointer (semantics::data_member&, semantics::class_&); virtual void - generate (string const& alias, semantics::class_&); + generate_decl (string const& tag, semantics::class_&); - private: - void - generate_specialization (string const& alias, - string const& tag, - semantics::class_&); + virtual void + generate_def (string const& tag, semantics::class_&, string const& alias); - std::set& tags_; - std::set& specs_; + protected: + bool decl_; + string scope_; }; // @@ -257,8 +256,7 @@ namespace relational { typedef query_columns_base base; - query_columns_base (); - query_columns_base (semantics::class_&); + query_columns_base (semantics::class_&, bool decl); virtual void traverse_object (semantics::class_&); @@ -272,6 +270,7 @@ namespace relational protected: bool decl_; string scope_; + string tag_scope_; }; // diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx index 1295106..3c9cd5a 100644 --- a/odb/relational/header.cxx +++ b/odb/relational/header.cxx @@ -147,6 +147,22 @@ traverse_object (type& c) } // + // Query (abstract and concrete). + // + + if (options.generate_query ()) + { + // Generate object pointer tags. + // + if (has_a (c, test_pointer | exclude_base)) + { + instance t; + t->traverse (c); + os << endl; + } + } + + // // Functions (abstract and concrete). // @@ -630,6 +646,7 @@ void relational::header::class1:: traverse_view (type& c) { string const& type (class_fq_name (c)); + size_t obj_count (c.get ("object-count")); os << "// " << class_name (c) << endl << "//" << endl; @@ -656,12 +673,41 @@ traverse_view (type& c) // Query. // + // Generate associated object tags. + // + if (obj_count != 0) + { + view_objects& objs (c.get ("objects")); + + { + instance t; + + bool gen (false); + for (view_objects::const_iterator i (objs.begin ()); + i < objs.end (); + ++i) + { + if (i->kind != view_object::object) + continue; // Skip tables. + + if (i->alias.empty ()) + continue; + + t->generate (i->alias); + gen = true; + } + + if (gen) + os << endl; + } + } + // query_base_type and query_columns (definition generated by class2). // os << "typedef " << db << "::query_base query_base_type;" << "struct query_columns"; - if (c.get ("object-count") == 0) + if (obj_count == 0) os << "{" << "};"; else diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index c0e1e89..c2bf73e 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -142,6 +142,62 @@ namespace relational }; // + // query_tags + // + + struct query_tags: object_columns_base, virtual context + { + typedef query_tags base; + + virtual void + traverse_object (semantics::class_& c) + { + names (c); // We don't want to traverse bases. + } + + virtual void + traverse_composite (semantics::data_member* m, semantics::class_& c) + { + // Base type. + // + if (m == 0) + { + object_columns_base::traverse_composite (m, c); + return; + } + + // Don't generate an empty struct if we don't have any pointers. + // + if (!has_a (c, test_pointer)) + return; + + os << "struct " << public_name (*m) << "_tag" + << "{"; + + object_columns_base::traverse_composite (m, c); + + os << "};"; + } + + virtual void + traverse_pointer (semantics::data_member& m, semantics::class_&) + { + // Ignore polymorphic id references. + // + if (m.count ("polymorphic-ref")) + return; + + generate (public_name (m)); + } + + virtual void + generate (string const& name) + { + os << "struct " << name << "_tag;"; + } + }; + + // // query_columns_type // @@ -305,7 +361,8 @@ namespace relational db << " >" << "{"; - instance t; + bool true_ (true); //@@ (im)perfect forwarding. + instance t (c, true_); t->traverse (c); os << "};"; @@ -1072,7 +1129,8 @@ namespace relational // if (has_ptr) { - instance t (alias_tags_, alias_specs_); + bool true_ (true); //@@ (im)perfect forwarding + instance t (c, true_); t->traverse (c); query_columns_type_->traverse (c); @@ -1098,10 +1156,11 @@ namespace relational view_objects& objs (c.get ("objects")); - // Generate the alias tags and alias_traits specializations. + // Generate alias_traits specializations. // { - instance at (alias_tags_, alias_specs_); + bool true_ (true); //@@ (im)perfect forwarding + instance at (c, true_); for (view_objects::const_iterator i (objs.begin ()); i < objs.end (); @@ -1121,7 +1180,7 @@ namespace relational // a prefix). // if (polymorphic (o) || t.qualified () || i->alias != t.uname ()) - at->generate (i->alias, o); + at->generate_decl (i->alias, o); } } @@ -1156,9 +1215,10 @@ namespace relational table.qualified () || i->alias != table.uname ())) { - string tag (escape (i->alias + "_alias_tag")); - os << " odb::alias_traits< " << otype << ", id_" << db << - ", " << tag << " > >" << endl; + os << " odb::alias_traits< " << otype << "," << endl + << " id_" << db << "," << endl + << " access::view_traits_impl< " << type << ", id_" << + db << " >::" << i->alias << "_tag> >" << endl; } else os << " odb::access::object_traits_impl< " << otype << @@ -1198,9 +1258,11 @@ namespace relational table.qualified () || vo->alias != table.uname ())) { - string tag (escape (vo->alias + "_alias_tag")); - os << " odb::alias_traits< " << otype << ", id_" << - db << ", " << tag << " > >"; + os << " odb::alias_traits<" << endl + << " " << otype << "," << endl + << " id_" << db << "," << endl + << " access::view_traits_impl< " << type << ", id_" << + db << " >::" << vo->alias << "_tag> >"; } else os << " odb::access::object_traits_impl< " << otype << @@ -1221,9 +1283,6 @@ namespace relational private: instance query_columns_type_; - - std::set alias_tags_; - std::set alias_specs_; }; struct include: virtual context diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 7fc3ce6..21c0f57 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -22,8 +22,6 @@ traverse_object (type& c) bool base_id (id && &id->scope () != &c); // Comes from base. member_access* id_ma (id ? &id->get ("get") : 0); - bool has_ptr (has_a (c, test_pointer)); - data_member* opt (optimistic (c)); member_access* opt_ma_get (opt ? &opt->get ("get") : 0); member_access* opt_ma_set (opt ? &opt->get ("set") : 0); @@ -61,16 +59,30 @@ traverse_object (type& c) object_extra (c); // - // Query. + // Query (abstract and concrete). // if (options.generate_query ()) { + bool has_ptr (has_a (c, test_pointer | exclude_base)); + + // Generate alias_traits specializations. While the class + // is generated even if our base has a pointer, there is + // not source code if we don't have pointers ourselves. + // + if (has_ptr) + { + bool false_ (false); //@@ (im)perfect forwarding + instance t (c, false_); + t->traverse (c); + } + // query_columns_base // if (has_ptr) { - instance t (c); + bool false_ (false); //@@ (im)perfect forwarding. + instance t (c, false_); t->traverse (c); } } @@ -2865,6 +2877,39 @@ traverse_view (type& c) view_extra (c); + if (c.get ("object-count") != 0) + { + view_objects& objs (c.get ("objects")); + + // Generate alias_traits specializations. + // + { + bool false_ (false); //@@ (im)perfect forwarding + instance at (c, false_); + + for (view_objects::const_iterator i (objs.begin ()); + i < objs.end (); + ++i) + { + if (i->kind != view_object::object) + continue; // Skip tables. + + if (i->alias.empty ()) + continue; + + semantics::class_& o (*i->obj); + qname const& t (table_name (o)); + + // Check that the alias is not the same as the table name + // (if this is a polymorphic object, then the alias is just + // a prefix). + // + if (polymorphic (o) || t.qualified () || i->alias != t.uname ()) + at->generate_def (i->alias, o, i->alias); + } + } + } + // // Functions. // -- cgit v1.1