From 9ad0acf37561de9bf359a561faed53de17c2ca3b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 21 Nov 2012 13:11:43 +0200 Subject: Add dynamic multi-database query support --- odb/header.cxx | 404 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 333 insertions(+), 71 deletions(-) (limited to 'odb/header.cxx') diff --git a/odb/header.cxx b/odb/header.cxx index 66248d2..1f02463 100644 --- a/odb/header.cxx +++ b/odb/header.cxx @@ -10,8 +10,12 @@ using namespace std; namespace header { - struct class_: traversal::class_, virtual context + struct class1: traversal::class_, virtual context { + class1 () + : query_columns_type_ (false, true), + pointer_query_columns_type_ (true, true) {} + virtual void traverse (type& c) { @@ -30,12 +34,13 @@ namespace header void traverse_view (type&); - void - traverse_composite (type&); + private: + instance query_columns_type_; + instance pointer_query_columns_type_; }; } -void header::class_:: +void header::class1:: traverse_object (type& c) { using semantics::data_member; @@ -210,8 +215,7 @@ traverse_object (type& c) // Generate object pointer tags here if we are generating dynamic // multi-database support. // - if (options.multi_database () == multi_database::dynamic && - has_a (c, test_pointer | exclude_base)) + if (multi_dynamic && has_a (c, test_pointer | exclude_base)) { query_tags t; t.traverse (c); @@ -220,80 +224,114 @@ traverse_object (type& c) // The rest does not apply to reuse-abstract objects. // - if (reuse_abst) - { - os << "};"; - return; - } - - // Cache traits typedefs. - // - if (id == 0) - { - os << "typedef" << endl - << "no_id_pointer_cache_traits" << endl - << "pointer_cache_traits;" - << endl - << "typedef" << endl - << "no_id_reference_cache_traits" << endl - << "reference_cache_traits;" - << endl; - } - else + if (!reuse_abst) { - char const* p (session (c) ? "odb::" : "no_op_"); - - if (poly_derived) + // Cache traits typedefs. + // + if (id == 0) { os << "typedef" << endl - << p << "pointer_cache_traits<" << - "object_traits::pointer_type>" << endl + << "no_id_pointer_cache_traits" << endl << "pointer_cache_traits;" << endl << "typedef" << endl - << p << "reference_cache_traits" << endl + << "no_id_reference_cache_traits" << endl << "reference_cache_traits;" << endl; } else { - os << "typedef" << endl - << p << "pointer_cache_traits" << endl - << "pointer_cache_traits;" - << endl - << "typedef" << endl - << p << "reference_cache_traits" << endl - << "reference_cache_traits;" - << endl; + char const* p (session (c) ? "odb::" : "no_op_"); + + if (poly_derived) + { + os << "typedef" << endl + << p << "pointer_cache_traits<" << + "object_traits::pointer_type>" << endl + << "pointer_cache_traits;" + << endl + << "typedef" << endl + << p << "reference_cache_traits" << endl + << "reference_cache_traits;" + << endl; + } + else + { + os << "typedef" << endl + << p << "pointer_cache_traits" << endl + << "pointer_cache_traits;" + << endl + << "typedef" << endl + << p << "reference_cache_traits" << endl + << "reference_cache_traits;" + << endl; + } } - } - // callback () - // - os << "static void" << endl - << "callback (database&, object_type&, callback_event);" - << endl; + // callback () + // + os << "static void" << endl + << "callback (database&, object_type&, callback_event);" + << endl; - os << "static void" << endl - << "callback (database&, const object_type&, callback_event);" - << endl; + os << "static void" << endl + << "callback (database&, const object_type&, callback_event);" + << endl; + } os << "};"; // The rest only applies to dynamic milti-database support. // - if (options.multi_database () != multi_database::dynamic) + if (!multi_dynamic) + return; + + // pointer_query_columns & query_columns + // + if (options.generate_query ()) + { + // If we don't have object pointers, then also generate + // query_columns (in this case pointer_query_columns and + // query_columns are the same and the former inherits from + // the latter). Otherwise we have to postpone query_columns + // generation until the second pass to deal with forward- + // declared objects. + // + if (!has_a (c, test_pointer | include_base)) + query_columns_type_->traverse (c); + + pointer_query_columns_type_->traverse (c); + } + + // We don't need to generate object_traits_impl for reuse-abstract + // objects. + // + if (reuse_abst) return; // object_traits_impl // os << "template <>" << endl << "class access::object_traits_impl< " << type << ", " << - "id_default >:" << endl + "id_common >:" << endl << " public access::object_traits< " << type << " >" << "{" << "public:" << endl; + if (options.generate_query ()) + { + // base_traits is needed for query support. + // + if (poly_derived) + os << "typedef object_traits_impl base_traits;" + << endl; + + // query_base_type + // + os << "typedef odb::query_base query_base_type;" + << endl; + } + // function_table_type // os << "struct function_table_type" @@ -338,6 +376,28 @@ traverse_object (type& c) (poly ? ", bool, bool" : "") << ");"; } + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + os << "result (*query) (database&, const query_base_type&);" + << endl; + + os << "unsigned long long (*erase_query) (database&, " << + "const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "odb::details::shared_ptr " << + "(*prepare_query) (connection&, const char*, const query_base_type&);" + << endl; + + os << "odb::details::shared_ptr (*execute_query) (" + "prepared_query_impl&);" + << endl; + } + } + os << "};" // function_table_type << "static const function_table_type* function_table[database_count];" << endl; @@ -393,10 +453,35 @@ traverse_object (type& c) << endl; } + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + { + os << "static result" << endl + << "query (database&, const query_base_type&);" + << endl; + } + + os << "static unsigned long long" << endl + << "erase_query (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "static odb::details::shared_ptr" << endl + << "prepare_query (connection&, const char*, const query_base_type&);" + << endl; + + os << "static odb::details::shared_ptr" << endl + << "execute_query (prepared_query_impl&);" + << endl; + } + } + os << "};"; // object_traits_impl } -void header::class_:: +void header::class1:: traverse_view (type& c) { string const& type (class_fq_name (c)); @@ -428,7 +513,7 @@ traverse_view (type& c) // Generate associated object tags here if we are generating dynamic // multi-database support. // - if (options.multi_database () == multi_database::dynamic) + if (multi_dynamic) { query_tags t; t.traverse (c); @@ -441,6 +526,152 @@ traverse_view (type& c) << endl; os << "};"; + + // The rest only applies to dynamic milti-database support. + // + if (!multi_dynamic) + return; + + size_t obj_count (c.get ("object-count")); + + // view_traits_impl + // + os << "template <>" << endl + << "class access::view_traits_impl< " << type << ", id_common >:" << endl + << " public access::view_traits< " << type << " >" + << "{" + << "public:" << endl; + + // query_base_type and query_columns (definition generated by class2). + // + os << "typedef odb::query_base query_base_type;" + << "struct query_columns"; + + if (obj_count == 0) + os << "{" + << "};"; + else + os << ";" + << endl; + + // function_table_type + // + os << "struct function_table_type" + << "{"; + + if (!options.omit_unprepared ()) + os << "result (*query) (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "odb::details::shared_ptr " << + "(*prepare_query) (connection&, const char*, const query_base_type&);" + << endl; + + os << "odb::details::shared_ptr (*execute_query) (" + "prepared_query_impl&);" + << endl; + } + + os << "};" // function_table_type + << "static const function_table_type* function_table[database_count];" + << endl; + + // + // Forwarding functions. + // + + if (!options.omit_unprepared ()) + os << "static result" << endl + << "query (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "static odb::details::shared_ptr" << endl + << "prepare_query (connection&, const char*, const query_base_type&);" + << endl; + + os << "static odb::details::shared_ptr" << endl + << "execute_query (prepared_query_impl&);" + << endl; + } + + os << "};"; +} + +namespace header +{ + struct class2: traversal::class_, virtual context + { + class2 () + : query_columns_type_ (false, true), + view_query_columns_type_ (true) + { + } + + virtual void + traverse (type& c) + { + if (!options.at_once () && class_file (c) != unit.file ()) + return; + + if (object (c)) + traverse_object (c); + else if (view (c)) + traverse_view (c); + } + + void + traverse_object (type&); + + void + traverse_view (type&); + + private: + instance query_columns_type_; + instance view_query_columns_type_; + }; +} + +void header::class2:: +traverse_object (type& c) +{ + if (options.generate_query ()) + { + bool has_ptr (has_a (c, test_pointer | include_base)); + + if (has_ptr) + os << "// " << class_name (c) << endl + << "//" << endl; + + // query_columns + // + // If we don't have any pointers, then query_columns is generated + // in pass 1 (see the comment in class1 for details). + // + if (has_ptr) + query_columns_type_->traverse (c); + } + + // Move header comment out of if-block if adding any code here. +} + +void header::class2:: +traverse_view (type& c) +{ + // query_columns + // + if (c.get ("object-count") != 0) + { + os << "// " << class_name (c) << endl + << "//" << endl; + + view_query_columns_type_->traverse (c); + } + + // Move header comment out of if-block if adding any code here. } namespace header @@ -495,6 +726,9 @@ namespace header if (ctx.options.generate_query ()) { + if (ctx.multi_dynamic) + os << "#include " << endl; + if (ctx.options.generate_prepared ()) os << "#include " << endl; @@ -514,32 +748,60 @@ namespace header } os << endl - << "#include " << endl - << endl; + << "#include " << endl; + + if (ctx.options.generate_query ()) + os << "#include " << endl; + + os << endl; + + os << "namespace odb" + << "{"; // Generate common code. // - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (false); - traversal::namespace_ ns; - class_ c; + { + traversal::unit unit; + traversal::defines unit_defines; + typedefs unit_typedefs (false); + traversal::namespace_ ns; + class1 c; - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; + unit >> unit_defines >> ns; + unit_defines >> c; + unit >> unit_typedefs >> c; - traversal::defines ns_defines; - typedefs ns_typedefs (false); + traversal::defines ns_defines; + typedefs ns_typedefs (false); - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; + ns >> ns_defines >> ns; + ns_defines >> c; + ns >> ns_typedefs >> c; - os << "namespace odb" - << "{"; + unit.dispatch (ctx.unit); + } - unit.dispatch (ctx.unit); + if (ctx.multi_dynamic) + { + traversal::unit unit; + traversal::defines unit_defines; + typedefs unit_typedefs (false); + traversal::namespace_ ns; + class2 c; + + unit >> unit_defines >> ns; + unit_defines >> c; + unit >> unit_typedefs >> c; + + traversal::defines ns_defines; + typedefs ns_typedefs (false); + + ns >> ns_defines >> ns; + ns_defines >> c; + ns >> ns_typedefs >> c; + + unit.dispatch (ctx.unit); + } os << "}"; } -- cgit v1.1