aboutsummaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-06-04 16:29:02 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-06-04 16:29:02 +0200
commitbb76e9388009ed0bb2512034f8cd48a7d19aabb3 (patch)
tree0b43ebff1c36a35bf7cf66c670f04707d4334e38 /odb
parent633f9c5ac574750799efdfe5d1eb31db40a267da (diff)
Next chunk of functionality
Diffstat (limited to 'odb')
-rw-r--r--odb/common.hxx43
-rw-r--r--odb/context.cxx47
-rw-r--r--odb/context.hxx15
-rw-r--r--odb/database.cxx51
-rw-r--r--odb/database.hxx37
-rw-r--r--odb/generator.cxx130
-rw-r--r--odb/header.cxx154
-rw-r--r--odb/header.hxx14
-rw-r--r--odb/inline.cxx72
-rw-r--r--odb/inline.hxx14
-rw-r--r--odb/makefile49
-rw-r--r--odb/mysql-schema.cxx141
-rw-r--r--odb/mysql-schema.hxx14
-rw-r--r--odb/odb.cxx13
-rw-r--r--odb/options.cli73
-rw-r--r--odb/options.cxx214
-rw-r--r--odb/options.hxx87
-rw-r--r--odb/options.ixx110
-rw-r--r--odb/pragma.cxx183
-rw-r--r--odb/source.cxx126
-rw-r--r--odb/source.hxx2
21 files changed, 1462 insertions, 127 deletions
diff --git a/odb/common.hxx b/odb/common.hxx
new file mode 100644
index 0000000..5588f00
--- /dev/null
+++ b/odb/common.hxx
@@ -0,0 +1,43 @@
+// file : odb/common.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_COMMON_HXX
+#define ODB_COMMON_HXX
+
+#include <odb/context.hxx>
+
+// Find id member.
+//
+struct id_member: traversal::class_,
+ traversal::data_member,
+ context
+{
+ id_member (context& c)
+ : context (c), m_ (0)
+ {
+ *this >> names_ >> *this;
+ }
+
+ semantics::data_member*
+ member () const
+ {
+ return m_;
+ }
+
+ virtual void
+ traverse (semantics::data_member& m)
+ {
+ if (m.count ("id"))
+ m_ = &m;
+ }
+
+ using class_::traverse;
+
+private:
+ traversal::names names_;
+ semantics::data_member* m_;
+};
+
+#endif // ODB_COMMON_HXX
diff --git a/odb/context.cxx b/odb/context.cxx
index c90086e..33aa73d 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -114,6 +114,53 @@ context (context& c)
}
string context::
+table_name (semantics::type& t) const
+{
+ if (t.count ("table"))
+ return t.get<string> ("table");
+ else
+ return t.name ();
+}
+
+string context::
+column_name (semantics::data_member& m) const
+{
+ if (m.count ("column"))
+ return m.get<string> ("column");
+ else
+ {
+ string s (m.name ());
+ size_t n (s.size ());
+
+ // Do basic processing: remove trailing and leading underscores
+ // as well as the 'm_' prefix.
+ //
+ // @@ What if the resulting names conflict?
+ //
+ size_t b (0), e (n - 1);
+
+ if (n > 2 && s[0] == 'm' && s[1] == '_')
+ b += 2;
+
+ for (; b <= e && s[b] == '_'; b++) ;
+ for (; e >= b && s[e] == '_'; e--) ;
+
+ return b > e ? s : string (s, b, e - b + 1);
+ }
+}
+
+string context::
+db_type (semantics::data_member& m) const
+{
+ if (m.count ("type"))
+ return m.get<string> ("type");
+ else
+ {
+ return "INT";
+ }
+}
+
+string context::
escape (string const& name) const
{
typedef string::size_type size;
diff --git a/odb/context.hxx b/odb/context.hxx
index 057b821..064b0d5 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -10,14 +10,17 @@
#include <string>
#include <ostream>
#include <cstddef> // std::size_t
+#include <iostream>
#include <cutl/shared-ptr.hxx>
+#include <odb/database.hxx>
#include <odb/options.hxx>
#include <odb/semantics.hxx>
#include <odb/traversal.hxx>
using std::endl;
+using std::cerr;
class generation_failed {};
@@ -28,6 +31,18 @@ public:
typedef std::string string;
typedef ::options options_type;
+ // Database names and types.
+ //
+public:
+ string
+ table_name (semantics::type&) const;
+
+ string
+ column_name (semantics::data_member&) const;
+
+ string
+ db_type (semantics::data_member&) const;
+
public:
// Escape C++ keywords, reserved names, and illegal characters.
//
diff --git a/odb/database.cxx b/odb/database.cxx
new file mode 100644
index 0000000..d094397
--- /dev/null
+++ b/odb/database.cxx
@@ -0,0 +1,51 @@
+// file : odb/database.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; 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/database.hxx b/odb/database.hxx
new file mode 100644
index 0000000..c20e1c4
--- /dev/null
+++ b/odb/database.hxx
@@ -0,0 +1,37 @@
+// file : odb/database.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DATABASE_HXX
+#define ODB_DATABASE_HXX
+
+#include <iosfwd>
+
+struct database
+{
+ enum value
+ {
+ // Keep in alphabetic order.
+ //
+ mysql,
+ tracer
+ };
+
+ database (value v = value (0)) : v_ (v) {}
+ operator value () const {return v_;}
+
+ const char*
+ string () const;
+
+private:
+ value v_;
+};
+
+std::istream&
+operator>> (std::istream&, database&);
+
+std::ostream&
+operator<< (std::ostream&, database);
+
+#endif // ODB_DATABASE_HXX
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 9e1da47..0d4e0c9 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -16,8 +16,12 @@
#include <odb/context.hxx>
#include <odb/generator.hxx>
+#include <odb/header.hxx>
+#include <odb/inline.hxx>
#include <odb/source.hxx>
+#include <odb/mysql-schema.hxx>
+
using namespace std;
using namespace cutl;
@@ -25,12 +29,11 @@ using semantics::path;
namespace
{
- static char const cxx_header[] =
+ static char const file_header[] =
"// This code was generated by CodeSynthesis ODB object persistence\n"
"// compiler for C++.\n"
"//\n\n";
- /*
string
make_guard (string const& file, context& ctx)
{
@@ -50,11 +53,10 @@ namespace
if (isalpha (c1) && isalpha (c2) && islower (c1) && isupper (c2))
r += "_";
}
- r += std::toupper (g[g.size () - 1]);
+ r += toupper (g[g.size () - 1]);
return ctx.escape (r);
}
- */
void
open (ifstream& ifs, string const& path)
@@ -86,15 +88,51 @@ generate (options const& ops, semantics::unit& unit, path const& p)
// C++ output.
//
+ 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 sql_name (base + ops.sql_suffix ());
+
+ path hxx_path (hxx_name);
+ path ixx_path (ixx_name);
path cxx_path (cxx_name);
+ path sql_path (sql_name);
if (!ops.output_dir ().empty ())
{
path dir (ops.output_dir ());
+ hxx_path = dir / hxx_path;
+ ixx_path = dir / ixx_path;
cxx_path = dir / cxx_path;
+ sql_path = dir / sql_path;
+ }
+
+ //
+ //
+ ofstream hxx (hxx_path.string ().c_str ());
+
+ if (!hxx.is_open ())
+ {
+ cerr << "error: unable to open '" << hxx_path << "' in write mode"
+ << endl;
+ throw failed ();
}
+ auto_rm.add (hxx_path);
+
+ //
+ //
+ ofstream ixx (ixx_path.string ().c_str ());
+
+ if (!ixx.is_open ())
+ {
+ cerr << "error: unable to open '" << ixx_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
+
+ auto_rm.add (ixx_path);
+
//
//
ofstream cxx (cxx_path.string ().c_str ());
@@ -108,9 +146,29 @@ generate (options const& ops, semantics::unit& unit, path const& p)
auto_rm.add (cxx_path);
- // Print headers.
//
- cxx << cxx_header;
+ //
+ ofstream sql;
+
+ if (ops.generate_schema ())
+ {
+ sql.open (sql_path.string ().c_str (), ios_base::out);
+
+ if (!sql.is_open ())
+ {
+ cerr << "error: unable to open '" << sql_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
+
+ auto_rm.add (sql_path);
+ }
+
+ // Print C++ headers.
+ //
+ hxx << file_header;
+ ixx << file_header;
+ cxx << file_header;
typedef compiler::ostream_filter<compiler::cxx_indenter, char> cxx_filter;
@@ -118,23 +176,81 @@ generate (options const& ops, semantics::unit& unit, path const& p)
//
bool br (ops.include_with_brackets ());
string ip (ops.include_prefix ());
+ string gp (ops.guard_prefix ());
if (!ip.empty () && ip[ip.size () - 1] != '/')
ip.append ("/");
+ if (!gp.empty () && gp[gp.size () - 1] != '_')
+ gp.append ("_");
+
+ // HXX
+ //
+ {
+ cxx_filter filt (hxx);
+ context ctx (hxx, unit, ops);
+
+ string guard (make_guard (gp + hxx_name, ctx));
+
+ hxx << "#ifndef " << guard << endl
+ << "#define " << guard << endl
+ << endl;
+
+ hxx << "#include " << (br ? '<' : '"') << ip << file <<
+ (br ? '>' : '"') << endl
+ << endl;
+
+ generate_header (ctx);
+
+ hxx << "#include " << (br ? '<' : '"') << ip << ixx_name <<
+ (br ? '>' : '"') << endl
+ << endl;
+
+ hxx << "#endif // " << guard << endl;
+ }
+
+ // IXX
+ //
+ {
+ cxx_filter filt (ixx);
+ context ctx (ixx, unit, ops);
+ generate_inline (ctx);
+ }
+
// CXX
//
{
cxx_filter filt (cxx);
context ctx (cxx, unit, ops);
- cxx << "#include " << (br ? '<' : '"') << ip << file <<
+ cxx << "#include " << (br ? '<' : '"') << ip << hxx_name <<
(br ? '>' : '"') << endl
<< endl;
generate_source (ctx);
}
+ // SQL
+ //
+ if (ops.generate_schema ())
+ {
+ context ctx (sql, unit, ops);
+
+ switch (ops.database ())
+ {
+ case database::mysql:
+ {
+ generate_mysql_schema (ctx);
+ break;
+ }
+ case database::tracer:
+ {
+ cerr << "error: the tracer database does not have schema" << endl;
+ throw failed ();
+ }
+ }
+ }
+
auto_rm.cancel ();
}
catch (const generation_failed&)
diff --git a/odb/header.cxx b/odb/header.cxx
new file mode 100644
index 0000000..5d87991
--- /dev/null
+++ b/odb/header.cxx
@@ -0,0 +1,154 @@
+// file : odb/header.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/common.hxx>
+#include <odb/header.hxx>
+
+namespace
+{
+ struct class_: traversal::class_, context
+ {
+ class_ (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.file () != unit.file ())
+ return;
+
+ if (!c.count ("object"))
+ return;
+
+ string const& type (c.fq_name ());
+
+ // Find the id member and type.
+ //
+ id_member t (*this);
+ t.traverse (c);
+
+ if (t.member () == 0)
+ {
+ cerr << c.file () << ":" << c.line () << ":" << c.column ()
+ << " error: no data member designated as object id" << endl;
+
+ cerr << c.file () << ":" << c.line () << ":" << c.column ()
+ << " info: use '#pragma odb id' to specify object id member"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ semantics::data_member& id (*t.member ());
+ semantics::type& id_type (id.type ());
+
+ if (id_type.anonymous ())
+ {
+ // Can be a template-id (which we should handle eventually) or an
+ // anonymous type in member declaration (e.g., struct {...} m_;).
+ //
+ cerr << id.file () << ":" << id.line () << ":" << id.column ()
+ << " error: unnamed type in data member declaration" << endl;
+
+ cerr << id.file () << ":" << id.line () << ":" << id.column ()
+ << " info: use 'typedef' to name this type"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ os << "// " << c.name () << endl
+ << "//" << endl;
+
+ os << "template <>" << endl
+ << "class access::object_traits< " << type << " >: " << endl
+ << " public access::object_memory< " << type << " >," << endl
+ << " public access::object_factory< " << type << " >"
+ << "{"
+ << "public:" << endl;
+
+ // object_type & shared_ptr
+ //
+ os << "typedef " << type << " object_type;";
+
+ // id_type
+ //
+ os << "typedef " << id_type.fq_name () << " id_type;"
+ << endl;
+
+ // id_source
+ //
+ os << "static const odb::id_source id_source = odb::ids_assigned;"
+ << endl;
+
+ // type_name ()
+ //
+ os << "static const char*" << endl
+ << "type_name ();"
+ << endl;
+
+ // id ()
+ //
+ os << "static id_type" << endl
+ << "id (const object_type&);"
+ << endl;
+
+ // insert ()
+ //
+ os << "static void" << endl
+ << "insert (database&, const object_type&);"
+ << endl;
+
+ // update ()
+ //
+ os << "static void" << endl
+ << "update (database&, const object_type&);"
+ << endl;
+
+ // erase ()
+ //
+ os << "static void" << endl
+ << "erase (database&, const id_type&);"
+ << endl;
+
+ // find ()
+ //
+ os << "static shared_ptr" << endl
+ << "find (database&, const id_type&);";
+
+ os << "};";
+ }
+ };
+}
+
+void
+generate_header (context& ctx)
+{
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ ctx.os << "#include <odb/core.hxx>" << endl
+ << "#include <odb/traits.hxx>" << endl
+ << endl;
+
+ ctx.os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ ctx.os << "}";
+}
diff --git a/odb/header.hxx b/odb/header.hxx
new file mode 100644
index 0000000..f7f3a34
--- /dev/null
+++ b/odb/header.hxx
@@ -0,0 +1,14 @@
+// file : odb/header.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_HEADER_HXX
+#define ODB_HEADER_HXX
+
+#include <odb/context.hxx>
+
+void
+generate_header (context&);
+
+#endif // ODB_HEADER_HXX
diff --git a/odb/inline.cxx b/odb/inline.cxx
new file mode 100644
index 0000000..ee3a8e6
--- /dev/null
+++ b/odb/inline.cxx
@@ -0,0 +1,72 @@
+// file : odb/inline.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/common.hxx>
+#include <odb/inline.hxx>
+
+namespace
+{
+ struct class_: traversal::class_, context
+ {
+ class_ (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.file () != unit.file ())
+ return;
+
+ if (!c.count ("object"))
+ return;
+
+ string const& type (c.fq_name ());
+ string traits ("access::object_traits< " + type + " >");
+
+ id_member t (*this);
+ t.traverse (c);
+ semantics::data_member& id (*t.member ());
+
+ os << "// " << c.name () << endl
+ << "//" << endl
+ << endl;
+
+ // id ()
+ //
+ os << "inline" << endl
+ << traits << "::id_type " << traits << "::" << endl
+ << "id (const object_type& obj)"
+ << "{"
+ << "return obj." << id.name () << ";" << endl
+ << "}";
+ }
+ };
+}
+
+void
+generate_inline (context& ctx)
+{
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ ctx.os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ ctx.os << "}";
+}
diff --git a/odb/inline.hxx b/odb/inline.hxx
new file mode 100644
index 0000000..77a2d56
--- /dev/null
+++ b/odb/inline.hxx
@@ -0,0 +1,14 @@
+// file : odb/inline.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_INLINE_HXX
+#define ODB_INLINE_HXX
+
+#include <odb/context.hxx>
+
+void
+generate_inline (context&);
+
+#endif // ODB_INLINE_HXX
diff --git a/odb/makefile b/odb/makefile
index 12c4a74..f6da371 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -13,7 +13,10 @@ generator.cxx \
parser.cxx \
plugin.cxx \
pragma.cxx \
-source.cxx
+header.cxx \
+inline.cxx \
+source.cxx \
+mysql-schema.cxx
cxx_ptun += \
semantics/class.cxx \
@@ -42,19 +45,32 @@ traversal/union-template.cxx
#
cxx_dtun := odb.cxx
+# Common units.
+#
+cxx_ctun := database.cxx
+
# Options file.
#
cli_tun := options.cli
#
#
-cxx_pobj := $(addprefix $(out_base)/,$(cxx_ptun:.cxx=.o) $(cli_tun:.cli=.o))
-cxx_dobj := $(addprefix $(out_base)/,$(cxx_dtun:.cxx=.o) $(cli_tun:.cli=.o))
+cxx_pobj := $(addprefix $(out_base)/,$(cxx_ptun:.cxx=.o))
+cxx_dobj := $(addprefix $(out_base)/,$(cxx_dtun:.cxx=.o))
+cxx_cobj := $(addprefix $(out_base)/,$(cxx_ctun:.cxx=.o) $(cli_tun:.cli=.o))
cxx_pod := $(cxx_pobj:.o=.o.d)
cxx_dod := $(cxx_dobj:.o=.o.d)
+cxx_cod := $(cxx_cobj:.o=.o.d)
+
odb := $(out_base)/odb
odb_so := $(out_base)/odb.so
+
+# Dummy library to force driver timestamp update when the plugin DSO
+# changes.
+#
+odb.l := $(out_base)/odb.l
+
clean := $(out_base)/.clean
install := $(out_base)/.install
@@ -70,17 +86,19 @@ $(call import,\
# Build.
#
-$(odb): $(cxx_dobj) $(cutl.l) | $(odb_so)
-$(odb_so): $(cxx_pobj) $(cutl.l)
+$(odb): $(cxx_dobj) $(cxx_cobj) $(odb.l) $(cutl.l)
+$(odb_so): $(cxx_pobj) $(cxx_cobj) $(cutl.l)
-$(cxx_dobj) $(cxx_dod): cpp_options := -I$(src_root)
-$(cxx_pobj) $(cxx_dobj) $(cxx_pod) $(cxx_dod): $(cutl.l.cpp-options)
+$(cxx_pobj) $(cxx_dobj) $(cxx_cobj) $(cxx_pod) $(cxx_dod) $(cxx_cod): \
+$(cutl.l.cpp-options)
genf := $(cli_tun:.cli=.hxx) $(cli_tun:.cli=.ixx) $(cli_tun:.cli=.cxx)
gen := $(addprefix $(out_base)/,$(genf))
+$(gen): $(cli)
$(gen): cli := $(cli)
-$(gen): cli_options := \
+$(gen): cli_options += \
+--generate-specifier \
--generate-file-scanner \
--include-with-brackets \
--include-prefix odb \
@@ -88,6 +106,7 @@ $(gen): cli_options := \
$(call include-dep,$(cxx_pod))
$(call include-dep,$(cxx_dod))
+$(call include-dep,$(cxx_cod))
# Alias for default target.
#
@@ -105,9 +124,12 @@ $(clean): \
$(odb).o.clean \
$(addsuffix .cxx.clean,$(cxx_pobj)) \
$(addsuffix .cxx.clean,$(cxx_dobj)) \
+ $(addsuffix .cxx.clean,$(cxx_cobj)) \
$(addsuffix .cxx.clean,$(cxx_pod)) \
- $(addsuffix .cxx.clean,$(cxx_dod))
+ $(addsuffix .cxx.clean,$(cxx_dod)) \
+ $(addsuffix .cxx.clean,$(cxx_cod))
$(call message,rm $$1,rm -f $$1,$(out_base)/odb.so)
+ $(call message,,rm -f $(out_base)/odb.l)
# Generated .gitignore.
#
@@ -128,12 +150,14 @@ $(call include,$(bld_root)/cxx/cxx-d.make)
$(call include,$(bld_root)/cxx/cxx-o.make)
$(call include,$(bld_root)/cxx/o-e.make)
-# Custom rules for the plugin.
+# Custom rules for the plugin and the driver.
#
ifdef cxx_gnu
-$(cxx_pobj): cxx_pic_options := -fPIC
+$(cxx_pobj) $(cxx_cobj): cxx_pic_options := -fPIC
+$(cxx_cobj) $(cxx_cod): cpp_options := -I$(src_root)
+$(cxx_dobj) $(cxx_dod): cpp_options := -I$(src_root) '-DGXX_NAME="$(cxx_gnu)"'
$(cxx_pobj) $(cxx_pod): cpp_options := -I$(src_root) \
-I$(shell $(cxx_gnu) -print-file-name=plugin)/include
@@ -142,4 +166,7 @@ $(odb_so):
$(cxx_extra_options) $(ld_options) $(cxx_ld_extra_options) -shared -o $@ \
$(foreach f,$^,$(if $(patsubst %.l,,$f),$f,$(call expand-l,$f))) $(cxx_extra_libs))
+$(odb.l): $(odb_so)
+ $(call message,,touch $@)
+
endif
diff --git a/odb/mysql-schema.cxx b/odb/mysql-schema.cxx
new file mode 100644
index 0000000..ea3fece
--- /dev/null
+++ b/odb/mysql-schema.cxx
@@ -0,0 +1,141 @@
+// file : odb/mysql-schema.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/mysql-schema.hxx>
+
+namespace
+{
+ struct data_member: traversal::data_member, context
+ {
+ data_member (context& c)
+ : context (c), first_ (true)
+ {
+ }
+
+ virtual void
+ traverse (type& m)
+ {
+ if (first_)
+ first_ = false;
+ else
+ os << "," << endl;
+
+ os << " `" << column_name (m) << "` " << db_type (m) <<
+ " NOT NULL";
+
+ if (m.count ("id"))
+ os << " PRIMARY KEY";
+ }
+
+ private:
+ bool first_;
+ };
+
+ 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;
+
+ os << "CREATE TABLE `" << table_name (c) << "` (" << endl;
+
+ {
+ data_member m (*this);
+ traversal::names n (m);
+ names (c, n);
+ }
+
+ os << ")";
+
+ string const& engine (options.mysql_engine ());
+
+ if (engine != "default")
+ os << endl
+ << " ENGINE=" << engine;
+
+ os << ";" << endl
+ << endl;
+ }
+ };
+
+ 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;
+
+ os << "DROP TABLE IF EXISTS `" << table_name (c) << "`;" << endl;
+ }
+ };
+}
+
+static char const file_header[] =
+ "/* This file was generated by CodeSynthesis ODB object persistence\n"
+ " * compiler for C++.\n"
+ " */\n\n";
+
+void
+generate_mysql_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
new file mode 100644
index 0000000..f4a7996
--- /dev/null
+++ b/odb/mysql-schema.hxx
@@ -0,0 +1,14 @@
+// file : odb/mysql-schema.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_MYSQL_SCHEMA_HXX
+#define ODB_MYSQL_SCHEMA_HXX
+
+#include <odb/context.hxx>
+
+void
+generate_mysql_schema (context&);
+
+#endif // ODB_MYSQL_SCHEMA_HXX
diff --git a/odb/odb.cxx b/odb/odb.cxx
index b53b7ea..b6f76a0 100644
--- a/odb/odb.cxx
+++ b/odb/odb.cxx
@@ -49,7 +49,11 @@ main (int argc, char* argv[])
// The first argument points to the program name, which is
// g++ by default.
//
+#ifdef GXX_NAME
+ args.push_back (GXX_NAME);
+#else
args.push_back ("g++");
+#endif
// Default options.
//
@@ -202,6 +206,15 @@ main (int argc, char* argv[])
return 0;
}
+ // Check that required options were specifed.
+ //
+ if (!ops.database_specified ())
+ {
+ e << argv[0] << ": error: no database specified with the --database "
+ << "option" << endl;
+ return 1;
+ }
+
size_t end (scan.end () - 1); // We have one less in plugin_args.
if (end == plugin_args.size ())
diff --git a/odb/options.cli b/odb/options.cli
index 1454d9a..ebe65e5 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -6,6 +6,8 @@
include <string>;
include <vector>;
+include <odb/database.hxx>;
+
class options
{
//
@@ -18,6 +20,21 @@ class options
//
// Plugin options.
//
+ ::database --database | -d
+ {
+ "<db>",
+ "Generate code for the <db> database. Valid values are \cb{mysql} and
+ \cb{tracer}."
+ };
+
+ 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."
+ };
+
std::string --output-dir | -o
{
"<dir>",
@@ -28,28 +45,35 @@ class options
{
"<suffix>",
"Use <suffix> instead of the default \cb{-odb} to construct the names
- of the generated ODB files."
+ of the generated C++ files."
};
std::string --hxx-suffix = ".hxx"
{
"<suffix>",
"Use <suffix> instead of the default \cb{.hxx} to construct the name of
- the generated header file."
+ the generated C++ header file."
};
std::string --ixx-suffix = ".ixx"
{
"<suffix>",
"Use <suffix> instead of the default \cb{.ixx} to construct the name of
- the generated inline file."
+ the generated C++ inline file."
};
std::string --cxx-suffix = ".cxx"
{
"<suffix>",
"Use <suffix> instead of the default \cb{.cxx} to construct the name of
- the generated source file."
+ the generated C++ source file."
+ };
+
+ std::string --sql-suffix = ".sql"
+ {
+ "<suffix>",
+ "Use <suffix> instead of the default \cb{.sql} to construct the name of
+ the generated database schema file."
};
bool --include-with-brackets
@@ -64,6 +88,14 @@ class options
"Add <prefix> to the generated \cb{#include} directive paths."
};
+ std::string --guard-prefix
+ {
+ "<prefix>",
+ "Add <prefix> to the generated header inclusion guards. The prefix is
+ transformed to upper case and characters that are illegal in a
+ preprocessor macro name are replaced with underscores."
+ };
+
// This is a "fake" option in that it is actually handled by
// argv_file_scanner. We have it here to get the documentation.
//
@@ -72,13 +104,34 @@ class options
"<file>",
"Read additional options from <file> with each option appearing on a
separate line optionally followed by space and an option value. Empty
- lines and lines starting with \cb{#} are ignored. The semantics of
- providing options in a file is equivalent to providing the same set
- of options in the same order on the command line at the point where the
- \cb{--options-file} option is specified except that shell escaping and
- quoting is not required. Repeat this option to specify more than one
- options files."
+ lines and lines starting with \cb{#} are ignored. Option values can
+ be enclosed in double (\cb{\"}) or single (\cb{'}) quotes to preserve
+ leading and trailing whitespaces as well as to specify empty values.
+ If the value itself contains trailing or leading quotes, enclose it
+ with an extra pair of quotes, for example \cb{'\"x\"'}. Non-leading
+ and non-trailing quotes are interpreted as being part of the option
+ value.
+
+ The semantics of providing options in a file is equivalent to providing
+ the same set of options in the same order on the command line at the
+ point where the \cb{--options-file} option is specified except that
+ the shell escaping and quoting is not required. Repeat this option
+ to specify more than one options files."
};
bool --trace {"Trace the compilation process."};
+
+ //
+ // MySQL-specific options.
+ //
+
+ std::string --mysql-engine = "InnoDB"
+ {
+ "<engine>",
+ "Use <engine> instead of the default \cb{InnoDB} in the generated
+ database schema file. For more information on the storage engine
+ options see the MySQL documentation. If you would like to use the
+ database-default engine, pass \cb{default} as the value for this
+ option."
+ };
};
diff --git a/odb/options.cxx b/odb/options.cxx
index c5c2c0b..2af4e8e 100644
--- a/odb/options.cxx
+++ b/odb/options.cxx
@@ -125,6 +125,25 @@ namespace cli
return "unable to open file or read failure";
}
+ // unmatched_quote
+ //
+ unmatched_quote::
+ ~unmatched_quote () throw ()
+ {
+ }
+
+ void unmatched_quote::
+ print (std::ostream& os) const
+ {
+ os << "unmatched quote in argument '" << argument () << "'";
+ }
+
+ const char* unmatched_quote::
+ what () const throw ()
+ {
+ return "unmatched quote";
+ }
+
// scanner
//
scanner::
@@ -329,6 +348,19 @@ namespace cli
string s2 (line, p);
+ // If the string is wrapped in quotes, remove them.
+ //
+ n = s2.size ();
+ char cf (s2[0]), cl (s2[n - 1]);
+
+ if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'')
+ {
+ if (n == 1 || cf != cl)
+ throw unmatched_quote (s2);
+
+ s2 = string (s2, 1, n - 2);
+ }
+
if (!skip_ && s1 == option_)
load (s2.c_str ());
else
@@ -344,7 +376,7 @@ namespace cli
struct parser
{
static void
- parse (X& x, scanner& s)
+ parse (X& x, bool& xs, scanner& s)
{
const char* o (s.next ());
@@ -357,6 +389,8 @@ namespace cli
}
else
throw missing_value (o);
+
+ xs = true;
}
};
@@ -375,7 +409,7 @@ namespace cli
struct parser<std::string>
{
static void
- parse (std::string& x, scanner& s)
+ parse (std::string& x, bool& xs, scanner& s)
{
const char* o (s.next ());
@@ -383,6 +417,8 @@ namespace cli
x = s.next ();
else
throw missing_value (o);
+
+ xs = true;
}
};
@@ -390,11 +426,12 @@ namespace cli
struct parser<std::vector<X> >
{
static void
- parse (std::vector<X>& c, scanner& s)
+ parse (std::vector<X>& c, bool& xs, scanner& s)
{
X x;
parser<X>::parse (x, s);
c.push_back (x);
+ xs = true;
}
};
@@ -402,11 +439,12 @@ namespace cli
struct parser<std::set<X> >
{
static void
- parse (std::set<X>& c, scanner& s)
+ parse (std::set<X>& c, bool& xs, scanner& s)
{
X x;
parser<X>::parse (x, s);
c.insert (x);
+ xs = true;
}
};
@@ -414,7 +452,7 @@ namespace cli
struct parser<std::map<K, V> >
{
static void
- parse (std::map<K, V>& m, scanner& s)
+ parse (std::map<K, V>& m, bool& xs, scanner& s)
{
const char* o (s.next ());
@@ -465,14 +503,23 @@ namespace cli
}
else
throw missing_value (o);
+
+ xs = true;
}
};
- template <typename X, typename T, T X::*P>
+ template <typename X, typename T, T X::*M>
void
thunk (X& x, scanner& s)
{
- parser<T>::parse (x.*P, s);
+ parser<T>::parse (x.*M, s);
+ }
+
+ template <typename X, typename T, T X::*M, bool X::*S>
+ void
+ thunk (X& x, scanner& s)
+ {
+ parser<T>::parse (x.*M, x.*S, s);
}
}
@@ -490,15 +537,31 @@ options (int& argc,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ database_ (),
+ database_specified_ (false),
+ generate_schema_ (),
output_dir_ (),
+ output_dir_specified_ (false),
odb_file_suffix_ ("-odb"),
+ odb_file_suffix_specified_ (false),
hxx_suffix_ (".hxx"),
+ hxx_suffix_specified_ (false),
ixx_suffix_ (".ixx"),
+ ixx_suffix_specified_ (false),
cxx_suffix_ (".cxx"),
+ cxx_suffix_specified_ (false),
+ sql_suffix_ (".sql"),
+ sql_suffix_specified_ (false),
include_with_brackets_ (),
include_prefix_ (),
+ include_prefix_specified_ (false),
+ guard_prefix_ (),
+ guard_prefix_specified_ (false),
options_file_ (),
- trace_ ()
+ options_file_specified_ (false),
+ trace_ (),
+ mysql_engine_ ("InnoDB"),
+ mysql_engine_specified_ (false)
{
::cli::argv_scanner s (argc, argv, erase);
_parse (s, opt, arg);
@@ -513,15 +576,31 @@ options (int start,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ database_ (),
+ database_specified_ (false),
+ generate_schema_ (),
output_dir_ (),
+ output_dir_specified_ (false),
odb_file_suffix_ ("-odb"),
+ odb_file_suffix_specified_ (false),
hxx_suffix_ (".hxx"),
+ hxx_suffix_specified_ (false),
ixx_suffix_ (".ixx"),
+ ixx_suffix_specified_ (false),
cxx_suffix_ (".cxx"),
+ cxx_suffix_specified_ (false),
+ sql_suffix_ (".sql"),
+ sql_suffix_specified_ (false),
include_with_brackets_ (),
include_prefix_ (),
+ include_prefix_specified_ (false),
+ guard_prefix_ (),
+ guard_prefix_specified_ (false),
options_file_ (),
- trace_ ()
+ options_file_specified_ (false),
+ trace_ (),
+ mysql_engine_ ("InnoDB"),
+ mysql_engine_specified_ (false)
{
::cli::argv_scanner s (start, argc, argv, erase);
_parse (s, opt, arg);
@@ -536,15 +615,31 @@ options (int& argc,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ database_ (),
+ database_specified_ (false),
+ generate_schema_ (),
output_dir_ (),
+ output_dir_specified_ (false),
odb_file_suffix_ ("-odb"),
+ odb_file_suffix_specified_ (false),
hxx_suffix_ (".hxx"),
+ hxx_suffix_specified_ (false),
ixx_suffix_ (".ixx"),
+ ixx_suffix_specified_ (false),
cxx_suffix_ (".cxx"),
+ cxx_suffix_specified_ (false),
+ sql_suffix_ (".sql"),
+ sql_suffix_specified_ (false),
include_with_brackets_ (),
include_prefix_ (),
+ include_prefix_specified_ (false),
+ guard_prefix_ (),
+ guard_prefix_specified_ (false),
options_file_ (),
- trace_ ()
+ options_file_specified_ (false),
+ trace_ (),
+ mysql_engine_ ("InnoDB"),
+ mysql_engine_specified_ (false)
{
::cli::argv_scanner s (argc, argv, erase);
_parse (s, opt, arg);
@@ -561,15 +656,31 @@ options (int start,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ database_ (),
+ database_specified_ (false),
+ generate_schema_ (),
output_dir_ (),
+ output_dir_specified_ (false),
odb_file_suffix_ ("-odb"),
+ odb_file_suffix_specified_ (false),
hxx_suffix_ (".hxx"),
+ hxx_suffix_specified_ (false),
ixx_suffix_ (".ixx"),
+ ixx_suffix_specified_ (false),
cxx_suffix_ (".cxx"),
+ cxx_suffix_specified_ (false),
+ sql_suffix_ (".sql"),
+ sql_suffix_specified_ (false),
include_with_brackets_ (),
include_prefix_ (),
+ include_prefix_specified_ (false),
+ guard_prefix_ (),
+ guard_prefix_specified_ (false),
options_file_ (),
- trace_ ()
+ options_file_specified_ (false),
+ trace_ (),
+ mysql_engine_ ("InnoDB"),
+ mysql_engine_specified_ (false)
{
::cli::argv_scanner s (start, argc, argv, erase);
_parse (s, opt, arg);
@@ -582,15 +693,31 @@ options (::cli::scanner& s,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ database_ (),
+ database_specified_ (false),
+ generate_schema_ (),
output_dir_ (),
+ output_dir_specified_ (false),
odb_file_suffix_ ("-odb"),
+ odb_file_suffix_specified_ (false),
hxx_suffix_ (".hxx"),
+ hxx_suffix_specified_ (false),
ixx_suffix_ (".ixx"),
+ ixx_suffix_specified_ (false),
cxx_suffix_ (".cxx"),
+ cxx_suffix_specified_ (false),
+ sql_suffix_ (".sql"),
+ sql_suffix_specified_ (false),
include_with_brackets_ (),
include_prefix_ (),
+ include_prefix_specified_ (false),
+ guard_prefix_ (),
+ guard_prefix_specified_ (false),
options_file_ (),
- trace_ ()
+ options_file_specified_ (false),
+ trace_ (),
+ mysql_engine_ ("InnoDB"),
+ mysql_engine_specified_ (false)
{
_parse (s, opt, arg);
}
@@ -602,20 +729,28 @@ print_usage (::std::ostream& os)
os << "--version Print version and exit." << ::std::endl;
+ os << "--database|-d <db> Generate code for the <db> database." << ::std::endl;
+
+ os << "--generate-schema Generate database schema." << ::std::endl;
+
os << "--output-dir|-o <dir> Write the generated files to <dir> instead of the" << ::std::endl
<< " current directory." << ::std::endl;
os << "--odb-file-suffix <suffix> Use <suffix> instead of the default '-odb' to" << ::std::endl
- << " construct the names of the generated ODB files." << ::std::endl;
+ << " construct the names of the generated C++ files." << ::std::endl;
os << "--hxx-suffix <suffix> Use <suffix> instead of the default '.hxx' to" << ::std::endl
- << " construct the name of the generated header file." << ::std::endl;
+ << " construct the name of the generated C++ header file." << ::std::endl;
os << "--ixx-suffix <suffix> Use <suffix> instead of the default '.ixx' to" << ::std::endl
- << " construct the name of the generated inline file." << ::std::endl;
+ << " construct the name of the generated C++ inline file." << ::std::endl;
os << "--cxx-suffix <suffix> Use <suffix> instead of the default '.cxx' to" << ::std::endl
- << " construct the name of the generated source file." << ::std::endl;
+ << " construct the name of the generated C++ source file." << ::std::endl;
+
+ os << "--sql-suffix <suffix> Use <suffix> instead of the default '.sql' to" << ::std::endl
+ << " construct the name of the generated database schema" << ::std::endl
+ << " file." << ::std::endl;
os << "--include-with-brackets Use angle brackets (<>) instead of quotes (\"\") in the" << ::std::endl
<< " generated '#include' directives." << ::std::endl;
@@ -623,11 +758,17 @@ print_usage (::std::ostream& os)
os << "--include-prefix <prefix> Add <prefix> to the generated '#include' directive" << ::std::endl
<< " paths." << ::std::endl;
+ os << "--guard-prefix <prefix> Add <prefix> to the generated header inclusion" << ::std::endl
+ << " guards." << ::std::endl;
+
os << "--options-file <file> Read additional options from <file> with each option" << ::std::endl
<< " appearing on a separate line optionally followed by" << ::std::endl
<< " space and an option value." << ::std::endl;
os << "--trace Trace the compilation process." << ::std::endl;
+
+ os << "--mysql-engine <engine> Use <engine> instead of the default 'InnoDB' in the" << ::std::endl
+ << " generated database schema file." << ::std::endl;
}
typedef
@@ -644,26 +785,51 @@ struct _cli_options_map_init
&::cli::thunk< options, bool, &options::help_ >;
_cli_options_map_["--version"] =
&::cli::thunk< options, bool, &options::version_ >;
+ _cli_options_map_["--database"] =
+ &::cli::thunk< options, ::database, &options::database_,
+ &options::database_specified_ >;
+ _cli_options_map_["-d"] =
+ &::cli::thunk< options, ::database, &options::database_,
+ &options::database_specified_ >;
+ _cli_options_map_["--generate-schema"] =
+ &::cli::thunk< options, bool, &options::generate_schema_ >;
_cli_options_map_["--output-dir"] =
- &::cli::thunk< options, std::string, &options::output_dir_ >;
+ &::cli::thunk< options, std::string, &options::output_dir_,
+ &options::output_dir_specified_ >;
_cli_options_map_["-o"] =
- &::cli::thunk< options, std::string, &options::output_dir_ >;
+ &::cli::thunk< options, std::string, &options::output_dir_,
+ &options::output_dir_specified_ >;
_cli_options_map_["--odb-file-suffix"] =
- &::cli::thunk< options, std::string, &options::odb_file_suffix_ >;
+ &::cli::thunk< options, std::string, &options::odb_file_suffix_,
+ &options::odb_file_suffix_specified_ >;
_cli_options_map_["--hxx-suffix"] =
- &::cli::thunk< options, std::string, &options::hxx_suffix_ >;
+ &::cli::thunk< options, std::string, &options::hxx_suffix_,
+ &options::hxx_suffix_specified_ >;
_cli_options_map_["--ixx-suffix"] =
- &::cli::thunk< options, std::string, &options::ixx_suffix_ >;
+ &::cli::thunk< options, std::string, &options::ixx_suffix_,
+ &options::ixx_suffix_specified_ >;
_cli_options_map_["--cxx-suffix"] =
- &::cli::thunk< options, std::string, &options::cxx_suffix_ >;
+ &::cli::thunk< options, std::string, &options::cxx_suffix_,
+ &options::cxx_suffix_specified_ >;
+ _cli_options_map_["--sql-suffix"] =
+ &::cli::thunk< options, std::string, &options::sql_suffix_,
+ &options::sql_suffix_specified_ >;
_cli_options_map_["--include-with-brackets"] =
&::cli::thunk< options, bool, &options::include_with_brackets_ >;
_cli_options_map_["--include-prefix"] =
- &::cli::thunk< options, std::string, &options::include_prefix_ >;
+ &::cli::thunk< options, std::string, &options::include_prefix_,
+ &options::include_prefix_specified_ >;
+ _cli_options_map_["--guard-prefix"] =
+ &::cli::thunk< options, std::string, &options::guard_prefix_,
+ &options::guard_prefix_specified_ >;
_cli_options_map_["--options-file"] =
- &::cli::thunk< options, std::string, &options::options_file_ >;
+ &::cli::thunk< options, std::string, &options::options_file_,
+ &options::options_file_specified_ >;
_cli_options_map_["--trace"] =
&::cli::thunk< options, bool, &options::trace_ >;
+ _cli_options_map_["--mysql-engine"] =
+ &::cli::thunk< options, std::string, &options::mysql_engine_,
+ &options::mysql_engine_specified_ >;
}
} _cli_options_map_init_;
diff --git a/odb/options.hxx b/odb/options.hxx
index daf3d31..21cc496 100644
--- a/odb/options.hxx
+++ b/odb/options.hxx
@@ -166,6 +166,27 @@ namespace cli
std::string file_;
};
+ class unmatched_quote: public exception
+ {
+ public:
+ virtual
+ ~unmatched_quote () throw ();
+
+ unmatched_quote (const std::string& argument);
+
+ const std::string&
+ argument () const;
+
+ virtual void
+ print (std::ostream&) const;
+
+ virtual const char*
+ what () const throw ();
+
+ private:
+ std::string argument_;
+ };
+
class scanner
{
public:
@@ -256,6 +277,8 @@ namespace cli
#include <vector>
+#include <odb/database.hxx>
+
class options
{
public:
@@ -301,33 +324,81 @@ class options
const bool&
version () const;
+ const ::database&
+ database () const;
+
+ bool
+ database_specified () const;
+
+ const bool&
+ generate_schema () const;
+
const std::string&
output_dir () const;
+ bool
+ output_dir_specified () const;
+
const std::string&
odb_file_suffix () const;
+ bool
+ odb_file_suffix_specified () const;
+
const std::string&
hxx_suffix () const;
+ bool
+ hxx_suffix_specified () const;
+
const std::string&
ixx_suffix () const;
+ bool
+ ixx_suffix_specified () const;
+
const std::string&
cxx_suffix () const;
+ bool
+ cxx_suffix_specified () const;
+
+ const std::string&
+ sql_suffix () const;
+
+ bool
+ sql_suffix_specified () const;
+
const bool&
include_with_brackets () const;
const std::string&
include_prefix () const;
+ bool
+ include_prefix_specified () const;
+
+ const std::string&
+ guard_prefix () const;
+
+ bool
+ guard_prefix_specified () const;
+
const std::string&
options_file () const;
+ bool
+ options_file_specified () const;
+
const bool&
trace () const;
+ const std::string&
+ mysql_engine () const;
+
+ bool
+ mysql_engine_specified () const;
+
// Print usage information.
//
static void
@@ -342,15 +413,31 @@ class options
public:
bool help_;
bool version_;
+ ::database database_;
+ bool database_specified_;
+ bool generate_schema_;
std::string output_dir_;
+ bool output_dir_specified_;
std::string odb_file_suffix_;
+ bool odb_file_suffix_specified_;
std::string hxx_suffix_;
+ bool hxx_suffix_specified_;
std::string ixx_suffix_;
+ bool ixx_suffix_specified_;
std::string cxx_suffix_;
+ bool cxx_suffix_specified_;
+ std::string sql_suffix_;
+ bool sql_suffix_specified_;
bool include_with_brackets_;
std::string include_prefix_;
+ bool include_prefix_specified_;
+ std::string guard_prefix_;
+ bool guard_prefix_specified_;
std::string options_file_;
+ bool options_file_specified_;
bool trace_;
+ std::string mysql_engine_;
+ bool mysql_engine_specified_;
};
#include <odb/options.ixx>
diff --git a/odb/options.ixx b/odb/options.ixx
index dfe6995..9796a83 100644
--- a/odb/options.ixx
+++ b/odb/options.ixx
@@ -98,6 +98,20 @@ namespace cli
return file_;
}
+ // unmatched_quote
+ //
+ inline unmatched_quote::
+ unmatched_quote (const std::string& argument)
+ : argument_ (argument)
+ {
+ }
+
+ inline const std::string& unmatched_quote::
+ argument () const
+ {
+ return argument_;
+ }
+
// argv_scanner
//
inline argv_scanner::
@@ -159,36 +173,96 @@ version () const
return this->version_;
}
+inline const ::database& options::
+database () const
+{
+ return this->database_;
+}
+
+inline bool options::
+database_specified () const
+{
+ return this->database_specified_;
+}
+
+inline const bool& options::
+generate_schema () const
+{
+ return this->generate_schema_;
+}
+
inline const std::string& options::
output_dir () const
{
return this->output_dir_;
}
+inline bool options::
+output_dir_specified () const
+{
+ return this->output_dir_specified_;
+}
+
inline const std::string& options::
odb_file_suffix () const
{
return this->odb_file_suffix_;
}
+inline bool options::
+odb_file_suffix_specified () const
+{
+ return this->odb_file_suffix_specified_;
+}
+
inline const std::string& options::
hxx_suffix () const
{
return this->hxx_suffix_;
}
+inline bool options::
+hxx_suffix_specified () const
+{
+ return this->hxx_suffix_specified_;
+}
+
inline const std::string& options::
ixx_suffix () const
{
return this->ixx_suffix_;
}
+inline bool options::
+ixx_suffix_specified () const
+{
+ return this->ixx_suffix_specified_;
+}
+
inline const std::string& options::
cxx_suffix () const
{
return this->cxx_suffix_;
}
+inline bool options::
+cxx_suffix_specified () const
+{
+ return this->cxx_suffix_specified_;
+}
+
+inline const std::string& options::
+sql_suffix () const
+{
+ return this->sql_suffix_;
+}
+
+inline bool options::
+sql_suffix_specified () const
+{
+ return this->sql_suffix_specified_;
+}
+
inline const bool& options::
include_with_brackets () const
{
@@ -201,15 +275,51 @@ include_prefix () const
return this->include_prefix_;
}
+inline bool options::
+include_prefix_specified () const
+{
+ return this->include_prefix_specified_;
+}
+
+inline const std::string& options::
+guard_prefix () const
+{
+ return this->guard_prefix_;
+}
+
+inline bool options::
+guard_prefix_specified () const
+{
+ return this->guard_prefix_specified_;
+}
+
inline const std::string& options::
options_file () const
{
return this->options_file_;
}
+inline bool options::
+options_file_specified () const
+{
+ return this->options_file_specified_;
+}
+
inline const bool& options::
trace () const
{
return this->trace_;
}
+inline const std::string& options::
+mysql_engine () const
+{
+ return this->mysql_engine_;
+}
+
+inline bool options::
+mysql_engine_specified () const
+{
+ return this->mysql_engine_specified_;
+}
+
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 33d69f0..eff1312 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -84,16 +84,19 @@ check_decl_type (tree d, string const& name, string const& p, location_t l)
int tc (TREE_CODE (d));
char const* pc (p.c_str ());
- if (p == "column")
+ if (p == "id" ||
+ p == "column" ||
+ p == "type")
{
if (tc != FIELD_DECL)
{
error_at (l, "name %qs in odb pragma %qs does not refer to "
- "a member variable", name.c_str (), pc);
+ "a data member", name.c_str (), pc);
return false;
}
}
- else if (p == "table")
+ else if (p == "object" ||
+ p == "table")
{
if (tc != RECORD_TYPE)
{
@@ -122,7 +125,136 @@ handle_pragma (string const& p)
tree decl (0);
location_t loc (input_location);
- if (p == "column")
+ if (p == "object")
+ {
+ // object [(<identifier>)]
+ //
+
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_OPEN_PAREN)
+ {
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_NAME || tt == CPP_SCOPE)
+ {
+ string name;
+ decl = parse_scoped_name (t, tt, name, true, p);
+
+ if (decl == 0)
+ return;
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (!check_decl_type (decl, name, p, loc))
+ return;
+
+ if (tt != CPP_CLOSE_PAREN)
+ {
+ error ("%qs expected at the end of odb pragma %qs", ")", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+ }
+ else
+ {
+ error ("type name expected in odb pragma %qs", pc);
+ return;
+ }
+ }
+ }
+ else if (p == "table")
+ {
+ // table ([<identifier>,] "<name>")
+ //
+
+ if (pragma_lex (&t) != CPP_OPEN_PAREN)
+ {
+ error ("%qs expected after odb pragma %qs", "(", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_NAME || tt == CPP_SCOPE)
+ {
+ string name;
+ decl = parse_scoped_name (t, tt, name, true, p);
+
+ if (decl == 0)
+ return;
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (!check_decl_type (decl, name, p, loc))
+ return;
+
+ if (tt != CPP_COMMA)
+ {
+ error ("table name expected in odb pragma %qs", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+ }
+
+ if (tt != CPP_STRING)
+ {
+ error ("table name expected in odb pragma %qs", pc);
+ return;
+ }
+
+ val = TREE_STRING_POINTER (t);
+
+ if (pragma_lex (&t) != CPP_CLOSE_PAREN)
+ {
+ error ("%qs expected at the end of odb pragma %qs", ")", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+ }
+ else if (p == "id")
+ {
+ // id [(<identifier>)]
+ //
+
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_OPEN_PAREN)
+ {
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_NAME || tt == CPP_SCOPE)
+ {
+ string name;
+ decl = parse_scoped_name (t, tt, name, false, p);
+
+ if (decl == 0)
+ return;
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (!check_decl_type (decl, name, p, loc))
+ return;
+
+ if (tt != CPP_CLOSE_PAREN)
+ {
+ error ("%qs expected at the end of odb pragma %qs", ")", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+ }
+ else
+ {
+ error ("data member name expected in odb pragma %qs", pc);
+ return;
+ }
+ }
+ }
+ else if (p == "column")
{
// column ([<identifier>,] "<name>")
//
@@ -170,10 +302,12 @@ handle_pragma (string const& p)
error ("%qs expected at the end of odb pragma %qs", ")", pc);
return;
}
+
+ tt = pragma_lex (&t);
}
- else if (p == "table")
+ else if (p == "type")
{
- // table ([<identifier>,] "<name>")
+ // type ([<identifier>,] "<type>")
//
if (pragma_lex (&t) != CPP_OPEN_PAREN)
@@ -187,7 +321,7 @@ handle_pragma (string const& p)
if (tt == CPP_NAME || tt == CPP_SCOPE)
{
string name;
- decl = parse_scoped_name (t, tt, name, true, p);
+ decl = parse_scoped_name (t, tt, name, false, p);
if (decl == 0)
return;
@@ -199,7 +333,7 @@ handle_pragma (string const& p)
if (tt != CPP_COMMA)
{
- error ("table name expected in odb pragma %qs", pc);
+ error ("type name expected in odb pragma %qs", pc);
return;
}
@@ -208,7 +342,7 @@ handle_pragma (string const& p)
if (tt != CPP_STRING)
{
- error ("table name expected in odb pragma %qs", pc);
+ error ("type name expected in odb pragma %qs", pc);
return;
}
@@ -219,6 +353,8 @@ handle_pragma (string const& p)
error ("%qs expected at the end of odb pragma %qs", ")", pc);
return;
}
+
+ tt = pragma_lex (&t);
}
else
{
@@ -244,8 +380,6 @@ handle_pragma (string const& p)
// See if there are any more pragmas.
//
- tt = pragma_lex (&t);
-
if (tt == CPP_NAME)
{
handle_pragma (IDENTIFIER_POINTER (t));
@@ -255,9 +389,9 @@ handle_pragma (string const& p)
}
extern "C" void
-handle_pragma_odb_column (cpp_reader*)
+handle_pragma_odb_object (cpp_reader*)
{
- handle_pragma ("column");
+ handle_pragma ("object");
}
extern "C" void
@@ -267,8 +401,29 @@ handle_pragma_odb_table (cpp_reader*)
}
extern "C" void
+handle_pragma_odb_id (cpp_reader*)
+{
+ handle_pragma ("id");
+}
+
+extern "C" void
+handle_pragma_odb_column (cpp_reader*)
+{
+ handle_pragma ("column");
+}
+
+extern "C" void
+handle_pragma_odb_type (cpp_reader*)
+{
+ handle_pragma ("type");
+}
+
+extern "C" void
register_odb_pragmas (void*, void*)
{
- c_register_pragma_with_expansion ("odb", "column", handle_pragma_odb_column);
+ c_register_pragma_with_expansion ("odb", "object", handle_pragma_odb_object);
c_register_pragma_with_expansion ("odb", "table", handle_pragma_odb_table);
+ c_register_pragma_with_expansion ("odb", "id", handle_pragma_odb_id);
+ c_register_pragma_with_expansion ("odb", "column", handle_pragma_odb_column);
+ c_register_pragma_with_expansion ("odb", "type", handle_pragma_odb_type);
}
diff --git a/odb/source.cxx b/odb/source.cxx
index 02d26c4..0a14354 100644
--- a/odb/source.cxx
+++ b/odb/source.cxx
@@ -3,6 +3,7 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <odb/common.hxx>
#include <odb/source.hxx>
namespace
@@ -17,77 +18,71 @@ namespace
virtual void
traverse (type& c)
{
- if (c.file () != unit.file () || !odb_class (c))
+ if (c.file () != unit.file ())
return;
- string const& name (c.name ());
+ if (!c.count ("object"))
+ return;
+
+ string const& type (c.fq_name ());
+ string traits ("access::object_traits< " + type + " >");
+
+ id_member t (*this);
+ t.traverse (c);
+ semantics::data_member& id (*t.member ());
os << "// " << c.name () << endl
- << "//" << endl;
+ << "//" << endl
+ << endl;
- os << name << "::" << endl
- << name << " (::odb::image& i)"
+ // type_name ()
+ //
+ os << "const char* " << traits << "::" << endl
+ << "type_name ()"
<< "{"
+ << "return \"" << type << "\";"
<< "}";
- }
- private:
- bool
- odb_class (type& c)
- {
- // See if this class defines the ODB-specific c-tor.
+ // insert ()
//
- tree t (c.tree_node ());
-
- for (tree f (TYPE_METHODS (t)); f != 0; f = TREE_CHAIN (f))
- {
- if (DECL_CONSTRUCTOR_P (f))
- {
- // Get the argument list and skip the first (this) argument.
- //
- tree a (TREE_CHAIN (DECL_ARGUMENTS (f)));
-
- if (a == 0)
- continue;
-
- tree at (TREE_TYPE (a));
-
- // Check that it is ::odb::image&.
- //
- if (TREE_CODE (at) != REFERENCE_TYPE)
- continue;
-
- tree rt (TREE_TYPE (at));
- tree mt (TYPE_MAIN_VARIANT (rt));
-
- semantics::node* node (unit.find (mt));
-
- if (node == 0)
- continue;
-
- semantics::type* t_node (dynamic_cast<semantics::type*> (node));
-
- if (t_node == 0)
- continue;
-
- if (t_node->anonymous () || t_node->fq_name () != "::odb::image")
- continue;
-
- // Make sure it is unqualified.
- //
- if (cp_type_quals (rt) != TYPE_UNQUALIFIED)
- continue; // @@ Should probably be an error/warning.
+ os << "void " << traits << "::" << endl
+ << "insert (database&, const object_type& obj)"
+ << "{"
+ << "std::cout << \"insert \" << type_name () << \" id \" << " <<
+ "id (obj) << std::endl;"
+ << "}";
- // Check that it is the only argument.
- //
- if (TREE_CHAIN (a) != 0)
- continue; // @@ Should probably be an error/warning.
+ // update ()
+ //
+ os << "void " << traits << "::" << endl
+ << "update (database&, const object_type& obj)"
+ << "{"
+ << "std::cout << \"update \" << type_name () << \" id \" << " <<
+ "id (obj) << std::endl;"
+ << "}";
- return true;
- }
- }
+ // erase ()
+ //
+ os << "void " << traits << "::" << endl
+ << "erase (database&, const id_type& id)"
+ << "{"
+ << "std::cout << \"delete \" << type_name () << \" id \" << " <<
+ "id << std::endl;"
+ << "}";
- return false;
+ // find ()
+ //
+ os << traits << "::shared_ptr " << endl
+ << traits << "::" << endl
+ << "find (database&, const id_type& id)"
+ << "{"
+ << "std::cout << \"select \" << type_name () << \" id \" << " <<
+ "id << std::endl;"
+ << "shared_ptr r (access::object_factory< " << type <<
+ " >::create ());"
+ << "r->" << id.name () << " = id;"
+ << "return r;"
+ << "}";
}
};
}
@@ -97,7 +92,7 @@ generate_source (context& ctx)
{
traversal::unit unit;
traversal::defines unit_defines;
- namespace_ ns (ctx);
+ traversal::namespace_ ns;
class_ c (ctx);
unit >> unit_defines >> ns;
@@ -108,5 +103,16 @@ generate_source (context& ctx)
ns >> ns_defines >> ns;
ns_defines >> c;
+ ctx.os << "#include <iostream>" << endl
+ << endl;
+
+ //ctx.os << "#include <odb/database.hxx>" << endl
+ // << endl;
+
+ ctx.os << "namespace odb"
+ << "{";
+
unit.dispatch (ctx.unit);
+
+ ctx.os << "}";
}
diff --git a/odb/source.hxx b/odb/source.hxx
index 9fac039..2db3fe2 100644
--- a/odb/source.hxx
+++ b/odb/source.hxx
@@ -6,7 +6,7 @@
#ifndef ODB_SOURCE_HXX
#define ODB_SOURCE_HXX
-#include "context.hxx"
+#include <odb/context.hxx>
void
generate_source (context&);