From 5d33aeaa327f53c920a65302925090debdfc80b8 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 5 Jul 2011 18:39:09 +0200 Subject: Add support for multi-pass database schema generation --- odb/relational/header.hxx | 4 +- odb/relational/schema.cxx | 14 +++- odb/relational/schema.hxx | 30 ++++++-- odb/relational/source.hxx | 179 +++++++++++++++++++++++++++++++++------------- 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 c (emitter); + + unsigned short pass (1); + instance 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_; }; } 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_id_value_member_; + unsigned short pass_; schema_emitter schema_emitter_; instance schema_drop_; instance schema_create_; -- cgit v1.1