aboutsummaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-10-31 07:59:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-11-21 13:13:50 +0200
commit8a637f5697fdee3e7ae2d46f64a64d40cba5954b (patch)
treec0255a90876c464803245a39f8505898ab6a3f74 /odb
parent2b7b3e9d9e69bbf0fdd6ce1a8564765027580d10 (diff)
Add dynamic multi-database support excluding query
Diffstat (limited to 'odb')
-rw-r--r--odb/generate.hxx6
-rw-r--r--odb/generator.cxx14
-rw-r--r--odb/header.cxx192
-rw-r--r--odb/inline.cxx99
-rw-r--r--odb/makefile1
-rw-r--r--odb/relational/source.cxx70
-rw-r--r--odb/relational/source.hxx3
-rw-r--r--odb/source.cxx100
8 files changed, 439 insertions, 46 deletions
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<context> 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<pointer_type>" << endl
+ << "pointer_cache_traits;"
+ << endl
+ << "typedef" << endl
+ << "no_id_reference_cache_traits<object_type>" << 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<pointer_type>" << endl
+ << p << "pointer_cache_traits<" <<
+ "object_traits<root_type>::pointer_type>" << endl
<< "pointer_cache_traits;"
<< endl
<< "typedef" << endl
- << "no_id_reference_cache_traits<object_type>" << endl
+ << p << "reference_cache_traits<root_type>" << endl
<< "reference_cache_traits;"
<< endl;
}
else
{
- char const* p (session (c) ? "odb::" : "no_op_");
+ 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;
+ }
+ }
- 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;
+
+ 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 <odb/database.hxx>" << 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 <odb/schema-catalog-impl.hxx>" << endl;
+ if (options.multi_database () == multi_database::dynamic)
+ os << "#include <odb/function-table.hxx>" << endl;
+
os << endl;
os << "#include <odb/" << db << "/traits.hxx>" << 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 <odb/common.hxx>
+#include <odb/context.hxx>
+#include <odb/generate.hxx>
+#include <odb/diagnostics.hxx>
+
+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 << "}";
+ }
+}