From 6aab653d6975b92c11eef1b56f025c11e6d8e612 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 30 Jul 2010 13:30:16 +0200 Subject: Add support for the rest of database operations --- odb/common.hxx | 47 ++- odb/makefile | 1 + odb/mysql/common.cxx | 118 +++++++ odb/mysql/common.hxx | 104 ++++++ odb/mysql/context.hxx | 8 +- odb/mysql/header.cxx | 299 ++++++----------- odb/mysql/source.cxx | 885 ++++++++++++++++++++++++++++++++++++++++++++++++-- 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 // std::size_t #include // 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&, 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 " << endl << "#include " << endl << "#include " << endl + << endl + << "#include " << 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 // std::size_t +#include + #include #include +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 (" << 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 (" << 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 (" << 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 (" << 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 (" << 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 (" << 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 (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 (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 (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 (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 (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 (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& st (" << endl - << "conn.statement_cache ().find ().insert ());" - << "init (st.image (), obj);" + << "object_statements& sts (" << endl + << "conn.statement_cache ().find ());" + << "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& sts (" << endl + << "conn.statement_cache ().find ());" + << 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& sts (" << endl + << "conn.statement_cache ().find ());" + << 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& sts (" << endl + << "conn.statement_cache ().find ());" + << 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& sts (" << endl + << "conn.statement_cache ().find ());" + << endl + << "if (find (sts, id))" + << "{" + << "init (obj, sts.image ());" + << "return true;" + << "}" + << "return false;" + << "}"; + + os << "bool " << traits << "::" << endl + << "find (mysql::object_statements& 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 " << endl + ctx.os << "#include " << endl + << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl -- cgit v1.1