summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-10-27 17:36:59 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-10-27 17:36:59 +0200
commit7f6c64f2211d37db76a97fbc79a4b5492302ef2f (patch)
treef2e386644fcaab5c51e3f5ad0ac737ea5b4d5bd2
parent5259b98c75f3754a0f713bcee4bddd0ed7ce35ef (diff)
Implement support for composite value types
New test: common/composite.
-rw-r--r--odb/common.cxx64
-rw-r--r--odb/common.hxx50
-rw-r--r--odb/context.cxx82
-rw-r--r--odb/context.hxx41
-rw-r--r--odb/generator.cxx26
-rw-r--r--odb/header.cxx108
-rw-r--r--odb/header.hxx14
-rw-r--r--odb/include.cxx8
-rw-r--r--odb/inline.cxx97
-rw-r--r--odb/inline.hxx14
-rw-r--r--odb/makefile3
-rw-r--r--odb/mysql/common.cxx265
-rw-r--r--odb/mysql/common.hxx65
-rw-r--r--odb/mysql/context.cxx107
-rw-r--r--odb/mysql/context.hxx10
-rw-r--r--odb/mysql/header.cxx146
-rw-r--r--odb/mysql/inline.cxx44
-rw-r--r--odb/mysql/schema.cxx27
-rw-r--r--odb/mysql/source.cxx527
-rw-r--r--odb/tracer/header.cxx4
-rw-r--r--odb/validator.cxx72
21 files changed, 1370 insertions, 404 deletions
diff --git a/odb/common.cxx b/odb/common.cxx
new file mode 100644
index 0000000..f398b6e
--- /dev/null
+++ b/odb/common.cxx
@@ -0,0 +1,64 @@
+// file : odb/common.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/common.hxx>
+
+using namespace std;
+
+//
+// object_columns_base
+//
+
+void object_columns_base::
+composite (semantics::data_member& m)
+{
+ dispatch (m.type ());
+}
+
+void object_columns_base::
+traverse (semantics::class_& c)
+{
+ inherits (c);
+ names (c);
+}
+
+void object_columns_base::member::
+traverse (semantics::data_member& m)
+{
+ if (m.count ("transient"))
+ return;
+
+ if (comp_value (m.type ()))
+ {
+ string old_prefix (prefix_);
+
+ bool custom (m.count ("column"));
+ string name (column_name (m));
+
+ // If the user provided the column prefix, then use it verbatime.
+ // Otherwise, append the underscore, unless it is already there.
+ //
+ prefix_ += name;
+
+ if (!custom)
+ {
+ size_t n (name.size ());
+
+ if (n != 0 && name[n - 1] != '_')
+ prefix_ += '_';
+ }
+
+ oc_.composite (m);
+
+ prefix_ = old_prefix;
+ }
+ else
+ {
+ oc_.column (m, prefix_ + column_name (m), first_);
+
+ if (first_)
+ first_ = false;
+ }
+}
diff --git a/odb/common.hxx b/odb/common.hxx
index 952a7dd..dcfe87f 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -6,7 +6,9 @@
#ifndef ODB_COMMON_HXX
#define ODB_COMMON_HXX
+#include <string>
#include <cstddef> // std::size_t
+
#include <odb/context.hxx>
// Find id member.
@@ -48,43 +50,49 @@ private:
traversal::names names_;
};
-// Count persistent members.
+// Traverse object columns.
//
-struct member_count: traversal::class_
+struct object_columns_base: traversal::class_
{
- member_count ()
- {
- *this >> names_ >> member_;
- }
+ virtual void
+ column (semantics::data_member&, std::string const& name, bool first) = 0;
- std::size_t
- count () const
+ // If you override this callback, always call the base.
+ //
+ virtual void
+ composite (semantics::data_member&);
+
+ object_columns_base (context& c)
+ : member_ (c, *this)
{
- return member_.count_;
+ *this >> names_ >> member_;
+ *this >> inherits_ >> *this;
}
virtual void
- traverse (semantics::class_& c)
- {
- member_.count_ = 0;
- names (c);
- }
+ traverse (semantics::class_&);
private:
- struct data_member: traversal::data_member
+ struct member: traversal::data_member, context
{
- virtual void
- traverse (semantics::data_member& m)
+ member (context& c, object_columns_base& oc)
+ : context (c), oc_ (oc), first_ (true)
{
- if (!m.count ("transient"))
- count_++;
}
- std::size_t count_;
+ virtual void
+ traverse (semantics::data_member&);
+
+ private:
+ object_columns_base& oc_;
+
+ string prefix_;
+ bool first_;
};
- data_member member_;
+ member member_;
traversal::names names_;
+ traversal::inherits inherits_;
};
#endif // ODB_COMMON_HXX
diff --git a/odb/context.cxx b/odb/context.cxx
index 236c0c0..c578cd9 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -119,8 +119,8 @@ context::
{
}
-string context::
-public_name (semantics::data_member& m) const
+static string
+public_name_impl (semantics::data_member& m)
{
string s (m.name ());
size_t n (s.size ());
@@ -153,7 +153,7 @@ table_name (semantics::type& t) const
string context::
column_name (semantics::data_member& m) const
{
- return m.count ("column") ? m.get<string> ("column") : public_name (m);
+ return m.count ("column") ? m.get<string> ("column") : public_name_impl (m);
}
string context::
@@ -188,6 +188,12 @@ column_type (semantics::data_member& m) const
}
string context::
+public_name (semantics::data_member& m) const
+{
+ return escape (public_name_impl (m));
+}
+
+string context::
escape (string const& name) const
{
typedef string::size_type size;
@@ -261,6 +267,76 @@ escape (string const& name) const
return r;
}
+namespace
+{
+ struct column_count_impl: traversal::class_
+ {
+ column_count_impl ()
+ : member_ (*this)
+ {
+ *this >> names_ >> member_;
+ *this >> inherits_ >> *this;
+ }
+
+ size_t
+ count () const
+ {
+ return member_.count_;
+ }
+
+ virtual void
+ traverse (semantics::class_& c)
+ {
+ if (c.count ("column-count"))
+ member_.count_ += c.get<size_t> ("column-count");
+ else
+ {
+ size_t n (member_.count_);
+ inherits (c);
+ names (c);
+ c.set ("column-count", member_.count_ - n);
+ }
+ }
+
+ private:
+ struct member: traversal::data_member
+ {
+ member (column_count_impl& cc): count_ (0), cc_ (cc) {}
+
+ virtual void
+ traverse (semantics::data_member& m)
+ {
+ if (m.count ("transient"))
+ return;
+
+ if (context::comp_value (m.type ()))
+ cc_.dispatch (m.type ());
+ else
+ count_++;
+ }
+
+ size_t count_;
+ column_count_impl& cc_;
+ };
+
+ member member_;
+ traversal::names names_;
+
+ traversal::inherits inherits_;
+ };
+}
+
+size_t context::
+column_count (semantics::class_& c)
+{
+ if (c.count ("column-count"))
+ return c.get<size_t> ("column-count");
+
+ column_count_impl t;
+ t.traverse (c);
+ return t.count ();
+}
+
// namespace
//
diff --git a/odb/context.hxx b/odb/context.hxx
index ac83736..b8a33c5 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -32,15 +32,33 @@ public:
typedef std::string string;
typedef ::options options_type;
- // Database names and types.
+ // Predicates.
//
public:
- // Cleaned-up member name that can be used in public interfaces
- // such as queries, column names, etc.
+
+ // 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).
//
- string
- public_name (semantics::data_member&) const;
+ static bool
+ comp_value (semantics::class_& c)
+ {
+ return c.count ("value") && !c.count ("type");
+ }
+ // Return the class object if this type is a composite value type
+ // and NULL otherwise.
+ //
+ static semantics::class_*
+ comp_value (semantics::type& t)
+ {
+ semantics::class_* c (dynamic_cast<semantics::class_*> (&t));
+ return c != 0 && t.count ("value") && !t.count ("type") ? c : 0;
+ }
+
+ // Database names and types.
+ //
+public:
string
table_name (semantics::type&) const;
@@ -50,12 +68,25 @@ public:
virtual string
column_type (semantics::data_member&) const;
+ // C++ names.
+ //
public:
+ // Cleaned-up member name that can be used in public interfaces.
+ //
+ string
+ public_name (semantics::data_member&) const;
+
// Escape C++ keywords, reserved names, and illegal characters.
//
string
escape (string const&) const;
+ // Counts and other information.
+ //
+public:
+ static size_t
+ column_count (semantics::class_&);
+
protected:
struct data;
typedef cutl::shared_ptr<data> data_ptr;
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 3205e7e..5d8c47c 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -19,6 +19,8 @@
#include <odb/generator.hxx>
#include <odb/include.hxx>
+#include <odb/header.hxx>
+#include <odb/inline.hxx>
#include <odb/tracer/header.hxx>
#include <odb/tracer/inline.hxx>
@@ -261,6 +263,7 @@ generate (options const& ops, semantics::unit& unit, path const& p)
<< endl;
generate_include (*ctx);
+ generate_header (*ctx);
switch (ops.database ())
{
@@ -299,6 +302,21 @@ generate (options const& ops, semantics::unit& unit, path const& p)
//
{
cxx_filter filt (ixx);
+ auto_ptr<context> ctx;
+
+ switch (ops.database ())
+ {
+ case database::mysql:
+ {
+ ctx.reset (new mysql::context (ixx, unit, ops));
+ break;
+ }
+ case database::tracer:
+ {
+ ctx.reset (new context (ixx, unit, ops));
+ break;
+ }
+ }
// Copy prologue.
//
@@ -309,18 +327,18 @@ generate (options const& ops, semantics::unit& unit, path const& p)
<< "// End prologue." << endl
<< endl;
+ generate_inline (*ctx);
+
switch (ops.database ())
{
case database::mysql:
{
- mysql::context ctx (ixx, unit, ops);
- mysql::generate_inline (ctx);
+ mysql::generate_inline (static_cast<mysql::context&> (*ctx));
break;
}
case database::tracer:
{
- context ctx (ixx, unit, ops);
- tracer::generate_inline (ctx);
+ tracer::generate_inline (*ctx);
break;
}
}
diff --git a/odb/header.cxx b/odb/header.cxx
new file mode 100644
index 0000000..9c816d8
--- /dev/null
+++ b/odb/header.cxx
@@ -0,0 +1,108 @@
+// file : odb/header.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/common.hxx>
+#include <odb/header.hxx>
+
+namespace
+{
+ struct data_member: traversal::data_member, context
+ {
+ data_member (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (semantics::data_member& m)
+ {
+ if (m.count ("transient"))
+ return;
+
+ string const& name (public_name (m));
+ string const& type (m.type ().fq_name (m.belongs ().hint ()));
+
+ os << "static " << type << "&" << endl
+ << name << " (value_type&);"
+ << endl;
+
+ os << "static const " << type << "&" << endl
+ << name << " (const value_type&);"
+ << endl;
+ }
+ };
+
+ struct class_: traversal::class_, context
+ {
+ class_ (context& c)
+ : context (c), member_ (c)
+ {
+ member_names_ >> member_;
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.file () != unit.file ())
+ return;
+
+ if (!comp_value (c))
+ return;
+
+ string const& type (c.fq_name ());
+
+ os << "// " << c.name () << endl
+ << "//" << endl;
+
+ os << "template <>" << endl
+ << "class access::value_traits< " << type << " >"
+ << "{"
+ << "public:" << endl;
+
+ // value_type
+ //
+ os << "typedef " << type << " value_type;"
+ << endl;
+
+ names (c, member_names_);
+
+ os << "};";
+ }
+
+ private:
+ data_member member_;
+ traversal::names member_names_;
+ };
+}
+
+void
+generate_header (context& ctx)
+{
+ ctx.os << "#include <odb/core.hxx>" << endl
+ << "#include <odb/traits.hxx>" << endl
+ << endl;
+
+ /*
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ ctx.os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ ctx.os << "}";
+ */
+}
diff --git a/odb/header.hxx b/odb/header.hxx
new file mode 100644
index 0000000..da5d830
--- /dev/null
+++ b/odb/header.hxx
@@ -0,0 +1,14 @@
+// file : odb/header.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_HEADER_HXX
+#define ODB_HEADER_HXX
+
+#include <odb/context.hxx>
+
+void
+generate_header (context&);
+
+#endif // ODB_HEADER_HXX
diff --git a/odb/include.cxx b/odb/include.cxx
index a56d577..c9da8b2 100644
--- a/odb/include.cxx
+++ b/odb/include.cxx
@@ -74,11 +74,13 @@ namespace
if (c.file () == unit.file ())
return;
- if (!(c.count ("object") || c.count ("value")))
+ // We only generate things for objects and composite value types.
+ //
+ if (!(c.count ("object") || comp_value (c)))
return;
- // This is a persistent object or value type declared in another
- // header file. Include its -odb header.
+ // This is a persistent object or composite value type declared in
+ // another header file. Include its -odb header.
//
tree decl (TYPE_NAME (c.tree_node ()));
location_t l (DECL_SOURCE_LOCATION (decl));
diff --git a/odb/inline.cxx b/odb/inline.cxx
new file mode 100644
index 0000000..630cf1b
--- /dev/null
+++ b/odb/inline.cxx
@@ -0,0 +1,97 @@
+// file : odb/inline.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/common.hxx>
+#include <odb/inline.hxx>
+
+namespace
+{
+ struct data_member: traversal::data_member, context
+ {
+ data_member (context& c, semantics::class_& cl)
+ : context (c)
+ {
+ scope_ = "access::value_traits< " + cl.fq_name () + " >";
+ }
+
+ virtual void
+ traverse (semantics::data_member& m)
+ {
+ if (m.count ("transient"))
+ return;
+
+ string const& name (public_name (m));
+ string const& type (m.type ().fq_name (m.belongs ().hint ()));
+
+ os << "inline" << endl
+ << type << "& " << scope_ << "::" << endl
+ << name << " (value_type& v)"
+ << "{"
+ << "return v." << m.name () << ";"
+ << "}";
+
+ os << "inline" << endl
+ << "const " << type << "& " << scope_ << "::" << endl
+ << name << " (const value_type& v)"
+ << "{"
+ << "return v." << m.name () << ";"
+ << "}";
+ }
+
+ private:
+ string scope_;
+ };
+
+ struct class_: traversal::class_, context
+ {
+ class_ (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.file () != unit.file ())
+ return;
+
+ if (!comp_value (c))
+ return;
+
+ os << "// " << c.name () << endl
+ << "//" << endl;
+
+ data_member member (*this, c);
+ traversal::names member_names (member);
+ names (c, member_names);
+ }
+ };
+}
+
+void
+generate_inline (context& /*ctx*/)
+{
+ /*
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ traversal::namespace_ ns;
+ class_ c (ctx);
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+
+ traversal::defines ns_defines;
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+
+ ctx.os << "namespace odb"
+ << "{";
+
+ unit.dispatch (ctx.unit);
+
+ ctx.os << "}";
+ */
+}
diff --git a/odb/inline.hxx b/odb/inline.hxx
new file mode 100644
index 0000000..41daac6
--- /dev/null
+++ b/odb/inline.hxx
@@ -0,0 +1,14 @@
+// file : odb/inline.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_INLINE_HXX
+#define ODB_INLINE_HXX
+
+#include <odb/context.hxx>
+
+void
+generate_inline (context&);
+
+#endif // ODB_INLINE_HXX
diff --git a/odb/makefile b/odb/makefile
index 381e44c..c6cec8c 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -10,7 +10,10 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
cxx_ptun := \
sql-lexer.cxx \
context.cxx \
+common.cxx \
include.cxx \
+header.cxx \
+inline.cxx \
validator.cxx \
generator.cxx \
parser.cxx \
diff --git a/odb/mysql/common.cxx b/odb/mysql/common.cxx
index 284a80e..372d08e 100644
--- a/odb/mysql/common.cxx
+++ b/odb/mysql/common.cxx
@@ -3,6 +3,8 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <cassert>
+
#include <odb/mysql/common.hxx>
using namespace std;
@@ -25,109 +27,114 @@ namespace mysql
pre (m);
- sql_type const& t (db_type (m));
-
- switch (t.type)
+ if (comp_value (m.type ()))
+ traverse_composite (m);
+ else
{
- // Integral types.
- //
- case sql_type::TINYINT:
- case sql_type::SMALLINT:
- case sql_type::MEDIUMINT:
- case sql_type::INT:
- case sql_type::BIGINT:
- {
- traverse_integer (m, t);
- break;
- }
+ sql_type const& t (db_type (m));
- // Float types.
- //
- case sql_type::FLOAT:
- case sql_type::DOUBLE:
- {
- traverse_float (m, t);
- break;
- }
- case sql_type::DECIMAL:
+ switch (t.type)
{
- traverse_decimal (m, t);
- break;
- }
-
- // Data-time types.
- //
- case sql_type::DATE:
- case sql_type::TIME:
- case sql_type::DATETIME:
- case sql_type::TIMESTAMP:
- case sql_type::YEAR:
- {
- traverse_date_time (m, t);
- break;
- }
-
- // String and binary types.
- //
- case sql_type::CHAR:
- case sql_type::VARCHAR:
- case sql_type::TINYTEXT:
- case sql_type::TEXT:
- case sql_type::MEDIUMTEXT:
- case sql_type::LONGTEXT:
- {
- // For string types the limit is in characters rather
- // than in bytes. The fixed-length pre-allocated buffer
- // optimization can only be used for 1-byte encodings.
- // To support this we will need the character encoding
- // in sql_type.
+ // Integral types.
//
- traverse_long_string (m, t);
- break;
- }
- case sql_type::BINARY:
- case sql_type::TINYBLOB:
- {
- // BINARY's range is always 255 or less from MySQL 5.0.3.
- // TINYBLOB can only store up to 255 bytes.
+ case sql_type::TINYINT:
+ case sql_type::SMALLINT:
+ case sql_type::MEDIUMINT:
+ case sql_type::INT:
+ case sql_type::BIGINT:
+ {
+ traverse_integer (m, t);
+ break;
+ }
+
+ // Float types.
//
- traverse_short_string (m, t);
- break;
- }
- case sql_type::VARBINARY:
- case sql_type::BLOB:
- case sql_type::MEDIUMBLOB:
- case sql_type::LONGBLOB:
- {
- if (t.range && t.range_value <= 255)
- traverse_short_string (m, t);
- else
+ case sql_type::FLOAT:
+ case sql_type::DOUBLE:
+ {
+ traverse_float (m, t);
+ break;
+ }
+ case sql_type::DECIMAL:
+ {
+ traverse_decimal (m, t);
+ break;
+ }
+
+ // Data-time types.
+ //
+ case sql_type::DATE:
+ case sql_type::TIME:
+ case sql_type::DATETIME:
+ case sql_type::TIMESTAMP:
+ case sql_type::YEAR:
+ {
+ traverse_date_time (m, t);
+ break;
+ }
+
+ // String and binary types.
+ //
+ case sql_type::CHAR:
+ case sql_type::VARCHAR:
+ case sql_type::TINYTEXT:
+ case sql_type::TEXT:
+ case sql_type::MEDIUMTEXT:
+ case sql_type::LONGTEXT:
+ {
+ // For string types the limit is in characters rather
+ // than in bytes. The fixed-length pre-allocated buffer
+ // optimization can only be used for 1-byte encodings.
+ // To support this we will need the character encoding
+ // in sql_type.
+ //
traverse_long_string (m, t);
-
- break;
- }
-
- // Other types.
- //
- case sql_type::BIT:
- {
- traverse_bit (m, t);
- break;
- }
- case sql_type::ENUM:
- {
- traverse_enum (m, t);
- break;
- }
- case sql_type::SET:
- {
- traverse_set (m, t);
- break;
- }
- case sql_type::invalid:
- {
- assert (false);
- break;
+ break;
+ }
+ case sql_type::BINARY:
+ case sql_type::TINYBLOB:
+ {
+ // BINARY's range is always 255 or less from MySQL 5.0.3.
+ // TINYBLOB can only store up to 255 bytes.
+ //
+ traverse_short_string (m, t);
+ break;
+ }
+ case sql_type::VARBINARY:
+ case sql_type::BLOB:
+ case sql_type::MEDIUMBLOB:
+ case sql_type::LONGBLOB:
+ {
+ if (t.range && t.range_value <= 255)
+ traverse_short_string (m, t);
+ else
+ traverse_long_string (m, t);
+
+ break;
+ }
+
+ // Other types.
+ //
+ case sql_type::BIT:
+ {
+ traverse_bit (m, t);
+ break;
+ }
+ case sql_type::ENUM:
+ {
+ traverse_enum (m, t);
+ break;
+ }
+ case sql_type::SET:
+ {
+ traverse_set (m, t);
+ break;
+ }
+ case sql_type::invalid:
+ {
+ assert (false);
+ break;
+ }
}
}
@@ -171,6 +178,13 @@ namespace mysql
}
void member_image_type::
+ traverse_composite (type& m)
+ {
+ type_ = "composite_value_traits< " + m.type ().fq_name () +
+ " >::image_type";
+ }
+
+ void member_image_type::
traverse_integer (type&, sql_type const& t)
{
if (t.unsign)
@@ -297,6 +311,12 @@ namespace mysql
}
void member_database_type::
+ traverse_composite (type&)
+ {
+ assert (false);
+ }
+
+ void member_database_type::
traverse_integer (type&, sql_type const& t)
{
size_t i ((t.type - sql_type::TINYINT) * 2 + (t.unsign ? 1 : 0));
@@ -346,21 +366,23 @@ namespace mysql
}
//
- // query_column
+ // query_columns
//
- query_column::
- query_column (context& c)
- : context (c),
+ query_columns::
+ query_columns (context& c)
+ : object_columns_base (c),
+ context (c),
decl_ (true),
member_image_type_ (c, false),
member_database_type_ (c)
{
}
- query_column::
- query_column (context& c, semantics::class_& cl)
- : context (c),
+ query_columns::
+ query_columns (context& c, semantics::class_& cl)
+ : object_columns_base (c),
+ context (c),
decl_ (false),
member_image_type_ (c, false),
member_database_type_ (c)
@@ -369,10 +391,37 @@ namespace mysql
table_ = table_name (cl);
}
- void query_column::
- traverse (type& m)
+ void query_columns::
+ composite (semantics::data_member& m)
+ {
+ string name (public_name (m));
+
+ if (decl_)
+ {
+ os << "// " << name << endl
+ << "//" << endl
+ << "struct " << name
+ << "{";
+
+ object_columns_base::composite (m);
+
+ os << "};";
+ }
+ else
+ {
+ string old_scope (scope_);
+ scope_ += "::" + name;
+
+ object_columns_base::composite (m);
+
+ scope_ = old_scope;
+ }
+ }
+
+ void query_columns::
+ column (semantics::data_member& m, string const& col_name, bool)
{
- string name (escape (public_name (m)));
+ string name (public_name (m));
string db_type (member_database_type_.database_type (m));
string type (
@@ -394,7 +443,7 @@ namespace mysql
}
else
{
- string column ("\"`" + table_ + "`.`" + column_name (m) + "`\"");
+ string column ("\"`" + table_ + "`.`" + col_name + "`\"");
os << "const mysql::query_column<" << endl
<< " " << type << "," << endl
diff --git a/odb/mysql/common.hxx b/odb/mysql/common.hxx
index c689bb6..83fa998 100644
--- a/odb/mysql/common.hxx
+++ b/odb/mysql/common.hxx
@@ -32,6 +32,11 @@ namespace mysql
}
virtual void
+ traverse_composite (type&)
+ {
+ }
+
+ virtual void
traverse_integer (type&, sql_type const&)
{
}
@@ -96,6 +101,9 @@ namespace mysql
image_type (type&);
virtual void
+ traverse_composite (type&);
+
+ virtual void
traverse_integer (type&, sql_type const&);
virtual void
@@ -131,6 +139,9 @@ namespace mysql
database_type (type&);
virtual void
+ traverse_composite (type&);
+
+ virtual void
traverse_integer (type&, sql_type const&);
virtual void
@@ -158,60 +169,16 @@ namespace mysql
string type_;
};
- struct has_grow_member: member_base
+ struct query_columns: object_columns_base, context
{
- has_grow_member (context& c)
- : member_base (c, false), r_ (false)
- {
- }
-
- bool
- result ()
- {
- return r_;
- }
-
- virtual void
- traverse_decimal (type&, sql_type const&)
- {
- r_ = true;
- }
+ query_columns (context&);
+ query_columns (context&, semantics::class_&);
virtual void
- traverse_long_string (type&, sql_type const&)
- {
- r_ = true;
- }
-
- virtual void
- traverse_short_string (type&, sql_type const&)
- {
- r_ = true; // @@ Short string optimization disabled.
- }
-
- virtual void
- traverse_enum (type&, sql_type const&)
- {
- r_ = true;
- }
-
- virtual void
- traverse_set (type&, sql_type const&)
- {
- r_ = true;
- }
-
- private:
- bool r_;
- };
-
- struct query_column: traversal::data_member, context
- {
- query_column (context&);
- query_column (context&, semantics::class_&);
+ composite (semantics::data_member&);
virtual void
- traverse (type&);
+ column (semantics::data_member&, string const&, bool);
private:
string scope_;
diff --git a/odb/mysql/context.cxx b/odb/mysql/context.cxx
index 7665ed6..f33916e 100644
--- a/odb/mysql/context.cxx
+++ b/odb/mysql/context.cxx
@@ -9,6 +9,7 @@
#include <odb/sql-lexer.hxx>
#include <odb/mysql/context.hxx>
+#include <odb/mysql/common.hxx>
using namespace std;
@@ -76,6 +77,112 @@ namespace mysql
{
}
+ namespace
+ {
+ struct has_grow: traversal::class_
+ {
+ has_grow (context& c)
+ : member_ (c, *this)
+ {
+ *this >> member_names_ >> member_;
+ *this >> inherits_ >> *this;
+ }
+
+ bool
+ dispatch (semantics::type& t)
+ {
+ r_ = false;
+ traversal::class_::dispatch (t);
+ return r_;
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ if (c.count ("mysql::grow"))
+ r_ = c.get<bool> ("mysql::grow");
+ else
+ {
+ // r_ should be false.
+ //
+ inherits (c);
+
+ if (!r_)
+ names (c);
+
+ c.set ("mysql::grow", r_);
+ }
+ }
+
+ private:
+ struct member: member_base
+ {
+ member (context& c, has_grow& hg) : member_base (c, false), hg_ (hg) {}
+
+ virtual void
+ traverse_composite (type& m)
+ {
+ if (!hg_.r_)
+ hg_.r_ = hg_.dispatch (m.type ());
+ }
+
+ virtual void
+ traverse_decimal (type&, sql_type const&)
+ {
+ hg_.r_ = true;
+ }
+
+ virtual void
+ traverse_long_string (type&, sql_type const&)
+ {
+ hg_.r_ = true;
+ }
+
+ virtual void
+ traverse_short_string (type&, sql_type const&)
+ {
+ hg_.r_ = true; // @@ Short string optimization disabled.
+ }
+
+ virtual void
+ traverse_enum (type&, sql_type const&)
+ {
+ hg_.r_ = true;
+ }
+
+ virtual void
+ traverse_set (type&, sql_type const&)
+ {
+ hg_.r_ = true;
+ }
+
+ private:
+ has_grow& hg_;
+ };
+
+ bool r_;
+
+ member member_;
+ traversal::names member_names_;
+
+ traversal::inherits inherits_;
+ };
+ }
+
+ bool context::
+ grow (semantics::class_& c)
+ {
+ if (c.count ("mysql::grow"))
+ return c.get<bool> ("mysql::grow");
+
+ has_grow t (*this);
+ return t.dispatch (c);
+ }
+
+ //
+ // SQL type parsing.
+ //
+
string context::
column_type (semantics::data_member& m) const
{
diff --git a/odb/mysql/context.hxx b/odb/mysql/context.hxx
index c4615e8..266d38f 100644
--- a/odb/mysql/context.hxx
+++ b/odb/mysql/context.hxx
@@ -76,6 +76,16 @@ namespace mysql
class context: public ::context
{
+ // Predicates.
+ //
+ public:
+
+ // Return true if an object or value type has members for which
+ // the image can grow.
+ //
+ bool
+ grow (semantics::class_&);
+
private:
typedef ::context base_context;
diff --git a/odb/mysql/header.cxx b/odb/mysql/header.cxx
index cc13264..2544ff3 100644
--- a/odb/mysql/header.cxx
+++ b/odb/mysql/header.cxx
@@ -30,6 +30,13 @@ namespace mysql
}
virtual void
+ traverse_composite (type&)
+ {
+ os << image_type << " " << var << "value;"
+ << endl;
+ }
+
+ virtual void
traverse_integer (type&, sql_type const&)
{
os << image_type << " " << var << "value;"
@@ -140,19 +147,51 @@ namespace mysql
member_image_type member_image_type_;
};
+ struct image_base: traversal::class_, context
+ {
+ image_base (context& c): context (c), first_ (true) {}
+
+ virtual void
+ traverse (type& c)
+ {
+ if (first_)
+ {
+ os << ": ";
+ first_ = false;
+ }
+ else
+ {
+ os << "," << endl
+ << " ";
+ }
+
+ os << "composite_value_traits< " << c.fq_name () << " >::image_type";
+ }
+
+ private:
+ bool first_;
+ };
+
struct image_type: traversal::class_, context
{
image_type (context& c)
- : context (c), image_member_ (c, false)
+ : context (c), member_ (c, false)
{
- *this >> names_image_member_ >> image_member_;
+ *this >> names_member_ >> member_;
}
virtual void
traverse (type& c)
{
- os << "struct image_type"
- << "{";
+ os << "struct image_type";
+
+ {
+ image_base b (*this);
+ traversal::inherits i (b);
+ inherits (c, i);
+ }
+
+ os << "{";
names (c);
@@ -160,8 +199,8 @@ namespace mysql
}
private:
- image_member image_member_;
- traversal::names names_image_member_;
+ image_member member_;
+ traversal::names names_member_;
};
struct id_image_type: traversal::class_, context
@@ -193,10 +232,8 @@ namespace mysql
class_ (context& c)
: context (c),
image_type_ (c),
- id_image_type_ (c),
- query_column_ (c)
+ id_image_type_ (c)
{
- *this >> query_column_names_ >> query_column_;
}
virtual void
@@ -205,9 +242,15 @@ namespace mysql
if (c.file () != unit.file ())
return;
- if (!c.count ("object"))
- return;
+ if (c.count ("object"))
+ traverse_object (c);
+ else if (comp_value (c))
+ traverse_value (c);
+ }
+ virtual void
+ traverse_object (type& c)
+ {
string const& type (c.fq_name ());
bool def_ctor (TYPE_HAS_DEFAULT_CONSTRUCTOR (c.tree_node ()));
@@ -215,9 +258,6 @@ namespace mysql
semantics::data_member& id (*id_member_.member ());
bool auto_id (id.count ("auto"));
- member_count_.traverse (c);
- size_t column_count (member_count_.count ());
-
os << "// " << c.name () << endl
<< "//" << endl;
@@ -260,7 +300,10 @@ namespace mysql
os << "struct query_type: query_base_type"
<< "{";
- names (c, query_column_names_);
+ {
+ query_columns t (*this);
+ t.traverse (c);
+ }
os << "query_type ();"
<< "query_type (const std::string&);"
@@ -270,8 +313,8 @@ namespace mysql
// column_count
//
- os << "static const std::size_t column_count = " << column_count <<
- "UL;"
+ os << "static const std::size_t column_count = " <<
+ column_count (c) << "UL;"
<< endl;
// Queries.
@@ -301,13 +344,13 @@ namespace mysql
// bind (image_type)
//
os << "static void" << endl
- << "bind (mysql::binding&, image_type&);"
+ << "bind (MYSQL_BIND*, image_type&);"
<< endl;
// bind (id_image_type)
//
os << "static void" << endl
- << "bind (mysql::binding&, id_image_type&);"
+ << "bind (MYSQL_BIND*, id_image_type&);"
<< endl;
// init (image, object)
@@ -368,14 +411,59 @@ namespace mysql
os << "};";
}
+ virtual void
+ traverse_value (type& c)
+ {
+ string const& type (c.fq_name ());
+
+ os << "// " << c.name () << endl
+ << "//" << endl;
+
+ os << "template <>" << endl
+ << "class access::composite_value_traits< " << type << " >"
+ << "{"
+ << "public:" << endl;
+
+ // object_type
+ //
+ os << "typedef " << type << " value_type;"
+ << endl;
+
+ // image_type
+ //
+ image_type_.traverse (c);
+
+ // grow ()
+ //
+ os << "static bool" << endl
+ << "grow (image_type&, my_bool*);"
+ << endl;
+
+ // bind (image_type)
+ //
+ os << "static void" << endl
+ << "bind (MYSQL_BIND*, image_type&);"
+ << endl;
+
+ // init (image, object)
+ //
+ os << "static bool" << endl
+ << "init (image_type&, const value_type&);"
+ << endl;
+
+ // init (object, image)
+ //
+ os << "static void" << endl
+ << "init (value_type&, const image_type&);"
+ << endl;
+
+ os << "};";
+ }
+
private:
id_member id_member_;
- member_count member_count_;
image_type image_type_;
id_image_type id_image_type_;
-
- query_column query_column_;
- traversal::names query_column_names_;
};
}
@@ -398,17 +486,13 @@ namespace mysql
ctx.os << "#include <cstddef>" << endl // std::size_t
<< endl;
- ctx.os << "#include <odb/core.hxx>" << endl
- << "#include <odb/traits.hxx>" << endl;
-
if (ctx.options.generate_query ())
- ctx.os << "#include <odb/result.hxx>" << endl;
+ ctx.os << "#include <odb/result.hxx>" << endl
+ << endl;
- ctx.os << endl
- << "#include <odb/mysql/version.hxx>" << endl
+ ctx.os << "#include <odb/mysql/version.hxx>" << endl
<< "#include <odb/mysql/forward.hxx>" << endl
- << "#include <odb/mysql/mysql-types.hxx>" << endl
- << endl;
+ << "#include <odb/mysql/mysql-types.hxx>" << endl;
if (ctx.options.generate_query ())
ctx.os << "#include <odb/mysql/query.hxx>" << endl;
diff --git a/odb/mysql/inline.cxx b/odb/mysql/inline.cxx
index 2527e1f..47766e2 100644
--- a/odb/mysql/inline.cxx
+++ b/odb/mysql/inline.cxx
@@ -23,9 +23,15 @@ namespace mysql
if (c.file () != unit.file ())
return;
- if (!c.count ("object"))
- return;
+ if (c.count ("object"))
+ traverse_object (c);
+ else if (comp_value (c))
+ traverse_value (c);
+ }
+ virtual void
+ traverse_object (type& c)
+ {
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
@@ -33,14 +39,6 @@ namespace mysql
t.traverse (c);
semantics::data_member& id (*t.member ());
- bool has_grow;
- {
- has_grow_member m (*this);
- traversal::names n (m);
- names (c, n);
- has_grow = m.result ();
- }
-
os << "// " << c.name () << endl
<< "//" << endl
<< endl;
@@ -79,20 +77,20 @@ namespace mysql
<< "{"
<< "return obj." << id.name () << ";" << endl
<< "}";
+ }
- // grow ()
- //
- if (!has_grow)
- {
- // The dummy implementation is needed for result_impl.
- //
- os << "inline" << endl
- << "bool " << traits << "::" << endl
- << "grow (image_type&, my_bool*)"
- << "{"
- << "return false;"
- << "}";
- }
+ virtual void
+ traverse_value (type&)
+ {
+ /*
+ string const& type (c.fq_name ());
+ string traits ("access::composite_value_traits< " + type + " >");
+
+ os << "// " << c.name () << endl
+ << "//" << endl
+ << endl;
+
+ */
}
};
}
diff --git a/odb/mysql/schema.cxx b/odb/mysql/schema.cxx
index 59a6900..3ef412b 100644
--- a/odb/mysql/schema.cxx
+++ b/odb/mysql/schema.cxx
@@ -4,38 +4,32 @@
// license : GNU GPL v3; see accompanying LICENSE file
#include <set>
+
+#include <odb/mysql/common.hxx>
#include <odb/mysql/schema.hxx>
namespace mysql
{
namespace
{
- struct data_member: traversal::data_member, context
+ struct object_columns: object_columns_base, context
{
- data_member (context& c)
- : context (c), first_ (true)
+ object_columns (context& c)
+ : object_columns_base (c), context (c)
{
}
virtual void
- traverse (type& m)
+ column (semantics::data_member& m, string const& name, bool first)
{
- if (m.count ("transient"))
- return;
-
- if (first_)
- first_ = false;
- else
+ if (!first)
os << "," << endl;
- os << " `" << column_name (m) << "` " << column_type (m);
+ os << " `" << name << "` " << column_type (m);
if (m.count ("id"))
os << " PRIMARY KEY";
}
-
- private:
- bool first_;
};
struct class_create: traversal::class_, context
@@ -65,9 +59,8 @@ namespace mysql
os << "CREATE TABLE `" << name << "` (" << endl;
{
- data_member m (*this);
- traversal::names n (m);
- names (c, n);
+ object_columns t (*this);
+ t.traverse (c);
}
os << ")";
diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx
index c0ce773..d572560 100644
--- a/odb/mysql/source.cxx
+++ b/odb/mysql/source.cxx
@@ -16,30 +16,24 @@ namespace mysql
{
namespace
{
- struct member_column: traversal::data_member, context
+ struct object_columns: object_columns_base, context
{
- member_column (context& c, string const& suffix = "")
- : context (c), suffix_ (suffix), first_ (true)
+ object_columns (context& c, string const& suffix = "")
+ : object_columns_base (c), context (c), suffix_ (suffix)
{
}
virtual void
- traverse (type& m)
+ column (semantics::data_member&, string const& name, bool first)
{
- if (m.count ("transient"))
- return;
-
- if (first_)
- first_ = false;
- else
+ if (!first)
os << ",\"" << endl;
- os << "\"`" << column_name (m) << "`" << suffix_;
+ os << "\"`" << name << "`" << suffix_;
}
private:
string suffix_;
- bool first_;
};
const char* integer_buffer_types[] =
@@ -82,10 +76,14 @@ namespace mysql
"MYSQL_TYPE_BLOB" // LONGBLOB
};
+ //
+ // bind
+ //
+
struct bind_member: member_base
{
- bind_member (context& c, bool id)
- : member_base (c, id), index_ (0)
+ bind_member (context& c, size_t& index, bool id)
+ : member_base (c, id), index_ (index)
{
}
@@ -93,7 +91,7 @@ namespace mysql
pre (type& m)
{
ostringstream ostr;
- ostr << "b.bind[" << index_ << "UL]";
+ ostr << "b[" << index_ << "UL]";
b = ostr.str ();
if (!id_)
@@ -102,9 +100,21 @@ namespace mysql
}
virtual void
- post (type&)
+ post (type& m)
{
- index_++;
+ if (semantics::class_* c = comp_value (m.type ()))
+ index_ += column_count (*c);
+ else
+ index_++;
+ }
+
+ virtual void
+ traverse_composite (type& m)
+ {
+ os << "composite_value_traits< " << m.type ().fq_name () <<
+ " >::bind (" << endl
+ << "b + " << index_ << "UL, i." << var << "value);"
+ << endl;
}
virtual void
@@ -234,13 +244,40 @@ namespace mysql
private:
string b;
- size_t index_;
+ size_t& index_;
+ };
+
+ struct bind_base: traversal::class_, context
+ {
+ bind_base (context& c, size_t& index)
+ : context (c), index_ (index)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ os << "// " << c.name () << " base" << endl
+ << "//" << endl
+ << "composite_value_traits< " << c.fq_name () <<
+ " >::bind (b + " << index_ << "UL, i);"
+ << endl;
+
+ index_ += column_count (c);
+ }
+
+ private:
+ size_t& index_;
};
+ //
+ // grow
+ //
+
struct grow_member: member_base
{
- grow_member (context& c)
- : member_base (c, false), index_ (0)
+ grow_member (context& c, size_t& index)
+ : member_base (c, false), index_ (index)
{
}
@@ -256,9 +293,23 @@ namespace mysql
}
virtual void
- post (type&)
+ post (type& m)
{
- index_++;
+ if (semantics::class_* c = comp_value (m.type ()))
+ index_ += column_count (*c);
+ else
+ index_++;
+ }
+
+ virtual void
+ traverse_composite (type& m)
+ {
+ os << "if (composite_value_traits< " << m.type ().fq_name () <<
+ " >::grow (" << endl
+ << "i." << var << "value, e + " << index_ << "UL))"
+ << "{"
+ << "r = true;"
+ << "}";
}
virtual void
@@ -349,11 +400,38 @@ namespace mysql
private:
string e;
- size_t index_;
+ size_t& index_;
+ };
+
+ struct grow_base: traversal::class_, context
+ {
+ grow_base (context& c, size_t& index)
+ : context (c), index_ (index)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ os << "// " << c.name () << " base" << endl
+ << "//" << endl
+ << "if (composite_value_traits< " << c.fq_name () <<
+ " >::grow (i, e + " << index_ << "UL))"
+ << "{"
+ << "r = true;"
+ << "}";
+
+ index_ += column_count (c);
+ }
+
+ private:
+ size_t& index_;
};
//
+ // init image
//
+
struct init_image_member: member_base
{
init_image_member (context& c, bool id)
@@ -366,14 +444,21 @@ namespace mysql
virtual void
pre (type& m)
{
- type = m.type ().fq_name (m.belongs ().hint ());
- image_type = member_image_type_.image_type (m);
- db_type = member_database_type_.database_type (m);
+ semantics::type& t (m.type ());
- traits = "mysql::value_traits< "
- + type + ", "
- + image_type + ", "
- + db_type + " >";
+ if (comp_value (t))
+ traits = "composite_value_traits< " + t.fq_name () + " >";
+ else
+ {
+ type = t.fq_name (m.belongs ().hint ());
+ image_type = member_image_type_.image_type (m);
+ db_type = member_database_type_.database_type (m);
+
+ traits = "mysql::value_traits< "
+ + type + ", "
+ + image_type + ", "
+ + db_type + " >";
+ }
if (id_)
member = "id";
@@ -388,21 +473,35 @@ namespace mysql
}
virtual void
+ traverse_composite (type&)
+ {
+ os << "if (" << traits << "::init (i." << var << "value, " <<
+ member << "))"
+ << "{"
+ << "grew = true;"
+ << "}";
+ }
+
+ virtual void
traverse_integer (type&, sql_type const&)
{
- os << traits << "::set_image (" << endl
+ os << "{"
+ << "bool is_null;"
+ << traits << "::set_image (" << endl
<< "i." << var << "value, is_null, " << member << ");"
<< "i." << var << "null = is_null;"
- << endl;
+ << "}";
}
virtual void
traverse_float (type&, sql_type const&)
{
- os << traits << "::set_image (" << endl
+ os << "{"
+ << "bool is_null;"
+ << traits << "::set_image (" << endl
<< "i." << var << "value, is_null, " << member << ");"
<< "i." << var << "null = is_null;"
- << endl;
+ << "}";
}
virtual void
@@ -411,6 +510,7 @@ namespace mysql
// @@ 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 ());"
<< traits << "::set_image (" << endl
@@ -427,10 +527,12 @@ namespace mysql
virtual void
traverse_date_time (type&, sql_type const&)
{
- os << traits << "::set_image (" << endl
+ os << "{"
+ << "bool is_null;"
+ << traits << "::set_image (" << endl
<< "i." << var << "value, is_null, " << member << ");"
<< "i." << var << "null = is_null;"
- << endl;
+ << "}";
}
virtual void
@@ -439,6 +541,7 @@ namespace mysql
// @@ 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 ());"
<< traits << "::set_image (" << endl
@@ -456,6 +559,7 @@ namespace mysql
traverse_long_string (type&, sql_type const&)
{
os << "{"
+ << "bool is_null;"
<< "std::size_t size;"
<< "std::size_t cap (i." << var << "value.capacity ());"
<< traits << "::set_image (" << endl
@@ -475,6 +579,7 @@ namespace mysql
// Represented as a BLOB.
//
os << "{"
+ << "bool is_null;"
<< "std::size_t size;"
<< traits << "::set_image (" << endl
<< "i." << var << "value," << endl
@@ -493,6 +598,7 @@ namespace mysql
// Represented as a string.
//
os << "{"
+ << "bool is_null;"
<< "std::size_t size;"
<< "std::size_t cap (i." << var << "value.capacity ());"
<< traits << "::set_image (" << endl
@@ -512,6 +618,7 @@ namespace mysql
// Represented as a string.
//
os << "{"
+ << "bool is_null;"
<< "std::size_t size;"
<< "std::size_t cap (i." << var << "value.capacity ());"
<< traits << "::set_image (" << endl
@@ -536,8 +643,30 @@ namespace mysql
member_database_type member_database_type_;
};
+ struct init_image_base: traversal::class_, context
+ {
+ init_image_base (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ os << "// " << c.name () << " base" << endl
+ << "//" << endl
+ << "if (composite_value_traits< " << c.fq_name () <<
+ " >::init (i, o))"
+ << "{"
+ << "grew = true;"
+ << "}";
+ }
+ };
+
//
+ // init value
//
+
struct init_value_member: member_base
{
init_value_member (context& c)
@@ -550,20 +679,34 @@ namespace mysql
virtual void
pre (type& m)
{
- type = m.type ().fq_name (m.belongs ().hint ());
- image_type = member_image_type_.image_type (m);
- db_type = member_database_type_.database_type (m);
+ semantics::type& t (m.type ());
- traits = "mysql::value_traits< "
- + type + ", "
- + image_type + ", "
- + db_type + " >";
+ if (comp_value (t))
+ traits = "composite_value_traits< " + t.fq_name () + " >";
+ 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);
+
+ traits = "mysql::value_traits< "
+ + type + ", "
+ + image_type + ", "
+ + db_type + " >";
+ }
os << "// " << m.name () << endl
<< "//" << endl;
}
virtual void
+ traverse_composite (type& m)
+ {
+ os << traits << "::init (o." << m.name () << ", i." << var << "value);"
+ << endl;
+ }
+
+ virtual void
traverse_integer (type& m, sql_type const&)
{
os << traits << "::set_value (" << endl
@@ -672,19 +815,54 @@ namespace mysql
member_database_type member_database_type_;
};
+ struct init_value_base: traversal::class_, context
+ {
+ init_value_base (context& c)
+ : context (c)
+ {
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ os << "// " << c.name () << " base" << endl
+ << "//" << endl
+ << "composite_value_traits< " << c.fq_name () << " >::init (o, i);"
+ << endl;
+ }
+ };
+
//
//
struct class_: traversal::class_, context
{
class_ (context& c)
: context (c),
+ grow_base_ (c, index_),
+ grow_member_ (c, index_),
+ bind_base_ (c, index_),
+ bind_member_ (c, index_, false),
+ bind_id_member_ (c, index_, true),
+ init_image_base_ (c),
init_image_member_ (c, false),
init_id_image_member_ (c, true),
+ init_value_base_ (c),
init_value_member_ (c)
{
- *this >> init_image_member_names_ >> init_image_member_;
- *this >> init_id_image_member_names_ >> init_id_image_member_;
- *this >> init_value_member_names_ >> init_value_member_;
+ grow_base_inherits_ >> grow_base_;
+ grow_member_names_ >> grow_member_;
+
+ 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_;
}
virtual void
@@ -693,28 +871,25 @@ namespace mysql
if (c.file () != unit.file ())
return;
- if (!c.count ("object"))
- return;
+ if (c.count ("object"))
+ traverse_object (c);
+ else if (comp_value (c))
+ traverse_value (c);
+ }
+ virtual void
+ traverse_object (type& c)
+ {
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
+
+ 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 ());
bool auto_id (id.count ("auto"));
- member_count_.traverse (c);
- size_t column_count (member_count_.count ());
-
- bool has_grow;
- {
- has_grow_member m (*this);
- traversal::names n (m);
- names (c, n);
- has_grow = m.result ();
- }
-
os << "// " << c.name () << endl
<< "//" << endl
<< endl;
@@ -723,9 +898,8 @@ namespace mysql
//
if (options.generate_query ())
{
- query_column t (*this, c);
- traversal::names n (t);
- names (c, n);
+ query_columns t (*this, c);
+ t.traverse (c);
}
// persist_statement
@@ -734,15 +908,14 @@ namespace mysql
<< "\"INSERT INTO `" << table_name (c) << "` (\"" << endl;
{
- member_column m (*this);
- traversal::names n (m);
- names (c, n);
+ object_columns t (*this);
+ t.traverse (c);
}
os << "\"" << endl
<< "\") VALUES (";
- for (size_t i (0); i < column_count; ++i)
+ for (size_t i (0), n (column_count (c)); i < n; ++i)
os << (i != 0 ? "," : "") << '?';
os << ")\";"
@@ -754,9 +927,8 @@ namespace mysql
<< "\"SELECT \"" << endl;
{
- member_column m (*this);
- traversal::names n (m);
- names (c, n);
+ object_columns t (*this);
+ t.traverse (c);
}
os << "\"" << endl
@@ -770,9 +942,8 @@ namespace mysql
<< "\"UPDATE `" << table_name (c) << "` SET \"" << endl;
{
- member_column m (*this, " = ?");
- traversal::names n (m);
- names (c, n);
+ object_columns t (*this, " = ?");
+ t.traverse (c);
}
os << "\"" << endl
@@ -794,9 +965,8 @@ namespace mysql
<< "\"SELECT \"" << endl;
{
- member_column m (*this);
- traversal::names n (m);
- names (c, n);
+ object_columns t (*this);
+ t.traverse (c);
}
os << "\"" << endl
@@ -806,53 +976,41 @@ namespace mysql
// grow ()
//
- if (has_grow)
- {
- os << "bool " << traits << "::" << endl
- << "grow (image_type& i, my_bool* e)"
- << "{"
- << "bool r (false);"
- << endl;
+ os << "bool " << traits << "::" << endl
+ << "grow (image_type&" << (grow ? " i" : "") << ", my_bool* e)"
+ << "{"
+ << "bool r (false);"
+ << endl;
- {
- grow_member m (*this);
- traversal::names n (m);
- names (c, n);
- }
+ index_ = 0;
+ inherits (c, grow_base_inherits_);
+ names (c, grow_member_names_);
- os << "return r;"
- << "}";
- }
+ os << "return r;"
+ << "}";
// bind (image_type)
//
os << "void " << traits << "::" << endl
- << "bind (mysql::binding& b, image_type& i)"
+ << "bind (MYSQL_BIND* b, image_type& i)"
<< "{";
- {
- bind_member m (*this, false);
- traversal::names n (m);
- names (c, n);
- }
+ index_ = 0;
+ inherits (c, bind_base_inherits_);
+ names (c, bind_member_names_);
- os << "b.version++;"
- << "}";
+ os << "}";
// bind (id_image_type)
//
os << "void " << traits << "::" << endl
- << "bind (mysql::binding& b, id_image_type& i)"
+ << "bind (MYSQL_BIND* b, id_image_type& i)"
<< "{";
- {
- bind_member m (*this, true);
- traversal::names n (m);
- names (c, n);
- }
+ index_ = 0;
+ names (c, bind_id_member_names_);
- os << "b.version++;"
- << "}";
+ os << "}";
// init (image, object)
//
@@ -860,9 +1018,11 @@ namespace mysql
<< "init (image_type& i, const object_type& o)"
<< "{"
<< "bool grew (false);"
- << "bool is_null;"
<< endl;
+
+ inherits (c, init_image_base_inherits_);
names (c, init_image_member_names_);
+
os << "return grew;"
<< "}";
@@ -871,7 +1031,10 @@ namespace mysql
os << "void " << traits << "::" << endl
<< "init (object_type& o, const image_type& i)"
<< "{";
+
+ inherits (c, init_value_base_inherits_);
names (c, init_value_member_names_);
+
os << "}";
// persist ()
@@ -892,9 +1055,11 @@ namespace mysql
os << "obj." << id.name () << " = 0;"
<< endl;
- os << "if (init (sts.image (), obj) || b.version == 0)" << endl
- << "bind (b, sts.image ());"
- << endl
+ os << "if (init (sts.image (), obj) || b.version == 0)"
+ << "{"
+ << "bind (b.bind, sts.image ());"
+ << "b.version++;"
+ << "}"
<< "mysql::persist_statement& st (sts.persist_statement ());"
<< "st.execute ();";
@@ -914,18 +1079,22 @@ namespace mysql
<< "object_statements<object_type>& sts (" << endl
<< "conn.statement_cache ().find<object_type> ());"
<< endl
- << "bool is_null, grew (false);"
+ << "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_);
os << "binding& idb (sts.id_image_binding ());"
- << "if (grew || idb.version == 0)" << endl
- << "bind (idb, i);"
- << endl
+ << "if (grew || idb.version == 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ << "idb.version++;"
+ << "}"
<< "binding& imb (sts.image_binding ());"
- << "if (init (sts.image (), obj) || imb.version == 0)" << endl
- << "bind (imb, sts.image ());"
- << endl
+ << "if (init (sts.image (), obj) || imb.version == 0)"
+ << "{"
+ << "bind (imb.bind, sts.image ());"
+ << "imb.version++;"
+ << "}"
<< "sts.update_statement ().execute ();"
<< "}";
@@ -940,13 +1109,15 @@ namespace mysql
<< "object_statements<object_type>& sts (" << endl
<< "conn.statement_cache ().find<object_type> ());"
<< endl
- << "bool is_null, grew (false);"
+ << "bool grew (false);"
<< "id_image_type& i (sts.id_image ());";
names (c, init_id_image_member_names_);
os << "binding& idb (sts.id_image_binding ());"
- << "if (grew || idb.version == 0)" << endl
- << "bind (idb, i);"
- << endl
+ << "if (grew || idb.version == 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ << "idb.version++;"
+ << "}"
<< "sts.erase_statement ().execute ();"
<< "}";
@@ -999,17 +1170,21 @@ namespace mysql
<< "{"
<< "using namespace mysql;"
<< endl
- << "bool is_null, grew (false);"
+ << "bool grew (false);"
<< "id_image_type& i (sts.id_image ());";
names (c, init_id_image_member_names_);
os << "binding& idb (sts.id_image_binding ());"
- << "if (grew || idb.version == 0)" << endl
- << "bind (idb, i);"
- << endl
+ << "if (grew || idb.version == 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ << "idb.version++;"
+ << "}"
<< "binding& imb (sts.image_binding ());"
- << "if (imb.version == 0)" << endl
- << "bind (imb, sts.image ());"
- << endl
+ << "if (imb.version == 0)"
+ << "{"
+ << "bind (imb.bind, sts.image ());"
+ << "imb.version++;"
+ << "}"
<< "mysql::find_statement& st (sts.find_statement ());"
<< "mysql::find_statement::result r (st.execute ());"
<< endl
@@ -1017,12 +1192,13 @@ namespace mysql
<< "return false;"
<< endl;
- if (has_grow)
+ if (grow)
os << "if (r == mysql::find_statement::truncated)"
<< "{"
<< "if (grow (sts.image (), sts.image_error ()))"
<< "{"
- << "bind (imb, sts.image ());"
+ << "bind (imb.bind, sts.image ());"
+ << "imb.version++;"
<< "st.refetch ();"
<< "}"
<< "}";
@@ -1046,9 +1222,11 @@ namespace mysql
<< "conn.statement_cache ().find<object_type> ());"
<< endl
<< "binding& imb (sts.image_binding ());"
- << "if (imb.version == 0)" << endl
- << "bind (imb, sts.image ());"
- << endl
+ << "if (imb.version == 0)"
+ << "{"
+ << "bind (imb.bind, sts.image ());"
+ << "imb.version++;"
+ << "}"
<< "details::shared_ptr<query_statement> st (" << endl
<< "new (details::shared) query_statement (conn," << endl
<< "query_clause + q.clause ()," << endl
@@ -1063,16 +1241,97 @@ namespace mysql
}
}
+ virtual void
+ traverse_value (type& c)
+ {
+ string const& type (c.fq_name ());
+ string traits ("access::composite_value_traits< " + type + " >");
+
+ os << "// " << c.name () << endl
+ << "//" << endl
+ << endl;
+
+ // grow ()
+ //
+ os << "bool " << traits << "::" << endl
+ << "grow (image_type&" << (grow (c) ? " i" : "") << ", my_bool* e)"
+ << "{"
+ << "bool r (false);"
+ << endl;
+
+ index_ = 0;
+ inherits (c, grow_base_inherits_);
+ names (c, grow_member_names_);
+
+ os << "return r;"
+ << "}";
+
+ // bind (image_type)
+ //
+ os << "void " << traits << "::" << endl
+ << "bind (MYSQL_BIND* b, image_type& i)"
+ << "{";
+
+ index_ = 0;
+ inherits (c, bind_base_inherits_);
+ names (c, bind_member_names_);
+
+ os << "}";
+
+ // init (image, object)
+ //
+ os << "bool " << traits << "::" << endl
+ << "init (image_type& i, const value_type& o)"
+ << "{"
+ << "bool grew (false);"
+ << endl;
+
+ inherits (c, init_image_base_inherits_);
+ names (c, init_image_member_names_);
+
+ os << "return grew;"
+ << "}";
+
+ // init (object, image)
+ //
+ os << "void " << traits << "::" << endl
+ << "init (value_type& o, const image_type& i)"
+ << "{";
+
+ inherits (c, init_value_base_inherits_);
+ names (c, init_value_member_names_);
+
+ os << "}";
+ }
+
private:
id_member id_member_;
- member_count member_count_;
+ bool id_;
+ size_t index_;
+
+ grow_base grow_base_;
+ traversal::inherits grow_base_inherits_;
+ grow_member grow_member_;
+ traversal::names grow_member_names_;
+
+ bind_base bind_base_;
+ traversal::inherits bind_base_inherits_;
+ 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_;
init_image_member init_image_member_;
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_;
init_value_member init_value_member_;
traversal::names init_value_member_names_;
};
diff --git a/odb/tracer/header.cxx b/odb/tracer/header.cxx
index b3dad8e..d9732de 100644
--- a/odb/tracer/header.cxx
+++ b/odb/tracer/header.cxx
@@ -116,10 +116,6 @@ namespace tracer
ns >> ns_defines >> ns;
ns_defines >> c;
- ctx.os << "#include <odb/core.hxx>" << endl
- << "#include <odb/traits.hxx>" << endl
- << endl;
-
ctx.os << "namespace odb"
<< "{";
diff --git a/odb/validator.cxx b/odb/validator.cxx
index 9f733a1..ee1c4dc 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -6,6 +6,7 @@
#include <iostream>
#include <odb/traversal.hxx>
+#include <odb/context.hxx>
#include <odb/validator.hxx>
using namespace std;
@@ -77,8 +78,22 @@ namespace
virtual void
traverse (type& c)
{
- if (c.file () != unit_.file () || !c.count ("object"))
- return;
+ if (c.count ("object"))
+ traverse_object (c);
+ else if (context::comp_value (c))
+ traverse_value (c);
+ }
+
+ virtual void
+ traverse_object (type& c)
+ {
+ if (c.inherits_begin () != c.inherits_end ())
+ {
+ cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: object inheritance is not yet supported" << endl;
+
+ valid_ = false;
+ }
member_.count_ = 0;
member_.id_ = 0;
@@ -106,6 +121,59 @@ namespace
}
}
+ virtual void
+ traverse_value (type& c)
+ {
+ for (type::inherits_iterator i (c.inherits_begin ());
+ i != c.inherits_end ();
+ ++i)
+ {
+ type& b (i->base ());
+
+ if (!context::comp_value (b))
+ {
+ // @@ Should we use hint here? Need template printer.
+ //
+ string name (b.fq_anonymous () ? "<anonymous>" : b.fq_name ());
+
+ cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: base class '" << name << "' is not a "
+ << "composite value type" << endl;
+
+ cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " info: composite value types can only derive from other "
+ << "composite value types" << endl;
+
+ cerr << b.file () << ":" << b.line () << ":" << b.column () << ":"
+ << " info: class '" << name << "' is defined here" << endl;
+
+ valid_ = false;
+ }
+ }
+
+ member_.count_ = 0;
+ member_.id_ = 0;
+
+ names (c);
+
+ if (member_.id_ != 0)
+ {
+ cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: value type data member cannot be designated as "
+ << "object id" << endl;
+
+ valid_ = false;
+ }
+
+ if (member_.count_ == 0)
+ {
+ cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
+ << " error: no persistent data members in the class" << endl;
+
+ valid_ = false;
+ }
+ }
+
bool& valid_;
semantics::unit& unit_;