diff options
-rw-r--r-- | odb/common.cxx | 64 | ||||
-rw-r--r-- | odb/common.hxx | 50 | ||||
-rw-r--r-- | odb/context.cxx | 82 | ||||
-rw-r--r-- | odb/context.hxx | 41 | ||||
-rw-r--r-- | odb/generator.cxx | 26 | ||||
-rw-r--r-- | odb/header.cxx | 108 | ||||
-rw-r--r-- | odb/header.hxx | 14 | ||||
-rw-r--r-- | odb/include.cxx | 8 | ||||
-rw-r--r-- | odb/inline.cxx | 97 | ||||
-rw-r--r-- | odb/inline.hxx | 14 | ||||
-rw-r--r-- | odb/makefile | 3 | ||||
-rw-r--r-- | odb/mysql/common.cxx | 265 | ||||
-rw-r--r-- | odb/mysql/common.hxx | 65 | ||||
-rw-r--r-- | odb/mysql/context.cxx | 107 | ||||
-rw-r--r-- | odb/mysql/context.hxx | 10 | ||||
-rw-r--r-- | odb/mysql/header.cxx | 146 | ||||
-rw-r--r-- | odb/mysql/inline.cxx | 44 | ||||
-rw-r--r-- | odb/mysql/schema.cxx | 27 | ||||
-rw-r--r-- | odb/mysql/source.cxx | 527 | ||||
-rw-r--r-- | odb/tracer/header.cxx | 4 | ||||
-rw-r--r-- | odb/validator.cxx | 72 |
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_; |