From cd44a367fd73293b1c8edc36aa61667ca020a2eb Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 5 Mar 2012 11:59:00 +0200 Subject: Add support for generating schema creation code into separate C++ file --- NEWS | 6 + doc/manual.xhtml | 20 +-- doc/odb-prologue.1 | 7 +- doc/odb-prologue.xhtml | 5 +- odb/context.cxx | 3 + odb/context.hxx | 1 + odb/generator.cxx | 76 +++++++++ odb/makefile | 3 +- odb/option-types.cxx | 1 + odb/option-types.hxx | 1 + odb/options.cli | 42 ++++- odb/relational/generate.hxx | 6 + odb/relational/header.hxx | 2 +- odb/relational/mssql/schema.cxx | 6 +- odb/relational/oracle/schema.cxx | 12 +- odb/relational/schema-source.cxx | 44 +++++ odb/relational/schema-source.hxx | 68 ++++++++ odb/relational/schema.cxx | 8 +- odb/relational/schema.hxx | 344 +++++++++++++++++++++++++++++++++------ odb/relational/source.hxx | 224 +------------------------ 20 files changed, 580 insertions(+), 299 deletions(-) create mode 100644 odb/relational/schema-source.cxx create mode 100644 odb/relational/schema-source.hxx diff --git a/NEWS b/NEWS index f2ec0fd..890eae2 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,12 @@ Version 1.9.0 7.2.1, "Composite Object Ids" in the ODB manual as well as the 'composite' example in the odb-examples package. + * New schema format (--schema-format), 'separate', allows the generation + of the schema creation code into a separate C++ source file (called + 'name-schema.cxx' by default). This value is primarily useful if you + want to place the schema creation functionality into a separate program + or library. + Version 1.8.0 * Support for the Microsoft SQL Server database. The provided connection diff --git a/doc/manual.xhtml b/doc/manual.xhtml index 347c8ef..5060268 100644 --- a/doc/manual.xhtml +++ b/doc/manual.xhtml @@ -2394,16 +2394,16 @@ auto_ptr<odb::database> db (

There are several ways to create the database schema. The easiest is to instruct the ODB compiler to generate the corresponding schema from the persistent classes (--generate-schema option). The ODB - compiler can generate the schema either as a standalone SQL file or - embedded into the generated C++ code (--schema-format - option). If we are using the SQL file to create the database schema, then - this file should be executed, normally only once, before the application - is started.

- -

Alternatively, the schema can be embedded directly into the generated - code and we can use the odb::schema_catalog class to - create it in the database from within our application, - for example:

+ compiler can generate the schema as a standalone SQL file, + embedded into the generated C++ code, or as a separate C++ source file + (--schema-format option). If we are using the SQL file + to create the database schema, then this file should be executed, + normally only once, before the application is started.

+ +

Alternatively, if the schema is embedded directly into the generated + code or produced as a separate C++ source file, then we can use the + odb::schema_catalog class to create it in the database + from within our application, for example:

 #include <odb/schema-catalog.hxx>
diff --git a/doc/odb-prologue.1 b/doc/odb-prologue.1
index ca9d079..78d95c4 100644
--- a/doc/odb-prologue.1
+++ b/doc/odb-prologue.1
@@ -53,7 +53,12 @@ option is specified and the
 .B sql
 schema format is requested, the
 .B name.sql
-database schema file is generated.
+database schema file is generated. If the
+.B separate
+schema format is requested, the database creation code is generated into
+the separate
+.B name-schema.cxx
+file.
 .\"
 .\"
 .\"
diff --git a/doc/odb-prologue.xhtml b/doc/odb-prologue.xhtml
index 79a06eb..46d6e3f 100644
--- a/doc/odb-prologue.xhtml
+++ b/doc/odb-prologue.xhtml
@@ -75,6 +75,9 @@
 
   Additionally, if the --generate-schema option is
   specified and the sql schema format is requested,
-  the name.sql database schema file is generated.

+ the name.sql database schema file is generated. If + the separate schema format is requested, the database + creation code is generated into the separate + name-schema.cxx file.

OPTIONS

diff --git a/odb/context.cxx b/odb/context.cxx index 86cca9d..265d4ca 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -179,6 +179,8 @@ context (ostream& os_, include_regex (data_->include_regex_), embedded_schema (ops.generate_schema () && ops.schema_format ().count (schema_format::embedded)), + separate_schema (ops.generate_schema () && + ops.schema_format ().count (schema_format::separate)), top_object (data_->top_object_), cur_object (data_->cur_object_) { @@ -203,6 +205,7 @@ context () keyword_set (current ().keyword_set), include_regex (current ().include_regex), embedded_schema (current ().embedded_schema), + separate_schema (current ().separate_schema), top_object (current ().top_object), cur_object (current ().cur_object) { diff --git a/odb/context.hxx b/odb/context.hxx index 3865e88..b590ea4 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -818,6 +818,7 @@ public: regex_mapping const& include_regex; bool embedded_schema; + bool separate_schema; // Outermost object or view currently being traversed. // diff --git a/odb/generator.cxx b/odb/generator.cxx index bd5c9d5..2ab272d 100644 --- a/odb/generator.cxx +++ b/odb/generator.cxx @@ -123,11 +123,13 @@ generate (options const& ops, semantics::unit& unit, path const& p) string hxx_name (base + ops.odb_file_suffix () + ops.hxx_suffix ()); string ixx_name (base + ops.odb_file_suffix () + ops.ixx_suffix ()); string cxx_name (base + ops.odb_file_suffix () + ops.cxx_suffix ()); + string sch_name (base + ops.schema_file_suffix () + ops.cxx_suffix ()); string sql_name (base + ops.sql_suffix ()); path hxx_path (hxx_name); path ixx_path (ixx_name); path cxx_path (cxx_name); + path sch_path (sch_name); path sql_path (sql_name); if (!ops.output_dir ().empty ()) @@ -136,6 +138,7 @@ generate (options const& ops, semantics::unit& unit, path const& p) hxx_path = dir / hxx_path; ixx_path = dir / ixx_path; cxx_path = dir / cxx_path; + sch_path = dir / sch_path; sql_path = dir / sql_path; } @@ -198,12 +201,36 @@ generate (options const& ops, semantics::unit& unit, path const& p) auto_rm.add (sql_path); } + // + // + bool sep_schema (ops.generate_schema () && + ops.schema_format ().count (schema_format::separate)); + + ofstream sch; + + if (sep_schema) + { + sch.open (sch_path.string ().c_str (), ios_base::out); + + if (!sch.is_open ()) + { + cerr << "error: unable to open '" << sch_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (sch_path); + } + // Print C++ headers. // hxx << file_header; ixx << file_header; cxx << file_header; + if (sep_schema) + sch << file_header; + typedef compiler::ostream_filter cxx_filter; // Include settings. @@ -367,6 +394,55 @@ generate (options const& ops, semantics::unit& unit, path const& p) cxx << "#include " << endl; } + // SCH + // + if (sep_schema) + { + cxx_filter filt (sch); + auto_ptr ctx (create_context (sch, unit, ops, model.get ())); + + // Copy prologue. + // + sch << "#include " << endl + << endl; + + // Copy prologue. + // + sch << "// Begin prologue." << endl + << "//" << endl; + append (sch, ops.schema_prologue (), ops.schema_prologue_file ()); + sch << "//" << endl + << "// End prologue." << endl + << endl; + + sch << "#include " << ctx->process_include_path (hxx_name) << endl + << endl; + + switch (ops.database ()) + { + case database::mssql: + case database::mysql: + case database::oracle: + case database::pgsql: + case database::sqlite: + { + relational::schema_source::generate (); + break; + } + } + + // Copy epilogue. + // + sch << "// Begin epilogue." << endl + << "//" << endl; + append (sch, ops.schema_epilogue (), ops.schema_epilogue_file ()); + sch << "//" << endl + << "// End epilogue." << endl + << endl; + + sch << "#include " << endl; + } + // SQL // if (sql_schema) diff --git a/odb/makefile b/odb/makefile index 244c302..d048065 100644 --- a/odb/makefile +++ b/odb/makefile @@ -35,7 +35,8 @@ relational/header.cxx \ relational/inline.cxx \ relational/source.cxx \ relational/model.cxx \ -relational/schema.cxx +relational/schema.cxx \ +relational/schema-source.cxx # Relational/MSSQL. # diff --git a/odb/option-types.cxx b/odb/option-types.cxx index 3bbe72e..ceb71db 100644 --- a/odb/option-types.cxx +++ b/odb/option-types.cxx @@ -98,6 +98,7 @@ operator<< (ostream& os, database db) static const char* schema_format_[] = { "embedded", + "separate", "sql" }; diff --git a/odb/option-types.hxx b/odb/option-types.hxx index de3bdb7..66e2f28 100644 --- a/odb/option-types.hxx +++ b/odb/option-types.hxx @@ -72,6 +72,7 @@ struct schema_format // Keep in alphabetic order. // embedded, + separate, sql }; diff --git a/odb/options.cli b/odb/options.cli index f501315..ae72e25 100644 --- a/odb/options.cli +++ b/odb/options.cli @@ -79,6 +79,10 @@ class options "Generate the database schema in the specified format. Pass \cb{sql} as to generate the database schema as a standalone SQL file or pass \cb{embedded} to embed the schema into the generated C++ code. + The \cb{separate} value is similar to \cb{embedded} except the schema + creation code is generated into a separate C++ file (\cb{name-schema.cxx} + by default). This value is primarily useful if you want to place the + schema creation functionality into a separate program or library. Repeat this option to generate the same database schema in multiple formats." }; @@ -188,6 +192,14 @@ class options of the generated C++ files." }; + std::string --schema-file-suffix = "-schema" + { + "", + "Use instead of the default \cb{-schema} to construct the name + of the generated schema C++ source file. See the \cb{--schema-format} + option for details." + }; + std::string --hxx-suffix = ".hxx" { "", @@ -236,6 +248,12 @@ class options "Insert at the beginning of the generated C++ source file." }; + std::vector --schema-prologue + { + "", + "Insert at the beginning of the generated schema C++ source file." + }; + std::vector --sql-prologue { "", @@ -262,6 +280,12 @@ class options "Insert at the end of the generated C++ source file." }; + std::vector --schema-epilogue + { + "", + "Insert at the end of the generated schema C++ source file." + }; + std::vector --sql-epilogue { "", @@ -291,6 +315,13 @@ class options source file." }; + std::string --schema-prologue-file + { + "", + "Insert the content of at the beginning of the generated schema + C++ source file." + }; + std::string --sql-prologue-file { "", @@ -321,6 +352,13 @@ class options file." }; + std::string --schema-epilogue-file + { + "", + "Insert the content of at the end of the generated schema C++ + source file." + }; + std::string --sql-epilogue-file { "", @@ -454,7 +492,7 @@ class options ::mssql_version --mssql-server-version (10, 0) { - "", + "", "Specify the minimum SQL Server server version with which the generated C++ code will be used. This information is used to enable version-specific optimizations and workarounds in the generated C++ @@ -502,7 +540,7 @@ class options ::oracle_version --oracle-client-version (10, 1) { - "", + "", "Specify the minimum Oracle client library (OCI) version with which the generated C++ code will be linked. This information is used to enable version-specific optimizations and workarounds in the generated C++ diff --git a/odb/relational/generate.hxx b/odb/relational/generate.hxx index 685f563..fb29bf4 100644 --- a/odb/relational/generate.hxx +++ b/odb/relational/generate.hxx @@ -29,6 +29,12 @@ namespace relational generate (); } + namespace schema_source + { + void + generate (); + } + namespace model { cutl::shared_ptr diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index dda9e2a..250a07c 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -1308,7 +1308,7 @@ namespace relational // create_schema () // - if (embedded_schema) + if (embedded_schema || separate_schema) { os << "static bool" << endl << "create_schema (database&, unsigned short pass, bool drop);" diff --git a/odb/relational/mssql/schema.cxx b/odb/relational/mssql/schema.cxx index 7f50bf3..52d36ed 100644 --- a/odb/relational/mssql/schema.cxx +++ b/odb/relational/mssql/schema.cxx @@ -19,9 +19,9 @@ namespace relational { namespace relational = relational::schema; - struct schema_emitter: relational::schema_emitter + struct sql_emitter: relational::sql_emitter { - schema_emitter (const base& x): base (x) {} + sql_emitter (const base& x): base (x) {} virtual void post () @@ -34,7 +34,7 @@ namespace relational } } }; - entry schema_emitter_; + entry sql_emitter_; // // Drop. diff --git a/odb/relational/oracle/schema.cxx b/odb/relational/oracle/schema.cxx index a9f5a36..2fd0602 100644 --- a/odb/relational/oracle/schema.cxx +++ b/odb/relational/oracle/schema.cxx @@ -19,9 +19,9 @@ namespace relational { namespace relational = relational::schema; - struct schema_emitter: relational::schema_emitter + struct sql_emitter: relational::sql_emitter { - schema_emitter (const base& x): base (x) {} + sql_emitter (const base& x): base (x) {} virtual void line (const std::string& l) @@ -54,15 +54,15 @@ namespace relational private: string last_; }; - entry schema_emitter_; + entry sql_emitter_; // // File. // - struct schema_file: relational::schema_file, context + struct sql_file: relational::sql_file, context { - schema_file (const base& x): base (x) {} + sql_file (const base& x): base (x) {} virtual void prologue () @@ -82,7 +82,7 @@ namespace relational os << "EXIT;" << endl; } }; - entry schema_file_; + entry sql_file_; // // Drop. diff --git a/odb/relational/schema-source.cxx b/odb/relational/schema-source.cxx new file mode 100644 index 0000000..0acb6c4 --- /dev/null +++ b/odb/relational/schema-source.cxx @@ -0,0 +1,44 @@ +// file : odb/relational/schema-source.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include +#include + +using namespace std; + +namespace relational +{ + namespace schema_source + { + void + generate () + { + context ctx; + ostream& os (ctx.os); + + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + instance c; + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + + instance i; + i->generate (); + + os << "namespace odb" + << "{"; + + unit.dispatch (ctx.unit); + + os << "}"; + } + } +} diff --git a/odb/relational/schema-source.hxx b/odb/relational/schema-source.hxx new file mode 100644 index 0000000..a72b55b --- /dev/null +++ b/odb/relational/schema-source.hxx @@ -0,0 +1,68 @@ +// file : odb/relational/schema-source.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_RELATIONAL_SCHEMA_SOURCE_HXX +#define ODB_RELATIONAL_SCHEMA_SOURCE_HXX + +#include + +#include +#include + +namespace relational +{ + namespace schema_source + { + struct class_: traversal::class_, virtual context + { + typedef class_ base; + + virtual void + traverse (type& c) + { + if (class_file (c) != unit.file () || !object (c) || abstract (c)) + return; + + context::top_object = context::cur_object = &c; + + os << "// " << class_name (c) << endl + << "//" << endl + << endl; + + schema_->traverse (c); + + context::top_object = context::cur_object = 0; + } + + private: + instance schema_; + }; + + struct include: virtual context + { + typedef include base; + + virtual void + generate () + { + extra_pre (); + os << "#include " << endl; + extra_post (); + os << endl; + } + + virtual void + extra_pre () + { + } + + virtual void + extra_post () + { + } + }; + } +} + +#endif // ODB_RELATIONAL_SCHEMA_SOURCE_HXX diff --git a/odb/relational/schema.cxx b/odb/relational/schema.cxx index 05f5949..ea9083d 100644 --- a/odb/relational/schema.cxx +++ b/odb/relational/schema.cxx @@ -17,6 +17,10 @@ namespace relational { namespace schema { + // cxx_object + // + schema_format cxx_object::format_embedded (schema_format::embedded); + static char const file_header[] = "/* This file was generated by ODB, object-relational mapping (ORM)\n" " * compiler for C++.\n" @@ -30,10 +34,10 @@ namespace relational os << file_header; - instance file; + instance file; file->prologue (); - instance em; + instance em; emitter_ostream emos (*em); schema_format f (schema_format::sql); diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx index 7e8d34c..b0ac01f 100644 --- a/odb/relational/schema.hxx +++ b/odb/relational/schema.hxx @@ -54,58 +54,6 @@ namespace relational ostream& os_; }; - struct schema_emitter: emitter, virtual context - { - typedef schema_emitter base; - - virtual void - pre () - { - first_ = true; - } - - virtual void - line (const std::string& l) - { - if (first_ && !l.empty ()) - first_ = false; - else - os << endl; - - os << l; - } - - virtual void - post () - { - if (!first_) // Ignore empty statements. - os << ';' << endl - << endl; - } - - protected: - bool first_; - }; - - // - // File prologue/epilogue. - // - - struct schema_file: virtual context - { - typedef schema_file base; - - virtual void - prologue () - { - } - - virtual void - epilogue () - { - } - }; - // // Drop. // @@ -675,6 +623,298 @@ namespace relational schema_format format_; unsigned short pass_; }; + + // + // SQL output. + // + + struct sql_emitter: emitter, virtual context + { + typedef sql_emitter base; + + virtual void + pre () + { + first_ = true; + } + + virtual void + line (const std::string& l) + { + if (first_ && !l.empty ()) + first_ = false; + else + os << endl; + + os << l; + } + + virtual void + post () + { + if (!first_) // Ignore empty statements. + os << ';' << endl + << endl; + } + + protected: + bool first_; + }; + + struct sql_file: virtual context + { + typedef sql_file base; + + virtual void + prologue () + { + } + + virtual void + epilogue () + { + } + }; + + // + // C++ output. + // + + struct cxx_emitter: emitter, virtual context + { + typedef cxx_emitter base; + + void + pass (unsigned short p) + { + empty_ = true; + pass_ = p; + new_pass_ = true; + } + + // Did this pass produce anything? + // + bool + empty () const + { + return empty_; + } + + virtual void + pre () + { + first_ = true; + } + + virtual void + line (const string& l) + { + if (l.empty ()) + return; // Ignore empty lines. + + 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_ == 1) + { + os << "switch (pass)" + << "{" + << "case 1:" << endl + << "{"; + } + else + { + os << "return true;" // One more pass. + << "}" + << "case " << pass_ << ":" << endl + << "{"; + } + } + + os << "db.execute ("; + } + else + os << strlit (line_ + '\n') << endl; + + line_ = l; + } + + virtual void + post () + { + if (!first_) // Ignore empty statements. + os << strlit (line_) << ");" << endl; + } + + private: + std::string line_; + bool first_; + bool empty_; + bool new_pass_; + unsigned short pass_; + }; + + struct cxx_object: virtual context + { + typedef cxx_object base; + + //@@ (im)-perfect forwarding. + // + static schema_format format_embedded; + + cxx_object () + : stream_ (*emitter_), + drop_model_ (*emitter_, stream_, format_embedded), + drop_table_ (*emitter_, stream_, format_embedded), + drop_index_ (*emitter_, stream_, format_embedded), + create_model_ (*emitter_, stream_, format_embedded), + create_table_ (*emitter_, stream_, format_embedded), + create_index_ (*emitter_, stream_, format_embedded) + { + init (); + } + + cxx_object (cxx_object const&) + : root_context (), //@@ -Wextra + context (), + stream_ (*emitter_), + drop_model_ (*emitter_, stream_, format_embedded), + drop_table_ (*emitter_, stream_, format_embedded), + drop_index_ (*emitter_, stream_, format_embedded), + create_model_ (*emitter_, stream_, format_embedded), + create_table_ (*emitter_, stream_, format_embedded), + create_index_ (*emitter_, stream_, format_embedded) + { + init (); + } + + void + init () + { + drop_model_ >> drop_names_; + drop_names_ >> drop_table_; + drop_names_ >> drop_index_; + + create_model_ >> create_names_; + create_names_ >> create_table_; + create_names_ >> create_index_; + } + + void + traverse (semantics::class_& c) + { + typedef sema_rel::model::names_iterator iterator; + + iterator begin (c.get ("model-range-first")); + iterator end (c.get ("model-range-last")); + + if (begin == model->names_end ()) + return; // This class doesn't have any model entities (e.g., + // a second class mapped to the same table). + + ++end; // Transform the range from [begin, end] to [begin, end). + + string const& type (class_fq_name (c)); + string traits ("access::object_traits< " + type + " >"); + + // create_schema () + // + os << "bool " << traits << "::" << endl + << "create_schema (database& db, unsigned short pass, bool drop)" + << "{" + << "ODB_POTENTIALLY_UNUSED (db);" + << "ODB_POTENTIALLY_UNUSED (pass);" + << endl; + + // Drop. + // + { + bool close (false); + + os << "if (drop)" + << "{"; + + for (unsigned short pass (1); pass < 3; ++pass) + { + emitter_->pass (pass); + drop_model_->pass (pass); + drop_table_->pass (pass); + drop_index_->pass (pass); + + drop_model_->traverse (begin, end); + + close = close || !emitter_->empty (); + } + + if (close) // Close the last case and the switch block. + os << "return false;" + << "}" // case + << "}"; // switch + + os << "}"; + } + + // Create. + // + { + bool close (false); + + os << "else" + << "{"; + + for (unsigned short pass (1); pass < 3; ++pass) + { + emitter_->pass (pass); + create_model_->pass (pass); + create_table_->pass (pass); + create_index_->pass (pass); + + create_model_->traverse (begin, end); + + close = close || !emitter_->empty (); + } + + if (close) // Close the last case and the switch block. + os << "return false;" + << "}" // case + << "}"; // switch + + os << "}"; + } + + os << "return false;" + << "}"; + + os << "static const schema_catalog_entry" << endl + << "schema_catalog_entry_" << flat_name (type) << "_ (" << endl + << strlit (options.schema_name ()) << "," << endl + << "&" << traits << "::create_schema);" + << endl; + } + + private: + instance emitter_; + emitter_ostream stream_; + + trav_rel::qnames drop_names_; + instance drop_model_; + instance drop_table_; + instance drop_index_; + + trav_rel::qnames create_names_; + instance create_model_; + instance create_table_; + instance create_index_; + }; } } diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index ab5220a..fb13ade 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -2665,10 +2664,6 @@ namespace relational query_parameters& qp_; }; - //@@ (im)-perfect forwarding. - // - static schema_format format_embedded (schema_format::embedded); - // // struct class_: traversal::class_, virtual context @@ -2683,14 +2678,7 @@ namespace relational init_id_image_member_ ("id_", "id"), init_version_image_member_ ("version_", "(*v)"), init_id_value_member_ ("id"), - init_version_value_member_ ("v"), - stream_ (emitter_), - drop_model_ (emitter_, stream_, format_embedded), - drop_table_ (emitter_, stream_, format_embedded), - drop_index_ (emitter_, stream_, format_embedded), - create_model_ (emitter_, stream_, format_embedded), - create_table_ (emitter_, stream_, format_embedded), - create_index_ (emitter_, stream_, format_embedded) + init_version_value_member_ ("v") { init (); } @@ -2705,14 +2693,7 @@ namespace relational init_id_image_member_ ("id_", "id"), init_version_image_member_ ("version_", "(*v)"), init_id_value_member_ ("id"), - init_version_value_member_ ("v"), - stream_ (emitter_), - drop_model_ (emitter_, stream_, format_embedded), - drop_table_ (emitter_, stream_, format_embedded), - drop_index_ (emitter_, stream_, format_embedded), - create_model_ (emitter_, stream_, format_embedded), - create_table_ (emitter_, stream_, format_embedded), - create_index_ (emitter_, stream_, format_embedded) + init_version_value_member_ ("v") { init (); } @@ -2734,17 +2715,6 @@ namespace relational init_value_base_inherits_ >> init_value_base_; init_value_member_names_ >> init_value_member_; - - if (embedded_schema) - { - drop_model_ >> drop_names_; - drop_names_ >> drop_table_; - drop_names_ >> drop_index_; - - create_model_ >> create_names_; - create_names_ >> create_table_; - create_names_ >> create_index_; - } } virtual void @@ -4016,180 +3986,7 @@ namespace relational } if (embedded_schema) - schema (c); - } - - struct schema_emitter: emitter, virtual context - { - void - pass (unsigned short p) - { - empty_ = true; - pass_ = p; - new_pass_ = true; - } - - // Did this pass produce anything? - // - bool - empty () const - { - return empty_; - } - - virtual void - pre () - { - first_ = true; - } - - virtual void - line (const string& l) - { - if (l.empty ()) - return; // Ignore empty lines. - - 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_ == 1) - { - os << "switch (pass)" - << "{" - << "case 1:" << endl - << "{"; - } - else - { - os << "return true;" // One more pass. - << "}" - << "case " << pass_ << ":" << endl - << "{"; - } - } - - os << "db.execute ("; - } - else - os << strlit (line_ + '\n') << endl; - - line_ = l; - } - - virtual void - post () - { - if (!first_) // Ignore empty statements. - os << strlit (line_) << ");" << endl; - } - - private: - std::string line_; - bool first_; - bool empty_; - bool new_pass_; - unsigned short pass_; - }; - - virtual void - schema (type& c) - { - typedef sema_rel::model::names_iterator iterator; - - iterator begin (c.get ("model-range-first")); - iterator end (c.get ("model-range-last")); - - if (begin == model->names_end ()) - return; // This class doesn't have any model entities (e.g., - // a second class mapped to the same table). - - ++end; // Transform the range from [begin, end] to [begin, end). - - string const& type (class_fq_name (c)); - string traits ("access::object_traits< " + type + " >"); - - // create_schema () - // - os << "bool " << traits << "::" << endl - << "create_schema (database& db, unsigned short pass, bool drop)" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << "ODB_POTENTIALLY_UNUSED (pass);" - << endl; - - // Drop. - // - { - bool close (false); - - os << "if (drop)" - << "{"; - - for (unsigned short pass (1); pass < 3; ++pass) - { - emitter_.pass (pass); - drop_model_->pass (pass); - drop_table_->pass (pass); - drop_index_->pass (pass); - - drop_model_->traverse (begin, end); - - close = close || !emitter_.empty (); - } - - if (close) // Close the last case and the switch block. - os << "return false;" - << "}" // case - << "}"; // switch - - os << "}"; - } - - // Create. - // - { - bool close (false); - - os << "else" - << "{"; - - for (unsigned short pass (1); pass < 3; ++pass) - { - emitter_.pass (pass); - create_model_->pass (pass); - create_table_->pass (pass); - create_index_->pass (pass); - - create_model_->traverse (begin, end); - - close = close || !emitter_.empty (); - } - - if (close) // Close the last case and the switch block. - os << "return false;" - << "}" // case - << "}"; // switch - - os << "}"; - } - - os << "return false;" - << "}"; - - os << "static const schema_catalog_entry" << endl - << "schema_catalog_entry_" << flat_name (type) << "_ (" << endl - << strlit (options.schema_name ()) << "," << endl - << "&" << traits << "::create_schema);" - << endl; + schema_->traverse (c); } // @@ -5120,9 +4917,7 @@ namespace relational } private: - bool id_; size_t index_; - instance grow_base_; traversal::inherits grow_base_inherits_; instance grow_member_; @@ -5151,18 +4946,7 @@ namespace relational instance init_id_value_member_; instance init_version_value_member_; - schema_emitter emitter_; - emitter_ostream stream_; - - trav_rel::qnames drop_names_; - instance drop_model_; - instance drop_table_; - instance drop_index_; - - trav_rel::qnames create_names_; - instance create_model_; - instance create_table_; - instance create_index_; + instance schema_; }; struct include: virtual context -- cgit v1.1