aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-03-10 08:44:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-03-21 15:39:59 +0200
commit7ae497743c7b042904fe1f6b4153ab3f4763ff2b (patch)
tree08ba3f742f20d16d893856ccceb070094bd69225
parent2436f20262a41bd1cafa5107ab6d6799c03e0964 (diff)
Split MySQL code generator into common and db-specific parts
The common part (in relational/) still has some MySQL-specific parts. Also, add the notion of the current context which is used to avoid explicitly passing the context object to every generator's c-tor.
-rw-r--r--odb/common.cxx22
-rw-r--r--odb/common.hxx65
-rw-r--r--odb/context.cxx71
-rw-r--r--odb/context.hxx100
-rw-r--r--odb/emitter.cxx16
-rw-r--r--odb/generator.cxx26
-rw-r--r--odb/makefile24
-rw-r--r--odb/mysql/common.cxx566
-rw-r--r--odb/mysql/common.hxx270
-rw-r--r--odb/mysql/context.cxx637
-rw-r--r--odb/mysql/context.hxx127
-rw-r--r--odb/mysql/header.hxx17
-rw-r--r--odb/mysql/inline.hxx17
-rw-r--r--odb/mysql/schema.cxx11
-rw-r--r--odb/mysql/schema.hxx325
-rw-r--r--odb/mysql/source.hxx17
-rw-r--r--odb/mysql/sql-schema.cxx98
-rw-r--r--odb/mysql/sql-schema.hxx17
-rw-r--r--odb/relational/common.cxx178
-rw-r--r--odb/relational/common.hxx303
-rw-r--r--odb/relational/context.cxx54
-rw-r--r--odb/relational/context.hxx81
-rw-r--r--odb/relational/context.ixx31
-rw-r--r--odb/relational/generate.hxx36
-rw-r--r--odb/relational/header.cxx54
-rw-r--r--odb/relational/header.hxx (renamed from odb/mysql/header.cxx)287
-rw-r--r--odb/relational/inline.cxx42
-rw-r--r--odb/relational/inline.hxx (renamed from odb/mysql/inline.cxx)56
-rw-r--r--odb/relational/mysql/common.cxx448
-rw-r--r--odb/relational/mysql/common.hxx226
-rw-r--r--odb/relational/mysql/context.cxx642
-rw-r--r--odb/relational/mysql/context.hxx127
-rw-r--r--odb/relational/mysql/header.cxx166
-rw-r--r--odb/relational/mysql/schema.cxx53
-rw-r--r--odb/relational/mysql/source.cxx899
-rw-r--r--odb/relational/schema.cxx101
-rw-r--r--odb/relational/schema.hxx379
-rw-r--r--odb/relational/source.cxx79
-rw-r--r--odb/relational/source.hxx (renamed from odb/mysql/source.cxx)1314
-rw-r--r--odb/type-processor.cxx23
40 files changed, 4478 insertions, 3527 deletions
diff --git a/odb/common.cxx b/odb/common.cxx
index fe722df..342f28b 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -37,14 +37,23 @@ traverse_composite (semantics::data_member& m, semantics::class_& c)
void object_members_base::
traverse (semantics::class_& c)
{
+ bool obj (c.count ("object"));
+
// Ignore transient bases.
//
- if (!(c.count ("object") || context::comp_value (c)))
+ if (!(obj || context::comp_value (c)))
return;
- if (build_table_prefix_ && c.count ("object"))
+ semantics::class_* prev;
+ if (obj)
+ {
+ prev = object;
+ object = &c;
+ }
+
+ if (obj && build_table_prefix_)
{
- table_prefix_.prefix = ctx_->table_name (c);
+ table_prefix_.prefix = table_name (c);
table_prefix_.prefix += '_';
table_prefix_.level = 1;
@@ -59,6 +68,9 @@ traverse (semantics::class_& c)
inherits (c);
names (c);
}
+
+ if (obj)
+ object = prev;
}
void object_members_base::member::
@@ -76,7 +88,7 @@ traverse (semantics::data_member& m)
if (om_.build_prefix_)
{
old_prefix = om_.prefix_;
- om_.prefix_ += om_.ctx_->public_name (m);
+ om_.prefix_ += om_.public_name (m);
om_.prefix_ += '_';
}
@@ -99,7 +111,7 @@ traverse (semantics::data_member& m)
//
else
{
- string name (om_.ctx_->public_name_db (m));
+ string name (om_.public_name_db (m));
size_t n (name.size ());
om_.table_prefix_.prefix += name;
diff --git a/odb/common.hxx b/odb/common.hxx
index 9479b77..99741b2 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -13,7 +13,7 @@
// Traverse object members recursively by going into composite members.
//
-struct object_members_base: traversal::class_
+struct object_members_base: traversal::class_, virtual context
{
virtual void
simple (semantics::data_member&);
@@ -31,25 +31,21 @@ struct object_members_base: traversal::class_
public:
object_members_base ()
- : ctx_ (0),
- build_prefix_ (false),
- build_table_prefix_ (false),
- member_ (*this)
+ : member_ (*this)
{
- *this >> names_ >> member_;
- *this >> inherits_ >> *this;
+ init (false, false);
}
- object_members_base (context& c,
- bool build_prefix,
- bool build_table_prefix)
- : ctx_ (&c),
- build_prefix_ (build_prefix),
- build_table_prefix_ (build_table_prefix),
- member_ (*this)
+ object_members_base (bool build_prefix, bool build_table_prefix)
+ : member_ (*this)
{
- *this >> names_ >> member_;
- *this >> inherits_ >> *this;
+ init (build_prefix, build_table_prefix);
+ }
+
+ object_members_base (object_members_base const& x)
+ : context (), member_ (*this)
+ {
+ init (x.build_prefix_, x.build_table_prefix_);
}
virtual void
@@ -63,6 +59,17 @@ protected:
context::table_prefix table_prefix_;
private:
+ void
+ init (bool build_prefix, bool build_table_prefix)
+ {
+ build_prefix_ = build_prefix;
+ build_table_prefix_ = build_table_prefix;
+
+ *this >> names_ >> member_;
+ *this >> inherits_ >> *this;
+ }
+
+private:
struct member: traversal::data_member
{
member (object_members_base& om)
@@ -77,7 +84,6 @@ private:
object_members_base& om_;
};
- context* ctx_;
bool build_prefix_;
bool build_table_prefix_;
@@ -104,11 +110,16 @@ struct object_columns_base: traversal::class_
composite (semantics::data_member&, semantics::class_&);
public:
- object_columns_base (context& c)
- : member_ (c, *this)
+ object_columns_base ()
+ : member_ (*this)
{
- *this >> names_ >> member_;
- *this >> inherits_ >> *this;
+ init ();
+ }
+
+ object_columns_base (object_columns_base const&)
+ : member_ (*this)
+ {
+ init ();
}
virtual void
@@ -121,10 +132,18 @@ public:
std::string const& default_name);
private:
+ void
+ init ()
+ {
+ *this >> names_ >> member_;
+ *this >> inherits_ >> *this;
+ }
+
+private:
struct member: traversal::data_member, context
{
- member (context& c, object_columns_base& oc)
- : context (c), oc_ (oc), first_ (true)
+ member (object_columns_base& oc)
+ : oc_ (oc), first_ (true)
{
}
diff --git a/odb/context.cxx b/odb/context.cxx
index 6fde943..944756a 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -4,6 +4,7 @@
// license : GNU GPL v3; see accompanying LICENSE file
#include <cctype> // std::toupper, std::is{alpha,upper,lower}
+#include <cassert>
#include <odb/context.hxx>
#include <odb/common.hxx>
@@ -93,47 +94,85 @@ namespace
}
context::
+~context ()
+{
+ if (current_ == this)
+ current_ = 0;
+}
+
+context::
context (ostream& os_,
semantics::unit& u,
options_type const& ops,
data_ptr d)
- : data_ (d ? d : data_ptr (new (shared) data)),
- os (os_),
+ : data_ (d ? d : data_ptr (new (shared) data (os_))),
+ os (data_->os_),
unit (u),
options (ops),
keyword_set (data_->keyword_set_),
embedded_schema (ops.generate_schema () &&
- ops.schema_format ().count (schema_format::embedded))
+ ops.schema_format ().count (schema_format::embedded)),
+ object (data_->object_)
{
+ assert (current_ == 0);
+ current_ = this;
+
for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i)
data_->keyword_set_.insert (keywords[i]);
}
context::
-context (context& c)
+context (const context& c)
: data_ (c.data_),
os (c.os),
unit (c.unit),
options (c.options),
keyword_set (c.keyword_set),
- embedded_schema (c.embedded_schema)
+ embedded_schema (c.embedded_schema),
+ object (c.object)
{
}
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)
+context ()
+ : data_ (current ().data_),
+ os (current ().os),
+ unit (current ().unit),
+ options (current ().options),
+ keyword_set (current ().keyword_set),
+ embedded_schema (current ().embedded_schema),
+ object (current ().object)
{
}
-context::
-~context ()
+context* context::current_;
+
+void context::
+diverge (streambuf* sb)
+{
+ data_->os_stack_.push (data_->os_.rdbuf ());
+ data_->os_.rdbuf (sb);
+}
+
+void context::
+restore ()
{
+ data_->os_.rdbuf (data_->os_stack_.top ());
+ data_->os_stack_.pop ();
+}
+
+semantics::type& context::
+member_type (semantics::data_member& m, string const& key_prefix)
+{
+ if (key_prefix.empty ())
+ return m.type ();
+
+ string const key ("tree-" + key_prefix + "-type");
+
+ if (m.count (key))
+ return *indirect_value<semantics::type*> (m, key);
+
+ return *indirect_value<semantics::type*> (m.type (), key);
}
string context::
@@ -223,11 +262,11 @@ column_name (semantics::data_member& m, string const& p, string const& d) const
}
string context::
-column_type (semantics::data_member& m, string const& kp) const
+column_type (semantics::data_member& m, string const& kp)
{
return kp.empty ()
? m.get<string> ("column-type")
- : m.get<string> (kp + "-column-type");
+ : indirect_value<string> (m, kp + "-column-type");
}
string context::data::
diff --git a/odb/context.hxx b/odb/context.hxx
index 365936d..d8c457b 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -8,6 +8,7 @@
#include <map>
#include <set>
+#include <stack>
#include <string>
#include <ostream>
#include <cstddef> // std::size_t
@@ -50,19 +51,16 @@ class context
public:
typedef std::size_t size_t;
typedef std::string string;
+ typedef std::ostream ostream;
+
typedef ::options options_type;
static string
upcase (string const&);
public:
- static semantics::type&
- member_type (semantics::data_member& m, string const& key_prefix)
- {
- return key_prefix.empty ()
- ? m.type ()
- : *m.type ().get<semantics::type*> ("tree-" + key_prefix + "-type");
- }
+ semantics::type&
+ member_type (semantics::data_member& m, string const& key_prefix);
// Predicates.
//
@@ -132,9 +130,8 @@ public:
string const& key_prefix,
string const& default_name) const;
- virtual string
- column_type (semantics::data_member&,
- string const& key_prefix = string ()) const;
+ string
+ column_type (semantics::data_member&, string const& key_prefix = string ());
// Cleaned-up member name that can be used for database names.
//
@@ -184,31 +181,31 @@ public:
public:
typedef ::pointer_kind pointer_kind_type;
- static pointer_kind_type
+ pointer_kind_type
pointer_kind (semantics::type& p)
{
return p.get<pointer_kind_type> ("pointer-kind");
}
- static bool
+ bool
lazy_pointer (semantics::type& p)
{
return p.get<bool> ("pointer-lazy");
}
- static bool
+ bool
weak_pointer (semantics::type& p)
{
return pointer_kind (p) == pk_weak;
}
- static bool
+ bool
null_pointer (semantics::data_member& m)
{
return !(m.count ("not-null") || m.type ().count ("not-null"));
}
- static bool
+ bool
null_pointer (semantics::data_member& m, string const& key_prefix)
{
if (key_prefix.empty ())
@@ -219,7 +216,7 @@ public:
member_type (m, key_prefix).count ("not-null"));
}
- static semantics::data_member*
+ semantics::data_member*
inverse (semantics::data_member& m)
{
return object_pointer (m.type ())
@@ -227,7 +224,7 @@ public:
: 0;
}
- static semantics::data_member*
+ semantics::data_member*
inverse (semantics::data_member& m, string const& key_prefix)
{
if (key_prefix.empty ())
@@ -284,25 +281,55 @@ public:
static unsigned short const test_straight_container = 0x10;
static unsigned short const test_inverse_container = 0x20;
- static bool
+ bool
is_a (semantics::data_member& m, unsigned short flags)
{
return is_a (m, flags, m.type (), "");
}
- static bool
+ bool
is_a (semantics::data_member&,
unsigned short flags,
semantics::type&,
string const& key_prefix);
- static bool
+ bool
has_a (semantics::type&, unsigned short flags);
+ // Diverge output.
+ //
+public:
+ void
+ diverge (std::ostream& os)
+ {
+ diverge (os.rdbuf ());
+ }
+
+ void
+ diverge (std::streambuf* sb);
+
+ void
+ restore ();
+
+ // Implementation details.
+ //
private:
static bool
comp_value_ (semantics::class_&);
+ template <typename X>
+ X
+ indirect_value (semantics::context const& c, string const& key)
+ {
+ typedef X (*func) (context&);
+ std::type_info const& ti (c.type_info (key));
+
+ if (ti == typeid (func))
+ return c.get<func> (key) (*this);
+ else
+ return c.get<X> (key);
+ }
+
protected:
struct data;
typedef cutl::shared_ptr<data> data_ptr;
@@ -318,6 +345,8 @@ public:
bool embedded_schema;
+ semantics::class_*& object; // Object currently being traversed.
+
struct db_type_type
{
db_type_type () {}
@@ -347,7 +376,15 @@ protected:
struct data
{
- virtual ~data () {}
+ virtual
+ ~data () {}
+ data (std::ostream& os): os_ (os.rdbuf ()), object_ (0) {}
+
+ public:
+ std::ostream os_;
+ std::stack<std::streambuf*> os_stack_;
+
+ semantics::class_* object_;
// Per-database customizable functionality.
//
@@ -366,15 +403,28 @@ protected:
};
public:
+ virtual
+ ~context ();
+
+ typedef context root_context;
+
context (std::ostream&,
semantics::unit&,
options_type const&,
data_ptr = data_ptr ());
- context (context&);
- context (context&, std::ostream&);
+ context (const context&);
- virtual
- ~context ();
+ static context&
+ current ()
+ {
+ return *current_;
+ }
+
+protected:
+ context ();
+
+private:
+ static context* current_;
private:
context&
diff --git a/odb/emitter.cxx b/odb/emitter.cxx
index 6cfe64a..2989ffb 100644
--- a/odb/emitter.cxx
+++ b/odb/emitter.cxx
@@ -3,6 +3,7 @@
// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <odb/context.hxx>
#include <odb/emitter.hxx>
using namespace std;
@@ -30,7 +31,22 @@ sync ()
s.resize (n - 1);
}
+ // Temporary restore output diversion.
+ //
+ bool r (false);
+ context& ctx (context::current ());
+
+ if (ctx.os.rdbuf () == this)
+ {
+ ctx.restore ();
+ r = true;
+ }
+
e_.line (s);
+
+ if (r)
+ ctx.diverge (this);
+
str (string ());
return 0;
}
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 91548e4..e0187d6 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -28,11 +28,9 @@
#include <odb/tracer/inline.hxx>
#include <odb/tracer/source.hxx>
-#include <odb/mysql/context.hxx>
-#include <odb/mysql/header.hxx>
-#include <odb/mysql/inline.hxx>
-#include <odb/mysql/source.hxx>
-#include <odb/mysql/sql-schema.hxx>
+#include <odb/relational/generate.hxx>
+
+#include <odb/relational/mysql/context.hxx>
using namespace std;
using namespace cutl;
@@ -119,7 +117,7 @@ generate (options const& ops, semantics::unit& unit, path const& p)
{
case database::mysql:
{
- ctx.reset (new mysql::context (cerr, unit, ops));
+ ctx.reset (new relational::mysql::context (cerr, unit, ops));
break;
}
case database::tracer:
@@ -249,7 +247,7 @@ generate (options const& ops, semantics::unit& unit, path const& p)
{
case database::mysql:
{
- ctx.reset (new mysql::context (hxx, unit, ops));
+ ctx.reset (new relational::mysql::context (hxx, unit, ops));
break;
}
case database::tracer:
@@ -297,7 +295,7 @@ generate (options const& ops, semantics::unit& unit, path const& p)
{
case database::mysql:
{
- mysql::generate_header (static_cast<mysql::context&> (*ctx));
+ relational::header::generate ();
break;
}
case database::tracer:
@@ -336,7 +334,7 @@ generate (options const& ops, semantics::unit& unit, path const& p)
{
case database::mysql:
{
- ctx.reset (new mysql::context (ixx, unit, ops));
+ ctx.reset (new relational::mysql::context (ixx, unit, ops));
break;
}
case database::tracer:
@@ -361,7 +359,7 @@ generate (options const& ops, semantics::unit& unit, path const& p)
{
case database::mysql:
{
- mysql::generate_inline (static_cast<mysql::context&> (*ctx));
+ relational::inline_::generate ();
break;
}
case database::tracer:
@@ -405,8 +403,8 @@ generate (options const& ops, semantics::unit& unit, path const& p)
{
case database::mysql:
{
- mysql::context ctx (cxx, unit, ops);
- mysql::generate_source (ctx);
+ relational::mysql::context ctx (cxx, unit, ops);
+ relational::source::generate ();
break;
}
case database::tracer:
@@ -441,8 +439,8 @@ generate (options const& ops, semantics::unit& unit, path const& p)
{
case database::mysql:
{
- mysql::context ctx (sql, unit, ops);
- mysql::generate_schema (ctx);
+ relational::mysql::context ctx (sql, unit, ops);
+ relational::schema::generate ();
break;
}
case database::tracer:
diff --git a/odb/makefile b/odb/makefile
index ea9385a..fafb406 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -30,16 +30,24 @@ tracer/header.cxx \
tracer/inline.cxx \
tracer/source.cxx
-# MySQL
+# Relational
#
cxx_ptun += \
-mysql/context.cxx \
-mysql/common.cxx \
-mysql/header.cxx \
-mysql/inline.cxx \
-mysql/source.cxx \
-mysql/schema.cxx \
-mysql/sql-schema.cxx
+relational/common.cxx \
+relational/context.cxx \
+relational/header.cxx \
+relational/inline.cxx \
+relational/source.cxx \
+relational/schema.cxx
+
+# Relational/MySQL
+#
+cxx_ptun += \
+relational/mysql/common.cxx \
+relational/mysql/context.cxx \
+relational/mysql/header.cxx \
+relational/mysql/source.cxx \
+relational/mysql/schema.cxx
cxx_ptun += \
semantics/class.cxx \
diff --git a/odb/mysql/common.cxx b/odb/mysql/common.cxx
deleted file mode 100644
index b771990..0000000
--- a/odb/mysql/common.cxx
+++ /dev/null
@@ -1,566 +0,0 @@
-// file : odb/mysql/common.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 <cassert>
-
-#include <odb/mysql/common.hxx>
-
-using namespace std;
-
-namespace mysql
-{
- //
- // member_base
- //
-
- void member_base::
- traverse (semantics::data_member& m)
- {
- if (m.count ("transient"))
- return;
-
- string var;
-
- if (!var_override_.empty ())
- var = var_override_;
- else
- {
- string const& name (m.name ());
- var = name + (name[name.size () - 1] == '_' ? "" : "_");
- }
-
- semantics::type& t (type_override_ != 0 ? *type_override_ : m.type ());
-
- if (comp_value (t))
- {
- member_info mi (m, t, var, fq_type_override_);
- if (pre (mi))
- {
- traverse_composite (mi);
- post (mi);
- }
- }
- else if (container (t))
- {
- member_info mi (m, t, var, fq_type_override_);
- if (pre (mi))
- {
- traverse_container (mi);
- post (mi);
- }
- }
- else
- {
- sql_type const& st (db_type (m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (t))
- {
- member_info mi (m, id_member (*c).type (), var, fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_object_pointer (mi);
- post (mi);
- }
- }
- else
- {
- member_info mi (m, t, var, fq_type_override_);
- mi.st = &st;
- if (pre (mi))
- {
- traverse_simple (mi);
- post (mi);
- }
- }
- }
- }
-
- void member_base::
- traverse_simple (member_info& mi)
- {
- switch (mi.st->type)
- {
- // Integral types.
- //
- case sql_type::TINYINT:
- case sql_type::SMALLINT:
- case sql_type::MEDIUMINT:
- case sql_type::INT:
- case sql_type::BIGINT:
- {
- traverse_integer (mi);
- break;
- }
-
- // Float types.
- //
- case sql_type::FLOAT:
- case sql_type::DOUBLE:
- {
- traverse_float (mi);
- break;
- }
- case sql_type::DECIMAL:
- {
- traverse_decimal (mi);
- break;
- }
-
- // Data-time types.
- //
- case sql_type::DATE:
- case sql_type::TIME:
- case sql_type::DATETIME:
- case sql_type::TIMESTAMP:
- case sql_type::YEAR:
- {
- traverse_date_time (mi);
- break;
- }
-
- // String and binary types.
- //
- case sql_type::CHAR:
- case sql_type::VARCHAR:
- case sql_type::TINYTEXT:
- case sql_type::TEXT:
- case sql_type::MEDIUMTEXT:
- case sql_type::LONGTEXT:
- {
- // For string types the limit is in characters rather
- // than in bytes. The fixed-length pre-allocated buffer
- // optimization can only be used for 1-byte encodings.
- // To support this we will need the character encoding
- // in sql_type.
- //
- traverse_long_string (mi);
- break;
- }
- case sql_type::BINARY:
- case sql_type::TINYBLOB:
- {
- // BINARY's range is always 255 or less from MySQL 5.0.3.
- // TINYBLOB can only store up to 255 bytes.
- //
- traverse_short_string (mi);
- break;
- }
- case sql_type::VARBINARY:
- case sql_type::BLOB:
- case sql_type::MEDIUMBLOB:
- case sql_type::LONGBLOB:
- {
- if (mi.st->range && mi.st->range_value <= 255)
- traverse_short_string (mi);
- else
- traverse_long_string (mi);
-
- break;
- }
-
- // Other types.
- //
- case sql_type::BIT:
- {
- traverse_bit (mi);
- break;
- }
- case sql_type::ENUM:
- {
- traverse_enum (mi);
- break;
- }
- case sql_type::SET:
- {
- traverse_set (mi);
- break;
- }
- case sql_type::invalid:
- {
- assert (false);
- break;
- }
- }
- }
-
- //
- // member_image_type
- //
-
- namespace
- {
- const char* integer_types[] =
- {
- "char",
- "short",
- "int",
- "int",
- "long long"
- };
-
- const char* float_types[] =
- {
- "float",
- "double"
- };
- }
-
- member_image_type::
- member_image_type (context& c)
- : member_base (c)
- {
- }
-
- member_image_type::
- member_image_type (context& c,
- semantics::type& type,
- string const& fq_type,
- string const& key_prefix)
- : member_base (c, "", type, fq_type, key_prefix)
- {
- }
-
- string member_image_type::
- image_type (semantics::data_member& m)
- {
- type_.clear ();
- member_base::traverse (m);
- return type_;
- }
-
- void member_image_type::
- traverse_composite (member_info& mi)
- {
- type_ = "composite_value_traits< " + mi.fq_type () + " >::image_type";
- }
-
- void member_image_type::
- traverse_integer (member_info& mi)
- {
- if (mi.st->unsign)
- type_ = "unsigned ";
- else if (mi.st->type == sql_type::TINYINT)
- type_ = "signed ";
-
- type_ += integer_types[mi.st->type - sql_type::TINYINT];
- }
-
- void member_image_type::
- traverse_float (member_info& mi)
- {
- type_ = float_types[mi.st->type - sql_type::FLOAT];
- }
-
- void member_image_type::
- traverse_decimal (member_info&)
- {
- type_ = "details::buffer";
- }
-
- void member_image_type::
- traverse_date_time (member_info& mi)
- {
- if (mi.st->type == sql_type::YEAR)
- type_ = "short";
- else
- type_ = "MYSQL_TIME";
- }
-
- void member_image_type::
- traverse_string (member_info&)
- {
- type_ = "details::buffer";
- }
-
- void member_image_type::
- traverse_bit (member_info&)
- {
- type_ = "unsigned char*";
- }
-
- void member_image_type::
- traverse_enum (member_info&)
- {
- // Represented as string.
- //
- type_ = "details::buffer";
- }
-
- void member_image_type::
- traverse_set (member_info&)
- {
- // Represented as string.
- //
- type_ = "details::buffer";
- }
-
- //
- // member_database_type
- //
-
- namespace
- {
- const char* integer_database_id[] =
- {
- "id_tiny",
- "id_utiny",
- "id_short",
- "id_ushort",
- "id_long", // INT24
- "id_ulong", // INT24 UNSIGNED
- "id_long",
- "id_ulong",
- "id_longlong",
- "id_ulonglong"
- };
-
- const char* float_database_id[] =
- {
- "id_float",
- "id_double"
- };
-
- const char* date_time_database_id[] =
- {
- "id_date",
- "id_time",
- "id_datetime",
- "id_timestamp",
- "id_year"
- };
-
- const char* char_bin_database_id[] =
- {
- "id_string", // CHAR
- "id_blob", // BINARY,
- "id_string", // VARCHAR
- "id_blob", // VARBINARY
- "id_string", // TINYTEXT
- "id_blob", // TINYBLOB
- "id_string", // TEXT
- "id_blob", // BLOB
- "id_string", // MEDIUMTEXT
- "id_blob", // MEDIUMBLOB
- "id_string", // LONGTEXT
- "id_blob" // LONGBLOB
- };
- }
-
- member_database_type::
- member_database_type (context& c)
- : member_base (c)
- {
- }
-
- member_database_type::
- member_database_type (context& c,
- semantics::type& type,
- string const& fq_type,
- string const& key_prefix)
- : member_base (c, "", type, fq_type, key_prefix)
- {
- }
-
- string member_database_type::
- database_type (type& m)
- {
- type_.clear ();
- member_base::traverse (m);
- return type_;
- }
-
- void member_database_type::
- traverse_composite (member_info&)
- {
- assert (false);
- }
-
- void member_database_type::
- traverse_integer (member_info& mi)
- {
- size_t i ((mi.st->type - sql_type::TINYINT) * 2 + (mi.st->unsign ? 1 : 0));
- type_ = string ("mysql::") + integer_database_id[i];
- }
-
- void member_database_type::
- traverse_float (member_info& mi)
- {
- type_ = string ("mysql::") +
- float_database_id[mi.st->type - sql_type::FLOAT];
- }
-
- void member_database_type::
- traverse_decimal (member_info&)
- {
- type_ = "mysql::id_decimal";
- }
-
- void member_database_type::
- traverse_date_time (member_info& mi)
- {
- type_ = string ("mysql::") +
- date_time_database_id[mi.st->type - sql_type::DATE];
- }
-
- void member_database_type::
- traverse_string (member_info& mi)
- {
- type_ = string ("mysql::") +
- char_bin_database_id[mi.st->type - sql_type::CHAR];
- }
-
- void member_database_type::
- traverse_bit (member_info&)
- {
- type_ = "mysql::id_bit";
- }
-
- void member_database_type::
- traverse_enum (member_info&)
- {
- type_ = "mysql::id_enum";
- }
-
- void member_database_type::
- traverse_set (member_info&)
- {
- type_ = "mysql::id_set";
- }
-
- //
- // query_columns
- //
-
- query_columns::
- query_columns (context& c)
- : object_columns_base (c),
- context (c),
- ptr_ (true),
- decl_ (true),
- member_image_type_ (c),
- member_database_type_ (c)
- {
- }
-
- query_columns::
- query_columns (context& c, semantics::class_& cl)
- : object_columns_base (c),
- context (c),
- ptr_ (true),
- decl_ (false),
- member_image_type_ (c),
- member_database_type_ (c)
- {
- scope_ = "access::object_traits< " + cl.fq_name () + " >::query_type";
- table_ = table_name (cl);
- }
-
- void query_columns::
- composite (semantics::data_member& m, semantics::class_& c)
- {
- string name (public_name (m));
-
- if (decl_)
- {
- os << "// " << name << endl
- << "//" << endl
- << "struct " << name
- << "{";
-
- object_columns_base::composite (m, c);
-
- os << "};";
- }
- else
- {
- string old_scope (scope_);
- scope_ += "::" + name;
-
- object_columns_base::composite (m, c);
-
- scope_ = old_scope;
- }
- }
-
- bool query_columns::
- column (semantics::data_member& m, string const& col_name, bool)
- {
- string name (public_name (m));
-
- if (semantics::class_* c = object_pointer (m.type ()))
- {
- // We cannot just typedef the query_type from the referenced
- // object for two reasons: (1) it may not be defined yet and
- // (2) it will contain columns for its own pointers which
- // won't work (for now we only support one level of indirection
- // in queries). So we will have to duplicate the columns (sans
- // the pointers).
- //
- if (ptr_)
- {
- ptr_ = false;
-
- if (decl_)
- {
- os << "// " << name << endl
- << "//" << endl
- << "struct " << name
- << "{";
-
- traverse (*c);
-
- os << "};";
- }
- else
- {
- string old_scope (scope_), old_table (table_);
- scope_ += "::" + name;
- table_ = table_name (*c);
- traverse (*c);
- table_ = old_table;
- scope_ = old_scope;
- }
-
- ptr_ = true;
- }
- }
- else
- {
- string db_type (member_database_type_.database_type (m));
-
- string type (
- "mysql::value_traits< "
- + m.type ().fq_name (m.belongs ().hint ()) + ", "
- + member_image_type_.image_type (m) + ", "
- + db_type
- + " >::query_type");
-
- if (decl_)
- {
- os << "// " << name << endl
- << "//" << endl
- << "static const mysql::query_column<" << endl
- << " " << type << "," << endl
- << " " << db_type << ">" << endl
- << name << ";"
- << endl;
- }
- else
- {
- string column ("\"`" + table_ + "`.`" + col_name + "`\"");
-
- os << "const mysql::query_column<" << endl
- << " " << type << "," << endl
- << " " << db_type << ">" << endl
- << scope_ << "::" << name << " (" << endl
- << column << ");"
- << endl;
- }
- }
-
- return true;
- }
-}
diff --git a/odb/mysql/common.hxx b/odb/mysql/common.hxx
deleted file mode 100644
index df01e5f..0000000
--- a/odb/mysql/common.hxx
+++ /dev/null
@@ -1,270 +0,0 @@
-// file : odb/mysql/common.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_COMMON_HXX
-#define ODB_MYSQL_COMMON_HXX
-
-#include <odb/common.hxx>
-#include <odb/mysql/context.hxx>
-
-namespace mysql
-{
- struct member_base: traversal::data_member, context
- {
- member_base (context& c, string const& var = string ())
- : context (c), var_override_ (var), type_override_ (0)
- {
- }
-
- member_base (context& c,
- string const& var,
- semantics::type& type,
- string const& fq_type,
- string const& key_prefix)
- : context (c),
- var_override_ (var),
- type_override_ (&type),
- fq_type_override_ (fq_type),
- key_prefix_ (key_prefix)
- {
- }
-
- virtual void
- traverse (semantics::data_member& m);
-
- struct member_info
- {
- semantics::data_member& m; // Member.
- semantics::type& t; // Member C++ type (m.type () may != t).
- sql_type const* st; // Member SQL type (only simple value types).
- string& var; // Member variable name with trailing '_'.
-
- // C++ type fq-name.
- //
- string
- fq_type () const
- {
- // Use the original type from 'm' instead of 't' since the hint
- // may be invalid for a different type. Plus, if a type is
- // overriden, then the fq_type must be as well.
- //
- return fq_type_.empty ()
- ? m.type ().fq_name (m.belongs ().hint ())
- : fq_type_;
- }
-
- string const& fq_type_;
-
- member_info (semantics::data_member& m_,
- semantics::type& t_,
- string& var_,
- string const& fq_type)
- : m (m_), t (t_), st (0), var (var_), fq_type_ (fq_type)
- {
- }
- };
-
- // The false return value indicates that no further callbacks
- // should be called for this member.
- //
- virtual bool
- pre (member_info&)
- {
- return true;
- }
-
- virtual void
- post (member_info&)
- {
- }
-
- virtual void
- traverse_composite (member_info&)
- {
- }
-
- virtual void
- traverse_container (member_info&)
- {
- }
-
- virtual void
- traverse_object_pointer (member_info& mi)
- {
- traverse_simple (mi);
- }
-
- virtual void
- traverse_simple (member_info&);
-
- virtual void
- traverse_integer (member_info&)
- {
- }
-
- virtual void
- traverse_float (member_info&)
- {
- }
-
- virtual void
- traverse_decimal (member_info&)
- {
- }
-
- virtual void
- traverse_date_time (member_info&)
- {
- }
-
- virtual void
- traverse_string (member_info&)
- {
- }
-
- virtual void
- traverse_short_string (member_info& mi)
- {
- traverse_string (mi);
- }
-
- virtual void
- traverse_long_string (member_info& mi)
- {
- traverse_string (mi);
- }
-
- virtual void
- traverse_bit (member_info&)
- {
- }
-
- virtual void
- traverse_enum (member_info&)
- {
- }
-
- virtual void
- traverse_set (member_info&)
- {
- }
-
- protected:
- string var_override_;
- semantics::type* type_override_;
- string fq_type_override_;
- string key_prefix_;
- };
-
- struct member_image_type: member_base
- {
- member_image_type (context&);
-
- member_image_type (context& c,
- semantics::type& type,
- string const& fq_type,
- string const& key_prefix);
-
- string
- image_type (semantics::data_member&);
-
- virtual void
- traverse_composite (member_info&);
-
- virtual void
- traverse_integer (member_info&);
-
- virtual void
- traverse_float (member_info&);
-
- virtual void
- traverse_decimal (member_info&);
-
- virtual void
- traverse_date_time (member_info&);
-
- virtual void
- traverse_string (member_info&);
-
- virtual void
- traverse_bit (member_info&);
-
- virtual void
- traverse_enum (member_info&);
-
- virtual void
- traverse_set (member_info&);
-
- private:
- string type_;
- };
-
- struct member_database_type: member_base
- {
- member_database_type (context&);
-
- member_database_type (context& c,
- semantics::type& type,
- string const& fq_type,
- string const& key_prefix);
-
- string
- database_type (type&);
-
- virtual void
- traverse_composite (member_info&);
-
- virtual void
- traverse_integer (member_info&);
-
- virtual void
- traverse_float (member_info&);
-
- virtual void
- traverse_decimal (member_info&);
-
- virtual void
- traverse_date_time (member_info&);
-
- virtual void
- traverse_string (member_info&);
-
- virtual void
- traverse_bit (member_info&);
-
- virtual void
- traverse_enum (member_info&);
-
- virtual void
- traverse_set (member_info&);
-
- private:
- string type_;
- };
-
- struct query_columns: object_columns_base, context
- {
- query_columns (context&);
- query_columns (context&, semantics::class_&);
-
- virtual void
- composite (semantics::data_member&, semantics::class_&);
-
- virtual bool
- column (semantics::data_member&, string const&, bool);
-
- private:
- bool ptr_;
- bool decl_;
-
- string scope_;
- string table_;
-
- member_image_type member_image_type_;
- member_database_type member_database_type_;
- };
-}
-
-#endif // ODB_MYSQL_COMMON_HXX
diff --git a/odb/mysql/context.cxx b/odb/mysql/context.cxx
deleted file mode 100644
index b7d6540..0000000
--- a/odb/mysql/context.cxx
+++ /dev/null
@@ -1,637 +0,0 @@
-// file : odb/mysql/context.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 <sstream>
-
-#include <odb/sql-token.hxx>
-#include <odb/sql-lexer.hxx>
-
-#include <odb/mysql/context.hxx>
-#include <odb/mysql/common.hxx>
-
-using namespace std;
-
-namespace mysql
-{
- namespace
- {
- struct type_map_entry
- {
- const char* const cxx_type;
- const char* const db_type;
- const char* const db_id_type;
- };
-
- type_map_entry type_map[] =
- {
- {"bool", "TINYINT(1)", 0},
-
- {"char", "TINYINT", 0},
- {"signed char", "TINYINT", 0},
- {"unsigned char", "TINYINT UNSIGNED", 0},
-
- {"short int", "SMALLINT", 0},
- {"short unsigned int", "SMALLINT UNSIGNED", 0},
-
- {"int", "INT", 0},
- {"unsigned int", "INT UNSIGNED", 0},
-
- {"long int", "BIGINT", 0},
- {"long unsigned int", "BIGINT UNSIGNED", 0},
-
- {"long long int", "BIGINT", 0},
- {"long long unsigned int", "BIGINT UNSIGNED", 0},
-
- {"float", "FLOAT", 0},
- {"double", "DOUBLE", 0},
-
- {"::std::string", "TEXT", "VARCHAR (255)"}
- };
- }
-
- context::
- context (ostream& os, semantics::unit& u, options_type const& ops)
- : base_context (os, u, ops, data_ptr (new (shared) data)),
- data_ (static_cast<data*> (base_context::data_.get ()))
- {
- // Populate the C++ type to DB type map.
- //
- for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i)
- {
- type_map_entry const& e (type_map[i]);
-
- type_map_type::value_type v (
- e.cxx_type,
- db_type_type (e.db_type, e.db_id_type ? e.db_id_type : e.db_type));
-
- data_->type_map_.insert (v);
- }
- }
-
- context::
- context (context& c)
- : base_context (c),
- data_ (c.data_)
- {
- }
-
- context::
- context (context& c, ostream& os)
- : base_context (c, os),
- data_ (c.data_)
- {
- }
-
- namespace
- {
- struct has_grow: traversal::class_
- {
- has_grow (bool& r)
- : r_ (r)
- {
- *this >> inherits_ >> *this;
- }
-
- virtual void
- traverse (type& c)
- {
- // Ignore transient bases.
- //
- if (!(c.count ("object") || context::comp_value (c)))
- return;
-
- if (c.count ("mysql::grow"))
- r_ = c.get<bool> ("mysql::grow");
- else
- {
- // r_ should be false.
- //
- inherits (c);
-
- if (!r_)
- names (c);
-
- c.set ("mysql::grow", r_);
- }
- }
-
- private:
- bool& r_;
- traversal::inherits inherits_;
- };
-
- struct has_grow_member: member_base
- {
- has_grow_member (context& c, bool& r)
- : member_base (c), r_ (r)
- {
- }
-
- has_grow_member (context& c,
- bool& r,
- semantics::type& type,
- string const& key_prefix)
- : member_base (c, "", type, "", key_prefix), r_ (r)
- {
- }
-
- virtual void
- traverse_composite (member_info& mi)
- {
- // By calling grow() instead of recursing, we reset any overrides.
- //
- r_ = r_ || context::grow (dynamic_cast<semantics::class_&> (mi.t));
- }
-
- virtual void
- traverse_decimal (member_info&)
- {
- r_ = true;
- }
-
- virtual void
- traverse_long_string (member_info&)
- {
- r_ = true;
- }
-
- virtual void
- traverse_short_string (member_info&)
- {
- r_ = true; // @@ Short string optimization disabled.
- }
-
- virtual void
- traverse_enum (member_info&)
- {
- r_ = true;
- }
-
- virtual void
- traverse_set (member_info&)
- {
- r_ = true;
- }
-
- private:
- bool& r_;
- };
- }
-
- bool context::
- grow (semantics::class_& c)
- {
- if (c.count ("mysql::grow"))
- return c.get<bool> ("mysql::grow");
-
- bool r (false);
- has_grow ct (r);
- has_grow_member mt (*this, r);
- traversal::names names;
- ct >> names >> mt;
- ct.traverse (c);
- return r;
- }
-
- bool context::
- grow (semantics::data_member& m)
- {
- bool r (false);
- has_grow_member mt (*this, r);
- mt.traverse (m);
- return r;
- }
-
- bool context::
- grow (semantics::data_member& m, semantics::type& t, string const& kp)
- {
- bool r (false);
- has_grow_member mt (*this, r, t, kp);
- mt.traverse (m);
- return r;
- }
-
- //
- // SQL type parsing.
- //
-
- string context::data::
- column_type_impl (semantics::type& t,
- string const& type,
- semantics::context& ctx,
- column_type_flags f) const
- {
- string r (::context::data::column_type_impl (t, type, ctx, f));
-
- if (!r.empty () && ctx.count ("auto") && (f & ctf_object_id_ref) == 0)
- r += " AUTO_INCREMENT";
-
- return r;
- }
-
- static sql_type
- parse_sql_type (semantics::data_member& m, std::string const& sql);
-
- sql_type const& context::
- db_type (semantics::data_member& m, string const& kp)
- {
- string key (kp.empty () ? string ("db-type") : kp + "-db-type");
-
- if (!m.count (key))
- m.set (key, parse_sql_type (m, column_type (m, kp)));
-
- return m.get<sql_type> (key);
- }
-
- static sql_type
- parse_sql_type (semantics::data_member& m, string const& sql)
- {
- try
- {
- sql_type r;
- sql_lexer l (sql);
-
- // While most type names use single identifier, there are
- // a couple of exceptions to this rule:
- //
- // NATIONAL CHAR|VARCHAR
- // CHAR BYTE (BINARY)
- // CHARACTER VARYING (VARCHAR)
- // LONG VARBINARY (MEDIUMBLOB)
- // LONG VARCHAR (MEDIUMTEXT)
- //
- //
- enum state
- {
- parse_prefix,
- parse_name,
- parse_range,
- parse_sign,
- parse_done
- };
-
- state s (parse_prefix);
- string prefix;
-
- for (sql_token t (l.next ());
- s != parse_done && t.type () != sql_token::t_eos;
- t = l.next ())
- {
- sql_token::token_type tt (t.type ());
-
- switch (s)
- {
- case parse_prefix:
- {
- if (tt == sql_token::t_identifier)
- {
- string const& id (context::upcase (t.identifier ()));
-
- if (id == "NATIONAL" ||
- id == "CHAR" ||
- id == "CHARACTER" ||
- id == "LONG")
- {
- prefix = id;
- s = parse_name;
- continue;
- }
- }
-
- // Fall through.
- //
- s = parse_name;
- }
- case parse_name:
- {
- if (tt == sql_token::t_identifier)
- {
- bool match (true);
- string const& id (context::upcase (t.identifier ()));
-
- // Numeric types.
- //
- if (id == "BIT")
- {
- r.type = sql_type::BIT;
- }
- else if (id == "TINYINT" || id == "INT1")
- {
- r.type = sql_type::TINYINT;
- }
- else if (id == "BOOL" || id == "BOOLEAN")
- {
- r.type = sql_type::TINYINT;
- r.range = true;
- r.range_value = 1;
- }
- else if (id == "SMALLINT" || id == "INT2")
- {
- r.type = sql_type::SMALLINT;
- }
- else if (id == "MEDIUMINT" || id == "INT3" || id == "MIDDLEINT")
- {
- r.type = sql_type::MEDIUMINT;
- }
- else if (id == "INT" || id == "INTEGER" || id == "INT4")
- {
- r.type = sql_type::INT;
- }
- else if (id == "BIGINT" || id == "INT8")
- {
- r.type = sql_type::BIGINT;
- }
- else if (id == "SERIAL")
- {
- r.type = sql_type::BIGINT;
- r.unsign = true;
- }
- else if (id == "FLOAT" || id == "FLOAT4")
- {
- r.type = sql_type::FLOAT;
- }
- else if (id == "DOUBLE" || id == "FLOAT8")
- {
- r.type = sql_type::DOUBLE;
- }
- else if (id == "DECIMAL" ||
- id == "DEC" ||
- id == "NUMERIC" ||
- id == "FIXED")
- {
- r.type = sql_type::DECIMAL;
- }
- //
- // Date-time types.
- //
- else if (id == "DATE")
- {
- r.type = sql_type::DATE;
- }
- else if (id == "TIME")
- {
- r.type = sql_type::TIME;
- }
- else if (id == "DATETIME")
- {
- r.type = sql_type::DATETIME;
- }
- else if (id == "TIMESTAMP")
- {
- r.type = sql_type::TIMESTAMP;
- }
- else if (id == "YEAR")
- {
- r.type = sql_type::YEAR;
- }
- //
- // String and binary types.
- //
- else if (id == "NCHAR")
- {
- r.type = sql_type::CHAR;
- }
- else if (id == "VARCHAR")
- {
- r.type = prefix == "LONG"
- ? sql_type::MEDIUMTEXT
- : sql_type::VARCHAR;
- }
- else if (id == "NVARCHAR")
- {
- r.type = sql_type::VARCHAR;
- }
- else if (id == "VARYING" && prefix == "CHARACTER")
- {
- r.type = sql_type::VARCHAR;
- }
- else if (id == "BINARY")
- {
- r.type = sql_type::BINARY;
- }
- else if (id == "BYTE" && prefix == "CHAR")
- {
- r.type = sql_type::BINARY;
- }
- else if (id == "VARBINARY")
- {
- r.type = prefix == "LONG"
- ? sql_type::MEDIUMBLOB
- : sql_type::VARBINARY;
- }
- else if (id == "TINYBLOB")
- {
- r.type = sql_type::TINYBLOB;
- }
- else if (id == "TINYTEXT")
- {
- r.type = sql_type::TINYTEXT;
- }
- else if (id == "BLOB")
- {
- r.type = sql_type::BLOB;
- }
- else if (id == "TEXT")
- {
- r.type = sql_type::TEXT;
- }
- else if (id == "MEDIUMBLOB")
- {
- r.type = sql_type::MEDIUMBLOB;
- }
- else if (id == "MEDIUMTEXT")
- {
- r.type = sql_type::MEDIUMTEXT;
- }
- else if (id == "LONGBLOB")
- {
- r.type = sql_type::LONGBLOB;
- }
- else if (id == "LONGTEXT")
- {
- r.type = sql_type::LONGTEXT;
- }
- else if (id == "ENUM")
- {
- r.type = sql_type::ENUM;
- }
- else if (id == "SET")
- {
- r.type = sql_type::SET;
- }
- else
- match = false;
-
- if (match)
- {
- s = parse_range;
- continue;
- }
- }
-
- // Some prefixes can also be type names if not followed
- // by the actual type name.
- //
- if (!prefix.empty ())
- {
- if (prefix == "CHAR" || prefix == "CHARACTER")
- {
- r.type = sql_type::CHAR;
- }
- else if (prefix == "LONG")
- {
- r.type = sql_type::MEDIUMTEXT;
- }
- }
-
- if (r.type == sql_type::invalid)
- {
- cerr << m.file () << ":" << m.line () << ":" <<
- m.column () << ":";
-
- if (tt == sql_token::t_identifier)
- cerr << " error: unknown MySQL type '" <<
- t.identifier () << "'" << endl;
- else
- cerr << " error: expected MySQL type name" << endl;
-
- throw generation_failed ();
- }
-
- // Fall through.
- //
- s = parse_range;
- }
- case parse_range:
- {
- if (t.punctuation () == sql_token::p_lparen)
- {
- t = l.next ();
-
- // ENUM and SET have a list of members instead of the range.
- //
- if (r.type == sql_type::ENUM || r.type == sql_type::SET)
- {
- // Skip tokens until we get the closing paren.
- //
- while (t.type () != sql_token::t_eos &&
- t.punctuation () != sql_token::p_rparen)
- t = l.next ();
- }
- else
- {
- if (t.type () != sql_token::t_int_lit)
- {
- cerr << m.file () << ":" << m.line () << ":" << m.column ()
- << ": error: integer range expected in MySQL type "
- << "declaration" << endl;
-
- throw generation_failed ();
- }
-
- unsigned int v;
- istringstream is (t.literal ());
-
- if (!(is >> v && is.eof ()))
- {
- cerr << m.file () << ":" << m.line () << ":" << m.column ()
- << ": error: invalid range value '" << t.literal ()
- << "'in MySQL type declaration" << endl;
-
- throw generation_failed ();
- }
-
- r.range = true;
- r.range_value = v;
-
- t = l.next ();
-
- if (t.punctuation () == sql_token::p_comma)
- {
- // We have the second range value. Skip it.
- //
- l.next ();
- t = l.next ();
- }
- }
-
- if (t.punctuation () != sql_token::p_rparen)
- {
- cerr << m.file () << ":" << m.line () << ":" << m.column ()
- << ": error: expected ')' in MySQL type declaration"
- << endl;
-
- throw generation_failed ();
- }
-
- s = parse_sign;
- continue;
- }
-
- // Fall through.
- //
- s = parse_sign;
- }
- case parse_sign:
- {
- if (tt == sql_token::t_identifier &&
- context::upcase (t.identifier ()) == "UNSIGNED")
- {
- r.unsign = true;
- }
-
- s = parse_done;
- break;
- }
- case parse_done:
- {
- assert (false);
- break;
- }
- }
- }
-
- if (s == parse_name && !prefix.empty ())
- {
- // Some prefixes can also be type names if not followed
- // by the actual type name.
- //
- if (prefix == "CHAR" || prefix == "CHARACTER")
- {
- r.type = sql_type::CHAR;
- }
- else if (prefix == "LONG")
- {
- r.type = sql_type::MEDIUMTEXT;
- }
- }
-
- if (r.type == sql_type::invalid)
- {
- cerr << m.file () << ":" << m.line () << ":" << m.column ()
- << ": error: incomplete MySQL type declaration" << endl;
-
- throw generation_failed ();
- }
-
- // If range is omitted for CHAR or BIT types, it defaults to 1.
- //
- if ((r.type == sql_type::CHAR || r.type == sql_type::BIT) && !r.range)
- {
- r.range = true;
- r.range_value = 1;
- }
-
- return r;
- }
- catch (sql_lexer::invalid_input const& e)
- {
- cerr << m.file () << ":" << m.line () << ":" << m.column ()
- << ": error: invalid MySQL type declaration: " << e.message << endl;
-
- throw generation_failed ();
- }
- }
-}
diff --git a/odb/mysql/context.hxx b/odb/mysql/context.hxx
deleted file mode 100644
index 05b6639..0000000
--- a/odb/mysql/context.hxx
+++ /dev/null
@@ -1,127 +0,0 @@
-// file : odb/mysql/context.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_CONTEXT_HXX
-#define ODB_MYSQL_CONTEXT_HXX
-
-#include <string>
-
-#include <odb/context.hxx>
-
-namespace mysql
-{
- struct sql_type
- {
- // Keep the order in each block of types.
- //
- enum core_type
- {
- // Integral types.
- //
- TINYINT,
- SMALLINT,
- MEDIUMINT,
- INT,
- BIGINT,
-
- // Float types.
- //
- FLOAT,
- DOUBLE,
- DECIMAL,
-
- // Data-time types.
- //
- DATE,
- TIME,
- DATETIME,
- TIMESTAMP,
- YEAR,
-
- // String and binary types.
- //
- CHAR,
- BINARY,
- VARCHAR,
- VARBINARY,
- TINYTEXT,
- TINYBLOB,
- TEXT,
- BLOB,
- MEDIUMTEXT,
- MEDIUMBLOB,
- LONGTEXT,
- LONGBLOB,
-
- // Other types.
- //
- BIT,
- ENUM,
- SET,
-
- // Invalid type.
- //
- invalid
- };
-
- sql_type () : type (invalid), unsign (false), range (false) {}
-
- core_type type;
- bool unsign;
- bool range;
- unsigned int range_value; // MySQL max value is 2^32 - 1 (LONGBLOG/TEXT).
- };
-
- class context: public ::context
- {
- // Predicates.
- //
- public:
-
- // Return true if an object or value type has members for which
- // the image can grow.
- //
- bool
- grow (semantics::class_&);
-
- // The same for a member's value type.
- //
- bool
- grow (semantics::data_member&);
-
- bool
- grow (semantics::data_member&, semantics::type&, string const& key_prefix);
-
- //
- //
- public:
- sql_type const&
- db_type (semantics::data_member&, string const& key_prefix = string ());
-
- private:
- typedef ::context base_context;
-
- struct data: base_context::data
- {
- virtual string
- column_type_impl (semantics::type&,
- string const& type,
- semantics::context&,
- column_type_flags) const;
- };
-
- private:
- data* data_;
-
- public:
-
- public:
- context (std::ostream&, semantics::unit&, options_type const&);
- context (context&);
- context (context&, std::ostream&);
- };
-}
-
-#endif // ODB_MYSQL_CONTEXT_HXX
diff --git a/odb/mysql/header.hxx b/odb/mysql/header.hxx
deleted file mode 100644
index ec7cbf1..0000000
--- a/odb/mysql/header.hxx
+++ /dev/null
@@ -1,17 +0,0 @@
-// file : odb/mysql/header.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_HEADER_HXX
-#define ODB_MYSQL_HEADER_HXX
-
-#include <odb/mysql/context.hxx>
-
-namespace mysql
-{
- void
- generate_header (context&);
-}
-
-#endif // ODB_MYSQL_HEADER_HXX
diff --git a/odb/mysql/inline.hxx b/odb/mysql/inline.hxx
deleted file mode 100644
index e902ef3..0000000
--- a/odb/mysql/inline.hxx
+++ /dev/null
@@ -1,17 +0,0 @@
-// file : odb/mysql/inline.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_INLINE_HXX
-#define ODB_MYSQL_INLINE_HXX
-
-#include <odb/mysql/context.hxx>
-
-namespace mysql
-{
- void
- generate_inline (context&);
-}
-
-#endif // ODB_MYSQL_INLINE_HXX
diff --git a/odb/mysql/schema.cxx b/odb/mysql/schema.cxx
deleted file mode 100644
index b40a019..0000000
--- a/odb/mysql/schema.cxx
+++ /dev/null
@@ -1,11 +0,0 @@
-// file : odb/mysql/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/schema.hxx>
-
-namespace mysql
-{
-
-}
diff --git a/odb/mysql/schema.hxx b/odb/mysql/schema.hxx
deleted file mode 100644
index 1defad7..0000000
--- a/odb/mysql/schema.hxx
+++ /dev/null
@@ -1,325 +0,0 @@
-// file : odb/mysql/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_SCHEMA_HXX
-#define ODB_MYSQL_SCHEMA_HXX
-
-#include <set>
-
-#include <odb/emitter.hxx>
-#include <odb/mysql/common.hxx>
-
-namespace mysql
-{
- 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.hxx b/odb/mysql/source.hxx
deleted file mode 100644
index 43a051b..0000000
--- a/odb/mysql/source.hxx
+++ /dev/null
@@ -1,17 +0,0 @@
-// file : odb/mysql/source.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_SOURCE_HXX
-#define ODB_MYSQL_SOURCE_HXX
-
-#include <odb/mysql/context.hxx>
-
-namespace mysql
-{
- void
- generate_source (context&);
-}
-
-#endif // ODB_MYSQL_SOURCE_HXX
diff --git a/odb/mysql/sql-schema.cxx b/odb/mysql/sql-schema.cxx
deleted file mode 100644
index 7c71b24..0000000
--- a/odb/mysql/sql-schema.cxx
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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
deleted file mode 100644
index fdbdf28..0000000
--- a/odb/mysql/sql-schema.hxx
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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/relational/common.cxx b/odb/relational/common.cxx
new file mode 100644
index 0000000..0bcc676
--- /dev/null
+++ b/odb/relational/common.cxx
@@ -0,0 +1,178 @@
+// file : odb/relational/common.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 <cstddef> // std::size_
+#include <cstdlib> // abort
+#include <sstream>
+#include <cxxabi.h> // abi::__cxa_demangle
+
+#include <odb/relational/common.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ // query_columns
+ //
+
+ query_columns::
+ query_columns ()
+ : ptr_ (true), decl_ (true)
+ {
+ }
+
+ query_columns::
+ query_columns (semantics::class_& cl) //@@ context::object
+ : ptr_ (true), decl_ (false)
+ {
+ scope_ = "access::object_traits< " + cl.fq_name () + " >::query_type";
+ table_ = table_name (cl);
+ }
+
+ void query_columns::
+ composite (semantics::data_member& m, semantics::class_& c)
+ {
+ string name (public_name (m));
+
+ if (decl_)
+ {
+ os << "// " << name << endl
+ << "//" << endl
+ << "struct " << name
+ << "{";
+
+ object_columns_base::composite (m, c);
+
+ os << "};";
+ }
+ else
+ {
+ string old_scope (scope_);
+ scope_ += "::" + name;
+
+ object_columns_base::composite (m, c);
+
+ scope_ = old_scope;
+ }
+ }
+
+ bool query_columns::
+ column (semantics::data_member& m, string const& col_name, bool)
+ {
+ string name (public_name (m));
+
+ if (semantics::class_* c = object_pointer (m.type ()))
+ {
+ // We cannot just typedef the query_type from the referenced
+ // object for two reasons: (1) it may not be defined yet and
+ // (2) it will contain columns for its own pointers which
+ // won't work (for now we only support one level of indirection
+ // in queries). So we will have to duplicate the columns (sans
+ // the pointers).
+ //
+ if (ptr_)
+ {
+ ptr_ = false;
+
+ if (decl_)
+ {
+ os << "// " << name << endl
+ << "//" << endl
+ << "struct " << name
+ << "{";
+
+ traverse (*c);
+
+ os << "};";
+ }
+ else
+ {
+ string old_scope (scope_), old_table (table_);
+ scope_ += "::" + name;
+ table_ = table_name (*c);
+ traverse (*c);
+ table_ = old_table;
+ scope_ = old_scope;
+ }
+
+ ptr_ = true;
+ }
+ }
+ else
+ {
+ string im_type (image_type (m));
+ string db_type (database_type (m));
+
+ string type (
+ "mysql::value_traits< "
+ + m.type ().fq_name (m.belongs ().hint ()) + ", "
+ + im_type + ", "
+ + db_type
+ + " >::query_type");
+
+ if (decl_)
+ {
+ os << "// " << name << endl
+ << "//" << endl
+ << "static const mysql::query_column<" << endl
+ << " " << type << "," << endl
+ << " " << db_type << ">" << endl
+ << name << ";"
+ << endl;
+ }
+ else
+ {
+ string column ("\"`" + table_ + "`.`" + col_name + "`\"");
+
+ os << "const mysql::query_column<" << endl
+ << " " << type << "," << endl
+ << " " << db_type << ">" << endl
+ << scope_ << "::" << name << " (" << endl
+ << column << ");"
+ << endl;
+ }
+ }
+
+ return true;
+ }
+
+ //
+ // Dynamic traversal support.
+ //
+
+ struct demangled_name
+ {
+ demangled_name (): s (0), n (0) {}
+ ~demangled_name () {free (s);}
+ char* s;
+ size_t n;
+ };
+
+ static demangled_name name_;
+
+ database entry_base::
+ db (type_info const& ti)
+ {
+ char*& s (name_.s);
+
+ int r;
+ s = abi::__cxa_demangle (ti.name (), s, &name_.n, &r);
+
+ if (r != 0)
+ abort (); // We are in static initialization, so this is fatal.
+
+ //
+ //
+ string str (s + 12); // 12 for "relational::"
+ istringstream is (string (str, str.find (':')));
+
+ database d;
+ if (!is >> d)
+ abort ();
+
+ return d;
+ }
+}
diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx
new file mode 100644
index 0000000..513d9d6
--- /dev/null
+++ b/odb/relational/common.hxx
@@ -0,0 +1,303 @@
+// file : odb/relational/common.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_RELATIONAL_COMMON_HXX
+#define ODB_RELATIONAL_COMMON_HXX
+
+#include <map>
+#include <cstddef> // std::size_t
+#include <cassert>
+#include <typeinfo>
+
+#include <odb/common.hxx>
+#include <odb/relational/context.hxx>
+
+namespace relational
+{
+ struct member_base: traversal::data_member, virtual context
+ {
+ typedef member_base base;
+
+ member_base (semantics::type* type,
+ string const& fq_type,
+ string const& key_prefix)
+ : type_override_ (type),
+ fq_type_override_ (fq_type),
+ key_prefix_ (key_prefix)
+ {
+ }
+
+ member_base (string const& var,
+ semantics::type* type,
+ string const& fq_type,
+ string const& key_prefix)
+ : var_override_ (var),
+ type_override_ (type),
+ fq_type_override_ (fq_type),
+ key_prefix_ (key_prefix)
+ {
+ }
+
+ protected:
+ // For virtual inheritance only. Should not be actually called.
+ //
+ member_base (); // {assert (false);}
+
+ protected:
+ string var_override_;
+ semantics::type* type_override_;
+ string fq_type_override_;
+ string key_prefix_;
+ };
+
+ //
+ //
+ struct query_columns: object_columns_base, virtual context
+ {
+ typedef query_columns base;
+
+ query_columns ();
+ query_columns (semantics::class_&);
+
+ virtual string
+ image_type (semantics::data_member&)
+ {
+ assert (false);
+ }
+
+ virtual string
+ database_type (semantics::data_member&)
+ {
+ assert (false);
+ }
+
+ virtual void
+ composite (semantics::data_member&, semantics::class_&);
+
+ virtual bool
+ column (semantics::data_member&, string const&, bool);
+
+
+ protected:
+ bool ptr_;
+ bool decl_;
+
+ string scope_;
+ string table_;
+ };
+
+ //
+ // Dynamic traversal support.
+ //
+
+ template <typename B>
+ struct factory
+ {
+ static B*
+ create (B const& prototype)
+ {
+ database db (context::current ().options.database ());
+
+ if (map_ != 0)
+ {
+ typename map::const_iterator i (map_->find (db));
+
+ if (i != map_->end ())
+ return i->second (prototype);
+ }
+
+ return new B (prototype);
+ }
+
+ private:
+ template <typename>
+ friend struct entry;
+
+ static void
+ init ()
+ {
+ if (factory<B>::count_++ == 0)
+ factory<B>::map_ = new typename factory<B>::map;
+ }
+
+ static void
+ term ()
+ {
+ if (--factory<B>::count_ == 0)
+ delete factory<B>::map_;
+ }
+
+ typedef B* (*create_func) (B const&);
+ typedef std::map<database, create_func> map;
+ static map* map_;
+ static std::size_t count_;
+ };
+
+ template <typename B>
+ typename factory<B>::map* factory<B>::map_;
+
+ template <typename B>
+ std::size_t factory<B>::count_;
+
+ struct entry_base
+ {
+ static database
+ db (std::type_info const&);
+ };
+
+ template <typename D>
+ struct entry: entry_base
+ {
+ typedef typename D::base base;
+
+ entry ()
+ {
+ factory<base>::init ();
+ (*factory<base>::map_)[db (typeid (D))] = &create;
+ }
+
+ ~entry ()
+ {
+ factory<base>::term ();
+ }
+
+ static base*
+ create (base const& prototype)
+ {
+ return new D (prototype);
+ }
+ };
+
+ template <typename B>
+ struct instance
+ {
+ typedef relational::factory<B> factory;
+
+ ~instance ()
+ {
+ delete x_;
+ }
+
+ instance ()
+ {
+ B prototype;
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1>
+ instance (A1& a1)
+ {
+ B prototype (a1);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1>
+ instance (A1 const& a1)
+ {
+ B prototype (a1);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1, typename A2>
+ instance (A1& a1, A2& a2)
+ {
+ B prototype (a1, a2);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1, typename A2>
+ instance (A1 const& a1, A2 const& a2)
+ {
+ B prototype (a1, a2);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3>
+ instance (A1& a1, A2& a2, A3& a3)
+ {
+ B prototype (a1, a2, a3);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3>
+ instance (A1 const& a1, A2 const& a2, A3 const& a3)
+ {
+ B prototype (a1, a2, a3);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4>
+ instance (A1& a1, A2& a2, A3& a3, A4& a4)
+ {
+ B prototype (a1, a2, a3, a4);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4>
+ instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4)
+ {
+ B prototype (a1, a2, a3, a4);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5>
+ instance (A1& a1, A2& a2, A3& a3, A4& a4, A5& a5)
+ {
+ B prototype (a1, a2, a3, a4, a5);
+ x_ = factory::create (prototype);
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5>
+ instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4,
+ A5 const& a5)
+ {
+ B prototype (a1, a2, a3, a4, a5);
+ x_ = factory::create (prototype);
+ }
+
+ instance (instance const& i)
+ {
+ // This is tricky: use the other instance as a prototype.
+ //
+ x_ = factory::create (*i.x_);
+ }
+
+ B*
+ operator-> () const
+ {
+ return x_;
+ }
+
+ B&
+ operator* () const
+ {
+ return *x_;
+ }
+
+ private:
+ instance& operator= (instance const&);
+
+ private:
+ B* x_;
+ };
+
+ template <typename T>
+ inline traversal::edge_base&
+ operator>> (instance<T>& n, traversal::edge_base& e)
+ {
+ n->edge_traverser (e);
+ return e;
+ }
+
+ template <typename T>
+ inline traversal::node_base&
+ operator>> (traversal::edge_base& e, instance<T>& n)
+ {
+ e.node_traverser (*n);
+ return *n;
+ }
+}
+
+#endif // ODB_RELATIONAL_COMMON_HXX
diff --git a/odb/relational/context.cxx b/odb/relational/context.cxx
new file mode 100644
index 0000000..e7a4f21
--- /dev/null
+++ b/odb/relational/context.cxx
@@ -0,0 +1,54 @@
+// file : odb/relational/context.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/relational/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ context::
+ context ()
+ : data_ (current ().data_)
+ {
+ }
+
+ context::
+ context (data* d)
+ : data_ (d)
+ {
+ }
+
+ bool context::
+ grow_impl (semantics::class_&)
+ {
+ return false;
+ }
+
+ bool context::
+ grow_impl (semantics::data_member&)
+ {
+ return false;
+ }
+
+ bool context::
+ grow_impl (semantics::data_member&,
+ semantics::type&,
+ string const&)
+ {
+ return false;
+ }
+
+ string context::
+ quote_id_impl (string const& id) const
+ {
+ string r;
+ r.reserve (id.size ());
+ r += '"';
+ r += id;
+ r += '"';
+ return r;
+ }
+}
diff --git a/odb/relational/context.hxx b/odb/relational/context.hxx
new file mode 100644
index 0000000..fbd6059
--- /dev/null
+++ b/odb/relational/context.hxx
@@ -0,0 +1,81 @@
+// file : odb/relational/context.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_RELATIONAL_CONTEXT_HXX
+#define ODB_RELATIONAL_CONTEXT_HXX
+
+#include <odb/context.hxx>
+
+namespace relational
+{
+ class context: public virtual ::context
+ {
+ public:
+ // Return true if an object or value type has members for which
+ // the image can grow.
+ //
+ bool
+ grow (semantics::class_&);
+
+ // The same for a member's value type.
+ //
+ bool
+ grow (semantics::data_member&);
+
+ bool
+ grow (semantics::data_member&, semantics::type&, string const& key_prefix);
+
+ public:
+ // Quote SQL identifier.
+ //
+ string
+ quote_id (string const&) const;
+
+ public:
+ context ();
+
+ static context&
+ current ()
+ {
+ return dynamic_cast<context&> (root_context::current ());
+ }
+
+ protected:
+ // The default implementation returns false.
+ //
+ virtual bool
+ grow_impl (semantics::class_&);
+
+ virtual bool
+ grow_impl (semantics::data_member&);
+
+ virtual bool
+ grow_impl (semantics::data_member&,
+ semantics::type&,
+ string const&);
+
+ // The default implementation uses the ISO quoting ("").
+ //
+ virtual string
+ quote_id_impl (string const&) const;
+
+ protected:
+ struct data;
+ typedef context base_context;
+
+ context (data*);
+
+ protected:
+ struct data: root_context::data
+ {
+ data (std::ostream& os): root_context::data (os) {}
+ };
+ data* data_;
+ };
+}
+
+#include <odb/relational/context.ixx>
+
+#endif // ODB_RELATIONAL_CONTEXT_HXX
diff --git a/odb/relational/context.ixx b/odb/relational/context.ixx
new file mode 100644
index 0000000..da24d39
--- /dev/null
+++ b/odb/relational/context.ixx
@@ -0,0 +1,31 @@
+// file : odb/relational/context.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+namespace relational
+{
+ inline bool context::
+ grow (semantics::class_& c)
+ {
+ return current ().grow_impl (c);
+ }
+
+ inline bool context::
+ grow (semantics::data_member& m)
+ {
+ return current ().grow_impl (m);
+ }
+
+ inline bool context::
+ grow (semantics::data_member& m, semantics::type& t, string const& kp)
+ {
+ return current ().grow_impl (m, t, kp);
+ }
+
+ inline context::string context::
+ quote_id (string const& id) const
+ {
+ return current ().quote_id_impl (id);
+ }
+}
diff --git a/odb/relational/generate.hxx b/odb/relational/generate.hxx
new file mode 100644
index 0000000..c7c7837
--- /dev/null
+++ b/odb/relational/generate.hxx
@@ -0,0 +1,36 @@
+// file : odb/relational/generate.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_RELATIONAL_GENERATE_HXX
+#define ODB_RELATIONAL_GENERATE_HXX
+
+namespace relational
+{
+ namespace header
+ {
+ void
+ generate ();
+ }
+
+ namespace inline_
+ {
+ void
+ generate ();
+ }
+
+ namespace source
+ {
+ void
+ generate ();
+ }
+
+ namespace schema
+ {
+ void
+ generate ();
+ }
+}
+
+#endif // ODB_RELATIONAL_GENERATE_HXX
diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx
new file mode 100644
index 0000000..f8529f4
--- /dev/null
+++ b/odb/relational/header.cxx
@@ -0,0 +1,54 @@
+// file : odb/relational/header.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/relational/header.hxx>
+#include <odb/relational/generate.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace header
+ {
+ void
+ generate ()
+ {
+ context ctx;
+ ostream& os (ctx.os);
+ options const& ops (ctx.options);
+
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ instance<class_> c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ os << "#include <odb/mysql/version.hxx>" << endl
+ << "#include <odb/mysql/forward.hxx>" << endl
+ << "#include <odb/mysql/mysql-types.hxx>" << endl;
+
+ if (ops.generate_query ())
+ os << "#include <odb/mysql/query.hxx>" << endl;
+
+ os << endl
+ << "#include <odb/details/buffer.hxx>" << endl
+ << endl;
+
+ os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ os << "}";
+ }
+ }
+}
diff --git a/odb/mysql/header.cxx b/odb/relational/header.hxx
index 59793b0..12a587d 100644
--- a/odb/mysql/header.cxx
+++ b/odb/relational/header.hxx
@@ -1,170 +1,43 @@
-// file : odb/mysql/header.cxx
+// file : odb/relational/header.hxx
// 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/gcc.hxx>
+#ifndef ODB_RELATIONAL_HEADER_HXX
+#define ODB_RELATIONAL_HEADER_HXX
-#include <odb/mysql/common.hxx>
-#include <odb/mysql/header.hxx>
+#include <odb/gcc.hxx> //@@ ??
-namespace mysql
+#include <odb/relational/context.hxx>
+#include <odb/relational/common.hxx>
+
+namespace relational
{
- namespace
+ namespace header
{
- struct image_member: member_base
+ struct image_member: virtual member_base
{
- image_member (context& c, string const& var = string ())
- : member_base (c, var), member_image_type_ (c)
+ typedef image_member base;
+
+ image_member (string const& var = string ())
+ : member_base (var, 0, string (), string ())
{
}
- image_member (context& c,
- string const& var,
+ image_member (string const& var,
semantics::type& t,
string const& fq_type,
string const& key_prefix)
- : member_base (c, var, t, fq_type, key_prefix),
- member_image_type_ (c, t, fq_type, key_prefix)
- {
- }
-
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi.t))
- return false;
-
- image_type = member_image_type_.image_type (mi.m);
-
- if (var_override_.empty ())
- os << "// " << mi.m.name () << endl
- << "//" << endl;
-
- return true;
- }
-
- virtual void
- traverse_composite (member_info& mi)
- {
- os << image_type << " " << mi.var << "value;"
- << endl;
- }
-
- virtual void
- traverse_integer (member_info& mi)
- {
- os << image_type << " " << mi.var << "value;"
- << "my_bool " << mi.var << "null;"
- << endl;
- }
-
- virtual void
- traverse_float (member_info& mi)
- {
- os << image_type << " " << mi.var << "value;"
- << "my_bool " << mi.var << "null;"
- << endl;
- }
-
- virtual void
- traverse_decimal (member_info& mi)
- {
- // Exchanged as strings. Can have up to 65 digits not counting
- // '-' and '.'. If range is not specified, the default is 10.
- //
-
- /*
- @@ Disabled.
- os << "char " << mi.var << "value[" <<
- (t.range ? t.range_value : 10) + 3 << "];"
- */
-
- os << image_type << " " << mi.var << "value;"
- << "unsigned long " << mi.var << "size;"
- << "my_bool " << mi.var << "null;"
- << endl;
- }
-
- virtual void
- traverse_date_time (member_info& mi)
- {
- os << image_type << " " << mi.var << "value;"
- << "my_bool " << mi.var << "null;"
- << endl;
-
- }
-
- virtual void
- traverse_short_string (member_info& mi)
- {
- // If range is not specified, the default buffer size is 255.
- //
- /*
- @@ Disabled.
- os << "char " << mi.var << "value[" <<
- (t.range ? t.range_value : 255) + 1 << "];"
- */
-
- os << image_type << " " << mi.var << "value;"
- << "unsigned long " << mi.var << "size;"
- << "my_bool " << mi.var << "null;"
- << endl;
- }
-
- virtual void
- traverse_long_string (member_info& mi)
+ : member_base (var, &t, fq_type, key_prefix)
{
- os << image_type << " " << mi.var << "value;"
- << "unsigned long " << mi.var << "size;"
- << "my_bool " << mi.var << "null;"
- << endl;
}
-
- virtual void
- traverse_bit (member_info& mi)
- {
- // Valid range is 1 to 64.
- //
- unsigned int n (mi.st->range / 8 + (mi.st->range % 8 ? 1 : 0));
-
- os << "unsigned char " << mi.var << "value[" << n << "];"
- << "unsigned long " << mi.var << "size;"
- << "my_bool " << mi.var << "null;"
- << endl;
- }
-
- virtual void
- traverse_enum (member_info& mi)
- {
- // Represented as string.
- //
- os << image_type << " " << mi.var << "value;"
- << "unsigned long " << mi.var << "size;"
- << "my_bool " << mi.var << "null;"
- << endl;
- }
-
- virtual void
- traverse_set (member_info& mi)
- {
- // Represented as string.
- //
- os << image_type << " " << mi.var << "value;"
- << "unsigned long " << mi.var << "size;"
- << "my_bool " << mi.var << "null;"
- << endl;
- }
-
- private:
- string image_type;
-
- member_image_type member_image_type_;
};
- struct image_base: traversal::class_, context
+ struct image_base: traversal::class_, virtual context
{
- image_base (context& c): context (c), first_ (true) {}
+ typedef image_base base;
+
+ image_base (): first_ (true) {}
virtual void
traverse (type& c)
@@ -192,10 +65,17 @@ namespace mysql
bool first_;
};
- struct image_type: traversal::class_, context
+ struct image_type: traversal::class_, virtual context
{
- image_type (context& c)
- : context (c), member_ (c)
+ typedef image_type base;
+
+ image_type ()
+ {
+ *this >> names_member_ >> member_;
+ }
+
+ image_type (image_type const&)
+ : root_context (), context () //@@ -Wextra
{
*this >> names_member_ >> member_;
}
@@ -206,8 +86,8 @@ namespace mysql
os << "struct image_type";
{
- image_base b (*this);
- traversal::inherits i (b);
+ instance<image_base> b;
+ traversal::inherits i (*b);
inherits (c, i);
}
@@ -222,16 +102,18 @@ namespace mysql
}
private:
- image_member member_;
+ instance<image_member> member_;
traversal::names names_member_;
};
// Member-specific traits types for container members.
//
- struct container_traits: object_members_base, context
+ struct container_traits: object_members_base, virtual context
{
- container_traits (context& c, semantics::class_& obj)
- : object_members_base (c, true, false), context (c)
+ typedef container_traits base;
+
+ container_traits (semantics::class_& obj) //@@ context::object
+ : object_members_base (true, false)
{
scope_ = "object_traits< " + obj.fq_name () + " >";
}
@@ -429,8 +311,8 @@ namespace mysql
{
os << "// index" << endl
<< "//" << endl;
- image_member im (*this, "index_", *it, "index_type", "index");
- im.traverse (m);
+ instance<image_member> im ("index_", *it, "index_type", "index");
+ im->traverse (m);
}
break;
}
@@ -439,8 +321,8 @@ namespace mysql
{
os << "// key" << endl
<< "//" << endl;
- image_member im (*this, "key_", *kt, "key_type", "key");
- im.traverse (m);
+ instance<image_member> im ("key_", *kt, "key_type", "key");
+ im->traverse (m);
break;
}
case ck_set:
@@ -448,8 +330,8 @@ namespace mysql
{
os << "// value" << endl
<< "//" << endl;
- image_member im (*this, "value_", vt, "value_type", "value");
- im.traverse (m);
+ instance<image_member> im ("value_", vt, "value_type", "value");
+ im->traverse (m);
break;
}
}
@@ -470,8 +352,8 @@ namespace mysql
{
os << "// index" << endl
<< "//" << endl;
- image_member im (*this, "index_", *it, "index_type", "index");
- im.traverse (m);
+ instance<image_member> im ("index_", *it, "index_type", "index");
+ im->traverse (m);
}
break;
}
@@ -480,8 +362,8 @@ namespace mysql
{
os << "// key" << endl
<< "//" << endl;
- image_member im (*this, "key_", *kt, "key_type", "key");
- im.traverse (m);
+ instance<image_member> im ("key_", *kt, "key_type", "key");
+ im->traverse (m);
break;
}
case ck_set:
@@ -493,8 +375,8 @@ namespace mysql
os << "// value" << endl
<< "//" << endl;
- image_member im (*this, "value_", vt, "value_type", "value");
- im.traverse (m);
+ instance<image_member> im ("value_", vt, "value_type", "value");
+ im->traverse (m);
os << "std::size_t version;"
<< "};";
@@ -518,7 +400,7 @@ namespace mysql
<< "bind (MYSQL_BIND*, id_image_type*, data_image_type&);"
<< endl;
- // grow()
+ // grow ()
//
os << "static void" << endl
<< "grow (data_image_type&, my_bool*);"
@@ -690,10 +572,16 @@ namespace mysql
//
//
- struct class_: traversal::class_, context
+ struct class_: traversal::class_, virtual context
{
- class_ (context& c)
- : context (c), image_type_ (c), id_image_member_ (c, "id_")
+ typedef class_ base;
+
+ class_ (): id_image_member_ ("id_") {}
+
+ class_ (class_ const&)
+ : root_context (), //@@ -Wextra
+ context (),
+ id_image_member_ ("id_")
{
}
@@ -739,14 +627,14 @@ namespace mysql
// image_type
//
- image_type_.traverse (c);
+ image_type_->traverse (c);
// id_image_type
//
os << "struct id_image_type"
<< "{";
- id_image_member_.traverse (id);
+ id_image_member_->traverse (id);
os << "std::size_t version;"
<< "};";
@@ -766,8 +654,8 @@ namespace mysql
<< "{";
{
- query_columns t (*this);
- t.traverse (c);
+ instance<query_columns> t;
+ t->traverse (c);
}
os << "query_type ();"
@@ -803,8 +691,8 @@ namespace mysql
// Traits types.
//
{
- container_traits t (*this, c);
- t.traverse (c);
+ instance<container_traits> t (c);
+ t->traverse (c);
}
// Statement cache (forward declaration).
@@ -959,7 +847,7 @@ namespace mysql
// image_type
//
- image_type_.traverse (c);
+ image_type_->traverse (c);
// grow ()
//
@@ -989,43 +877,10 @@ namespace mysql
}
private:
- image_type image_type_;
- image_member id_image_member_;
+ instance<image_type> image_type_;
+ instance<image_member> id_image_member_;
};
}
-
- 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/mysql/version.hxx>" << endl
- << "#include <odb/mysql/forward.hxx>" << endl
- << "#include <odb/mysql/mysql-types.hxx>" << endl;
-
- if (ctx.options.generate_query ())
- ctx.os << "#include <odb/mysql/query.hxx>" << endl;
-
- ctx.os << endl
- << "#include <odb/details/buffer.hxx>" << endl
- << endl;
-
- ctx.os << "namespace odb"
- << "{";
-
- unit.dispatch (ctx.unit);
-
- ctx.os << "}";
- }
}
+
+#endif // ODB_RELATIONAL_HEADER_HXX
diff --git a/odb/relational/inline.cxx b/odb/relational/inline.cxx
new file mode 100644
index 0000000..e5371ab
--- /dev/null
+++ b/odb/relational/inline.cxx
@@ -0,0 +1,42 @@
+// file : odb/relational/inline.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/relational/inline.hxx>
+#include <odb/relational/generate.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace inline_
+ {
+ void
+ generate ()
+ {
+ context ctx;
+ ostream& os (ctx.os);
+
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ os << "}";
+ }
+ }
+}
diff --git a/odb/mysql/inline.cxx b/odb/relational/inline.hxx
index 1ab16ca..ef0e32e 100644
--- a/odb/mysql/inline.cxx
+++ b/odb/relational/inline.hxx
@@ -1,21 +1,21 @@
-// file : odb/mysql/inline.cxx
+// file : odb/relational/inline.hxx
// 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/inline.hxx>
+#ifndef ODB_RELATIONAL_INLINE_HXX
+#define ODB_RELATIONAL_INLINE_HXX
-namespace mysql
+#include <odb/relational/context.hxx>
+#include <odb/relational/common.hxx>
+
+namespace relational
{
- namespace
+ namespace inline_
{
- struct class_: traversal::class_, context
+ struct class_: traversal::class_, virtual context
{
- class_ (context& c)
- : context (c)
- {
- }
+ typedef class_ base;
virtual void
traverse (type& c)
@@ -91,39 +91,17 @@ namespace mysql
traverse_value (type&)
{
/*
- string const& type (c.fq_name ());
- string traits ("access::composite_value_traits< " + type + " >");
+ string const& type (c.fq_name ());
+ string traits ("access::composite_value_traits< " + type + " >");
- os << "// " << c.name () << endl
- << "//" << endl
- << endl;
+ os << "// " << c.name () << endl
+ << "//" << endl
+ << 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 << "}";
- }
}
+
+#endif // ODB_RELATIONAL_INLINE_HXX
diff --git a/odb/relational/mysql/common.cxx b/odb/relational/mysql/common.cxx
new file mode 100644
index 0000000..d45229a
--- /dev/null
+++ b/odb/relational/mysql/common.cxx
@@ -0,0 +1,448 @@
+// file : odb/relational/mysql/common.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 <cassert>
+
+#include <odb/relational/mysql/common.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace mysql
+ {
+ //
+ // member_base
+ //
+
+ void member_base::
+ traverse (semantics::data_member& m)
+ {
+ if (m.count ("transient"))
+ return;
+
+ string var;
+
+ if (!var_override_.empty ())
+ var = var_override_;
+ else
+ {
+ string const& name (m.name ());
+ var = name + (name[name.size () - 1] == '_' ? "" : "_");
+ }
+
+ semantics::type& t (type_override_ != 0 ? *type_override_ : m.type ());
+
+ if (comp_value (t))
+ {
+ member_info mi (m, t, var, fq_type_override_);
+ if (pre (mi))
+ {
+ traverse_composite (mi);
+ post (mi);
+ }
+ }
+ else if (container (t))
+ {
+ member_info mi (m, t, var, fq_type_override_);
+ if (pre (mi))
+ {
+ traverse_container (mi);
+ post (mi);
+ }
+ }
+ else
+ {
+ sql_type const& st (db_type (m, key_prefix_));
+
+ if (semantics::class_* c = object_pointer (t))
+ {
+ member_info mi (m, id_member (*c).type (), var, fq_type_override_);
+ mi.st = &st;
+ if (pre (mi))
+ {
+ traverse_object_pointer (mi);
+ post (mi);
+ }
+ }
+ else
+ {
+ member_info mi (m, t, var, fq_type_override_);
+ mi.st = &st;
+ if (pre (mi))
+ {
+ traverse_simple (mi);
+ post (mi);
+ }
+ }
+ }
+ }
+
+ void member_base::
+ traverse_simple (member_info& mi)
+ {
+ switch (mi.st->type)
+ {
+ // Integral types.
+ //
+ case sql_type::TINYINT:
+ case sql_type::SMALLINT:
+ case sql_type::MEDIUMINT:
+ case sql_type::INT:
+ case sql_type::BIGINT:
+ {
+ traverse_integer (mi);
+ break;
+ }
+
+ // Float types.
+ //
+ case sql_type::FLOAT:
+ case sql_type::DOUBLE:
+ {
+ traverse_float (mi);
+ break;
+ }
+ case sql_type::DECIMAL:
+ {
+ traverse_decimal (mi);
+ break;
+ }
+
+ // Data-time types.
+ //
+ case sql_type::DATE:
+ case sql_type::TIME:
+ case sql_type::DATETIME:
+ case sql_type::TIMESTAMP:
+ case sql_type::YEAR:
+ {
+ traverse_date_time (mi);
+ break;
+ }
+
+ // String and binary types.
+ //
+ case sql_type::CHAR:
+ case sql_type::VARCHAR:
+ case sql_type::TINYTEXT:
+ case sql_type::TEXT:
+ case sql_type::MEDIUMTEXT:
+ case sql_type::LONGTEXT:
+ {
+ // For string types the limit is in characters rather
+ // than in bytes. The fixed-length pre-allocated buffer
+ // optimization can only be used for 1-byte encodings.
+ // To support this we will need the character encoding
+ // in sql_type.
+ //
+ traverse_long_string (mi);
+ break;
+ }
+ case sql_type::BINARY:
+ case sql_type::TINYBLOB:
+ {
+ // BINARY's range is always 255 or less from MySQL 5.0.3.
+ // TINYBLOB can only store up to 255 bytes.
+ //
+ traverse_short_string (mi);
+ break;
+ }
+ case sql_type::VARBINARY:
+ case sql_type::BLOB:
+ case sql_type::MEDIUMBLOB:
+ case sql_type::LONGBLOB:
+ {
+ if (mi.st->range && mi.st->range_value <= 255)
+ traverse_short_string (mi);
+ else
+ traverse_long_string (mi);
+
+ break;
+ }
+
+ // Other types.
+ //
+ case sql_type::BIT:
+ {
+ traverse_bit (mi);
+ break;
+ }
+ case sql_type::ENUM:
+ {
+ traverse_enum (mi);
+ break;
+ }
+ case sql_type::SET:
+ {
+ traverse_set (mi);
+ break;
+ }
+ case sql_type::invalid:
+ {
+ assert (false);
+ break;
+ }
+ }
+ }
+
+ //
+ // member_image_type
+ //
+
+ namespace
+ {
+ const char* integer_types[] =
+ {
+ "char",
+ "short",
+ "int",
+ "int",
+ "long long"
+ };
+
+ const char* float_types[] =
+ {
+ "float",
+ "double"
+ };
+ }
+
+ member_image_type::
+ member_image_type (semantics::type* type,
+ string const& fq_type,
+ string const& key_prefix)
+ : relational::member_base (type, fq_type, key_prefix)
+ {
+ }
+
+ string member_image_type::
+ image_type (semantics::data_member& m)
+ {
+ type_.clear ();
+ member_base::traverse (m);
+ return type_;
+ }
+
+ void member_image_type::
+ traverse_composite (member_info& mi)
+ {
+ type_ = "composite_value_traits< " + mi.fq_type () + " >::image_type";
+ }
+
+ void member_image_type::
+ traverse_integer (member_info& mi)
+ {
+ if (mi.st->unsign)
+ type_ = "unsigned ";
+ else if (mi.st->type == sql_type::TINYINT)
+ type_ = "signed ";
+
+ type_ += integer_types[mi.st->type - sql_type::TINYINT];
+ }
+
+ void member_image_type::
+ traverse_float (member_info& mi)
+ {
+ type_ = float_types[mi.st->type - sql_type::FLOAT];
+ }
+
+ void member_image_type::
+ traverse_decimal (member_info&)
+ {
+ type_ = "details::buffer";
+ }
+
+ void member_image_type::
+ traverse_date_time (member_info& mi)
+ {
+ if (mi.st->type == sql_type::YEAR)
+ type_ = "short";
+ else
+ type_ = "MYSQL_TIME";
+ }
+
+ void member_image_type::
+ traverse_string (member_info&)
+ {
+ type_ = "details::buffer";
+ }
+
+ void member_image_type::
+ traverse_bit (member_info&)
+ {
+ type_ = "unsigned char*";
+ }
+
+ void member_image_type::
+ traverse_enum (member_info&)
+ {
+ // Represented as string.
+ //
+ type_ = "details::buffer";
+ }
+
+ void member_image_type::
+ traverse_set (member_info&)
+ {
+ // Represented as string.
+ //
+ type_ = "details::buffer";
+ }
+
+ //
+ // member_database_type
+ //
+
+ namespace
+ {
+ const char* integer_database_id[] =
+ {
+ "id_tiny",
+ "id_utiny",
+ "id_short",
+ "id_ushort",
+ "id_long", // INT24
+ "id_ulong", // INT24 UNSIGNED
+ "id_long",
+ "id_ulong",
+ "id_longlong",
+ "id_ulonglong"
+ };
+
+ const char* float_database_id[] =
+ {
+ "id_float",
+ "id_double"
+ };
+
+ const char* date_time_database_id[] =
+ {
+ "id_date",
+ "id_time",
+ "id_datetime",
+ "id_timestamp",
+ "id_year"
+ };
+
+ const char* char_bin_database_id[] =
+ {
+ "id_string", // CHAR
+ "id_blob", // BINARY,
+ "id_string", // VARCHAR
+ "id_blob", // VARBINARY
+ "id_string", // TINYTEXT
+ "id_blob", // TINYBLOB
+ "id_string", // TEXT
+ "id_blob", // BLOB
+ "id_string", // MEDIUMTEXT
+ "id_blob", // MEDIUMBLOB
+ "id_string", // LONGTEXT
+ "id_blob" // LONGBLOB
+ };
+ }
+
+ member_database_type::
+ member_database_type (semantics::type* type,
+ string const& fq_type,
+ string const& key_prefix)
+ : relational::member_base (type, fq_type, key_prefix)
+ {
+ }
+
+ string member_database_type::
+ database_type (type& m)
+ {
+ type_.clear ();
+ member_base::traverse (m);
+ return type_;
+ }
+
+ void member_database_type::
+ traverse_composite (member_info&)
+ {
+ assert (false);
+ }
+
+ void member_database_type::
+ traverse_integer (member_info& mi)
+ {
+ size_t i (
+ (mi.st->type - sql_type::TINYINT) * 2 + (mi.st->unsign ? 1 : 0));
+ type_ = string ("mysql::") + integer_database_id[i];
+ }
+
+ void member_database_type::
+ traverse_float (member_info& mi)
+ {
+ type_ = string ("mysql::") +
+ float_database_id[mi.st->type - sql_type::FLOAT];
+ }
+
+ void member_database_type::
+ traverse_decimal (member_info&)
+ {
+ type_ = "mysql::id_decimal";
+ }
+
+ void member_database_type::
+ traverse_date_time (member_info& mi)
+ {
+ type_ = string ("mysql::") +
+ date_time_database_id[mi.st->type - sql_type::DATE];
+ }
+
+ void member_database_type::
+ traverse_string (member_info& mi)
+ {
+ type_ = string ("mysql::") +
+ char_bin_database_id[mi.st->type - sql_type::CHAR];
+ }
+
+ void member_database_type::
+ traverse_bit (member_info&)
+ {
+ type_ = "mysql::id_bit";
+ }
+
+ void member_database_type::
+ traverse_enum (member_info&)
+ {
+ type_ = "mysql::id_enum";
+ }
+
+ void member_database_type::
+ traverse_set (member_info&)
+ {
+ type_ = "mysql::id_set";
+ }
+
+ //
+ // query_columns
+ //
+
+ struct query_columns: relational::query_columns, context
+ {
+ query_columns (base const& x): base (x) {}
+
+ virtual string
+ image_type (semantics::data_member& m)
+ {
+ return member_image_type_.image_type (m);
+ }
+
+ virtual string
+ database_type (semantics::data_member& m)
+ {
+ return member_database_type_.database_type (m);
+ }
+
+ private:
+ member_image_type member_image_type_;
+ member_database_type member_database_type_;
+ };
+ entry<query_columns> query_columns_;
+ }
+}
diff --git a/odb/relational/mysql/common.hxx b/odb/relational/mysql/common.hxx
new file mode 100644
index 0000000..e58390f
--- /dev/null
+++ b/odb/relational/mysql/common.hxx
@@ -0,0 +1,226 @@
+// file : odb/relational/mysql/common.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_RELATIONAL_MYSQL_COMMON_HXX
+#define ODB_RELATIONAL_MYSQL_COMMON_HXX
+
+#include <odb/relational/common.hxx>
+#include <odb/relational/mysql/context.hxx>
+
+namespace relational
+{
+ namespace mysql
+ {
+ struct member_base: virtual relational::member_base, context
+ {
+ member_base (base const& x): base (x) {}
+
+ // This c-tor is for the direct use inside the mysql namespace.
+ // If you do use this c-tor, you should also explicitly call
+ // relational::member_base.
+ //
+ member_base () {}
+
+ virtual void
+ traverse (semantics::data_member& m);
+
+ struct member_info
+ {
+ semantics::data_member& m; // Member.
+ semantics::type& t; // Member C++ type (m.type () may != t).
+ sql_type const* st; // Member SQL type (only simple values).
+ string& var; // Member variable name with trailing '_'.
+
+ // C++ type fq-name.
+ //
+ string
+ fq_type () const
+ {
+ // Use the original type from 'm' instead of 't' since the hint
+ // may be invalid for a different type. Plus, if a type is
+ // overriden, then the fq_type must be as well.
+ //
+ return fq_type_.empty ()
+ ? m.type ().fq_name (m.belongs ().hint ())
+ : fq_type_;
+ }
+
+ string const& fq_type_;
+
+ member_info (semantics::data_member& m_,
+ semantics::type& t_,
+ string& var_,
+ string const& fq_type)
+ : m (m_), t (t_), st (0), var (var_), fq_type_ (fq_type)
+ {
+ }
+ };
+
+ // The false return value indicates that no further callbacks
+ // should be called for this member.
+ //
+ virtual bool
+ pre (member_info&)
+ {
+ return true;
+ }
+
+ virtual void
+ post (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_composite (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_container (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_object_pointer (member_info& mi)
+ {
+ traverse_simple (mi);
+ }
+
+ virtual void
+ traverse_simple (member_info&);
+
+ virtual void
+ traverse_integer (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_float (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_decimal (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_date_time (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_string (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_short_string (member_info& mi)
+ {
+ traverse_string (mi);
+ }
+
+ virtual void
+ traverse_long_string (member_info& mi)
+ {
+ traverse_string (mi);
+ }
+
+ virtual void
+ traverse_bit (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_enum (member_info&)
+ {
+ }
+
+ virtual void
+ traverse_set (member_info&)
+ {
+ }
+ };
+
+ struct member_image_type: member_base
+ {
+ member_image_type (semantics::type* type = 0,
+ string const& fq_type = string (),
+ string const& key_prefix = string ());
+ string
+ image_type (semantics::data_member&);
+
+ virtual void
+ traverse_composite (member_info&);
+
+ virtual void
+ traverse_integer (member_info&);
+
+ virtual void
+ traverse_float (member_info&);
+
+ virtual void
+ traverse_decimal (member_info&);
+
+ virtual void
+ traverse_date_time (member_info&);
+
+ virtual void
+ traverse_string (member_info&);
+
+ virtual void
+ traverse_bit (member_info&);
+
+ virtual void
+ traverse_enum (member_info&);
+
+ virtual void
+ traverse_set (member_info&);
+
+ private:
+ string type_;
+ };
+
+ struct member_database_type: member_base
+ {
+ member_database_type (semantics::type* type = 0,
+ string const& fq_type = string (),
+ string const& key_prefix = string ());
+ string
+ database_type (type&);
+
+ virtual void
+ traverse_composite (member_info&);
+
+ virtual void
+ traverse_integer (member_info&);
+
+ virtual void
+ traverse_float (member_info&);
+
+ virtual void
+ traverse_decimal (member_info&);
+
+ virtual void
+ traverse_date_time (member_info&);
+
+ virtual void
+ traverse_string (member_info&);
+
+ virtual void
+ traverse_bit (member_info&);
+
+ virtual void
+ traverse_enum (member_info&);
+
+ virtual void
+ traverse_set (member_info&);
+
+ private:
+ string type_;
+ };
+ }
+}
+#endif // ODB_RELATIONAL_MYSQL_COMMON_HXX
diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx
new file mode 100644
index 0000000..014aa7d
--- /dev/null
+++ b/odb/relational/mysql/context.cxx
@@ -0,0 +1,642 @@
+// file : odb/relational/mysql/context.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 <sstream>
+
+#include <odb/sql-token.hxx>
+#include <odb/sql-lexer.hxx>
+
+#include <odb/relational/mysql/context.hxx>
+#include <odb/relational/mysql/common.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace mysql
+ {
+ namespace
+ {
+ struct type_map_entry
+ {
+ const char* const cxx_type;
+ const char* const db_type;
+ const char* const db_id_type;
+ };
+
+ type_map_entry type_map[] =
+ {
+ {"bool", "TINYINT(1)", 0},
+
+ {"char", "TINYINT", 0},
+ {"signed char", "TINYINT", 0},
+ {"unsigned char", "TINYINT UNSIGNED", 0},
+
+ {"short int", "SMALLINT", 0},
+ {"short unsigned int", "SMALLINT UNSIGNED", 0},
+
+ {"int", "INT", 0},
+ {"unsigned int", "INT UNSIGNED", 0},
+
+ {"long int", "BIGINT", 0},
+ {"long unsigned int", "BIGINT UNSIGNED", 0},
+
+ {"long long int", "BIGINT", 0},
+ {"long long unsigned int", "BIGINT UNSIGNED", 0},
+
+ {"float", "FLOAT", 0},
+ {"double", "DOUBLE", 0},
+
+ {"::std::string", "TEXT", "VARCHAR (255)"}
+ };
+ }
+
+ context::
+ context (ostream& os, semantics::unit& u, options_type const& ops)
+ : root_context (os, u, ops, data_ptr (new (shared) data (os))),
+ base_context (static_cast<data*> (root_context::data_.get ())),
+ data_ (static_cast<data*> (base_context::data_))
+ {
+ // Populate the C++ type to DB type map.
+ //
+ for (size_t i (0); i < sizeof (type_map) / sizeof (type_map_entry); ++i)
+ {
+ type_map_entry const& e (type_map[i]);
+
+ type_map_type::value_type v (
+ e.cxx_type,
+ db_type_type (e.db_type, e.db_id_type ? e.db_id_type : e.db_type));
+
+ data_->type_map_.insert (v);
+ }
+ }
+
+ context::
+ context ()
+ : data_ (current ().data_)
+ {
+ }
+
+ string context::
+ quote_id_impl (string const& id) const
+ {
+ string r;
+ r.reserve (id.size ());
+ r += '`';
+ r += id;
+ r += '`';
+ return r;
+ }
+
+ namespace
+ {
+ struct has_grow: traversal::class_
+ {
+ has_grow (bool& r)
+ : r_ (r)
+ {
+ *this >> inherits_ >> *this;
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ // Ignore transient bases.
+ //
+ if (!(c.count ("object") || context::comp_value (c)))
+ return;
+
+ if (c.count ("mysql::grow"))
+ r_ = c.get<bool> ("mysql::grow");
+ else
+ {
+ // r_ should be false.
+ //
+ inherits (c);
+
+ if (!r_)
+ names (c);
+
+ c.set ("mysql::grow", r_);
+ }
+ }
+
+ private:
+ bool& r_;
+ traversal::inherits inherits_;
+ };
+
+ struct has_grow_member: member_base
+ {
+ has_grow_member (bool& r,
+ semantics::type* type = 0,
+ string const& key_prefix = string ())
+ : relational::member_base (type, string (), key_prefix),
+ r_ (r)
+ {
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ // By calling grow() instead of recursing, we reset any overrides.
+ //
+ r_ = r_ || context::grow (dynamic_cast<semantics::class_&> (mi.t));
+ }
+
+ virtual void
+ traverse_decimal (member_info&)
+ {
+ r_ = true;
+ }
+
+ virtual void
+ traverse_long_string (member_info&)
+ {
+ r_ = true;
+ }
+
+ virtual void
+ traverse_short_string (member_info&)
+ {
+ r_ = true; // @@ Short string optimization disabled.
+ }
+
+ virtual void
+ traverse_enum (member_info&)
+ {
+ r_ = true;
+ }
+
+ virtual void
+ traverse_set (member_info&)
+ {
+ r_ = true;
+ }
+
+ private:
+ bool& r_;
+ };
+ }
+
+ bool context::
+ grow_impl (semantics::class_& c)
+ {
+ if (c.count ("mysql::grow"))
+ return c.get<bool> ("mysql::grow");
+
+ bool r (false);
+ has_grow ct (r);
+ has_grow_member mt (r);
+ traversal::names names;
+ ct >> names >> mt;
+ ct.traverse (c);
+ return r;
+ }
+
+ bool context::
+ grow_impl (semantics::data_member& m)
+ {
+ bool r (false);
+ has_grow_member mt (r);
+ mt.traverse (m);
+ return r;
+ }
+
+ bool context::
+ grow_impl (semantics::data_member& m, semantics::type& t, string const& kp)
+ {
+ bool r (false);
+ has_grow_member mt (r, &t, kp);
+ mt.traverse (m);
+ return r;
+ }
+
+ //
+ // SQL type parsing.
+ //
+
+ string context::data::
+ column_type_impl (semantics::type& t,
+ string const& type,
+ semantics::context& ctx,
+ column_type_flags f) const
+ {
+ string r (::context::data::column_type_impl (t, type, ctx, f));
+
+ if (!r.empty () && ctx.count ("auto") && (f & ctf_object_id_ref) == 0)
+ r += " AUTO_INCREMENT";
+
+ return r;
+ }
+
+ static sql_type
+ parse_sql_type (semantics::data_member& m, std::string const& sql);
+
+ sql_type const& context::
+ db_type (semantics::data_member& m, string const& kp)
+ {
+ string key (kp.empty () ? string ("db-type") : kp + "-db-type");
+
+ if (!m.count (key))
+ m.set (key, parse_sql_type (m, column_type (m, kp)));
+
+ return m.get<sql_type> (key);
+ }
+
+ static sql_type
+ parse_sql_type (semantics::data_member& m, string const& sql)
+ {
+ try
+ {
+ sql_type r;
+ sql_lexer l (sql);
+
+ // While most type names use single identifier, there are
+ // a couple of exceptions to this rule:
+ //
+ // NATIONAL CHAR|VARCHAR
+ // CHAR BYTE (BINARY)
+ // CHARACTER VARYING (VARCHAR)
+ // LONG VARBINARY (MEDIUMBLOB)
+ // LONG VARCHAR (MEDIUMTEXT)
+ //
+ //
+ enum state
+ {
+ parse_prefix,
+ parse_name,
+ parse_range,
+ parse_sign,
+ parse_done
+ };
+
+ state s (parse_prefix);
+ string prefix;
+
+ for (sql_token t (l.next ());
+ s != parse_done && t.type () != sql_token::t_eos;
+ t = l.next ())
+ {
+ sql_token::token_type tt (t.type ());
+
+ switch (s)
+ {
+ case parse_prefix:
+ {
+ if (tt == sql_token::t_identifier)
+ {
+ string const& id (t.identifier ());
+
+ if (id == "NATIONAL" ||
+ id == "CHAR" ||
+ id == "CHARACTER" ||
+ id == "LONG")
+ {
+ prefix = id;
+ s = parse_name;
+ continue;
+ }
+ }
+
+ // Fall through.
+ //
+ s = parse_name;
+ }
+ case parse_name:
+ {
+ if (tt == sql_token::t_identifier)
+ {
+ bool match (true);
+ string const& id (t.identifier ());
+
+ // Numeric types.
+ //
+ if (id == "BIT")
+ {
+ r.type = sql_type::BIT;
+ }
+ else if (id == "TINYINT" || id == "INT1")
+ {
+ r.type = sql_type::TINYINT;
+ }
+ else if (id == "BOOL" || id == "BOOLEAN")
+ {
+ r.type = sql_type::TINYINT;
+ r.range = true;
+ r.range_value = 1;
+ }
+ else if (id == "SMALLINT" || id == "INT2")
+ {
+ r.type = sql_type::SMALLINT;
+ }
+ else if (id == "MEDIUMINT" ||
+ id == "INT3" ||
+ id == "MIDDLEINT")
+ {
+ r.type = sql_type::MEDIUMINT;
+ }
+ else if (id == "INT" || id == "INTEGER" || id == "INT4")
+ {
+ r.type = sql_type::INT;
+ }
+ else if (id == "BIGINT" || id == "INT8")
+ {
+ r.type = sql_type::BIGINT;
+ }
+ else if (id == "SERIAL")
+ {
+ r.type = sql_type::BIGINT;
+ r.unsign = true;
+ }
+ else if (id == "FLOAT" || id == "FLOAT4")
+ {
+ r.type = sql_type::FLOAT;
+ }
+ else if (id == "DOUBLE" || id == "FLOAT8")
+ {
+ r.type = sql_type::DOUBLE;
+ }
+ else if (id == "DECIMAL" ||
+ id == "DEC" ||
+ id == "NUMERIC" ||
+ id == "FIXED")
+ {
+ r.type = sql_type::DECIMAL;
+ }
+ //
+ // Date-time types.
+ //
+ else if (id == "DATE")
+ {
+ r.type = sql_type::DATE;
+ }
+ else if (id == "TIME")
+ {
+ r.type = sql_type::TIME;
+ }
+ else if (id == "DATETIME")
+ {
+ r.type = sql_type::DATETIME;
+ }
+ else if (id == "TIMESTAMP")
+ {
+ r.type = sql_type::TIMESTAMP;
+ }
+ else if (id == "YEAR")
+ {
+ r.type = sql_type::YEAR;
+ }
+ //
+ // String and binary types.
+ //
+ else if (id == "NCHAR")
+ {
+ r.type = sql_type::CHAR;
+ }
+ else if (id == "VARCHAR")
+ {
+ r.type = prefix == "LONG"
+ ? sql_type::MEDIUMTEXT
+ : sql_type::VARCHAR;
+ }
+ else if (id == "NVARCHAR")
+ {
+ r.type = sql_type::VARCHAR;
+ }
+ else if (id == "VARYING" && prefix == "CHARACTER")
+ {
+ r.type = sql_type::VARCHAR;
+ }
+ else if (id == "BINARY")
+ {
+ r.type = sql_type::BINARY;
+ }
+ else if (id == "BYTE" && prefix == "CHAR")
+ {
+ r.type = sql_type::BINARY;
+ }
+ else if (id == "VARBINARY")
+ {
+ r.type = prefix == "LONG"
+ ? sql_type::MEDIUMBLOB
+ : sql_type::VARBINARY;
+ }
+ else if (id == "TINYBLOB")
+ {
+ r.type = sql_type::TINYBLOB;
+ }
+ else if (id == "TINYTEXT")
+ {
+ r.type = sql_type::TINYTEXT;
+ }
+ else if (id == "BLOB")
+ {
+ r.type = sql_type::BLOB;
+ }
+ else if (id == "TEXT")
+ {
+ r.type = sql_type::TEXT;
+ }
+ else if (id == "MEDIUMBLOB")
+ {
+ r.type = sql_type::MEDIUMBLOB;
+ }
+ else if (id == "MEDIUMTEXT")
+ {
+ r.type = sql_type::MEDIUMTEXT;
+ }
+ else if (id == "LONGBLOB")
+ {
+ r.type = sql_type::LONGBLOB;
+ }
+ else if (id == "LONGTEXT")
+ {
+ r.type = sql_type::LONGTEXT;
+ }
+ else if (id == "ENUM")
+ {
+ r.type = sql_type::ENUM;
+ }
+ else if (id == "SET")
+ {
+ r.type = sql_type::SET;
+ }
+ else
+ match = false;
+
+ if (match)
+ {
+ s = parse_range;
+ continue;
+ }
+ }
+
+ // Some prefixes can also be type names if not followed
+ // by the actual type name.
+ //
+ if (!prefix.empty ())
+ {
+ if (prefix == "CHAR" || prefix == "CHARACTER")
+ {
+ r.type = sql_type::CHAR;
+ }
+ else if (prefix == "LONG")
+ {
+ r.type = sql_type::MEDIUMTEXT;
+ }
+ }
+
+ if (r.type == sql_type::invalid)
+ {
+ cerr << m.file () << ":" << m.line () << ":" <<
+ m.column () << ":";
+
+ if (tt == sql_token::t_identifier)
+ cerr << " error: unknown MySQL type '" <<
+ t.identifier () << "'" << endl;
+ else
+ cerr << " error: expected MySQL type name" << endl;
+
+ throw generation_failed ();
+ }
+
+ // Fall through.
+ //
+ s = parse_range;
+ }
+ case parse_range:
+ {
+ if (t.punctuation () == sql_token::p_lparen)
+ {
+ t = l.next ();
+
+ // ENUM and SET have a list of members instead of the range.
+ //
+ if (r.type == sql_type::ENUM || r.type == sql_type::SET)
+ {
+ // Skip tokens until we get the closing paren.
+ //
+ while (t.type () != sql_token::t_eos &&
+ t.punctuation () != sql_token::p_rparen)
+ t = l.next ();
+ }
+ else
+ {
+ if (t.type () != sql_token::t_int_lit)
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: integer range expected in MySQL type "
+ << "declaration" << endl;
+
+ throw generation_failed ();
+ }
+
+ unsigned int v;
+ istringstream is (t.literal ());
+
+ if (!(is >> v && is.eof ()))
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: invalid range value '" << t.literal ()
+ << "'in MySQL type declaration" << endl;
+
+ throw generation_failed ();
+ }
+
+ r.range = true;
+ r.range_value = v;
+
+ t = l.next ();
+
+ if (t.punctuation () == sql_token::p_comma)
+ {
+ // We have the second range value. Skip it.
+ //
+ l.next ();
+ t = l.next ();
+ }
+ }
+
+ if (t.punctuation () != sql_token::p_rparen)
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: expected ')' in MySQL type declaration"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ s = parse_sign;
+ continue;
+ }
+
+ // Fall through.
+ //
+ s = parse_sign;
+ }
+ case parse_sign:
+ {
+ if (tt == sql_token::t_identifier &&
+ t.identifier () == "UNSIGNED")
+ {
+ r.unsign = true;
+ }
+
+ s = parse_done;
+ break;
+ }
+ case parse_done:
+ {
+ assert (false);
+ break;
+ }
+ }
+ }
+
+ if (s == parse_name && !prefix.empty ())
+ {
+ // Some prefixes can also be type names if not followed
+ // by the actual type name.
+ //
+ if (prefix == "CHAR" || prefix == "CHARACTER")
+ {
+ r.type = sql_type::CHAR;
+ }
+ else if (prefix == "LONG")
+ {
+ r.type = sql_type::MEDIUMTEXT;
+ }
+ }
+
+ if (r.type == sql_type::invalid)
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: incomplete MySQL type declaration" << endl;
+
+ throw generation_failed ();
+ }
+
+ // If range is omitted for CHAR or BIT types, it defaults to 1.
+ //
+ if ((r.type == sql_type::CHAR || r.type == sql_type::BIT) && !r.range)
+ {
+ r.range = true;
+ r.range_value = 1;
+ }
+
+ return r;
+ }
+ catch (sql_lexer::invalid_input const& e)
+ {
+ cerr << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: invalid MySQL type declaration: " << e.message
+ << endl;
+
+ throw generation_failed ();
+ }
+ }
+ }
+}
diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx
new file mode 100644
index 0000000..b1de84c
--- /dev/null
+++ b/odb/relational/mysql/context.hxx
@@ -0,0 +1,127 @@
+// file : odb/relational/mysql/context.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_RELATIONAL_MYSQL_CONTEXT_HXX
+#define ODB_RELATIONAL_MYSQL_CONTEXT_HXX
+
+#include <odb/relational/context.hxx>
+
+namespace relational
+{
+ namespace mysql
+ {
+ struct sql_type
+ {
+ // Keep the order in each block of types.
+ //
+ enum core_type
+ {
+ // Integral types.
+ //
+ TINYINT,
+ SMALLINT,
+ MEDIUMINT,
+ INT,
+ BIGINT,
+
+ // Float types.
+ //
+ FLOAT,
+ DOUBLE,
+ DECIMAL,
+
+ // Data-time types.
+ //
+ DATE,
+ TIME,
+ DATETIME,
+ TIMESTAMP,
+ YEAR,
+
+ // String and binary types.
+ //
+ CHAR,
+ BINARY,
+ VARCHAR,
+ VARBINARY,
+ TINYTEXT,
+ TINYBLOB,
+ TEXT,
+ BLOB,
+ MEDIUMTEXT,
+ MEDIUMBLOB,
+ LONGTEXT,
+ LONGBLOB,
+
+ // Other types.
+ //
+ BIT,
+ ENUM,
+ SET,
+
+ // Invalid type.
+ //
+ invalid
+ };
+
+ sql_type () : type (invalid), unsign (false), range (false) {}
+
+ core_type type;
+ bool unsign;
+ bool range;
+ unsigned int range_value; // MySQL max value is 2^32 - 1 (LONGBLOG/TEXT).
+ };
+
+ class context: public virtual relational::context
+ {
+ public:
+ sql_type const&
+ db_type (semantics::data_member&, string const& key_prefix = string ());
+
+ protected:
+ virtual bool
+ grow_impl (semantics::class_&);
+
+ virtual bool
+ grow_impl (semantics::data_member&);
+
+ virtual bool
+ grow_impl (semantics::data_member&, semantics::type&, string const&);
+
+ protected:
+ virtual string
+ quote_id_impl (string const&) const;
+
+ private:
+ struct data: base_context::data
+ {
+ data (std::ostream& os): base_context::data (os) {}
+
+ virtual string
+ column_type_impl (semantics::type&,
+ string const& type,
+ semantics::context&,
+ column_type_flags) const;
+ };
+
+ private:
+ data* data_;
+
+ public:
+ static context&
+ current ()
+ {
+ return dynamic_cast<context&> (base_context::current ());
+ }
+
+ context (std::ostream&, semantics::unit&, options_type const&);
+
+ protected:
+ context ();
+ };
+ }
+}
+
+#endif // ODB_RELATIONAL_MYSQL_CONTEXT_HXX
diff --git a/odb/relational/mysql/header.cxx b/odb/relational/mysql/header.cxx
new file mode 100644
index 0000000..5210677
--- /dev/null
+++ b/odb/relational/mysql/header.cxx
@@ -0,0 +1,166 @@
+// file : odb/relational/mysql/header.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/relational/header.hxx>
+
+#include <odb/relational/mysql/common.hxx>
+#include <odb/relational/mysql/context.hxx>
+
+namespace relational
+{
+ namespace mysql
+ {
+ namespace header
+ {
+ namespace relational = relational::header;
+
+ struct image_member: relational::image_member, member_base
+ {
+ image_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x),
+ member_image_type_ (base::type_override_,
+ base::fq_type_override_,
+ base::key_prefix_)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return false;
+
+ image_type = member_image_type_.image_type (mi.m);
+
+ if (var_override_.empty ())
+ os << "// " << mi.m.name () << endl
+ << "//" << endl;
+
+ return true;
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << image_type << " " << mi.var << "value;"
+ << endl;
+ }
+
+ virtual void
+ traverse_integer (member_info& mi)
+ {
+ os << image_type << " " << mi.var << "value;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_float (member_info& mi)
+ {
+ os << image_type << " " << mi.var << "value;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_decimal (member_info& mi)
+ {
+ // Exchanged as strings. Can have up to 65 digits not counting
+ // '-' and '.'. If range is not specified, the default is 10.
+ //
+
+ /*
+ @@ Disabled.
+ os << "char " << mi.var << "value[" <<
+ (t.range ? t.range_value : 10) + 3 << "];"
+ */
+
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_date_time (member_info& mi)
+ {
+ os << image_type << " " << mi.var << "value;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+
+ }
+
+ virtual void
+ traverse_short_string (member_info& mi)
+ {
+ // If range is not specified, the default buffer size is 255.
+ //
+ /*
+ @@ Disabled.
+ os << "char " << mi.var << "value[" <<
+ (t.range ? t.range_value : 255) + 1 << "];"
+ */
+
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_long_string (member_info& mi)
+ {
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_bit (member_info& mi)
+ {
+ // Valid range is 1 to 64.
+ //
+ unsigned int n (mi.st->range / 8 + (mi.st->range % 8 ? 1 : 0));
+
+ os << "unsigned char " << mi.var << "value[" << n << "];"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_enum (member_info& mi)
+ {
+ // Represented as string.
+ //
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_set (member_info& mi)
+ {
+ // Represented as string.
+ //
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
+ << endl;
+ }
+
+ private:
+ string image_type;
+
+ member_image_type member_image_type_;
+ };
+ entry<image_member> image_member_;
+ }
+ }
+}
diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx
new file mode 100644
index 0000000..19569e4
--- /dev/null
+++ b/odb/relational/mysql/schema.cxx
@@ -0,0 +1,53 @@
+// file : odb/relational/mysql/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/relational/schema.hxx>
+
+#include <odb/relational/mysql/common.hxx>
+#include <odb/relational/mysql/context.hxx>
+
+namespace relational
+{
+ namespace mysql
+ {
+ namespace schema
+ {
+ namespace relational = relational::schema;
+
+ //
+ // Create.
+ //
+
+ struct create_common: virtual relational::create_common
+ {
+ virtual void
+ create_post ()
+ {
+ os << ")";
+
+ string const& engine (options.mysql_engine ());
+
+ if (engine != "default")
+ os << endl
+ << " ENGINE=" << engine;
+
+ os << endl;
+ }
+ };
+
+ struct member_create: relational::member_create, create_common
+ {
+ member_create (base const& x): base (x) {}
+ };
+ entry<member_create> member_create_;
+
+ struct class_create: relational::class_create, create_common
+ {
+ class_create (base const& x): base (x) {}
+ };
+ entry<class_create> class_create_;
+ }
+ }
+}
diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx
new file mode 100644
index 0000000..71f556a
--- /dev/null
+++ b/odb/relational/mysql/source.cxx
@@ -0,0 +1,899 @@
+// file : odb/relational/mysql/source.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/relational/source.hxx>
+
+#include <odb/relational/mysql/common.hxx>
+#include <odb/relational/mysql/context.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace mysql
+ {
+ namespace source
+ {
+ namespace relational = relational::source;
+
+ namespace
+ {
+ const char* integer_buffer_types[] =
+ {
+ "MYSQL_TYPE_TINY",
+ "MYSQL_TYPE_SHORT",
+ "MYSQL_TYPE_LONG", // *_bind_param() doesn't support INT24.
+ "MYSQL_TYPE_LONG",
+ "MYSQL_TYPE_LONGLONG"
+ };
+
+ const char* float_buffer_types[] =
+ {
+ "MYSQL_TYPE_FLOAT",
+ "MYSQL_TYPE_DOUBLE"
+ };
+
+ const char* date_time_buffer_types[] =
+ {
+ "MYSQL_TYPE_DATE",
+ "MYSQL_TYPE_TIME",
+ "MYSQL_TYPE_DATETIME",
+ "MYSQL_TYPE_TIMESTAMP",
+ "MYSQL_TYPE_SHORT"
+ };
+
+ const char* char_bin_buffer_types[] =
+ {
+ "MYSQL_TYPE_STRING", // CHAR
+ "MYSQL_TYPE_BLOB", // BINARY,
+ "MYSQL_TYPE_STRING", // VARCHAR
+ "MYSQL_TYPE_BLOB", // VARBINARY
+ "MYSQL_TYPE_STRING", // TINYTEXT
+ "MYSQL_TYPE_BLOB", // TINYBLOB
+ "MYSQL_TYPE_STRING", // TEXT
+ "MYSQL_TYPE_BLOB", // BLOB
+ "MYSQL_TYPE_STRING", // MEDIUMTEXT
+ "MYSQL_TYPE_BLOB", // MEDIUMBLOB
+ "MYSQL_TYPE_STRING", // LONGTEXT
+ "MYSQL_TYPE_BLOB" // LONGBLOB
+ };
+ }
+
+ //
+ // bind
+ //
+
+ struct bind_member: relational::bind_member, member_base
+ {
+ bind_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return false;
+
+ ostringstream ostr;
+ ostr << "b[n]";
+ b = ostr.str ();
+
+ arg = arg_override_.empty () ? string ("i") : arg_override_;
+
+ if (var_override_.empty ())
+ {
+ os << "// " << mi.m.name () << endl
+ << "//" << endl;
+
+ if (inverse (mi.m, key_prefix_))
+ os << "if (out)"
+ << "{";
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (var_override_.empty ())
+ {
+ if (semantics::class_* c = comp_value (mi.t))
+ os << "n += " << in_column_count (*c) << "UL;";
+ else
+ os << "n++;";
+
+ if (inverse (mi.m, key_prefix_))
+ os << "}";
+ else
+ os << endl;
+ }
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << "composite_value_traits< " << mi.fq_type () <<
+ " >::bind (b + n, " << arg << "." << mi.var << "value);";
+ }
+
+ virtual void
+ traverse_integer (member_info& mi)
+ {
+ // While the is_unsigned should indicate whether the
+ // buffer variable is unsigned, rather than whether the
+ // database type is unsigned, in case of the image types,
+ // this is the same.
+ //
+ os << b << ".buffer_type = " <<
+ integer_buffer_types[mi.st->type - sql_type::TINYINT] << ";"
+ << b << ".is_unsigned = " << (mi.st->unsign ? "1" : "0") << ";"
+ << b << ".buffer = &" << arg << "." << mi.var << "value;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_float (member_info& mi)
+ {
+ os << b << ".buffer_type = " <<
+ float_buffer_types[mi.st->type - sql_type::FLOAT] << ";"
+ << b << ".buffer = &" << arg << "." << mi.var << "value;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_decimal (member_info& mi)
+ {
+ os << b << ".buffer_type = MYSQL_TYPE_NEWDECIMAL;"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".buffer_length = static_cast<unsigned long> (" << endl
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_date_time (member_info& mi)
+ {
+ os << b << ".buffer_type = " <<
+ date_time_buffer_types[mi.st->type - sql_type::DATE] << ";"
+ << b << ".buffer = &" << arg << "." << mi.var << "value;";
+
+ if (mi.st->type == sql_type::YEAR)
+ os << b << ".is_unsigned = 0;";
+
+ os << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_short_string (member_info& mi)
+ {
+ // MySQL documentation is quite confusing about the use of
+ // buffer_length and length when it comes to input parameters.
+ // Source code, however, tells us that it uses buffer_length
+ // only if length is NULL.
+ //
+ os << b << ".buffer_type = " <<
+ char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".buffer_length = static_cast<unsigned long> (" << endl
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_long_string (member_info& mi)
+ {
+ os << b << ".buffer_type = " <<
+ char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".buffer_length = static_cast<unsigned long> (" << endl
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_bit (member_info& mi)
+ {
+ // Treated as a BLOB.
+ //
+ os << b << ".buffer_type = MYSQL_TYPE_BLOB;"
+ << b << ".buffer = " << arg << "." << mi.var << "value;"
+ << b << ".buffer_length = static_cast<unsigned long> (" << endl
+ << "sizeof (" << arg << "." << mi.var << "value));"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_enum (member_info& mi)
+ {
+ // Represented as a string.
+ //
+ os << b << ".buffer_type = MYSQL_TYPE_STRING;"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".buffer_length = static_cast<unsigned long> (" << endl
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ virtual void
+ traverse_set (member_info& mi)
+ {
+ // Represented as a string.
+ //
+ os << b << ".buffer_type = MYSQL_TYPE_STRING;"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".buffer_length = static_cast<unsigned long> (" << endl
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;";
+ }
+
+ private:
+ string b;
+ string arg;
+ };
+ entry<bind_member> bind_member_;
+
+ //
+ // grow
+ //
+
+ struct grow_member: relational::grow_member, member_base
+ {
+ grow_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return false;
+
+ ostringstream ostr;
+ ostr << "e[" << index_ << "UL]";
+ e = ostr.str ();
+
+ if (var_override_.empty ())
+ os << "// " << mi.m.name () << endl
+ << "//" << endl;
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (semantics::class_* c = comp_value (mi.t))
+ index_ += in_column_count (*c);
+ else
+ index_++;
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << "if (composite_value_traits< " << mi.fq_type () <<
+ " >::grow (" << endl
+ << "i." << mi.var << "value, e + " << index_ << "UL))"
+ << "{"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_integer (member_info&)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_float (member_info&)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_decimal (member_info& mi)
+ {
+ // @@ Optimization disabled.
+ //
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_date_time (member_info&)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_short_string (member_info& mi)
+ {
+ // @@ Optimization disabled.
+ //
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_long_string (member_info& mi)
+ {
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_bit (member_info&)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_enum (member_info& mi)
+ {
+ // Represented as a string.
+ //
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_set (member_info& mi)
+ {
+ // Represented as a string.
+ //
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
+ << "grew = true;"
+ << "}";
+ }
+
+ private:
+ string e;
+ };
+ entry<grow_member> grow_member_;
+
+ //
+ // init image
+ //
+
+ struct init_image_member: relational::init_image_member, member_base
+ {
+ init_image_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x),
+ member_image_type_ (base::type_override_,
+ base::fq_type_override_,
+ base::key_prefix_),
+ member_database_type_ (base::type_override_,
+ base::fq_type_override_,
+ base::key_prefix_)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ // Ignore containers (they get their own table) and inverse
+ // object pointers (they are not present in the 'in' binding).
+ //
+ if (container (mi.t) || inverse (mi.m, key_prefix_))
+ return false;
+
+ if (!member_override_.empty ())
+ member = member_override_;
+ else
+ {
+ string const& name (mi.m.name ());
+ member = "o." + name;
+
+ os << "// " << name << endl
+ << "//" << endl;
+ }
+
+ if (comp_value (mi.t))
+ traits = "composite_value_traits< " + mi.fq_type () + " >";
+ else
+ {
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (semantics::class_* c = object_pointer (mt))
+ {
+ type = "obj_traits::id_type";
+ image_type = member_image_type_.image_type (mi.m);
+ db_type = member_database_type_.database_type (mi.m);
+
+ // Handle NULL pointers and extract the id.
+ //
+ os << "{"
+ << "typedef object_traits< " << c->fq_name () <<
+ " > obj_traits;";
+
+ if (weak_pointer (mt))
+ {
+ os << "typedef pointer_traits< " << mi.fq_type () <<
+ " > wptr_traits;"
+ << "typedef pointer_traits< wptr_traits::" <<
+ "strong_pointer_type > ptr_traits;"
+ << endl
+ << "wptr_traits::strong_pointer_type sp (" <<
+ "wptr_traits::lock (" << member << "));";
+
+ member = "sp";
+ }
+ else
+ os << "typedef pointer_traits< " << mi.fq_type () <<
+ " > ptr_traits;"
+ << endl;
+
+ os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
+ << "if (!is_null)"
+ << "{"
+ << "const " << type << "& id (" << endl;
+
+ if (lazy_pointer (mt))
+ os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
+ member << ")";
+ else
+ os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
+
+ os << ");"
+ << endl;
+
+ member = "id";
+ }
+ else
+ {
+ type = mi.fq_type ();
+ image_type = member_image_type_.image_type (mi.m);
+ db_type = member_database_type_.database_type (mi.m);
+
+ os << "{"
+ << "bool is_null;";
+ }
+
+ traits = "mysql::value_traits<\n "
+ + type + ",\n "
+ + image_type + ",\n "
+ + db_type + " >";
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (!comp_value (mi.t))
+ {
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ if (object_pointer (member_type (mi.m, key_prefix_)))
+ {
+ os << "}";
+
+ if (!null_pointer (mi.m, key_prefix_))
+ os << "else" << endl
+ << "throw null_pointer ();";
+ }
+
+ os << "i." << mi.var << "null = is_null;"
+ << "}";
+ }
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << "if (" << traits << "::init (i." << mi.var << "value, " <<
+ member << "))"
+ << "{"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_integer (member_info& mi)
+ {
+ os << traits << "::set_image (" << endl
+ << "i." << mi.var << "value, is_null, " << member << ");";
+ }
+
+ virtual void
+ traverse_float (member_info& mi)
+ {
+ os << traits << "::set_image (" << endl
+ << "i." << mi.var << "value, is_null, " << member << ");";
+ }
+
+ virtual void
+ traverse_decimal (member_info& mi)
+ {
+ // @@ Optimization: can remove growth check if buffer is fixed.
+ //
+ os << "std::size_t size (0);"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
+ << traits << "::set_image (" << endl
+ << "i." << mi.var << "value," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
+ }
+
+ virtual void
+ traverse_date_time (member_info& mi)
+ {
+ os << traits << "::set_image (" << endl
+ << "i." << mi.var << "value, is_null, " << member << ");";
+ }
+
+ virtual void
+ traverse_short_string (member_info& mi)
+ {
+ // @@ Optimization: can remove growth check if buffer is fixed.
+ //
+ os << "std::size_t size (0);"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
+ << traits << "::set_image (" << endl
+ << "i." << mi.var << "value," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
+ }
+
+ virtual void
+ traverse_long_string (member_info& mi)
+ {
+ os << "std::size_t size (0);"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
+ << traits << "::set_image (" << endl
+ << "i." << mi.var << "value," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
+ }
+
+ virtual void
+ traverse_bit (member_info& mi)
+ {
+ // Represented as a BLOB.
+ //
+ os << "std::size_t size (0);"
+ << traits << "::set_image (" << endl
+ << "i." << mi.var << "value," << endl
+ << "sizeof (i." << mi.var << "value)," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);";
+ }
+
+ virtual void
+ traverse_enum (member_info& mi)
+ {
+ // Represented as a string.
+ //
+ os << "std::size_t size (0);"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
+ << traits << "::set_image (" << endl
+ << "i." << mi.var << "value," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
+ }
+
+ virtual void
+ traverse_set (member_info& mi)
+ {
+ // Represented as a string.
+ //
+ os << "std::size_t size (0);"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
+ << traits << "::set_image (" << endl
+ << "i." << mi.var << "value," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
+ }
+
+ private:
+ string type;
+ string db_type;
+ string member;
+ string image_type;
+ string traits;
+
+ member_image_type member_image_type_;
+ member_database_type member_database_type_;
+ };
+ entry<init_image_member> init_image_member_;
+
+ //
+ // init value
+ //
+
+ struct init_value_member: relational::init_value_member, member_base
+ {
+ init_value_member (base const& x)
+ : member_base::base (x), // virtual base
+ base (x),
+ member_base (x),
+ member_image_type_ (base::type_override_,
+ base::fq_type_override_,
+ base::key_prefix_),
+ member_database_type_ (base::type_override_,
+ base::fq_type_override_,
+ base::key_prefix_)
+ {
+ }
+
+ virtual bool
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return false;
+
+ if (!member_override_.empty ())
+ member = member_override_;
+ else
+ {
+ string const& name (mi.m.name ());
+ member = "o." + name;
+
+ os << "// " << name << endl
+ << "//" << endl;
+ }
+
+ if (comp_value (mi.t))
+ traits = "composite_value_traits< " + mi.fq_type () + " >";
+ else
+ {
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (semantics::class_* c = object_pointer (mt))
+ {
+ type = "obj_traits::id_type";
+ image_type = member_image_type_.image_type (mi.m);
+ db_type = member_database_type_.database_type (mi.m);
+
+ // Handle NULL pointers and extract the id.
+ //
+ os << "{"
+ << "typedef object_traits< " << c->fq_name () <<
+ " > obj_traits;"
+ << "typedef pointer_traits< " << mi.fq_type () <<
+ " > ptr_traits;"
+ << endl
+ << "if (i." << mi.var << "null)" << endl;
+
+ if (null_pointer (mi.m, key_prefix_))
+ os << member << " = ptr_traits::pointer_type ();";
+ else
+ os << "throw null_pointer ();";
+
+ os << "else"
+ << "{"
+ << type << " id;";
+
+ member = "id";
+ }
+ else
+ {
+ type = mi.fq_type ();
+ image_type = member_image_type_.image_type (mi.m);
+ db_type = member_database_type_.database_type (mi.m);
+ }
+
+ traits = "mysql::value_traits<\n "
+ + type + ",\n "
+ + image_type + ",\n "
+ + db_type + " >";
+ }
+
+ return true;
+ }
+
+ virtual void
+ post (member_info& mi)
+ {
+ if (comp_value (mi.t))
+ return;
+
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (object_pointer (mt))
+ {
+ member = member_override_.empty ()
+ ? "o." + mi.m.name ()
+ : member_override_;
+
+ if (lazy_pointer (mt))
+ os << member << " = ptr_traits::pointer_type (db, id);";
+ else
+ os << "// If a compiler error points to the line below, then" << endl
+ << "// it most likely means that a pointer used in a member" << endl
+ << "// cannot be initialized from an object pointer." << endl
+ << "//" << endl
+ << member << " = ptr_traits::pointer_type (" << endl
+ << "db.load< ptr_traits::element_type > (id));";
+
+ os << "}"
+ << "}";
+ }
+ }
+
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ os << traits << "::init (" << member << ", i." <<
+ mi.var << "value, db);"
+ << endl;
+ }
+
+ virtual void
+ traverse_integer (member_info& mi)
+ {
+ os << traits << "::set_value (" << endl
+ << member << ", i." << mi.var << "value, " <<
+ "i." << mi.var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_float (member_info& mi)
+ {
+ os << traits << "::set_value (" << endl
+ << member << ", i." << mi.var << "value, " <<
+ "i." << mi.var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_decimal (member_info& mi)
+ {
+ os << traits << "::set_value (" << endl
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_date_time (member_info& mi)
+ {
+ os << traits << "::set_value (" << endl
+ << member << ", i." << mi.var << "value, " <<
+ "i." << mi.var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_short_string (member_info& mi)
+ {
+ os << traits << "::set_value (" << endl
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_long_string (member_info& mi)
+ {
+ os << traits << "::set_value (" << endl
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_bit (member_info& mi)
+ {
+ // Represented as a BLOB.
+ //
+ os << traits << "::set_value (" << endl
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_enum (member_info& mi)
+ {
+ // Represented as a string.
+ //
+ os << traits << "::set_value (" << endl
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_set (member_info& mi)
+ {
+ // Represented as a string.
+ //
+ os << traits << "::set_value (" << endl
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
+ << endl;
+ }
+
+ private:
+ string type;
+ string db_type;
+ string image_type;
+ string traits;
+ string member;
+
+ member_image_type member_image_type_;
+ member_database_type member_database_type_;
+ };
+ entry<init_value_member> init_value_member_;
+ }
+ }
+}
diff --git a/odb/relational/schema.cxx b/odb/relational/schema.cxx
new file mode 100644
index 0000000..0836e03
--- /dev/null
+++ b/odb/relational/schema.cxx
@@ -0,0 +1,101 @@
+// file : odb/relational/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/emitter.hxx>
+
+#include <odb/relational/schema.hxx>
+#include <odb/relational/generate.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace schema
+ {
+ struct schema_emitter: emitter, context
+ {
+ 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 ()
+ {
+ context ctx;
+ ostream& os (ctx.os);
+
+ os << file_header;
+
+ schema_emitter emitter;
+
+ // Drop.
+ //
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ instance<class_drop> c (emitter);
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+ unit.dispatch (ctx.unit);
+ }
+
+ os << endl;
+
+ // Create.
+ //
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ instance<class_create> c (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/relational/schema.hxx b/odb/relational/schema.hxx
new file mode 100644
index 0000000..bccb2a9
--- /dev/null
+++ b/odb/relational/schema.hxx
@@ -0,0 +1,379 @@
+// file : odb/relational/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_RELATIONAL_SCHEMA_HXX
+#define ODB_RELATIONAL_SCHEMA_HXX
+
+#include <set>
+#include <cassert>
+
+#include <odb/emitter.hxx>
+
+#include <odb/relational/common.hxx>
+#include <odb/relational/context.hxx>
+
+namespace relational
+{
+ namespace schema
+ {
+ typedef std::set<std::string> tables;
+
+ struct common: virtual context
+ {
+ common (emitter& e, ostream& os): e_ (e), os_ (os) {}
+
+ void
+ pre_statement ()
+ {
+ e_.pre ();
+ diverge (os_);
+ }
+
+ void
+ post_statement ()
+ {
+ restore ();
+ e_.post ();
+ }
+
+ protected:
+ emitter& e_;
+ ostream& os_;
+ };
+
+ //
+ // Drop.
+ //
+
+ struct drop_common: virtual context
+ {
+ virtual void
+ drop (string const& table)
+ {
+ os << "DROP TABLE IF EXISTS " << quote_id (table) << endl;
+ }
+ };
+
+ struct member_drop: object_members_base, common, virtual drop_common
+ {
+ typedef member_drop base;
+
+ member_drop (emitter& e, ostream& os, tables& t)
+ : object_members_base (false, true), common (e, os), 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;
+
+ pre_statement ();
+ drop (name);
+ post_statement ();
+
+ tables_.insert (name);
+ }
+
+ protected:
+ tables& tables_;
+ };
+
+ struct class_drop: traversal::class_, common, virtual drop_common
+ {
+ typedef class_drop base;
+
+ class_drop (emitter& e)
+ : common (e, os_), os_ (e), member_drop_ (e, os_, tables_)
+ {
+ }
+
+ class_drop (class_drop const& x)
+ : root_context (), //@@ -Wextra
+ context (),
+ common (x.e_, os_), os_ (x.e_), member_drop_ (x.e_, os_, 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;
+
+ pre_statement ();
+ drop (name);
+ post_statement ();
+
+ tables_.insert (name);
+
+ // Drop tables for members.
+ //
+ member_drop_->traverse (c);
+ }
+
+ protected:
+ tables tables_;
+ emitter_ostream os_;
+ instance<member_drop> member_drop_;
+ };
+
+ //
+ // Create.
+ //
+
+ struct object_columns: object_columns_base, virtual context
+ {
+ typedef object_columns base;
+
+ object_columns (string const& prefix = string ())
+ : 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 << " " << quote_id (name) << " " << column_type (m, prefix_);
+
+ if (m.count ("id"))
+ os << " PRIMARY KEY";
+
+ if (semantics::class_* c = object_pointer (member_type (m, prefix_)))
+ {
+ os << " REFERENCES " << quote_id (table_name (*c)) << " (" <<
+ quote_id (column_name (id_member (*c))) << ")";
+ }
+
+ return true;
+ }
+
+ protected:
+ string prefix_;
+ };
+
+ struct create_common: virtual context
+ {
+ virtual void
+ create_pre (string const& table)
+ {
+ os << "CREATE TABLE " << quote_id (table) << " (" << endl;
+ }
+
+ virtual void
+ index (string const& column)
+ {
+ os << "INDEX (" << quote_id (column) << ")";
+ }
+
+ virtual void
+ create_post ()
+ {
+ os << ")" << endl;
+ }
+ };
+
+
+ struct member_create: object_members_base, common, virtual create_common
+ {
+ typedef member_create base;
+
+ member_create (emitter& e, ostream& os, tables& t)
+ : object_members_base (false, true), common (e, os), 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;
+
+ pre_statement ();
+ create_pre (name);
+
+ // object_id (simple value)
+ //
+ string id_name (column_name (m, "id", "object_id"));
+ {
+ instance<object_columns> oc ("id");
+ oc->column (m, id_name, true);
+ }
+
+ // index (simple value)
+ //
+ string index_name;
+ bool ordered (ck == ck_ordered && !unordered (m));
+ if (ordered)
+ {
+ os << "," << endl;
+
+ instance<object_columns> oc ("index");
+ index_name = column_name (m, "index", "index");
+ oc->column (m, index_name, true);
+ }
+
+ // 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))
+ {
+ instance<object_columns> oc;
+ oc->traverse_composite (m, *ckt, "key", "key");
+ }
+ else
+ {
+ instance<object_columns> oc ("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))
+ {
+ instance<object_columns> oc;
+ oc->traverse_composite (m, *cvt, "value", "value");
+ }
+ else
+ {
+ instance<object_columns> oc ("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);
+ }
+
+ create_post ();
+ post_statement ();
+
+ tables_.insert (name);
+ }
+
+ protected:
+ tables& tables_;
+ };
+
+ struct class_create: traversal::class_, common, virtual create_common
+ {
+ typedef class_create base;
+
+ class_create (emitter& e)
+ : common (e, os_), os_ (e), member_create_ (e, os_, tables_)
+ {
+ }
+
+ class_create (class_create const& x)
+ : root_context (), //@@ -Wextra
+ context (),
+ common (x.e_, os_), os_ (x.e_), member_create_ (x.e_, os_, tables_)
+ {
+ }
+
+ 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;
+
+ pre_statement ();
+ create_pre (name);
+
+ {
+ instance<object_columns> oc;
+ oc->traverse (c);
+ }
+
+ create_post ();
+ post_statement ();
+
+ tables_.insert (name);
+
+ // Create tables for members.
+ //
+ member_create_->traverse (c);
+ }
+
+ protected:
+ tables tables_;
+ emitter_ostream os_;
+ instance<member_create> member_create_;
+ };
+ }
+}
+
+#endif // ODB_RELATIONAL_SCHEMA_HXX
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
new file mode 100644
index 0000000..be9da93
--- /dev/null
+++ b/odb/relational/source.cxx
@@ -0,0 +1,79 @@
+// file : odb/relational/source.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/relational/source.hxx>
+#include <odb/relational/generate.hxx>
+
+using namespace std;
+
+namespace relational
+{
+ namespace source
+ {
+ void
+ generate ()
+ {
+ context ctx;
+ ostream& os (ctx.os);
+ options const& ops (ctx.options);
+
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ //
+ //
+ os << "#include <odb/cache-traits.hxx>" << endl;
+
+ if (ctx.embedded_schema)
+ os << "#include <odb/schema-catalog-impl.hxx>" << endl;
+
+ os << endl;
+
+ //
+ //
+ os << "#include <odb/mysql/mysql.hxx>" << endl
+ << "#include <odb/mysql/traits.hxx>" << endl
+ << "#include <odb/mysql/database.hxx>" << endl
+ << "#include <odb/mysql/transaction.hxx>" << endl
+ << "#include <odb/mysql/connection.hxx>" << endl
+ << "#include <odb/mysql/statement.hxx>" << endl
+ << "#include <odb/mysql/statement-cache.hxx>" << endl
+ << "#include <odb/mysql/object-statements.hxx>" << endl
+ << "#include <odb/mysql/container-statements.hxx>" << endl
+ << "#include <odb/mysql/exceptions.hxx>" << endl;
+
+ if (ops.generate_query ())
+ os << "#include <odb/mysql/result.hxx>" << endl;
+
+ os << endl;
+
+ // Details includes.
+ //
+ os << "#include <odb/details/unused.hxx>" << endl;
+
+ if (ops.generate_query ())
+ os << "#include <odb/details/shared-ptr.hxx>" << endl;
+
+ os << endl;
+
+ os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ os << "}";
+ }
+ }
+}
diff --git a/odb/mysql/source.cxx b/odb/relational/source.hxx
index bc7340a..6f30007 100644
--- a/odb/mysql/source.cxx
+++ b/odb/relational/source.hxx
@@ -1,29 +1,30 @@
-// file : odb/mysql/source.cxx
+// file : odb/relational/source.hxx
// 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/gcc.hxx>
+#ifndef ODB_RELATIONAL_SOURCE_HXX
+#define ODB_RELATIONAL_SOURCE_HXX
+
+#include <odb/gcc.hxx> // @@ ??
#include <map>
#include <set>
#include <vector>
#include <sstream>
-#include <odb/mysql/common.hxx>
-#include <odb/mysql/schema.hxx>
-#include <odb/mysql/source.hxx>
+#include <odb/emitter.hxx>
-using namespace std;
+#include <odb/relational/context.hxx>
+#include <odb/relational/common.hxx>
+#include <odb/relational/schema.hxx>
-namespace mysql
+namespace relational
{
- namespace
+ namespace source
{
- struct schema_emitter: emitter, context
+ struct schema_emitter: emitter, virtual context
{
- schema_emitter (context& c): context (c) {}
-
virtual void
pre ()
{
@@ -52,29 +53,25 @@ namespace mysql
bool first_;
};
- struct object_columns: object_columns_base, context
+ struct object_columns: object_columns_base, virtual context
{
- object_columns (context& c,
- std::string const& table_name,
+ typedef object_columns base;
+
+ object_columns (std::string const& table_name,
bool out,
char const* suffix = "")
- : object_columns_base (c),
- context (c),
- table_name_ (table_name),
+ : table_name_ (table_name),
out_ (out),
first_ (true),
suffix_ (suffix)
{
}
- object_columns (context& c,
- std::string const& table_name,
+ object_columns (std::string const& table_name,
bool out,
bool first,
char const* suffix = "")
- : object_columns_base (c),
- context (c),
- table_name_ (table_name),
+ : table_name_ (table_name),
out_ (out),
first_ (first),
suffix_ (suffix)
@@ -130,12 +127,14 @@ namespace mysql
string suffix_;
};
- struct object_joins: object_columns_base, context
+ struct object_joins: object_columns_base, virtual context
{
- object_joins (context& c, semantics::class_& scope, bool query)
- : object_columns_base (c),
- context (c),
- query_ (query),
+ typedef object_joins base;
+
+ //@@ context::object Might have to be create every time.
+ //
+ object_joins (semantics::class_& scope, bool query)
+ : query_ (query),
table_ (table_name (scope)),
id_ (id_member (scope))
{
@@ -179,7 +178,7 @@ namespace mysql
return true;
string t, dt;
- ostringstream cond, dcond;
+ std::ostringstream cond, dcond; // @@ diversion?
if (semantics::data_member* im = inverse (m))
{
@@ -279,7 +278,7 @@ namespace mysql
string table_;
semantics::data_member& id_;
- typedef set<string> conditions;
+ typedef std::set<string> conditions;
struct join
{
@@ -294,253 +293,45 @@ namespace mysql
}
};
- typedef vector<join> joins;
- typedef map<string, size_t> table_map;
+ typedef std::vector<join> joins;
+ typedef std::map<string, size_t> table_map;
joins joins_;
table_map table_map_;
};
- const char* integer_buffer_types[] =
- {
- "MYSQL_TYPE_TINY",
- "MYSQL_TYPE_SHORT",
- "MYSQL_TYPE_LONG", // *_bind_param() doesn't support INT24.
- "MYSQL_TYPE_LONG",
- "MYSQL_TYPE_LONGLONG"
- };
-
- const char* float_buffer_types[] =
- {
- "MYSQL_TYPE_FLOAT",
- "MYSQL_TYPE_DOUBLE"
- };
-
- const char* date_time_buffer_types[] =
- {
- "MYSQL_TYPE_DATE",
- "MYSQL_TYPE_TIME",
- "MYSQL_TYPE_DATETIME",
- "MYSQL_TYPE_TIMESTAMP",
- "MYSQL_TYPE_SHORT"
- };
-
- const char* char_bin_buffer_types[] =
- {
- "MYSQL_TYPE_STRING", // CHAR
- "MYSQL_TYPE_BLOB", // BINARY,
- "MYSQL_TYPE_STRING", // VARCHAR
- "MYSQL_TYPE_BLOB", // VARBINARY
- "MYSQL_TYPE_STRING", // TINYTEXT
- "MYSQL_TYPE_BLOB", // TINYBLOB
- "MYSQL_TYPE_STRING", // TEXT
- "MYSQL_TYPE_BLOB", // BLOB
- "MYSQL_TYPE_STRING", // MEDIUMTEXT
- "MYSQL_TYPE_BLOB", // MEDIUMBLOB
- "MYSQL_TYPE_STRING", // LONGTEXT
- "MYSQL_TYPE_BLOB" // LONGBLOB
- };
-
//
// bind
//
- struct bind_member: member_base
+ struct bind_member: virtual member_base
{
- bind_member (context& c,
- string const& var = string (),
+ typedef bind_member base;
+
+ bind_member (string const& var = string (),
string const& arg = string ())
- : member_base (c, var), arg_override_ (arg)
+ : member_base (var, 0, string (), string ()),
+ arg_override_ (arg)
{
}
- bind_member (context& c,
- string const& var,
+ bind_member (string const& var,
string const& arg,
semantics::type& t,
string const& fq_type,
string const& key_prefix)
- : member_base (c, var, t, fq_type, key_prefix), arg_override_ (arg)
- {
- }
-
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi.t))
- return false;
-
- ostringstream ostr;
- ostr << "b[n]";
- b = ostr.str ();
-
- arg = arg_override_.empty () ? string ("i") : arg_override_;
-
- if (var_override_.empty ())
- {
- os << "// " << mi.m.name () << endl
- << "//" << endl;
-
- if (inverse (mi.m, key_prefix_))
- os << "if (out)"
- << "{";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
- {
- if (var_override_.empty ())
- {
- if (semantics::class_* c = comp_value (mi.t))
- os << "n += " << in_column_count (*c) << "UL;";
- else
- os << "n++;";
-
- if (inverse (mi.m, key_prefix_))
- os << "}";
- else
- os << endl;
- }
- }
-
- virtual void
- traverse_composite (member_info& mi)
- {
- os << "composite_value_traits< " << mi.fq_type () <<
- " >::bind (b + n, " << arg << "." << mi.var << "value);";
- }
-
- virtual void
- traverse_integer (member_info& mi)
- {
- // While the is_unsigned should indicate whether the
- // buffer variable is unsigned, rather than whether the
- // database type is unsigned, in case of the image types,
- // this is the same.
- //
- os << b << ".buffer_type = " <<
- integer_buffer_types[mi.st->type - sql_type::TINYINT] << ";"
- << b << ".is_unsigned = " << (mi.st->unsign ? "1" : "0") << ";"
- << b << ".buffer = &" << arg << "." << mi.var << "value;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
-
- virtual void
- traverse_float (member_info& mi)
+ : member_base (var, &t, fq_type, key_prefix),
+ arg_override_ (arg)
{
- os << b << ".buffer_type = " <<
- float_buffer_types[mi.st->type - sql_type::FLOAT] << ";"
- << b << ".buffer = &" << arg << "." << mi.var << "value;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
}
- virtual void
- traverse_decimal (member_info& mi)
- {
- os << b << ".buffer_type = MYSQL_TYPE_NEWDECIMAL;"
- << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
- << b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "" << arg << "." << mi.var << "value.capacity ());"
- << b << ".length = &" << arg << "." << mi.var << "size;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
-
- virtual void
- traverse_date_time (member_info& mi)
- {
- os << b << ".buffer_type = " <<
- date_time_buffer_types[mi.st->type - sql_type::DATE] << ";"
- << b << ".buffer = &" << arg << "." << mi.var << "value;";
-
- if (mi.st->type == sql_type::YEAR)
- os << b << ".is_unsigned = 0;";
-
- os << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
-
- virtual void
- traverse_short_string (member_info& mi)
- {
- // MySQL documentation is quite confusing about the use of
- // buffer_length and length when it comes to input parameters.
- // Source code, however, tells us that it uses buffer_length
- // only if length is NULL.
- //
- os << b << ".buffer_type = " <<
- char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";"
- << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
- << b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "" << arg << "." << mi.var << "value.capacity ());"
- << b << ".length = &" << arg << "." << mi.var << "size;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
-
- virtual void
- traverse_long_string (member_info& mi)
- {
- os << b << ".buffer_type = " <<
- char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";"
- << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
- << b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "" << arg << "." << mi.var << "value.capacity ());"
- << b << ".length = &" << arg << "." << mi.var << "size;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
-
- virtual void
- traverse_bit (member_info& mi)
- {
- // Treated as a BLOB.
- //
- os << b << ".buffer_type = MYSQL_TYPE_BLOB;"
- << b << ".buffer = " << arg << "." << mi.var << "value;"
- << b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "sizeof (" << arg << "." << mi.var << "value));"
- << b << ".length = &" << arg << "." << mi.var << "size;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
-
- virtual void
- traverse_enum (member_info& mi)
- {
- // Represented as a string.
- //
- os << b << ".buffer_type = MYSQL_TYPE_STRING;"
- << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
- << b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "" << arg << "." << mi.var << "value.capacity ());"
- << b << ".length = &" << arg << "." << mi.var << "size;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
-
- virtual void
- traverse_set (member_info& mi)
- {
- // Represented as a string.
- //
- os << b << ".buffer_type = MYSQL_TYPE_STRING;"
- << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
- << b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "" << arg << "." << mi.var << "value.capacity ());"
- << b << ".length = &" << arg << "." << mi.var << "size;"
- << b << ".is_null = &" << arg << "." << mi.var << "null;";
- }
-
- private:
- string b;
- string arg;
+ protected:
string arg_override_;
};
- struct bind_base: traversal::class_, context
+ struct bind_base: traversal::class_, virtual context
{
- bind_base (context& c)
- : context (c)
- {
- }
+ typedef bind_base base;
virtual void
traverse (type& c)
@@ -563,157 +354,33 @@ namespace mysql
// grow
//
- struct grow_member: member_base
+ struct grow_member: virtual member_base
{
- grow_member (context& c, size_t& index)
- : member_base (c), index_ (index)
+ typedef grow_member base;
+
+ grow_member (size_t& index)
+ : member_base (string (), 0, string (), string ()), index_ (index)
{
}
- grow_member (context& c,
- size_t& index,
+ grow_member (size_t& index,
string const& var,
semantics::type& t,
string const& fq_type,
string const& key_prefix)
- : member_base (c, var, t, fq_type, key_prefix), index_ (index)
+ : member_base (var, &t, fq_type, key_prefix), index_ (index)
{
}
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi.t))
- return false;
-
- ostringstream ostr;
- ostr << "e[" << index_ << "UL]";
- e = ostr.str ();
-
- if (var_override_.empty ())
- os << "// " << mi.m.name () << endl
- << "//" << endl;
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
- {
- if (semantics::class_* c = comp_value (mi.t))
- index_ += in_column_count (*c);
- else
- index_++;
- }
-
- virtual void
- traverse_composite (member_info& mi)
- {
- os << "if (composite_value_traits< " << mi.fq_type () <<
- " >::grow (" << endl
- << "i." << mi.var << "value, e + " << index_ << "UL))"
- << "{"
- << "grew = true;"
- << "}";
- }
-
- virtual void
- traverse_integer (member_info&)
- {
- os << e << " = 0;"
- << endl;
- }
-
- virtual void
- traverse_float (member_info&)
- {
- os << e << " = 0;"
- << endl;
- }
-
- virtual void
- traverse_decimal (member_info& mi)
- {
- // @@ Optimization disabled.
- //
- os << "if (" << e << ")" << endl
- << "{"
- << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
- << "grew = true;"
- << "}";
- }
-
- virtual void
- traverse_date_time (member_info&)
- {
- os << e << " = 0;"
- << endl;
- }
-
- virtual void
- traverse_short_string (member_info& mi)
- {
- // @@ Optimization disabled.
- //
- os << "if (" << e << ")" << endl
- << "{"
- << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
- << "grew = true;"
- << "}";
- }
-
- virtual void
- traverse_long_string (member_info& mi)
- {
- os << "if (" << e << ")" << endl
- << "{"
- << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
- << "grew = true;"
- << "}";
- }
-
- virtual void
- traverse_bit (member_info&)
- {
- os << e << " = 0;"
- << endl;
- }
-
- virtual void
- traverse_enum (member_info& mi)
- {
- // Represented as a string.
- //
- os << "if (" << e << ")" << endl
- << "{"
- << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
- << "grew = true;"
- << "}";
- }
-
- virtual void
- traverse_set (member_info& mi)
- {
- // Represented as a string.
- //
- os << "if (" << e << ")" << endl
- << "{"
- << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
- << "grew = true;"
- << "}";
- }
-
- private:
- string e;
+ protected:
size_t& index_;
};
- struct grow_base: traversal::class_, context
+ struct grow_base: traversal::class_, virtual context
{
- grow_base (context& c, size_t& index)
- : context (c), index_ (index)
- {
- }
+ typedef grow_base base;
+
+ grow_base (size_t& index): index_ (index) {}
virtual void
traverse (type& c)
@@ -734,7 +401,7 @@ namespace mysql
index_ += in_column_count (c);
}
- private:
+ protected:
size_t& index_;
};
@@ -742,289 +409,34 @@ namespace mysql
// init image
//
- struct init_image_member: member_base
+ struct init_image_member: virtual member_base
{
- init_image_member (context& c,
- string const& var = string (),
+ typedef init_image_member base;
+
+ init_image_member (string const& var = string (),
string const& member = string ())
- : member_base (c, var),
- member_image_type_ (c),
- member_database_type_ (c),
+ : member_base (var, 0, string (), string ()),
member_override_ (member)
{
}
- init_image_member (context& c,
- string const& var,
+ init_image_member (string const& var,
string const& member,
semantics::type& t,
string const& fq_type,
string const& key_prefix)
- : member_base (c, var, t, fq_type, key_prefix),
- member_image_type_ (c, t, fq_type, key_prefix),
- member_database_type_ (c, t, fq_type, key_prefix),
+ : member_base (var, &t, fq_type, key_prefix),
member_override_ (member)
{
}
- virtual bool
- pre (member_info& mi)
- {
- // Ignore containers (they get their own table) and inverse
- // object pointers (they are not present in the 'in' binding).
- //
- if (container (mi.t) || inverse (mi.m, key_prefix_))
- return false;
-
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- string const& name (mi.m.name ());
- member = "o." + name;
-
- os << "// " << name << endl
- << "//" << endl;
- }
-
- if (comp_value (mi.t))
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_type (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- image_type = member_image_type_.image_type (mi.m);
- db_type = member_database_type_.database_type (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << c->fq_name () <<
- " > obj_traits;";
-
- if (weak_pointer (mt))
- {
- os << "typedef pointer_traits< " << mi.fq_type () <<
- " > wptr_traits;"
- << "typedef pointer_traits< wptr_traits::" <<
- "strong_pointer_type > ptr_traits;"
- << endl
- << "wptr_traits::strong_pointer_type sp (" <<
- "wptr_traits::lock (" << member << "));";
-
- member = "sp";
- }
- else
- os << "typedef pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl;
-
- os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
- << "if (!is_null)"
- << "{"
- << "const " << type << "& id (" << endl;
-
- if (lazy_pointer (mt))
- os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
- member << ")";
- else
- os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
-
- os << ");"
- << endl;
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- image_type = member_image_type_.image_type (mi.m);
- db_type = member_database_type_.database_type (mi.m);
-
- os << "{"
- << "bool is_null;";
- }
-
- traits = "mysql::value_traits<\n "
- + type + ",\n "
- + image_type + ",\n "
- + db_type + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
- {
- if (!comp_value (mi.t))
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- if (object_pointer (member_type (mi.m, key_prefix_)))
- {
- os << "}";
-
- if (!null_pointer (mi.m, key_prefix_))
- os << "else" << endl
- << "throw null_pointer ();";
- }
-
- os << "i." << mi.var << "null = is_null;"
- << "}";
- }
- }
-
- virtual void
- traverse_composite (member_info& mi)
- {
- os << "if (" << traits << "::init (i." << mi.var << "value, " <<
- member << "))"
- << "{"
- << "grew = true;"
- << "}";
- }
-
- virtual void
- traverse_integer (member_info& mi)
- {
- os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
- }
-
- virtual void
- traverse_float (member_info& mi)
- {
- os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
- }
-
- virtual void
- traverse_decimal (member_info& mi)
- {
- // @@ Optimization: can remove growth check if buffer is fixed.
- //
- os << "std::size_t size (0);"
- << "std::size_t cap (i." << mi.var << "value.capacity ());"
- << traits << "::set_image (" << endl
- << "i." << mi.var << "value," << endl
- << "size," << endl
- << "is_null," << endl
- << member << ");"
- << "i." << mi.var << "size = static_cast<unsigned long> (size);"
- << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
- }
-
- virtual void
- traverse_date_time (member_info& mi)
- {
- os << traits << "::set_image (" << endl
- << "i." << mi.var << "value, is_null, " << member << ");";
- }
-
- virtual void
- traverse_short_string (member_info& mi)
- {
- // @@ Optimization: can remove growth check if buffer is fixed.
- //
- os << "std::size_t size (0);"
- << "std::size_t cap (i." << mi.var << "value.capacity ());"
- << traits << "::set_image (" << endl
- << "i." << mi.var << "value," << endl
- << "size," << endl
- << "is_null," << endl
- << member << ");"
- << "i." << mi.var << "size = static_cast<unsigned long> (size);"
- << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
- }
-
- virtual void
- traverse_long_string (member_info& mi)
- {
- os << "std::size_t size (0);"
- << "std::size_t cap (i." << mi.var << "value.capacity ());"
- << traits << "::set_image (" << endl
- << "i." << mi.var << "value," << endl
- << "size," << endl
- << "is_null," << endl
- << member << ");"
- << "i." << mi.var << "size = static_cast<unsigned long> (size);"
- << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
- }
-
- virtual void
- traverse_bit (member_info& mi)
- {
- // Represented as a BLOB.
- //
- os << "std::size_t size (0);"
- << traits << "::set_image (" << endl
- << "i." << mi.var << "value," << endl
- << "sizeof (i." << mi.var << "value)," << endl
- << "size," << endl
- << "is_null," << endl
- << member << ");"
- << "i." << mi.var << "size = static_cast<unsigned long> (size);";
- }
-
- virtual void
- traverse_enum (member_info& mi)
- {
- // Represented as a string.
- //
- os << "std::size_t size (0);"
- << "std::size_t cap (i." << mi.var << "value.capacity ());"
- << traits << "::set_image (" << endl
- << "i." << mi.var << "value," << endl
- << "size," << endl
- << "is_null," << endl
- << member << ");"
- << "i." << mi.var << "size = static_cast<unsigned long> (size);"
- << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
- }
-
- virtual void
- traverse_set (member_info& mi)
- {
- // Represented as a string.
- //
- os << "std::size_t size (0);"
- << "std::size_t cap (i." << mi.var << "value.capacity ());"
- << traits << "::set_image (" << endl
- << "i." << mi.var << "value," << endl
- << "size," << endl
- << "is_null," << endl
- << member << ");"
- << "i." << mi.var << "size = static_cast<unsigned long> (size);"
- << "grew = grew || (cap != i." << mi.var << "value.capacity ());";
- }
-
- private:
- string type;
- string db_type;
- string member;
- string image_type;
- string traits;
-
- member_image_type member_image_type_;
- member_database_type member_database_type_;
-
+ protected:
string member_override_;
};
- struct init_image_base: traversal::class_, context
+ struct init_image_base: traversal::class_, virtual context
{
- init_image_base (context& c)
- : context (c)
- {
- }
+ typedef init_image_base base;
virtual void
traverse (type& c)
@@ -1048,256 +460,33 @@ namespace mysql
// init value
//
- struct init_value_member: member_base
+ struct init_value_member: virtual member_base
{
- init_value_member (context& c, string const& member = string ())
- : member_base (c),
- member_image_type_ (c),
- member_database_type_ (c),
+ typedef init_value_member base;
+
+ init_value_member (string const& member = string ())
+ : member_base (string (), 0, string (), string ()),
member_override_ (member)
{
}
- init_value_member (context& c,
- string const& var,
+ init_value_member (string const& var,
string const& member,
semantics::type& t,
string const& fq_type,
string const& key_prefix)
- : member_base (c, var, t, fq_type, key_prefix),
- member_image_type_ (c, t, fq_type, key_prefix),
- member_database_type_ (c, t, fq_type, key_prefix),
+ : member_base (var, &t, fq_type, key_prefix),
member_override_ (member)
{
}
- virtual bool
- pre (member_info& mi)
- {
- if (container (mi.t))
- return false;
-
- if (!member_override_.empty ())
- member = member_override_;
- else
- {
- string const& name (mi.m.name ());
- member = "o." + name;
-
- os << "// " << name << endl
- << "//" << endl;
- }
-
- if (comp_value (mi.t))
- traits = "composite_value_traits< " + mi.fq_type () + " >";
- else
- {
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_type (mi.m, key_prefix_));
-
- if (semantics::class_* c = object_pointer (mt))
- {
- type = "obj_traits::id_type";
- image_type = member_image_type_.image_type (mi.m);
- db_type = member_database_type_.database_type (mi.m);
-
- // Handle NULL pointers and extract the id.
- //
- os << "{"
- << "typedef object_traits< " << c->fq_name () <<
- " > obj_traits;"
- << "typedef pointer_traits< " << mi.fq_type () <<
- " > ptr_traits;"
- << endl
- << "if (i." << mi.var << "null)" << endl;
-
- if (null_pointer (mi.m, key_prefix_))
- os << member << " = ptr_traits::pointer_type ();";
- else
- os << "throw null_pointer ();";
-
- os << "else"
- << "{"
- << type << " id;";
-
- member = "id";
- }
- else
- {
- type = mi.fq_type ();
- image_type = member_image_type_.image_type (mi.m);
- db_type = member_database_type_.database_type (mi.m);
- }
-
- traits = "mysql::value_traits<\n "
- + type + ",\n "
- + image_type + ",\n "
- + db_type + " >";
- }
-
- return true;
- }
-
- virtual void
- post (member_info& mi)
- {
- if (comp_value (mi.t))
- return;
-
- // When handling a pointer, mi.t is the id type of the referenced
- // object.
- //
- semantics::type& mt (member_type (mi.m, key_prefix_));
-
- if (object_pointer (mt))
- {
- member = member_override_.empty ()
- ? "o." + mi.m.name ()
- : member_override_;
-
- if (lazy_pointer (mt))
- os << member << " = ptr_traits::pointer_type (db, id);";
- else
- os << "// If a compiler error points to the line below, then" << endl
- << "// it most likely means that a pointer used in a member" << endl
- << "// cannot be initialized from an object pointer." << endl
- << "//" << endl
- << member << " = ptr_traits::pointer_type (" << endl
- << "db.load< ptr_traits::element_type > (id));";
-
- os << "}"
- << "}";
- }
- }
-
- virtual void
- traverse_composite (member_info& mi)
- {
- os << traits << "::init (" << member << ", i." <<
- mi.var << "value, db);"
- << endl;
- }
-
- virtual void
- traverse_integer (member_info& mi)
- {
- os << traits << "::set_value (" << endl
- << member << ", i." << mi.var << "value, " <<
- "i." << mi.var << "null);"
- << endl;
- }
-
- virtual void
- traverse_float (member_info& mi)
- {
- os << traits << "::set_value (" << endl
- << member << ", i." << mi.var << "value, " <<
- "i." << mi.var << "null);"
- << endl;
- }
-
- virtual void
- traverse_decimal (member_info& mi)
- {
- os << traits << "::set_value (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "i." << mi.var << "size," << endl
- << "i." << mi.var << "null);"
- << endl;
- }
-
- virtual void
- traverse_date_time (member_info& mi)
- {
- os << traits << "::set_value (" << endl
- << member << ", i." << mi.var << "value, " <<
- "i." << mi.var << "null);"
- << endl;
- }
-
- virtual void
- traverse_short_string (member_info& mi)
- {
- os << traits << "::set_value (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "i." << mi.var << "size," << endl
- << "i." << mi.var << "null);"
- << endl;
- }
-
- virtual void
- traverse_long_string (member_info& mi)
- {
- os << traits << "::set_value (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "i." << mi.var << "size," << endl
- << "i." << mi.var << "null);"
- << endl;
- }
-
- virtual void
- traverse_bit (member_info& mi)
- {
- // Represented as a BLOB.
- //
- os << traits << "::set_value (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "i." << mi.var << "size," << endl
- << "i." << mi.var << "null);"
- << endl;
- }
-
- virtual void
- traverse_enum (member_info& mi)
- {
- // Represented as a string.
- //
- os << traits << "::set_value (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "i." << mi.var << "size," << endl
- << "i." << mi.var << "null);"
- << endl;
- }
-
- virtual void
- traverse_set (member_info& mi)
- {
- // Represented as a string.
- //
- os << traits << "::set_value (" << endl
- << member << "," << endl
- << "i." << mi.var << "value," << endl
- << "i." << mi.var << "size," << endl
- << "i." << mi.var << "null);"
- << endl;
- }
-
- private:
- string type;
- string db_type;
- string image_type;
- string traits;
- string member;
-
- member_image_type member_image_type_;
- member_database_type member_database_type_;
-
+ protected:
string member_override_;
};
- struct init_value_base: traversal::class_, context
+ struct init_value_base: traversal::class_, virtual context
{
- init_value_base (context& c)
- : context (c)
- {
- }
+ typedef init_value_base base;
virtual void
traverse (type& c)
@@ -1317,11 +506,12 @@ namespace mysql
// Member-specific traits types for container members.
//
- struct container_traits: object_members_base, context
+ struct container_traits: object_members_base, virtual context
{
- container_traits (context& c, semantics::class_& obj)
- : object_members_base (c, true, true),
- context (c),
+ typedef container_traits base;
+
+ container_traits (semantics::class_& obj) // @@ context::object
+ : object_members_base (true, true),
object_ (obj),
id_member_ (id_member (obj))
{
@@ -1451,8 +641,8 @@ namespace mysql
{
if (semantics::class_* ckt = comp_value (*kt))
{
- object_columns t (*this, table, false, false);
- t.traverse_composite (m, *ckt, "key", "key");
+ instance<object_columns> t (table, false, false);
+ t->traverse_composite (m, *ckt, "key", "key");
}
else
{
@@ -1470,8 +660,8 @@ namespace mysql
if (semantics::class_* cvt = comp_value (vt))
{
- object_columns t (*this, table, false, false);
- t.traverse_composite (m, *cvt, "value", "value");
+ instance<object_columns> t (table, false, false);
+ t->traverse_composite (m, *cvt, "value", "value");
}
else
{
@@ -1520,8 +710,8 @@ namespace mysql
{
if (semantics::class_* ckt = comp_value (*kt))
{
- object_columns t (*this, table, false, false);
- t.traverse_composite (m, *ckt, "key", "key");
+ instance<object_columns> t (table, false, false);
+ t->traverse_composite (m, *ckt, "key", "key");
}
else
{
@@ -1539,8 +729,8 @@ namespace mysql
if (semantics::class_* cvt = comp_value (vt))
{
- object_columns t (*this, table, false, false);
- t.traverse_composite (m, *cvt, "value", "value");
+ instance<object_columns> t (table, false, false);
+ t->traverse_composite (m, *cvt, "value", "value");
}
else
{
@@ -1580,7 +770,7 @@ namespace mysql
// bind()
//
{
- bind_member bind_id (*this, "id_", "id");
+ instance<bind_member> bind_id ("id_", "id");
// bind (cond_image_type)
//
@@ -1597,7 +787,7 @@ namespace mysql
<< "if (p != 0)"
<< "{"
<< "id_image_type& id (*p);";
- bind_id.traverse (id_member_);
+ bind_id->traverse (id_member_);
os << "}"
<< "n++;"
<< endl;
@@ -1613,9 +803,9 @@ namespace mysql
{
os << "// index" << endl
<< "//" << endl;
- bind_member bm (
- *this, "index_", "c", *it, "index_type", "index");
- bm.traverse (m);
+ instance<bind_member> bm (
+ "index_", "c", *it, "index_type", "index");
+ bm->traverse (m);
}
break;
}
@@ -1624,8 +814,8 @@ namespace mysql
{
os << "// key" << endl
<< "//" << endl;
- bind_member bm (*this, "key_", "c", *kt, "key_type", "key");
- bm.traverse (m);
+ instance<bind_member> bm ("key_", "c", *kt, "key_type", "key");
+ bm->traverse (m);
break;
}
case ck_set:
@@ -1633,8 +823,9 @@ namespace mysql
{
os << "// value" << endl
<< "//" << endl;
- bind_member bm (*this, "value_", "c", vt, "value_type", "value");
- bm.traverse (m);
+ instance<bind_member> bm (
+ "value_", "c", vt, "value_type", "value");
+ bm->traverse (m);
break;
}
}
@@ -1654,7 +845,7 @@ namespace mysql
<< "if (p != 0)"
<< "{"
<< "id_image_type& id (*p);";
- bind_id.traverse (id_member_);
+ bind_id->traverse (id_member_);
os << "}"
<< "n++;"
<< endl;
@@ -1667,9 +858,9 @@ namespace mysql
{
os << "// index" << endl
<< "//" << endl;
- bind_member bm (
- *this, "index_", "d", *it, "index_type", "index");
- bm.traverse (m);
+ instance<bind_member> bm (
+ "index_", "d", *it, "index_type", "index");
+ bm->traverse (m);
os << "n++;" // Simple value.
<< endl;
}
@@ -1680,8 +871,8 @@ namespace mysql
{
os << "// key" << endl
<< "//" << endl;
- bind_member bm (*this, "key_", "d", *kt, "key_type", "key");
- bm.traverse (m);
+ instance<bind_member> bm ("key_", "d", *kt, "key_type", "key");
+ bm->traverse (m);
if (semantics::class_* c = comp_value (*kt))
os << "n += " << in_column_count (*c) << "UL;"
@@ -1703,8 +894,8 @@ namespace mysql
//
os << "// value" << endl
<< "//" << endl;
- bind_member bm (*this, "value_", "d", vt, "value_type", "value");
- bm.traverse (m);
+ instance<bind_member> bm ("value_", "d", vt, "value_type", "value");
+ bm->traverse (m);
os << "}";
}
@@ -1728,9 +919,9 @@ namespace mysql
{
os << "// index" << endl
<< "//" << endl;
- grow_member gm (
- *this, index, "index_", *it, "index_type", "index");
- gm.traverse (m);
+ instance<grow_member> gm (
+ index, "index_", *it, "index_type", "index");
+ gm->traverse (m);
}
break;
}
@@ -1739,8 +930,8 @@ namespace mysql
{
os << "// key" << endl
<< "//" << endl;
- grow_member gm (*this, index, "key_", *kt, "key_type", "key");
- gm.traverse (m);
+ instance<grow_member> gm (index, "key_", *kt, "key_type", "key");
+ gm->traverse (m);
break;
}
case ck_set:
@@ -1752,8 +943,9 @@ namespace mysql
os << "// value" << endl
<< "//" << endl;
- grow_member gm (*this, index, "value_", vt, "value_type", "value");
- gm.traverse (m);
+ instance<grow_member> gm (
+ index, "value_", vt, "value_type", "value");
+ gm->traverse (m);
os << "if (grew)" << endl
<< "i.version++;"
@@ -1785,9 +977,9 @@ namespace mysql
os << "// index" << endl
<< "//" << endl;
- init_image_member im (
- *this, "index_", "j", *it, "index_type", "index");
- im.traverse (m);
+ instance<init_image_member> im (
+ "index_", "j", *it, "index_type", "index");
+ im->traverse (m);
}
break;
@@ -1803,9 +995,9 @@ namespace mysql
<< "// key" << endl
<< "//" << endl;
- init_image_member im (
- *this, "key_", "k", *kt, "key_type", "key");
- im.traverse (m);
+ instance<init_image_member> im (
+ "key_", "k", *kt, "key_type", "key");
+ im->traverse (m);
break;
}
@@ -1823,9 +1015,9 @@ namespace mysql
os << "// value" << endl
<< "//" << endl;
{
- init_image_member im (
- *this, "value_", "v", vt, "value_type", "value");
- im.traverse (m);
+ instance<init_image_member> im (
+ "value_", "v", vt, "value_type", "value");
+ im->traverse (m);
}
os << "if (grew)" << endl
@@ -1857,9 +1049,9 @@ namespace mysql
os << "// index" << endl
<< "//" << endl;
- init_value_member im (
- *this, "index_", "j", *it, "index_type", "index");
- im.traverse (m);
+ instance<init_value_member> im (
+ "index_", "j", *it, "index_type", "index");
+ im->traverse (m);
}
break;
@@ -1875,8 +1067,9 @@ namespace mysql
<< "// key" << endl
<< "//" << endl;
- init_value_member im (*this, "key_", "k", *kt, "key_type", "key");
- im.traverse (m);
+ instance<init_value_member> im (
+ "key_", "k", *kt, "key_type", "key");
+ im->traverse (m);
break;
}
@@ -1898,9 +1091,9 @@ namespace mysql
// If the value is an object pointer, pass the id type as a
// type override.
//
- init_value_member im (
- *this, "value_", "v", vt, "value_type", "value");
- im.traverse (m);
+ instance<init_value_member> im (
+ "value_", "v", vt, "value_type", "value");
+ im->traverse (m);
}
os << "}";
@@ -2277,7 +1470,7 @@ namespace mysql
}
}
- private:
+ protected:
string obj_scope_;
semantics::class_& object_;
semantics::data_member& id_member_;
@@ -2285,10 +1478,12 @@ namespace mysql
// Container statement cache members.
//
- struct container_cache_members: object_members_base, context
+ struct container_cache_members: object_members_base, virtual context
{
- container_cache_members (context& c)
- : object_members_base (c, true, false), context (c)
+ typedef container_cache_members base;
+
+ container_cache_members ()
+ : object_members_base (true, false)
{
}
@@ -2301,10 +1496,12 @@ namespace mysql
}
};
- struct container_cache_init_members: object_members_base, context
+ struct container_cache_init_members: object_members_base, virtual context
{
- container_cache_init_members (context& c)
- : object_members_base (c, true, false), context (c), first_ (true)
+ typedef container_cache_init_members base;
+
+ container_cache_init_members ()
+ : object_members_base (true, false), first_ (true)
{
}
@@ -2324,14 +1521,16 @@ namespace mysql
os << prefix_ << m.name () << " (c)";
}
- private:
+ protected:
bool first_;
};
// Calls for container members.
//
- struct container_calls: object_members_base, context
+ struct container_calls: object_members_base, virtual context
{
+ typedef container_calls base;
+
enum call_type
{
persist_call,
@@ -2340,8 +1539,8 @@ namespace mysql
erase_call
};
- container_calls (context& c, call_type call)
- : object_members_base (c, true, false), context (c), call_ (call)
+ container_calls (call_type call)
+ : object_members_base (true, false), call_ (call)
{
}
@@ -2410,32 +1609,45 @@ namespace mysql
}
}
- private:
+ protected:
call_type call_;
string obj_prefix_;
};
//
//
- struct class_: traversal::class_, context
+ struct class_: traversal::class_, virtual context
{
- class_ (context& c)
- : context (c),
- grow_base_ (c, index_),
- grow_member_ (c, index_),
- bind_base_ (c),
- bind_member_ (c),
- bind_id_member_ (c, "id_"),
- init_image_base_ (c),
- init_image_member_ (c),
- init_id_image_member_ (c, "id_", "id"),
- init_value_base_ (c),
- init_value_member_ (c),
- init_id_value_member_ (c, "id"),
-
- schema_emitter_ (c),
- schema_drop_ (c, schema_emitter_),
- schema_create_ (c, schema_emitter_)
+ typedef class_ base;
+
+ class_ ()
+ : grow_base_ (index_),
+ grow_member_ (index_),
+ bind_id_member_ ("id_"),
+ init_id_image_member_ ("id_", "id"),
+ init_id_value_member_ ("id"),
+ schema_drop_ (schema_emitter_),
+ schema_create_ (schema_emitter_)
+ {
+ init ();
+ }
+
+ class_ (class_ const&)
+ : root_context (), //@@ -Wextra
+ context (),
+ grow_base_ (index_),
+ grow_member_ (index_),
+ bind_id_member_ ("id_"),
+ init_id_image_member_ ("id_", "id"),
+ init_id_value_member_ ("id"),
+ schema_drop_ (schema_emitter_),
+ schema_create_ (schema_emitter_)
+ {
+ init ();
+ }
+
+ void
+ init ()
{
grow_base_inherits_ >> grow_base_;
grow_member_names_ >> grow_member_;
@@ -2450,6 +1662,7 @@ namespace mysql
init_value_member_names_ >> init_value_member_;
}
+
virtual void
traverse (type& c)
{
@@ -2491,15 +1704,15 @@ namespace mysql
os << "struct " << traits << "::container_statement_cache_type"
<< "{";
- container_cache_members cm (*this);
- cm.traverse (c);
+ instance<container_cache_members> cm;
+ cm->traverse (c);
os << (containers ? "\n" : "")
<< "container_statement_cache_type (mysql::connection&" <<
(containers ? " c" : "") << ")";
- container_cache_init_members im (*this);
- im.traverse (c);
+ instance<container_cache_init_members> im;
+ im->traverse (c);
os << "{"
<< "}"
@@ -2510,16 +1723,16 @@ namespace mysql
//
if (containers)
{
- container_traits t (*this, c);
- t.traverse (c);
+ instance<container_traits> t (c);
+ t->traverse (c);
}
// query columns
//
if (options.generate_query ())
{
- query_columns t (*this, c);
- t.traverse (c);
+ instance<query_columns> t (c);
+ t->traverse (c);
}
string const& table (table_name (c));
@@ -2530,8 +1743,8 @@ namespace mysql
<< "\"INSERT INTO `" << table << "` (\"" << endl;
{
- object_columns t (*this, table, false);
- t.traverse (c);
+ instance<object_columns> t (table, false);
+ t->traverse (c);
}
os << "\"" << endl
@@ -2549,17 +1762,18 @@ namespace mysql
<< "\"SELECT \"" << endl;
{
- object_columns t (*this, table, true);
- t.traverse (c);
+ instance<object_columns> t (table, true);
+ t->traverse (c);
}
os << "\"" << endl
<< "\" FROM `" << table << "`\"" << endl;
{
- object_joins t (*this, c, false);
- t.traverse (c);
- t.write ();
+ bool f (false);
+ instance<object_joins> t (c, f); // @@ (im)perfect forwarding
+ t->traverse (c);
+ t->write ();
}
os << "\" WHERE `" << table << "`.`" << column_name (id) << "` = ?\";"
@@ -2571,8 +1785,8 @@ namespace mysql
<< "\"UPDATE `" << table << "` SET \"" << endl;
{
- object_columns t (*this, table, false, " = ?");
- t.traverse (c);
+ instance<object_columns> t (table, false, " = ?");
+ t->traverse (c);
}
os << "\"" << endl
@@ -2590,24 +1804,26 @@ namespace mysql
//
if (options.generate_query ())
{
- object_joins oj (*this, c, true);
- oj.traverse (c);
+ bool t (true);
+ instance<object_joins> oj (c, t); //@@ (im)perfect forwarding
+ oj->traverse (c);
// We only need DISTINCT if there are joins (object pointers)
// and can optimize it out otherwise.
//
os << "const char* const " << traits << "::query_clause =" << endl
- << "\"SELECT " << (oj.count () ? "DISTINCT " : "") << "\"" << endl;
+ << "\"SELECT " << (oj->count () ? "DISTINCT " : "") << "\""
+ << endl;
{
- object_columns oc (*this, table, true);
- oc.traverse (c);
+ instance<object_columns> oc (table, true);
+ oc->traverse (c);
}
os << "\"" << endl
<< "\" FROM `" << table << "`\"" << endl;
- oj.write ();
+ oj->write ();
os << "\" \";"
<< endl;
@@ -2622,7 +1838,7 @@ namespace mysql
<< "id (const image_type& i)"
<< "{"
<< "id_type id;";
- init_id_value_member_.traverse (id);
+ init_id_value_member_->traverse (id);
os << "return id;"
<< "}";
}
@@ -2664,7 +1880,7 @@ namespace mysql
<< "bind (MYSQL_BIND* b, id_image_type& i)"
<< "{"
<< "std::size_t n (0);";
- bind_id_member_.traverse (id);
+ bind_id_member_->traverse (id);
os << "}";
// init (image, object)
@@ -2704,7 +1920,7 @@ namespace mysql
if (grow_id)
os << "bool grew (false);";
- init_id_image_member_.traverse (id);
+ init_id_image_member_->traverse (id);
if (grow_id)
os << endl
@@ -2756,8 +1972,8 @@ namespace mysql
<< "init (i, obj." << id.name () << ");"
<< endl;
- container_calls t (*this, container_calls::persist_call);
- t.traverse (c);
+ instance<container_calls> t (container_calls::persist_call);
+ t->traverse (c);
}
os << "}";
@@ -2805,8 +2021,8 @@ namespace mysql
if (straight_containers)
{
os << endl;
- container_calls t (*this, container_calls::update_call);
- t.traverse (c);
+ instance<container_calls> t (container_calls::update_call);
+ t->traverse (c);
}
os << "}";
@@ -2842,8 +2058,8 @@ namespace mysql
if (straight_containers)
{
os << endl;
- container_calls t (*this, container_calls::erase_call);
- t.traverse (c);
+ instance<container_calls> t (container_calls::erase_call);
+ t->traverse (c);
}
os << "}";
@@ -2992,8 +2208,8 @@ namespace mysql
<< "{"
<< "id_image_type& i (sts.id_image ());"
<< endl;
- container_calls t (*this, container_calls::load_call);
- t.traverse (c);
+ instance<container_calls> t (container_calls::load_call);
+ t->traverse (c);
os << "}";
}
@@ -3079,8 +2295,8 @@ namespace mysql
<< "create_schema (database& db)"
<< "{";
- schema_drop_.traverse (c);
- schema_create_.traverse (c);
+ schema_drop_->traverse (c);
+ schema_create_->traverse (c);
os << "}";
@@ -3174,93 +2390,35 @@ namespace mysql
bool id_;
size_t index_;
- grow_base grow_base_;
+ instance<grow_base> grow_base_;
traversal::inherits grow_base_inherits_;
- grow_member grow_member_;
+ instance<grow_member> grow_member_;
traversal::names grow_member_names_;
- bind_base bind_base_;
+ instance<bind_base> bind_base_;
traversal::inherits bind_base_inherits_;
- bind_member bind_member_;
+ instance<bind_member> bind_member_;
traversal::names bind_member_names_;
- bind_member bind_id_member_;
+ instance<bind_member> bind_id_member_;
- init_image_base init_image_base_;
+ instance<init_image_base> init_image_base_;
traversal::inherits init_image_base_inherits_;
- init_image_member init_image_member_;
+ instance<init_image_member> init_image_member_;
traversal::names init_image_member_names_;
- init_image_member init_id_image_member_;
+ instance<init_image_member> init_id_image_member_;
- init_value_base init_value_base_;
+ instance<init_value_base> init_value_base_;
traversal::inherits init_value_base_inherits_;
- init_value_member init_value_member_;
+ instance<init_value_member> init_value_member_;
traversal::names init_value_member_names_;
- init_value_member init_id_value_member_;
+ instance<init_value_member> init_id_value_member_;
schema_emitter schema_emitter_;
- class_drop schema_drop_;
- class_create schema_create_;
+ instance<schema::class_drop> schema_drop_;
+ instance<schema::class_create> schema_create_;
};
}
-
- void
- generate_source (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/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
- << "#include <odb/mysql/transaction.hxx>" << endl
- << "#include <odb/mysql/connection.hxx>" << endl
- << "#include <odb/mysql/statement.hxx>" << endl
- << "#include <odb/mysql/statement-cache.hxx>" << endl
- << "#include <odb/mysql/object-statements.hxx>" << endl
- << "#include <odb/mysql/container-statements.hxx>" << endl
- << "#include <odb/mysql/exceptions.hxx>" << endl;
-
- if (ctx.options.generate_query ())
- ctx.os << "#include <odb/mysql/result.hxx>" << endl;
-
- ctx.os << endl;
-
- // Details includes.
- //
- ctx.os << "#include <odb/details/unused.hxx>" << endl;
-
- if (ctx.options.generate_query ())
- ctx.os << "#include <odb/details/shared-ptr.hxx>" << endl;
-
- ctx.os << endl;
-
- ctx.os << "namespace odb"
- << "{";
-
- unit.dispatch (ctx.unit);
-
- ctx.os << "}";
- }
}
+
+#endif // ODB_RELATIONAL_SOURCE_HXX
diff --git a/odb/type-processor.cxx b/odb/type-processor.cxx
index 190b102..af6ab3d 100644
--- a/odb/type-processor.cxx
+++ b/odb/type-processor.cxx
@@ -8,8 +8,26 @@
#include <odb/cxx-lexer.hxx>
#include <odb/type-processor.hxx>
+using namespace std;
+
namespace
{
+ // Indirect (dynamic) context values.
+ //
+ static semantics::type*
+ id_tree_type (context& c)
+ {
+ semantics::data_member& id (c.id_member (*c.object));
+ return &id.type ();
+ }
+
+ static string
+ id_column_type (context& c)
+ {
+ semantics::data_member& id (c.id_member (*c.object));
+ return id.get<string> ("ref-column-type");
+ }
+
struct data_member: traversal::data_member, context
{
data_member (context& c)
@@ -408,6 +426,9 @@ namespace
// Process member data.
//
+ m.set ("tree-id-type", &id_tree_type);
+ m.set ("id-column-type", &id_column_type);
+
process_container_value (*vt, m, "value", true);
if (it != 0)
@@ -417,7 +438,7 @@ namespace
process_container_value (*kt, m, "key", false);
// If this is an inverse side of a bidirectional object relationship
- // and it is an ordred container, mark it as unordred since there is
+ // and it is an ordered container, mark it as unordred since there is
// no concept of order in this construct.
//
if (ck == ck_ordered && m.count ("value-inverse"))