aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-11-21 13:11:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-11-21 13:13:50 +0200
commit9ad0acf37561de9bf359a561faed53de17c2ca3b (patch)
tree4b38b866a4917992a6e22cde9f22539e08d4ed9e
parentd01c8e22abea35477f21488613f2474a2e4e8fc7 (diff)
Add dynamic multi-database query support
-rw-r--r--odb/common-query.cxx1112
-rw-r--r--odb/common-query.hxx239
-rw-r--r--odb/common.hxx97
-rw-r--r--odb/context.cxx4
-rw-r--r--odb/context.hxx3
-rw-r--r--odb/generator.cxx19
-rw-r--r--odb/header.cxx404
-rw-r--r--odb/inline.cxx93
-rw-r--r--odb/instance.cxx74
-rw-r--r--odb/instance.hxx279
-rw-r--r--odb/makefile3
-rw-r--r--odb/option-functions.cxx9
-rw-r--r--odb/option-types.cxx11
-rw-r--r--odb/option-types.hxx12
-rw-r--r--odb/processor.cxx3
-rw-r--r--odb/relational/common-query.cxx167
-rw-r--r--odb/relational/common-query.hxx64
-rw-r--r--odb/relational/common.cxx571
-rw-r--r--odb/relational/common.hxx350
-rw-r--r--odb/relational/header.cxx62
-rw-r--r--odb/relational/header.hxx371
-rw-r--r--odb/relational/mssql/common.cxx16
-rw-r--r--odb/relational/mysql/common.cxx2
-rw-r--r--odb/relational/oracle/common.cxx18
-rw-r--r--odb/relational/pgsql/common.cxx2
-rw-r--r--odb/relational/source.cxx178
-rw-r--r--odb/relational/source.hxx17
-rw-r--r--odb/relational/sqlite/common.cxx2
-rw-r--r--odb/source.cxx53
29 files changed, 2699 insertions, 1536 deletions
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 <odb/common-query.hxx>
+
+using namespace std;
+
+// query_tags
+//
+
+void query_tags::
+traverse (semantics::class_& c)
+{
+ if (object (c))
+ {
+ object_columns_base::traverse (c);
+ }
+ else if (c.get<size_t> ("object-count") != 0) // View.
+ {
+ view_objects& objs (c.get<view_objects> ("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<query_columns_base_insts> 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 <typename A>" << 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 <typename A>" << 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 <typename A>" << 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<query_columns_bases> b (ptr_);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ os << "{";
+
+ {
+ instance<query_columns_base_aliases> b (ptr_);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ {
+ instance<query_columns> 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<query_alias_traits> 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<query_columns_base> t (c, true_);
+ t->traverse (c);
+
+ os << "};";
+ }
+
+ os << "template <typename A>" << endl
+ << "struct query_columns< " << type << ", id_" << db << ", A >";
+
+ if (has_ptr)
+ os << ":" << endl
+ << " query_columns_base< " << type << ", id_" << db << " >";
+
+ {
+ instance<query_columns_bases> b (ptr_, !has_ptr);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ os << "{";
+
+ {
+ instance<query_columns_base_aliases> b (ptr_);
+ traversal::inherits i (*b);
+ inherits (c, i);
+ }
+
+ {
+ instance<query_columns> 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<query_alias_traits> t (c, false_);
+ t->traverse (c);
+ }
+
+ // query_columns_base
+ //
+ if (has_ptr)
+ {
+ bool false_ (false); //@@ (im)perfect forwarding.
+ instance<query_columns_base> 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<query_columns_base_insts> 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<query_columns> 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<view_objects> ("objects"));
+
+ // Generate alias_traits specializations.
+ //
+ {
+ bool true_ (true); //@@ (im)perfect forwarding
+ instance<query_alias_traits> 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<size_t> ("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<view_objects> ("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<query_alias_traits> 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<query_columns_base_insts> 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 <odb/common.hxx>
+#include <odb/context.hxx>
+
+//
+// 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 <cassert>
#include <odb/context.hxx>
+#include <odb/instance.hxx>
// 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<size_t> ("object-count") != 0) // View.
- {
- view_objects& objs (c.get<view_objects> ("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 <odb/common-query.hxx>
#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> query_columns_type_;
+ instance<query_columns_type> 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<pointer_type>" << endl
- << "pointer_cache_traits;"
- << endl
- << "typedef" << endl
- << "no_id_reference_cache_traits<object_type>" << 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<root_type>::pointer_type>" << endl
+ << "no_id_pointer_cache_traits<pointer_type>" << endl
<< "pointer_cache_traits;"
<< endl
<< "typedef" << endl
- << p << "reference_cache_traits<root_type>" << endl
+ << "no_id_reference_cache_traits<object_type>" << endl
<< "reference_cache_traits;"
<< endl;
}
else
{
- os << "typedef" << endl
- << p << "pointer_cache_traits<pointer_type>" << endl
- << "pointer_cache_traits;"
- << endl
- << "typedef" << endl
- << p << "reference_cache_traits<object_type>" << 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<root_type>::pointer_type>" << endl
+ << "pointer_cache_traits;"
+ << endl
+ << "typedef" << endl
+ << p << "reference_cache_traits<root_type>" << endl
+ << "reference_cache_traits;"
+ << endl;
+ }
+ else
+ {
+ os << "typedef" << endl
+ << p << "pointer_cache_traits<pointer_type>" << endl
+ << "pointer_cache_traits;"
+ << endl
+ << "typedef" << endl
+ << p << "reference_cache_traits<object_type>" << 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_type, id_common> 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<object_type> (*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<prepared_query_impl> " <<
+ "(*prepare_query) (connection&, const char*, const query_base_type&);"
+ << endl;
+
+ os << "odb::details::shared_ptr<result_impl> (*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<object_type>" << 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<prepared_query_impl>" << endl
+ << "prepare_query (connection&, const char*, const query_base_type&);"
+ << endl;
+
+ os << "static odb::details::shared_ptr<result_impl>" << 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<size_t> ("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<view_type> (*query) (database&, const query_base_type&);"
+ << endl;
+
+ if (options.generate_prepared ())
+ {
+ os << "odb::details::shared_ptr<prepared_query_impl> " <<
+ "(*prepare_query) (connection&, const char*, const query_base_type&);"
+ << endl;
+
+ os << "odb::details::shared_ptr<result_impl> (*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<view_type>" << endl
+ << "query (database&, const query_base_type&);"
+ << endl;
+
+ if (options.generate_prepared ())
+ {
+ os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
+ << "prepare_query (connection&, const char*, const query_base_type&);"
+ << endl;
+
+ os << "static odb::details::shared_ptr<result_impl>" << 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> query_columns_type_;
+ instance<view_query_columns_type> 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<size_t> ("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 <odb/query-dynamic.hxx>" << endl;
+
if (ctx.options.generate_prepared ())
os << "#include <odb/prepared-query.hxx>" << endl;
@@ -514,32 +748,60 @@ namespace header
}
os << endl
- << "#include <odb/details/unused.hxx>" << endl
- << endl;
+ << "#include <odb/details/unused.hxx>" << endl;
+
+ if (ctx.options.generate_query ())
+ os << "#include <odb/details/shared-ptr.hxx>" << 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<prepared_query_impl>" << 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<result_impl>" << 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<prepared_query_impl>" << 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<result_impl>" << 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 <odb/database.hxx>" << 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 <sstream>
+#include <cstdlib> // abort
+#include <cxxabi.h> // abi::__cxa_demangle
+
+#include <odb/instance.hxx>
+
+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 <map>
+#include <string>
+#include <cstddef> // std::size_t
+#include <typeinfo>
+
+#include <odb/option-types.hxx>
+#include <odb/context.hxx>
+
+#include <odb/traversal/elements.hxx>
+#include <odb/traversal/relational/elements.hxx>
+
+//
+// Dynamic traversal instantiation support.
+//
+
+template <typename B>
+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 <typename>
+ friend struct entry;
+
+ static void
+ init ()
+ {
+ if (factory<B>::count_++ == 0)
+ factory<B>::map_ = new typename factory<B>::map;
+ }
+
+ static void
+ term ()
+ {
+ if (--factory<B>::count_ == 0)
+ delete factory<B>::map_;
+ }
+
+ typedef B* (*create_func) (B const&);
+ typedef std::map<std::string, create_func> map;
+ static map* map_;
+ static std::size_t count_;
+};
+
+template <typename B>
+typename factory<B>::map* factory<B>::map_;
+
+template <typename B>
+std::size_t factory<B>::count_;
+
+struct entry_base
+{
+ static std::string
+ name (std::type_info const&);
+};
+
+template <typename D>
+struct entry: entry_base
+{
+ typedef typename D::base base;
+
+ entry ()
+ {
+ factory<base>::init ();
+ (*factory<base>::map_)[name (typeid (D))] = &create;
+ }
+
+ ~entry ()
+ {
+ factory<base>::term ();
+ }
+
+ static base*
+ create (base const& prototype)
+ {
+ return new D (prototype);
+ }
+};
+
+template <typename B>
+struct instance
+{
+ typedef typename B::base base_type;
+ typedef ::factory<base_type> factory_type;
+
+ ~instance ()
+ {
+ delete x_;
+ }
+
+ instance ()
+ {
+ base_type prototype;
+ x_ = factory_type::create (prototype);
+ }
+
+ template <typename A1>
+ instance (A1& a1)
+ {
+ base_type prototype (a1);
+ x_ = factory_type::create (prototype);
+ }
+
+ template <typename A1>
+ instance (A1 const& a1)
+ {
+ base_type prototype (a1);
+ x_ = factory_type::create (prototype);
+ }
+
+ template <typename A1, typename A2>
+ instance (A1& a1, A2& a2)
+ {
+ base_type prototype (a1, a2);
+ x_ = factory_type::create (prototype);
+ }
+
+ template <typename A1, typename A2>
+ instance (A1 const& a1, A2 const& a2)
+ {
+ base_type prototype (a1, a2);
+ x_ = factory_type::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3>
+ instance (A1& a1, A2& a2, A3& a3)
+ {
+ base_type prototype (a1, a2, a3);
+ x_ = factory_type::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3>
+ instance (A1 const& a1, A2 const& a2, A3 const& a3)
+ {
+ base_type prototype (a1, a2, a3);
+ x_ = factory_type::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4>
+ instance (A1& a1, A2& a2, A3& a3, A4& a4)
+ {
+ base_type prototype (a1, a2, a3, a4);
+ x_ = factory_type::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4>
+ 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 <typename A1, typename A2, typename A3, typename A4, typename A5>
+ 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 <typename A1, typename A2, typename A3, typename A4, typename A5>
+ 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 <typename T>
+inline traversal::edge_base&
+operator>> (instance<T>& n, traversal::edge_base& e)
+{
+ n->edge_traverser (e);
+ return e;
+}
+
+template <typename T>
+inline traversal::relational::edge_base&
+operator>> (instance<T>& n, traversal::relational::edge_base& e)
+{
+ n->edge_traverser (e);
+ return e;
+}
+
+template <typename T>
+inline traversal::node_base&
+operator>> (traversal::edge_base& e, instance<T>& n)
+{
+ e.node_traverser (*n);
+ return *n;
+}
+
+template <typename T>
+inline traversal::relational::node_base&
+operator>> (traversal::relational::edge_base& e, instance<T>& 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 <string>
#include <istream>
#include <ostream>
#include <algorithm> // 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 <map>
#include <iosfwd>
+#include <string>
#include <cassert>
+
#include <odb/semantics/relational/name.hxx>
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 <odb/relational/common-query.hxx>
+
+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_alias_traits_;
+
+
+ // query_columns_base
+ //
+
+ entry<query_columns_base> 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 <typename A>" << 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 <odb/relational/common.hxx>
+
+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 <string>
-#include <cstddef> // std::size_
-#include <cstdlib> // abort
-#include <sstream>
-#include <cxxabi.h> // abi::__cxa_demangle
-
#include <odb/relational/common.hxx>
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 <typename A>" << 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 <typename A>" << 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 <map>
#include <set>
-#include <cstddef> // std::size_t
#include <cassert>
-#include <typeinfo>
#include <odb/common.hxx>
#include <odb/relational/context.hxx>
@@ -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 <typename B>
- 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 <typename>
- friend struct entry;
-
- static void
- init ()
- {
- if (factory<B>::count_++ == 0)
- factory<B>::map_ = new typename factory<B>::map;
- }
-
- static void
- term ()
- {
- if (--factory<B>::count_ == 0)
- delete factory<B>::map_;
- }
-
- typedef B* (*create_func) (B const&);
- typedef std::map<database, create_func> map;
- static map* map_;
- static std::size_t count_;
+ database_type_id (semantics::data_member&);
};
-
- template <typename B>
- typename factory<B>::map* factory<B>::map_;
-
- template <typename B>
- std::size_t factory<B>::count_;
-
- struct entry_base
- {
- static database
- db (std::type_info const&);
- };
-
- template <typename D>
- struct entry: entry_base
- {
- typedef typename D::base base;
-
- entry ()
- {
- factory<base>::init ();
- (*factory<base>::map_)[db (typeid (D))] = &create;
- }
-
- ~entry ()
- {
- factory<base>::term ();
- }
-
- static base*
- create (base const& prototype)
- {
- return new D (prototype);
- }
- };
-
- template <typename B>
- struct instance
- {
- typedef relational::factory<B> factory;
-
- ~instance ()
- {
- delete x_;
- }
-
- instance ()
- {
- B prototype;
- x_ = factory::create (prototype);
- }
-
- template <typename A1>
- instance (A1& a1)
- {
- B prototype (a1);
- x_ = factory::create (prototype);
- }
-
- template <typename A1>
- instance (A1 const& a1)
- {
- B prototype (a1);
- x_ = factory::create (prototype);
- }
-
- template <typename A1, typename A2>
- instance (A1& a1, A2& a2)
- {
- B prototype (a1, a2);
- x_ = factory::create (prototype);
- }
-
- template <typename A1, typename A2>
- instance (A1 const& a1, A2 const& a2)
- {
- B prototype (a1, a2);
- x_ = factory::create (prototype);
- }
-
- template <typename A1, typename A2, typename A3>
- instance (A1& a1, A2& a2, A3& a3)
- {
- B prototype (a1, a2, a3);
- x_ = factory::create (prototype);
- }
-
- template <typename A1, typename A2, typename A3>
- instance (A1 const& a1, A2 const& a2, A3 const& a3)
- {
- B prototype (a1, a2, a3);
- x_ = factory::create (prototype);
- }
-
- template <typename A1, typename A2, typename A3, typename A4>
- instance (A1& a1, A2& a2, A3& a3, A4& a4)
- {
- B prototype (a1, a2, a3, a4);
- x_ = factory::create (prototype);
- }
-
- template <typename A1, typename A2, typename A3, typename A4>
- instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4)
- {
- B prototype (a1, a2, a3, a4);
- x_ = factory::create (prototype);
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5>
- instance (A1& a1, A2& a2, A3& a3, A4& a4, A5& a5)
- {
- B prototype (a1, a2, a3, a4, a5);
- x_ = factory::create (prototype);
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5>
- 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 <typename T>
- inline traversal::edge_base&
- operator>> (instance<T>& n, traversal::edge_base& e)
- {
- n->edge_traverser (e);
- return e;
- }
-
- template <typename T>
- inline traversal::relational::edge_base&
- operator>> (instance<T>& n, traversal::relational::edge_base& e)
- {
- n->edge_traverser (e);
- return e;
- }
-
- template <typename T>
- inline traversal::node_base&
- operator>> (traversal::edge_base& e, instance<T>& n)
- {
- e.node_traverser (*n);
- return *n;
- }
-
- template <typename T>
- inline traversal::relational::node_base&
- operator>> (traversal::relational::edge_base& e, instance<T>& n)
- {
- e.node_traverser (*n);
- return *n;
- }
}
#include <odb/relational/common.txx>
+// Other common parts.
+//
+#include <odb/relational/common-query.hxx>
+
#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<object_type>" << endl
<< "query (database&, const query_base_type&);"
<< endl;
+
+ if (multi_dynamic)
+ os << "static result<object_type>" << 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<prepared_query_impl>" << endl
<< "prepare_query (connection&, const char*, const query_base_type&);"
<< endl;
+ if (multi_dynamic)
+ os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
+ << "prepare_query (connection&, const char*, " <<
+ "const odb::query_base&);"
+ << endl;
+
os << "static odb::details::shared_ptr<result_impl>" << 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<view_type>" << endl
<< "query (database&, const query_base_type&);"
<< endl;
+ if (multi_dynamic)
+ os << "static result<view_type>" << endl
+ << "query (database&, const odb::query_base&);"
+ << endl;
+ }
+
if (options.generate_prepared ())
{
os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
<< "prepare_query (connection&, const char*, const query_base_type&);"
<< endl;
+ if (multi_dynamic)
+ os << "static odb::details::shared_ptr<prepared_query_impl>" << endl
+ << "prepare_query (connection&, const char*, " <<
+ "const odb::query_base&);"
+ << endl;
+
os << "static odb::details::shared_ptr<result_impl>" << 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 <typename A>" << 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<query_columns_bases> b (ptr_);
- traversal::inherits i (*b);
- inherits (c, i);
- }
-
- os << "{";
-
- {
- instance<query_columns_base_aliases> b (ptr_);
- traversal::inherits i (*b);
- inherits (c, i);
- }
-
- {
- instance<query_columns> t (ptr_);
- t->traverse (c);
- }
-
- os << "};";
-
- {
- instance<query_columns> 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<query_columns_base> t (c, true_);
- t->traverse (c);
-
- os << "};";
- }
-
- os << "template <typename A>" << endl
- << "struct query_columns< " << type << ", id_" << db << ", A >";
-
- if (has_ptr)
- os << ":" << endl
- << " query_columns_base< " << type << ", id_" << db << " >";
-
- {
- instance<query_columns_bases> b (ptr_, !has_ptr);
- traversal::inherits i (*b);
- inherits (c, i);
- }
-
- os << "{";
-
- {
- instance<query_columns_base_aliases> b (ptr_);
- traversal::inherits i (*b);
- inherits (c, i);
- }
-
- {
- instance<query_columns> t (ptr_);
- t->traverse (c);
- }
-
- os << "};";
-
- {
- instance<query_columns> 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<query_alias_traits> 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<size_t> ("object-count"));
-
- if (obj_count != 0)
+ if (c.get<size_t> ("object-count") != 0)
{
os << "// " << class_name (c) << endl
<< "//" << endl;
- view_objects& objs (c.get<view_objects> ("objects"));
-
- // Generate alias_traits specializations.
- //
- {
- bool true_ (true); //@@ (im)perfect forwarding
- instance<query_alias_traits> 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> query_columns_type_;
+ instance<view_query_columns_type> view_query_columns_type_;
};
struct include: virtual context
@@ -1236,12 +906,8 @@ namespace relational
virtual void
generate ()
{
- os << "#include <odb/details/buffer.hxx>" << endl;
-
- if (options.generate_query ())
- os << "#include <odb/details/shared-ptr.hxx>" << endl;
-
- os << endl;
+ os << "#include <odb/details/buffer.hxx>" << endl
+ << endl;
os << "#include <odb/" << db << "/version.hxx>" << endl
<< "#include <odb/" << db << "/forward.hxx>" << endl
@@ -1249,8 +915,13 @@ namespace relational
<< "#include <odb/" << db << "/" << db << "-types.hxx>" << endl;
if (options.generate_query ())
+ {
os << "#include <odb/" << db << "/query.hxx>" << endl;
+ if (multi_dynamic)
+ os << "#include <odb/" << db << "/query-dynamic.hxx>" << 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<query_alias_traits> t (c, false_);
- t->traverse (c);
- }
-
- // query_columns_base
- //
- if (has_ptr)
- {
- bool false_ (false); //@@ (im)perfect forwarding.
- instance<query_columns_base> 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<object_type> (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<prepared_query_impl>" << 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<prepared_query_impl>" << 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<result_impl>" << 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<size_t> ("object-count") != 0)
- {
- view_objects& objs (c.get<view_objects> ("objects"));
-
- // Generate alias_traits specializations.
- //
- {
- bool false_ (false); //@@ (im)perfect forwarding
- instance<query_alias_traits> 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<view_type> (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<prepared_query_impl>" << 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<prepared_query_impl>" << 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<result_impl>" << 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> query_columns_type_;
+ instance<view_query_columns_type> view_query_columns_type_;
+
size_t index_;
instance<grow_base> grow_base_;
traversal::inherits grow_base_inherits_;
@@ -3669,7 +3678,7 @@ namespace relational
if (embedded_schema)
os << "#include <odb/schema-catalog-impl.hxx>" << endl;
- if (options.multi_database () == multi_database::dynamic)
+ if (multi_dynamic)
os << "#include <odb/function-table.hxx>" << 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> query_columns_type_;
+ instance<view_query_columns_type> 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<size_t> ("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