aboutsummaryrefslogtreecommitdiff
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
parent6c97eb68924e7f9ea5b0d859182562ec8f812a1e (diff)
Add support for embedded database schemas
New options: --schema-format, --default-schema. New example: schema/embedded.
-rw-r--r--NEWS17
-rw-r--r--doc/manual.xhtml100
-rw-r--r--doc/odb-prologue.14
-rw-r--r--doc/odb-prologue.xhtml4
-rw-r--r--odb/context.cxx188
-rw-r--r--odb/context.hxx16
-rw-r--r--odb/database.cxx51
-rw-r--r--odb/emitter.cxx36
-rw-r--r--odb/emitter.hxx49
-rw-r--r--odb/generator.cxx8
-rw-r--r--odb/makefile9
-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
-rw-r--r--odb/option-functions.cxx36
-rw-r--r--odb/option-functions.hxx14
-rw-r--r--odb/option-types.cxx93
-rw-r--r--odb/option-types.hxx (renamed from odb/database.hxx)36
-rw-r--r--odb/options.cli40
-rw-r--r--odb/plugin.cxx9
25 files changed, 1146 insertions, 427 deletions
diff --git a/NEWS b/NEWS
index c489179..0a005a1 100644
--- a/NEWS
+++ b/NEWS
@@ -11,10 +11,19 @@ Version 1.2.0
using namespace odb;
The new approach brings all the essential ODB names into the current
- namespace without any of the auxiliary objects such as traits, etc.,
- which minimizes the likelihood of conflicts with other libraries.
- Note that you can still use the odb namespace when qualifying
- individual names, for example, odb::database.
+ namespace without any of the auxiliary objects such as traits, etc., which
+ minimizes the likelihood of conflicts with other libraries. Note that you
+ can still use the odb namespace when qualifying individual names, for
+ example, odb::database.
+
+ * Support for embedded database schemas. The new option, --schema-format,
+ allows the selection of the schema format. The valid values for this
+ option are 'sql' for a standalone SQL file and 'embedded' for a schema
+ embedded into the generated C++ code. The new odb::schema_catalog class
+ provides support for accessing embedded schemas from within the
+ application. For details refer to Section 3.3, "Database" in the ODB
+ manual as well as the 'schema/embedded' example in the odb-examples
+ package.
* New exceptions: odb::recoverbale, odb::connection_lost, and odb::timeout.
The odb::recoverbale exception is a common base class for all recoverable
diff --git a/doc/manual.xhtml b/doc/manual.xhtml
index fd14163..f244dc5 100644
--- a/doc/manual.xhtml
+++ b/doc/manual.xhtml
@@ -1046,10 +1046,16 @@ mysql --user=odb_test --database=odb_test &lt; person.sql
<p>The above command will log in to a local MySQL server as user
<code>odb_test</code> without a password and use the database
- named <code>odb_test</code>. Note that after executing this
+ named <code>odb_test</code>. Beware that after executing this
command, all the data stored in the <code>odb_test</code> database
will be deleted.</p>
+ <p>Note also that using a standalone generated SQL file is not the
+ only way to create a database schema in ODB. We can also embed
+ the schema directly into our application or use custom schemas
+ that were not generated by the ODB compiler. Refer to
+ <a href="#3.3">Section 3.3, "Database"</a> for details.</p>
+
<p>Once the database schema is ready, we run our application
using the same login and database name:</p>
@@ -1916,6 +1922,80 @@ auto_ptr&lt;odb::database> db (
system-specific <code>database</code> classes, refer to
<a href="#10">Chapter 10, "Database Systems"</a>.</p>
+ <p>Before we can persist our objects, the corresponding database schema has
+ to be created in the database. The schema contains table definitions and
+ other relational database artifacts that are used to store the state of
+ persistent objects in the database.</p>
+
+ <p>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 (<code>--generate-schema</code> option). The ODB
+ compiler can generate the schema either as a standalone SQL file or
+ embedded into the generated C++ code (<code>--schema-format</code>
+ 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.</p>
+
+ <p>Alternatively, the schema can be embedded directly into the generated
+ code and we can use the <code>odb::schema_catalog</code> class to
+ create it in the database from within our application,
+ for example:</p>
+
+ <pre class="c++">
+#include &lt;odb/schema-catalog.hxx>
+
+odb::transaction t (db->begin ());
+odb::schema_catalog::create_schema (*db);
+t.commit ();
+ </pre>
+
+ <p>Refer to the next section for information on the
+ <code>odb::transaction</code> class. The complete version of the above
+ code fragment is available in the <code>schema/embedded</code> example in
+ the <code>odb-examples</code> package.</p>
+
+ <p>The <code>odb::schema_catalog</code> class has the following interface.
+ You will need to include the <code>&lt;odb/schema-catalog.hxx></code>
+ header file to make this class available in your application.</p>
+
+ <pre class="c++">
+namespace odb
+{
+ class schema_catalog
+ {
+ public:
+ static void
+ create_schema (database&amp;, const std::string&amp; name = "");
+ };
+}
+ </pre>
+
+ <p>The first argument to the <code>create_schema()</code> function
+ is the database instance that we would like to create the schema in.
+ The second argument is the schema name. By default, the ODB
+ compiler generates all embedded schemas with the default schema
+ name (empty string). However, if your application needs to
+ have several separate schemas, you can use the
+ <code>--default-schema</code> ODB compiler option to assign
+ custom schema names and then use these names as a second argument
+ to <code>create_schema()</code>. If the schema is not found,
+ <code>create_schema()</code> throws the
+ <code>odb::unknown_schema</code> exception. The
+ <code>create_schema()</code> function should be called within
+ a transaction.</p>
+
+ <p>Finally, we can also use a custom database schema with ODB. This approach
+ can work similarly to the standalone SQL file described above except that
+ the database schema is hand-written or produced by another program. Or we
+ could execute custom SQL statements that create the schema directly from
+ our application. To map persistent classes to custom database schemas, ODB
+ provides a wide range of mapping customization pragmas, such
+ as <code>db&nbsp;table</code>, <code>db&nbsp;column</code>,
+ and <code>db&nbsp;type</code> (<a href="#9">Chapter 9, "ODB Pragma
+ Language"</a>). For sample code that shows how to perform such mapping
+ for various C++ constructs, refer to the <code>schema/custom</code>
+ example in the <code>odb-examples</code> package.</p>
+
<h2><a name="3.4">3.4 Transactions</a></h2>
<p>A transaction is an atomic, consistent, isolated and durable
@@ -2615,6 +2695,17 @@ namespace odb
struct database_exception: exception
{
};
+
+ // Schema catalog exceptions.
+ //
+ struct unknown_schema: exception
+ {
+ const std::string&amp;
+ name () const;
+
+ virtual const char*
+ what () const throw ();
+ };
}
</pre>
@@ -2663,11 +2754,16 @@ namespace odb
the query result class. Refer to <a href="#4.4">Section 4.4,
"Query Result"</a> for details.</p>
- <p>The <code>database_exception</code> is a base class for all
+ <p>The <code>database_exception</code> exception is a base class for all
database system-specific exceptions that are thrown by the
database system-specific runtime library. See <a href="#10">Chapter
10, "Database Systems"</a> for more information.</p>
+ <p>The <code>unknown_schema</code> exception is thrown by the
+ <code>odb::schema_catalog</code> class if a schema with the specified
+ name is not found. Refer to <a href="#3.3">Section 3.3, "Database"</a>
+ for details.</p>
+
<p>The <code>odb::exception</code> class is defined in the
<code>&lt;odb/exception.hxx></code> header file. All the
concrete ODB exceptions are defined in
diff --git a/doc/odb-prologue.1 b/doc/odb-prologue.1
index 0eb3fb4..7610917 100644
--- a/doc/odb-prologue.1
+++ b/doc/odb-prologue.1
@@ -49,7 +49,9 @@ option is specified), and
.B name-odb.cxx
(source file). Additionally, if the
.B --generate-schema
-option is specified and the target database supports it, the
+option is specified and the
+.B sql
+schema format is requested, the
.B name.sql
database schema file is generated.
.\"
diff --git a/doc/odb-prologue.xhtml b/doc/odb-prologue.xhtml
index d3edc41..61826e2 100644
--- a/doc/odb-prologue.xhtml
+++ b/doc/odb-prologue.xhtml
@@ -74,7 +74,7 @@
<code><b>name-odb.cxx</b></code> (source file).
Additionally, if the <code><b>--generate-schema</b></code> option is
- specified and the target database supports it, the <code><b>name.sql</b></code> database
- schema file is generated.</p>
+ specified and the <code><b>sql</b></code> schema format is requested,
+ the <code><b>name.sql</b></code> database schema file is generated.</p>
<h1>OPTIONS</h1>
diff --git a/odb/context.cxx b/odb/context.cxx
index 580b54c..8b07da5 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -3,6 +3,8 @@
// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <cctype> // std::is{alpha,upper,lower}
+
#include <odb/context.hxx>
#include <odb/common.hxx>
@@ -99,7 +101,9 @@ context (ostream& os_,
os (os_),
unit (u),
options (ops),
- keyword_set (data_->keyword_set_)
+ keyword_set (data_->keyword_set_),
+ embedded_schema (ops.generate_schema () &&
+ ops.schema_format ().count (schema_format::embedded))
{
for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i)
data_->keyword_set_.insert (keywords[i]);
@@ -111,7 +115,19 @@ context (context& c)
os (c.os),
unit (c.unit),
options (c.options),
- keyword_set (c.keyword_set)
+ keyword_set (c.keyword_set),
+ embedded_schema (c.embedded_schema)
+{
+}
+
+context::
+context (context& c, ostream& os_)
+ : data_ (c.data_),
+ os (os_),
+ unit (c.unit),
+ options (c.options),
+ keyword_set (c.keyword_set),
+ embedded_schema (c.embedded_schema)
{
}
@@ -263,6 +279,29 @@ public_name (semantics::data_member& m) const
}
string context::
+flat_name (string const& fq)
+{
+ string r;
+ r.reserve (fq.size ());
+
+ for (string::size_type i (0), n (fq.size ()); i < n; ++i)
+ {
+ char c (fq[i]);
+
+ if (c == ':')
+ {
+ if (!r.empty ())
+ r += '_';
+ ++i; // Skip the second ':'.
+ }
+ else
+ r += c;
+ }
+
+ return r;
+}
+
+string context::
escape (string const& name) const
{
typedef string::size_type size;
@@ -336,6 +375,151 @@ escape (string const& name) const
return r;
}
+static string
+charlit (unsigned int u)
+{
+ string r ("\\x");
+ bool lead (true);
+
+ for (short i (7); i >= 0; --i)
+ {
+ unsigned int x ((u >> (i * 4)) & 0x0F);
+
+ if (lead)
+ {
+ if (x == 0)
+ continue;
+
+ lead = false;
+ }
+
+ r += static_cast<char> (x < 10 ? ('0' + x) : ('A' + x - 10));
+ }
+
+ return r;
+}
+
+static string
+strlit_ascii (string const& str)
+{
+ string r;
+ string::size_type n (str.size ());
+
+ // In most common cases we will have that many chars.
+ //
+ r.reserve (n + 2);
+
+ r += '"';
+
+ bool escape (false);
+
+ for (string::size_type i (0); i < n; ++i)
+ {
+ unsigned int u (static_cast<unsigned int> (str[i]));
+
+ // [128 - ] - unrepresentable
+ // 127 - \x7F
+ // [32 - 126] - as is
+ // [0 - 31] - \X or \xXX
+ //
+
+ if (u < 32 || u == 127)
+ {
+ switch (u)
+ {
+ case '\n':
+ {
+ r += "\\n";
+ break;
+ }
+ case '\t':
+ {
+ r += "\\t";
+ break;
+ }
+ case '\v':
+ {
+ r += "\\v";
+ break;
+ }
+ case '\b':
+ {
+ r += "\\b";
+ break;
+ }
+ case '\r':
+ {
+ r += "\\r";
+ break;
+ }
+ case '\f':
+ {
+ r += "\\f";
+ break;
+ }
+ case '\a':
+ {
+ r += "\\a";
+ break;
+ }
+ default:
+ {
+ r += charlit (u);
+ escape = true;
+ break;
+ }
+ }
+ }
+ else if (u < 127)
+ {
+ if (escape)
+ {
+ // Close and open the string so there are no clashes.
+ //
+ r += '"';
+ r += '"';
+
+ escape = false;
+ }
+
+ switch (u)
+ {
+ case '"':
+ {
+ r += "\\\"";
+ break;
+ }
+ case '\\':
+ {
+ r += "\\\\";
+ break;
+ }
+ default:
+ {
+ r += static_cast<char> (u);
+ break;
+ }
+ }
+ }
+ else
+ {
+ // @@ Unrepresentable character.
+ //
+ r += '?';
+ }
+ }
+
+ r += '"';
+
+ return r;
+}
+
+string context::
+strlit (string const& str)
+{
+ return strlit_ascii (str);
+}
+
namespace
{
struct column_count_impl: object_members_base
diff --git a/odb/context.hxx b/odb/context.hxx
index 03a3871..b052a71 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -15,7 +15,6 @@
#include <cutl/shared-ptr.hxx>
-#include <odb/database.hxx>
#include <odb/options.hxx>
#include <odb/semantics.hxx>
#include <odb/traversal.hxx>
@@ -148,11 +147,23 @@ public:
string
public_name (semantics::data_member&) const;
+ // "Flatten" fully-qualified C++ name by replacing '::' with '_'
+ // and removing leading '::', if any.
+ //
+ static string
+ flat_name (string const& fqname);
+
// Escape C++ keywords, reserved names, and illegal characters.
//
string
escape (string const&) const;
+ // Return a string literal that can be used in C++ source code. It
+ // includes "".
+ //
+ string
+ strlit (string const&);
+
// Counts and other information.
//
public:
@@ -302,6 +313,8 @@ public:
typedef std::set<string> keyword_set_type;
keyword_set_type const& keyword_set;
+ bool embedded_schema;
+
struct db_type_type
{
db_type_type () {}
@@ -355,6 +368,7 @@ public:
options_type const&,
data_ptr = data_ptr ());
context (context&);
+ context (context&, std::ostream&);
virtual
~context ();
diff --git a/odb/database.cxx b/odb/database.cxx
deleted file mode 100644
index e5b9b24..0000000
--- a/odb/database.cxx
+++ /dev/null
@@ -1,51 +0,0 @@
-// file : odb/database.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 <string>
-#include <istream>
-#include <ostream>
-#include <algorithm> // std::lower_bound
-
-#include <odb/database.hxx>
-
-using namespace std;
-
-static const char* str[] =
-{
- "mysql",
- "tracer"
-};
-
-const char* database::
-string () const
-{
- return str[v_];
-}
-
-istream&
-operator>> (istream& is, database& db)
-{
- string s;
- is >> s;
-
- if (!is.fail ())
- {
- const char** e (str + sizeof (str) / sizeof (char*));
- const char** i (lower_bound (str, e, s));
-
- if (i != e && *i == s)
- db = database::value (i - str);
- else
- is.setstate (istream::failbit);
- }
-
- return is;
-}
-
-ostream&
-operator<< (ostream& os, database db)
-{
- return os << db.string ();
-}
diff --git a/odb/emitter.cxx b/odb/emitter.cxx
new file mode 100644
index 0000000..6cfe64a
--- /dev/null
+++ b/odb/emitter.cxx
@@ -0,0 +1,36 @@
+// file : odb/emitter.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/emitter.hxx>
+
+using namespace std;
+
+void emitter::
+pre ()
+{
+}
+
+void emitter::
+post ()
+{
+}
+
+int emitter_ostream::streambuf::
+sync ()
+{
+ string s (str ());
+
+ // Get rid of the trailing newline if any.
+ //
+ if (string::size_type n = s.size ())
+ {
+ if (s[n - 1] == '\n')
+ s.resize (n - 1);
+ }
+
+ e_.line (s);
+ str (string ());
+ return 0;
+}
diff --git a/odb/emitter.hxx b/odb/emitter.hxx
new file mode 100644
index 0000000..f68253b
--- /dev/null
+++ b/odb/emitter.hxx
@@ -0,0 +1,49 @@
+// file : odb/emitter.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_EMITTER_HXX
+#define ODB_EMITTER_HXX
+
+#include <string>
+#include <sstream>
+
+// Emit a code construct one line at a time.
+//
+struct emitter
+{
+ virtual void
+ pre ();
+
+ virtual void
+ line (const std::string&) = 0;
+
+ virtual void
+ post ();
+};
+
+// Send output line-by-line (std::endl marker) to the emitter.
+//
+class emitter_ostream: public std::ostream
+{
+public:
+ emitter_ostream (emitter& e): std::ostream (&buf_), buf_ (e) {}
+
+private:
+ class streambuf: public std::stringbuf
+ {
+ public:
+ streambuf (emitter& e): e_ (e) {}
+
+ virtual int
+ sync ();
+
+ private:
+ emitter& e_;
+ };
+
+ streambuf buf_;
+};
+
+#endif // ODB_EMITTER_HXX
diff --git a/odb/generator.cxx b/odb/generator.cxx
index ddeda2b..91548e4 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -29,10 +29,10 @@
#include <odb/tracer/source.hxx>
#include <odb/mysql/context.hxx>
-#include <odb/mysql/schema.hxx>
#include <odb/mysql/header.hxx>
#include <odb/mysql/inline.hxx>
#include <odb/mysql/source.hxx>
+#include <odb/mysql/sql-schema.hxx>
using namespace std;
using namespace cutl;
@@ -201,9 +201,11 @@ generate (options const& ops, semantics::unit& unit, path const& p)
//
//
+ bool sql_schema (ops.generate_schema () &&
+ ops.schema_format ().count (schema_format::sql));
ofstream sql;
- if (ops.generate_schema ())
+ if (sql_schema)
{
sql.open (sql_path.string ().c_str (), ios_base::out);
@@ -429,7 +431,7 @@ generate (options const& ops, semantics::unit& unit, path const& p)
// SQL
//
- if (ops.generate_schema ())
+ if (sql_schema)
{
// Copy prologue.
//
diff --git a/odb/makefile b/odb/makefile
index d73f007..ea9385a 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -12,6 +12,7 @@ cxx-lexer.cxx \
sql-lexer.cxx \
context.cxx \
common.cxx \
+emitter.cxx \
type-processor.cxx \
include.cxx \
header.cxx \
@@ -34,10 +35,11 @@ tracer/source.cxx
cxx_ptun += \
mysql/context.cxx \
mysql/common.cxx \
-mysql/schema.cxx \
mysql/header.cxx \
mysql/inline.cxx \
-mysql/source.cxx
+mysql/source.cxx \
+mysql/schema.cxx \
+mysql/sql-schema.cxx
cxx_ptun += \
semantics/class.cxx \
@@ -68,7 +70,7 @@ cxx_dtun := odb.cxx
# Common units.
#
-cxx_ctun := database.cxx profile.cxx
+cxx_ctun := option-types.cxx option-functions.cxx profile.cxx
# Options file.
#
@@ -118,6 +120,7 @@ gen := $(addprefix $(out_base)/,$(genf))
$(gen): $(cli)
$(gen): cli := $(cli)
$(gen): cli_options += \
+--generate-modifier \
--generate-specifier \
--generate-description \
--suppress-undocumented \
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
diff --git a/odb/option-functions.cxx b/odb/option-functions.cxx
new file mode 100644
index 0000000..22a57f0
--- /dev/null
+++ b/odb/option-functions.cxx
@@ -0,0 +1,36 @@
+// file : odb/option-functions.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 <set>
+
+#include <odb/option-functions.hxx>
+
+using namespace std;
+
+void
+process_options (options& o)
+{
+ // Set the default schema format depending on the database.
+ //
+ if (o.generate_schema () && o.schema_format ().empty ())
+ {
+ set<schema_format> f;
+
+ switch (o.database ())
+ {
+ case database::mysql:
+ {
+ f.insert (schema_format::sql);
+ break;
+ }
+ case database::tracer:
+ {
+ break;
+ }
+ }
+
+ o.schema_format (f);
+ }
+}
diff --git a/odb/option-functions.hxx b/odb/option-functions.hxx
new file mode 100644
index 0000000..3d63992
--- /dev/null
+++ b/odb/option-functions.hxx
@@ -0,0 +1,14 @@
+// file : odb/option-functions.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_OPTION_FUNCTIONS_HXX
+#define ODB_OPTION_FUNCTIONS_HXX
+
+#include <odb/options.hxx>
+
+void
+process_options (options&);
+
+#endif // ODB_OPTION_FUNCTIONS_HXX
diff --git a/odb/option-types.cxx b/odb/option-types.cxx
new file mode 100644
index 0000000..b05fead
--- /dev/null
+++ b/odb/option-types.cxx
@@ -0,0 +1,93 @@
+// file : odb/option-types.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 <string>
+#include <istream>
+#include <ostream>
+#include <algorithm> // std::lower_bound
+
+#include <odb/option-types.hxx>
+
+using namespace std;
+
+// database
+//
+static const char* database_[] =
+{
+ "mysql",
+ "tracer"
+};
+
+const char* database::
+string () const
+{
+ return database_[v_];
+}
+
+istream&
+operator>> (istream& is, database& db)
+{
+ string s;
+ is >> s;
+
+ if (!is.fail ())
+ {
+ const char** e (database_ + sizeof (database_) / sizeof (char*));
+ const char** i (lower_bound (database_, e, s));
+
+ if (i != e && *i == s)
+ db = database::value (i - database_);
+ else
+ is.setstate (istream::failbit);
+ }
+
+ return is;
+}
+
+ostream&
+operator<< (ostream& os, database db)
+{
+ return os << db.string ();
+}
+
+// schema_format
+//
+static const char* schema_format_[] =
+{
+ "embedded",
+ "sql"
+};
+
+const char* schema_format::
+string () const
+{
+ return schema_format_[v_];
+}
+
+istream&
+operator>> (istream& is, schema_format& sf)
+{
+ string s;
+ is >> s;
+
+ if (!is.fail ())
+ {
+ const char** e (schema_format_ + sizeof (schema_format_) / sizeof (char*));
+ const char** i (lower_bound (schema_format_, e, s));
+
+ if (i != e && *i == s)
+ sf = schema_format::value (i - schema_format_);
+ else
+ is.setstate (istream::failbit);
+ }
+
+ return is;
+}
+
+ostream&
+operator<< (ostream& os, schema_format sf)
+{
+ return os << sf.string ();
+}
diff --git a/odb/database.hxx b/odb/option-types.hxx
index c47a9da..dc09780 100644
--- a/odb/database.hxx
+++ b/odb/option-types.hxx
@@ -1,10 +1,10 @@
-// file : odb/database.hxx
+// file : odb/option-types.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_DATABASE_HXX
-#define ODB_DATABASE_HXX
+#ifndef ODB_OPTION_TYPES_HXX
+#define ODB_OPTION_TYPES_HXX
#include <iosfwd>
@@ -34,4 +34,32 @@ operator>> (std::istream&, database&);
std::ostream&
operator<< (std::ostream&, database);
-#endif // ODB_DATABASE_HXX
+//
+//
+struct schema_format
+{
+ enum value
+ {
+ // Keep in alphabetic order.
+ //
+ embedded,
+ sql
+ };
+
+ schema_format (value v = value (0)) : v_ (v) {}
+ operator value () const {return v_;}
+
+ const char*
+ string () const;
+
+private:
+ value v_;
+};
+
+std::istream&
+operator>> (std::istream&, schema_format&);
+
+std::ostream&
+operator<< (std::ostream&, schema_format);
+
+#endif // ODB_OPTION_TYPES_HXX
diff --git a/odb/options.cli b/odb/options.cli
index 562daa6..bb21095 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -3,10 +3,11 @@
// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
-include <string>;
+include <set>;
include <vector>;
+include <string>;
-include <odb/database.hxx>;
+include <odb/option-types.hxx>;
class options
{
@@ -59,10 +60,37 @@ class options
bool --generate-schema
{
- "Generate database schema. The resulting SQL file creates database
- tables required to store classes defined in the file being compiled.
- Note that all the existing information stored in such tables will be
- lost."
+ "Generate the database schema. The database schema contains SQL
+ statements that create database tables necessary to store persistent
+ classes defined in the file being compiled. Note that by applying
+ this schema, all the existing information stored in such tables will
+ be lost.
+
+ Depending on the database being used (\cb{--database} option), the
+ schema is generated either as a standalone SQL file or embedded into
+ the generated C++ code. By default the SQL file is generated for
+ the MySQL database and the schema is embedded into the C++ code for
+ the SQLite database. Use the \cb{--schema-format} option to alter
+ the default schema format."
+ };
+
+ std::set< ::schema_format> --schema-format
+ {
+ "<format>",
+ "Generate the database schema in the specified format. Pass \cb{sql} as
+ <format> to generate the database schema as a standalone SQL file or
+ pass \cb{embedded} to embed the schema into the generated C++ code.
+ Repeat this option to generate the same database schema in multiple
+ formats."
+ };
+
+ std::string --default-schema = ""
+ {
+ "<name>",
+ "Use <name> as the default database schema name. Schema names are
+ primarily used for distinguishing between multiple embedded schemas in
+ the schema catalog. If this option is not specified, the empty name,
+ which corresponds to the default schema, is used."
};
std::string --default-pointer = "*"
diff --git a/odb/plugin.cxx b/odb/plugin.cxx
index 47a524d..ede0235 100644
--- a/odb/plugin.cxx
+++ b/odb/plugin.cxx
@@ -16,6 +16,7 @@
#include <odb/pragma.hxx>
#include <odb/parser.hxx>
#include <odb/options.hxx>
+#include <odb/option-functions.hxx>
#include <odb/profile.hxx>
#include <odb/version.hxx>
#include <odb/validator.hxx>
@@ -204,8 +205,14 @@ plugin_init (plugin_name_args* plugin_info, plugin_gcc_version*)
cli::argv_file_scanner scan (argc, &argv[0], oi, 3);
- options_.reset (
+ auto_ptr<options> ops (
new options (scan, cli::unknown_mode::fail, cli::unknown_mode::fail));
+
+ // Process options.
+ //
+ process_options (*ops);
+
+ options_ = ops;
}
if (options_->trace ())