summaryrefslogtreecommitdiff
path: root/odb/mysql
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-03-01 11:56:33 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-03-01 11:56:33 +0200
commitfe69d94f3d2dcb37d69ac2d7a0f88ad5fce2ad5c (patch)
treed93f7ea21f66e9fe416c48766b99f987ad7b3804 /odb/mysql
parent6c97eb68924e7f9ea5b0d859182562ec8f812a1e (diff)
Add support for embedded database schemas
New options: --schema-format, --default-schema. New example: schema/embedded.
Diffstat (limited to 'odb/mysql')
-rw-r--r--odb/mysql/context.cxx7
-rw-r--r--odb/mysql/context.hxx1
-rw-r--r--odb/mysql/header.cxx9
-rw-r--r--odb/mysql/schema.cxx339
-rw-r--r--odb/mysql/schema.hxx314
-rw-r--r--odb/mysql/source.cxx78
-rw-r--r--odb/mysql/sql-schema.cxx98
-rw-r--r--odb/mysql/sql-schema.hxx17
8 files changed, 516 insertions, 347 deletions
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 <set>
-
-#include <odb/mysql/common.hxx>
#include <odb/mysql/schema.hxx>
-using namespace std;
-
namespace mysql
{
- namespace
- {
- typedef set<string> 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 <odb/mysql/context.hxx>
+#include <set>
+
+#include <odb/emitter.hxx>
+#include <odb/mysql/common.hxx>
namespace mysql
{
- void
- generate_schema (context&);
+ struct schema_context: context
+ {
+ typedef std::set<string> 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 <sstream>
#include <odb/mysql/common.hxx>
+#include <odb/mysql/schema.hxx>
#include <odb/mysql/source.hxx>
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<const object_type> (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 <odb/cache-traits.hxx>" << endl
- << endl;
+ //
+ //
+ ctx.os << "#include <odb/cache-traits.hxx>" << endl;
+ if (ctx.embedded_schema)
+ ctx.os << "#include <odb/schema-catalog-impl.hxx>" << endl;
+
+ ctx.os << endl;
+
+ //
+ //
ctx.os << "#include <odb/mysql/mysql.hxx>" << endl
<< "#include <odb/mysql/traits.hxx>" << endl
<< "#include <odb/mysql/database.hxx>" << 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 <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/mysql/common.hxx>
+#include <odb/mysql/schema.hxx>
+#include <odb/mysql/sql-schema.hxx>
+
+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 <boris@codesynthesis.com>
+// 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 <odb/mysql/context.hxx>
+
+namespace mysql
+{
+ void
+ generate_schema (context&);
+}
+
+#endif // ODB_MYSQL_SQL_SCHEMA_HXX