From e56ba020233ad7cb4762df300a6774db9195d817 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 9 Sep 2011 12:18:39 +0200 Subject: New templated query_columns architecture We also now use the correct separate "role"-base join approach instead of having a single merged join for each table. --- odb/relational/common.cxx | 253 ++++++++++++++++++------------- odb/relational/common.hxx | 27 +++- odb/relational/header.cxx | 47 ++++-- odb/relational/header.hxx | 321 +++++++++++++++++++++++++++++++++------- odb/relational/pgsql/header.cxx | 26 ++-- odb/relational/pgsql/source.cxx | 32 ++-- odb/relational/source.hxx | 181 ++++++++-------------- 7 files changed, 567 insertions(+), 320 deletions(-) diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx index ae2e1f4..2cb525e 100644 --- a/odb/relational/common.cxx +++ b/odb/relational/common.cxx @@ -15,32 +15,123 @@ using namespace std; namespace relational { + // query_columns_base + // + + query_columns_base:: + query_columns_base () + : decl_ (true) + { + } + + query_columns_base:: + query_columns_base (semantics::class_& c) //@@ context::{cur,top}_object + : decl_ (false) + { + scope_ = "query_columns_base< " + c.fq_name () + " >"; + } + + 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_" + << "{"; + + object_columns_base::traverse_composite (m, c); + + os << "};"; + } + else + { + string old_scope (scope_); + scope_ += "::" + name + "_base_"; + + object_columns_base::traverse_composite (m, c); + + scope_ = old_scope; + } + } + + bool query_columns_base:: + traverse_column (semantics::data_member& m, string const& column, bool) + { + semantics::class_* c (object_pointer (m.type ())); + + if (c == 0) + return false; + + string name (public_name (m)); + + if (decl_) + os << "// " << name << endl + << "//" << endl + << "static const char " << name << "_alias_[];" + << endl + << "typedef" << endl + << "odb::pointer_query_columns< " << c->fq_name () << ", " << + name << "_alias_ >" << endl + << name << ";" + << endl; + else + // For now use column name. This will become problematic when we + // add support for composite ids. + // + os << "const char " << scope_ << "::" << name << "_alias_[] =" << endl + << strlit (column) << ";" + << endl; + + return true; + } + // query_columns // query_columns:: - query_columns () - : ptr_ (true), decl_ (true) + query_columns (bool ptr) + : ptr_ (ptr), decl_ (true) { } query_columns:: - query_columns (semantics::class_& c) //@@ context::{cur,top}_object - : ptr_ (true), decl_ (false) + query_columns (bool ptr, semantics::class_& c) //@@ context::{cur,top}_object + : ptr_ (ptr), decl_ (false) { - scope_ = "access::object_traits< " + c.fq_name () + " >::query_columns"; - table_ = default_table_ = table_qname (c); + scope_ = ptr ? "pointer_query_columns" : "query_columns"; + scope_ += "< " + c.fq_name () + ", table >"; } void query_columns:: traverse_object (semantics::class_& c) { - // We only want members for objects unless we are traversing a - // pointer, in which case we need the whole thing. + // We don't want to traverse bases. // - if (!ptr_) - inherits (c); - names (c); } @@ -61,8 +152,15 @@ namespace relational { os << "// " << name << endl << "//" << endl - << "struct " << name - << "{"; + << "struct " << name; + + // Derive from the base in query_columns_base. It contains columns + // for the pointer members. + // + if (!ptr_ && has_a (c, test_pointer)) + os << ": " << name << "_base_"; + + os << "{"; object_columns_base::traverse_composite (m, c); @@ -80,104 +178,55 @@ namespace relational } bool query_columns:: - traverse_column (semantics::data_member& m, string const& col_name, bool) + traverse_column (semantics::data_member& m, string const& column, bool) { - string name (public_name (m)); + string mtype; if (semantics::class_* c = object_pointer (m.type ())) { - // We cannot just typedef the query_type from the referenced - // object for two reasons: (1) it may not be defined yet and - // (2) it will contain columns for its own pointers which - // won't work (for now we only support one level of indirection - // in queries). So we will have to duplicate the columns (sans - // the pointers). - // - // There are a number of problems with this approach: Regarding (1), - // the class have to be defined during ODB compilation in which - // case the ODB compiler will hunt down the #include statement - // and add it to the generated code. Regarding (2), things get - // complicated really quickly once we bring inheritance into - // the picture (name conflicts, etc). Plus, it is nice to reuse - // things. So the long-term solution is probably to make it a - // template with the table name as an argument. + // 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 the + // corresponding member is defined in query_columns_base. // + if (!ptr_ || inverse (m)) + return false; - if (ptr_) - { - ptr_ = false; - - if (decl_) - { - os << "// " << name << endl - << "//" << endl - << "struct " << name - << "{"; - - traverse (*c); - - os << "};"; - } - else - { - string old_scope (scope_), old_table (table_); - scope_ += "::" + name; - table_ = table_qname (*c); - traverse (*c); - table_ = old_table; - scope_ = old_scope; - } - - ptr_ = true; - } + semantics::data_member& id (*id_member (*c)); + mtype = id.type ().fq_name (id.belongs ().hint ()); + } + else + mtype = m.type ().fq_name (m.belongs ().hint ()); + + string name (public_name (m)); + string db_type_id (database_type_id (m)); + + string type ( + string (db.string ()) + "::value_traits< " + + mtype + ", " + + db_type_id + + " >::query_type"); + + if (decl_) + { + os << "// " << name << endl + << "//" << endl + << "static const " << db << "::query_column<" << endl + << " " << type << "," << endl + << " " << db_type_id << " >" << endl + << name << ";" + << endl; } else { - string db_type_id (database_type_id (m)); - - string type ( - string (db.string ()) + "::value_traits< " - + m.type ().fq_name (m.belongs ().hint ()) + ", " - + db_type_id - + " >::query_type"); - - if (decl_) - { - os << "// " << name << endl - << "//" << endl - << "static const " << db << "::query_column<" << endl - << " " << type << "," << endl - << " " << db_type_id << " >" << endl - << name << ";" - << endl; - } - else - { - // Leave the default table name unless we are generating members - // for a referenced object. - // - string column; - - if (!ptr_) - { - // If this is a self-reference, use the special '_' alias. - // - if (table_ != default_table_) - column = table_; - else - column = "_"; - } - - column += '.'; - column += quote_id (col_name); - - os << "const " << db << "::query_column<" << endl - << " " << type << "," << endl - << " " << db_type_id << " >" << endl - << scope_ << "::" << name << " (" << endl - << strlit (column) << ");" - << endl; - } + os << "template " << endl + << "const " << db << "::query_column<" << endl + << " " << type << "," << endl + << " " << db_type_id << " >" << endl + << scope_ << "::" << name << " (" << endl + << "table, " << strlit (column) << ");" + << endl; } return true; diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx index 8fc88e3..92edba6 100644 --- a/odb/relational/common.hxx +++ b/odb/relational/common.hxx @@ -54,12 +54,35 @@ namespace relational // // + struct query_columns_base: object_columns_base, virtual context + { + typedef query_columns_base base; + + query_columns_base (); + query_columns_base (semantics::class_&); + + virtual void + traverse_object (semantics::class_&); + + virtual void + traverse_composite (semantics::data_member*, semantics::class_&); + + virtual bool + traverse_column (semantics::data_member&, string const&, bool); + + protected: + bool decl_; + string scope_; + }; + + // + // struct query_columns: object_columns_base, virtual context { typedef query_columns base; - query_columns (); - query_columns (semantics::class_&); + query_columns (bool ptr); + query_columns (bool ptr, semantics::class_&); virtual string database_type_id (semantics::data_member&) diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx index c70ef27..11d3cf6 100644 --- a/odb/relational/header.cxx +++ b/odb/relational/header.cxx @@ -18,26 +18,45 @@ namespace relational context ctx; ostream& os (ctx.os); - traversal::unit unit; - traversal::defines unit_defines; - traversal::namespace_ ns; - instance c; - - unit >> unit_defines >> ns; - unit_defines >> c; - - traversal::defines ns_defines; - - ns >> ns_defines >> ns; - ns_defines >> c; - instance i; i->generate (); os << "namespace odb" << "{"; - unit.dispatch (ctx.unit); + { + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + instance c; + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + + unit.dispatch (ctx.unit); + } + + { + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + instance c; + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + + unit.dispatch (ctx.unit); + } os << "}"; } diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 30cb01e..cc89e9a 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -115,14 +115,17 @@ namespace relational }; // - // query_type + // query_columns_type // - struct query_base: traversal::class_, virtual context + struct query_columns_bases: traversal::class_, virtual context { - typedef query_base base; + typedef query_columns_bases base; - query_base (): first_ (true) {} + query_columns_bases (bool ptr, bool first = true) + : ptr_ (ptr), first_ (first) + { + } virtual void traverse (type& c) @@ -143,37 +146,156 @@ namespace relational << " "; } - os << "object_traits< " << c.fq_name () << " >::query_columns"; + os << (ptr_ ? "pointer_query_columns" : "query_columns") << + "< " << c.fq_name () << ", table >"; } private: + bool ptr_; bool first_; }; - struct query_type: traversal::class_, virtual context + struct query_columns_base_aliases: traversal::class_, virtual context { - typedef query_type base; + typedef query_columns_base_aliases base; + + query_columns_base_aliases (bool ptr) + : ptr_ (ptr) + { + } virtual void traverse (type& c) { - os << "struct query_columns"; + // Ignore transient bases. Not used for views. + // + if (!object (c)) + return; - { - instance b; - traversal::inherits i (*b); - inherits (c, i); - } + os << "// " << c.name () << endl + << "//" << endl + << "typedef " << + (ptr_ ? "pointer_query_columns" : "query_columns") << + "< " << c.fq_name () << ", table > " << c.name () << ";" + << endl; + } - os << "{"; + 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 (c.fq_name ()); + + if (ptr_) { - instance t; - t->traverse (c); + os << "template " << endl + << "struct pointer_query_columns< " << type << ", table >"; + + // 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)) + { + os << ":" << endl + << " query_columns< " << type << ", table >" + << "{" + << "};"; + } + else + { + { + instance b (ptr_); + traversal::inherits i (*b); + inherits (c, i); + } + + os << "{"; + + { + instance b (ptr_); + traversal::inherits i (*b); + inherits (c, i); + } + + { + instance t (ptr_); + t->traverse (c); + } + + os << "};"; + + { + instance t (ptr_, c); + t->traverse (c); + } + } } + else + { + bool has_ptr (has_a (c, test_pointer | exclude_base)); - os << "};"; + if (has_ptr) + { + os << "template <>" << endl + << "struct query_columns_base< " << type << " >" + << "{"; + + instance t; + t->traverse (c); + + os << "};"; + } + + os << "template " << endl + << "struct query_columns< " << type << ", table >"; + + if (has_ptr) + os << ":" << endl + << " query_columns_base< " << type << " >"; + + { + instance b (ptr_, !has_ptr); + traversal::inherits i (*b); + inherits (c, i); + } + + os << "{"; + + { + instance b (ptr_); + traversal::inherits i (*b); + inherits (c, i); + } + + { + instance t (ptr_); + t->traverse (c); + } + + os << "};"; + + { + instance t (ptr_, c); + t->traverse (c); + } + } } + + public: + bool ptr_; }; // Member-specific traits types for container members. @@ -368,9 +490,9 @@ namespace relational // Statements. // - os << "static const char* const insert_one_statement;" - << "static const char* const select_all_statement;" - << "static const char* const delete_all_statement;" + os << "static const char insert_one_statement[];" + << "static const char select_all_statement[];" + << "static const char delete_all_statement[];" << endl; } @@ -732,18 +854,26 @@ namespace relational semantics::class_& c_; }; + // First pass over objects, views, and composites. Some code must be + // split into two parts to deal with yet undefined types. // - // - struct class_: traversal::class_, virtual context + struct class1: traversal::class_, virtual context { - typedef class_ base; + typedef class1 base; - class_ (): id_image_member_ ("id_") {} + class1 () + : id_image_member_ ("id_"), + query_columns_type_ (false), + pointer_query_columns_type_ (true) + { + } - class_ (class_ const&) + class1 (class_ const&) : root_context (), //@@ -Wextra context (), - id_image_member_ ("id_") + id_image_member_ ("id_"), + query_columns_type_ (false), + pointer_query_columns_type_ (true) { } @@ -774,7 +904,6 @@ namespace relational virtual void traverse_object (type& c) { - bool abst (abstract (c)); string const& type (c.fq_name ()); semantics::data_member* id (id_member (c)); @@ -784,12 +913,33 @@ namespace relational os << "// " << c.name () << endl << "//" << endl; + // class_traits + // os << "template <>" << endl << "struct class_traits< " << type << " >" << "{" << "static const class_kind kind = class_object;" << "};"; + // 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)) + query_columns_type_->traverse (c); + + pointer_query_columns_type_->traverse (c); + } + + // object_traits + // os << "template <>" << endl << "class access::object_traits< " << type << " >" << "{" @@ -837,17 +987,6 @@ namespace relational image_type_->traverse (c); // - // Query (abstract and concrete). - // - - if (options.generate_query ()) - { - // query_columns - // - query_type_->traverse (c); - } - - // // Containers (abstract and concrete). // @@ -919,7 +1058,7 @@ namespace relational // // The rest only applies to concrete objects. // - if (abst) + if (abstract (c)) { object_public_extra_post (c); os << "};"; @@ -939,12 +1078,7 @@ namespace relational // query_type // - os << "struct query_type: query_base_type, query_columns" - << "{" - << "query_type ();" - << "query_type (const std::string&);" - << "query_type (const query_base_type&);" - << "};"; + os << "struct query_type;"; } // @@ -966,17 +1100,17 @@ namespace relational // Statements. // - os << "static const char* const persist_statement;" - << "static const char* const find_statement;" - << "static const char* const update_statement;" - << "static const char* const erase_statement;"; + os << "static const char persist_statement[];" + << "static const char find_statement[];" + << "static const char update_statement[];" + << "static const char erase_statement[];"; if (options.generate_query ()) { - os << "static const char* const query_clause;" - << "static const char* const erase_query_clause;" + os << "static const char query_clause[];" + << "static const char erase_query_clause[];" << endl - << "static const char* const table_name;"; + << "static const char table_name[];"; } os << endl; @@ -1184,7 +1318,7 @@ namespace relational // Statements. // - os << "static const char* const query_statement;" + os << "static const char query_statement[];" << endl; // @@ -1272,8 +1406,87 @@ namespace relational private: instance image_type_; - instance query_type_; instance id_image_member_; + + instance query_columns_type_; + instance pointer_query_columns_type_; + }; + + // Second pass over objects, views, and composites. + // + struct class2: traversal::class_, virtual context + { + typedef class2 base; + + class2 (): query_columns_type_ (false) {} + + class2 (class_ const&) + : root_context (), //@@ -Wextra + context (), + query_columns_type_ (false) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (object (c)) + traverse_object (c); + else if (view (c)) + traverse_view (c); + else if (composite (c)) + traverse_composite (c); + } + + virtual void + traverse_object (type& c) + { + bool abst (abstract (c)); + string const& type (c.fq_name ()); + + os << "// " << c.name () << endl + << "//" << endl; + + if (options.generate_query ()) + { + // 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_a (c, test_pointer)) + query_columns_type_->traverse (c); + + // query_type + // + if (!abst) + os << "struct access::object_traits< " << type << " >::" << + "query_type:" << endl + << " query_base_type," << endl + << " query_columns< " << type << ", table_name >" + << "{" + << "query_type ();" + << "query_type (const std::string&);" + << "query_type (const query_base_type&);" + << "};"; + } + } + + virtual void + traverse_view (type&) + { + } + + virtual void + traverse_composite (type&) + { + } + + private: + instance query_columns_type_; }; struct include: virtual context diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx index 8a606bd..4043809 100644 --- a/odb/relational/pgsql/header.cxx +++ b/odb/relational/pgsql/header.cxx @@ -16,9 +16,9 @@ namespace relational { namespace relational = relational::header; - struct class_: relational::class_ + struct class1: relational::class1 { - class_ (base const& x): base (x) {} + class1 (base const& x): base (x) {} virtual void object_public_extra_post (type& c) @@ -28,16 +28,16 @@ namespace relational // Statement names. // - os << "static const char* const persist_statement_name;" - << "static const char* const find_statement_name;" - << "static const char* const update_statement_name;" - << "static const char* const erase_statement_name;"; + os << "static const char persist_statement_name[];" + << "static const char find_statement_name[];" + << "static const char update_statement_name[];" + << "static const char erase_statement_name[];"; // Query statement name. // if (options.generate_query ()) - os << "static const char* const query_statement_name;" - << "static const char* const erase_query_statement_name;"; + os << "static const char query_statement_name[];" + << "static const char erase_query_statement_name[];"; os << endl; @@ -56,11 +56,11 @@ namespace relational { // Statement names. // - os << "static const char* const query_statement_name;" + os << "static const char query_statement_name[];" << endl; } }; - entry class_entry_; + entry class1_entry_; struct container_traits: relational::container_traits, context { @@ -74,9 +74,9 @@ namespace relational // Container statement names. // - os << "static const char* const select_all_name;" - << "static const char* const insert_one_name;" - << "static const char* const delete_all_name;" + os << "static const char select_all_name[];" + << "static const char insert_one_name[];" + << "static const char delete_all_name[];" << endl; // Container statement types. diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index f020c5a..28d04e6 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -891,19 +891,19 @@ namespace relational string const& n (c.fq_name ()); string traits ("access::object_traits< " + n + " >::"); string const& fn (flat_name (n)); - string name_decl ("const char* const " + traits); + string name_decl ("const char " + traits); os << name_decl << endl - << "persist_statement_name = " << strlit (fn + "_persist") << ";" + << "persist_statement_name[] = " << strlit (fn + "_persist") << ";" << endl << name_decl << endl - << "find_statement_name = " << strlit (fn + "_find") << ";" + << "find_statement_name[] = " << strlit (fn + "_find") << ";" << endl << name_decl << endl - << "update_statement_name = " << strlit (fn + "_update") << ";" + << "update_statement_name[] = " << strlit (fn + "_update") << ";" << endl << name_decl << endl - << "erase_statement_name = " << strlit (fn + "_erase") << ";" + << "erase_statement_name[] = " << strlit (fn + "_erase") << ";" << endl; // Query statement name. @@ -911,10 +911,10 @@ namespace relational if (options.generate_query ()) { os << name_decl << endl - << "query_statement_name = " << strlit (fn + "_query") << ";" + << "query_statement_name[] = " << strlit (fn + "_query") << ";" << endl << name_decl << endl - << "erase_query_statement_name = " << + << "erase_query_statement_name[] = " << strlit (fn + "_erase_query") << ";" << endl; } @@ -984,10 +984,10 @@ namespace relational string const& n (c.fq_name ()); string traits ("access::view_traits< " + n + " >::"); string const& fn (flat_name (n)); - string name_decl ("const char* const " + traits); + string name_decl ("const char " + traits); os << name_decl << endl - << "query_statement_name = " << strlit (fn + "_query") << ";" + << "query_statement_name[] = " << strlit (fn + "_query") << ";" << endl; } @@ -996,7 +996,7 @@ namespace relational { os << "sts.connection ()," << endl << "query_statement_name," << endl - << "query_clause + q.clause (table_name)," << endl + << "query_clause + q.clause ()," << endl << "q.parameter_types ()," << endl << "q.parameter_count ()," << endl << "q.parameters_binding ()," << endl @@ -1008,7 +1008,7 @@ namespace relational { os << "conn," << endl << "erase_query_statement_name," << endl - << "erase_query_clause + q.clause (table_name)," << endl + << "erase_query_clause + q.clause ()," << endl << "q.parameter_types ()," << endl << "q.parameter_count ()," << endl << "q.parameters_binding ()"; @@ -1019,7 +1019,7 @@ namespace relational { os << "sts.connection ()," << endl << "query_statement_name," << endl - << "query_statement + q.clause (\"\")," << endl + << "query_statement + q.clause ()," << endl << "q.parameter_types ()," << endl << "q.parameter_count ()," << endl << "q.parameters_binding ()," << endl @@ -1048,7 +1048,7 @@ namespace relational // Statment names. // - string stmt_decl ("const char* const " + scope + "::"); + string stmt_decl ("const char " + scope + "::"); // Prefix top-object name to avoid conflicts with inherited // member statement names. @@ -1056,15 +1056,15 @@ namespace relational string stmt_prefix (top_object->fq_name () + m.fq_name ()); os << stmt_decl << endl - << "select_all_name = " << + << "select_all_name[] = " << strlit (stmt_prefix + "_select_all") << ";" << endl << stmt_decl << endl - << "insert_one_name = " << + << "insert_one_name[] = " << strlit (stmt_prefix + "_insert_one") << ";" << endl << stmt_decl << endl - << "delete_all_name = " << + << "delete_all_name[] = " << strlit (stmt_prefix + "_delete_all") << ";" << endl; diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index a3ef5de..f83ad24 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -91,7 +91,8 @@ namespace relational if (container_wrapper (im->type ())) { // This container is a direct member of the class so the table - // prefix is just the class table name. + // prefix is just the class table name. We don't assign join + // aliases for container tables so use the actual table name. // column ( *im, "id", @@ -104,8 +105,12 @@ namespace relational else { semantics::data_member& id (*id_member (*c)); + + // Use the join alias (column name) instead of the actual + // table name unless we are handling a container. + // column (id, "", - table_name_.empty () ? table_name_ : table_qname (*c), + table_name_.empty () ? table_name_ : quote_id (name), column_qname (id)); } } @@ -162,7 +167,7 @@ namespace relational { typedef object_joins base; - //@@ context::{cur,top}_object Might have to be created every time. + //@@ context::{cur,top}_object; might have to be created every time. // object_joins (semantics::class_& scope, bool query) : query_ (query), @@ -188,38 +193,25 @@ namespace relational string line (" LEFT JOIN "); line += i->table; - // If this is a self-join, alias it as '_' to resolve any - // ambiguities. - // - if (i->table == table_) - line += " AS _"; + if (!i->alias.empty ()) + line += " AS " + i->alias; line += " ON "; - - for (conditions::iterator b (i->cond.begin ()), j (b); - j != i->cond.end (); ++j) - { - if (j != b) - line += " OR "; - - line += *j; - } + line += i->cond; os << strlit (line) << endl; } } virtual bool - traverse_column (semantics::data_member& m, - string const& col_name, - bool) + traverse_column (semantics::data_member& m, string const& column, bool) { semantics::class_* c (object_pointer (m.type ())); if (c == 0) - return true; + return false; - string t, dt; + string t, a, dt, da; std::ostringstream cond, dcond; // @@ diversion? if (semantics::data_member* im = inverse (m)) @@ -243,33 +235,20 @@ namespace relational if (query_) { dt = quote_id (ct); - string const& id (column_qname (*im, "id", "object_id")); + da = quote_id (column); - // If this is a self-join, use the '_' alias instead of the - // table name. - // - if (dt == table_) - dcond << "_"; - else - dcond << dt; + string const& id (column_qname (*im, "id", "object_id")); - dcond << '.' << column_qname (*id_member (*c)) << " = " << + dcond << da << '.' << column_qname (*id_member (*c)) << " = " << t << '.' << id; } } else { t = table_qname (*c); + a = quote_id (column); - // If this is a self-join, use the '_' alias instead of the - // table name. - // - if (t == table_) - cond << "_"; - else - cond << t; - - cond << '.' << column_qname (*im) << " = " << + cond << a << '.' << column_qname (*im) << " = " << table_ << "." << column_qname (id_); } } @@ -279,61 +258,29 @@ namespace relational // in the WHERE clause. // t = table_qname (*c); + a = quote_id (column); - // If this is a self-join, use the '_' alias instead of the - // table name. - // - if (t == table_) - cond << "_"; - else - cond << t; - - cond << '.' << column_qname (*id_member (*c)) << " = " << - table_ << "." << quote_id (col_name); + cond << a << '.' << column_qname (*id_member (*c)) << " = " << + table_ << "." << quote_id (column); } if (!t.empty ()) { - size_t i; - table_map::iterator it (table_map_.find (t)); - - if (it != table_map_.end ()) - i = it->second; - else - { - i = joins_.size (); - joins_.push_back (join ()); - table_map_[t] = i; - } - - joins_[i].table = t; - joins_[i].cond.insert (cond.str ()); + joins_.push_back (join ()); + joins_.back ().table = t; + joins_.back ().alias = a; + joins_.back ().cond = cond.str (); } + // Add dependent join (i.e., an object table join via the + // container table). + // if (!dt.empty ()) { - // Add dependent join. If one already exists, move it to the - // bottom. - // - size_t i; - table_map::iterator it (table_map_.find (dt)); - - if (it != table_map_.end ()) - { - i = joins_.size (); - joins_.push_back (join ()); - joins_[it->second].swap (joins_.back ()); - it->second = i; - } - else - { - i = joins_.size (); - joins_.push_back (join ()); - table_map_[dt] = i; - } - - joins_[i].table = dt; - joins_[i].cond.insert (dcond.str ()); + joins_.push_back (join ()); + joins_.back ().table = dt; + joins_.back ().alias = da; + joins_.back ().cond = dcond.str (); } return true; @@ -341,29 +288,19 @@ namespace relational private: bool query_; - string table_; //@@ No longer used because of the _ alias. + string table_; semantics::data_member& id_; - typedef std::set conditions; - struct join { string table; - conditions cond; - - void - swap (join& o) - { - table.swap (o.table); - cond.swap (o.cond); - } + string alias; + string cond; }; typedef std::vector joins; - typedef std::map table_map; joins joins_; - table_map table_map_; }; // @@ -715,8 +652,8 @@ namespace relational // select_all_statement // - os << "const char* const " << scope << - "::select_all_statement =" << endl; + os << "const char " << scope << + "::select_all_statement[] =" << endl; if (inverse) { @@ -830,8 +767,8 @@ namespace relational // insert_one_statement // - os << "const char* const " << scope << - "::insert_one_statement =" << endl; + os << "const char " << scope << + "::insert_one_statement[] =" << endl; if (inverse) os << strlit ("") << ";" @@ -901,8 +838,8 @@ namespace relational // delete_all_statement // - os << "const char* const " << scope << - "::delete_all_statement =" << endl; + os << "const char " << scope << + "::delete_all_statement[] =" << endl; if (inverse) os << strlit ("") << ";" @@ -1935,7 +1872,7 @@ namespace relational object_query_statement_ctor_args (type&) { os << "sts.connection ()," << endl - << "query_clause + q.clause (table_name)," << endl + << "query_clause + q.clause ()," << endl << "q.parameters_binding ()," << endl << "imb"; } @@ -1944,7 +1881,7 @@ namespace relational object_erase_query_statement_ctor_args (type&) { os << "conn," << endl - << "erase_query_clause + q.clause (table_name)," << endl + << "erase_query_clause + q.clause ()," << endl << "q.parameters_binding ()"; } @@ -1956,6 +1893,7 @@ namespace relational string traits ("access::object_traits< " + type + " >"); bool grow (context::grow (c)); + bool has_ptr (has_a (c, test_pointer)); semantics::data_member* id (id_member (c)); bool auto_id (id ? id->count ("auto") : false); @@ -1974,8 +1912,13 @@ namespace relational if (options.generate_query ()) { - instance t (c); - t->traverse (c); + // query_columns_base + // + if (has_ptr) + { + instance t (c); + t->traverse (c); + } } // @@ -2147,7 +2090,7 @@ namespace relational // persist_statement // { - os << "const char* const " << traits << "::persist_statement " << + os << "const char " << traits << "::persist_statement[] " << "=" << endl << strlit ("INSERT INTO " + table + " (") << endl; @@ -2165,7 +2108,7 @@ namespace relational // find_statement // { - os << "const char* const " << traits << "::find_statement =" << endl + os << "const char " << traits << "::find_statement[] =" << endl << strlit ("SELECT ") << endl; instance t (table, true); @@ -2187,7 +2130,7 @@ namespace relational // update_statement // { - os << "const char* const " << traits << "::update_statement " << + os << "const char " << traits << "::update_statement[] " << "=" << endl << strlit ("UPDATE " + table + " SET ") << endl; @@ -2203,7 +2146,7 @@ namespace relational // { instance qp; - os << "const char* const " << traits << "::erase_statement =" << endl + os << "const char " << traits << "::erase_statement[] =" << endl << strlit ("DELETE FROM " + table) << endl << strlit (" WHERE " + id_col + "=" + qp->next ()) << ";" << endl; @@ -2220,7 +2163,7 @@ namespace relational // We only need DISTINCT if there are joins (object pointers) // and can optimize it out otherwise. // - os << "const char* const " << traits << "::query_clause =" << endl + os << "const char " << traits << "::query_clause[] =" << endl << strlit (oj->count () ? "SELECT DISTINCT " : "SELECT ") << endl; { @@ -2235,7 +2178,7 @@ namespace relational // erase_query_clause // - os << "const char* const " << traits << "::erase_query_clause =" << endl + os << "const char " << traits << "::erase_query_clause[] =" << endl << strlit ("DELETE FROM " + table) << endl; // DELETE JOIN: @@ -2251,8 +2194,8 @@ namespace relational // table_name // - os << "const char* const " << traits << "::table_name =" << endl - << strlit (table) << ";" + os << "const char " << traits << "::table_name[] =" << endl + << strlit (table_name (c)) << ";" // Use unquoted name. << endl; } @@ -2849,7 +2792,7 @@ namespace relational view_query_statement_ctor_args (type&) { os << "sts.connection ()," << endl - << "query_statement + q.clause (\"\")," << endl + << "query_statement + q.clause ()," << endl << "q.parameters_binding ()," << endl << "imb"; } @@ -2917,7 +2860,7 @@ namespace relational // query_statement // - os << "const char* const " << traits << "::query_statement =" << endl + os << "const char " << traits << "::query_statement[] =" << endl << strlit (c.get ("query")) << endl << strlit (" ") << ";" << endl << endl; -- cgit v1.1