aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-07-30 13:30:16 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-07-30 13:30:16 +0200
commit6aab653d6975b92c11eef1b56f025c11e6d8e612 (patch)
treef2e2681836da00c8d77d829ff3fb9f2ace71a607
parent8e220faa86451ad4df72001282bb3ae4c8dcd1fb (diff)
Add support for the rest of database operations
-rw-r--r--odb/common.hxx47
-rw-r--r--odb/makefile1
-rw-r--r--odb/mysql/common.cxx118
-rw-r--r--odb/mysql/common.hxx104
-rw-r--r--odb/mysql/context.hxx8
-rw-r--r--odb/mysql/header.cxx299
-rw-r--r--odb/mysql/source.cxx885
7 files changed, 1244 insertions, 218 deletions
diff --git a/odb/common.hxx b/odb/common.hxx
index 5588f00..ef188d8 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -6,6 +6,7 @@
#ifndef ODB_COMMON_HXX
#define ODB_COMMON_HXX
+#include <cstddef> // std::size_t
#include <odb/context.hxx>
// Find id member.
@@ -15,7 +16,7 @@ struct id_member: traversal::class_,
context
{
id_member (context& c)
- : context (c), m_ (0)
+ : context (c)
{
*this >> names_ >> *this;
}
@@ -33,11 +34,53 @@ struct id_member: traversal::class_,
m_ = &m;
}
- using class_::traverse;
+ virtual void
+ traverse (semantics::class_& c)
+ {
+ m_ = 0;
+ names (c);
+ }
private:
traversal::names names_;
semantics::data_member* m_;
};
+// Find id member.
+//
+struct member_count: traversal::class_,
+ traversal::data_member,
+ context
+{
+ member_count (context& c)
+ : context (c)
+ {
+ *this >> names_ >> *this;
+ }
+
+ std::size_t
+ count () const
+ {
+ return count_;
+ }
+
+ virtual void
+ traverse (semantics::data_member& m)
+ {
+ if (!m.count ("transient"))
+ count_++;
+ }
+
+ virtual void
+ traverse (semantics::class_& c)
+ {
+ count_ = 0;
+ names (c);
+ }
+
+private:
+ traversal::names names_;
+ std::size_t count_;
+};
+
#endif // ODB_COMMON_HXX
diff --git a/odb/makefile b/odb/makefile
index 1fb240d..d9e5a5d 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -26,6 +26,7 @@ tracer/source.cxx
#
cxx_ptun += \
mysql/context.cxx \
+mysql/common.cxx \
mysql/schema.cxx \
mysql/header.cxx \
mysql/inline.cxx \
diff --git a/odb/mysql/common.cxx b/odb/mysql/common.cxx
index cd572d6..71e3e00 100644
--- a/odb/mysql/common.cxx
+++ b/odb/mysql/common.cxx
@@ -9,4 +9,122 @@ using namespace std;
namespace mysql
{
+ void member_base::
+ traverse (type& m)
+ {
+ if (m.count ("transient") || id_ && !m.count ("id"))
+ return;
+
+ if (id_)
+ var = "id_";
+ else
+ {
+ string const& name (m.name ());
+ var = name + (name[name.size () - 1] == '_' ? "" : "_");
+ }
+
+ pre (m);
+
+ sql_type const& t (db_type (m));
+
+ switch (t.type)
+ {
+ // Integral types.
+ //
+ case sql_type::TINYINT:
+ case sql_type::SMALLINT:
+ case sql_type::MEDIUMINT:
+ case sql_type::INT:
+ case sql_type::BIGINT:
+ {
+ traverse_integer (m, t);
+ break;
+ }
+
+ // Float types.
+ //
+ 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;
+ }
+ case sql_type::BINARY:
+ {
+ // BINARY's range is always 255 or less from MySQL 5.0.3.
+ //
+ traverse_short_string (m, t);
+ break;
+ }
+ case sql_type::VARBINARY:
+ case sql_type::TINYBLOB:
+ 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;
+ }
+ }
+
+ post (m);
+ }
}
diff --git a/odb/mysql/common.hxx b/odb/mysql/common.hxx
index cd4d27f..5017158 100644
--- a/odb/mysql/common.hxx
+++ b/odb/mysql/common.hxx
@@ -11,6 +11,110 @@
namespace mysql
{
+ struct member_base: traversal::data_member, context
+ {
+ member_base (context& c, bool id)
+ : context (c), id_ (id)
+ {
+ }
+
+ virtual void
+ traverse (type& m);
+
+ virtual void
+ pre (type&)
+ {
+ }
+
+ virtual void
+ post (type&)
+ {
+ }
+
+ virtual void
+ traverse_integer (type&, sql_type const&)
+ {
+ }
+
+ virtual void
+ traverse_float (type&, sql_type const&)
+ {
+ }
+
+ virtual void
+ traverse_decimal (type&, sql_type const&)
+ {
+ }
+
+ virtual void
+ traverse_date_time (type&, sql_type const&)
+ {
+ }
+
+ virtual void
+ traverse_short_string (type&, sql_type const&)
+ {
+ }
+
+ virtual void
+ traverse_long_string (type&, sql_type const&)
+ {
+ }
+
+ virtual void
+ traverse_bit (type&, sql_type const&)
+ {
+ }
+
+ virtual void
+ traverse_enum (type&, sql_type const&)
+ {
+ }
+
+ virtual void
+ traverse_set (type&, sql_type const&)
+ {
+ }
+
+ protected:
+ bool id_;
+ string var;
+ };
+
+ struct has_grow_member: member_base
+ {
+ has_grow_member (context& c)
+ : member_base (c, false), r_ (false)
+ {
+ }
+
+ bool
+ result ()
+ {
+ return r_;
+ }
+
+ virtual void
+ traverse_long_string (type&, sql_type const& t)
+ {
+ r_ = true;
+ }
+
+ virtual void
+ traverse_enum (type&, sql_type const&)
+ {
+ r_ = true;
+ }
+
+ virtual void
+ traverse_set (type&, sql_type const&)
+ {
+ r_ = true;
+ }
+
+ private:
+ bool r_;
+ };
}
#endif // ODB_MYSQL_COMMON_HXX
diff --git a/odb/mysql/context.hxx b/odb/mysql/context.hxx
index bf01719..4007bda 100644
--- a/odb/mysql/context.hxx
+++ b/odb/mysql/context.hxx
@@ -46,14 +46,14 @@ namespace mysql
BINARY,
VARCHAR,
VARBINARY,
- TINYBLOB,
TINYTEXT,
- BLOB,
+ TINYBLOB,
TEXT,
- MEDIUMBLOB,
+ BLOB,
MEDIUMTEXT,
- LONGBLOB,
+ MEDIUMBLOB,
LONGTEXT,
+ LONGBLOB,
// Other types.
//
diff --git a/odb/mysql/header.cxx b/odb/mysql/header.cxx
index 0d34991..65221f8 100644
--- a/odb/mysql/header.cxx
+++ b/odb/mysql/header.cxx
@@ -25,177 +25,19 @@ namespace mysql
"double"
};
- struct image_member_base: traversal::data_member, context
+ struct image_member: member_base
{
- image_member_base (context& c)
- : context (c)
+ image_member (context& c, bool id)
+ : member_base (c, id)
{
}
virtual void
- traverse (type& m)
- {
- string const& name (m.name ());
- var = name + (name[name.size () - 1] == '_' ? "" : "_");
-
- os << "// " << name << endl
- << "//" << endl;
-
- sql_type const& t (db_type (m));
-
- switch (t.type)
- {
- // Integral types.
- //
- case sql_type::TINYINT:
- case sql_type::SMALLINT:
- case sql_type::MEDIUMINT:
- case sql_type::INT:
- case sql_type::BIGINT:
- {
- traverse_integer (m, t);
- break;
- }
-
- // Float types.
- //
- 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;
- }
- case sql_type::BINARY:
- {
- // BINARY's range is always 255 or less from MySQL 5.0.3.
- //
- traverse_short_string (m, t);
- break;
- }
- case sql_type::VARBINARY:
- case sql_type::TINYBLOB:
- 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;
- }
- }
- }
-
- virtual void
- traverse_integer (type&, sql_type const&)
- {
- }
-
- virtual void
- traverse_float (type&, sql_type const&)
- {
- }
-
- virtual void
- traverse_decimal (type&, sql_type const&)
- {
- }
-
- virtual void
- traverse_date_time (type&, sql_type const&)
- {
- }
-
- virtual void
- traverse_short_string (type&, sql_type const&)
- {
- }
-
- virtual void
- traverse_long_string (type&, sql_type const&)
- {
- }
-
- virtual void
- traverse_bit (type&, sql_type const&)
- {
- }
-
- virtual void
- traverse_enum (type&, sql_type const&)
- {
- }
-
- virtual void
- traverse_set (type&, sql_type const&)
- {
- }
-
- protected:
- string var;
- };
-
- struct image_member: image_member_base
- {
- image_member (context& c)
- : image_member_base (c)
+ pre (type& m)
{
+ if (!id_)
+ os << "// " << m.name () << endl
+ << "//" << endl;
}
virtual void
@@ -226,11 +68,10 @@ namespace mysql
// Exchanged as strings. Can have up to 65 digits not counting
// '-' and '.'. If range is not specified, the default is 10.
//
- os << "const char* " << var << "value;"
+ os << "char " << var << "value[" <<
+ (t.range ? t.range_value : 10) + 3 << "];"
<< "unsigned long " << var << "size;"
<< "my_bool " << var << "null;"
- << "char " << var << "buffer[" <<
- (t.range ? t.range_value : 10) + 3 << "];"
<< endl;
}
@@ -253,21 +94,19 @@ namespace mysql
{
// If range is not specified, the default buffer size is 255.
//
- os << "const char* " << var << "value;"
+ os << "char " << var << "value[" <<
+ (t.range ? t.range_value : 255) + 1 << "];"
<< "unsigned long " << var << "size;"
<< "my_bool " << var << "null;"
- << "char " << var << "buffer[" <<
- (t.range ? t.range_value : 255) + 1 << "];"
<< endl;
}
virtual void
traverse_long_string (type&, sql_type const& t)
{
- os << "const char* " << var << "value;"
+ os << "odb::buffer " << var << "value;"
<< "unsigned long " << var << "size;"
<< "my_bool " << var << "null;"
- << "odb::buffer " << var << "buffer;"
<< endl;
}
@@ -279,6 +118,7 @@ namespace mysql
unsigned int n (t.range / 8 + (t.range % 8 ? 1 : 0));
os << "unsigned char " << var << "value[" << n << "];"
+ << "unsigned long " << var << "size;"
<< "my_bool " << var << "null;"
<< endl;
}
@@ -288,10 +128,9 @@ namespace mysql
{
// Represented as string.
//
- os << "const char* " << var << "value;"
+ os << "odb::buffer " << var << "value;"
<< "unsigned long " << var << "size;"
<< "my_bool " << var << "null;"
- << "odb::buffer " << var << "buffer;"
<< endl;
}
@@ -300,10 +139,9 @@ namespace mysql
{
// Represented as string.
//
- os << "const char* " << var << "value;"
+ os << "odb::buffer " << var << "value;"
<< "unsigned long " << var << "size;"
<< "my_bool " << var << "null;"
- << "odb::buffer " << var << "buffer;"
<< endl;
}
};
@@ -311,7 +149,7 @@ namespace mysql
struct image_type: traversal::class_, context
{
image_type (context& c)
- : context (c), image_member_ (c)
+ : context (c), image_member_ (c, false)
{
*this >> names_image_member_ >> image_member_;
}
@@ -332,10 +170,38 @@ namespace mysql
traversal::names names_image_member_;
};
+ struct id_image_type: traversal::class_, context
+ {
+ id_image_type (context& c)
+ : context (c), image_member_ (c, true)
+ {
+ *this >> names_image_member_ >> image_member_;
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ os << "struct id_image_type"
+ << "{";
+
+ names (c);
+
+ os << "};";
+ }
+
+ private:
+ image_member image_member_;
+ traversal::names names_image_member_;
+ };
+
struct class_: traversal::class_, context
{
class_ (context& c)
- : context (c), image_type_ (c)
+ : context (c),
+ id_member_ (c),
+ member_count_ (c),
+ image_type_ (c),
+ id_image_type_ (c)
{
}
@@ -352,10 +218,9 @@ namespace mysql
// Find the id member and type.
//
- id_member t (*this);
- t.traverse (c);
+ id_member_.traverse (c);
- if (t.member () == 0)
+ if (id_member_.member () == 0)
{
cerr << c.file () << ":" << c.line () << ":" << c.column ()
<< " error: no data member designated as object id" << endl;
@@ -363,11 +228,9 @@ namespace mysql
cerr << c.file () << ":" << c.line () << ":" << c.column ()
<< " info: use '#pragma odb id' to specify object id member"
<< endl;
-
- throw generation_failed ();
}
- semantics::data_member& id (*t.member ());
+ semantics::data_member& id (*id_member_.member ());
semantics::type& id_type (id.type ());
if (id_type.anonymous ())
@@ -385,6 +248,25 @@ namespace mysql
throw generation_failed ();
}
+ member_count_.traverse (c);
+ size_t column_count (member_count_.count ());
+
+ if (column_count == 0)
+ {
+ cerr << c.file () << ":" << c.line () << ":" << c.column ()
+ << " error: no persistent data members in the class" << endl;
+
+ throw generation_failed ();
+ }
+
+ bool has_grow;
+ {
+ has_grow_member m (*this);
+ traversal::names n (m);
+ names (c, n);
+ has_grow = m.result ();
+ }
+
os << "// " << c.name () << endl
<< "//" << endl;
@@ -408,19 +290,27 @@ namespace mysql
//
image_type_.traverse (c);
+ // id_image_type
+ //
+ id_image_type_.traverse (c);
+
// id_source
//
os << "static const odb::id_source id_source = odb::ids_assigned;"
<< endl;
- // column_count @@
+ // column_count
//
- os << "static const std::size_t column_count = 10;"
+ os << "static const std::size_t column_count = " << column_count <<
+ "UL;"
<< endl;
- // insert_query
+ // Queries.
//
os << "static const char* const insert_query;"
+ << "static const char* const select_query;"
+ << "static const char* const update_query;"
+ << "static const char* const delete_query;"
<< endl;
// id ()
@@ -429,15 +319,30 @@ namespace mysql
<< "id (const object_type&);"
<< endl;
- // bind ()
+ // grow ()
+ //
+ if (has_grow)
+ {
+ os << "static bool" << endl
+ << "grow (image_type&, my_bool*);"
+ << endl;
+ }
+
+ // bind (image_type)
//
os << "static void" << endl
- << "bind (MYSQL_BIND*, image_type&);"
+ << "bind (mysql::binding&, image_type&);"
<< endl;
- // init (image, object)
+ // bind (id_image_type)
//
os << "static void" << endl
+ << "bind (mysql::binding&, id_image_type&);"
+ << endl;
+
+ // init (image, object)
+ //
+ os << "static bool" << endl
<< "init (image_type&, object_type&);"
<< endl;
@@ -472,13 +377,21 @@ namespace mysql
<< endl;
os << "static bool" << endl
- << "find (database&, const id_type&, object_type&);";
+ << "find (database&, const id_type&, object_type&);"
+ << endl;
+
+ os << "private:" << endl
+ << "static bool" << endl
+ << "find (mysql::object_statements<object_type>&, const id_type&);";
os << "};";
}
private:
+ id_member id_member_;
+ member_count member_count_;
image_type image_type_;
+ id_image_type id_image_type_;
};
}
@@ -507,6 +420,8 @@ namespace mysql
ctx.os << "#include <odb/core.hxx>" << endl
<< "#include <odb/traits.hxx>" << endl
<< "#include <odb/buffer.hxx>" << endl
+ << endl
+ << "#include <odb/mysql/forward.hxx>" << endl
<< endl;
ctx.os << "namespace odb"
diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx
index 3959894..83608f5 100644
--- a/odb/mysql/source.cxx
+++ b/odb/mysql/source.cxx
@@ -3,18 +3,639 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <cstddef> // std::size_t
+#include <sstream>
+
#include <odb/mysql/common.hxx>
#include <odb/mysql/source.hxx>
+using namespace std;
+
namespace mysql
{
namespace
{
+ struct member_column: traversal::data_member, context
+ {
+ member_column (context& c, string const& suffix = "")
+ : context (c), suffix_ (suffix), first_ (true)
+ {
+ }
+
+ virtual void
+ traverse (type& m)
+ {
+ if (m.count ("transient"))
+ return;
+
+ if (first_)
+ first_ = false;
+ else
+ os << ",\"" << endl;
+
+ os << "\"`" << column_name (m) << "`" << suffix_;
+ }
+
+ private:
+ string suffix_;
+ bool first_;
+ };
+
+ const char* integer_buffer_types[] =
+ {
+ "MYSQL_TYPE_TINY",
+ "MYSQL_TYPE_SHORT",
+ "MYSQL_TYPE_INT24",
+ "MYSQL_TYPE_LONG",
+ "MYSQL_TYPE_LONGLONG"
+ };
+
+ const char* float_buffer_types[] =
+ {
+ "MYSQL_TYPE_FLOAT",
+ "MYSQL_TYPE_DOUBLE"
+ };
+
+ const char* date_time_buffer_types[] =
+ {
+ "MYSQL_TYPE_DATE",
+ "MYSQL_TYPE_TIME",
+ "MYSQL_TYPE_DATETIME",
+ "MYSQL_TYPE_TIMESTAMP",
+ "MYSQL_TYPE_SHORT"
+ };
+
+ const char* char_bin_buffer_types[] =
+ {
+ "MYSQL_TYPE_STRING", // CHAR
+ "MYSQL_TYPE_BLOB", // BINARY,
+ "MYSQL_TYPE_STRING", // VARCHAR
+ "MYSQL_TYPE_BLOB", // VARBINARY
+ "MYSQL_TYPE_STRING", // TINYTEXT
+ "MYSQL_TYPE_BLOB", // TINYBLOB
+ "MYSQL_TYPE_STRING", // TEXT
+ "MYSQL_TYPE_BLOB", // BLOB
+ "MYSQL_TYPE_STRING", // MEDIUMTEXT
+ "MYSQL_TYPE_BLOB", // MEDIUMBLOB
+ "MYSQL_TYPE_STRING", // LONGTEXT
+ "MYSQL_TYPE_BLOB" // LONGBLOB
+ };
+
+ struct bind_member: member_base
+ {
+ bind_member (context& c, bool id)
+ : member_base (c, id), index_ (0)
+ {
+ }
+
+ virtual void
+ pre (type& m)
+ {
+ ostringstream ostr;
+ ostr << "b.bind[" << index_ << "UL]";
+ b = ostr.str ();
+
+ if (!id_)
+ os << "// " << m.name () << endl
+ << "//" << endl;
+ }
+
+ virtual void
+ post (type&)
+ {
+ index_++;
+ }
+
+ virtual void
+ traverse_integer (type&, sql_type const& t)
+ {
+ // While the is_unsigned should indicate whether the
+ // buffer variable is unsigned, rather than whether the
+ // database type is unsigned, in case of the image types,
+ // this is the same.
+ //
+ os << b << ".buffer_type = " <<
+ integer_buffer_types[t.type - sql_type::TINYINT] << ";"
+ << b << ".is_unsigned = " << (t.unsign ? "1" : "0") << ";"
+ << b << ".buffer = &i." << var << "value;"
+ << b << ".is_null = &i." << var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_float (type&, sql_type const& t)
+ {
+ os << b << ".buffer_type = " <<
+ float_buffer_types[t.type - sql_type::FLOAT] << ";"
+ << b << ".buffer = &i." << var << "value;"
+ << b << ".is_null = &i." << var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_decimal (type&, sql_type const& t)
+ {
+ os << b << ".buffer_type = MYSQL_TYPE_NEWDECIMAL;"
+ << b << ".buffer = i." << 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;"
+ << endl;
+ }
+
+ virtual void
+ traverse_date_time (type&, sql_type const& t)
+ {
+ os << b << ".buffer_type = " <<
+ date_time_buffer_types[t.type - sql_type::DATE] << ";"
+ << b << ".buffer = &i." << var << "value;"
+ << b << ".is_null = &i." << var << "null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_short_string (type&, sql_type const& t)
+ {
+ // MySQL documentation is quite confusing about the use of
+ // buffer_length and length when it comes to input parameters.
+ // Source code, however, tells us that it uses buffer_length
+ // only if length is NULL.
+ //
+ os << b << ".buffer_type = " <<
+ char_bin_buffer_types[t.type - sql_type::CHAR] << ";"
+ << b << ".buffer = i." << 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;"
+ << endl;
+ }
+
+ virtual void
+ traverse_long_string (type&, sql_type const& t)
+ {
+ os << b << ".buffer_type = " <<
+ char_bin_buffer_types[t.type - sql_type::CHAR] << ";"
+ << b << ".buffer = i." << 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;"
+ << endl;
+ }
+
+ virtual void
+ traverse_bit (type&, sql_type const& t)
+ {
+ // Treated as a BLOB.
+ //
+ os << b << ".buffer_type = MYSQL_TYPE_BLOB;"
+ << b << ".buffer = i." << 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;"
+ << endl;
+ }
+
+ virtual void
+ traverse_enum (type&, sql_type const&)
+ {
+ // Represented as a string.
+ //
+ os << b << ".buffer_type = MYSQL_TYPE_STRING;"
+ << b << ".buffer = i." << 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;"
+ << endl;
+ }
+
+ virtual void
+ traverse_set (type&, sql_type const&)
+ {
+ // Represented as a string.
+ //
+ os << b << ".buffer_type = MYSQL_TYPE_STRING;"
+ << b << ".buffer = i." << 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;"
+ << endl;
+ }
+
+ private:
+ string b;
+ size_t index_;
+ };
+
+ struct grow_member: member_base
+ {
+ grow_member (context& c)
+ : member_base (c, false), index_ (0)
+ {
+ }
+
+ virtual void
+ pre (type& m)
+ {
+ ostringstream ostr;
+ ostr << "e[" << index_ << "UL]";
+ e = ostr.str ();
+
+ os << "// " << m.name () << endl
+ << "//" << endl;
+ }
+
+ virtual void
+ post (type&)
+ {
+ index_++;
+ }
+
+ virtual void
+ traverse_integer (type&, sql_type const& t)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_float (type&, sql_type const& t)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_decimal (type&, sql_type const& t)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_date_time (type&, sql_type const& t)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_short_string (type&, sql_type const& t)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_long_string (type&, sql_type const& t)
+ {
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << var << "value.capacity (i." << var << "size);"
+ << "r = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_bit (type&, sql_type const& t)
+ {
+ os << e << " = 0;"
+ << endl;
+ }
+
+ virtual void
+ traverse_enum (type&, sql_type const&)
+ {
+ // Represented as a string.
+ //
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << var << "value.capacity (i." << var << "size);"
+ << "r = true;"
+ << "}";
+ }
+
+ virtual void
+ traverse_set (type&, sql_type const&)
+ {
+ // Represented as a string.
+ //
+ os << "if (" << e << ")" << endl
+ << "{"
+ << "i." << var << "value.capacity (i." << var << "size);"
+ << "r = true;"
+ << "}";
+ }
+
+ private:
+ string e;
+ size_t index_;
+ };
+
+ //
+ //
+ struct init_image_member: member_base
+ {
+ init_image_member (context& c, bool id)
+ : member_base (c, id)
+ {
+ }
+
+ virtual void
+ pre (type& m)
+ {
+ type = m.type ().fq_name ();
+
+ if (id_)
+ member = "id";
+ else
+ {
+ string const& name (m.name ());
+ member = "o." + name;
+
+ os << "// " << name << endl
+ << "//" << endl;
+ }
+ }
+
+ virtual void
+ traverse_integer (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << var << "value, is_null, " << member << ");"
+ << "i." << var << "null = is_null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_float (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << var << "value, is_null, " << member << ");"
+ << "i." << var << "null = is_null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_decimal (type& m, sql_type const&)
+ {
+ os << "{"
+ << "std::size_t size;"
+ << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << var << "value," << endl
+ << "sizeof (i." << var << "value)," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << var << "size = static_cast<unsigned long> (size);"
+ << "i." << var << "null = is_null;"
+ << "}";
+ }
+
+ virtual void
+ traverse_date_time (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << var << "value, is_null, " << member << ");"
+ << "i." << var << "null = is_null;"
+ << endl;
+ }
+
+ virtual void
+ traverse_short_string (type& m, sql_type const&)
+ {
+ os << "{"
+ << "std::size_t size;"
+ << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << var << "value," << endl
+ << "sizeof (i." << var << "value)," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << var << "size = static_cast<unsigned long> (size);"
+ << "i." << var << "null = is_null;"
+ << "}";
+ }
+
+ virtual void
+ traverse_long_string (type& m, sql_type const&)
+ {
+ os << "{"
+ << "std::size_t size;"
+ << "std::size_t cap (i." << var << "value.capacity ());"
+ << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << 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 ());"
+ << "}";
+ }
+
+ virtual void
+ traverse_bit (type& m, sql_type const&)
+ {
+ // Represented as a BLOB.
+ //
+ os << "{"
+ << "std::size_t size;"
+ << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << var << "value," << endl
+ << "sizeof (i." << var << "value)," << endl
+ << "size," << endl
+ << "is_null," << endl
+ << member << ");"
+ << "i." << var << "size = static_cast<unsigned long> (size);"
+ << "i." << var << "null = is_null;"
+ << "}";
+ }
+
+ virtual void
+ traverse_enum (type& m, sql_type const&)
+ {
+ // Represented as a string.
+ //
+ os << "{"
+ << "std::size_t size;"
+ << "std::size_t cap (i." << var << "value.capacity ());"
+ << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << 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 ());"
+ << "}";
+ }
+
+ virtual void
+ traverse_set (type& m, sql_type const&)
+ {
+ // Represented as a string.
+ //
+ os << "{"
+ << "std::size_t size;"
+ << "std::size_t cap (i." << var << "value.capacity ());"
+ << "mysql::value_traits< " << type << " >::set_image (" << endl
+ << "i." << 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 ());"
+ << "}";
+ }
+
+ private:
+ string type;
+ string member;
+ };
+
+ //
+ //
+ struct init_value_member: member_base
+ {
+ init_value_member (context& c)
+ : member_base (c, false)
+ {
+ }
+
+ virtual void
+ pre (type& m)
+ {
+ type = m.type ().fq_name ();
+
+ os << "// " << m.name () << endl
+ << "//" << endl;
+ }
+
+ virtual void
+ traverse_integer (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << ", i." << var << "value, " <<
+ "i." << var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_float (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << ", i." << var << "value, " <<
+ "i." << var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_decimal (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << "," << endl
+ << "i." << var << "value," << endl
+ << "i." << var << "size," << endl
+ << "i." << var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_date_time (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << ", i." << var << "value, " <<
+ "i." << var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_short_string (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << "," << endl
+ << "i." << var << "value," << endl
+ << "i." << var << "size," << endl
+ << "i." << var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_long_string (type& m, sql_type const&)
+ {
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << "," << endl
+ << "i." << var << "value.data ()," << endl
+ << "i." << var << "size," << endl
+ << "i." << var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_bit (type& m, sql_type const&)
+ {
+ // Represented as a BLOB.
+ //
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << "," << endl
+ << "i." << var << "value," << endl
+ << "i." << var << "size," << endl
+ << "i." << var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_enum (type& m, sql_type const&)
+ {
+ // Represented as a string.
+ //
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << "," << endl
+ << "i." << var << "value.data ()," << endl
+ << "i." << var << "size," << endl
+ << "i." << var << "null);"
+ << endl;
+ }
+
+ virtual void
+ traverse_set (type& m, sql_type const&)
+ {
+ // Represented as a string.
+ //
+ os << "mysql::value_traits< " << type << " >::set_value (" << endl
+ << "o." << m.name () << "," << endl
+ << "i." << var << "value.data ()," << endl
+ << "i." << var << "size," << endl
+ << "i." << var << "null);"
+ << endl;
+ }
+
+ private:
+ string type;
+ };
+
+ //
+ //
struct class_: traversal::class_, context
{
class_ (context& c)
- : context (c)
+ : context (c),
+ id_member_ (c),
+ member_count_ (c),
+ init_image_member_ (c, false),
+ init_id_image_member_ (c, true),
+ 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_;
}
virtual void
@@ -29,9 +650,19 @@ namespace mysql
string const& type (c.fq_name ());
string traits ("access::object_traits< " + type + " >");
- id_member t (*this);
- t.traverse (c);
- semantics::data_member& id (*t.member ());
+ id_member_.traverse (c);
+ semantics::data_member& id (*id_member_.member ());
+
+ 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
@@ -39,30 +670,127 @@ namespace mysql
// insert_query
//
- os << "const char* const " << traits << "::insert_query = " << endl
- << "\"INSERT INTO\";"
- << endl;
+ os << "const char* const " << traits << "::insert_query =" << endl
+ << "\"INSERT INTO `" << table_name (c) << "` (\"" << endl;
- // bind ()
+ {
+ member_column m (*this);
+ traversal::names n (m);
+ names (c, n);
+ }
+
+ os << "\"" << endl
+ << "\") VALUES (";
+
+ for (size_t i (0); i < column_count; ++i)
+ os << (i != 0 ? "," : "") << '?';
+
+ os << ")\";" << endl;
+
+ // select_query
+ //
+ os << "const char* const " << traits << "::select_query =" << endl
+ << "\"SELECT \"" << endl;
+
+ {
+ member_column m (*this);
+ traversal::names n (m);
+ names (c, n);
+ }
+
+ os << "\"" << endl
+ << "\" FROM `" << table_name (c) << "` WHERE `" <<
+ column_name (id) << "` = ?\";" << endl;
+
+ // update_query
+ //
+ os << "const char* const " << traits << "::update_query =" << endl
+ << "\"UPDATE `" << table_name (c) << "` SET \"" << endl;
+
+ {
+ member_column m (*this, " = ?");
+ traversal::names n (m);
+ names (c, n);
+ }
+
+ os << "\"" << endl
+ << "\" WHERE `" << column_name (id) << "` = ?\";" << endl;
+
+ // delete_query
+ //
+ os << "const char* const " << traits << "::delete_query =" << endl
+ << "\"DELETE FROM `" << table_name (c) << "`\"" << endl
+ << "\" WHERE `" << column_name (id) << "` = ?\";" << endl;
+
+ // grow ()
+ //
+ if (has_grow)
+ {
+ os << "bool " << traits << "::" << endl
+ << "grow (image_type& i, my_bool* e)"
+ << "{"
+ << "bool r (false);"
+ << endl;
+
+ {
+ grow_member m (*this);
+ traversal::names n (m);
+ names (c, n);
+ }
+
+ os << "return r;"
+ << "}";
+ }
+
+ // bind (image_type)
//
os << "void " << traits << "::" << endl
- << "bind (MYSQL_BIND*, image_type&)"
- << "{"
+ << "bind (mysql::binding& b, image_type& i)"
+ << "{";
+
+ {
+ bind_member m (*this, false);
+ traversal::names n (m);
+ names (c, n);
+ }
+
+ os << "b.version++;"
<< "}";
- // init (image, object)
+ // bind (id_image_type)
//
os << "void " << traits << "::" << endl
- << "init (image_type&, object_type&)"
+ << "bind (mysql::binding& b, id_image_type& i)"
+ << "{";
+
+ {
+ bind_member m (*this, true);
+ traversal::names n (m);
+ names (c, n);
+ }
+
+ os << "b.version++;"
+ << "}";
+
+ // init (image, object)
+ //
+ os << "bool " << traits << "::" << endl
+ << "init (image_type& i, object_type& o)"
<< "{"
+ << "bool grew (false);"
+ << "bool is_null;"
+ << endl;
+ names (c, init_image_member_names_);
+ os << "return grew;"
<< "}";
// init (object, image)
//
os << "void " << traits << "::" << endl
- << "init (object_type&, image_type&)"
- << "{"
- << "}";
+ << "init (object_type& o, image_type& i)"
+ << "{";
+ names (c, init_value_member_names_);
+ os << "}";
// persist ()
//
@@ -72,9 +800,14 @@ namespace mysql
<< "using namespace mysql;"
<< endl
<< "connection& conn (mysql::transaction::current ().connection ());"
- << "insert_statement<object_type>& st (" << endl
- << "conn.statement_cache ().find<object_type> ().insert ());"
- << "init (st.image (), obj);"
+ << "object_statements<object_type>& sts (" << endl
+ << "conn.statement_cache ().find<object_type> ());"
+ << "binding& b (sts.image_binding ());"
+ << endl
+ << "if (init (sts.image (), obj) || b.version == 0)" << endl
+ << "bind (b, sts.image ());"
+ << endl
+ << "insert_statement& st (sts.insert ());"
<< "st.execute ();"
<< "}";
@@ -83,6 +816,26 @@ namespace mysql
os << "void " << traits << "::" << endl
<< "store (database&, object_type& obj)"
<< "{"
+ << "using namespace mysql;"
+ << endl
+ << "connection& conn (mysql::transaction::current ().connection ());"
+ << "object_statements<object_type>& sts (" << endl
+ << "conn.statement_cache ().find<object_type> ());"
+ << endl
+ << "bool is_null, 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
+ << "binding& imb (sts.image_binding ());"
+ << "if (init (sts.image (), obj) || imb.version == 0)" << endl
+ << "bind (imb, sts.image ());"
+ << endl
+ << "update_statement& st (sts.update ());"
+ << "st.execute ();"
<< "}";
// erase ()
@@ -90,6 +843,21 @@ namespace mysql
os << "void " << traits << "::" << endl
<< "erase (database&, const id_type& id)"
<< "{"
+ << "using namespace mysql;"
+ << endl
+ << "connection& conn (mysql::transaction::current ().connection ());"
+ << "object_statements<object_type>& sts (" << endl
+ << "conn.statement_cache ().find<object_type> ());"
+ << endl
+ << "bool is_null, 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
+ << "delete_statement& st (sts.delete_ ());"
+ << "st.execute ();"
<< "}";
// find ()
@@ -98,15 +866,91 @@ namespace mysql
<< traits << "::" << endl
<< "find (database&, const id_type& id)"
<< "{"
- << "return 0;"
+ << "using namespace mysql;"
+ << endl
+ << "connection& conn (mysql::transaction::current ().connection ());"
+ << "object_statements<object_type>& sts (" << endl
+ << "conn.statement_cache ().find<object_type> ());"
+ << endl
+ << "if (find (sts, id))"
+ << "{"
+ << "pointer_type p (access::object_factory< " << type <<
+ " >::create ());"
+ << "init (pointer_traits< pointer_type >::get_ref (p), " <<
+ "sts.image ());"
+ << "return p;"
+ << "}"
+ << "return pointer_type ();"
<< "}";
os << "bool " << traits << "::" << endl
<< "find (database&, const id_type& id, object_type& obj)"
<< "{"
+ << "using namespace mysql;"
+ << endl
+ << "connection& conn (mysql::transaction::current ().connection ());"
+ << "object_statements<object_type>& sts (" << endl
+ << "conn.statement_cache ().find<object_type> ());"
+ << endl
+ << "if (find (sts, id))"
+ << "{"
+ << "init (obj, sts.image ());"
+ << "return true;"
+ << "}"
+ << "return false;"
+ << "}";
+
+ os << "bool " << traits << "::" << endl
+ << "find (mysql::object_statements<object_type>& sts, " <<
+ "const id_type& id)"
+ << "{"
+ << "using namespace mysql;"
+ << endl
+ << "bool is_null, 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
+ << "binding& imb (sts.image_binding ());"
+ << "if (imb.version == 0)" << endl
+ << "bind (imb, sts.image ());"
+ << endl
+ << "select_statement& st (sts.select ());"
+ << "select_statement::result r (st.execute ());"
+ << endl
+ << "if (r == select_statement::no_data)" << endl
<< "return false;"
+ << endl;
+
+ if (has_grow)
+ os << "if (r == select_statement::truncated)"
+ << "{"
+ << "if (grow (sts.image (), sts.image_error ()))"
+ << "{"
+ << "bind (imb, sts.image ());"
+ << "st.refetch ();"
+ << "}"
+ << "}";
+
+ os << "st.free_result ();"
+ << "return true;"
<< "}";
}
+
+ private:
+ id_member id_member_;
+ member_count member_count_;
+
+ 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_member init_value_member_;
+ traversal::names init_value_member_names_;
};
}
@@ -126,7 +970,8 @@ namespace mysql
ns >> ns_defines >> ns;
ns_defines >> c;
- ctx.os << "#include <odb/mysql/database.hxx>" << endl
+ ctx.os << "#include <odb/mysql/traits.hxx>" << endl
+ << "#include <odb/mysql/database.hxx>" << endl
<< "#include <odb/mysql/transaction.hxx>" << endl
<< "#include <odb/mysql/connection.hxx>" << endl
<< "#include <odb/mysql/statement.hxx>" << endl