From fe69d94f3d2dcb37d69ac2d7a0f88ad5fce2ad5c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 1 Mar 2011 11:56:33 +0200 Subject: Add support for embedded database schemas New options: --schema-format, --default-schema. New example: schema/embedded. --- odb/mysql/context.cxx | 7 + odb/mysql/context.hxx | 1 + odb/mysql/header.cxx | 9 ++ odb/mysql/schema.cxx | 339 ----------------------------------------------- odb/mysql/schema.hxx | 314 ++++++++++++++++++++++++++++++++++++++++++- odb/mysql/source.cxx | 78 ++++++++++- odb/mysql/sql-schema.cxx | 98 ++++++++++++++ odb/mysql/sql-schema.hxx | 17 +++ 8 files changed, 516 insertions(+), 347 deletions(-) create mode 100644 odb/mysql/sql-schema.cxx create mode 100644 odb/mysql/sql-schema.hxx (limited to 'odb/mysql') diff --git a/odb/mysql/context.cxx b/odb/mysql/context.cxx index 3b00c96..6a218af 100644 --- a/odb/mysql/context.cxx +++ b/odb/mysql/context.cxx @@ -77,6 +77,13 @@ namespace mysql { } + context:: + context (context& c, ostream& os) + : base_context (c, os), + data_ (c.data_) + { + } + namespace { struct has_grow: traversal::class_ diff --git a/odb/mysql/context.hxx b/odb/mysql/context.hxx index 0dfb3ba..05b6639 100644 --- a/odb/mysql/context.hxx +++ b/odb/mysql/context.hxx @@ -120,6 +120,7 @@ namespace mysql public: context (std::ostream&, semantics::unit&, options_type const&); context (context&); + context (context&, std::ostream&); }; } diff --git a/odb/mysql/header.cxx b/odb/mysql/header.cxx index 12f3e4d..59793b0 100644 --- a/odb/mysql/header.cxx +++ b/odb/mysql/header.cxx @@ -901,6 +901,15 @@ namespace mysql << "query (database&, const query_type&);" << endl; + // create_schema () + // + if (embedded_schema) + { + os << "static void" << endl + << "create_schema (database&);" + << endl; + } + // Implementation details. // os << "public:" << endl; diff --git a/odb/mysql/schema.cxx b/odb/mysql/schema.cxx index 686272c..b40a019 100644 --- a/odb/mysql/schema.cxx +++ b/odb/mysql/schema.cxx @@ -3,348 +3,9 @@ // copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file -#include - -#include #include -using namespace std; - namespace mysql { - namespace - { - typedef set tables; - - struct object_columns: object_columns_base, context - { - object_columns (context& c, string const& prefix = string ()) - : object_columns_base (c), context (c), prefix_ (prefix) - { - } - - virtual bool - column (semantics::data_member& m, string const& name, bool first) - { - // Ignore inverse object pointers. - // - if (inverse (m)) - return false; - - if (!first) - os << "," << endl; - - os << " `" << name << "` " << column_type (m, prefix_); - - if (m.count ("id")) - os << " PRIMARY KEY"; - - using semantics::class_; - if (class_* c = object_pointer (member_type (m, prefix_))) - { - os << " REFERENCES `" << table_name (*c) << "` (`" << - column_name (id_member (*c)) << "`)"; - } - - return true; - } - - private: - string prefix_; - }; - - struct member_create: object_members_base, context - { - member_create (context& c, semantics::class_& object, tables& t) - : object_members_base (c, false, true), - context (c), - object_ (object), - id_member_ (id_member (object)), - tables_ (t) - { - } - - virtual void - container (semantics::data_member& m) - { - using semantics::type; - using semantics::data_member; - - // Ignore inverse containers of object pointers. - // - if (inverse (m, "value")) - return; - - type& t (m.type ()); - container_kind_type ck (container_kind (t)); - type& vt (container_vt (t)); - - string const& name (table_name (m, table_prefix_)); - - if (tables_.count (name)) - return; - - os << "CREATE TABLE `" << name << "` (" << endl; - - // object_id (simple value) - // - string id_name (column_name (m, "id", "object_id")); - os << " `" << id_name << "` " << column_type (id_member_, "ref"); - - // index (simple value) - // - string index_name; - bool ordered (ck == ck_ordered && !unordered (m)); - if (ordered) - { - index_name = column_name (m, "index", "index"); - - os << "," << endl - << " `" << index_name << "` " << column_type (m, "index"); - } - - // key (simple or composite value) - // - if (ck == ck_map || ck == ck_multimap) - { - type& kt (container_kt (t)); - - os << "," << endl; - - if (semantics::class_* ckt = comp_value (kt)) - { - object_columns oc (*this); - oc.traverse_composite (m, *ckt, "key", "key"); - } - else - { - object_columns oc (*this, "key"); - string const& name (column_name (m, "key", "key")); - oc.column (m, name, true); - } - } - - // value (simple or composite value) - // - { - os << "," << endl; - - if (semantics::class_* cvt = comp_value (vt)) - { - object_columns oc (*this); - oc.traverse_composite (m, *cvt, "value", "value"); - } - else - { - object_columns oc (*this, "value"); - string const& name (column_name (m, "value", "value")); - oc.column (m, name, true); - } - } - - // object_id index - // - os << "," << endl - << " INDEX (`" << id_name << "`)"; - - // index index - // - if (ordered) - os << "," << endl - << " INDEX (`" << index_name << "`)"; - - os << ")"; - - string const& engine (options.mysql_engine ()); - - if (engine != "default") - os << endl - << " ENGINE=" << engine; - - os << ";" << endl - << endl; - - tables_.insert (name); - } - - private: - semantics::class_& object_; - semantics::data_member& id_member_; - tables& tables_; - }; - - struct class_create: traversal::class_, context - { - class_create (context& c) - : context (c) - { - } - - virtual void - traverse (type& c) - { - if (c.file () != unit.file ()) - return; - - if (!c.count ("object")) - return; - - string const& name (table_name (c)); - - // If the table with this name was already created, assume the - // user knows what they are doing and skip it. - // - if (tables_.count (name)) - return; - - os << "CREATE TABLE `" << name << "` (" << endl; - - { - object_columns oc (*this); - oc.traverse (c); - } - - os << ")"; - - string const& engine (options.mysql_engine ()); - - if (engine != "default") - os << endl - << " ENGINE=" << engine; - - os << ";" << endl - << endl; - - // Create tables for members. - // - { - member_create mc (*this, c, tables_); - mc.traverse (c); - } - - tables_.insert (name); - } - - private: - tables tables_; - }; - - struct member_drop: object_members_base, context - { - member_drop (context& c, semantics::class_& object, tables& t) - : object_members_base (c, false, true), - context (c), - object_ (object), - tables_ (t) - { - } - - virtual void - container (semantics::data_member& m) - { - // Ignore inverse containers of object pointers. - // - if (inverse (m, "value")) - return; - - string const& name (table_name (m, table_prefix_)); - - if (tables_.count (name)) - return; - - os << "DROP TABLE IF EXISTS `" << name << "`;" << endl; - tables_.insert (name); - } - - private: - semantics::class_& object_; - tables& tables_; - }; - - struct class_drop: traversal::class_, context - { - class_drop (context& c) - : context (c) - { - } - - virtual void - traverse (type& c) - { - if (c.file () != unit.file ()) - return; - - if (!c.count ("object")) - return; - - string const& name (table_name (c)); - - if (tables_.count (name)) - return; - - os << "DROP TABLE IF EXISTS `" << name << "`;" << endl; - - // Drop tables for members. - // - { - member_drop mc (*this, c, tables_); - mc.traverse (c); - } - - tables_.insert (name); - } - - private: - tables tables_; - }; - - static char const file_header[] = - "/* This file was generated by ODB, object-relational mapping (ORM)\n" - " * compiler for C++.\n" - " */\n\n"; - } - - void - generate_schema (context& ctx) - { - ctx.os << file_header; - - // Drop. - // - { - traversal::unit unit; - traversal::defines unit_defines; - traversal::namespace_ ns; - class_drop c (ctx); - - unit >> unit_defines >> ns; - unit_defines >> c; - - traversal::defines ns_defines; - - ns >> ns_defines >> ns; - ns_defines >> c; - unit.dispatch (ctx.unit); - } - - ctx.os << endl; - - // Create. - // - { - traversal::unit unit; - traversal::defines unit_defines; - traversal::namespace_ ns; - class_create c (ctx); - - unit >> unit_defines >> ns; - unit_defines >> c; - - traversal::defines ns_defines; - ns >> ns_defines >> ns; - ns_defines >> c; - unit.dispatch (ctx.unit); - } - } } diff --git a/odb/mysql/schema.hxx b/odb/mysql/schema.hxx index e221c92..1defad7 100644 --- a/odb/mysql/schema.hxx +++ b/odb/mysql/schema.hxx @@ -6,12 +6,320 @@ #ifndef ODB_MYSQL_SCHEMA_HXX #define ODB_MYSQL_SCHEMA_HXX -#include +#include + +#include +#include namespace mysql { - void - generate_schema (context&); + struct schema_context: context + { + typedef std::set tables; + + schema_context (context& c, std::ostream& os, emitter& e) + : context (c, os), e_ (e) + { + } + + schema_context (schema_context& c) : context (c), e_ (c.e_) {} + + emitter& e_; + }; + + // + // Drop. + // + + struct member_drop: object_members_base, schema_context + { + member_drop (schema_context& c, tables& t) + : object_members_base (c, false, true), + schema_context (c), + tables_ (t) + { + } + + virtual void + container (semantics::data_member& m) + { + // Ignore inverse containers of object pointers. + // + if (inverse (m, "value")) + return; + + string const& name (table_name (m, table_prefix_)); + + if (tables_.count (name)) + return; + + e_.pre (); + os << "DROP TABLE IF EXISTS `" << name << "`" << endl; + e_.post (); + + tables_.insert (name); + } + + private: + tables& tables_; + }; + + struct class_drop: traversal::class_, schema_context + { + class_drop (context& c, emitter& e) + : schema_context (c, os, e), os (e), + member_drop_ (*this, tables_) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (!c.count ("object")) + return; + + string const& name (table_name (c)); + + if (tables_.count (name)) + return; + + e_.pre (); + os << "DROP TABLE IF EXISTS `" << name << "`" << endl; + e_.post (); + + tables_.insert (name); + + // Drop tables for members. + // + member_drop_.traverse (c); + } + + private: + tables tables_; + emitter_ostream os; + member_drop member_drop_; + }; + + // + // Create. + // + + struct object_columns: object_columns_base, schema_context + { + object_columns (schema_context& c, string const& prefix = string ()) + : object_columns_base (c), schema_context (c), prefix_ (prefix) + { + } + + virtual bool + column (semantics::data_member& m, string const& name, bool first) + { + // Ignore inverse object pointers. + // + if (inverse (m)) + return false; + + if (!first) + os << "," << endl; + + os << " `" << name << "` " << column_type (m, prefix_); + + if (m.count ("id")) + os << " PRIMARY KEY"; + + using semantics::class_; + if (class_* c = object_pointer (member_type (m, prefix_))) + { + os << " REFERENCES `" << table_name (*c) << "` (`" << + column_name (id_member (*c)) << "`)"; + } + + return true; + } + + private: + string prefix_; + }; + + struct member_create: object_members_base, schema_context + { + member_create (schema_context& c, semantics::class_& object, tables& t) + : object_members_base (c, false, true), + schema_context (c), + id_member_ (id_member (object)), + tables_ (t) + { + } + + virtual void + container (semantics::data_member& m) + { + using semantics::type; + using semantics::data_member; + + // Ignore inverse containers of object pointers. + // + if (inverse (m, "value")) + return; + + type& t (m.type ()); + container_kind_type ck (container_kind (t)); + type& vt (container_vt (t)); + + string const& name (table_name (m, table_prefix_)); + + if (tables_.count (name)) + return; + + e_.pre (); + os << "CREATE TABLE `" << name << "` (" << endl; + + // object_id (simple value) + // + string id_name (column_name (m, "id", "object_id")); + os << " `" << id_name << "` " << column_type (id_member_, "ref"); + + // index (simple value) + // + string index_name; + bool ordered (ck == ck_ordered && !unordered (m)); + if (ordered) + { + index_name = column_name (m, "index", "index"); + + os << "," << endl + << " `" << index_name << "` " << column_type (m, "index"); + } + + // key (simple or composite value) + // + if (ck == ck_map || ck == ck_multimap) + { + type& kt (container_kt (t)); + + os << "," << endl; + + if (semantics::class_* ckt = comp_value (kt)) + { + object_columns oc (*this); + oc.traverse_composite (m, *ckt, "key", "key"); + } + else + { + object_columns oc (*this, "key"); + string const& name (column_name (m, "key", "key")); + oc.column (m, name, true); + } + } + + // value (simple or composite value) + // + { + os << "," << endl; + + if (semantics::class_* cvt = comp_value (vt)) + { + object_columns oc (*this); + oc.traverse_composite (m, *cvt, "value", "value"); + } + else + { + object_columns oc (*this, "value"); + string const& name (column_name (m, "value", "value")); + oc.column (m, name, true); + } + } + + // object_id index + // + os << "," << endl + << " INDEX (`" << id_name << "`)"; + + // index index + // + if (ordered) + os << "," << endl + << " INDEX (`" << index_name << "`)"; + + os << ")"; + + string const& engine (options.mysql_engine ()); + + if (engine != "default") + os << endl + << " ENGINE=" << engine; + + os << endl; + e_.post (); + + tables_.insert (name); + } + + private: + semantics::data_member& id_member_; + tables& tables_; + }; + + struct class_create: traversal::class_, schema_context + { + class_create (context& c, emitter& e) + : schema_context (c, os, e), os (e) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (!c.count ("object")) + return; + + string const& name (table_name (c)); + + // If the table with this name was already created, assume the + // user knows what they are doing and skip it. + // + if (tables_.count (name)) + return; + + e_.pre (); + os << "CREATE TABLE `" << name << "` (" << endl; + + { + object_columns oc (*this); + oc.traverse (c); + } + + os << ")"; + + string const& engine (options.mysql_engine ()); + + if (engine != "default") + os << endl + << " ENGINE=" << engine; + + os << endl; + e_.post (); + + tables_.insert (name); + + // Create tables for members. + // + { + member_create mc (*this, c, tables_); + mc.traverse (c); + } + } + + private: + tables tables_; + emitter_ostream os; + }; } #endif // ODB_MYSQL_SCHEMA_HXX diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx index fece2e5..bc7340a 100644 --- a/odb/mysql/source.cxx +++ b/odb/mysql/source.cxx @@ -11,6 +11,7 @@ #include #include +#include #include using namespace std; @@ -19,6 +20,38 @@ namespace mysql { namespace { + struct schema_emitter: emitter, context + { + schema_emitter (context& c): context (c) {} + + virtual void + pre () + { + first_ = true; + os << "db.execute ("; + } + + virtual void + line (const std::string& l) + { + if (first_) + first_ = false; + else + os << endl; + + os << strlit (l); + } + + virtual void + post () + { + os << ");" << endl; + } + + private: + bool first_; + }; + struct object_columns: object_columns_base, context { object_columns (context& c, @@ -2398,7 +2431,11 @@ namespace mysql init_id_image_member_ (c, "id_", "id"), init_value_base_ (c), init_value_member_ (c), - init_id_value_member_ (c, "id") + init_id_value_member_ (c, "id"), + + schema_emitter_ (c), + schema_drop_ (c, schema_emitter_), + schema_create_ (c, schema_emitter_) { grow_base_inherits_ >> grow_base_; grow_member_names_ >> grow_member_; @@ -3008,8 +3045,7 @@ namespace mysql << "return result (r);" << "}"; - os << "void" << endl - << traits << "::" << endl + os << "void " << traits << "::" << endl << "query_ (database&," << endl << "const query_type& q," << endl << "mysql::object_statements< object_type >& sts," @@ -3034,6 +3070,26 @@ namespace mysql << "st->execute ();" << "}"; } + + // create_schema () + // + if (embedded_schema) + { + os << "void " << traits << "::" << endl + << "create_schema (database& db)" + << "{"; + + schema_drop_.traverse (c); + schema_create_.traverse (c); + + os << "}"; + + 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 @@ -3141,6 +3197,10 @@ namespace mysql init_value_member init_value_member_; traversal::names init_value_member_names_; init_value_member init_id_value_member_; + + schema_emitter schema_emitter_; + class_drop schema_drop_; + class_create schema_create_; }; } @@ -3160,9 +3220,17 @@ namespace mysql ns >> ns_defines >> ns; ns_defines >> c; - ctx.os << "#include " << endl - << endl; + // + // + ctx.os << "#include " << endl; + if (ctx.embedded_schema) + ctx.os << "#include " << endl; + + ctx.os << endl; + + // + // ctx.os << "#include " << endl << "#include " << endl << "#include " << endl diff --git a/odb/mysql/sql-schema.cxx b/odb/mysql/sql-schema.cxx new file mode 100644 index 0000000..7c71b24 --- /dev/null +++ b/odb/mysql/sql-schema.cxx @@ -0,0 +1,98 @@ +// file : odb/mysql/sql-schema.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include +#include +#include + +using namespace std; + +namespace mysql +{ + namespace + { + struct schema_emitter: emitter, context + { + schema_emitter (context& c): context (c) {} + + virtual void + pre () + { + first_ = true; + } + + virtual void + line (const std::string& l) + { + if (first_) + first_ = false; + else + os << endl; + + os << l; + } + + virtual void + post () + { + os << ';' << endl + << endl; + } + + private: + bool first_; + }; + + static char const file_header[] = + "/* This file was generated by ODB, object-relational mapping (ORM)\n" + " * compiler for C++.\n" + " */\n\n"; + } + + void + generate_schema (context& ctx) + { + ctx.os << file_header; + schema_emitter emitter (ctx); + + // Drop. + // + { + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + class_drop c (ctx, emitter); + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + unit.dispatch (ctx.unit); + } + + ctx.os << endl; + + // Create. + // + { + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + class_create c (ctx, emitter); + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + unit.dispatch (ctx.unit); + } + } +} diff --git a/odb/mysql/sql-schema.hxx b/odb/mysql/sql-schema.hxx new file mode 100644 index 0000000..fdbdf28 --- /dev/null +++ b/odb/mysql/sql-schema.hxx @@ -0,0 +1,17 @@ +// file : odb/mysql/sql-schema.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_MYSQL_SQL_SCHEMA_HXX +#define ODB_MYSQL_SQL_SCHEMA_HXX + +#include + +namespace mysql +{ + void + generate_schema (context&); +} + +#endif // ODB_MYSQL_SQL_SCHEMA_HXX -- cgit v1.1