From 8a637f5697fdee3e7ae2d46f64a64d40cba5954b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 31 Oct 2012 07:59:18 +0200 Subject: Add dynamic multi-database support excluding query --- odb/generate.hxx | 6 ++ odb/generator.cxx | 14 ++-- odb/header.cxx | 192 +++++++++++++++++++++++++++++++++++++--------- odb/inline.cxx | 99 ++++++++++++++++++++++++ odb/makefile | 1 + odb/relational/source.cxx | 70 +++++++++++++++-- odb/relational/source.hxx | 3 + odb/source.cxx | 100 ++++++++++++++++++++++++ 8 files changed, 439 insertions(+), 46 deletions(-) create mode 100644 odb/source.cxx diff --git a/odb/generate.hxx b/odb/generate.hxx index 1ca6f43..49b3aae 100644 --- a/odb/generate.hxx +++ b/odb/generate.hxx @@ -23,4 +23,10 @@ namespace inline_ generate (); } +namespace source +{ + void + generate (); +} + #endif // ODB_GENERATE_HXX diff --git a/odb/generator.cxx b/odb/generator.cxx index ec98a15..4fa4cf2 100644 --- a/odb/generator.cxx +++ b/odb/generator.cxx @@ -81,6 +81,7 @@ generate (options const& ops, try { database db (ops.database ()[0]); + multi_database md (ops.multi_database ()); // First create the database model. // @@ -181,7 +182,7 @@ generate (options const& ops, // ofstream cxx; - if (gen_cxx && db != database::common) + if (gen_cxx && (db != database::common || md == multi_database::dynamic)) { cxx.open (cxx_path.string ().c_str (), ios_base::out); @@ -346,7 +347,7 @@ generate (options const& ops, case database::pgsql: case database::sqlite: { - if (ops.multi_database () == multi_database::disabled) + if (md == multi_database::disabled) header::generate (); else { @@ -445,7 +446,7 @@ generate (options const& ops, case database::pgsql: case database::sqlite: { - if (ops.multi_database () == multi_database::disabled) + if (md == multi_database::disabled) inline_::generate (); relational::inline_::generate (); @@ -482,7 +483,7 @@ generate (options const& ops, // CXX // - if (gen_cxx && db != database::common) + if (gen_cxx && (db != database::common || md == multi_database::dynamic)) { auto_ptr ctx ( create_context (cxx, unit, ops, fts, model.get ())); @@ -530,7 +531,10 @@ generate (options const& ops, { case database::common: { - assert (false); + // Dynamic multi-database support. + // + source::generate (); + break; } case database::mssql: case database::mysql: diff --git a/odb/header.cxx b/odb/header.cxx index 67e4cc0..7e0a377 100644 --- a/odb/header.cxx +++ b/odb/header.cxx @@ -203,62 +203,182 @@ traverse_object (type& c) << endl; } - if (!reuse_abst) + // The rest does not apply to reuse-abstract objects. + // + if (reuse_abst) { - // Cache traits typedefs. - // - if (id == 0) + 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 + { + char const* p (session (c) ? "odb::" : "no_op_"); + + if (poly_derived) { os << "typedef" << endl - << "no_id_pointer_cache_traits" << endl + << p << "pointer_cache_traits<" << + "object_traits::pointer_type>" << endl << "pointer_cache_traits;" << endl << "typedef" << endl - << "no_id_reference_cache_traits" << endl + << p << "reference_cache_traits" << endl << "reference_cache_traits;" << endl; } else { - char const* p (session (c) ? "odb::" : "no_op_"); + os << "typedef" << endl + << p << "pointer_cache_traits" << endl + << "pointer_cache_traits;" + << endl + << "typedef" << endl + << p << "reference_cache_traits" << endl + << "reference_cache_traits;" + << endl; + } + } - 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; + + 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) + return; + + // object_traits_impl + // + os << "template <>" << endl + << "class access::object_traits_impl< " << type << ", " << + "id_default >:" << endl + << " public access::object_traits< " << type << " >" + << "{" + << "public:" << endl; + + // function_table_type + // + os << "struct function_table_type" + << "{"; + + // persist () + // + os << "void (*persist) (database&, " << (auto_id ? "" : "const ") << + "object_type&" << (poly ? ", bool, bool" : "") << ");"; + + if (id != 0) + { + // find (id) + // + if (c.default_ctor ()) + os << "pointer_type (*find1) (database&, const id_type&);"; + + // find (id, obj) + // + os << "bool (*find2) (database&, const id_type&, object_type&" << + (poly ? ", bool" : "") << ");"; + + // reload () + // + os << "bool (*reload) (database&, object_type&" << + (poly ? ", bool" : "") << ");"; + + // update () + // + if (!readonly (c) || poly) + { + os << "void (*update) (database&, const object_type&" << + (poly ? ", bool, bool" : "") << ");"; + } + + // erase () + // + os << "void (*erase1) (database&, const id_type&" << + (poly ? ", bool, bool" : "") << ");"; + + os << "void (*erase2) (database&, const object_type&" << + (poly ? ", bool, bool" : "") << ");"; + } + + os << "};" // function_table_type + << "static const function_table_type* function_table[database_count];" + << endl; + + // + // Forwarding functions. + // + + // persist () + // + os << "static void" << endl + << "persist (database&, " << (auto_id ? "" : "const ") << "object_type&);" + << endl; + + if (id != 0) + { + // find (id) + // + if (c.default_ctor ()) + os << "static pointer_type" << endl + << "find (database&, const id_type&);" + << endl; + + // find (id, obj) + // + os << "static bool" << endl + << "find (database&, const id_type&, object_type&);" + << endl; + + // reload () + // + os << "static bool" << endl + << "reload (database&, object_type&);" + << endl; + + // update () + // + if (!readonly (c) || poly) + { + os << "static void" << endl + << "update (database&, const object_type&);" + << endl; } - // callback () + // erase () // os << "static void" << endl - << "callback (database&, object_type&, callback_event);" - << endl; + << "erase (database&, const id_type&);" + << endl; os << "static void" << endl - << "callback (database&, const object_type&, callback_event);" - << endl; + << "erase (database&, const object_type&);" + << endl; } - os << "};"; + os << "};"; // object_traits_impl } void header::class_:: diff --git a/odb/inline.cxx b/odb/inline.cxx index 39bde4d..5b2b16c 100644 --- a/odb/inline.cxx +++ b/odb/inline.cxx @@ -96,6 +96,7 @@ traverse_object (type& c) using semantics::data_member; data_member* id (id_member (c)); + bool auto_id (id && auto_ (*id)); bool base_id (id && &id->scope () != &c); // Comes from base. // Base class that contains the object id. @@ -175,6 +176,100 @@ traverse_object (type& c) << endl; callback_calls_.traverse (c, true); os << "}"; + + // The rest only applies to dynamic milti-database support. + // + if (options.multi_database () != multi_database::dynamic) + return; + + traits = "access::object_traits_impl< " + type + ", id_default >"; + + // + // Forwarding functions. + // + + // persist () + // + os << "inline" << endl + << "void " << traits << "::" << endl + << "persist (database& db, " << (auto_id ? "" : "const ") << + "object_type& o)" + << "{" + << "function_table[db.id ()]->persist (db, o" << + (poly ? ", true, true" : "") << ");" + << "}"; + + if (id != 0) + { + // find (id) + // + if (c.default_ctor ()) + { + os << "inline" << endl + << traits << "::pointer_type" << endl + << traits << "::" << endl + << "find (database& db, const id_type& id)" + << "{" + << "return function_table[db.id ()]->find1 (db, id);" + << "}"; + } + + // find (id, obj) + // + os << "inline" << endl + << "bool " << traits << "::" << endl + << "find (database& db, const id_type& id, object_type& o)" + << "{" + << "return function_table[db.id ()]->find2 (db, id, o" << + (poly ? ", true" : "") << ");" + << "}"; + + // reload () + // + os << "inline" << endl + << "bool " << traits << "::" << endl + << "reload (database& db, object_type& o)" + << "{" + << "return function_table[db.id ()]->reload (db, o" << + (poly ? ", true" : "") << ");" + << "}"; + + // update () + // + // In case of a polymorphic object, we generate update() even if it is + // readonly since the potentially-readwrite base will rely on it to + // initialize the id image. + // + // + if (!readonly (c) || poly) + { + os << "inline" << endl + << "void " << traits << "::" << endl + << "update (database& db, const object_type& o)" + << "{" + << "function_table[db.id ()]->update (db, o" << + (poly ? ", true, true" : "") << ");" + << "}"; + } + + // erase () + // + os << "inline" << endl + << "void " << traits << "::" << endl + << "erase (database& db, const id_type& id)" + << "{" + << "function_table[db.id ()]->erase1 (db, id" << + (poly ? ", true, true" : "") << ");" + << "}"; + + os << "inline" << endl + << "void " << traits << "::" << endl + << "erase (database& db, const object_type& o)" + << "{" + << "function_table[db.id ()]->erase2 (db, o" << + (poly ? ", true, true" : "") << ");" + << "}"; + } } void inline_::class_:: @@ -210,6 +305,10 @@ namespace inline_ context ctx; ostream& os (ctx.os); + if (ctx.options.multi_database () == multi_database::dynamic) + os << "#include " << endl + << endl; + traversal::unit unit; traversal::defines unit_defines; typedefs unit_typedefs (false); diff --git a/odb/makefile b/odb/makefile index bb0deba..5d0650b 100644 --- a/odb/makefile +++ b/odb/makefile @@ -19,6 +19,7 @@ lookup.cxx \ include.cxx \ header.cxx \ inline.cxx \ +source.cxx \ validator.cxx \ processor.cxx \ generator.cxx \ diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 7516801..7fc3ce6 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -37,6 +37,7 @@ traverse_object (type& c) bool abst (abstract (c)); bool reuse_abst (abst && !poly); + bool readonly (context::readonly (c)); bool grow (false); bool grow_id (false); @@ -223,7 +224,7 @@ traverse_object (type& c) << "using namespace " << db << ";" << endl; - if (readonly (c)) + if (readonly) os << "assert (sk != statement_update);" << endl; @@ -252,7 +253,7 @@ traverse_object (type& c) { // The id reference comes last in the update statement. // - if (!readonly (c)) + if (!readonly) os << "// " << id->name () << endl << "//" << endl << "if (sk == statement_update)" @@ -321,7 +322,7 @@ traverse_object (type& c) << "using namespace " << db << ";" << endl; - if (readonly (c)) + if (readonly) os << "assert (sk != statement_update);" << endl; @@ -1061,8 +1062,6 @@ traverse_object (type& c) // update () // - bool readonly (context::readonly (c)); - if (id != 0 && (!readonly || poly)) { os << "void " << traits << "::" << endl @@ -2788,8 +2787,69 @@ traverse_object (type& c) } } + // Generate embedded schema. + // if (embedded_schema) schema_->traverse (c); + + // Generate function table registration for dynamic multi-database + // support. + // + if (options.multi_database () == multi_database::dynamic) + { + string fn (flat_name (type)); + string dt ("access::object_traits_impl< " + type + ", id_default >"); + + os << "static const" << endl + << dt << "::" << endl + << "function_table_type function_table_" << fn << "_ =" + << "{"; + + // persist () + // + os << "&" << traits << "::persist"; + + if (id != 0) + { + // find (id) + // + if (c.default_ctor ()) + os << "," << endl + << "&" << traits << "::find"; + + // find (id, obj) + // + os << "," << endl + << "&" << traits << "::find"; + + // reload () + // + os << "," << endl + << "&" << traits << "::reload"; + + // update () + // + if (!readonly || poly) + os << "," << endl + << "&" << traits << "::update"; + + // erase () + // + os << "," << endl + << "&" << traits << "::erase"; + + os << "," << endl + << "&" << traits << "::erase"; + } + + os << "};"; + + os << "static const function_table_entry< " << type << ", " << + "id_" << db << " >" << endl + << "function_table_entry_" << fn << "_ (" << endl + << "&function_table_" << fn << "_);" + << endl; + } } void relational::source::class_:: diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 8d57b1b..a9c5bb1 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -3669,6 +3669,9 @@ namespace relational if (embedded_schema) os << "#include " << endl; + if (options.multi_database () == multi_database::dynamic) + os << "#include " << endl; + os << endl; os << "#include " << endl diff --git a/odb/source.cxx b/odb/source.cxx new file mode 100644 index 0000000..94560ce --- /dev/null +++ b/odb/source.cxx @@ -0,0 +1,100 @@ +// file : odb/source.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include +#include +#include +#include + +using namespace std; + +namespace source +{ + struct class_: traversal::class_, virtual context + { + 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&); + }; +} + +void source::class_:: +traverse_object (type& c) +{ + bool poly (polymorphic (c)); + bool abst (abstract (c)); + bool reuse_abst (abst && !poly); + + // The rest only applies to dynamic milti-database support and non- + // reuse-abstract objects. + // + if (reuse_abst || options.multi_database () != multi_database::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; + + os << "const " << traits << "::" << endl + << "function_table_type*" << endl + << traits << "::" << endl + << "function_table[database_count];" + << endl; +} + +void source::class_:: +traverse_view (type&) +{ +} + +namespace source +{ + void + generate () + { + context ctx; + ostream& os (ctx.os); + + traversal::unit unit; + traversal::defines unit_defines; + typedefs unit_typedefs (false); + traversal::namespace_ ns; + class_ 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; + + os << "namespace odb" + << "{"; + + unit.dispatch (ctx.unit); + + os << "}"; + } +} -- cgit v1.1