summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-11-06 18:05:19 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-11-06 18:05:19 +0200
commitce696c26d2c9dd5a5813fd865082ab19ac49bcfa (patch)
treec44331b2a6e6fa1d9d518ddff63e711ce5d308c4
parent727a83dc82fa094aa91630d165d230a9a2dabe60 (diff)
Add support for container persistence
-rw-r--r--odb/common.cxx159
-rw-r--r--odb/common.hxx89
-rw-r--r--odb/context.cxx194
-rw-r--r--odb/context.hxx125
-rw-r--r--odb/generator.cxx6
-rw-r--r--odb/mysql/common.cxx158
-rw-r--r--odb/mysql/common.hxx138
-rw-r--r--odb/mysql/context.cxx146
-rw-r--r--odb/mysql/context.hxx13
-rw-r--r--odb/mysql/header.cxx573
-rw-r--r--odb/mysql/inline.cxx5
-rw-r--r--odb/mysql/schema.cxx165
-rw-r--r--odb/mysql/source.cxx1558
-rw-r--r--odb/parser.cxx20
-rw-r--r--odb/pragma.cxx107
-rw-r--r--odb/tracer/header.cxx6
-rw-r--r--odb/tracer/inline.cxx4
-rw-r--r--odb/tracer/source.cxx6
-rw-r--r--odb/type-processor.cxx357
19 files changed, 3209 insertions, 620 deletions
diff --git a/odb/common.cxx b/odb/common.cxx
index f398b6e..992b34b 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -8,13 +8,157 @@
using namespace std;
//
+// object_members_base
+//
+
+void object_members_base::
+simple (semantics::data_member&)
+{
+}
+
+void object_members_base::
+composite (semantics::data_member&, semantics::type& t)
+{
+ dispatch (t);
+}
+
+void object_members_base::
+container (semantics::data_member&)
+{
+}
+
+void object_members_base::
+traverse_composite (semantics::data_member& m, semantics::type& t)
+{
+ composite (m, t);
+}
+
+void object_members_base::
+traverse (semantics::class_& c)
+{
+ if (build_table_prefix_ && c.count ("object"))
+ {
+ table_prefix_.prefix = ctx_->table_name (c);
+ table_prefix_.prefix += '_';
+ table_prefix_.level = 1;
+
+ inherits (c);
+ names (c);
+
+ table_prefix_.level = 0;
+ table_prefix_.prefix.clear ();
+ }
+ else
+ {
+ inherits (c);
+ names (c);
+ }
+}
+
+void object_members_base::member::
+traverse (semantics::data_member& m)
+{
+ if (m.count ("transient"))
+ return;
+
+ semantics::type& t (m.type ());
+
+ if (context::comp_value (t))
+ {
+ string old_prefix, old_table_prefix;
+
+ if (om_.build_prefix_)
+ {
+ old_prefix = om_.prefix_;
+ om_.prefix_ += om_.ctx_->public_name (m);
+ om_.prefix_ += '_';
+ }
+
+ if (om_.build_table_prefix_)
+ {
+ old_table_prefix = om_.table_prefix_.prefix;
+
+ // If the user provided a table prefix, then use it verbatim. Also
+ // drop the top-level table prefix in this case.
+ //
+ if (m.count ("table"))
+ {
+ if (om_.table_prefix_.level == 1)
+ om_.table_prefix_.prefix.clear ();
+
+ om_.table_prefix_.prefix += m.get<string> ("table");
+ }
+ // Otherwise use the member name and add an underscore unless it is
+ // already there.
+ //
+ else
+ {
+ string name (om_.ctx_->public_name_db (m));
+ size_t n (name.size ());
+
+ om_.table_prefix_.prefix += name;
+
+ if (n != 0 && name[n - 1] != '_')
+ om_.table_prefix_.prefix += '_';
+ }
+
+ om_.table_prefix_.level++;
+ }
+
+ om_.composite (m, t);
+
+ if (om_.build_table_prefix_)
+ {
+ om_.table_prefix_.level--;
+ om_.table_prefix_.prefix = old_table_prefix;
+ }
+
+ if (om_.build_prefix_)
+ om_.prefix_ = old_prefix;
+ }
+ else if (context::container (t))
+ {
+ om_.container (m);
+ }
+ else
+ {
+ om_.simple (m);
+ }
+}
+
+//
// object_columns_base
//
void object_columns_base::
-composite (semantics::data_member& m)
+composite (semantics::data_member&, semantics::type& t)
{
- dispatch (m.type ());
+ dispatch (t);
+}
+
+void object_columns_base::
+traverse_composite (semantics::data_member& m,
+ semantics::type& t,
+ string const& key_prefix,
+ string const& default_name)
+{
+ bool custom (m.count (key_prefix + "-column"));
+ string name (member_.column_name (m, key_prefix, default_name));
+
+ // If the user provided the column prefix, then use it verbatime.
+ // Otherwise, append the underscore, unless it is already there.
+ //
+ member_.prefix_ = name;
+
+ if (!custom)
+ {
+ size_t n (name.size ());
+
+ if (n != 0 && name[n - 1] != '_')
+ member_.prefix_ += '_';
+ }
+
+ composite (m, t);
}
void object_columns_base::
@@ -30,7 +174,9 @@ traverse (semantics::data_member& m)
if (m.count ("transient"))
return;
- if (comp_value (m.type ()))
+ semantics::type& t (m.type ());
+
+ if (comp_value (t))
{
string old_prefix (prefix_);
@@ -50,10 +196,15 @@ traverse (semantics::data_member& m)
prefix_ += '_';
}
- oc_.composite (m);
+ oc_.composite (m, t);
prefix_ = old_prefix;
}
+ else if (container (t))
+ {
+ // Container gets its own table, so nothing to do here.
+ //
+ }
else
{
oc_.column (m, prefix_ + column_name (m), first_);
diff --git a/odb/common.hxx b/odb/common.hxx
index dcfe87f..3811ea9 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -11,57 +11,96 @@
#include <odb/context.hxx>
-// Find id member.
+// Traverse object members recursively by going into composite members.
//
-struct id_member: traversal::class_
+struct object_members_base: traversal::class_
{
- id_member ()
+ virtual void
+ simple (semantics::data_member&);
+
+ // If you override this function, call the base if you want the composite
+ // to be recursively traversed. The second argument is the actual composite
+ // type, which is not necessarily the same as m.type() in case of
+ // traverse_composite().
+ //
+ virtual void
+ composite (semantics::data_member& m, semantics::type& t);
+
+ virtual void
+ container (semantics::data_member&);
+
+public:
+ object_members_base ()
+ : ctx_ (0),
+ build_prefix_ (false),
+ build_table_prefix_ (false),
+ member_ (*this)
{
*this >> names_ >> member_;
+ *this >> inherits_ >> *this;
}
- semantics::data_member*
- member () const
+ 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)
{
- return member_.m_;
+ *this >> names_ >> member_;
+ *this >> inherits_ >> *this;
}
virtual void
- traverse (semantics::class_& c)
- {
- member_.m_ = 0;
- names (c);
- }
+ traverse (semantics::class_&);
+
+ virtual void
+ traverse_composite (semantics::data_member&, semantics::type&);
+
+protected:
+ std::string prefix_;
+ context::table_prefix table_prefix_;
private:
- struct data_member: traversal::data_member
+ struct member: traversal::data_member
{
- virtual void
- traverse (semantics::data_member& m)
+ member (object_members_base& om)
+ : om_ (om)
{
- if (m.count ("id"))
- m_ = &m;
}
- semantics::data_member* m_;
+ virtual void
+ traverse (semantics::data_member&);
+
+ public:
+ object_members_base& om_;
};
- data_member member_;
+ context* ctx_;
+ bool build_prefix_;
+ bool build_table_prefix_;
+
+ member member_;
traversal::names names_;
+ traversal::inherits inherits_;
};
-// Traverse object columns.
+// Traverse object columns recursively by going into composite members.
//
struct object_columns_base: traversal::class_
{
virtual void
column (semantics::data_member&, std::string const& name, bool first) = 0;
- // If you override this callback, always call the base.
+ // If you override this function, always call the base. The second argument
+ // is the actual composite type, which is not necessarily the same as
+ // m.type ().
//
virtual void
- composite (semantics::data_member&);
+ composite (semantics::data_member& m, semantics::type& t);
+public:
object_columns_base (context& c)
: member_ (c, *this)
{
@@ -72,6 +111,12 @@ struct object_columns_base: traversal::class_
virtual void
traverse (semantics::class_&);
+ virtual void
+ traverse_composite (semantics::data_member&,
+ semantics::type&,
+ std::string const& key_prefix,
+ std::string const& default_name);
+
private:
struct member: traversal::data_member, context
{
@@ -83,7 +128,7 @@ private:
virtual void
traverse (semantics::data_member&);
- private:
+ public:
object_columns_base& oc_;
string prefix_;
diff --git a/odb/context.cxx b/odb/context.cxx
index 1eb597f..552bc28 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -4,6 +4,7 @@
// license : GNU GPL v3; see accompanying LICENSE file
#include <odb/context.hxx>
+#include <odb/common.hxx>
using namespace std;
@@ -119,30 +120,8 @@ context::
{
}
-static string
-public_name_impl (semantics::data_member& m)
-{
- string s (m.name ());
- size_t n (s.size ());
-
- // Do basic processing: remove trailing and leading underscores
- // as well as the 'm_' prefix.
- //
- // @@ What if the resulting names conflict?
- //
- size_t b (0), e (n - 1);
-
- if (n > 2 && s[0] == 'm' && s[1] == '_')
- b += 2;
-
- for (; b <= e && s[b] == '_'; b++) ;
- for (; e >= b && s[e] == '_'; e--) ;
-
- return b > e ? s : string (s, b, e - b + 1);
-}
-
string context::
-table_name (semantics::type& t) const
+table_name (semantics::class_& t) const
{
if (t.count ("table"))
return t.get<string> ("table");
@@ -151,40 +130,89 @@ table_name (semantics::type& t) const
}
string context::
-column_name (semantics::data_member& m) const
+table_name (semantics::data_member& m, table_prefix const& p) const
{
- return m.count ("column") ? m.get<string> ("column") : public_name_impl (m);
+ // If a custom table name was specified, then ignore the top-level
+ // table prefix.
+ //
+ if (m.count ("table"))
+ {
+ string const& name (m.get<string> ("table"));
+ return p.level == 1 ? name : p.prefix + name;
+ }
+
+ return p.prefix + public_name_db (m);
}
string context::
-column_type (semantics::data_member& m) const
+column_name (semantics::data_member& m) const
{
- return m.get<string> ("column-type");
+ return m.count ("column") ? m.get<string> ("column") : public_name_db (m);
}
string context::
-column_type_impl (semantics::data_member& m) const
+column_name (semantics::data_member& m, string const& p, string const& d) const
{
- if (m.count ("type"))
- return m.get<string> ("type");
+ string key (p + "-column");
+ return m.count (key) ? m.get<string> (key) : d;
+}
- semantics::type& t (m.type ());
+string context::
+column_type (semantics::data_member& m, string const& kp) const
+{
+ return kp.empty ()
+ ? m.get<string> ("column-type")
+ : m.get<string> (kp + "-column-type");
+}
- if (t.count ("type"))
- return t.get<string> ("type");
+string context::data::
+column_type_impl (semantics::type& t,
+ string const& type,
+ semantics::context* ctx) const
+{
+ if (!type.empty ())
+ return type;
// Don't use the name hint here so that we get the primary name (e.g.,
// ::std::string) instead of a user typedef (e.g., my_string).
//
string const& name (t.fq_name ());
- type_map_type::const_iterator i (data_->type_map_.find (name));
+ type_map_type::const_iterator i (type_map_.find (name));
- if (i != data_->type_map_.end ())
- return m.count ("id") ? i->second.id_type : i->second.type;
+ if (i != type_map_.end ())
+ return ctx != 0 && ctx->count ("id") ? i->second.id_type : i->second.type;
return string ();
}
+static string
+public_name_impl (semantics::data_member& m)
+{
+ string s (m.name ());
+ size_t n (s.size ());
+
+ // Do basic processing: remove trailing and leading underscores
+ // as well as the 'm_' prefix.
+ //
+ // @@ What if the resulting names conflict?
+ //
+ size_t b (0), e (n - 1);
+
+ if (n > 2 && s[0] == 'm' && s[1] == '_')
+ b += 2;
+
+ for (; b <= e && s[b] == '_'; b++) ;
+ for (; e >= b && s[e] == '_'; e--) ;
+
+ return b > e ? s : string (s, b, e - b + 1);
+}
+
+string context::
+public_name_db (semantics::data_member& m) const
+{
+ return public_name_impl (m);
+}
+
string context::
public_name (semantics::data_member& m) const
{
@@ -267,72 +295,96 @@ escape (string const& name) const
namespace
{
- struct column_count_impl: traversal::class_
+ struct column_count_impl: object_members_base
{
column_count_impl ()
- : member_ (*this)
- {
- *this >> names_ >> member_;
- *this >> inherits_ >> *this;
- }
-
- size_t
- count () const
+ : count_ (0)
{
- return member_.count_;
}
virtual void
traverse (semantics::class_& c)
{
if (c.count ("column-count"))
- member_.count_ += c.get<size_t> ("column-count");
+ count_ += c.get<size_t> ("column-count");
else
{
- size_t n (member_.count_);
- inherits (c);
- names (c);
- c.set ("column-count", member_.count_ - n);
+ size_t n (count_);
+ object_members_base::traverse (c);
+ c.set ("column-count", count_ - n);
}
}
+ virtual void
+ simple (semantics::data_member&)
+ {
+ count_++;
+ }
+
private:
- struct member: traversal::data_member
+ size_t count_;
+ };
+}
+
+size_t context::
+column_count (semantics::class_& c)
+{
+ if (!c.count ("column-count"))
+ {
+ column_count_impl t;
+ t.traverse (c);
+ }
+
+ return c.get<size_t> ("column-count");
+}
+
+namespace
+{
+ // Find id member.
+ //
+ struct id_member_impl: traversal::class_
+ {
+ id_member_impl ()
+ {
+ *this >> names_ >> member_;
+ }
+
+ virtual void
+ traverse (semantics::class_& c)
{
- member (column_count_impl& cc): count_ (0), cc_ (cc) {}
+ member_.m_ = 0;
+ names (c);
+ c.set ("id-member", member_.m_);
+ }
+ private:
+ struct member: traversal::data_member
+ {
virtual void
traverse (semantics::data_member& m)
{
- if (m.count ("transient"))
- return;
-
- if (context::comp_value (m.type ()))
- cc_.dispatch (m.type ());
- else
- count_++;
+ if (m.count ("id"))
+ m_ = &m;
}
- size_t count_;
- column_count_impl& cc_;
+ semantics::data_member* m_;
};
member member_;
traversal::names names_;
-
- traversal::inherits inherits_;
};
}
-size_t context::
-column_count (semantics::class_& c)
+semantics::data_member& context::
+id_member (semantics::class_& c)
{
- if (c.count ("column-count"))
- return c.get<size_t> ("column-count");
+ if (!c.count ("id-member"))
+ {
+ id_member_impl t;
+ t.traverse (c);
+ }
- column_count_impl t;
- t.traverse (c);
- return t.count ();
+ return *c.get<semantics::data_member*> ("id-member");
}
// namespace
diff --git a/odb/context.hxx b/odb/context.hxx
index 1a1595d..7fe392b 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -25,6 +25,17 @@ using std::cerr;
class generation_failed {};
+// Keep this enum synchronized with the one in libodb/odb/container-traits.hxx.
+//
+enum container_kind
+{
+ ck_ordered,
+ ck_set,
+ ck_multiset,
+ ck_map,
+ ck_multimap
+};
+
class context
{
public:
@@ -37,8 +48,9 @@ public:
public:
// Composite value type is a class type that was explicitly marked
- // as value type and there was no SQL type mapping provided for it
- // by the user (specifying the SQL type makes the value type simple).
+ // as value type and there was no database type mapping provided for
+ // it by the user (specifying the database type makes the value type
+ // simple).
//
static bool
comp_value (semantics::class_& c)
@@ -56,22 +68,62 @@ public:
return c != 0 && t.count ("value") && !t.count ("type") ? c : 0;
}
+ static bool
+ container (semantics::type& t)
+ {
+ return t.count ("container-kind");
+ }
+
// Database names and types.
//
public:
string
- table_name (semantics::type&) const;
+ table_name (semantics::class_&) const;
+
+ // Table name for the container member.
+ //
+ struct table_prefix
+ {
+ string prefix;
+ size_t level;
+ };
+
+ string
+ table_name (semantics::data_member&, table_prefix const&) const;
string
column_name (semantics::data_member&) const;
+ string
+ column_name (semantics::data_member&,
+ string const& key_prefix,
+ string const& default_name) const;
+
virtual string
- column_type (semantics::data_member&) const;
+ column_type (semantics::data_member&,
+ string const& key_prefix = string ()) const;
+
+ // Return empty string if there is no mapping. The second argument
+ // is the custom type or empty string if it is not specified.
+ //
+ string
+ column_type_impl (semantics::type& t,
+ string const& type,
+ semantics::context* ctx) const
+ {
+ return data_->column_type_impl (t, type, ctx);
+ }
+
+ // Cleaned-up member name that can be used for database names.
+ //
+ string
+ public_name_db (semantics::data_member&) const;
// C++ names.
//
public:
- // Cleaned-up member name that can be used in public interfaces.
+ // Cleaned-up and escaped member name that can be used in public C++
+ // interfaces.
//
string
public_name (semantics::data_member&) const;
@@ -87,13 +139,58 @@ public:
static size_t
column_count (semantics::class_&);
- // Per-database customizable functionality.
+ semantics::data_member&
+ id_member (semantics::class_&);
+
+ // Container information.
//
public:
- // Return empty string if there is no mapping.
- //
- virtual string
- column_type_impl (semantics::data_member&) const;
+ typedef ::container_kind container_kind_type;
+
+ static container_kind_type
+ container_kind (semantics::type& c)
+ {
+ return c.get<container_kind_type> ("container-kind");
+ }
+
+ static semantics::type&
+ container_vt (semantics::type& c)
+ {
+ return *c.get<semantics::type*> ("tree-value-type");
+ }
+
+ static string
+ container_fq_vt (semantics::data_member& m)
+ {
+ return "container_traits< " + m.type ().fq_name (m.belongs ().hint ()) +
+ " >::value_type";
+ }
+
+ static semantics::type&
+ container_it (semantics::type& c)
+ {
+ return *c.get<semantics::type*> ("tree-index-type");
+ }
+
+ static string
+ container_fq_it (semantics::data_member& m)
+ {
+ return "container_traits< " + m.type ().fq_name (m.belongs ().hint ()) +
+ " >::index_type";
+ }
+
+ static semantics::type&
+ container_kt (semantics::type& c)
+ {
+ return *c.get<semantics::type*> ("tree-key-type");
+ }
+
+ static string
+ container_fq_kt (semantics::data_member& m)
+ {
+ return "container_traits< " + m.type ().fq_name (m.belongs ().hint ()) +
+ " >::key_type";
+ }
protected:
struct data;
@@ -127,6 +224,14 @@ protected:
{
virtual ~data () {}
+ // Per-database customizable functionality.
+ //
+ public:
+ virtual string
+ column_type_impl (semantics::type&,
+ string const& type,
+ semantics::context*) const;
+
keyword_set_type keyword_set_;
type_map_type type_map_;
};
diff --git a/odb/generator.cxx b/odb/generator.cxx
index be01886..343154d 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -421,10 +421,10 @@ generate (options const& ops, semantics::unit& unit, path const& p)
<< "//" << endl;
append (cxx, ops.cxx_epilogue (), ops.cxx_epilogue_file ());
cxx << "//" << endl
- << "// End epilogue." << endl;
-
- cxx << "#include <odb/post.hxx>" << endl
+ << "// End epilogue." << endl
<< endl;
+
+ cxx << "#include <odb/post.hxx>" << endl;
}
// SQL
diff --git a/odb/mysql/common.cxx b/odb/mysql/common.cxx
index 372d08e..17cae9e 100644
--- a/odb/mysql/common.cxx
+++ b/odb/mysql/common.cxx
@@ -11,29 +11,47 @@ using namespace std;
namespace mysql
{
+ //
+ // member_base
+ //
+
void member_base::
- traverse (type& m)
+ traverse (semantics::data_member& m)
{
- if (m.count ("transient") || (id_ && !m.count ("id")))
+ if (m.count ("transient"))
return;
- if (id_)
- var = "id_";
+ string var;
+
+ if (!var_override_.empty ())
+ var = var_override_;
else
{
string const& name (m.name ());
var = name + (name[name.size () - 1] == '_' ? "" : "_");
}
- pre (m);
+ semantics::type& t (type_override_ != 0 ? *type_override_ : m.type ());
+
+ member_info mi (m, t, var, fq_type_override_);
- if (comp_value (m.type ()))
- traverse_composite (m);
+ if (comp_value (t))
+ {
+ pre (mi);
+ traverse_composite (mi);
+ }
+ else if (container (t))
+ {
+ pre (mi);
+ traverse_container (mi);
+ }
else
{
- sql_type const& t (db_type (m));
+ sql_type const& st (db_type (m, key_prefix_));
+ mi.st = &st;
+ pre (mi);
- switch (t.type)
+ switch (st.type)
{
// Integral types.
//
@@ -43,7 +61,7 @@ namespace mysql
case sql_type::INT:
case sql_type::BIGINT:
{
- traverse_integer (m, t);
+ traverse_integer (mi);
break;
}
@@ -52,12 +70,12 @@ namespace mysql
case sql_type::FLOAT:
case sql_type::DOUBLE:
{
- traverse_float (m, t);
+ traverse_float (mi);
break;
}
case sql_type::DECIMAL:
{
- traverse_decimal (m, t);
+ traverse_decimal (mi);
break;
}
@@ -69,7 +87,7 @@ namespace mysql
case sql_type::TIMESTAMP:
case sql_type::YEAR:
{
- traverse_date_time (m, t);
+ traverse_date_time (mi);
break;
}
@@ -88,7 +106,7 @@ namespace mysql
// To support this we will need the character encoding
// in sql_type.
//
- traverse_long_string (m, t);
+ traverse_long_string (mi);
break;
}
case sql_type::BINARY:
@@ -97,7 +115,7 @@ namespace mysql
// BINARY's range is always 255 or less from MySQL 5.0.3.
// TINYBLOB can only store up to 255 bytes.
//
- traverse_short_string (m, t);
+ traverse_short_string (mi);
break;
}
case sql_type::VARBINARY:
@@ -105,10 +123,10 @@ namespace mysql
case sql_type::MEDIUMBLOB:
case sql_type::LONGBLOB:
{
- if (t.range && t.range_value <= 255)
- traverse_short_string (m, t);
+ if (st.range && st.range_value <= 255)
+ traverse_short_string (mi);
else
- traverse_long_string (m, t);
+ traverse_long_string (mi);
break;
}
@@ -117,17 +135,17 @@ namespace mysql
//
case sql_type::BIT:
{
- traverse_bit (m, t);
+ traverse_bit (mi);
break;
}
case sql_type::ENUM:
{
- traverse_enum (m, t);
+ traverse_enum (mi);
break;
}
case sql_type::SET:
{
- traverse_set (m, t);
+ traverse_set (mi);
break;
}
case sql_type::invalid:
@@ -138,7 +156,7 @@ namespace mysql
}
}
- post (m);
+ post (mi);
}
//
@@ -164,13 +182,22 @@ namespace mysql
}
member_image_type::
- member_image_type (context& c, bool id)
- : member_base (c, id)
+ 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 (type& m)
+ image_type (semantics::data_member& m)
{
type_.clear ();
member_base::traverse (m);
@@ -178,58 +205,57 @@ namespace mysql
}
void member_image_type::
- traverse_composite (type& m)
+ traverse_composite (member_info& mi)
{
- type_ = "composite_value_traits< " + m.type ().fq_name () +
- " >::image_type";
+ type_ = "composite_value_traits< " + mi.fq_type () + " >::image_type";
}
void member_image_type::
- traverse_integer (type&, sql_type const& t)
+ traverse_integer (member_info& mi)
{
- if (t.unsign)
+ if (mi.st->unsign)
type_ = "unsigned ";
- else if (t.type == sql_type::TINYINT)
+ else if (mi.st->type == sql_type::TINYINT)
type_ = "signed ";
- type_ += integer_types[t.type - sql_type::TINYINT];
+ type_ += integer_types[mi.st->type - sql_type::TINYINT];
}
void member_image_type::
- traverse_float (type&, sql_type const& t)
+ traverse_float (member_info& mi)
{
- type_ = float_types[t.type - sql_type::FLOAT];
+ type_ = float_types[mi.st->type - sql_type::FLOAT];
}
void member_image_type::
- traverse_decimal (type&, sql_type const&)
+ traverse_decimal (member_info&)
{
type_ = "details::buffer";
}
void member_image_type::
- traverse_date_time (type&, sql_type const& t)
+ traverse_date_time (member_info& mi)
{
- if (t.type == sql_type::YEAR)
+ if (mi.st->type == sql_type::YEAR)
type_ = "short";
else
type_ = "MYSQL_TIME";
}
void member_image_type::
- traverse_string (type&, sql_type const&)
+ traverse_string (member_info&)
{
type_ = "details::buffer";
}
void member_image_type::
- traverse_bit (type&, sql_type const&)
+ traverse_bit (member_info&)
{
type_ = "unsigned char*";
}
void member_image_type::
- traverse_enum (type&, sql_type const&)
+ traverse_enum (member_info&)
{
// Represented as string.
//
@@ -237,7 +263,7 @@ namespace mysql
}
void member_image_type::
- traverse_set (type&, sql_type const&)
+ traverse_set (member_info&)
{
// Represented as string.
//
@@ -298,7 +324,16 @@ namespace mysql
member_database_type::
member_database_type (context& c)
- : member_base (c, false)
+ : 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)
{
}
@@ -311,56 +346,59 @@ namespace mysql
}
void member_database_type::
- traverse_composite (type&)
+ traverse_composite (member_info&)
{
assert (false);
}
void member_database_type::
- traverse_integer (type&, sql_type const& t)
+ traverse_integer (member_info& mi)
{
- size_t i ((t.type - sql_type::TINYINT) * 2 + (t.unsign ? 1 : 0));
+ 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 (type&, sql_type const& t)
+ traverse_float (member_info& mi)
{
- type_ = string ("mysql::") + float_database_id[t.type - sql_type::FLOAT];
+ type_ = string ("mysql::") +
+ float_database_id[mi.st->type - sql_type::FLOAT];
}
void member_database_type::
- traverse_decimal (type&, sql_type const&)
+ traverse_decimal (member_info&)
{
type_ = "mysql::id_decimal";
}
void member_database_type::
- traverse_date_time (type&, sql_type const& t)
+ traverse_date_time (member_info& mi)
{
- type_ = string ("mysql::") + date_time_database_id[t.type - sql_type::DATE];
+ type_ = string ("mysql::") +
+ date_time_database_id[mi.st->type - sql_type::DATE];
}
void member_database_type::
- traverse_string (type&, sql_type const& t)
+ traverse_string (member_info& mi)
{
- type_ = string ("mysql::") + char_bin_database_id[t.type - sql_type::CHAR];
+ type_ = string ("mysql::") +
+ char_bin_database_id[mi.st->type - sql_type::CHAR];
}
void member_database_type::
- traverse_bit (type&, sql_type const&)
+ traverse_bit (member_info&)
{
type_ = "mysql::id_bit";
}
void member_database_type::
- traverse_enum (type&, sql_type const&)
+ traverse_enum (member_info&)
{
type_ = "mysql::id_enum";
}
void member_database_type::
- traverse_set (type&, sql_type const&)
+ traverse_set (member_info&)
{
type_ = "mysql::id_set";
}
@@ -374,7 +412,7 @@ namespace mysql
: object_columns_base (c),
context (c),
decl_ (true),
- member_image_type_ (c, false),
+ member_image_type_ (c),
member_database_type_ (c)
{
}
@@ -384,7 +422,7 @@ namespace mysql
: object_columns_base (c),
context (c),
decl_ (false),
- member_image_type_ (c, false),
+ member_image_type_ (c),
member_database_type_ (c)
{
scope_ = "access::object_traits< " + cl.fq_name () + " >::query_type";
@@ -392,7 +430,7 @@ namespace mysql
}
void query_columns::
- composite (semantics::data_member& m)
+ composite (semantics::data_member& m, semantics::type& t)
{
string name (public_name (m));
@@ -403,7 +441,7 @@ namespace mysql
<< "struct " << name
<< "{";
- object_columns_base::composite (m);
+ object_columns_base::composite (m, t);
os << "};";
}
@@ -412,7 +450,7 @@ namespace mysql
string old_scope (scope_);
scope_ += "::" + name;
- object_columns_base::composite (m);
+ object_columns_base::composite (m, t);
scope_ = old_scope;
}
diff --git a/odb/mysql/common.hxx b/odb/mysql/common.hxx
index 83fa998..31c6962 100644
--- a/odb/mysql/common.hxx
+++ b/odb/mysql/common.hxx
@@ -13,119 +13,170 @@ namespace mysql
{
struct member_base: traversal::data_member, context
{
- member_base (context& c, bool id)
- : context (c), id_ (id)
+ 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 (type& m);
+ 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
+ {
+ return fq_type_.empty () ? t.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)
+ {
+ }
+ };
+
+ virtual void
+ pre (member_info&)
+ {
+ }
virtual void
- pre (type&)
+ post (member_info&)
{
}
virtual void
- post (type&)
+ traverse_composite (member_info&)
{
}
virtual void
- traverse_composite (type&)
+ traverse_container (member_info&)
{
}
virtual void
- traverse_integer (type&, sql_type const&)
+ traverse_integer (member_info&)
{
}
virtual void
- traverse_float (type&, sql_type const&)
+ traverse_float (member_info&)
{
}
virtual void
- traverse_decimal (type&, sql_type const&)
+ traverse_decimal (member_info&)
{
}
virtual void
- traverse_date_time (type&, sql_type const&)
+ traverse_date_time (member_info&)
{
}
virtual void
- traverse_string (type&, sql_type const&)
+ traverse_string (member_info&)
{
}
virtual void
- traverse_short_string (type& t, sql_type const& st)
+ traverse_short_string (member_info& mi)
{
- traverse_string (t, st);
+ traverse_string (mi);
}
virtual void
- traverse_long_string (type& t, sql_type const& st)
+ traverse_long_string (member_info& mi)
{
- traverse_string (t, st);
+ traverse_string (mi);
}
virtual void
- traverse_bit (type&, sql_type const&)
+ traverse_bit (member_info&)
{
}
virtual void
- traverse_enum (type&, sql_type const&)
+ traverse_enum (member_info&)
{
}
virtual void
- traverse_set (type&, sql_type const&)
+ traverse_set (member_info&)
{
}
protected:
- bool id_;
- string var;
+ string var_override_;
+ semantics::type* type_override_;
+ string fq_type_override_;
+ string key_prefix_;
};
struct member_image_type: member_base
{
- member_image_type (context&, bool id);
+ member_image_type (context&);
+
+ member_image_type (context& c,
+ semantics::type& type,
+ string const& fq_type,
+ string const& key_prefix);
string
- image_type (type&);
+ image_type (semantics::data_member&);
virtual void
- traverse_composite (type&);
+ traverse_composite (member_info&);
virtual void
- traverse_integer (type&, sql_type const&);
+ traverse_integer (member_info&);
virtual void
- traverse_float (type&, sql_type const&);
+ traverse_float (member_info&);
virtual void
- traverse_decimal (type&, sql_type const&);
+ traverse_decimal (member_info&);
virtual void
- traverse_date_time (type&, sql_type const&);
+ traverse_date_time (member_info&);
virtual void
- traverse_string (type&, sql_type const&);
+ traverse_string (member_info&);
virtual void
- traverse_bit (type&, sql_type const&);
+ traverse_bit (member_info&);
virtual void
- traverse_enum (type&, sql_type const&);
+ traverse_enum (member_info&);
virtual void
- traverse_set (type&, sql_type const&);
+ traverse_set (member_info&);
private:
string type_;
@@ -135,35 +186,40 @@ namespace mysql
{
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 (type&);
+ traverse_composite (member_info&);
virtual void
- traverse_integer (type&, sql_type const&);
+ traverse_integer (member_info&);
virtual void
- traverse_float (type&, sql_type const&);
+ traverse_float (member_info&);
virtual void
- traverse_decimal (type&, sql_type const&);
+ traverse_decimal (member_info&);
virtual void
- traverse_date_time (type&, sql_type const&);
+ traverse_date_time (member_info&);
virtual void
- traverse_string (type&, sql_type const&);
+ traverse_string (member_info&);
virtual void
- traverse_bit (type&, sql_type const&);
+ traverse_bit (member_info&);
virtual void
- traverse_enum (type&, sql_type const&);
+ traverse_enum (member_info&);
virtual void
- traverse_set (type&, sql_type const&);
+ traverse_set (member_info&);
private:
string type_;
@@ -175,7 +231,7 @@ namespace mysql
query_columns (context&, semantics::class_&);
virtual void
- composite (semantics::data_member&);
+ composite (semantics::data_member&, semantics::type&);
virtual void
column (semantics::data_member&, string const&, bool);
diff --git a/odb/mysql/context.cxx b/odb/mysql/context.cxx
index e896f68..4803da2 100644
--- a/odb/mysql/context.cxx
+++ b/odb/mysql/context.cxx
@@ -81,18 +81,16 @@ namespace mysql
{
struct has_grow: traversal::class_
{
- has_grow (context& c)
- : member_ (c, *this)
+ has_grow ()
{
- *this >> member_names_ >> member_;
*this >> inherits_ >> *this;
}
bool
- dispatch (semantics::type& t)
+ dispatch (type& c)
{
r_ = false;
- traversal::class_::dispatch (t);
+ traverse (c);
return r_;
}
@@ -115,57 +113,74 @@ namespace mysql
}
private:
- struct member: member_base
- {
- member (context& c, has_grow& hg) : member_base (c, false), hg_ (hg) {}
+ friend class has_grow_member;
- virtual void
- traverse_composite (type& m)
- {
- if (!hg_.r_)
- hg_.r_ = hg_.dispatch (m.type ());
- }
+ bool r_;
+ traversal::inherits inherits_;
+ };
- virtual void
- traverse_decimal (type&, sql_type const&)
- {
- hg_.r_ = true;
- }
+ struct has_grow_member: member_base
+ {
+ has_grow_member (context& c, has_grow& hg)
+ : member_base (c), hg_ (hg)
+ {
+ }
- virtual void
- traverse_long_string (type&, sql_type const&)
- {
- hg_.r_ = true;
- }
+ has_grow_member (context& c,
+ has_grow& hg,
+ semantics::type& type,
+ string const& key_prefix)
+ : member_base (c, "", type, "", key_prefix), hg_ (hg)
+ {
+ }
- virtual void
- traverse_short_string (type&, sql_type const&)
- {
- hg_.r_ = true; // @@ Short string optimization disabled.
- }
+ bool
+ dispatch (semantics::data_member& m)
+ {
+ hg_.r_ = false;
+ member_base::traverse (m);
+ return hg_.r_;
+ }
- virtual void
- traverse_enum (type&, sql_type const&)
- {
- hg_.r_ = true;
- }
+ virtual void
+ traverse_composite (member_info& mi)
+ {
+ if (!hg_.r_)
+ hg_.r_ = hg_.dispatch (dynamic_cast<semantics::class_&> (mi.t));
+ }
- virtual void
- traverse_set (type&, sql_type const&)
- {
- hg_.r_ = true;
- }
+ virtual void
+ traverse_decimal (member_info&)
+ {
+ hg_.r_ = true;
+ }
- private:
- has_grow& hg_;
- };
+ virtual void
+ traverse_long_string (member_info&)
+ {
+ hg_.r_ = true;
+ }
- bool r_;
+ virtual void
+ traverse_short_string (member_info&)
+ {
+ hg_.r_ = true; // @@ Short string optimization disabled.
+ }
- member member_;
- traversal::names member_names_;
+ virtual void
+ traverse_enum (member_info&)
+ {
+ hg_.r_ = true;
+ }
- traversal::inherits inherits_;
+ virtual void
+ traverse_set (member_info&)
+ {
+ hg_.r_ = true;
+ }
+
+ private:
+ has_grow& hg_;
};
}
@@ -175,20 +190,37 @@ namespace mysql
if (c.count ("mysql::grow"))
return c.get<bool> ("mysql::grow");
- has_grow t (*this);
- return t.dispatch (c);
+ has_grow ct;
+ has_grow_member mt (*this, ct);
+ traversal::names names;
+ ct >> names >> mt;
+
+ return ct.dispatch (c);
+ }
+
+ bool context::
+ grow (semantics::data_member& m, semantics::type& t, string const& kp)
+ {
+ has_grow ct;
+ has_grow_member mt (*this, ct, t, kp);
+ traversal::names names;
+ ct >> names >> mt;
+
+ return mt.dispatch (m);
}
//
// SQL type parsing.
//
- string context::
- column_type_impl (semantics::data_member& m) const
+ string context::data::
+ column_type_impl (semantics::type& t,
+ string const& type,
+ semantics::context* ctx) const
{
- string r (::context::column_type_impl (m));
+ string r (::context::data::column_type_impl (t, type, ctx));
- if (m.count ("auto"))
+ if (!r.empty () && ctx != 0 && ctx->count ("auto"))
r += " AUTO_INCREMENT";
return r;
@@ -198,12 +230,14 @@ namespace mysql
parse_sql_type (semantics::data_member& m, std::string const& sql);
sql_type const& context::
- db_type (semantics::data_member& m)
+ db_type (semantics::data_member& m, string const& kp)
{
- if (!m.count ("db-type"))
- m.set ("db-type", parse_sql_type (m, column_type (m)));
+ 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> ("db-type");
+ return m.get<sql_type> (key);
}
static sql_type
diff --git a/odb/mysql/context.hxx b/odb/mysql/context.hxx
index 40facae..9a6beec 100644
--- a/odb/mysql/context.hxx
+++ b/odb/mysql/context.hxx
@@ -86,25 +86,32 @@ namespace mysql
bool
grow (semantics::class_&);
+ // The same for a member's value type.
+ //
+ bool
+ grow (semantics::data_member&, semantics::type&, string const& key_prefix);
+
//
//
public:
sql_type const&
- db_type (semantics::data_member&);
+ 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*) const;
};
private:
data* data_;
public:
- virtual string
- column_type_impl (semantics::data_member&) const;
public:
context (std::ostream&, semantics::unit&, options_type const&);
diff --git a/odb/mysql/header.cxx b/odb/mysql/header.cxx
index 2544ff3..b4781f9 100644
--- a/odb/mysql/header.cxx
+++ b/odb/mysql/header.cxx
@@ -14,46 +14,59 @@ namespace mysql
{
struct image_member: member_base
{
- image_member (context& c, bool id)
- : member_base (c, id), member_image_type_ (c, id)
+ image_member (context& c, string const& var = string ())
+ : member_base (c, var), member_image_type_ (c)
+ {
+ }
+
+ image_member (context& c,
+ 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 void
- pre (type& m)
+ pre (member_info& mi)
{
- image_type = member_image_type_.image_type (m);
+ if (container (mi.t))
+ return;
- if (!id_)
- os << "// " << m.name () << endl
+ image_type = member_image_type_.image_type (mi.m);
+
+ if (var_override_.empty ())
+ os << "// " << mi.m.name () << endl
<< "//" << endl;
}
virtual void
- traverse_composite (type&)
+ traverse_composite (member_info& mi)
{
- os << image_type << " " << var << "value;"
+ os << image_type << " " << mi.var << "value;"
<< endl;
}
virtual void
- traverse_integer (type&, sql_type const&)
+ traverse_integer (member_info& mi)
{
- os << image_type << " " << var << "value;"
- << "my_bool " << var << "null;"
+ os << image_type << " " << mi.var << "value;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
virtual void
- traverse_float (type&, sql_type const&)
+ traverse_float (member_info& mi)
{
- os << image_type << " " << var << "value;"
- << "my_bool " << var << "null;"
+ os << image_type << " " << mi.var << "value;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
virtual void
- traverse_decimal (type&, sql_type const&)
+ 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.
@@ -61,83 +74,83 @@ namespace mysql
/*
@@ Disabled.
- os << "char " << var << "value[" <<
+ os << "char " << mi.var << "value[" <<
(t.range ? t.range_value : 10) + 3 << "];"
*/
- os << image_type << " " << var << "value;"
- << "unsigned long " << var << "size;"
- << "my_bool " << var << "null;"
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
virtual void
- traverse_date_time (type&, sql_type const&)
+ traverse_date_time (member_info& mi)
{
- os << image_type << " " << var << "value;"
- << "my_bool " << var << "null;"
+ os << image_type << " " << mi.var << "value;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
virtual void
- traverse_short_string (type&, sql_type const&)
+ traverse_short_string (member_info& mi)
{
// If range is not specified, the default buffer size is 255.
//
/*
@@ Disabled.
- os << "char " << var << "value[" <<
+ os << "char " << mi.var << "value[" <<
(t.range ? t.range_value : 255) + 1 << "];"
*/
- os << image_type << " " << var << "value;"
- << "unsigned long " << var << "size;"
- << "my_bool " << var << "null;"
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
virtual void
- traverse_long_string (type&, sql_type const&)
+ traverse_long_string (member_info& mi)
{
- os << image_type << " " << var << "value;"
- << "unsigned long " << var << "size;"
- << "my_bool " << var << "null;"
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
virtual void
- traverse_bit (type&, sql_type const& t)
+ traverse_bit (member_info& mi)
{
// Valid range is 1 to 64.
//
- unsigned int n (t.range / 8 + (t.range % 8 ? 1 : 0));
+ unsigned int n (mi.st->range / 8 + (mi.st->range % 8 ? 1 : 0));
- os << "unsigned char " << var << "value[" << n << "];"
- << "unsigned long " << var << "size;"
- << "my_bool " << var << "null;"
+ os << "unsigned char " << mi.var << "value[" << n << "];"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
virtual void
- traverse_enum (type&, sql_type const&)
+ traverse_enum (member_info& mi)
{
// Represented as string.
//
- os << image_type << " " << var << "value;"
- << "unsigned long " << var << "size;"
- << "my_bool " << var << "null;"
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
virtual void
- traverse_set (type&, sql_type const&)
+ traverse_set (member_info& mi)
{
// Represented as string.
//
- os << image_type << " " << var << "value;"
- << "unsigned long " << var << "size;"
- << "my_bool " << var << "null;"
+ os << image_type << " " << mi.var << "value;"
+ << "unsigned long " << mi.var << "size;"
+ << "my_bool " << mi.var << "null;"
<< endl;
}
@@ -175,7 +188,7 @@ namespace mysql
struct image_type: traversal::class_, context
{
image_type (context& c)
- : context (c), member_ (c, false)
+ : context (c), member_ (c)
{
*this >> names_member_ >> member_;
}
@@ -203,36 +216,437 @@ namespace mysql
traversal::names names_member_;
};
- struct id_image_type: traversal::class_, context
+ // Member-specific traits types for container members.
+ //
+ struct container_traits: object_members_base, context
{
- id_image_type (context& c)
- : context (c), image_member_ (c, true)
+ container_traits (context& c)
+ : object_members_base (c, true, false), context (c)
{
- *this >> names_image_member_ >> image_member_;
}
virtual void
- traverse (type& c)
+ container (semantics::data_member& m)
{
- os << "struct id_image_type"
+ using semantics::type;
+ using semantics::class_;
+
+ type& t (m.type ());
+ container_kind_type ck (container_kind (t));
+
+ type& vt (container_vt (t));
+ type* it (0);
+ type* kt (0);
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ it = &container_it (t);
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ kt = &container_kt (t);
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ string name (prefix_ + public_name (m) + "_traits");
+
+ // Figure out column counts.
+ //
+ size_t data_columns (1), cond_columns (1); // One for object id.
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ // Add one for the index.
+ //
+ data_columns++;
+ cond_columns++;
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ // Add some for the key.
+ //
+ size_t n;
+
+ if (class_* kc = comp_value (*kt))
+ n = column_count (*kc);
+ else
+ n = 1;
+
+ data_columns += n;
+ cond_columns += n;
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ // Value is also a key.
+ //
+ if (class_* vc = comp_value (vt))
+ cond_columns += column_count (*vc);
+ else
+ cond_columns++;
+
+ break;
+ }
+ }
+
+ if (class_* vc = comp_value (vt))
+ data_columns += column_count (*vc);
+ else
+ data_columns++;
+
+ // Store column counts for the source generator.
+ //
+ m.set ("cond-column-count", cond_columns);
+ m.set ("data-column-count", data_columns);
+
+ os << "// " << m.name () << endl
+ << "//" << endl
+ << "struct " << name
<< "{";
- names (c);
+ // container_type
+ // index_type
+ // key_type
+ // value_type
+ //
+
+ os << "typedef " << t.fq_name (m.belongs ().hint ()) <<
+ " container_type;";
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "typedef " << container_fq_it (m) << " index_type;";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "typedef " << container_fq_kt (m) << " key_type;";
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ os << "typedef " << container_fq_vt (m) << " value_type;"
+ << endl;
+
+ os << "typedef odb::access::container_traits< container_type > " <<
+ "container_traits;";
+
+ // functions_type
+ //
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "typedef ordered_functions<index_type, value_type> " <<
+ "functions_type;";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "typedef map_functions<key_type, value_type> " <<
+ "functions_type;";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "typedef set_functions<value_type> functions_type;";
+ break;
+ }
+ }
+
+ os << "typedef mysql::container_statements< " << name <<
+ " > statements_type;"
+ << endl;
+
+ // column_count
+ //
+ os << "static const std::size_t cond_column_count = " <<
+ cond_columns << "UL;"
+ << "static const std::size_t data_column_count = " <<
+ data_columns << "UL;"
+ << endl;
+
+ // cond_image_type (object id is taken from the object image)
+ //
+ os << "struct cond_image_type"
+ << "{";
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "// index" << endl
+ << "//" << endl;
+ image_member im (*this, "index_", *it, "index_type", "index");
+ im.traverse (m);
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "// key" << endl
+ << "//" << endl;
+ image_member im (*this, "key_", *kt, "key_type", "key");
+ im.traverse (m);
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "// value" << endl
+ << "//" << endl;
+ image_member im (*this, "value_", vt, "value_type", "value");
+ im.traverse (m);
+ break;
+ }
+ }
os << "};";
- }
- private:
- image_member image_member_;
- traversal::names names_image_member_;
+ // data_image_type (object id is taken from the object image)
+ //
+ os << "struct data_image_type"
+ << "{";
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "// index" << endl
+ << "//" << endl;
+ image_member im (*this, "index_", *it, "index_type", "index");
+ im.traverse (m);
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "// key" << endl
+ << "//" << endl;
+ image_member im (*this, "key_", *kt, "key_type", "key");
+ im.traverse (m);
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ os << "// value" << endl
+ << "//" << endl;
+ image_member im (*this, "value_", vt, "value_type", "value");
+ im.traverse (m);
+
+ os << "};";
+
+ // Statements.
+ //
+ os << "static const char* const insert_one_statement;"
+ << "static const char* const select_all_statement;"
+ << "static const char* const delete_all_statement;"
+ << endl;
+
+ // bind (cond_image)
+ //
+ os << "static void" << endl
+ << "bind (MYSQL_BIND*, id_image_type*, cond_image_type&);"
+ << endl;
+
+ // bind (data_image)
+ //
+ os << "static void" << endl
+ << "bind (MYSQL_BIND*, id_image_type*, data_image_type&);"
+ << endl;
+
+ // grow()
+ //
+ os << "static bool" << endl
+ << "grow (data_image_type&, my_bool*);"
+ << endl;
+
+ // init (data_image)
+ //
+ os << "static bool" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (data_image_type&, index_type, const value_type&);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "init (data_image_type&, const key_type&, const value_type&);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "init (data_image_type&, const value_type&);";
+ break;
+ }
+ }
+
+ os << endl;
+
+ // init (data)
+ //
+ os << "static void" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (index_type&, value_type&, const data_image_type&);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "init (key_type&, value_type&, const data_image_type&);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "init (value_type&, const data_image_type&);";
+ break;
+ }
+ }
+
+ os << endl;
+
+ // insert_one
+ //
+ os << "static void" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "insert_one (index_type, const value_type&, void*);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "insert_one (const key_type&, const value_type&, void*);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "insert_one (const value_type&, void*);";
+ break;
+ }
+ }
+
+ os << endl;
+
+ // load_all
+ //
+ os << "static bool" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "load_all (index_type&, value_type&, void*);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "load_all (key_type&, value_type&, void*);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "load_all (value_type&, void*);";
+ break;
+ }
+ }
+
+ os << endl;
+
+ // delete_all
+ //
+ os << "static void" << endl
+ << "delete_all (void*);"
+ << endl;
+
+ // persist
+ //
+ os << "static void" << endl
+ << "persist (const container_type&," << endl
+ << "id_image_type&," << endl
+ << "bool," << endl
+ << "statements_type&);"
+ << endl;
+
+ // load
+ //
+ os << "static void" << endl
+ << "load (container_type&," << endl
+ << "id_image_type&," << endl
+ << "bool," << endl
+ << "statements_type&);"
+ << endl;
+
+ // update
+ //
+ os << "static void" << endl
+ << "update (const container_type&," << endl
+ << "id_image_type&," << endl
+ << "bool," << endl
+ << "statements_type&);"
+ << endl;
+
+ // erase
+ //
+ os << "static void" << endl
+ << "erase (id_image_type&, bool, statements_type&);"
+ << endl;
+
+ os << "};";
+ }
};
+ //
+ //
struct class_: traversal::class_, context
{
class_ (context& c)
- : context (c),
- image_type_ (c),
- id_image_type_ (c)
+ : context (c), image_type_ (c), id_image_member_ (c, "id_")
{
}
@@ -254,8 +668,7 @@ namespace mysql
string const& type (c.fq_name ());
bool def_ctor (TYPE_HAS_DEFAULT_CONSTRUCTOR (c.tree_node ()));
- id_member_.traverse (c);
- semantics::data_member& id (*id_member_.member ());
+ semantics::data_member& id (id_member (c));
bool auto_id (id.count ("auto"));
os << "// " << c.name () << endl
@@ -284,7 +697,12 @@ namespace mysql
// id_image_type
//
- id_image_type_.traverse (c);
+ os << "struct id_image_type"
+ << "{";
+
+ id_image_member_.traverse (id);
+
+ os << "};";
// query_type & query_base_type
//
@@ -317,7 +735,7 @@ namespace mysql
column_count (c) << "UL;"
<< endl;
- // Queries.
+ // Statements.
//
os << "static const char* const persist_statement;"
<< "static const char* const find_statement;"
@@ -329,6 +747,28 @@ namespace mysql
os << endl;
+ //
+ // Containers.
+ //
+
+ // Traits types.
+ //
+ {
+ // @@ Make it class members?
+ //
+ container_traits t (*this);
+ t.traverse (c);
+ }
+
+ // Statement cache (forward declaration).
+ //
+ os << "struct container_statement_cache_type;"
+ << endl;
+
+ //
+ // Functions.
+ //
+
// id ()
//
os << "static id_type" << endl
@@ -406,7 +846,9 @@ namespace mysql
//
os << "private:" << endl
<< "static bool" << endl
- << "find (mysql::object_statements<object_type>&, const id_type&);";
+ << "find (mysql::object_statements<object_type>&," << endl
+ << "const id_type&," << endl
+ << "bool&);";
os << "};";
}
@@ -461,9 +903,8 @@ namespace mysql
}
private:
- id_member id_member_;
image_type image_type_;
- id_image_type id_image_type_;
+ image_member id_image_member_;
};
}
diff --git a/odb/mysql/inline.cxx b/odb/mysql/inline.cxx
index 47766e2..948caac 100644
--- a/odb/mysql/inline.cxx
+++ b/odb/mysql/inline.cxx
@@ -34,10 +34,7 @@ namespace mysql
{
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
-
- id_member t;
- t.traverse (c);
- semantics::data_member& id (*t.member ());
+ semantics::data_member& id (id_member (c));
os << "// " << c.name () << endl
<< "//" << endl
diff --git a/odb/mysql/schema.cxx b/odb/mysql/schema.cxx
index 3ef412b..1dfeb1f 100644
--- a/odb/mysql/schema.cxx
+++ b/odb/mysql/schema.cxx
@@ -8,10 +8,14 @@
#include <odb/mysql/common.hxx>
#include <odb/mysql/schema.hxx>
+using namespace std;
+
namespace mysql
{
namespace
{
+ typedef set<string> tables;
+
struct object_columns: object_columns_base, context
{
object_columns (context& c)
@@ -32,6 +36,118 @@ namespace mysql
}
};
+ struct member_create: object_members_base, context
+ {
+ member_create (context& c, semantics::class_& object, tables& t)
+ : object_members_base (c, false, true),
+ context (c),
+ object_ (object),
+ id_member_ (id_member (object)),
+ tables_ (t)
+ {
+ }
+
+ virtual void
+ container (semantics::data_member& m)
+ {
+ using semantics::type;
+ using semantics::data_member;
+
+ type& t (m.type ());
+ container_kind_type ck (container_kind (t));
+ type& vt (container_vt (t));
+
+ string const& name (table_name (m, table_prefix_));
+
+ if (tables_.count (name))
+ return;
+
+ os << "CREATE TABLE `" << name << "` (" << endl;
+
+ // object_id (simple value)
+ //
+ string id_name (column_name (m, "id", "object_id"));
+ os << " `" << id_name << "` " << column_type (id_member_);
+
+ // index (simple value)
+ //
+ string index_name;
+ if (ck == ck_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 (comp_value (kt))
+ {
+ object_columns oc (*this);
+ oc.traverse_composite (m, kt, "key", "key");
+ }
+ else
+ {
+ string const& name (column_name (m, "key", "key"));
+ os << " `" << name << "` " << column_type (m, "key");
+ }
+ }
+
+ // value (simple or composite value)
+ //
+ {
+ os << "," << endl;
+
+ if (comp_value (vt))
+ {
+ object_columns oc (*this);
+ oc.traverse_composite (m, vt, "value", "value");
+ }
+ else
+ {
+ string const& name (column_name (m, "value", "value"));
+ os << " `" << name << "` " << column_type (m, "value");
+ }
+ }
+
+ // object_id index
+ //
+ os << "," << endl
+ << " INDEX (`" << id_name << "`)";
+
+ // index index
+ //
+ if (ck == ck_ordered)
+ os << "," << endl
+ << " INDEX (`" << index_name << "`)";
+
+ os << ")";
+
+ string const& engine (options.mysql_engine ());
+
+ if (engine != "default")
+ os << endl
+ << " ENGINE=" << engine;
+
+ os << ";" << endl
+ << endl;
+
+ tables_.insert (name);
+ }
+
+ private:
+ semantics::class_& object_;
+ semantics::data_member& id_member_;
+ tables& tables_;
+ };
+
struct class_create: traversal::class_, context
{
class_create (context& c)
@@ -59,8 +175,8 @@ namespace mysql
os << "CREATE TABLE `" << name << "` (" << endl;
{
- object_columns t (*this);
- t.traverse (c);
+ object_columns oc (*this);
+ oc.traverse (c);
}
os << ")";
@@ -74,11 +190,45 @@ namespace mysql
os << ";" << endl
<< endl;
+ // Create tables for members.
+ //
+ {
+ member_create mc (*this, c, tables_);
+ mc.traverse (c);
+ }
+
tables_.insert (name);
}
private:
- std::set<string> tables_;
+ tables tables_;
+ };
+
+ struct member_drop: object_members_base, context
+ {
+ member_drop (context& c, semantics::class_& object, tables& t)
+ : object_members_base (c, false, true),
+ context (c),
+ object_ (object),
+ tables_ (t)
+ {
+ }
+
+ virtual void
+ container (semantics::data_member& m)
+ {
+ string const& name (table_name (m, table_prefix_));
+
+ if (tables_.count (name))
+ return;
+
+ os << "DROP TABLE IF EXISTS `" << name << "`;" << endl;
+ tables_.insert (name);
+ }
+
+ private:
+ semantics::class_& object_;
+ tables& tables_;
};
struct class_drop: traversal::class_, context
@@ -104,11 +254,18 @@ namespace mysql
os << "DROP TABLE IF EXISTS `" << name << "`;" << endl;
+ // Drop tables for members.
+ //
+ {
+ member_drop mc (*this, c, tables_);
+ mc.traverse (c);
+ }
+
tables_.insert (name);
}
private:
- std::set<string> tables_;
+ tables tables_;
};
static char const file_header[] =
diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx
index d572560..29495df 100644
--- a/odb/mysql/source.cxx
+++ b/odb/mysql/source.cxx
@@ -18,21 +18,33 @@ namespace mysql
{
struct object_columns: object_columns_base, context
{
- object_columns (context& c, string const& suffix = "")
- : object_columns_base (c), context (c), suffix_ (suffix)
+ object_columns (context& c, char const* suffix = "")
+ : object_columns_base (c),
+ context (c),
+ first_ (true),
+ suffix_ (suffix)
+ {
+ }
+
+ object_columns (context& c, bool first, char const* suffix = "")
+ : object_columns_base (c),
+ context (c),
+ first_ (first),
+ suffix_ (suffix)
{
}
virtual void
column (semantics::data_member&, string const& name, bool first)
{
- if (!first)
+ if (!first || !first_)
os << ",\"" << endl;
os << "\"`" << name << "`" << suffix_;
}
private:
+ bool first_;
string suffix_;
};
@@ -82,43 +94,66 @@ namespace mysql
struct bind_member: member_base
{
- bind_member (context& c, size_t& index, bool id)
- : member_base (c, id), index_ (index)
+ bind_member (context& c,
+ size_t& index,
+ string const& var = string (),
+ string const& arg = string ())
+ : member_base (c, var), index_ (index), arg_override_ (arg)
+ {
+ }
+
+ bind_member (context& c,
+ size_t& index,
+ 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),
+ index_ (index),
+ arg_override_ (arg)
{
}
virtual void
- pre (type& m)
+ pre (member_info& mi)
{
+ if (container (mi.t))
+ return;
+
ostringstream ostr;
ostr << "b[" << index_ << "UL]";
b = ostr.str ();
- if (!id_)
- os << "// " << m.name () << endl
+ arg = arg_override_.empty () ? string ("i") : arg_override_;
+
+ if (var_override_.empty ())
+ os << "// " << mi.m.name () << endl
<< "//" << endl;
}
virtual void
- post (type& m)
+ post (member_info& mi)
{
- if (semantics::class_* c = comp_value (m.type ()))
+ if (container (mi.t))
+ return;
+ else if (semantics::class_* c = comp_value (mi.t))
index_ += column_count (*c);
else
index_++;
}
virtual void
- traverse_composite (type& m)
+ traverse_composite (member_info& mi)
{
- os << "composite_value_traits< " << m.type ().fq_name () <<
+ os << "composite_value_traits< " << mi.fq_type () <<
" >::bind (" << endl
- << "b + " << index_ << "UL, i." << var << "value);"
+ << "b + " << index_ << "UL, " << arg << "." << mi.var << "value);"
<< endl;
}
virtual void
- traverse_integer (type&, sql_type const& t)
+ traverse_integer (member_info& mi)
{
// While the is_unsigned should indicate whether the
// buffer variable is unsigned, rather than whether the
@@ -126,51 +161,51 @@ namespace mysql
// this is the same.
//
os << b << ".buffer_type = " <<
- integer_buffer_types[t.type - sql_type::TINYINT] << ";"
- << b << ".is_unsigned = " << (t.unsign ? "1" : "0") << ";"
- << b << ".buffer = &i." << var << "value;"
- << b << ".is_null = &i." << var << "null;"
+ 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;"
<< endl;
}
virtual void
- traverse_float (type&, sql_type const& t)
+ traverse_float (member_info& mi)
{
os << b << ".buffer_type = " <<
- float_buffer_types[t.type - sql_type::FLOAT] << ";"
- << b << ".buffer = &i." << var << "value;"
- << b << ".is_null = &i." << var << "null;"
+ float_buffer_types[mi.st->type - sql_type::FLOAT] << ";"
+ << b << ".buffer = &" << arg << "." << mi.var << "value;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;"
<< endl;
}
virtual void
- traverse_decimal (type&, sql_type const&)
+ traverse_decimal (member_info& mi)
{
os << b << ".buffer_type = MYSQL_TYPE_NEWDECIMAL;"
- << b << ".buffer = i." << var << "value.data ();"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
<< b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "i." << var << "value.capacity ());"
- << b << ".length = &i." << var << "size;"
- << b << ".is_null = &i." << var << "null;"
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;"
<< endl;
}
virtual void
- traverse_date_time (type&, sql_type const& t)
+ traverse_date_time (member_info& mi)
{
os << b << ".buffer_type = " <<
- date_time_buffer_types[t.type - sql_type::DATE] << ";"
- << b << ".buffer = &i." << var << "value;";
+ date_time_buffer_types[mi.st->type - sql_type::DATE] << ";"
+ << b << ".buffer = &" << arg << "." << mi.var << "value;";
- if (t.type == sql_type::YEAR)
+ if (mi.st->type == sql_type::YEAR)
os << b << ".is_unsigned = 0;";
- os << b << ".is_null = &i." << var << "null;"
+ os << b << ".is_null = &" << arg << "." << mi.var << "null;"
<< endl;
}
virtual void
- traverse_short_string (type&, sql_type const& t)
+ 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.
@@ -178,73 +213,76 @@ namespace mysql
// only if length is NULL.
//
os << b << ".buffer_type = " <<
- char_bin_buffer_types[t.type - sql_type::CHAR] << ";"
- << b << ".buffer = i." << var << "value.data ();"
+ 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
- << "i." << var << "value.capacity ());"
- << b << ".length = &i." << var << "size;"
- << b << ".is_null = &i." << var << "null;"
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;"
<< endl;
}
virtual void
- traverse_long_string (type&, sql_type const& t)
+ traverse_long_string (member_info& mi)
{
os << b << ".buffer_type = " <<
- char_bin_buffer_types[t.type - sql_type::CHAR] << ";"
- << b << ".buffer = i." << var << "value.data ();"
+ 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
- << "i." << var << "value.capacity ());"
- << b << ".length = &i." << var << "size;"
- << b << ".is_null = &i." << var << "null;"
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;"
<< endl;
}
virtual void
- traverse_bit (type&, sql_type const&)
+ traverse_bit (member_info& mi)
{
// Treated as a BLOB.
//
os << b << ".buffer_type = MYSQL_TYPE_BLOB;"
- << b << ".buffer = i." << var << "value;"
+ << b << ".buffer = " << arg << "." << mi.var << "value;"
<< b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "sizeof (i." << var << "value));"
- << b << ".length = &i." << var << "size;"
- << b << ".is_null = &i." << var << "null;"
+ << "sizeof (" << arg << "." << mi.var << "value));"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;"
<< endl;
}
virtual void
- traverse_enum (type&, sql_type const&)
+ traverse_enum (member_info& mi)
{
// Represented as a string.
//
os << b << ".buffer_type = MYSQL_TYPE_STRING;"
- << b << ".buffer = i." << var << "value.data ();"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
<< b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "i." << var << "value.capacity ());"
- << b << ".length = &i." << var << "size;"
- << b << ".is_null = &i." << var << "null;"
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;"
<< endl;
}
virtual void
- traverse_set (type&, sql_type const&)
+ traverse_set (member_info& mi)
{
// Represented as a string.
//
os << b << ".buffer_type = MYSQL_TYPE_STRING;"
- << b << ".buffer = i." << var << "value.data ();"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
<< b << ".buffer_length = static_cast<unsigned long> (" << endl
- << "i." << var << "value.capacity ());"
- << b << ".length = &i." << var << "size;"
- << b << ".is_null = &i." << var << "null;"
+ << "" << arg << "." << mi.var << "value.capacity ());"
+ << b << ".length = &" << arg << "." << mi.var << "size;"
+ << b << ".is_null = &" << arg << "." << mi.var << "null;"
<< endl;
}
private:
- string b;
size_t& index_;
+
+ string b;
+ string arg;
+ string arg_override_;
};
struct bind_base: traversal::class_, context
@@ -277,123 +315,139 @@ namespace mysql
struct grow_member: member_base
{
grow_member (context& c, size_t& index)
- : member_base (c, false), index_ (index)
+ : member_base (c), index_ (index)
+ {
+ }
+
+ grow_member (context& c,
+ 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)
{
}
virtual void
- pre (type& m)
+ pre (member_info& mi)
{
+ if (container (mi.t))
+ return;
+
ostringstream ostr;
ostr << "e[" << index_ << "UL]";
e = ostr.str ();
- os << "// " << m.name () << endl
- << "//" << endl;
+ if (var_override_.empty ())
+ os << "// " << mi.m.name () << endl
+ << "//" << endl;
}
virtual void
- post (type& m)
+ post (member_info& mi)
{
- if (semantics::class_* c = comp_value (m.type ()))
+ if (container (mi.t))
+ return;
+ else if (semantics::class_* c = comp_value (mi.t))
index_ += column_count (*c);
else
index_++;
}
virtual void
- traverse_composite (type& m)
+ traverse_composite (member_info& mi)
{
- os << "if (composite_value_traits< " << m.type ().fq_name () <<
+ os << "if (composite_value_traits< " << mi.fq_type () <<
" >::grow (" << endl
- << "i." << var << "value, e + " << index_ << "UL))"
+ << "i." << mi.var << "value, e + " << index_ << "UL))"
<< "{"
<< "r = true;"
<< "}";
}
virtual void
- traverse_integer (type&, sql_type const&)
+ traverse_integer (member_info&)
{
os << e << " = 0;"
<< endl;
}
virtual void
- traverse_float (type&, sql_type const&)
+ traverse_float (member_info&)
{
os << e << " = 0;"
<< endl;
}
virtual void
- traverse_decimal (type&, sql_type const&)
+ traverse_decimal (member_info& mi)
{
// @@ Optimization disabled.
//
os << "if (" << e << ")" << endl
<< "{"
- << "i." << var << "value.capacity (i." << var << "size);"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
<< "r = true;"
<< "}";
}
virtual void
- traverse_date_time (type&, sql_type const&)
+ traverse_date_time (member_info&)
{
os << e << " = 0;"
<< endl;
}
virtual void
- traverse_short_string (type&, sql_type const&)
+ traverse_short_string (member_info& mi)
{
// @@ Optimization disabled.
//
os << "if (" << e << ")" << endl
<< "{"
- << "i." << var << "value.capacity (i." << var << "size);"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
<< "r = true;"
<< "}";
}
virtual void
- traverse_long_string (type&, sql_type const&)
+ traverse_long_string (member_info& mi)
{
os << "if (" << e << ")" << endl
<< "{"
- << "i." << var << "value.capacity (i." << var << "size);"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
<< "r = true;"
<< "}";
}
virtual void
- traverse_bit (type&, sql_type const&)
+ traverse_bit (member_info&)
{
os << e << " = 0;"
<< endl;
}
virtual void
- traverse_enum (type&, sql_type const&)
+ traverse_enum (member_info& mi)
{
// Represented as a string.
//
os << "if (" << e << ")" << endl
<< "{"
- << "i." << var << "value.capacity (i." << var << "size);"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
<< "r = true;"
<< "}";
}
virtual void
- traverse_set (type&, sql_type const&)
+ traverse_set (member_info& mi)
{
// Represented as a string.
//
os << "if (" << e << ")" << endl
<< "{"
- << "i." << var << "value.capacity (i." << var << "size);"
+ << "i." << mi.var << "value.capacity (i." << mi.var << "size);"
<< "r = true;"
<< "}";
}
@@ -434,25 +488,41 @@ namespace mysql
struct init_image_member: member_base
{
- init_image_member (context& c, bool id)
- : member_base (c, id),
- member_image_type_ (c, id),
- member_database_type_ (c)
+ init_image_member (context& c,
+ string const& var = string (),
+ string const& member = string ())
+ : member_base (c, var),
+ member_image_type_ (c),
+ member_database_type_ (c),
+ member_override_ (member)
{
}
- virtual void
- pre (type& m)
+ init_image_member (context& c,
+ 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_override_ (member)
{
- semantics::type& t (m.type ());
+ }
- if (comp_value (t))
- traits = "composite_value_traits< " + t.fq_name () + " >";
+ virtual void
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return;
+ else if (comp_value (mi.t))
+ traits = "composite_value_traits< " + mi.fq_type () + " >";
else
{
- type = t.fq_name (m.belongs ().hint ());
- image_type = member_image_type_.image_type (m);
- db_type = member_database_type_.database_type (m);
+ 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< "
+ type + ", "
@@ -460,11 +530,11 @@ namespace mysql
+ db_type + " >";
}
- if (id_)
- member = "id";
+ if (!member_override_.empty ())
+ member = member_override_;
else
{
- string const& name (m.name ());
+ string const& name (mi.m.name ());
member = "o." + name;
os << "// " << name << endl
@@ -473,9 +543,9 @@ namespace mysql
}
virtual void
- traverse_composite (type&)
+ traverse_composite (member_info& mi)
{
- os << "if (" << traits << "::init (i." << var << "value, " <<
+ os << "if (" << traits << "::init (i." << mi.var << "value, " <<
member << "))"
<< "{"
<< "grew = true;"
@@ -483,98 +553,98 @@ namespace mysql
}
virtual void
- traverse_integer (type&, sql_type const&)
+ traverse_integer (member_info& mi)
{
os << "{"
<< "bool is_null;"
<< traits << "::set_image (" << endl
- << "i." << var << "value, is_null, " << member << ");"
- << "i." << var << "null = is_null;"
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "}";
}
virtual void
- traverse_float (type&, sql_type const&)
+ traverse_float (member_info& mi)
{
os << "{"
<< "bool is_null;"
<< traits << "::set_image (" << endl
- << "i." << var << "value, is_null, " << member << ");"
- << "i." << var << "null = is_null;"
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "}";
}
virtual void
- traverse_decimal (type&, sql_type const&)
+ traverse_decimal (member_info& mi)
{
// @@ Optimization: can remove growth check if buffer is fixed.
//
os << "{"
<< "bool is_null;"
<< "std::size_t size;"
- << "std::size_t cap (i." << var << "value.capacity ());"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
<< traits << "::set_image (" << endl
- << "i." << var << "value," << endl
+ << "i." << mi.var << "value," << endl
<< "size," << endl
<< "is_null," << endl
<< member << ");"
- << "i." << var << "size = static_cast<unsigned long> (size);"
- << "i." << var << "null = is_null;"
- << "grew = grew || (cap != i." << var << "value.capacity ());"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "i." << mi.var << "null = is_null;"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());"
<< "}";
}
virtual void
- traverse_date_time (type&, sql_type const&)
+ traverse_date_time (member_info& mi)
{
os << "{"
<< "bool is_null;"
<< traits << "::set_image (" << endl
- << "i." << var << "value, is_null, " << member << ");"
- << "i." << var << "null = is_null;"
+ << "i." << mi.var << "value, is_null, " << member << ");"
+ << "i." << mi.var << "null = is_null;"
<< "}";
}
virtual void
- traverse_short_string (type&, sql_type const&)
+ traverse_short_string (member_info& mi)
{
// @@ Optimization: can remove growth check if buffer is fixed.
//
os << "{"
<< "bool is_null;"
<< "std::size_t size;"
- << "std::size_t cap (i." << var << "value.capacity ());"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
<< traits << "::set_image (" << endl
- << "i." << var << "value," << endl
+ << "i." << mi.var << "value," << endl
<< "size," << endl
<< "is_null," << endl
<< member << ");"
- << "i." << var << "size = static_cast<unsigned long> (size);"
- << "i." << var << "null = is_null;"
- << "grew = grew || (cap != i." << var << "value.capacity ());"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "i." << mi.var << "null = is_null;"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());"
<< "}";
}
virtual void
- traverse_long_string (type&, sql_type const&)
+ traverse_long_string (member_info& mi)
{
os << "{"
<< "bool is_null;"
<< "std::size_t size;"
- << "std::size_t cap (i." << var << "value.capacity ());"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
<< traits << "::set_image (" << endl
- << "i." << var << "value," << endl
+ << "i." << mi.var << "value," << endl
<< "size," << endl
<< "is_null," << endl
<< member << ");"
- << "i." << var << "size = static_cast<unsigned long> (size);"
- << "i." << var << "null = is_null;"
- << "grew = grew || (cap != i." << var << "value.capacity ());"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "i." << mi.var << "null = is_null;"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());"
<< "}";
}
virtual void
- traverse_bit (type&, sql_type const&)
+ traverse_bit (member_info& mi)
{
// Represented as a BLOB.
//
@@ -582,53 +652,53 @@ namespace mysql
<< "bool is_null;"
<< "std::size_t size;"
<< traits << "::set_image (" << endl
- << "i." << var << "value," << endl
- << "sizeof (i." << var << "value)," << endl
+ << "i." << mi.var << "value," << endl
+ << "sizeof (i." << mi.var << "value)," << endl
<< "size," << endl
<< "is_null," << endl
<< member << ");"
- << "i." << var << "size = static_cast<unsigned long> (size);"
- << "i." << var << "null = is_null;"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "i." << mi.var << "null = is_null;"
<< "}";
}
virtual void
- traverse_enum (type&, sql_type const&)
+ traverse_enum (member_info& mi)
{
// Represented as a string.
//
os << "{"
<< "bool is_null;"
<< "std::size_t size;"
- << "std::size_t cap (i." << var << "value.capacity ());"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
<< traits << "::set_image (" << endl
- << "i." << var << "value," << endl
+ << "i." << mi.var << "value," << endl
<< "size," << endl
<< "is_null," << endl
<< member << ");"
- << "i." << var << "size = static_cast<unsigned long> (size);"
- << "i." << var << "null = is_null;"
- << "grew = grew || (cap != i." << var << "value.capacity ());"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "i." << mi.var << "null = is_null;"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());"
<< "}";
}
virtual void
- traverse_set (type&, sql_type const&)
+ traverse_set (member_info& mi)
{
// Represented as a string.
//
os << "{"
<< "bool is_null;"
<< "std::size_t size;"
- << "std::size_t cap (i." << var << "value.capacity ());"
+ << "std::size_t cap (i." << mi.var << "value.capacity ());"
<< traits << "::set_image (" << endl
- << "i." << var << "value," << endl
+ << "i." << mi.var << "value," << endl
<< "size," << endl
<< "is_null," << endl
<< member << ");"
- << "i." << var << "size = static_cast<unsigned long> (size);"
- << "i." << var << "null = is_null;"
- << "grew = grew || (cap != i." << var << "value.capacity ());"
+ << "i." << mi.var << "size = static_cast<unsigned long> (size);"
+ << "i." << mi.var << "null = is_null;"
+ << "grew = grew || (cap != i." << mi.var << "value.capacity ());"
<< "}";
}
@@ -641,6 +711,8 @@ namespace mysql
member_image_type member_image_type_;
member_database_type member_database_type_;
+
+ string member_override_;
};
struct init_image_base: traversal::class_, context
@@ -670,24 +742,37 @@ namespace mysql
struct init_value_member: member_base
{
init_value_member (context& c)
- : member_base (c, false),
- member_image_type_ (c, false),
+ : member_base (c),
+ member_image_type_ (c),
member_database_type_ (c)
{
}
- virtual void
- pre (type& m)
+ init_value_member (context& c,
+ 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_override_ (member)
{
- semantics::type& t (m.type ());
+ }
- if (comp_value (t))
- traits = "composite_value_traits< " + t.fq_name () + " >";
+ virtual void
+ pre (member_info& mi)
+ {
+ if (container (mi.t))
+ return;
+ else if (comp_value (mi.t))
+ traits = "composite_value_traits< " + mi.fq_type () + " >";
else
{
- type = m.type ().fq_name (m.belongs ().hint ());
- image_type = member_image_type_.image_type (m);
- db_type = member_database_type_.database_type (m);
+ 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< "
+ type + ", "
@@ -695,113 +780,122 @@ namespace mysql
+ db_type + " >";
}
- os << "// " << m.name () << endl
- << "//" << endl;
+ if (!member_override_.empty ())
+ member = member_override_;
+ else
+ {
+ string const& name (mi.m.name ());
+ member = "o." + name;
+
+ os << "// " << name << endl
+ << "//" << endl;
+ }
}
virtual void
- traverse_composite (type& m)
+ traverse_composite (member_info& mi)
{
- os << traits << "::init (o." << m.name () << ", i." << var << "value);"
+ os << traits << "::init (" << member << ", i." <<
+ mi.var << "value);"
<< endl;
}
virtual void
- traverse_integer (type& m, sql_type const&)
+ traverse_integer (member_info& mi)
{
os << traits << "::set_value (" << endl
- << "o." << m.name () << ", i." << var << "value, " <<
- "i." << var << "null);"
+ << member << ", i." << mi.var << "value, " <<
+ "i." << mi.var << "null);"
<< endl;
}
virtual void
- traverse_float (type& m, sql_type const&)
+ traverse_float (member_info& mi)
{
os << traits << "::set_value (" << endl
- << "o." << m.name () << ", i." << var << "value, " <<
- "i." << var << "null);"
+ << member << ", i." << mi.var << "value, " <<
+ "i." << mi.var << "null);"
<< endl;
}
virtual void
- traverse_decimal (type& m, sql_type const&)
+ traverse_decimal (member_info& mi)
{
os << traits << "::set_value (" << endl
- << "o." << m.name () << "," << endl
- << "i." << var << "value," << endl
- << "i." << var << "size," << endl
- << "i." << var << "null);"
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
<< endl;
}
virtual void
- traverse_date_time (type& m, sql_type const&)
+ traverse_date_time (member_info& mi)
{
os << traits << "::set_value (" << endl
- << "o." << m.name () << ", i." << var << "value, " <<
- "i." << var << "null);"
+ << member << ", i." << mi.var << "value, " <<
+ "i." << mi.var << "null);"
<< endl;
}
virtual void
- traverse_short_string (type& m, sql_type const&)
+ traverse_short_string (member_info& mi)
{
os << traits << "::set_value (" << endl
- << "o." << m.name () << "," << endl
- << "i." << var << "value," << endl
- << "i." << var << "size," << endl
- << "i." << var << "null);"
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
<< endl;
}
virtual void
- traverse_long_string (type& m, sql_type const&)
+ traverse_long_string (member_info& mi)
{
os << traits << "::set_value (" << endl
- << "o." << m.name () << "," << endl
- << "i." << var << "value," << endl
- << "i." << var << "size," << endl
- << "i." << var << "null);"
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
<< endl;
}
virtual void
- traverse_bit (type& m, sql_type const&)
+ traverse_bit (member_info& mi)
{
// Represented as a BLOB.
//
os << traits << "::set_value (" << endl
- << "o." << m.name () << "," << endl
- << "i." << var << "value," << endl
- << "i." << var << "size," << endl
- << "i." << var << "null);"
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
<< endl;
}
virtual void
- traverse_enum (type& m, sql_type const&)
+ traverse_enum (member_info& mi)
{
// Represented as a string.
//
os << traits << "::set_value (" << endl
- << "o." << m.name () << "," << endl
- << "i." << var << "value," << endl
- << "i." << var << "size," << endl
- << "i." << var << "null);"
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
<< endl;
}
virtual void
- traverse_set (type& m, sql_type const&)
+ traverse_set (member_info& mi)
{
// Represented as a string.
//
os << traits << "::set_value (" << endl
- << "o." << m.name () << "," << endl
- << "i." << var << "value," << endl
- << "i." << var << "size," << endl
- << "i." << var << "null);"
+ << member << "," << endl
+ << "i." << mi.var << "value," << endl
+ << "i." << mi.var << "size," << endl
+ << "i." << mi.var << "null);"
<< endl;
}
@@ -810,9 +904,12 @@ namespace mysql
string db_type;
string image_type;
string traits;
+ string member;
member_image_type member_image_type_;
member_database_type member_database_type_;
+
+ string member_override_;
};
struct init_value_base: traversal::class_, context
@@ -832,6 +929,872 @@ namespace mysql
}
};
+ // Member-specific traits types for container members.
+ //
+ struct container_traits: object_members_base, context
+ {
+ container_traits (context& c, semantics::class_& obj)
+ : object_members_base (c, true, true),
+ context (c),
+ object_ (obj),
+ id_member_ (id_member (obj))
+ {
+ obj_scope_ = "access::object_traits< " + obj.fq_name () + " >";
+ }
+
+ virtual void
+ container (semantics::data_member& m)
+ {
+ using semantics::type;
+
+ type& t (m.type ());
+ container_kind_type ck (container_kind (t));
+
+ type& vt (container_vt (t));
+ type* it (0);
+ type* kt (0);
+
+ bool grow (false);
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ it = &container_it (t);
+ grow = grow || context::grow (m, *it, "index");
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ kt = &container_kt (t);
+ grow = grow || context::grow (m, *kt, "key");
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ grow = grow || context::grow (m, vt, "value");
+
+ string name (prefix_ + public_name (m) + "_traits");
+ string scope (obj_scope_ + "::" + name);
+
+ os << "// " << m.name () << endl
+ << "//" << endl
+ << endl;
+
+ //
+ // Statements.
+ //
+ string table (table_name (m, table_prefix_));
+
+ // insert_one_statement
+ //
+ os << "const char* const " << scope << "::insert_one_statement =" << endl
+ << "\"INSERT INTO `" << table << "` (\"" << endl
+ << "\"`" << column_name (m, "id", "object_id") << "`";
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << ",\"" << endl
+ << "\"`" << column_name (m, "index", "index") << "`";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ if (comp_value (*kt))
+ {
+ object_columns t (*this, false);
+ t.traverse_composite (m, *kt, "key", "key");
+ }
+ else
+ {
+ os << ",\"" << endl
+ << "\"`" << column_name (m, "key", "key") << "`";
+ }
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ if (comp_value (vt))
+ {
+ object_columns t (*this, false);
+ t.traverse_composite (m, vt, "value", "value");
+ }
+ else
+ {
+ os << ",\"" << endl
+ << "\"`" << column_name (m, "value", "value") << "`";
+ }
+
+ os << "\"" << endl
+ << "\") VALUES (";
+
+ for (size_t i (0), n (m.get<size_t> ("data-column-count")); i < n; ++i)
+ os << (i != 0 ? "," : "") << '?';
+
+ os << ")\";"
+ << endl;
+
+ // select_all_statement
+ //
+ os << "const char* const " << scope << "::select_all_statement =" << endl
+ << "\"SELECT \"" << endl
+ << "\"`" << column_name (m, "id", "object_id") << "`";
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << ",\"" << endl
+ << "\"`" << column_name (m, "index", "index") << "`";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ if (comp_value (*kt))
+ {
+ object_columns t (*this, false);
+ t.traverse_composite (m, *kt, "key", "key");
+ }
+ else
+ {
+ os << ",\"" << endl
+ << "\"`" << column_name (m, "key", "key") << "`";
+ }
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ if (comp_value (vt))
+ {
+ object_columns t (*this, false);
+ t.traverse_composite (m, vt, "value", "value");
+ }
+ else
+ {
+ os << ",\"" << endl
+ << "\"`" << column_name (m, "value", "value") << "`";
+ }
+
+ os << "\"" << endl
+ << "\" FROM `" << table << "` WHERE `" <<
+ column_name (m, "id", "object_id") << "` = ?\"" << endl;
+
+ if (ck == ck_ordered)
+ os << "\" ORDER BY `" << column_name (m, "index", "index") << "`\"";
+
+ os << ";"
+ << endl;
+
+ // delete_all_statement
+ //
+ os << "const char* const " << scope << "::delete_all_statement =" << endl
+ << "\"DELETE FROM `" << table << "`\"" << endl
+ << "\" WHERE `" << column_name (m, "id", "object_id") << "` = ?\";"
+ << endl;
+
+ //
+ // Functions.
+ //
+
+ // bind()
+ //
+ {
+ size_t index;
+ bind_member bind_id (*this, index, "id_", "id");
+
+ // bind (cond_image_type)
+ //
+ os << "void " << scope << "::" << endl
+ << "bind (MYSQL_BIND* b, id_image_type* p, cond_image_type& c)"
+ << "{";
+
+ index = 0;
+
+ os << "// object_id" << endl
+ << "//" << endl
+ << "if (p != 0)"
+ << "{"
+ << "id_image_type& id (*p);";
+ bind_id.traverse (id_member_);
+ os << "}";
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "// index" << endl
+ << "//" << endl;
+ bind_member bm (
+ *this, index, "index_", "c", *it, "index_type", "index");
+ bm.traverse (m);
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "// key" << endl
+ << "//" << endl;
+ bind_member bm (
+ *this, index, "key_", "c", *kt, "key_type", "key");
+ bm.traverse (m);
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "// value" << endl
+ << "//" << endl;
+ bind_member bm (
+ *this, index, "value_", "c", vt, "value_type", "value");
+ bm.traverse (m);
+ break;
+ }
+ }
+
+ os << "}";
+
+ // bind (data_image_type)
+ //
+ os << "void " << scope << "::" << endl
+ << "bind (MYSQL_BIND* b, id_image_type* p, data_image_type& d)"
+ << "{";
+
+ index = 0;
+
+ os << "// object_id" << endl
+ << "//" << endl
+ << "if (p != 0)"
+ << "{"
+ << "id_image_type& id (*p);";
+ bind_id.traverse (id_member_);
+ os << "}";
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "// index" << endl
+ << "//" << endl;
+ bind_member bm (
+ *this, index, "index_", "d", *it, "index_type", "index");
+ bm.traverse (m);
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "// key" << endl
+ << "//" << endl;
+ bind_member bm (
+ *this, index, "key_", "d", *kt, "key_type", "key");
+ bm.traverse (m);
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ os << "// value" << endl
+ << "//" << endl;
+ bind_member bm (
+ *this, index, "value_", "d", vt, "value_type", "value");
+ bm.traverse (m);
+
+ os << "}";
+ }
+
+ // grow ()
+ //
+ {
+ size_t index (0);
+
+ os << "bool " << scope << "::" << endl
+ << "grow (data_image_type&" << (grow ? " i" : "") << ", my_bool* e)"
+ << "{"
+ << "bool r (false);"
+ << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "// index" << endl
+ << "//" << endl;
+ grow_member gm (
+ *this, index, "index_", *it, "index_type", "index");
+ gm.traverse (m);
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "// key" << endl
+ << "//" << endl;
+ grow_member gm (*this, index, "key_", *kt, "key_type", "key");
+ gm.traverse (m);
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ break;
+ }
+ }
+
+ os << "// value" << endl
+ << "//" << endl;
+ grow_member gm (*this, index, "value_", vt, "value_type", "value");
+ gm.traverse (m);
+
+ os << "return r;"
+ << "}";
+ }
+
+ // init (data_image)
+ //
+ os << "bool " << scope << "::" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (data_image_type& i, index_type j, const value_type& v)"
+ << "{"
+ << "bool grew (false);"
+ << endl
+ << "// index" << endl
+ << "//" << endl;
+
+ init_image_member im (
+ *this, "index_", "j", *it, "index_type", "index");
+ im.traverse (m);
+
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "init (data_image_type& i, const key_type& k, " <<
+ "const value_type& v)"
+ << "{"
+ << "bool grew (false);"
+ << endl
+ << "// key" << endl
+ << "//" << endl;
+
+ init_image_member im (*this, "key_", "k", *kt, "key_type", "key");
+ im.traverse (m);
+
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "init (data_image_type& i, const value_type& v)"
+ << "{"
+ << "bool grew (false);"
+ << endl;
+ break;
+ }
+ }
+
+ os << "// value" << endl
+ << "//" << endl;
+ {
+ init_image_member im (
+ *this, "value_", "v", vt, "value_type", "value");
+ im.traverse (m);
+ }
+ os << "return grew;"
+ << "}";
+
+ // init (data)
+ //
+ os << "void " << scope << "::" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (index_type& j, value_type& v, const data_image_type& i)"
+ << "{"
+ << "// index" << endl
+ << "//" << endl;
+
+ init_value_member im (
+ *this, "index_", "j", *it, "index_type", "index");
+ im.traverse (m);
+
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "init (key_type& k, value_type& v, const data_image_type& i)"
+ << "{"
+ << "// key" << endl
+ << "//" << endl;
+
+ init_value_member im (*this, "key_", "k", *kt, "key_type", "key");
+ im.traverse (m);
+
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "init (value_type& v, const data_image_type& i)"
+ << "{";
+ break;
+ }
+ }
+
+ os << "// value" << endl
+ << "//" << endl;
+ {
+ init_value_member im (
+ *this, "value_", "v", vt, "value_type", "value");
+ im.traverse (m);
+ }
+ os << "}";
+
+ // insert_one
+ //
+ os << "void " << scope << "::" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "insert_one (index_type i, const value_type& v, void* d)";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "insert_one (const key_type& k, const value_type& v, void* d)";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "insert_one (const value_type& v, void* d)";
+ break;
+ }
+ }
+
+ os << "{"
+ << "using namespace mysql;"
+ << endl
+ << "typedef container_statements< " << name << " > statements;"
+ << "statements& sts (*static_cast< statements* > (d));"
+ << "binding& b (sts.data_image_binding ());"
+ << "data_image_type& di (sts.data_image ());"
+ << endl
+ << "if (";
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (di, i, v)";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "init (di, k, v)";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "init (di, v)";
+ break;
+ }
+ }
+
+ os << " || b.version == 0)"
+ << "{"
+ << "bind (b.bind, 0, di);"
+ << "b.version++;"
+ << "}"
+ << "if (!sts.insert_one_statement ().execute ())" << endl
+ << "throw object_already_persistent ();"
+ << "}";
+
+
+ // load_all
+ //
+ os << "bool " << scope << "::" << endl;
+
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "load_all (index_type& i, value_type& v, void* d)";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "load_all (key_type& k, value_type& v, void* d)";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "load_all (value_type& v, void* d)";
+ break;
+ }
+ }
+
+ os << "{"
+ << "using namespace mysql;"
+ << endl
+ << "typedef container_statements< " << name << " > statements;"
+ << "statements& sts (*static_cast< statements* > (d));"
+ << "data_image_type& di (sts.data_image ());";
+
+ // Extract current element.
+ //
+ switch (ck)
+ {
+ case ck_ordered:
+ {
+ os << "init (i, v, di);";
+ break;
+ }
+ case ck_map:
+ case ck_multimap:
+ {
+ os << "init (k, v, di);";
+ break;
+ }
+ case ck_set:
+ case ck_multiset:
+ {
+ os << "init (v, di);";
+ break;
+ }
+ }
+
+ // Fetch next.
+ //
+ os << endl
+ << "select_statement& st (sts.select_all_statement ());"
+ << "select_statement::result r (st.fetch ());";
+
+ if (grow)
+ os << endl
+ << "if (r == select_statement::truncated)"
+ << "{"
+ << "if (grow (di, sts.data_image_error ()))"
+ << "{"
+ << "binding& db (sts.data_image_binding ());"
+ << "bind (db.bind, 0, di);"
+ << "db.version++;"
+ << "st.refetch ();"
+ << "}"
+ << "}";
+
+ os << "if (r == select_statement::no_data)"
+ << "{"
+ << "st.free_result ();"
+ << "return false;"
+ << "}"
+ << "return true;"
+ << "}";
+
+ // delete_all
+ //
+ os << "void " << scope << "::" << endl
+ << "delete_all (void* d)"
+ << "{"
+ << "using namespace mysql;"
+ << endl
+ << "typedef container_statements< " << name << " > statements;"
+ << "statements& sts (*static_cast< statements* > (d));"
+ << "sts.delete_all_statement ().execute ();"
+ << "}";
+
+ // persist
+ //
+ os << "void " << scope << "::" << endl
+ << "persist (const container_type& c," << endl
+ << "id_image_type& id," << endl
+ << "bool rebind," << endl
+ << "statements_type& sts)"
+ << "{"
+ << "using namespace mysql;"
+ << endl
+ << "binding& b (sts.data_image_binding ());"
+ << "if (rebind || b.version == 0)"
+ << "{"
+ << "bind (b.bind, &id, sts.data_image ());"
+ << "b.version++;"
+ << "}"
+ << "if (rebind)" // We don't need it, just don't miss the event.
+ << "{"
+ << "binding& cb (sts.cond_image_binding ());"
+ << "bind (cb.bind, &id, sts.cond_image ());"
+ << "cb.version++;"
+ << "}"
+ << "container_traits::persist (c, sts.functions ());"
+ << "}";
+
+ // load
+ //
+ os << "void " << scope << "::" << endl
+ << "load (container_type& c," << endl
+ << "id_image_type& id," << endl
+ << "bool rebind," << endl
+ << "statements_type& sts)"
+ << "{"
+ << "using namespace mysql;"
+ << endl
+ << "binding& db (sts.data_image_binding ());"
+ << "if (rebind || db.version == 0)"
+ << "{"
+ << "bind (db.bind, &id, sts.data_image ());"
+ << "db.version++;"
+ << "}"
+ << "binding& cb (sts.cond_image_binding ());"
+ << "if (rebind || cb.version == 0)"
+ << "{"
+ << "bind (cb.bind, &id, sts.cond_image ());"
+ << "cb.version++;"
+ << "}"
+ << "select_statement& st (sts.select_all_statement ());"
+ << "st.execute ();"
+ << "select_statement::result r (st.fetch ());";
+
+ if (grow)
+ os << endl
+ << "if (r == select_statement::truncated)"
+ << "{"
+ << "if (grow (sts.data_image (), sts.data_image_error ()))"
+ << "{"
+ << "bind (db.bind, 0, sts.data_image ());"
+ << "db.version++;"
+ << "st.refetch ();"
+ << "}"
+ << "}";
+
+ os << "bool more (r != select_statement::no_data);"
+ << endl
+ << "if (!more)" << endl
+ << "st.free_result ();"
+ << endl
+ << "container_traits::load (c, more, sts.functions ());"
+ << "}";
+
+ // update
+ //
+ os << "void " << scope << "::" << endl
+ << "update (const container_type& c," << endl
+ << "id_image_type& id," << endl
+ << "bool rebind," << endl
+ << "statements_type& sts)"
+ << "{"
+ << "using namespace mysql;"
+ << endl
+ << "binding& db (sts.data_image_binding ());"
+ << "if (rebind || db.version == 0)"
+ << "{"
+ << "bind (db.bind, &id, sts.data_image ());"
+ << "db.version++;"
+ << "}"
+ << "binding& cb (sts.cond_image_binding ());"
+ << "if (rebind || cb.version == 0)" // We may need it (delete_all).
+ << "{"
+ << "bind (cb.bind, &id, sts.cond_image ());"
+ << "cb.version++;"
+ << "}"
+ << "container_traits::update (c, sts.functions ());"
+ << "}";
+
+ // erase
+ //
+ os << "void " << scope << "::" << endl
+ << "erase (id_image_type& id, bool rebind, statements_type& sts)"
+ << "{"
+ << "using namespace mysql;"
+ << endl
+ << "binding& b (sts.cond_image_binding ());"
+ << "if (rebind || b.version == 0)"
+ << "{"
+ << "bind (b.bind, &id, sts.cond_image ());"
+ << "b.version++;"
+ << "}"
+ << "if (rebind)"
+ << "{"
+ << "binding& db (sts.data_image_binding ());"
+ << "bind (db.bind, &id, sts.data_image ());"
+ << "db.version++;"
+ << "}"
+ << "container_traits::erase (sts.functions ());"
+ << "}";
+ }
+
+ private:
+ string obj_scope_;
+ semantics::class_& object_;
+ semantics::data_member& id_member_;
+ };
+
+ // Container statement cache members.
+ //
+ struct container_cache_members: object_members_base, context
+ {
+ container_cache_members (context& c)
+ : object_members_base (c, true, false),
+ context (c),
+ containers_ (false)
+ {
+ }
+
+ bool
+ containers () const
+ {
+ return containers_;
+ }
+
+ virtual void
+ container (semantics::data_member& m)
+ {
+ string traits (prefix_ + public_name (m) + "_traits");
+ os << "mysql::container_statements< " << traits << " > " <<
+ prefix_ << m.name () << ";";
+
+ containers_ = true;
+ }
+
+ private:
+ bool containers_;
+ };
+
+ struct container_cache_init_members: object_members_base, context
+ {
+ container_cache_init_members (context& c)
+ : object_members_base (c, true, false), context (c), first_ (true)
+ {
+ }
+
+ virtual void
+ container (semantics::data_member& m)
+ {
+ if (first_)
+ {
+ os << endl
+ << ": ";
+ first_ = false;
+ }
+ else
+ os << "," << endl
+ << " ";
+
+ os << prefix_ << m.name () << " (c)";
+ }
+
+ private:
+ bool first_;
+ };
+
+ // Calls for container members.
+ //
+ struct container_calls: object_members_base, context
+ {
+ enum call_type
+ {
+ persist_call,
+ load_call,
+ update_call,
+ erase_call
+ };
+
+ container_calls (context& c, call_type call)
+ : object_members_base (c, true, false), context (c), call_ (call)
+ {
+ }
+
+ virtual void
+ composite (semantics::data_member& m, semantics::type& t)
+ {
+ string old (obj_prefix_);
+ obj_prefix_ += m.name ();
+ obj_prefix_ += '.';
+ object_members_base::composite (m, t);
+ obj_prefix_ = old;
+ }
+
+ virtual void
+ container (semantics::data_member& m)
+ {
+ using semantics::type;
+
+ string const& name (m.name ());
+ string obj_name (obj_prefix_ + name);
+ string sts_name (prefix_ + name);
+ string traits (prefix_ + public_name (m) + "_traits");
+
+ switch (call_)
+ {
+ case persist_call:
+ {
+ os << traits << "::persist (obj." << obj_name << ", i, grew, " <<
+ "sts.container_statment_cache ()." << sts_name << ");";
+ break;
+ }
+ case load_call:
+ {
+ os << traits << "::load (obj." << obj_name << ", i, grew, " <<
+ "sts.container_statment_cache ()." << sts_name << ");";
+ break;
+ }
+ case update_call:
+ {
+ os << traits << "::update (obj." << obj_name << ", i, grew, " <<
+ "sts.container_statment_cache ()." << sts_name << ");";
+ break;
+ }
+ case erase_call:
+ {
+ os << traits << "::erase (i, grew, " <<
+ "sts.container_statment_cache ()." << sts_name << ");";
+ break;
+ }
+ }
+ }
+
+ private:
+ call_type call_;
+ string obj_prefix_;
+ };
+
//
//
struct class_: traversal::class_, context
@@ -841,11 +1804,11 @@ namespace mysql
grow_base_ (c, index_),
grow_member_ (c, index_),
bind_base_ (c, index_),
- bind_member_ (c, index_, false),
- bind_id_member_ (c, index_, true),
+ bind_member_ (c, index_),
+ bind_id_member_ (c, index_, "id_"),
init_image_base_ (c),
- init_image_member_ (c, false),
- init_id_image_member_ (c, true),
+ init_image_member_ (c),
+ init_id_image_member_ (c, "id_", "id"),
init_value_base_ (c),
init_value_member_ (c)
{
@@ -854,13 +1817,10 @@ namespace mysql
bind_base_inherits_ >> bind_base_;
bind_member_names_ >> bind_member_;
- bind_id_member_names_ >> bind_id_member_;
init_image_base_inherits_ >> init_image_base_;
init_image_member_names_ >> init_image_member_;
- init_id_image_member_names_ >> init_id_image_member_;
-
init_value_base_inherits_ >> init_value_base_;
init_value_member_names_ >> init_value_member_;
}
@@ -886,14 +1846,48 @@ namespace mysql
bool grow (context::grow (c));
bool def_ctor (TYPE_HAS_DEFAULT_CONSTRUCTOR (c.tree_node ()));
- id_member_.traverse (c);
- semantics::data_member& id (*id_member_.member ());
+ semantics::data_member& id (id_member (c));
bool auto_id (id.count ("auto"));
os << "// " << c.name () << endl
<< "//" << endl
<< endl;
+ //
+ // Containers.
+ //
+
+ // Statement cache (definition).
+ //
+ bool containers;
+ {
+ os << "struct " << traits << "::container_statement_cache_type"
+ << "{";
+
+ container_cache_members cm (*this);
+ cm.traverse (c);
+ containers = cm.containers ();
+
+ os << (containers ? "\n" : "")
+ << "container_statement_cache_type (mysql::connection&" <<
+ (containers ? " c" : "") << ")";
+
+ container_cache_init_members im (*this);
+ im.traverse (c);
+
+ os << "{"
+ << "}"
+ << "};";
+ }
+
+ // Traits types.
+ //
+ if (containers)
+ {
+ container_traits t (*this, c);
+ t.traverse (c);
+ }
+
// query columns
//
if (options.generate_query ())
@@ -1008,7 +2002,7 @@ namespace mysql
<< "{";
index_ = 0;
- names (c, bind_id_member_names_);
+ bind_id_member_.traverse (id);
os << "}";
@@ -1060,11 +2054,36 @@ namespace mysql
<< "bind (b.bind, sts.image ());"
<< "b.version++;"
<< "}"
- << "mysql::persist_statement& st (sts.persist_statement ());"
- << "st.execute ();";
+ << "insert_statement& st (sts.persist_statement ());"
+ << "if (!st.execute ())" << endl
+ << "throw object_already_persistent ();"
+ << endl;
if (auto_id)
- os << "obj." << id.name () << " = static_cast<id_type> (st.id ());";
+ os << "obj." << id.name () << " = static_cast<id_type> (st.id ());"
+ << endl;
+
+ if (containers)
+ {
+ // Initialize id_image.
+ //
+ os << "{"
+ << "bool grew (false);"
+ << "const id_type& id (obj." << id.name () << ");"
+ << "id_image_type& i (sts.id_image ());";
+ init_id_image_member_.traverse (id);
+ os << "binding& idb (sts.id_image_binding ());"
+ << "if (grew && idb.version != 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ << "idb.version++;"
+ << "}";
+
+ container_calls t (*this, container_calls::persist_call);
+ t.traverse (c);
+
+ os << "}";
+ }
os << "}";
@@ -1082,7 +2101,7 @@ namespace mysql
<< "bool grew (false);"
<< "const id_type& id (object_traits::id (obj));"
<< "id_image_type& i (sts.id_image ());";
- names (c, init_id_image_member_names_);
+ init_id_image_member_.traverse (id);
os << "binding& idb (sts.id_image_binding ());"
<< "if (grew || idb.version == 0)"
<< "{"
@@ -1095,8 +2114,16 @@ namespace mysql
<< "bind (imb.bind, sts.image ());"
<< "imb.version++;"
<< "}"
- << "sts.update_statement ().execute ();"
- << "}";
+ << "sts.update_statement ().execute ();";
+
+ if (containers)
+ {
+ os << endl;
+ container_calls t (*this, container_calls::update_call);
+ t.traverse (c);
+ }
+
+ os << "}";
// erase ()
//
@@ -1111,19 +2138,29 @@ namespace mysql
<< endl
<< "bool grew (false);"
<< "id_image_type& i (sts.id_image ());";
- names (c, init_id_image_member_names_);
+ init_id_image_member_.traverse (id);
os << "binding& idb (sts.id_image_binding ());"
<< "if (grew || idb.version == 0)"
<< "{"
<< "bind (idb.bind, i);"
<< "idb.version++;"
<< "}"
- << "sts.erase_statement ().execute ();"
- << "}";
+ << "if (sts.erase_statement ().execute () != 1)" << endl
+ << "throw object_not_persistent ();";
+
+ if (containers)
+ {
+ os << endl;
+ container_calls t (*this, container_calls::erase_call);
+ t.traverse (c);
+ }
+
+ os << "}";
// find ()
//
if (def_ctor)
+ {
os << traits << "::pointer_type" << endl
<< traits << "::" << endl
<< "find (database&, const id_type& id)"
@@ -1134,18 +2171,30 @@ namespace mysql
<< "object_statements<object_type>& sts (" << endl
<< "conn.statement_cache ().find<object_type> ());"
<< endl
- << "if (find (sts, id))"
+ << "bool grew (false);"
+ << "if (find (sts, id, grew))"
<< "{"
<< "pointer_type p (access::object_factory< " << type <<
" >::create ());"
<< "pointer_traits< pointer_type >::guard g (p);"
- << "init (pointer_traits< pointer_type >::get_ref (p), " <<
- "sts.image ());"
- << "g.release ();"
+ << "object_type& obj (pointer_traits< pointer_type >::get_ref (p));"
+ << "init (obj, sts.image ());";
+
+ if (containers)
+ {
+ os << endl
+ << "id_image_type& i (sts.id_image ());";
+ container_calls t (*this, container_calls::load_call);
+ t.traverse (c);
+ os << endl;
+ }
+
+ os << "g.release ();"
<< "return p;"
<< "}"
<< "return pointer_type ();"
<< "}";
+ }
os << "bool " << traits << "::" << endl
<< "find (database&, const id_type& id, object_type& obj)"
@@ -1156,23 +2205,34 @@ namespace mysql
<< "object_statements<object_type>& sts (" << endl
<< "conn.statement_cache ().find<object_type> ());"
<< endl
- << "if (find (sts, id))"
+ << "bool grew (false);"
+ << "if (find (sts, id, grew))"
<< "{"
- << "init (obj, sts.image ());"
- << "return true;"
+ << "init (obj, sts.image ());";
+
+ if (containers)
+ {
+ os << endl
+ << "id_image_type& i (sts.id_image ());";
+ container_calls t (*this, container_calls::load_call);
+ t.traverse (c);
+ os << endl;
+ }
+
+ os << "return true;"
<< "}"
<< "return false;"
<< "}";
os << "bool " << traits << "::" << endl
- << "find (mysql::object_statements<object_type>& sts, " <<
- "const id_type& id)"
+ << "find (mysql::object_statements<object_type>& sts," << endl
+ << "const id_type& id," << endl
+ << "bool& grew)"
<< "{"
<< "using namespace mysql;"
<< endl
- << "bool grew (false);"
<< "id_image_type& i (sts.id_image ());";
- names (c, init_id_image_member_names_);
+ init_id_image_member_.traverse (id);
os << "binding& idb (sts.id_image_binding ());"
<< "if (grew || idb.version == 0)"
<< "{"
@@ -1185,15 +2245,13 @@ namespace mysql
<< "bind (imb.bind, sts.image ());"
<< "imb.version++;"
<< "}"
- << "mysql::find_statement& st (sts.find_statement ());"
- << "mysql::find_statement::result r (st.execute ());"
- << endl
- << "if (r == mysql::find_statement::no_data)" << endl
- << "return false;"
- << endl;
+ << "select_statement& st (sts.find_statement ());"
+ << "st.execute ();"
+ << "select_statement::result r (st.fetch ());";
if (grow)
- os << "if (r == mysql::find_statement::truncated)"
+ os << endl
+ << "if (r == select_statement::truncated)"
<< "{"
<< "if (grow (sts.image (), sts.image_error ()))"
<< "{"
@@ -1204,7 +2262,7 @@ namespace mysql
<< "}";
os << "st.free_result ();"
- << "return true;"
+ << "return r != select_statement::no_data;"
<< "}";
// query ()
@@ -1227,11 +2285,11 @@ namespace mysql
<< "bind (imb.bind, sts.image ());"
<< "imb.version++;"
<< "}"
- << "details::shared_ptr<query_statement> st (" << endl
- << "new (details::shared) query_statement (conn," << endl
+ << "details::shared_ptr<select_statement> st (" << endl
+ << "new (details::shared) select_statement (conn," << endl
<< "query_clause + q.clause ()," << endl
- << "imb," << endl
- << "q.parameters ()));"
+ << "q.parameters ()," << endl
+ << "imb));"
<< "st->execute ();"
<< endl
<< "details::shared_ptr<odb::result_impl<object_type> > r (" << endl
@@ -1244,6 +2302,9 @@ namespace mysql
virtual void
traverse_value (type& c)
{
+ bool columns (column_count (c) != 0);
+ bool grow (columns && context::grow (c));
+
string const& type (c.fq_name ());
string traits ("access::composite_value_traits< " + type + " >");
@@ -1254,7 +2315,8 @@ namespace mysql
// grow ()
//
os << "bool " << traits << "::" << endl
- << "grow (image_type&" << (grow (c) ? " i" : "") << ", my_bool* e)"
+ << "grow (image_type&" << (grow ? " i" : "") << ", " <<
+ "my_bool*" << (columns ? " e" : "") << ")"
<< "{"
<< "bool r (false);"
<< endl;
@@ -1269,7 +2331,8 @@ namespace mysql
// bind (image_type)
//
os << "void " << traits << "::" << endl
- << "bind (MYSQL_BIND* b, image_type& i)"
+ << "bind (MYSQL_BIND*" << (columns ? " b" : "") << ", " <<
+ "image_type&" << (columns ? " i" : "") << ")"
<< "{";
index_ = 0;
@@ -1281,7 +2344,8 @@ namespace mysql
// init (image, object)
//
os << "bool " << traits << "::" << endl
- << "init (image_type& i, const value_type& o)"
+ << "init (image_type&" << (columns ? " i" : "") << ", " <<
+ "const value_type&" << (columns ? " o" : "") << ")"
<< "{"
<< "bool grew (false);"
<< endl;
@@ -1295,7 +2359,8 @@ namespace mysql
// init (object, image)
//
os << "void " << traits << "::" << endl
- << "init (value_type& o, const image_type& i)"
+ << "init (value_type&" << (columns ? " o" : "") << ", " <<
+ "const image_type&" << (columns ? " i" : "") << ")"
<< "{";
inherits (c, init_value_base_inherits_);
@@ -1305,8 +2370,6 @@ namespace mysql
}
private:
- id_member id_member_;
-
bool id_;
size_t index_;
@@ -1320,7 +2383,6 @@ namespace mysql
bind_member bind_member_;
traversal::names bind_member_names_;
bind_member bind_id_member_;
- traversal::names bind_id_member_names_;
init_image_base init_image_base_;
traversal::inherits init_image_base_inherits_;
@@ -1328,7 +2390,6 @@ namespace mysql
traversal::names init_image_member_names_;
init_image_member init_id_image_member_;
- traversal::names init_id_image_member_names_;
init_value_base init_value_base_;
traversal::inherits init_value_base_inherits_;
@@ -1359,6 +2420,9 @@ namespace mysql
<< "#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 ())
diff --git a/odb/parser.cxx b/odb/parser.cxx
index c257305..528b55b 100644
--- a/odb/parser.cxx
+++ b/odb/parser.cxx
@@ -1812,7 +1812,15 @@ process_pragmas (tree t,
ts << "\t\t pragma " << i->name << " (" << i->value << ")"
<< endl;
- node.set (i->name, i->value);
+ // Convert '_' to '-' in the pragma name so we get foo-bar instead
+ // of foo_bar (that's the convention used).
+ //
+ string tmp (i->name);
+ for (size_t j (0); j < tmp.size (); ++j)
+ if (tmp[j] == '_')
+ tmp[j] = '-';
+
+ node.set (tmp, i->value);
}
}
@@ -1834,7 +1842,15 @@ process_named_pragmas (tree t, node& node)
ts << "\t\t pragma " << i->name << " (" << i->value << ")"
<< endl;
- node.set (i->name, i->value);
+ // Convert '_' to '-' in the pragma name so we get foo-bar instead
+ // of foo_bar (that's the convention used).
+ //
+ string tmp (i->name);
+ for (size_t j (0); j < tmp.size (); ++j)
+ if (tmp[j] == '_')
+ tmp[j] = '-';
+
+ node.set (tmp, i->value);
}
}
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 8226495..88c14a2 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -97,6 +97,10 @@ check_decl_type (tree d, string const& name, string const& p, location_t l)
p == "id" ||
p == "auto" ||
p == "column" ||
+ p == "value_column" ||
+ p == "index_column" ||
+ p == "key_column" ||
+ p == "id_column" ||
p == "transient")
{
if (tc != FIELD_DECL)
@@ -106,8 +110,7 @@ check_decl_type (tree d, string const& name, string const& p, location_t l)
return false;
}
}
- else if (p == "object" ||
- p == "table")
+ else if (p == "object")
{
if (tc != RECORD_TYPE)
{
@@ -116,6 +119,17 @@ check_decl_type (tree d, string const& name, string const& p, location_t l)
return false;
}
}
+ else if (p == "table")
+ {
+ // Table can be used for both members (container) and types.
+ //
+ if (tc != FIELD_DECL && tc != RECORD_TYPE)
+ {
+ error_at (l, "name %qs in db pragma %qs does not refer to a class "
+ "or data member", name.c_str (), pc);
+ return false;
+ }
+ }
else if (p == "value")
{
if (!TYPE_P (d))
@@ -125,7 +139,10 @@ check_decl_type (tree d, string const& name, string const& p, location_t l)
return false;
}
}
- else if (p == "type")
+ else if (p == "type" ||
+ p == "value_type" ||
+ p == "index_type" ||
+ p == "key_type")
{
// Type can be used for both members and types.
//
@@ -213,9 +230,17 @@ handle_pragma (string const& p, tree decl, string const& decl_name)
tt = pragma_lex (&t);
}
- else if (p == "column")
+ else if (p == "column" ||
+ p == "value_column" ||
+ p == "index_column" ||
+ p == "key_column" ||
+ p == "id_column")
{
- // column ([<identifier>,] "<name>")
+ // column ("<name>")
+ // value_column ("<name>")
+ // index_column ("<name>")
+ // key_column ("<name>")
+ // id_column ("<name>")
//
// Make sure we've got the correct declaration type.
@@ -247,9 +272,15 @@ handle_pragma (string const& p, tree decl, string const& decl_name)
tt = pragma_lex (&t);
}
- else if (p == "type")
+ else if (p == "type" ||
+ p == "value_type" ||
+ p == "index_type" ||
+ p == "key_type")
{
// type ("<type>")
+ // value_type ("<type>")
+ // index_type ("<type>")
+ // key_type ("<type>")
//
// Make sure we've got the correct declaration type.
@@ -459,7 +490,15 @@ handle_pragma_qualifier (string const& p)
else if (p == "id" ||
p == "auto" ||
p == "column" ||
+ p == "value_column" ||
+ p == "index_column" ||
+ p == "key_column" ||
+ p == "id_column" ||
p == "type" ||
+ p == "value_type" ||
+ p == "index_type" ||
+ p == "key_type" ||
+ p == "table" ||
p == "transient")
{
handle_pragma (p, 0, "");
@@ -534,12 +573,60 @@ handle_pragma_db_column (cpp_reader*)
}
extern "C" void
+handle_pragma_db_vcolumn (cpp_reader*)
+{
+ handle_pragma_qualifier ("value_column");
+}
+
+extern "C" void
+handle_pragma_db_icolumn (cpp_reader*)
+{
+ handle_pragma_qualifier ("index_column");
+}
+
+extern "C" void
+handle_pragma_db_kcolumn (cpp_reader*)
+{
+ handle_pragma_qualifier ("key_column");
+}
+
+extern "C" void
+handle_pragma_db_idcolumn (cpp_reader*)
+{
+ handle_pragma_qualifier ("id_column");
+}
+
+extern "C" void
handle_pragma_db_type (cpp_reader*)
{
handle_pragma_qualifier ("type");
}
extern "C" void
+handle_pragma_db_vtype (cpp_reader*)
+{
+ handle_pragma_qualifier ("value_type");
+}
+
+extern "C" void
+handle_pragma_db_itype (cpp_reader*)
+{
+ handle_pragma_qualifier ("index_type");
+}
+
+extern "C" void
+handle_pragma_db_ktype (cpp_reader*)
+{
+ handle_pragma_qualifier ("key_type");
+}
+
+extern "C" void
+handle_pragma_db_table (cpp_reader*)
+{
+ handle_pragma_qualifier ("table");
+}
+
+extern "C" void
handle_pragma_db_transient (cpp_reader*)
{
handle_pragma_qualifier ("transient");
@@ -554,6 +641,14 @@ register_odb_pragmas (void*, void*)
c_register_pragma_with_expansion ("db", "id", handle_pragma_db_id);
c_register_pragma_with_expansion ("db", "auto", handle_pragma_db_auto);
c_register_pragma_with_expansion ("db", "column", handle_pragma_db_column);
+ c_register_pragma_with_expansion ("db", "value_column", handle_pragma_db_vcolumn);
+ c_register_pragma_with_expansion ("db", "index_column", handle_pragma_db_icolumn);
+ c_register_pragma_with_expansion ("db", "key_column", handle_pragma_db_kcolumn);
+ c_register_pragma_with_expansion ("db", "id_column", handle_pragma_db_idcolumn);
c_register_pragma_with_expansion ("db", "type", handle_pragma_db_type);
+ c_register_pragma_with_expansion ("db", "value_type", handle_pragma_db_vtype);
+ c_register_pragma_with_expansion ("db", "index_type", handle_pragma_db_itype);
+ c_register_pragma_with_expansion ("db", "key_type", handle_pragma_db_ktype);
+ c_register_pragma_with_expansion ("db", "table", handle_pragma_db_table);
c_register_pragma_with_expansion ("db", "transient", handle_pragma_db_transient);
}
diff --git a/odb/tracer/header.cxx b/odb/tracer/header.cxx
index d9732de..eaa7546 100644
--- a/odb/tracer/header.cxx
+++ b/odb/tracer/header.cxx
@@ -28,8 +28,7 @@ namespace tracer
string const& type (c.fq_name ());
- id_member_.traverse (c);
- semantics::data_member& id (*id_member_.member ());
+ semantics::data_member& id (id_member (c));
bool auto_id (id.count ("auto"));
os << "// " << c.name () << endl
@@ -94,9 +93,6 @@ namespace tracer
os << "};";
}
-
- private:
- id_member id_member_;
};
}
diff --git a/odb/tracer/inline.cxx b/odb/tracer/inline.cxx
index 5efffff..2e73f21 100644
--- a/odb/tracer/inline.cxx
+++ b/odb/tracer/inline.cxx
@@ -29,9 +29,7 @@ namespace tracer
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
- id_member t;
- t.traverse (c);
- semantics::data_member& id (*t.member ());
+ semantics::data_member& id (id_member (c));
os << "// " << c.name () << endl
<< "//" << endl
diff --git a/odb/tracer/source.cxx b/odb/tracer/source.cxx
index 4cb4b32..338f2fb 100644
--- a/odb/tracer/source.cxx
+++ b/odb/tracer/source.cxx
@@ -29,8 +29,7 @@ namespace tracer
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
- id_member_.traverse (c);
- semantics::data_member& id (*id_member_.member ());
+ semantics::data_member& id (id_member (c));
bool auto_id (id.count ("auto"));
os << "// " << c.name () << endl
@@ -115,9 +114,6 @@ namespace tracer
<< "return true;"
<< "}";
}
-
- private:
- id_member id_member_;
};
}
diff --git a/odb/type-processor.cxx b/odb/type-processor.cxx
index c8e58a1..ff799b2 100644
--- a/odb/type-processor.cxx
+++ b/odb/type-processor.cxx
@@ -3,6 +3,8 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <odb/gcc.hxx>
+
#include <odb/type-processor.hxx>
namespace
@@ -12,10 +14,63 @@ namespace
data_member (context& c)
: context (c)
{
+ // Find the odb namespace.
+ //
+ tree odb = lookup_qualified_name (
+ global_namespace, get_identifier ("odb"), false, false);
+
+ if (odb == error_mark_node)
+ {
+ //@@ tmp
+ container_traits_ = 0;
+ return;
+
+ os << unit.file () << ": error: unable to resolve odb namespace"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ // Find the access class.
+ //
+ tree access = lookup_qualified_name (
+ odb, get_identifier ("access"), true, false);
+
+ if (access == error_mark_node)
+ {
+ //@@ tmp
+ container_traits_ = 0;
+ return;
+
+ os << unit.file () << ": error: unable to resolve access class"
+ << "in the odb namespace" << endl;
+
+ throw generation_failed ();
+ }
+
+ access = TREE_TYPE (access);
+
+ // Find container_traits.
+ //
+ container_traits_ = lookup_qualified_name (
+ access, get_identifier ("container_traits"), true, false);
+
+ if (container_traits_ == error_mark_node ||
+ !DECL_CLASS_TEMPLATE_P (container_traits_))
+ {
+ //@@ tmp
+ container_traits_ = 0;
+ return;
+
+ os << unit.file () << ": error: unable to resolve container_traits "
+ << "in the odb namespace" << endl;
+
+ throw generation_failed ();
+ }
}
virtual void
- traverse (type& m)
+ traverse (semantics::data_member& m)
{
if (m.count ("transient"))
return;
@@ -27,7 +82,15 @@ namespace
if (comp_value (t))
return;
- string const& type (column_type_impl (m));
+ string type;
+
+ if (m.count ("type"))
+ type = m.get<string> ("type");
+
+ if (type.empty () && t.count ("type"))
+ type = t.get<string> ("type");
+
+ type = column_type_impl (t, type, &m);
if (!type.empty ())
{
@@ -37,21 +100,299 @@ namespace
// See if this is a container type.
//
+ if (process_container (m))
+ return;
// If it is none of the above then we have an error.
//
string const& fq_type (t.fq_name (m.belongs ().hint ()));
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: unable to map C++ type '" << fq_type << "' used in "
- << "data member '" << m.name () << "' to a database type" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: unable to map C++ type '" << fq_type << "' used in "
+ << "data member '" << m.name () << "' to a database type" << endl;
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " info: use '#pragma db type' to specify the database type"
- << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " info: use '#pragma db type' to specify the database type"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ void
+ process_container_value (semantics::type& t,
+ string const& prefix,
+ semantics::data_member& m)
+ {
+ if (comp_value (t))
+ return;
+
+ string type;
+
+ // Custom mapping can come from these places (listed in the order
+ // of priority): member, container type, value type.
+ //
+ if (m.count (prefix + "-type"))
+ type = m.get<string> (prefix + "-type");
+
+ semantics::type& ct (m.type ());
+
+ if (type.empty () && ct.count (prefix + "-type"))
+ type = ct.get<string> (prefix + "-type");
+
+ if (type.empty () && t.count ("type"))
+ type = t.get<string> ("type");
+
+ type = column_type_impl (t, type, 0);
+
+ if (!type.empty ())
+ {
+ m.set (prefix + "-column-type", type);
+ return;
+ }
+
+ // We do not support nested containers so skip that test.
+ //
+
+ // If it is none of the above then we have an error.
+ //
+ string fq_type (t.fq_anonymous () ? "<anonymous>" : t.fq_name ());
+
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: unable to map C++ type '" << fq_type << "' used in "
+ << "data member '" << m.name () << "' to a database type" << endl;
+
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " info: use '#pragma db " << prefix << "_type' to specify the "
+ << "database type" << endl;
throw generation_failed ();
}
+
+ bool
+ process_container (semantics::data_member& m)
+ {
+ // @@ tmp
+ //
+ if (container_traits_ == 0)
+ return false;
+
+ // The overall idea is as follows: try to instantiate the container
+ // traits class template. If we are successeful, then this is a
+ // container type and we can extract the various information from
+ // the instantiation. Otherwise, this is not a container.
+ //
+
+ semantics::type& t (m.type ());
+
+ container_kind_type ck;
+ semantics::type* vt (0);
+ semantics::type* it (0);
+ semantics::type* kt (0);
+
+ if (t.count ("container"))
+ {
+ ck = t.get<container_kind_type> ("container-kind");
+ vt = t.get<semantics::type*> ("tree-value-type");
+
+ if (ck == ck_ordered)
+ it = t.get<semantics::type*> ("tree-index-type");
+
+ if (ck == ck_map || ck == ck_multimap)
+ kt = t.get<semantics::type*> ("tree-key-type");
+ }
+ else
+ {
+ tree args (make_tree_vec (1));
+ TREE_VEC_ELT (args, 0) = t.tree_node ();
+
+ // This step should succeed regardles of whether there is a
+ // container traits specialization for this type.
+ //
+ tree inst (
+ lookup_template_class (
+ container_traits_, args, 0, 0, 0, tf_warning_or_error));
+
+ if (inst == error_mark_node)
+ {
+ // Diagnostics has already been issued by lookup_template_class.
+ //
+ throw generation_failed ();
+ }
+
+ inst = TYPE_MAIN_VARIANT (inst);
+
+ // The instantiation may already be complete if it matches a
+ // (complete) specialization.
+ //
+ if (!COMPLETE_TYPE_P (inst))
+ inst = instantiate_class_template (inst);
+
+ // If we cannot instantiate this type, assume there is no suitable
+ // container traits specialization for it.
+ //
+ if (inst == error_mark_node || !COMPLETE_TYPE_P (inst))
+ return false;
+
+ // @@ This points to the primary template, not the specialization.
+ //
+ tree decl (TYPE_NAME (inst));
+
+ string f (DECL_SOURCE_FILE (decl));
+ size_t l (DECL_SOURCE_LINE (decl));
+ size_t c (DECL_SOURCE_COLUMN (decl));
+
+
+ // Determine the container kind.
+ //
+ try
+ {
+ tree kind (
+ lookup_qualified_name (
+ inst, get_identifier ("kind"), false, false));
+
+ if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL)
+ throw generation_failed ();
+
+
+ // Instantiate this decalaration so that we can get its value.
+ //
+ if (DECL_TEMPLATE_INSTANTIATION (kind) &&
+ !DECL_TEMPLATE_INSTANTIATED (kind) &&
+ !DECL_EXPLICIT_INSTANTIATION (kind))
+ instantiate_decl (kind, false, false);
+
+ tree init (DECL_INITIAL (kind));
+
+ if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST)
+ throw generation_failed ();
+
+ unsigned long long e;
+
+ {
+ HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init));
+ HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init));
+
+ unsigned long long l (hwl);
+ unsigned long long h (hwh);
+ unsigned short width (HOST_BITS_PER_WIDE_INT);
+
+ e = (h << width) + l;
+ }
+
+ ck = static_cast<container_kind_type> (e);
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "odb::container_traits specialization does not define the "
+ << "container kind constant" << endl;
+
+ throw;
+ }
+
+ t.set ("container-kind", ck);
+
+ // Get the value type.
+ //
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("value_type"), true, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
+ throw generation_failed ();
+
+ tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+
+ vt = &dynamic_cast<semantics::type&> (*unit.find (type));
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "odb::container_traits specialization does not define the "
+ << "value_type type" << endl;
+
+ throw;
+ }
+
+ t.set ("tree-value-type", vt);
+
+
+ // Get the index type for ordered containers.
+ //
+ if (ck == ck_ordered)
+ {
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("index_type"), true, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
+ throw generation_failed ();
+
+ tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+
+ it = &dynamic_cast<semantics::type&> (*unit.find (type));
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "odb::container_traits specialization does not define the "
+ << "index_type type" << endl;
+
+ throw;
+ }
+
+ t.set ("tree-index-type", it);
+ }
+
+ // Get the key type for maps.
+ //
+ if (ck == ck_map || ck == ck_multimap)
+ {
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("key_type"), true, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
+ throw generation_failed ();
+
+ tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+
+ kt = &dynamic_cast<semantics::type&> (*unit.find (type));
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "odb::container_traits specialization does not define the "
+ << "key_type type" << endl;
+
+ throw;
+ }
+
+ t.set ("tree-key-type", kt);
+ }
+ }
+
+ // Process member data.
+ //
+ process_container_value (*vt, "value", m);
+
+ if (it != 0)
+ process_container_value (*it, "index", m);
+
+ if (kt != 0)
+ process_container_value (*kt, "key", m);
+
+ return true;
+ }
+
+ private:
+ tree container_traits_;
};
struct class_: traversal::class_, context