aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-07-05 18:39:09 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-07-05 18:39:09 +0200
commit5d33aeaa327f53c920a65302925090debdfc80b8 (patch)
tree5c1c0806ae8b09b6f04a16ba2d50b762f83cd416
parentaae1a5139744da164e8565004753b69645038eb0 (diff)
Add support for multi-pass database schema generation
-rw-r--r--odb/relational/header.hxx4
-rw-r--r--odb/relational/schema.cxx14
-rw-r--r--odb/relational/schema.hxx30
-rw-r--r--odb/relational/source.hxx179
4 files changed, 168 insertions, 59 deletions
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 11ecfdf..f25e9fe 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -1008,8 +1008,8 @@ namespace relational
//
if (embedded_schema)
{
- os << "static void" << endl
- << "create_schema (database&);"
+ os << "static bool" << endl
+ << "create_schema (database&, unsigned short pass);"
<< endl;
}
diff --git a/odb/relational/schema.cxx b/odb/relational/schema.cxx
index 6afdb32..87e0533 100644
--- a/odb/relational/schema.cxx
+++ b/odb/relational/schema.cxx
@@ -60,7 +60,7 @@ namespace relational
schema_emitter emitter;
- // Drop.
+ // Drop. It is essentially pass 0.
//
{
traversal::unit unit;
@@ -86,7 +86,9 @@ namespace relational
traversal::unit unit;
traversal::defines unit_defines;
traversal::namespace_ ns;
- instance<class_create> c (emitter);
+
+ unsigned short pass (1);
+ instance<class_create> c (emitter, pass);
unit >> unit_defines >> ns;
unit_defines >> c;
@@ -95,6 +97,14 @@ namespace relational
ns >> ns_defines >> ns;
ns_defines >> c;
+
+ // Pass 1.
+ //
+ unit.dispatch (ctx.unit);
+
+ // Pass 2.
+ //
+ pass = 2;
unit.dispatch (ctx.unit);
}
}
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
index a59bf33..ada459d 100644
--- a/odb/relational/schema.hxx
+++ b/odb/relational/schema.hxx
@@ -243,8 +243,14 @@ namespace relational
{
typedef member_create base;
- member_create (emitter& e, ostream& os, tables& t)
- : object_members_base (false, true), common (e, os), tables_ (t)
+ member_create (emitter& e,
+ ostream& os,
+ tables& t,
+ unsigned short const& pass)
+ : object_members_base (false, true),
+ common (e, os),
+ tables_ (t),
+ pass_ (pass)
{
}
@@ -352,27 +358,40 @@ namespace relational
protected:
tables& tables_;
+ unsigned short const& pass_;
};
struct class_create: traversal::class_, common, virtual create_common
{
typedef class_create base;
- class_create (emitter& e)
- : common (e, os_), os_ (e), member_create_ (e, os_, tables_)
+ class_create (emitter& e, unsigned short const& pass)
+ : common (e, os_),
+ os_ (e),
+ pass_ (pass),
+ member_create_ (e, os_, tables_, pass_)
{
}
class_create (class_create const& x)
: root_context (), //@@ -Wextra
context (),
- common (x.e_, os_), os_ (x.e_), member_create_ (x.e_, os_, tables_)
+ common (x.e_, os_),
+ os_ (x.e_),
+ pass_ (x.pass_),
+ member_create_ (x.e_, os_, tables_, pass_)
{
}
virtual void
traverse (type& c)
{
+ // By default we do everything in a single pass. But some
+ // databases may require the second pass.
+ //
+ if (pass_ > 1)
+ return;
+
if (c.file () != unit.file ())
return;
@@ -408,6 +427,7 @@ namespace relational
protected:
tables tables_;
emitter_ostream os_;
+ unsigned short const& pass_;
instance<member_create> member_create_;
};
}
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index ba8e2e3..8221ec2 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -21,39 +21,6 @@ namespace relational
{
namespace source
{
- struct schema_emitter: emitter, virtual context
- {
- virtual void
- pre ()
- {
- first_ = true;
- }
-
- virtual void
- line (const string& l)
- {
- if (first_)
- {
- first_ = false;
- os << "db.execute (";
- }
- else
- os << endl;
-
- os << strlit (l);
- }
-
- virtual void
- post ()
- {
- if (!first_) // Ignore empty statements.
- os << ");" << endl;
- }
-
- private:
- bool first_;
- };
-
// Query parameter generator. A new instance is created for each
// query, so the customized version can have a counter to implement,
// for example, numbered parameters (e.g., $1, $2, etc). The auto_id()
@@ -1813,7 +1780,7 @@ namespace relational
init_id_image_member_ ("id_", "id"),
init_id_value_member_ ("id"),
schema_drop_ (schema_emitter_),
- schema_create_ (schema_emitter_)
+ schema_create_ (schema_emitter_, pass_)
{
init ();
}
@@ -1827,7 +1794,7 @@ namespace relational
init_id_image_member_ ("id_", "id"),
init_id_value_member_ ("id"),
schema_drop_ (schema_emitter_),
- schema_create_ (schema_emitter_)
+ schema_create_ (schema_emitter_, pass_)
{
init ();
}
@@ -2562,27 +2529,138 @@ namespace relational
os << "}";
}
- // create_schema ()
- //
if (embedded_schema)
+ schema (c);
+ }
+
+ struct schema_emitter: emitter, virtual context
+ {
+ void
+ pass (unsigned short p)
{
- os << "void " << traits << "::" << endl
- << "create_schema (database& db)"
- << "{"
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl;
+ empty_ = true;
+ pass_ = p;
+ new_pass_ = true;
+ }
- schema_drop_->traverse (c);
- schema_create_->traverse (c);
+ // Did this pass produce anything?
+ //
+ bool
+ empty () const
+ {
+ return empty_;
+ }
- os << "}";
+ virtual void
+ pre ()
+ {
+ first_ = true;
+ }
- os << "static const schema_catalog_entry" << endl
- << "schema_catalog_entry_" << flat_name (type) << "_ (" << endl
- << strlit (options.default_schema ()) << "," << endl
- << "&" << traits << "::create_schema);"
- << endl;
+ virtual void
+ line (const string& l)
+ {
+ if (first_)
+ {
+ first_ = false;
+
+ // If this line starts a new pass, then output the
+ // switch/case blocks.
+ //
+ if (new_pass_)
+ {
+ new_pass_ = false;
+ empty_ = false;
+
+ if (pass_ == 0)
+ {
+ os << "switch (pass)"
+ << "{"
+ << "case 0:" << endl
+ << "{";
+ }
+ else
+ {
+ os << "return true;" // One more pass.
+ << "}"
+ << "case " << pass_ << ":" << endl
+ << "{";
+ }
+ }
+
+ os << "db.execute (";
+ }
+ else
+ os << endl;
+
+ os << strlit (l);
+ }
+
+ virtual void
+ post ()
+ {
+ if (!first_) // Ignore empty statements.
+ os << ");" << endl;
}
+
+ private:
+ bool first_;
+ bool empty_;
+ bool new_pass_;
+ unsigned short pass_;
+ };
+
+ virtual void
+ schema (type& c)
+ {
+ string const& type (c.fq_name ());
+ string traits ("access::object_traits< " + type + " >");
+
+ // create_schema ()
+ //
+ os << "bool " << traits << "::" << endl
+ << "create_schema (database& db, unsigned short pass)"
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (db);"
+ << "ODB_POTENTIALLY_UNUSED (pass);"
+ << endl;
+
+ bool close (false);
+
+ // Pass 0.
+ //
+ pass_ = 0;
+ schema_emitter_.pass (pass_);
+ schema_drop_->traverse (c);
+ close = close || !schema_emitter_.empty ();
+
+ // Pass 1.
+ //
+ pass_ = 1;
+ schema_emitter_.pass (pass_);
+ schema_create_->traverse (c);
+ close = close || !schema_emitter_.empty ();
+
+ // Pass 2.
+ //
+ pass_ = 2;
+ schema_emitter_.pass (pass_);
+ schema_create_->traverse (c);
+ close = close || !schema_emitter_.empty ();
+
+ if (close) // Close the last case and the switch block.
+ os << "return false;"
+ << "}" // case
+ << "}"; // switch
+
+ os << "return false;"
+ << "}";
+
+ os << "static const schema_catalog_entry" << endl
+ << "schema_catalog_entry_" << flat_name (type) << "_ (" << endl
+ << strlit (options.default_schema ()) << "," << endl
+ << "&" << traits << "::create_schema);"
+ << endl;
}
virtual void
@@ -2698,6 +2776,7 @@ namespace relational
traversal::names init_value_member_names_;
instance<init_value_member> init_id_value_member_;
+ unsigned short pass_;
schema_emitter schema_emitter_;
instance<schema::class_drop> schema_drop_;
instance<schema::class_create> schema_create_;