From 9ad0acf37561de9bf359a561faed53de17c2ca3b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 21 Nov 2012 13:11:43 +0200 Subject: Add dynamic multi-database query support --- odb/common-query.cxx | 1112 ++++++++++++++++++++++++++++++++++++++ odb/common-query.hxx | 239 ++++++++ odb/common.hxx | 97 +--- odb/context.cxx | 4 + odb/context.hxx | 3 + odb/generator.cxx | 19 +- odb/header.cxx | 404 +++++++++++--- odb/inline.cxx | 93 +++- odb/instance.cxx | 74 +++ odb/instance.hxx | 279 ++++++++++ odb/makefile | 3 + odb/option-functions.cxx | 9 +- odb/option-types.cxx | 11 +- odb/option-types.hxx | 12 +- odb/processor.cxx | 3 +- odb/relational/common-query.cxx | 167 ++++++ odb/relational/common-query.hxx | 64 +++ odb/relational/common.cxx | 571 +------------------ odb/relational/common.hxx | 350 +----------- odb/relational/header.cxx | 62 ++- odb/relational/header.hxx | 371 +------------ odb/relational/mssql/common.cxx | 16 +- odb/relational/mysql/common.cxx | 2 +- odb/relational/oracle/common.cxx | 18 +- odb/relational/pgsql/common.cxx | 2 +- odb/relational/source.cxx | 178 ++++-- odb/relational/source.hxx | 17 +- odb/relational/sqlite/common.cxx | 2 +- odb/source.cxx | 53 +- 29 files changed, 2699 insertions(+), 1536 deletions(-) create mode 100644 odb/common-query.cxx create mode 100644 odb/common-query.hxx create mode 100644 odb/instance.cxx create mode 100644 odb/instance.hxx create mode 100644 odb/relational/common-query.cxx create mode 100644 odb/relational/common-query.hxx (limited to 'odb') diff --git a/odb/common-query.cxx b/odb/common-query.cxx new file mode 100644 index 0000000..ce07136 --- /dev/null +++ b/odb/common-query.cxx @@ -0,0 +1,1112 @@ +// file : odb/common-query.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include + +using namespace std; + +// query_tags +// + +void query_tags:: +traverse (semantics::class_& c) +{ + if (object (c)) + { + object_columns_base::traverse (c); + } + else if (c.get ("object-count") != 0) // View. + { + view_objects& objs (c.get ("objects")); + + 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; + + generate (i->alias); + } + } + + if (nl_) + os << endl; +} + +void query_tags:: +traverse_object (semantics::class_& c) +{ + names (c); // We don't want to traverse bases. +} + +void query_tags:: +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; + + if (nl_) + os << endl; + + os << "struct " << public_name (*m) << "_tag" + << "{"; + + object_columns_base::traverse_composite (m, c); + + os << "};"; + + nl_ = false; +} + +void query_tags:: +traverse_pointer (semantics::data_member& m, semantics::class_&) +{ + // Ignore polymorphic id references. + // + if (m.count ("polymorphic-ref")) + return; + + generate (public_name (m)); +} + +void query_tags:: +generate (string const& name) +{ + os << "struct " << name << "_tag;"; + nl_ = true; +} + +// 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) +{ + // We don't want to traverse bases. + // + names (c); +} + +void query_alias_traits:: +traverse_composite (semantics::data_member* m, semantics::class_& c) +{ + // Base type. + // + if (m == 0) + { + object_columns_base::traverse_composite (m, c); + return; + } + + string old_scope (scope_); + scope_ += "::" + public_name (*m) + "_tag"; + + object_columns_base::traverse_composite (m, c); + + scope_ = old_scope; +} + +void query_alias_traits:: +traverse_pointer (semantics::data_member& m, semantics::class_& c) +{ + // Ignore polymorphic id references. + // + if (m.count ("polymorphic-ref")) + return; + + if (decl_) + generate_decl (public_name (m), c); + else + generate_def (m, c); +} + +void query_alias_traits:: +generate_decl (string const& tag, semantics::class_& c) +{ + 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_decl (tag, *poly_base); + + string const& fq_name (class_fq_name (c)); + + os << "template <>" << endl + << "struct alias_traits<" << endl + << " " << fq_name << "," << endl + << " id_" << db << "," << endl + << " " << scope_ << "::" << tag << "_tag>" + << "{"; + + if (poly_derived) + os << "typedef alias_traits<" << endl + << " " << class_fq_name (*poly_base) << "," << endl + << " id_" << db << "," << endl + << " " << scope_ << "::" << tag << "_tag>" << endl + << "base_traits;" + << endl; + + // For dynamic multi-database support also generate common traits + // alias. Note that the tag type is the same since they all are + // derived from object_traits. + // + if (db != database::common && multi_dynamic) + os << "typedef alias_traits<" << endl + << " " << fq_name << "," << endl + << " id_common," << endl + << " " << scope_ << "::" << tag << "_tag>" << endl + << "common_traits;" + << endl; + + generate_decl_body (); // Table name, etc. + + os << "};"; +} + +void query_alias_traits:: +generate_decl_body () +{ +} + +void query_alias_traits:: +generate_def (semantics::data_member&, semantics::class_&) +{ +} + +void query_alias_traits:: +generate_def (string const&, semantics::class_&, string const&) +{ +} + +// query_columns_base +// + +query_columns_base:: +query_columns_base (semantics::class_& c, bool decl) + : decl_ (decl) +{ + string const& n (class_fq_name (c)); + + if (decl) + scope_ = "access::object_traits_impl< " + n + ", id_" + + db.string () + " >"; + else + scope_ = "query_columns_base< " + n + ", id_" + db.string () + " >"; +} + +void query_columns_base:: +traverse_object (semantics::class_& c) +{ + // We don't want to traverse bases. + // + names (c); +} + +void query_columns_base:: +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; + + string name (public_name (*m)); + + if (decl_) + { + os << "// " << name << endl + << "//" << endl + << "struct " << name << "_base_" + << "{"; + + string old_scope (scope_); + scope_ += "::" + name + "_tag"; + + object_columns_base::traverse_composite (m, c); + + scope_ = old_scope; + + os << "};"; + } + else + { + string old_scope (scope_); + scope_ += "::" + name + "_base_"; + + object_columns_base::traverse_composite (m, c); + + scope_ = old_scope; + } +} + +void query_columns_base:: +traverse_pointer (semantics::data_member& m, semantics::class_& c) +{ + // Ignore polymorphic id references. + // + if (m.count ("polymorphic-ref")) + return; + + string name (public_name (m)); + string const& fq_name (class_fq_name (c)); + bool inv (inverse (m, key_prefix_)); + + if (decl_) + { + os << "// " << name << endl + << "//" << endl; + + os << "typedef" << endl + << "odb::alias_traits<" << endl + << " " << fq_name << "," << endl + << " id_" << db << "," << endl + << " " << scope_ << "::" << name << "_tag>" << endl + << name << "_alias_;" + << endl; + + if (inv) + { + os << "typedef" << endl + << "odb::query_pointer<" << endl + << " odb::pointer_query_columns<" << endl + << " " << fq_name << "," << endl + << " id_" << db << "," << endl + << " " << name << "_alias_ > >" << endl + << name << "_type_ ;" + << endl + << "static " << const_ << name << "_type_ " << name << ";" + << endl; + } + } + else + { + // Generate explicit template instantiation directive for the + // pointed-to pointer_query_columns. + // + if (multi_dynamic) + { + // If the pointed-to class has no pointers of its own then + // pointer_query_columns just derives from query_columns and + // that's what we need to instantiate. + // + bool has_ptr (has_a (c, test_pointer | include_base)); + + string alias (scope_ + "::" + name + "_alias_"); + + // Instantiate base [pointer_]query_columns. + // + { + instance b (has_ptr, alias); + traversal::inherits i (*b); + inherits (c, i); + } + + os << "template struct " << (has_ptr ? "pointer_" : "") << + "query_columns<" << endl + << " " << fq_name << "," << endl + << " id_" << db << "," << endl + << " " << alias << " >;" + << endl; + } + + if (inv) + os << const_ << scope_ << "::" << name << "_type_" << endl + << scope_ << "::" << name << ";" + << endl; + } +} + +// query_columns +// + +query_columns:: +query_columns (bool ptr) + : ptr_ (ptr), decl_ (true), in_ptr_ (false) +{ +} + +query_columns:: +query_columns (bool ptr, semantics::class_& c) //@@ context::{cur,top}_object + : ptr_ (ptr), decl_ (false), in_ptr_ (false), fq_name_ (class_fq_name (c)) +{ +} + +void query_columns:: +traverse_object (semantics::class_& c) +{ + // We don't want to traverse bases. + // + names (c); +} + +void query_columns:: +traverse_composite (semantics::data_member* m, semantics::class_& c) +{ + // Base type. + // + if (m == 0) + { + object_columns_base::traverse_composite (m, c); + return; + } + + string name (public_name (*m)); + string suffix (in_ptr_ ? "_column_type_" : "_type_"); + + if (decl_) + { + os << "// " << name << endl + << "//" << endl + << "struct " << name << suffix; + + // Derive from the base in query_columns_base. It contains columns + // data for the pointer members. + // + if (!ptr_ && has_a (c, test_pointer)) + os << ": " << name << "_base_"; + + os << "{"; + + if (!const_.empty ()) + os << name << suffix << " ()" // Need user-defined default c-tor for + << "{" // initialization of static const. + << "}"; + + object_columns_base::traverse_composite (m, c); + + os << "};"; + + if (!in_ptr_) + os << "static " << const_ << name << "_type_ " << name << ";" + << endl; + } + else + { + // Handle nested members first. + // + string old_scope (scope_); + scope_ += "::" + name + suffix; + + object_columns_base::traverse_composite (m, c); + + scope_ = old_scope; + + // Composite member. Note that here we don't use suffix. + // + string tmpl (ptr_ ? "pointer_query_columns" : "query_columns"); + tmpl += "< " + fq_name_ + ", id_" + db.string () + ", A >" + scope_; + + os << "template " << endl + << const_ << "typename " << tmpl << "::" << name << "_type_" << endl + << tmpl << "::" << name << ";" + << endl; + } +} + +void query_columns:: +column_ctor (string const&, string const&, string const&) +{ +} + +void query_columns:: +column_common (semantics::data_member& m, + string const& type, + string const&, + string const& suffix) +{ + string name (public_name (m)); + + if (decl_) + { + os << "// " << name << endl + << "//" << endl; + + os << "typedef odb::query_column< " << type << " > " << name << + suffix << ";" + << endl; + } + else + { + // Note that here we don't use suffix. + // + string tmpl (ptr_ ? "pointer_query_columns" : "query_columns"); + tmpl += "< " + fq_name_ + ", id_" + db.string () + ", A >" + scope_; + + os << "template " << endl + << const_ << "typename " << tmpl << "::" << name << "_type_" << endl + << tmpl << "::" << name << ";" + << endl; + } +} + +bool query_columns:: +traverse_column (semantics::data_member& m, string const& column, bool) +{ + semantics::names* hint; + semantics::type& t (utype (m, hint)); + + column_common (m, t.fq_name (hint), column); + + if (decl_) + { + string name (public_name (m)); + + os << "static " << const_ << name << "_type_ " << name << ";" + << endl; + } + + return true; +} + +void query_columns:: +traverse_pointer (semantics::data_member& m, semantics::class_& c) +{ + // Ignore polymorphic id references. + // + if (m.count ("polymorphic-ref")) + return; + + // If this is for the pointer_query_columns and the member is not + // inverse, then create the normal member corresponding to the id + // column. This will allow the user to check it for NULL or to + // compare ids. In case this is for query_columns, then for the + // inverse member everything has been generated in query_columns_base. + // + if (inverse (m, key_prefix_)) + return; + + string name (public_name (m)); + + semantics::data_member& id (*id_member (c)); + semantics::names* hint; + semantics::type& t (utype (id, hint)); + + if (composite_wrapper (t)) + { + // Composite id. + // + + // For pointer_query_columns generate normal composite mapping. + // + if (ptr_) + object_columns_base::traverse_pointer (m, c); + else + { + // If this is a non-inverse relationship, then make the column have + // a dual interface: that of an object pointer and of an id column. + // The latter allows the user to, for example, use the is_null() + // test in a natural way. For inverse relationships there is no + // column and so the column interface is not available. + // + in_ptr_ = true; + object_columns_base::traverse_pointer (m, c); + in_ptr_ = false; + + if (decl_) + { + os << "typedef" << endl + << "odb::query_pointer<" << endl + << " odb::pointer_query_columns<" << endl + << " " << class_fq_name (c) << "," << endl + << " id_" << db << "," << endl + << " " << name << "_alias_ > >" << endl + << name << "_pointer_type_;" + << endl; + + os << "struct " << name << "_type_: " << name << "_pointer_type_, " << + name << "_column_type_" + << "{"; + + if (!const_.empty ()) + os << name << "_type_ ()" // Need user-defined default c-tor for + << "{" // initialization of static const. + << "}"; + + os << "};"; + + os << "static " << const_ << name << "_type_ " << name << ";" + << endl; + } + } + } + else + { + // Simple id. + // + string type (t.fq_name (hint)); + string column ( + compose_name ( + column_prefix_, column_name (m, key_prefix_, default_name_))); + + // For pointer_query_columns generate normal column mapping. + // + if (ptr_) + column_common (m, type, column); + else + { + // If this is a non-inverse relationship, then make the column have + // a dual interface: that of an object pointer and of an id column. + // The latter allows the user to, for example, use the is_null() + // test in a natural way. For inverse relationships there is no + // column and so the column interface is not available. + // + column_common (m, type, column, "_column_type_"); + + if (decl_) + { + os << "typedef" << endl + << "odb::query_pointer<" << endl + << " odb::pointer_query_columns<" << endl + << " " << class_fq_name (c) << "," << endl + << " id_" << db << "," << endl + << " " << name << "_alias_ > >" << endl + << name << "_pointer_type_;" + << endl; + + os << "struct " << name << "_type_: " << name << "_pointer_type_, " << + name << "_column_type_" + << "{"; + + column_ctor (type, name + "_type_", name + "_column_type_"); + + os << "};"; + } + } + + if (decl_) + os << "static " << const_ << name << "_type_ " << name << ";" + << endl; + } +} + +// query_columns_bases +// + +void query_columns_bases:: +traverse (type& c) +{ + // Ignore transient bases. Not used for views. + // + if (!object (c)) + return; + + if (first_) + { + os << ":" << endl + << " "; + first_ = false; + } + else + os << "," << endl + << " "; + + os << (ptr_ ? "pointer_query_columns" : "query_columns") << "< " << + class_fq_name (c) << ", id_" << db << ", "; + + // If our base is polymorphic, then it has its own table/alias. + // + if (polymorphic (c)) + os << "typename A::base_traits"; + else + os << "A"; + + os << " >"; +} + +// query_columns_base_aliases +// + +void query_columns_base_aliases:: +traverse (type& c) +{ + // Ignore transient bases. Not used for views. + // + if (!object (c)) + return; + + string const& name (class_name (c)); + + os << "// " << name << endl + << "//" << endl + << "typedef " << (ptr_ ? "pointer_query_columns" : "query_columns") << + "< " << class_fq_name (c) << ", id_" << db << ", "; + + if (polymorphic (c)) + os << "typename A::base_traits"; + else + os << "A"; + + os << " > " << name << ";" + << endl; +} + +// query_columns_base_insts +// + +query_columns_base_insts:: +query_columns_base_insts (bool ptr, string const& alias) + : ptr_ (ptr), alias_ (alias) +{ + *this >> inherits_ >> *this; +} + +query_columns_base_insts:: +query_columns_base_insts (query_columns_base_insts const& x) + : context (), // @@ -Wextra + ptr_ (x.ptr_), alias_ (x.alias_) +{ + *this >> inherits_ >> *this; +} + +void query_columns_base_insts:: +traverse (type& c) +{ + // We are only interested in reuse inheritance. + // + if (!object (c) || polymorphic (c)) + return; + + // Instantiate bases recursively. + // + inherits (c, inherits_); + + os << "template struct " << + (ptr_ ? "pointer_query_columns" : "query_columns") << "<" << endl + << " " << class_fq_name (c) << "," << endl + << " id_" << db << "," << endl + << " " << alias_ << " >;" + << endl; +} + +// query_columns_type +// + +void query_columns_type:: +traverse (type& c) +{ + string const& type (class_fq_name (c)); + + if (ptr_) + { + os << "template " << endl + << "struct pointer_query_columns< " << type << ", id_" << db << ", A >"; + + // If we don't have pointers (in the whole hierarchy), then + // pointer_query_columns and query_columns are the same. + // + if (!has_a (c, test_pointer | include_base)) + { + os << ":" << endl + << " query_columns< " << type << ", id_" << db << ", A >" + << "{" + << "};"; + } + else + { + { + instance b (ptr_); + traversal::inherits i (*b); + inherits (c, i); + } + + os << "{"; + + { + instance b (ptr_); + traversal::inherits i (*b); + inherits (c, i); + } + + { + instance t (ptr_); + t->traverse (c); + } + + os << "};"; + + generate_impl (c); + } + } + else if (decl_) + { + bool has_ptr (has_a (c, test_pointer | exclude_base)); + + if (has_ptr) + { + // Generate aliases. + // + { + bool true_ (true); //@@ (im)perfect forwarding + instance t (c, true_); + t->traverse (c); + } + + // This class contains everything for inverse pointers and + // aliases for non-inverse ones. It doesn't depend on the + // table alias (A) template argument. + // + os << "template <>" << endl + << "struct query_columns_base< " << type << ", id_" << db << " >" + << "{"; + + bool true_ (true); //@@ (im)perfect forwarding. + instance t (c, true_); + t->traverse (c); + + os << "};"; + } + + os << "template " << endl + << "struct query_columns< " << type << ", id_" << db << ", A >"; + + if (has_ptr) + os << ":" << endl + << " query_columns_base< " << type << ", id_" << db << " >"; + + { + instance b (ptr_, !has_ptr); + traversal::inherits i (*b); + inherits (c, i); + } + + os << "{"; + + { + instance b (ptr_); + traversal::inherits i (*b); + inherits (c, i); + } + + { + instance t (ptr_); + t->traverse (c); + } + + os << "};"; + + generate_impl (c); + } + else + { + 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) + { + bool false_ (false); //@@ (im)perfect forwarding. + instance t (c, false_); + t->traverse (c); + } + + // Explicit template instantiations. Here is what we need to + // instantiate + // + // 1. Reuse inheritance bases all the way to the ultimate base. + // Unlike poly inheritance, reuse inheritance uses the table + // alias of the derived type. Note that bases can have object + // pointers of their own but their types have already been + // instantiated by step 3 below performed for the base object. + // + // 2. Object pointers. Note that while object pointers cannot have + // their own pointers, they can have reuse inheritance bases. + // + // 3. The query_columns class for the table itself. + // + if (multi_dynamic) + { + string alias ("access::object_traits_impl< " + type + ", id_" + + db.string () + " >"); + + // 1 + // + { + instance b (false, alias); + traversal::inherits i (*b); + inherits (c, i); + } + + // 2: Handled by query_columns_base (which is where we generate + // all the aliases for object pointers). + // + + // 3 + // + os << "template struct query_columns<" << endl + << " " << type << "," << endl + << " id_" << db << "," << endl + << " " << alias << " >;" + << endl; + } + } +} + +void query_columns_type:: +generate_impl (type& c) +{ + string guard; + + if (multi_dynamic) + { + guard = make_guard ("ODB_" + db.string () + "_QUERY_COLUMNS_DEF"); + + os << "#ifdef " << guard << endl + << endl; + } + + instance t (ptr_, c); + t->traverse (c); + + if (!guard.empty ()) + os << "#endif // " << guard << endl + << endl; +} + +// view_query_columns_type +// + +void view_query_columns_type:: +traverse (type& c) +{ + if (decl_) + generate_decl (c); + else + generate_def (c); +} + +void view_query_columns_type:: +generate_decl (type& c) +{ + string const& type (class_fq_name (c)); + view_objects& objs (c.get ("objects")); + + // Generate alias_traits specializations. + // + { + bool true_ (true); //@@ (im)perfect forwarding + instance at (c, true_); + + 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_decl (i->alias, o); + } + } + + os << "struct access::view_traits_impl< " << type << ", id_" << db << + " >::query_columns"; + + if (c.get ("object-count") > 1) + { + os << "{"; + + for (view_objects::const_iterator i (objs.begin ()); i < objs.end (); ++i) + { + if (i->kind != view_object::object) + continue; // Skip tables. + + bool alias (!i->alias.empty ()); + semantics::class_& o (*i->obj); + string const& oname (alias ? i->alias : class_name (o)); + string const& otype (class_fq_name (o)); + qname const& table (table_name (o)); + + os << "// " << oname << endl + << "//" << endl + << "typedef" << endl + << "odb::pointer_query_columns<" << endl + << " " << otype << "," << endl + << " id_" << db << "," << endl; + + if (alias && (polymorphic (o) || + table.qualified () || + i->alias != table.uname ())) + { + 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 << ", id_" << + db << " > >" << endl; + + os << oname << ";" + << endl; + } + + os << "};"; + } + else + { + // For a single object view we generate a shortcut without + // an intermediate typedef. + // + view_object const* vo (0); + for (view_objects::const_iterator i (objs.begin ()); + vo == 0 && i < objs.end (); + ++i) + { + if (i->kind == view_object::object) + vo = &*i; + } + + bool alias (!vo->alias.empty ()); + semantics::class_& o (*vo->obj); + string const& otype (class_fq_name (o)); + qname const& table (table_name (o)); + + os << ":" << endl + << " odb::pointer_query_columns<" << endl + << " " << otype << "," << endl + << " id_" << db << "," << endl; + + if (alias && (polymorphic (o) || + table.qualified () || + vo->alias != table.uname ())) + { + 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 << + ", id_" << db << " > >"; + + os << "{" + << "};"; + } +} + +void view_query_columns_type:: +generate_def (type& c) +{ + string const& type (class_fq_name (c)); + view_objects& objs (c.get ("objects")); + + string traits ("access::view_traits_impl< " + type + ", id_" + + db.string () + " >"); + + // Generate alias_traits specializations and instantiate corresponding + // [pointer_]query_columns. + // + { + 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); + + // The same code as in query_columns_base. + // + if (multi_dynamic) + { + string const& otype (class_fq_name (o)); + + // If the pointed-to class has no pointers of its own then + // pointer_query_columns just derives from query_columns and + // that's what we need to instantiate. + // + bool has_ptr (has_a (o, test_pointer | include_base)); + + string alias ("odb::alias_traits<\n" + " " + otype + ",\n" + " id_" + db.string () + ",\n" + " " + traits + "::" + i->alias + "_tag>"); + + // Instantiate base [pointer_]query_columns. + // + { + instance b (has_ptr, alias); + traversal::inherits i (*b); + inherits (o, i); + } + + os << "template struct " << (has_ptr ? "pointer_" : "") << + "query_columns<" << endl + << " " << otype << "," << endl + << " id_" << db << "," << endl + << " " << alias << " >;" + << endl; + } + } + } + } +} diff --git a/odb/common-query.hxx b/odb/common-query.hxx new file mode 100644 index 0000000..4fa9fe1 --- /dev/null +++ b/odb/common-query.hxx @@ -0,0 +1,239 @@ +// file : odb/common-query.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_COMMON_QUERY_HXX +#define ODB_COMMON_QUERY_HXX + +#include +#include + +// +// Query-related generators. +// + +// Generate query tags for pointers in this objects. +// +struct query_tags: object_columns_base, virtual context +{ + typedef query_tags base; + + query_tags (): nl_ (false) {} + + virtual void + traverse (semantics::class_&); + + 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& name); + +private: + bool nl_; +}; + +// 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 (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_decl (string const& tag, semantics::class_&); + + virtual void + generate_decl_body (); + + virtual void + generate_def (semantics::data_member&, semantics::class_&); + + virtual void + generate_def (string const& tag, semantics::class_&, string const& alias); + +protected: + bool decl_; + string scope_; +}; + +// Generate query columns in the query_columns_base class. +// +struct query_columns_base: object_columns_base, virtual context +{ + typedef query_columns_base base; + + query_columns_base (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_&); + +protected: + bool decl_; + string const_; // Const prefix or empty. + string scope_; +}; + +// Generate query columns in the query_columns or pointer_query_columns +// class. +// +struct query_columns: object_columns_base, virtual context +{ + typedef query_columns base; + + query_columns (bool ptr); + query_columns (bool ptr, semantics::class_&); + + virtual void + column_ctor (string const& type, string const& name, string const& base); + + virtual void + traverse_object (semantics::class_&); + + virtual void + traverse_composite (semantics::data_member*, semantics::class_&); + + virtual void + column_common (semantics::data_member&, + string const& type, + string const& column, + string const& suffix = "_type_"); + + virtual bool + traverse_column (semantics::data_member&, string const&, bool); + + virtual void + traverse_pointer (semantics::data_member&, semantics::class_&); + +protected: + bool ptr_; + bool decl_; + string const_; // Const prefix or empty. + bool in_ptr_; // True while we are "inside" an object pointer. + string fq_name_; + string scope_; +}; + +// Generate the list of base classes for the query_columns or +// pointer_query_columns class. +// +struct query_columns_bases: traversal::class_, virtual context +{ + typedef query_columns_bases base; + + query_columns_bases (bool ptr, bool first = true) + : ptr_ (ptr), first_ (first) {} + + virtual void + traverse (type&); + +private: + bool ptr_; + bool first_; +}; + +// Generate the base class aliases (typedefs). These can be used to +// resolve member ambiguities. +// +struct query_columns_base_aliases: traversal::class_, virtual context +{ + typedef query_columns_base_aliases base; + + query_columns_base_aliases (bool ptr): ptr_ (ptr) {} + + virtual void + traverse (type&); + +private: + bool ptr_; +}; + +// Generate explicit instantiations of base classes (reuse inheritance). +// +struct query_columns_base_insts: traversal::class_, virtual context +{ + typedef query_columns_base_insts base; + + query_columns_base_insts (bool ptr, string const& alias); + query_columns_base_insts (query_columns_base_insts const&); + + virtual void + traverse (type&); + +private: + bool ptr_; + string alias_; + traversal::inherits inherits_; +}; + +// Generate the query_columns_base/query_columns or pointer_query_columns +// classes for objects. +// +struct query_columns_type: traversal::class_, virtual context +{ + typedef query_columns_type base; + + // Depending on the ptr argument, generate query_columns or + // pointer_query_columns specialization. The latter is used + // for object pointers where we don't support nested pointers. + // + // If decl is false then generate definitions (only needed for + // query_columns so ptr should be false). + // + query_columns_type (bool ptr, bool decl): ptr_ (ptr), decl_ (decl) {} + + virtual void + traverse (type&); + + virtual void + generate_impl (type&); + +public: + bool ptr_; + bool decl_; +}; + +// Generate the query_columns class for views. +// +struct view_query_columns_type: traversal::class_, virtual context +{ + typedef view_query_columns_type base; + + view_query_columns_type (bool decl): decl_ (decl) {} + + virtual void + traverse (type&); + + void + generate_decl (type&); + + void + generate_def (type&); + +public: + bool decl_; +}; + +#endif // ODB_COMMON_QUERY_HXX diff --git a/odb/common.hxx b/odb/common.hxx index b351d3d..7ce59a5 100644 --- a/odb/common.hxx +++ b/odb/common.hxx @@ -11,6 +11,7 @@ #include #include +#include // Traverse object members recursively by going into bases and // composite members. @@ -357,6 +358,8 @@ private: struct object_columns_list: object_columns_base { + typedef object_columns_list base; + object_columns_list (bool ignore_inverse = true) : ignore_inverse_ (ignore_inverse) { @@ -426,98 +429,8 @@ private: bool included_; }; -// Generate query tags for object pointers. +// Other common parts. // -struct query_tags: object_columns_base, virtual context -{ - typedef query_tags base; - - query_tags (): nl_ (false) {} - - virtual void - traverse (semantics::class_& c) - { - if (object (c)) - { - object_columns_base::traverse (c); - } - else if (c.get ("object-count") != 0) // View. - { - view_objects& objs (c.get ("objects")); - - 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; - - generate (i->alias); - } - } - - if (nl_) - os << endl; - } - - 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; - - if (nl_) - os << endl; - - os << "struct " << public_name (*m) << "_tag" - << "{"; - - object_columns_base::traverse_composite (m, c); - - os << "};"; - - nl_ = false; - } - - 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;"; - nl_ = true; - } - -private: - bool nl_; -}; +#include #endif // ODB_COMMON_HXX diff --git a/odb/context.cxx b/odb/context.cxx index 657c283..066287b 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -452,6 +452,8 @@ context (ostream& os_, separate_schema ( ops.generate_schema () && ops.schema_format ()[db].count (schema_format::separate)), + multi_static (ops.multi_database () == multi_database::static_), + multi_dynamic (ops.multi_database () == multi_database::dynamic), top_object (data_->top_object_), cur_object (data_->cur_object_) { @@ -501,6 +503,8 @@ context () modifier_regex (current ().modifier_regex), embedded_schema (current ().embedded_schema), separate_schema (current ().separate_schema), + multi_static (current ().multi_static), + multi_dynamic (current ().multi_dynamic), top_object (current ().top_object), cur_object (current ().cur_object) { diff --git a/odb/context.hxx b/odb/context.hxx index 129e5ee..fc1b3bd 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -993,6 +993,9 @@ public: bool embedded_schema; bool separate_schema; + bool multi_static; + bool multi_dynamic; + // Outermost object or view currently being traversed. // semantics::class_*& top_object; diff --git a/odb/generator.cxx b/odb/generator.cxx index 4fa4cf2..279017e 100644 --- a/odb/generator.cxx +++ b/odb/generator.cxx @@ -513,8 +513,23 @@ generate (options const& ops, } } - cxx << "#include " << ctx->process_include_path (hxx_name) << endl - << endl; + // Include query columns implementations for explicit instantiations. + // + string impl_guard; + if (md == multi_database::dynamic) + { + impl_guard = ctx->make_guard ( + "ODB_" + db.string () + "_QUERY_COLUMNS_DEF"); + + cxx << "#define " << impl_guard << endl; + } + + cxx << "#include " << ctx->process_include_path (hxx_name) << endl; + + if (!impl_guard.empty ()) + cxx << "#undef " << impl_guard << endl; + + cxx << endl; { // We don't want to indent prologues/epilogues. diff --git a/odb/header.cxx b/odb/header.cxx index 66248d2..1f02463 100644 --- a/odb/header.cxx +++ b/odb/header.cxx @@ -10,8 +10,12 @@ using namespace std; namespace header { - struct class_: traversal::class_, virtual context + struct class1: traversal::class_, virtual context { + class1 () + : query_columns_type_ (false, true), + pointer_query_columns_type_ (true, true) {} + virtual void traverse (type& c) { @@ -30,12 +34,13 @@ namespace header void traverse_view (type&); - void - traverse_composite (type&); + private: + instance query_columns_type_; + instance pointer_query_columns_type_; }; } -void header::class_:: +void header::class1:: traverse_object (type& c) { using semantics::data_member; @@ -210,8 +215,7 @@ traverse_object (type& c) // Generate object pointer tags here if we are generating dynamic // multi-database support. // - if (options.multi_database () == multi_database::dynamic && - has_a (c, test_pointer | exclude_base)) + if (multi_dynamic && has_a (c, test_pointer | exclude_base)) { query_tags t; t.traverse (c); @@ -220,80 +224,114 @@ traverse_object (type& c) // The rest does not apply to reuse-abstract objects. // - if (reuse_abst) - { - os << "};"; - return; - } - - // Cache traits typedefs. - // - if (id == 0) - { - os << "typedef" << endl - << "no_id_pointer_cache_traits" << endl - << "pointer_cache_traits;" - << endl - << "typedef" << endl - << "no_id_reference_cache_traits" << endl - << "reference_cache_traits;" - << endl; - } - else + if (!reuse_abst) { - char const* p (session (c) ? "odb::" : "no_op_"); - - if (poly_derived) + // Cache traits typedefs. + // + if (id == 0) { os << "typedef" << endl - << p << "pointer_cache_traits<" << - "object_traits::pointer_type>" << endl + << "no_id_pointer_cache_traits" << endl << "pointer_cache_traits;" << endl << "typedef" << endl - << p << "reference_cache_traits" << endl + << "no_id_reference_cache_traits" << endl << "reference_cache_traits;" << endl; } else { - os << "typedef" << endl - << p << "pointer_cache_traits" << endl - << "pointer_cache_traits;" - << endl - << "typedef" << endl - << p << "reference_cache_traits" << endl - << "reference_cache_traits;" - << endl; + char const* p (session (c) ? "odb::" : "no_op_"); + + if (poly_derived) + { + os << "typedef" << endl + << p << "pointer_cache_traits<" << + "object_traits::pointer_type>" << endl + << "pointer_cache_traits;" + << endl + << "typedef" << endl + << p << "reference_cache_traits" << endl + << "reference_cache_traits;" + << endl; + } + else + { + os << "typedef" << endl + << p << "pointer_cache_traits" << endl + << "pointer_cache_traits;" + << endl + << "typedef" << endl + << p << "reference_cache_traits" << endl + << "reference_cache_traits;" + << endl; + } } - } - // callback () - // - os << "static void" << endl - << "callback (database&, object_type&, callback_event);" - << endl; + // callback () + // + os << "static void" << endl + << "callback (database&, object_type&, callback_event);" + << endl; - os << "static void" << endl - << "callback (database&, const object_type&, callback_event);" - << endl; + os << "static void" << endl + << "callback (database&, const object_type&, callback_event);" + << endl; + } os << "};"; // The rest only applies to dynamic milti-database support. // - if (options.multi_database () != multi_database::dynamic) + if (!multi_dynamic) + return; + + // pointer_query_columns & query_columns + // + if (options.generate_query ()) + { + // If we don't have object pointers, then also generate + // query_columns (in this case pointer_query_columns and + // query_columns are the same and the former inherits from + // the latter). Otherwise we have to postpone query_columns + // generation until the second pass to deal with forward- + // declared objects. + // + if (!has_a (c, test_pointer | include_base)) + query_columns_type_->traverse (c); + + pointer_query_columns_type_->traverse (c); + } + + // We don't need to generate object_traits_impl for reuse-abstract + // objects. + // + if (reuse_abst) return; // object_traits_impl // os << "template <>" << endl << "class access::object_traits_impl< " << type << ", " << - "id_default >:" << endl + "id_common >:" << endl << " public access::object_traits< " << type << " >" << "{" << "public:" << endl; + if (options.generate_query ()) + { + // base_traits is needed for query support. + // + if (poly_derived) + os << "typedef object_traits_impl base_traits;" + << endl; + + // query_base_type + // + os << "typedef odb::query_base query_base_type;" + << endl; + } + // function_table_type // os << "struct function_table_type" @@ -338,6 +376,28 @@ traverse_object (type& c) (poly ? ", bool, bool" : "") << ");"; } + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + os << "result (*query) (database&, const query_base_type&);" + << endl; + + os << "unsigned long long (*erase_query) (database&, " << + "const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "odb::details::shared_ptr " << + "(*prepare_query) (connection&, const char*, const query_base_type&);" + << endl; + + os << "odb::details::shared_ptr (*execute_query) (" + "prepared_query_impl&);" + << endl; + } + } + os << "};" // function_table_type << "static const function_table_type* function_table[database_count];" << endl; @@ -393,10 +453,35 @@ traverse_object (type& c) << endl; } + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + { + os << "static result" << endl + << "query (database&, const query_base_type&);" + << endl; + } + + os << "static unsigned long long" << endl + << "erase_query (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "static odb::details::shared_ptr" << endl + << "prepare_query (connection&, const char*, const query_base_type&);" + << endl; + + os << "static odb::details::shared_ptr" << endl + << "execute_query (prepared_query_impl&);" + << endl; + } + } + os << "};"; // object_traits_impl } -void header::class_:: +void header::class1:: traverse_view (type& c) { string const& type (class_fq_name (c)); @@ -428,7 +513,7 @@ traverse_view (type& c) // Generate associated object tags here if we are generating dynamic // multi-database support. // - if (options.multi_database () == multi_database::dynamic) + if (multi_dynamic) { query_tags t; t.traverse (c); @@ -441,6 +526,152 @@ traverse_view (type& c) << endl; os << "};"; + + // The rest only applies to dynamic milti-database support. + // + if (!multi_dynamic) + return; + + size_t obj_count (c.get ("object-count")); + + // view_traits_impl + // + os << "template <>" << endl + << "class access::view_traits_impl< " << type << ", id_common >:" << endl + << " public access::view_traits< " << type << " >" + << "{" + << "public:" << endl; + + // query_base_type and query_columns (definition generated by class2). + // + os << "typedef odb::query_base query_base_type;" + << "struct query_columns"; + + if (obj_count == 0) + os << "{" + << "};"; + else + os << ";" + << endl; + + // function_table_type + // + os << "struct function_table_type" + << "{"; + + if (!options.omit_unprepared ()) + os << "result (*query) (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "odb::details::shared_ptr " << + "(*prepare_query) (connection&, const char*, const query_base_type&);" + << endl; + + os << "odb::details::shared_ptr (*execute_query) (" + "prepared_query_impl&);" + << endl; + } + + os << "};" // function_table_type + << "static const function_table_type* function_table[database_count];" + << endl; + + // + // Forwarding functions. + // + + if (!options.omit_unprepared ()) + os << "static result" << endl + << "query (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "static odb::details::shared_ptr" << endl + << "prepare_query (connection&, const char*, const query_base_type&);" + << endl; + + os << "static odb::details::shared_ptr" << endl + << "execute_query (prepared_query_impl&);" + << endl; + } + + os << "};"; +} + +namespace header +{ + struct class2: traversal::class_, virtual context + { + class2 () + : query_columns_type_ (false, true), + view_query_columns_type_ (true) + { + } + + virtual void + traverse (type& c) + { + if (!options.at_once () && class_file (c) != unit.file ()) + return; + + if (object (c)) + traverse_object (c); + else if (view (c)) + traverse_view (c); + } + + void + traverse_object (type&); + + void + traverse_view (type&); + + private: + instance query_columns_type_; + instance view_query_columns_type_; + }; +} + +void header::class2:: +traverse_object (type& c) +{ + if (options.generate_query ()) + { + bool has_ptr (has_a (c, test_pointer | include_base)); + + if (has_ptr) + os << "// " << class_name (c) << endl + << "//" << endl; + + // query_columns + // + // If we don't have any pointers, then query_columns is generated + // in pass 1 (see the comment in class1 for details). + // + if (has_ptr) + query_columns_type_->traverse (c); + } + + // Move header comment out of if-block if adding any code here. +} + +void header::class2:: +traverse_view (type& c) +{ + // query_columns + // + if (c.get ("object-count") != 0) + { + os << "// " << class_name (c) << endl + << "//" << endl; + + view_query_columns_type_->traverse (c); + } + + // Move header comment out of if-block if adding any code here. } namespace header @@ -495,6 +726,9 @@ namespace header if (ctx.options.generate_query ()) { + if (ctx.multi_dynamic) + os << "#include " << endl; + if (ctx.options.generate_prepared ()) os << "#include " << endl; @@ -514,32 +748,60 @@ namespace header } os << endl - << "#include " << endl - << endl; + << "#include " << endl; + + if (ctx.options.generate_query ()) + os << "#include " << endl; + + os << endl; + + os << "namespace odb" + << "{"; // Generate common code. // - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (false); - traversal::namespace_ ns; - class_ c; + { + traversal::unit unit; + traversal::defines unit_defines; + typedefs unit_typedefs (false); + traversal::namespace_ ns; + class1 c; - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; + unit >> unit_defines >> ns; + unit_defines >> c; + unit >> unit_typedefs >> c; - traversal::defines ns_defines; - typedefs ns_typedefs (false); + traversal::defines ns_defines; + typedefs ns_typedefs (false); - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; + ns >> ns_defines >> ns; + ns_defines >> c; + ns >> ns_typedefs >> c; - os << "namespace odb" - << "{"; + unit.dispatch (ctx.unit); + } - unit.dispatch (ctx.unit); + if (ctx.multi_dynamic) + { + traversal::unit unit; + traversal::defines unit_defines; + typedefs unit_typedefs (false); + traversal::namespace_ ns; + class2 c; + + unit >> unit_defines >> ns; + unit_defines >> c; + unit >> unit_typedefs >> c; + + traversal::defines ns_defines; + typedefs ns_typedefs (false); + + ns >> ns_defines >> ns; + ns_defines >> c; + ns >> ns_typedefs >> c; + + unit.dispatch (ctx.unit); + } os << "}"; } diff --git a/odb/inline.cxx b/odb/inline.cxx index 5b2b16c..a286f3d 100644 --- a/odb/inline.cxx +++ b/odb/inline.cxx @@ -179,10 +179,10 @@ traverse_object (type& c) // The rest only applies to dynamic milti-database support. // - if (options.multi_database () != multi_database::dynamic) + if (!multi_dynamic) return; - traits = "access::object_traits_impl< " + type + ", id_default >"; + traits = "access::object_traits_impl< " + type + ", id_common >"; // // Forwarding functions. @@ -270,6 +270,49 @@ traverse_object (type& c) (poly ? ", true, true" : "") << ");" << "}"; } + + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + { + os << "inline" << endl + << "result< " << traits << "::object_type >" << endl + << traits << "::" << endl + << "query (database& db, const query_base_type& q)" + << "{" + << "return function_table[db.id ()]->query (db, q);" + << "}"; + } + + os << "inline" << endl + << "unsigned long long " << traits << "::" << endl + << "erase_query (database& db, const query_base_type& q)" + << "{" + << "return function_table[db.id ()]->erase_query (db, q);" + << "}"; + + if (options.generate_prepared ()) + { + os << "inline" << endl + << "odb::details::shared_ptr" << endl + << traits << "::" << endl + << "prepare_query (connection& c, const char* n, " << + "const query_base_type& q)" + << "{" + << "return function_table[c.database ().id ()]->prepare_query (" << + "c, n, q);" + << "}"; + + os << "inline" << endl + << "odb::details::shared_ptr" << endl + << traits << "::" << endl + << "execute_query (prepared_query_impl& pq)" + << "{" + << "return function_table[pq.conn.database ().id ()]->" << + "execute_query (pq);" + << "}"; + } + } } void inline_::class_:: @@ -295,6 +338,50 @@ traverse_view (type& c) << endl; callback_calls_.traverse (c, false); os << "}"; + + // The rest only applies to dynamic milti-database support. + // + if (!multi_dynamic) + return; + + traits = "access::view_traits_impl< " + type + ", id_common >"; + + // + // Forwarding functions. + // + + if (!options.omit_unprepared ()) + { + os << "inline" << endl + << "result< " << traits << "::view_type >" << endl + << traits << "::" << endl + << "query (database& db, const query_base_type& q)" + << "{" + << "return function_table[db.id ()]->query (db, q);" + << "}"; + } + + if (options.generate_prepared ()) + { + os << "inline" << endl + << "odb::details::shared_ptr" << endl + << traits << "::" << endl + << "prepare_query (connection& c, const char* n, " << + "const query_base_type& q)" + << "{" + << "return function_table[c.database ().id ()]->prepare_query (" << + "c, n, q);" + << "}"; + + os << "inline" << endl + << "odb::details::shared_ptr" << endl + << traits << "::" << endl + << "execute_query (prepared_query_impl& pq)" + << "{" + << "return function_table[pq.conn.database ().id ()]->" << + "execute_query (pq);" + << "}"; + } } namespace inline_ @@ -305,7 +392,7 @@ namespace inline_ context ctx; ostream& os (ctx.os); - if (ctx.options.multi_database () == multi_database::dynamic) + if (ctx.multi_dynamic) os << "#include " << endl << endl; diff --git a/odb/instance.cxx b/odb/instance.cxx new file mode 100644 index 0000000..0fc41a7 --- /dev/null +++ b/odb/instance.cxx @@ -0,0 +1,74 @@ +// file : odb/instance.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include +#include // abort +#include // abi::__cxa_demangle + +#include + +using namespace std; + +struct demangled_name +{ + demangled_name (): s (0), n (0) {} + ~demangled_name () {free (s);} + char* s; + size_t n; +}; + +static demangled_name name_; + +string entry_base:: +name (type_info const& ti) +{ + char*& s (name_.s); + + { + int r; + s = abi::__cxa_demangle (ti.name (), s, &name_.n, &r); + + if (r != 0) + abort (); // We are in static initialization, so this is fatal. + } + + string str (s), r; + + // Get the first component. It can be a database kind or name. + // + string::size_type p (str.find ("::")); + + if (p == string::npos) + abort (); // Derived type should be in a namespace. + + string n (str, 0, p); + + // See if it is one of the known kinds. + // + if (n == "relational") + { + r = n; + p = str.find ("::", 12); // 12 for "relational::" + n.assign (str, 12, p == string::npos ? p : p - 12); + } + + // See if it is one of the known databases. + // + database db; + istringstream is (n); + if (!(is >> db)) + { + if (r.empty ()) + abort (); // Has to have either kind or database. + } + else + { + if (!r.empty ()) + r += "::"; + + r += n; + } + + return r; +} diff --git a/odb/instance.hxx b/odb/instance.hxx new file mode 100644 index 0000000..76e72c3 --- /dev/null +++ b/odb/instance.hxx @@ -0,0 +1,279 @@ +// file : odb/instance.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_INSTANCE_HXX +#define ODB_INSTANCE_HXX + +#include +#include +#include // std::size_t +#include + +#include +#include + +#include +#include + +// +// Dynamic traversal instantiation support. +// + +template +struct factory +{ + static B* + create (B const& prototype) + { + std::string kind, name; + database db (context::current ().options.database ()[0]); + + switch (db) + { + case database::common: + { + name = "common"; + break; + } + case database::mssql: + case database::mysql: + case database::oracle: + case database::pgsql: + case database::sqlite: + { + kind = "relational"; + name = kind + "::" + db.string (); + break; + } + } + + if (map_ != 0) + { + typename map::const_iterator i; + + if (!name.empty ()) + i = map_->find (name); + + if (i == map_->end ()) + i = map_->find (kind); + + if (i != map_->end ()) + return i->second (prototype); + } + + return new B (prototype); + } + +private: + template + friend struct entry; + + static void + init () + { + if (factory::count_++ == 0) + factory::map_ = new typename factory::map; + } + + static void + term () + { + if (--factory::count_ == 0) + delete factory::map_; + } + + typedef B* (*create_func) (B const&); + typedef std::map map; + static map* map_; + static std::size_t count_; +}; + +template +typename factory::map* factory::map_; + +template +std::size_t factory::count_; + +struct entry_base +{ + static std::string + name (std::type_info const&); +}; + +template +struct entry: entry_base +{ + typedef typename D::base base; + + entry () + { + factory::init (); + (*factory::map_)[name (typeid (D))] = &create; + } + + ~entry () + { + factory::term (); + } + + static base* + create (base const& prototype) + { + return new D (prototype); + } +}; + +template +struct instance +{ + typedef typename B::base base_type; + typedef ::factory factory_type; + + ~instance () + { + delete x_; + } + + instance () + { + base_type prototype; + x_ = factory_type::create (prototype); + } + + template + instance (A1& a1) + { + base_type prototype (a1); + x_ = factory_type::create (prototype); + } + + template + instance (A1 const& a1) + { + base_type prototype (a1); + x_ = factory_type::create (prototype); + } + + template + instance (A1& a1, A2& a2) + { + base_type prototype (a1, a2); + x_ = factory_type::create (prototype); + } + + template + instance (A1 const& a1, A2 const& a2) + { + base_type prototype (a1, a2); + x_ = factory_type::create (prototype); + } + + template + instance (A1& a1, A2& a2, A3& a3) + { + base_type prototype (a1, a2, a3); + x_ = factory_type::create (prototype); + } + + template + instance (A1 const& a1, A2 const& a2, A3 const& a3) + { + base_type prototype (a1, a2, a3); + x_ = factory_type::create (prototype); + } + + template + instance (A1& a1, A2& a2, A3& a3, A4& a4) + { + base_type prototype (a1, a2, a3, a4); + x_ = factory_type::create (prototype); + } + + template + instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4) + { + base_type prototype (a1, a2, a3, a4); + x_ = factory_type::create (prototype); + } + + template + instance (A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) + { + base_type prototype (a1, a2, a3, a4, a5); + x_ = factory_type::create (prototype); + } + + template + instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4, + A5 const& a5) + { + base_type prototype (a1, a2, a3, a4, a5); + x_ = factory_type::create (prototype); + } + + instance (instance const& i) + { + // This is tricky: use the other instance as a prototype. + // + x_ = factory_type::create (*i.x_); + } + + base_type* + operator-> () const + { + return x_; + } + + base_type& + operator* () const + { + return *x_; + } + + base_type* + get () const + { + return x_; + } + +private: + instance& operator= (instance const&); + +private: + base_type* x_; +}; + +template +inline traversal::edge_base& +operator>> (instance& n, traversal::edge_base& e) +{ + n->edge_traverser (e); + return e; +} + +template +inline traversal::relational::edge_base& +operator>> (instance& n, traversal::relational::edge_base& e) +{ + n->edge_traverser (e); + return e; +} + +template +inline traversal::node_base& +operator>> (traversal::edge_base& e, instance& n) +{ + e.node_traverser (*n); + return *n; +} + +template +inline traversal::relational::node_base& +operator>> (traversal::relational::edge_base& e, instance& n) +{ + e.node_traverser (*n); + return *n; +} + +#endif // ODB_INSTANCE_HXX diff --git a/odb/makefile b/odb/makefile index 5d0650b..c127ce5 100644 --- a/odb/makefile +++ b/odb/makefile @@ -12,10 +12,12 @@ sql-token.cxx \ sql-lexer.cxx \ context.cxx \ common.cxx \ +common-query.cxx \ location.cxx \ diagnostics.cxx \ emitter.cxx \ lookup.cxx \ +instance.cxx \ include.cxx \ header.cxx \ inline.cxx \ @@ -31,6 +33,7 @@ pragma.cxx # cxx_ptun += \ relational/common.cxx \ +relational/common-query.cxx \ relational/context.cxx \ relational/processor.cxx \ relational/header.cxx \ diff --git a/odb/option-functions.cxx b/odb/option-functions.cxx index b0b2523..075e8ab 100644 --- a/odb/option-functions.cxx +++ b/odb/option-functions.cxx @@ -71,12 +71,9 @@ process_options (options& o) } else { - o.odb_file_suffix ().insert ( - make_pair (db, string ("-odb-") + db.string ())); - o.sql_file_suffix ().insert ( - make_pair (db, string ("-") + db.string ())); - o.schema_file_suffix ().insert ( - make_pair (db, string ("-schema-") + db.string ())); + o.odb_file_suffix ().insert (make_pair (db, "-odb-" + db.string ())); + o.sql_file_suffix ().insert (make_pair (db, "-" + db.string ())); + o.schema_file_suffix ().insert (make_pair (db, "-schema-" + db.string ())); } // Set default --default-database value. diff --git a/odb/option-types.cxx b/odb/option-types.cxx index 6fcd922..8efb061 100644 --- a/odb/option-types.cxx +++ b/odb/option-types.cxx @@ -2,7 +2,6 @@ // copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file -#include #include #include #include // std::lower_bound @@ -21,7 +20,7 @@ static const char* cxx_version_[] = "c++11" }; -const char* cxx_version:: +string cxx_version:: string () const { return cxx_version_[v_]; @@ -70,13 +69,13 @@ static const char* database_name_[] = "SQLite" }; -const char* database:: +string database:: string () const { return database_[v_]; } -const char* database:: +string database:: name () const { return database_name_[v_]; @@ -119,7 +118,7 @@ static const char* multi_database_[] = "disabled" }; -const char* multi_database:: +string multi_database:: string () const { return multi_database_[v_]; @@ -163,7 +162,7 @@ static const char* schema_format_[] = "sql" }; -const char* schema_format:: +string schema_format:: string () const { return schema_format_[v_]; diff --git a/odb/option-types.hxx b/odb/option-types.hxx index b65589c..09be4ee 100644 --- a/odb/option-types.hxx +++ b/odb/option-types.hxx @@ -7,8 +7,10 @@ #include #include +#include #include + #include using semantics::relational::qname; @@ -24,7 +26,7 @@ struct cxx_version cxx_version (value v = value (0)) : v_ (v) {} operator value () const {return v_;} - const char* + std::string string () const; private: @@ -53,12 +55,12 @@ struct database database (value v = value (0)) : v_ (v) {} operator value () const {return v_;} - const char* + std::string string () const; // Full name (e.g., PostgreSQL). // - const char* + std::string name () const; private: @@ -105,7 +107,7 @@ struct multi_database multi_database (value v = disabled) : v_ (v) {} operator value () const {return v_;} - const char* + std::string string () const; private: @@ -134,7 +136,7 @@ struct schema_format schema_format (value v = value (0)) : v_ (v) {} operator value () const {return v_;} - const char* + std::string string () const; private: diff --git a/odb/processor.cxx b/odb/processor.cxx index d5f8c19..c290cca 100644 --- a/odb/processor.cxx +++ b/odb/processor.cxx @@ -43,8 +43,7 @@ namespace // We don't need to do any further processing for common if we // are generating static multi-database code. // - if (options.database ()[0] == database::common && - options.multi_database () == multi_database::static_) + if (multi_static && options.database ()[0] == database::common) return; semantics::names* hint; diff --git a/odb/relational/common-query.cxx b/odb/relational/common-query.cxx new file mode 100644 index 0000000..e49132f --- /dev/null +++ b/odb/relational/common-query.cxx @@ -0,0 +1,167 @@ +// file : odb/relational/common-query.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include + +using namespace std; + +namespace relational +{ + // query_alias_traits + // + + void query_alias_traits:: + generate_decl_body () + { + os << "static const char table_name[];"; + } + + void query_alias_traits:: + generate_def (semantics::data_member& m, semantics::class_& c) + { + // 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); + } + + generate_def (public_name (m), c, alias); + } + + 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); + + 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) + os << strlit (quote_id (alias + "_" + table_name (c).uname ())); + else + os << strlit (quote_id (alias)); + + os << ";" + << endl; + } + + entry query_alias_traits_; + + + // query_columns_base + // + + entry query_columns_base_; + + // query_columns + // + + void query_columns:: + column_ctor (string const& type, string const& name, string const& base) + { + os << name << " ("; + + if (multi_dynamic) + os << "odb::query_column< " << type << " >& qc," << endl; + + os << "const char* t, const char* c, const char* conv)" << endl + << " : " << base << " (" << (multi_dynamic ? "qc, " : "") << + "t, c, conv)" + << "{" + << "}"; + } + + void query_columns:: + column_ctor_args_extra (semantics::data_member&) + { + } + + void query_columns:: + column_common (semantics::data_member& m, + string const& type, + string const& column, + string const& suffix) + { + string name (public_name (m)); + + if (decl_) + { + string type_id (database_type_id (m)); + + os << "// " << name << endl + << "//" << endl; + + os << "typedef" << endl + << db << "::query_column<" << endl + << " " << db << "::value_traits<" << endl + << " " << type << "," << endl + << " " << type_id << " >::query_type," << endl + << " " << type_id << " >" << endl + << name << suffix << ";" + << endl; + } + else + { + // Note that here we don't use suffix. + // + string tmpl (ptr_ ? "pointer_query_columns" : "query_columns"); + tmpl += "< " + fq_name_ + ", id_" + db.string () + ", A >" + scope_; + + os << "template " << endl + << "const typename " << tmpl << "::" << name << "_type_" << endl + << tmpl << "::" << endl + << name << " ("; + + // Pass common query column for registration. + // + if (multi_dynamic) + { + string tmpl (ptr_ ? "pointer_query_columns" : "query_columns"); + tmpl += "< " + fq_name_ + ", id_common, typename A::common_traits >" + + scope_; + + os << tmpl << "::" << name << "," << endl; + } + + os << "A::" << "table_name, " << strlit (quote_id (column)); + + string const& conv (convert_to_expr (column_type (), m)); + os << ", " << (conv.empty () ? "0" : strlit (conv)); + + column_ctor_args_extra (m); + + os << ");" + << endl; + } + } +} diff --git a/odb/relational/common-query.hxx b/odb/relational/common-query.hxx new file mode 100644 index 0000000..2e8fdd4 --- /dev/null +++ b/odb/relational/common-query.hxx @@ -0,0 +1,64 @@ +// file : odb/relational/common-query.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_RELATIONAL_COMMON_QUERY_HXX +#define ODB_RELATIONAL_COMMON_QUERY_HXX + +#include + +namespace relational +{ + // + // + struct query_alias_traits: ::query_alias_traits, virtual context + { + typedef query_alias_traits base_impl; + + query_alias_traits (base const& x): base (x) {} + + virtual void + generate_decl_body (); + + virtual void + generate_def (semantics::data_member&, semantics::class_&); + + virtual void + generate_def (string const& tag, semantics::class_&, string const& alias); + }; + + // + // + struct query_columns_base: ::query_columns_base, virtual context + { + typedef query_columns_base base_impl; + + query_columns_base (base const& x): base (x) {const_ = "const ";} + }; + + // + // + struct query_columns: ::query_columns, virtual context + { + typedef query_columns base_impl; + + query_columns (base const& x): base (x) {const_ = "const ";} + + virtual string + database_type_id (semantics::data_member&) = 0; + + virtual void + column_ctor (string const& type, string const& name, string const& base); + + virtual void + column_ctor_args_extra (semantics::data_member&); + + virtual void + column_common (semantics::data_member&, + string const& type, + string const& column, + string const& suffix); + }; +} + +#endif // ODB_RELATIONAL_COMMON_QUERY_HXX diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx index b8d2c60..2b0e87f 100644 --- a/odb/relational/common.cxx +++ b/odb/relational/common.cxx @@ -2,580 +2,17 @@ // copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file -#include -#include // std::size_ -#include // abort -#include -#include // abi::__cxa_demangle - #include using namespace std; namespace relational { - // query_alias_traits + // member_database_type_id // - - 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) - { - // We don't want to traverse bases. - // - names (c); - } - - void query_alias_traits:: - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - // Base type. - // - if (m == 0) - { - object_columns_base::traverse_composite (m, c); - return; - } - - string old_scope (scope_); - scope_ += "::" + public_name (*m) + "_tag"; - - object_columns_base::traverse_composite (m, c); - - scope_ = old_scope; - } - - void query_alias_traits:: - traverse_pointer (semantics::data_member& m, semantics::class_& c) + string member_database_type_id:: + database_type_id (semantics::data_member&) { - // Ignore polymorphic id references. - // - if (m.count ("polymorphic-ref")) - return; - - if (decl_) - generate_decl (public_name (m), c); - else - { - // 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); - } - - generate_def (public_name (m), c, alias); - } - } - - void query_alias_traits:: - generate_decl (string const& tag, semantics::class_& c) - { - 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_decl (tag, *poly_base); - - 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 << 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); - - 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) - os << strlit (quote_id (alias + "_" + table_name (c).uname ())); - else - os << strlit (quote_id (alias)); - - os << ";" - << endl; - } - - // query_columns_base - // - - query_columns_base:: - query_columns_base (semantics::class_& c, bool decl) - : decl_ (decl) - { - string const& n (class_fq_name (c)); - - if (!decl) - scope_ = "query_columns_base< " + n + ", id_" + db.string () + " >"; - - tag_scope_ = "access::object_traits_impl< " + n + ", id_" + - db.string () + " >"; - } - - void query_columns_base:: - traverse_object (semantics::class_& c) - { - // We don't want to traverse bases. - // - names (c); - } - - void query_columns_base:: - 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; - - string name (public_name (*m)); - - if (decl_) - { - os << "// " << name << endl - << "//" << endl - << "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; - } - } - - void query_columns_base:: - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references. - // - if (m.count ("polymorphic-ref")) - return; - - string name (public_name (m)); - bool inv (inverse (m, key_prefix_)); - - if (decl_) - { - os << "// " << name << endl - << "//" << endl; - - string const& fq_name (class_fq_name (c)); - - os << "typedef" << endl - << "odb::alias_traits<" << endl - << " " << fq_name << "," << endl - << " id_" << db << "," << endl - << " " << tag_scope_ << "::" << name << "_tag>" << endl - << name << "_alias_;" - << endl; - - if (inv) - { - os << "typedef" << endl - << "odb::query_pointer<" << endl - << " odb::pointer_query_columns<" << endl - << " " << fq_name << "," << endl - << " id_" << db << "," << endl - << " " << name << "_alias_ > >" << endl - << name << "_type_ ;" - << endl - << "static const " << name << "_type_ " << name << ";" - << endl; - } - } - else - { - if (inv) - os << "const " << scope_ << "::" << name << "_type_" << endl - << scope_ << "::" << name << ";" - << endl; - } - } - - // query_columns - // - - query_columns:: - query_columns (bool ptr) - : ptr_ (ptr), decl_ (true), in_ptr_ (false) - { - } - - query_columns:: - query_columns (bool ptr, semantics::class_& c) //@@ context::{cur,top}_object - : ptr_ (ptr), decl_ (false), in_ptr_ (false) - { - scope_ = ptr ? "pointer_query_columns" : "query_columns"; - scope_ += "< " + class_fq_name (c) + ", id_" + db.string () + ", A >"; - } - - void query_columns:: - traverse_object (semantics::class_& c) - { - // We don't want to traverse bases. - // - names (c); - } - - void query_columns:: - traverse_composite (semantics::data_member* m, semantics::class_& c) - { - // Base type. - // - if (m == 0) - { - object_columns_base::traverse_composite (m, c); - return; - } - - string name (public_name (*m)); - string suffix (in_ptr_ ? "_column_type_" : "_type_"); - - if (decl_) - { - os << "// " << name << endl - << "//" << endl - << "struct " << name << suffix; - - // Derive from the base in query_columns_base. It contains columns - // data for the pointer members. - // - if (!ptr_ && has_a (c, test_pointer)) - os << ": " << name << "_base_"; - - os << "{" - << name << suffix << " (){}"; // Need user-defined default c-tor - // for initialization of const. - - object_columns_base::traverse_composite (m, c); - - os << "};"; - - if (!in_ptr_) - os << "static const " << name << "_type_ " << name << ";" - << endl; - } - else - { - // Handle nested members first. - // - string old_scope (scope_); - scope_ += "::" + name + suffix; - - object_columns_base::traverse_composite (m, c); - - scope_ = old_scope; - - // Composite member. Note that here we don't use suffix. - // - os << "template " << endl - << "const typename " << scope_ << "::" << name << "_type_" << endl - << scope_ << "::" << name << ";" - << endl; - } - } - - void query_columns:: - column_ctor (string const& type, string const& base) - { - os << type << " (const char* t, const char* c, const char* conv)" << endl - << " : " << base << " (t, c, conv)" - << "{" - << "}"; - } - - void query_columns:: - column_common (semantics::data_member& m, - string const& type, - string const& column, - string const& suffix) - { - string name (public_name (m)); - - if (decl_) - { - string type_id (database_type_id (m)); - - os << "// " << name << endl - << "//" << endl; - - os << "typedef" << endl - << db << "::query_column<" << endl - << " " << db << "::value_traits<" << endl - << " " << type << "," << endl - << " " << type_id << " >::query_type," << endl - << " " << type_id << " >" << endl - << name << suffix << ";" - << endl; - } - else - { - // Note that here we don't use suffix. - // - os << "template " << endl - << "const typename " << scope_ << "::" << name << "_type_" << endl - << scope_ << "::" << endl - << name << " (A::" << "table_name, " << strlit (quote_id (column)); - - string const& conv (convert_to_expr (column_type (), m)); - os << ", " << (conv.empty () ? "0" : strlit (conv)); - - column_ctor_extra (m); - - os << ");" - << endl; - } - } - - bool query_columns:: - traverse_column (semantics::data_member& m, string const& column, bool) - { - semantics::names* hint; - semantics::type& t (utype (m, hint)); - - column_common (m, t.fq_name (hint), column); - - if (decl_) - { - string name (public_name (m)); - - os << "static const " << name << "_type_ " << name << ";" - << endl; - } - - return true; - } - - void query_columns:: - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Ignore polymorphic id references. - // - if (m.count ("polymorphic-ref")) - return; - - // If this is for the pointer_query_columns and the member is not - // inverse, then create the normal member corresponding to the id - // column. This will allow the user to check it for NULL or to - // compare ids. In case this is for query_columns, then for the - // inverse member everything has been generated in query_columns_base. - // - if (inverse (m, key_prefix_)) - return; - - string name (public_name (m)); - - semantics::data_member& id (*id_member (c)); - semantics::names* hint; - semantics::type& t (utype (id, hint)); - - if (composite_wrapper (t)) - { - // Composite id. - // - - // For pointer_query_columns generate normal composite mapping. - // - if (ptr_) - object_columns_base::traverse_pointer (m, c); - else - { - // If this is a non-inverse relationship, then make the column have - // a dual interface: that of an object pointer and of an id column. - // The latter allows the user to, for example, use the is_null() - // test in a natural way. For inverse relationships there is no - // column and so the column interface is not available. - // - in_ptr_ = true; - object_columns_base::traverse_pointer (m, c); - in_ptr_ = false; - - if (decl_) - { - os << "typedef" << endl - << "odb::query_pointer<" << endl - << " odb::pointer_query_columns<" << endl - << " " << class_fq_name (c) << "," << endl - << " id_" << db << "," << endl - << " " << name << "_alias_ > >" << endl - << name << "_pointer_type_;" - << endl; - - os << "struct " << name << "_type_: " << - name << "_pointer_type_, " << name << "_column_type_" - << "{" - << name << "_type_ (){}" // Need user-defined default c-tor - // for initialization of const. - << "};"; - - os << "static const " << name << "_type_ " << name << ";" - << endl; - } - } - } - else - { - // Simple id. - // - string type (t.fq_name (hint)); - string column ( - compose_name ( - column_prefix_, column_name (m, key_prefix_, default_name_))); - - // For pointer_query_columns generate normal column mapping. - // - if (ptr_) - column_common (m, type, column); - else - { - // If this is a non-inverse relationship, then make the column have - // a dual interface: that of an object pointer and of an id column. - // The latter allows the user to, for example, use the is_null() - // test in a natural way. For inverse relationships there is no - // column and so the column interface is not available. - // - column_common (m, type, column, "_column_type_"); - - if (decl_) - { - os << "typedef" << endl - << "odb::query_pointer<" << endl - << " odb::pointer_query_columns<" << endl - << " " << class_fq_name (c) << "," << endl - << " id_" << db << "," << endl - << " " << name << "_alias_ > >" << endl - << name << "_pointer_type_;" - << endl; - - os << "struct " << name << "_type_: " << - name << "_pointer_type_, " << name << "_column_type_" - << "{" - << name << "_type_ (){}"; // Need user-defined default c-tor - // for initialization of const. - - column_ctor (name + "_type_", name + "_column_type_"); - - os << "};"; - } - } - - if (decl_) - os << "static const " << name << "_type_ " << name << ";" - << endl; - } - } - - // - // Dynamic traversal support. - // - - struct demangled_name - { - demangled_name (): s (0), n (0) {} - ~demangled_name () {free (s);} - char* s; - size_t n; - }; - - static demangled_name name_; - - database entry_base:: - db (type_info const& ti) - { - char*& s (name_.s); - - int r; - s = abi::__cxa_demangle (ti.name (), s, &name_.n, &r); - - if (r != 0) - abort (); // We are in static initialization, so this is fatal. - - string str (s + 12); // 12 for "relational::" - istringstream is (string (str, 0, str.find (':'))); - - database d; - if (!(is >> d)) - abort (); - - return d; + assert (false); } } diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx index 1e7143f..a077d6f 100644 --- a/odb/relational/common.hxx +++ b/odb/relational/common.hxx @@ -5,11 +5,8 @@ #ifndef ODB_RELATIONAL_COMMON_HXX #define ODB_RELATIONAL_COMMON_HXX -#include #include -#include // std::size_t #include -#include #include #include @@ -215,350 +212,17 @@ namespace relational { } + // Has to be overriden. + // virtual string - database_type_id (semantics::data_member&) - { - assert (false); - } - }; - - // 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 (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_decl (string const& tag, semantics::class_&); - - virtual void - generate_def (string const& tag, semantics::class_&, string const& alias); - - protected: - bool decl_; - string scope_; - }; - - // - // - struct query_columns_base: object_columns_base, virtual context - { - typedef query_columns_base base; - - query_columns_base (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_&); - - protected: - bool decl_; - string scope_; - string tag_scope_; - }; - - // - // - struct query_columns: object_columns_base, virtual context - { - typedef query_columns base; - - query_columns (bool ptr); - query_columns (bool ptr, semantics::class_&); - - virtual string - database_type_id (semantics::data_member&) - { - assert (false); - } - - virtual void - column_ctor (string const& type, string const& base); - - virtual void - column_ctor_extra (semantics::data_member&) - { - } - - virtual void - traverse_object (semantics::class_&); - - virtual void - traverse_composite (semantics::data_member*, semantics::class_&); - - virtual void - column_common (semantics::data_member&, - string const& type, - string const& column, - string const& suffix = "_type_"); - - virtual bool - traverse_column (semantics::data_member&, string const&, bool); - - virtual void - traverse_pointer (semantics::data_member&, semantics::class_&); - - protected: - bool ptr_; - bool decl_; - - bool in_ptr_; // True if we are "inside" an object pointer. - - string scope_; - string table_; - string default_table_; - }; - - // - // Dynamic traversal support. - // - - template - struct factory - { - static B* - create (B const& prototype) - { - database db (context::current ().options.database ()[0]); - - if (map_ != 0) - { - typename map::const_iterator i (map_->find (db)); - - if (i != map_->end ()) - return i->second (prototype); - } - - return new B (prototype); - } - - private: - template - friend struct entry; - - static void - init () - { - if (factory::count_++ == 0) - factory::map_ = new typename factory::map; - } - - static void - term () - { - if (--factory::count_ == 0) - delete factory::map_; - } - - typedef B* (*create_func) (B const&); - typedef std::map map; - static map* map_; - static std::size_t count_; + database_type_id (semantics::data_member&); }; - - template - typename factory::map* factory::map_; - - template - std::size_t factory::count_; - - struct entry_base - { - static database - db (std::type_info const&); - }; - - template - struct entry: entry_base - { - typedef typename D::base base; - - entry () - { - factory::init (); - (*factory::map_)[db (typeid (D))] = &create; - } - - ~entry () - { - factory::term (); - } - - static base* - create (base const& prototype) - { - return new D (prototype); - } - }; - - template - struct instance - { - typedef relational::factory factory; - - ~instance () - { - delete x_; - } - - instance () - { - B prototype; - x_ = factory::create (prototype); - } - - template - instance (A1& a1) - { - B prototype (a1); - x_ = factory::create (prototype); - } - - template - instance (A1 const& a1) - { - B prototype (a1); - x_ = factory::create (prototype); - } - - template - instance (A1& a1, A2& a2) - { - B prototype (a1, a2); - x_ = factory::create (prototype); - } - - template - instance (A1 const& a1, A2 const& a2) - { - B prototype (a1, a2); - x_ = factory::create (prototype); - } - - template - instance (A1& a1, A2& a2, A3& a3) - { - B prototype (a1, a2, a3); - x_ = factory::create (prototype); - } - - template - instance (A1 const& a1, A2 const& a2, A3 const& a3) - { - B prototype (a1, a2, a3); - x_ = factory::create (prototype); - } - - template - instance (A1& a1, A2& a2, A3& a3, A4& a4) - { - B prototype (a1, a2, a3, a4); - x_ = factory::create (prototype); - } - - template - instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4) - { - B prototype (a1, a2, a3, a4); - x_ = factory::create (prototype); - } - - template - instance (A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) - { - B prototype (a1, a2, a3, a4, a5); - x_ = factory::create (prototype); - } - - template - instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4, - A5 const& a5) - { - B prototype (a1, a2, a3, a4, a5); - x_ = factory::create (prototype); - } - - instance (instance const& i) - { - // This is tricky: use the other instance as a prototype. - // - x_ = factory::create (*i.x_); - } - - B* - operator-> () const - { - return x_; - } - - B& - operator* () const - { - return *x_; - } - - B* - get () const - { - return x_; - } - - private: - instance& operator= (instance const&); - - private: - B* x_; - }; - - template - inline traversal::edge_base& - operator>> (instance& n, traversal::edge_base& e) - { - n->edge_traverser (e); - return e; - } - - template - inline traversal::relational::edge_base& - operator>> (instance& n, traversal::relational::edge_base& e) - { - n->edge_traverser (e); - return e; - } - - template - inline traversal::node_base& - operator>> (traversal::edge_base& e, instance& n) - { - e.node_traverser (*n); - return *n; - } - - template - inline traversal::relational::node_base& - operator>> (traversal::relational::edge_base& e, instance& n) - { - e.node_traverser (*n); - return *n; - } } #include +// Other common parts. +// +#include + #endif // ODB_RELATIONAL_COMMON_HXX diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx index 099dc33..543e1ac 100644 --- a/odb/relational/header.cxx +++ b/odb/relational/header.cxx @@ -60,6 +60,16 @@ traverse_object (type& c) object_public_extra_pre (c); + // For dynamic multi-database support also generate common traits + // alias (used in query aliasing). + // + if (options.generate_query () && multi_dynamic) + { + os << "typedef access::object_traits_impl< " << type << ", " << + "id_common > common_traits;" + << endl; + } + // Polymorphic root_traits, base_traits, and discriminator_image_type. // if (poly) @@ -155,8 +165,7 @@ traverse_object (type& c) // Generate object pointer tags here unless we are generating dynamic // multi-database support, in which case they generated in object_traits. // - if (options.multi_database () != multi_database::dynamic && - has_a (c, test_pointer | exclude_base)) + if (!multi_dynamic && has_a (c, test_pointer | exclude_base)) { query_tags t; // Not customizable. t.traverse (c); @@ -501,18 +510,34 @@ traverse_object (type& c) os << "static result" << endl << "query (database&, const query_base_type&);" << endl; + + if (multi_dynamic) + os << "static result" << endl + << "query (database&, const odb::query_base&);" + << endl; } os << "static unsigned long long" << endl << "erase_query (database&, const query_base_type&);" << endl; + if (multi_dynamic) + os << "static unsigned long long" << endl + << "erase_query (database&, const odb::query_base&);" + << endl; + if (options.generate_prepared ()) { os << "static odb::details::shared_ptr" << endl << "prepare_query (connection&, const char*, const query_base_type&);" << endl; + if (multi_dynamic) + os << "static odb::details::shared_ptr" << endl + << "prepare_query (connection&, const char*, " << + "const odb::query_base&);" + << endl; + os << "static odb::details::shared_ptr" << endl << "execute_query (prepared_query_impl&);" << endl; @@ -626,7 +651,7 @@ traverse_object (type& c) os << "};"; - // object_traits_impl< , id_default> + // object_traits_impl< , id_common> // // Note that it is not generated for reuse-abstract classes. // @@ -635,7 +660,7 @@ traverse_object (type& c) { os << "template <>" << endl << "class access::object_traits_impl< " << type << ", " << - "id_default >:" << endl + "id_common >:" << endl << " public access::object_traits_impl< " << type << ", " << "id_" << db << " >" << "{" @@ -663,6 +688,16 @@ traverse_view (type& c) view_public_extra_pre (c); + // For dynamic multi-database support also generate common traits + // alias (used in query aliasing). + // + if (multi_dynamic) + { + os << "typedef access::view_traits_impl< " << type << ", " << + "id_common > common_traits;" + << endl; + } + // image_type // image_type_->traverse (c); @@ -677,7 +712,7 @@ traverse_view (type& c) // Generate associated object tags here unless we are generating dynamic // multi-database support, in which case they generated in object_traits. // - if (options.multi_database () != multi_database::dynamic) + if (!multi_dynamic) { query_tags t; // Not customizable. t.traverse (c); @@ -744,16 +779,29 @@ traverse_view (type& c) // query () // if (!options.omit_unprepared ()) + { os << "static result" << endl << "query (database&, const query_base_type&);" << endl; + if (multi_dynamic) + os << "static result" << endl + << "query (database&, const odb::query_base&);" + << endl; + } + if (options.generate_prepared ()) { os << "static odb::details::shared_ptr" << endl << "prepare_query (connection&, const char*, const query_base_type&);" << endl; + if (multi_dynamic) + os << "static odb::details::shared_ptr" << endl + << "prepare_query (connection&, const char*, " << + "const odb::query_base&);" + << endl; + os << "static odb::details::shared_ptr" << endl << "execute_query (prepared_query_impl&);" << endl; @@ -763,14 +811,14 @@ traverse_view (type& c) os << "};"; - // view_traits_impl< , id_default> + // view_traits_impl< , id_common> // if (options.default_database_specified () && options.default_database () == db) { os << "template <>" << endl << "class access::view_traits_impl< " << type << ", " << - "id_default >:" << endl + "id_common >:" << endl << " public access::view_traits_impl< " << type << ", " << "id_" << db << " >" << "{" diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 1ca87c6..89ef664 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -141,216 +141,6 @@ namespace relational traversal::names names_member_; }; - // - // query_columns_type - // - - struct query_columns_bases: traversal::class_, virtual context - { - typedef query_columns_bases base; - - query_columns_bases (bool ptr, bool first = true) - : ptr_ (ptr), first_ (first) - { - } - - virtual void - traverse (type& c) - { - // Ignore transient bases. Not used for views. - // - if (!object (c)) - return; - - if (first_) - { - os << ":" << endl - << " "; - first_ = false; - } - else - { - os << "," << endl - << " "; - } - - os << (ptr_ ? "pointer_query_columns" : "query_columns") << "< " << - class_fq_name (c) << ", id_" << db << ", "; - - // If our base is polymorphic, then it has its own table/alias. - // - if (polymorphic (c)) - os << "typename A::base_traits"; - else - os << "A"; - - os << " >"; - } - - private: - bool ptr_; - bool first_; - }; - - struct query_columns_base_aliases: traversal::class_, virtual context - { - typedef query_columns_base_aliases base; - - query_columns_base_aliases (bool ptr) - : ptr_ (ptr) - { - } - - virtual void - traverse (type& c) - { - // Ignore transient bases. Not used for views. - // - if (!object (c)) - return; - - string const& name (class_name (c)); - - os << "// " << name << endl - << "//" << endl - << "typedef " << - (ptr_ ? "pointer_query_columns" : "query_columns") << "< " << - class_fq_name (c) << ", id_" << db << ", "; - - if (polymorphic (c)) - os << "typename A::base_traits"; - else - os << "A"; - - os << " > " << name << ";" - << endl; - } - - private: - bool ptr_; - }; - - struct query_columns_type: traversal::class_, virtual context - { - typedef query_columns_type base; - - // Depending on the ptr argument, generate query_columns or - // pointer_query_columns specialization. The latter is used - // for object pointers where we don't support nested pointers. - // - query_columns_type (bool ptr): ptr_ (ptr) {} - - virtual void - traverse (type& c) - { - string const& type (class_fq_name (c)); - - if (ptr_) - { - os << "template " << endl - << "struct pointer_query_columns< " << type << ", id_" << db << - ", A >"; - - // If we don't have pointers (in the whole hierarchy), then - // pointer_query_columns and query_columns are the same. - // - if (!has_a (c, test_pointer | include_base)) - { - os << ":" << endl - << " query_columns< " << type << ", id_" << db << ", A >" - << "{" - << "};"; - } - else - { - { - instance b (ptr_); - traversal::inherits i (*b); - inherits (c, i); - } - - os << "{"; - - { - instance b (ptr_); - traversal::inherits i (*b); - inherits (c, i); - } - - { - instance t (ptr_); - t->traverse (c); - } - - os << "};"; - - { - instance t (ptr_, c); - t->traverse (c); - } - } - } - else - { - bool has_ptr (has_a (c, test_pointer | exclude_base)); - - if (has_ptr) - { - // This class contains everything for inverse pointers and - // aliases for non-inverse ones. It doesn't depend on the - // table alias (A) template argument. - // - os << "template <>" << endl - << "struct query_columns_base< " << type << ", id_" << - db << " >" - << "{"; - - bool true_ (true); //@@ (im)perfect forwarding. - instance t (c, true_); - t->traverse (c); - - os << "};"; - } - - os << "template " << endl - << "struct query_columns< " << type << ", id_" << db << ", A >"; - - if (has_ptr) - os << ":" << endl - << " query_columns_base< " << type << ", id_" << db << " >"; - - { - instance b (ptr_, !has_ptr); - traversal::inherits i (*b); - inherits (c, i); - } - - os << "{"; - - { - instance b (ptr_); - traversal::inherits i (*b); - inherits (c, i); - } - - { - instance t (ptr_); - t->traverse (c); - } - - os << "};"; - - { - instance t (ptr_, c); - t->traverse (c); - } - } - } - - public: - bool ptr_; - }; - // Member-specific traits types for container members. // struct container_traits: object_members_base, virtual context @@ -957,8 +747,8 @@ namespace relational : id_image_member_ ("id_"), version_image_member_ ("version_"), discriminator_image_member_ ("discriminator_"), - query_columns_type_ (false), - pointer_query_columns_type_ (true) + query_columns_type_ (false, true), + pointer_query_columns_type_ (true, true) { } @@ -968,8 +758,8 @@ namespace relational id_image_member_ ("id_"), version_image_member_ ("version_"), discriminator_image_member_ ("discriminator_"), - query_columns_type_ (false), - pointer_query_columns_type_ (true) + query_columns_type_ (false, true), + pointer_query_columns_type_ (true, true) { } @@ -1032,12 +822,17 @@ namespace relational { typedef class2 base; - class2 (): query_columns_type_ (false) {} + class2 () + : query_columns_type_ (false, true), + view_query_columns_type_ (true) + { + } class2 (class_ const&) : root_context (), //@@ -Wextra context (), - query_columns_type_ (false) + query_columns_type_ (false, true), + view_query_columns_type_ (true) { } @@ -1072,13 +867,7 @@ namespace relational // in pass 1 (see the comment in class1 for details). // if (has_ptr) - { - bool true_ (true); //@@ (im)perfect forwarding - instance t (c, true_); - t->traverse (c); - query_columns_type_->traverse (c); - } } // Move header comment out of if-block if adding any code here. @@ -1087,134 +876,14 @@ namespace relational virtual void traverse_view (type& c) { - string const& type (class_fq_name (c)); - // query_columns // - size_t obj_count (c.get ("object-count")); - - if (obj_count != 0) + if (c.get ("object-count") != 0) { os << "// " << class_name (c) << endl << "//" << endl; - view_objects& objs (c.get ("objects")); - - // Generate alias_traits specializations. - // - { - bool true_ (true); //@@ (im)perfect forwarding - instance at (c, true_); - - 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_decl (i->alias, o); - } - } - - os << "struct access::view_traits_impl< " << type << ", id_" << - db << " >::query_columns"; - - if (obj_count > 1) - { - os << "{"; - - for (view_objects::const_iterator i (objs.begin ()); - i < objs.end (); - ++i) - { - if (i->kind != view_object::object) - continue; // Skip tables. - - bool alias (!i->alias.empty ()); - semantics::class_& o (*i->obj); - string const& oname (alias ? i->alias : class_name (o)); - string const& otype (class_fq_name (o)); - qname const& table (table_name (o)); - - os << "// " << oname << endl - << "//" << endl - << "typedef" << endl - << "odb::pointer_query_columns<" << endl - << " " << otype << "," << endl - << " id_" << db << "," << endl; - - if (alias && (polymorphic (o) || - table.qualified () || - i->alias != table.uname ())) - { - 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 << - ", id_" << db << " > >" << endl; - - os << oname << ";" - << endl; - } - - os << "};"; - } - else - { - // For a single object view we generate a shortcut without - // an intermediate typedef. - // - view_object const* vo (0); - for (view_objects::const_iterator i (objs.begin ()); - vo == 0 && i < objs.end (); - ++i) - { - if (i->kind == view_object::object) - vo = &*i; - } - - bool alias (!vo->alias.empty ()); - semantics::class_& o (*vo->obj); - string const& otype (class_fq_name (o)); - qname const& table (table_name (o)); - - os << ":" << endl - << " odb::pointer_query_columns<" << endl - << " " << otype << "," << endl - << " id_" << db << "," << endl; - - if (alias && (polymorphic (o) || - table.qualified () || - vo->alias != table.uname ())) - { - 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 << - ", id_" << db << " > >"; - - os << "{" - << "};"; - } + view_query_columns_type_->traverse (c); } // Move header comment out of if-block if adding any code here. @@ -1227,6 +896,7 @@ namespace relational private: instance query_columns_type_; + instance view_query_columns_type_; }; struct include: virtual context @@ -1236,12 +906,8 @@ namespace relational virtual void generate () { - os << "#include " << endl; - - if (options.generate_query ()) - os << "#include " << endl; - - os << endl; + os << "#include " << endl + << endl; os << "#include " << endl << "#include " << endl @@ -1249,8 +915,13 @@ namespace relational << "#include " << endl; if (options.generate_query ()) + { os << "#include " << endl; + if (multi_dynamic) + os << "#include " << endl; + } + os << endl; } }; diff --git a/odb/relational/mssql/common.cxx b/odb/relational/mssql/common.cxx index d802e54..a16063b 100644 --- a/odb/relational/mssql/common.cxx +++ b/odb/relational/mssql/common.cxx @@ -473,7 +473,7 @@ namespace relational struct query_columns: relational::query_columns, context { - query_columns (base const& x): base (x) {} + query_columns (base const& x): base_impl (x) {} virtual string database_type_id (semantics::data_member& m) @@ -482,20 +482,26 @@ namespace relational } virtual void - column_ctor (string const& type, string const& base) + column_ctor (string const& type, string const& name, string const& base) { - os << type << " (const char* t," << endl + os << name << " ("; + + if (multi_dynamic) + os << "odb::query_column< " << type << " >& qc," << endl; + + os << "const char* t," << endl << "const char* c," << endl << "const char* conv," << endl << "unsigned short p = 0," << endl << "unsigned short s = 0xFFFF)" << endl - << " : " << base << " (t, c, conv, p, s)" + << " : " << base << " (" << (multi_dynamic ? "qc, " : "") << + "t, c, conv, p, s)" << "{" << "}"; } virtual void - column_ctor_extra (semantics::data_member& m) + column_ctor_args_extra (semantics::data_member& m) { // For some types we need to pass precision and scale. // diff --git a/odb/relational/mysql/common.cxx b/odb/relational/mysql/common.cxx index 9d62b6b..bbf2971 100644 --- a/odb/relational/mysql/common.cxx +++ b/odb/relational/mysql/common.cxx @@ -373,7 +373,7 @@ namespace relational struct query_columns: relational::query_columns, context { - query_columns (base const& x): base (x) {} + query_columns (base const& x): base_impl (x) {} virtual string database_type_id (semantics::data_member& m) diff --git a/odb/relational/oracle/common.cxx b/odb/relational/oracle/common.cxx index 04bb0f8..b1f5398 100644 --- a/odb/relational/oracle/common.cxx +++ b/odb/relational/oracle/common.cxx @@ -405,23 +405,29 @@ namespace relational struct query_columns: relational::query_columns, context { - query_columns (base const& x): base (x) {} + query_columns (base const& x): base_impl (x) {} - virtual void - column_ctor (string const& type, string const& base) + void + column_ctor (string const& type, string const& name, string const& base) { - os << type << " (const char* t," << endl + os << name << " ("; + + if (multi_dynamic) + os << "odb::query_column< " << type << " >& qc," << endl; + + os << "const char* t," << endl << "const char* c," << endl << "const char* conv," << endl << "unsigned short p = 0xFFF," << endl << "short s = 0xFFF)" << endl - << " : " << base << " (t, c, conv, p, s)" + << " : " << base << " (" << (multi_dynamic ? "qc, " : "") << + "t, c, conv, p, s)" << "{" << "}"; } virtual void - column_ctor_extra (semantics::data_member& m) + column_ctor_args_extra (semantics::data_member& m) { // For some types we need to pass precision and scale. // diff --git a/odb/relational/pgsql/common.cxx b/odb/relational/pgsql/common.cxx index 811269e..5d415c6 100644 --- a/odb/relational/pgsql/common.cxx +++ b/odb/relational/pgsql/common.cxx @@ -322,7 +322,7 @@ namespace relational struct query_columns: relational::query_columns, context { - query_columns (base const& x): base (x) {} + query_columns (base const& x): base_impl (x) {} virtual string database_type_id (semantics::data_member& m) diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 21c0f57..74690d6 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -62,30 +62,10 @@ traverse_object (type& c) // Query (abstract and concrete). // + // query_columns + // 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) - { - bool false_ (false); //@@ (im)perfect forwarding. - instance t (c, false_); - t->traverse (c); - } - } + query_columns_type_->traverse (c); // // Containers (abstract and concrete). @@ -2649,6 +2629,16 @@ traverse_object (type& c) << endl << "return result (r);" << "}"; + + // query(odb::query_base) + // + if (multi_dynamic) + os << "result< " << traits << "::object_type >" << endl + << traits << "::" << endl + << "query (database& db, const odb::query_base& q)" + << "{" + << "return query (db, query_base_type (q));" + << "}"; } // erase_query @@ -2669,11 +2659,22 @@ traverse_object (type& c) << "return st.execute ();" << "}"; + // erase_query(odb::query_base) + // + if (multi_dynamic) + os << "unsigned long long " << traits << "::" << endl + << "erase_query (database& db, const odb::query_base& q)" + << "{" + << "return erase_query (db, query_base_type (q));" + << "}"; + // Prepared. Very similar to unprepared but has some annoying variations // that make it difficult to factor out something common. // if (options.generate_prepared ()) { + // prepare_query + // os << "odb::details::shared_ptr" << endl << traits << "::" << endl << "prepare_query (connection& c, const char* n, " << @@ -2732,6 +2733,19 @@ traverse_object (type& c) << "return r;" << "}"; + // prepare_query(odb::query_base) + // + if (multi_dynamic) + os << "odb::details::shared_ptr" << endl + << traits << "::" << endl + << "prepare_query (connection& c, const char* n, " << + "const odb::query_base& q)" + << "{" + << "return prepare_query (c, n, query_base_type (q));" + << "}"; + + // execute_query + // os << "odb::details::shared_ptr" << endl << traits << "::" << endl << "execute_query (prepared_query_impl& q)" @@ -2807,10 +2821,10 @@ traverse_object (type& c) // Generate function table registration for dynamic multi-database // support. // - if (options.multi_database () == multi_database::dynamic) + if (multi_dynamic) { string fn (flat_name (type)); - string dt ("access::object_traits_impl< " + type + ", id_default >"); + string dt ("access::object_traits_impl< " + type + ", id_common >"); os << "static const" << endl << dt << "::" << endl @@ -2854,9 +2868,28 @@ traverse_object (type& c) << "&" << traits << "::erase"; } + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + os << "," << endl + << "&" << traits << "::query"; + + os << "," << endl + << "&" << traits << "::erase_query"; + + if (options.generate_prepared ()) + { + os << "," << endl + << "&" << traits << "::prepare_query"; + + os << "," << endl + << "&" << traits << "::execute_query"; + } + } + os << "};"; - os << "static const function_table_entry< " << type << ", " << + os << "static const object_function_table_entry< " << type << ", " << "id_" << db << " >" << endl << "function_table_entry_" << fn << "_ (" << endl << "&function_table_" << fn << "_);" @@ -2877,38 +2910,10 @@ traverse_view (type& c) view_extra (c); + // query_columns + // 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); - } - } - } + view_query_columns_type_->traverse (c); // // Functions. @@ -3684,6 +3689,16 @@ traverse_view (type& c) << endl << "return result (r);" << "}"; + + // query(odb::query_base) + // + if (multi_dynamic) + os << "result< " << traits << "::view_type >" << endl + << traits << "::" << endl + << "query (database& db, const odb::query_base& q)" + << "{" + << "return query (db, query_base_type (q));" + << "}"; } // Prepared. Very similar to unprepared but has some annoying variations @@ -3691,6 +3706,8 @@ traverse_view (type& c) // if (options.generate_prepared ()) { + // prepare_query + // os << "odb::details::shared_ptr" << endl << traits << "::" << endl << "prepare_query (connection& c, const char* n, " << @@ -3737,6 +3754,19 @@ traverse_view (type& c) << "return r;" << "}"; + // prepare_query(odb::query_base) + // + if (multi_dynamic) + os << "odb::details::shared_ptr" << endl + << traits << "::" << endl + << "prepare_query (connection& c, const char* n, " << + "const odb::query_base& q)" + << "{" + << "return prepare_query (c, n, query_base_type (q));" + << "}"; + + // execute_query + // os << "odb::details::shared_ptr" << endl << traits << "::" << endl << "execute_query (prepared_query_impl& q)" @@ -3786,6 +3816,40 @@ traverse_view (type& c) << "pq.query, st, sts));" << "}"; } + + // Generate function table registration for dynamic multi-database + // support. + // + if (multi_dynamic) + { + string fn (flat_name (type)); + string dt ("access::view_traits_impl< " + type + ", id_common >"); + + os << "static const" << endl + << dt << "::" << endl + << "function_table_type function_table_" << fn << "_ =" + << "{"; + + if (!options.omit_unprepared ()) + os << "&" << traits << "::query"; + + if (options.generate_prepared ()) + { + if (!options.omit_unprepared ()) + os << "," << endl; + + os << "&" << traits << "::prepare_query" << "," << endl + << "&" << traits << "::execute_query"; + } + + os << "};"; + + os << "static const view_function_table_entry< " << type << ", " << + "id_" << db << " >" << endl + << "function_table_entry_" << fn << "_ (" << endl + << "&function_table_" << fn << "_);" + << endl; + } } namespace relational diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index a9c5bb1..ed5f0e3 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -1325,7 +1325,7 @@ namespace relational else { db_type_id = member_database_type_id_->database_type_id (mi.m); - traits = string (db.string ()) + "::value_traits<\n " + traits = db.string () + "::value_traits<\n " + type + ",\n " + db_type_id + " >"; } @@ -1643,7 +1643,7 @@ namespace relational else { db_type_id = member_database_type_id_->database_type_id (mi.m); - traits = string (db.string ()) + "::value_traits<\n " + traits = db.string () + "::value_traits<\n " + type + ",\n " + db_type_id + " >"; } @@ -3245,6 +3245,8 @@ namespace relational // struct persist_statement_params: object_columns_base, virtual context { + typedef persist_statement_params base; + persist_statement_params (string& params, query_parameters& qp) : params_ (params), qp_ (qp) { @@ -3292,7 +3294,9 @@ namespace relational typedef class_ base; class_ () - : grow_base_ (index_), + : query_columns_type_ (false, false), + view_query_columns_type_ (false), + grow_base_ (index_), grow_member_ (index_), grow_version_member_ (index_, "version_"), grow_discriminator_member_ (index_, "discriminator_"), @@ -3314,6 +3318,8 @@ namespace relational class_ (class_ const&) : root_context (), //@@ -Wextra context (), + query_columns_type_ (false, false), + view_query_columns_type_ (false), grow_base_ (index_), grow_member_ (index_), grow_version_member_ (index_, "version_"), @@ -3607,6 +3613,9 @@ namespace relational } private: + instance query_columns_type_; + instance view_query_columns_type_; + size_t index_; instance grow_base_; traversal::inherits grow_base_inherits_; @@ -3669,7 +3678,7 @@ namespace relational if (embedded_schema) os << "#include " << endl; - if (options.multi_database () == multi_database::dynamic) + if (multi_dynamic) os << "#include " << endl; os << endl; diff --git a/odb/relational/sqlite/common.cxx b/odb/relational/sqlite/common.cxx index 601b01d..ac1de1c 100644 --- a/odb/relational/sqlite/common.cxx +++ b/odb/relational/sqlite/common.cxx @@ -166,7 +166,7 @@ namespace relational struct query_columns: relational::query_columns, context { - query_columns (base const& x): base (x) {} + query_columns (base const& x): base_impl (x) {} virtual string database_type_id (semantics::data_member& m) diff --git a/odb/source.cxx b/odb/source.cxx index 94560ce..a26adc7 100644 --- a/odb/source.cxx +++ b/odb/source.cxx @@ -13,6 +13,12 @@ namespace source { struct class_: traversal::class_, virtual context { + class_ () + : query_columns_type_ (false, false), + view_query_columns_type_ (false) + { + } + virtual void traverse (type& c) { @@ -30,6 +36,10 @@ namespace source void traverse_view (type&); + + private: + instance query_columns_type_; + instance view_query_columns_type_; }; } @@ -40,19 +50,28 @@ traverse_object (type& c) bool abst (abstract (c)); bool reuse_abst (abst && !poly); - // The rest only applies to dynamic milti-database support and non- - // reuse-abstract objects. + // The rest only applies to dynamic milti-database support. // - if (reuse_abst || options.multi_database () != multi_database::dynamic) + if (!multi_dynamic) return; - string const& type (class_fq_name (c)); - string traits ("access::object_traits_impl< " + type + ", id_default >"); - os << "// " << class_name (c) << endl << "//" << endl << endl; + // query_columns + // + if (options.generate_query ()) + query_columns_type_->traverse (c); + + // The rest does not apply to reuse-abstract objects. + // + if (reuse_abst) + return; + + string const& type (class_fq_name (c)); + string traits ("access::object_traits_impl< " + type + ", id_common >"); + os << "const " << traits << "::" << endl << "function_table_type*" << endl << traits << "::" << endl @@ -61,8 +80,28 @@ traverse_object (type& c) } void source::class_:: -traverse_view (type&) +traverse_view (type& c) { + // The rest only applies to dynamic milti-database support. + // + if (!multi_dynamic) + return; + + os << "// " << class_name (c) << endl + << "//" << endl + << endl; + + if (c.get ("object-count") != 0) + view_query_columns_type_->traverse (c); + + string const& type (class_fq_name (c)); + string traits ("access::view_traits_impl< " + type + ", id_common >"); + + os << "const " << traits << "::" << endl + << "function_table_type*" << endl + << traits << "::" << endl + << "function_table[database_count];" + << endl; } namespace source -- cgit v1.1