From ce696c26d2c9dd5a5813fd865082ab19ac49bcfa Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 6 Nov 2010 18:05:19 +0200 Subject: Add support for container persistence --- odb/mysql/common.cxx | 158 +++-- odb/mysql/common.hxx | 138 +++-- odb/mysql/context.cxx | 146 +++-- odb/mysql/context.hxx | 13 +- odb/mysql/header.cxx | 573 +++++++++++++++--- odb/mysql/inline.cxx | 5 +- odb/mysql/schema.cxx | 165 +++++- odb/mysql/source.cxx | 1558 +++++++++++++++++++++++++++++++++++++++++-------- 8 files changed, 2275 insertions(+), 481 deletions(-) (limited to 'odb/mysql') diff --git a/odb/mysql/common.cxx b/odb/mysql/common.cxx index 372d08e..17cae9e 100644 --- a/odb/mysql/common.cxx +++ b/odb/mysql/common.cxx @@ -11,29 +11,47 @@ using namespace std; namespace mysql { + // + // member_base + // + void member_base:: - traverse (type& m) + traverse (semantics::data_member& m) { - if (m.count ("transient") || (id_ && !m.count ("id"))) + if (m.count ("transient")) return; - if (id_) - var = "id_"; + string var; + + if (!var_override_.empty ()) + var = var_override_; else { string const& name (m.name ()); var = name + (name[name.size () - 1] == '_' ? "" : "_"); } - pre (m); + semantics::type& t (type_override_ != 0 ? *type_override_ : m.type ()); + + member_info mi (m, t, var, fq_type_override_); - if (comp_value (m.type ())) - traverse_composite (m); + if (comp_value (t)) + { + pre (mi); + traverse_composite (mi); + } + else if (container (t)) + { + pre (mi); + traverse_container (mi); + } else { - sql_type const& t (db_type (m)); + sql_type const& st (db_type (m, key_prefix_)); + mi.st = &st; + pre (mi); - switch (t.type) + switch (st.type) { // Integral types. // @@ -43,7 +61,7 @@ namespace mysql case sql_type::INT: case sql_type::BIGINT: { - traverse_integer (m, t); + traverse_integer (mi); break; } @@ -52,12 +70,12 @@ namespace mysql case sql_type::FLOAT: case sql_type::DOUBLE: { - traverse_float (m, t); + traverse_float (mi); break; } case sql_type::DECIMAL: { - traverse_decimal (m, t); + traverse_decimal (mi); break; } @@ -69,7 +87,7 @@ namespace mysql case sql_type::TIMESTAMP: case sql_type::YEAR: { - traverse_date_time (m, t); + traverse_date_time (mi); break; } @@ -88,7 +106,7 @@ namespace mysql // To support this we will need the character encoding // in sql_type. // - traverse_long_string (m, t); + traverse_long_string (mi); break; } case sql_type::BINARY: @@ -97,7 +115,7 @@ namespace mysql // BINARY's range is always 255 or less from MySQL 5.0.3. // TINYBLOB can only store up to 255 bytes. // - traverse_short_string (m, t); + traverse_short_string (mi); break; } case sql_type::VARBINARY: @@ -105,10 +123,10 @@ namespace mysql case sql_type::MEDIUMBLOB: case sql_type::LONGBLOB: { - if (t.range && t.range_value <= 255) - traverse_short_string (m, t); + if (st.range && st.range_value <= 255) + traverse_short_string (mi); else - traverse_long_string (m, t); + traverse_long_string (mi); break; } @@ -117,17 +135,17 @@ namespace mysql // case sql_type::BIT: { - traverse_bit (m, t); + traverse_bit (mi); break; } case sql_type::ENUM: { - traverse_enum (m, t); + traverse_enum (mi); break; } case sql_type::SET: { - traverse_set (m, t); + traverse_set (mi); break; } case sql_type::invalid: @@ -138,7 +156,7 @@ namespace mysql } } - post (m); + post (mi); } // @@ -164,13 +182,22 @@ namespace mysql } member_image_type:: - member_image_type (context& c, bool id) - : member_base (c, id) + member_image_type (context& c) + : member_base (c) + { + } + + member_image_type:: + member_image_type (context& c, + semantics::type& type, + string const& fq_type, + string const& key_prefix) + : member_base (c, "", type, fq_type, key_prefix) { } string member_image_type:: - image_type (type& m) + image_type (semantics::data_member& m) { type_.clear (); member_base::traverse (m); @@ -178,58 +205,57 @@ namespace mysql } void member_image_type:: - traverse_composite (type& m) + traverse_composite (member_info& mi) { - type_ = "composite_value_traits< " + m.type ().fq_name () + - " >::image_type"; + type_ = "composite_value_traits< " + mi.fq_type () + " >::image_type"; } void member_image_type:: - traverse_integer (type&, sql_type const& t) + traverse_integer (member_info& mi) { - if (t.unsign) + if (mi.st->unsign) type_ = "unsigned "; - else if (t.type == sql_type::TINYINT) + else if (mi.st->type == sql_type::TINYINT) type_ = "signed "; - type_ += integer_types[t.type - sql_type::TINYINT]; + type_ += integer_types[mi.st->type - sql_type::TINYINT]; } void member_image_type:: - traverse_float (type&, sql_type const& t) + traverse_float (member_info& mi) { - type_ = float_types[t.type - sql_type::FLOAT]; + type_ = float_types[mi.st->type - sql_type::FLOAT]; } void member_image_type:: - traverse_decimal (type&, sql_type const&) + traverse_decimal (member_info&) { type_ = "details::buffer"; } void member_image_type:: - traverse_date_time (type&, sql_type const& t) + traverse_date_time (member_info& mi) { - if (t.type == sql_type::YEAR) + if (mi.st->type == sql_type::YEAR) type_ = "short"; else type_ = "MYSQL_TIME"; } void member_image_type:: - traverse_string (type&, sql_type const&) + traverse_string (member_info&) { type_ = "details::buffer"; } void member_image_type:: - traverse_bit (type&, sql_type const&) + traverse_bit (member_info&) { type_ = "unsigned char*"; } void member_image_type:: - traverse_enum (type&, sql_type const&) + traverse_enum (member_info&) { // Represented as string. // @@ -237,7 +263,7 @@ namespace mysql } void member_image_type:: - traverse_set (type&, sql_type const&) + traverse_set (member_info&) { // Represented as string. // @@ -298,7 +324,16 @@ namespace mysql member_database_type:: member_database_type (context& c) - : member_base (c, false) + : member_base (c) + { + } + + member_database_type:: + member_database_type (context& c, + semantics::type& type, + string const& fq_type, + string const& key_prefix) + : member_base (c, "", type, fq_type, key_prefix) { } @@ -311,56 +346,59 @@ namespace mysql } void member_database_type:: - traverse_composite (type&) + traverse_composite (member_info&) { assert (false); } void member_database_type:: - traverse_integer (type&, sql_type const& t) + traverse_integer (member_info& mi) { - size_t i ((t.type - sql_type::TINYINT) * 2 + (t.unsign ? 1 : 0)); + size_t i ((mi.st->type - sql_type::TINYINT) * 2 + (mi.st->unsign ? 1 : 0)); type_ = string ("mysql::") + integer_database_id[i]; } void member_database_type:: - traverse_float (type&, sql_type const& t) + traverse_float (member_info& mi) { - type_ = string ("mysql::") + float_database_id[t.type - sql_type::FLOAT]; + type_ = string ("mysql::") + + float_database_id[mi.st->type - sql_type::FLOAT]; } void member_database_type:: - traverse_decimal (type&, sql_type const&) + traverse_decimal (member_info&) { type_ = "mysql::id_decimal"; } void member_database_type:: - traverse_date_time (type&, sql_type const& t) + traverse_date_time (member_info& mi) { - type_ = string ("mysql::") + date_time_database_id[t.type - sql_type::DATE]; + type_ = string ("mysql::") + + date_time_database_id[mi.st->type - sql_type::DATE]; } void member_database_type:: - traverse_string (type&, sql_type const& t) + traverse_string (member_info& mi) { - type_ = string ("mysql::") + char_bin_database_id[t.type - sql_type::CHAR]; + type_ = string ("mysql::") + + char_bin_database_id[mi.st->type - sql_type::CHAR]; } void member_database_type:: - traverse_bit (type&, sql_type const&) + traverse_bit (member_info&) { type_ = "mysql::id_bit"; } void member_database_type:: - traverse_enum (type&, sql_type const&) + traverse_enum (member_info&) { type_ = "mysql::id_enum"; } void member_database_type:: - traverse_set (type&, sql_type const&) + traverse_set (member_info&) { type_ = "mysql::id_set"; } @@ -374,7 +412,7 @@ namespace mysql : object_columns_base (c), context (c), decl_ (true), - member_image_type_ (c, false), + member_image_type_ (c), member_database_type_ (c) { } @@ -384,7 +422,7 @@ namespace mysql : object_columns_base (c), context (c), decl_ (false), - member_image_type_ (c, false), + member_image_type_ (c), member_database_type_ (c) { scope_ = "access::object_traits< " + cl.fq_name () + " >::query_type"; @@ -392,7 +430,7 @@ namespace mysql } void query_columns:: - composite (semantics::data_member& m) + composite (semantics::data_member& m, semantics::type& t) { string name (public_name (m)); @@ -403,7 +441,7 @@ namespace mysql << "struct " << name << "{"; - object_columns_base::composite (m); + object_columns_base::composite (m, t); os << "};"; } @@ -412,7 +450,7 @@ namespace mysql string old_scope (scope_); scope_ += "::" + name; - object_columns_base::composite (m); + object_columns_base::composite (m, t); scope_ = old_scope; } diff --git a/odb/mysql/common.hxx b/odb/mysql/common.hxx index 83fa998..31c6962 100644 --- a/odb/mysql/common.hxx +++ b/odb/mysql/common.hxx @@ -13,119 +13,170 @@ namespace mysql { struct member_base: traversal::data_member, context { - member_base (context& c, bool id) - : context (c), id_ (id) + member_base (context& c, string const& var = string ()) + : context (c), var_override_ (var), type_override_ (0) + { + } + + member_base (context& c, + string const& var, + semantics::type& type, + string const& fq_type, + string const& key_prefix) + : context (c), + var_override_ (var), + type_override_ (&type), + fq_type_override_ (fq_type), + key_prefix_ (key_prefix) { } virtual void - traverse (type& m); + traverse (semantics::data_member& m); + + struct member_info + { + semantics::data_member& m; // Member. + semantics::type& t; // Member C++ type (m.type () may != t). + sql_type const* st; // Member SQL type (only simple value types). + string& var; // Member variable name with trailing '_'. + + // C++ type fq-name. + // + string + fq_type () const + { + return fq_type_.empty () ? t.fq_name (m.belongs ().hint ()) : fq_type_; + } + + string const& fq_type_; + + member_info (semantics::data_member& m_, + semantics::type& t_, + string& var_, + string const& fq_type) + : m (m_), t (t_), st (0), var (var_), fq_type_ (fq_type) + { + } + }; + + virtual void + pre (member_info&) + { + } virtual void - pre (type&) + post (member_info&) { } virtual void - post (type&) + traverse_composite (member_info&) { } virtual void - traverse_composite (type&) + traverse_container (member_info&) { } virtual void - traverse_integer (type&, sql_type const&) + traverse_integer (member_info&) { } virtual void - traverse_float (type&, sql_type const&) + traverse_float (member_info&) { } virtual void - traverse_decimal (type&, sql_type const&) + traverse_decimal (member_info&) { } virtual void - traverse_date_time (type&, sql_type const&) + traverse_date_time (member_info&) { } virtual void - traverse_string (type&, sql_type const&) + traverse_string (member_info&) { } virtual void - traverse_short_string (type& t, sql_type const& st) + traverse_short_string (member_info& mi) { - traverse_string (t, st); + traverse_string (mi); } virtual void - traverse_long_string (type& t, sql_type const& st) + traverse_long_string (member_info& mi) { - traverse_string (t, st); + traverse_string (mi); } virtual void - traverse_bit (type&, sql_type const&) + traverse_bit (member_info&) { } virtual void - traverse_enum (type&, sql_type const&) + traverse_enum (member_info&) { } virtual void - traverse_set (type&, sql_type const&) + traverse_set (member_info&) { } protected: - bool id_; - string var; + string var_override_; + semantics::type* type_override_; + string fq_type_override_; + string key_prefix_; }; struct member_image_type: member_base { - member_image_type (context&, bool id); + member_image_type (context&); + + member_image_type (context& c, + semantics::type& type, + string const& fq_type, + string const& key_prefix); string - image_type (type&); + image_type (semantics::data_member&); virtual void - traverse_composite (type&); + traverse_composite (member_info&); virtual void - traverse_integer (type&, sql_type const&); + traverse_integer (member_info&); virtual void - traverse_float (type&, sql_type const&); + traverse_float (member_info&); virtual void - traverse_decimal (type&, sql_type const&); + traverse_decimal (member_info&); virtual void - traverse_date_time (type&, sql_type const&); + traverse_date_time (member_info&); virtual void - traverse_string (type&, sql_type const&); + traverse_string (member_info&); virtual void - traverse_bit (type&, sql_type const&); + traverse_bit (member_info&); virtual void - traverse_enum (type&, sql_type const&); + traverse_enum (member_info&); virtual void - traverse_set (type&, sql_type const&); + traverse_set (member_info&); private: string type_; @@ -135,35 +186,40 @@ namespace mysql { member_database_type (context&); + member_database_type (context& c, + semantics::type& type, + string const& fq_type, + string const& key_prefix); + string database_type (type&); virtual void - traverse_composite (type&); + traverse_composite (member_info&); virtual void - traverse_integer (type&, sql_type const&); + traverse_integer (member_info&); virtual void - traverse_float (type&, sql_type const&); + traverse_float (member_info&); virtual void - traverse_decimal (type&, sql_type const&); + traverse_decimal (member_info&); virtual void - traverse_date_time (type&, sql_type const&); + traverse_date_time (member_info&); virtual void - traverse_string (type&, sql_type const&); + traverse_string (member_info&); virtual void - traverse_bit (type&, sql_type const&); + traverse_bit (member_info&); virtual void - traverse_enum (type&, sql_type const&); + traverse_enum (member_info&); virtual void - traverse_set (type&, sql_type const&); + traverse_set (member_info&); private: string type_; @@ -175,7 +231,7 @@ namespace mysql query_columns (context&, semantics::class_&); virtual void - composite (semantics::data_member&); + composite (semantics::data_member&, semantics::type&); virtual void column (semantics::data_member&, string const&, bool); diff --git a/odb/mysql/context.cxx b/odb/mysql/context.cxx index e896f68..4803da2 100644 --- a/odb/mysql/context.cxx +++ b/odb/mysql/context.cxx @@ -81,18 +81,16 @@ namespace mysql { struct has_grow: traversal::class_ { - has_grow (context& c) - : member_ (c, *this) + has_grow () { - *this >> member_names_ >> member_; *this >> inherits_ >> *this; } bool - dispatch (semantics::type& t) + dispatch (type& c) { r_ = false; - traversal::class_::dispatch (t); + traverse (c); return r_; } @@ -115,57 +113,74 @@ namespace mysql } private: - struct member: member_base - { - member (context& c, has_grow& hg) : member_base (c, false), hg_ (hg) {} + friend class has_grow_member; - virtual void - traverse_composite (type& m) - { - if (!hg_.r_) - hg_.r_ = hg_.dispatch (m.type ()); - } + bool r_; + traversal::inherits inherits_; + }; - virtual void - traverse_decimal (type&, sql_type const&) - { - hg_.r_ = true; - } + struct has_grow_member: member_base + { + has_grow_member (context& c, has_grow& hg) + : member_base (c), hg_ (hg) + { + } - virtual void - traverse_long_string (type&, sql_type const&) - { - hg_.r_ = true; - } + has_grow_member (context& c, + has_grow& hg, + semantics::type& type, + string const& key_prefix) + : member_base (c, "", type, "", key_prefix), hg_ (hg) + { + } - virtual void - traverse_short_string (type&, sql_type const&) - { - hg_.r_ = true; // @@ Short string optimization disabled. - } + bool + dispatch (semantics::data_member& m) + { + hg_.r_ = false; + member_base::traverse (m); + return hg_.r_; + } - virtual void - traverse_enum (type&, sql_type const&) - { - hg_.r_ = true; - } + virtual void + traverse_composite (member_info& mi) + { + if (!hg_.r_) + hg_.r_ = hg_.dispatch (dynamic_cast (mi.t)); + } - virtual void - traverse_set (type&, sql_type const&) - { - hg_.r_ = true; - } + virtual void + traverse_decimal (member_info&) + { + hg_.r_ = true; + } - private: - has_grow& hg_; - }; + virtual void + traverse_long_string (member_info&) + { + hg_.r_ = true; + } - bool r_; + virtual void + traverse_short_string (member_info&) + { + hg_.r_ = true; // @@ Short string optimization disabled. + } - member member_; - traversal::names member_names_; + virtual void + traverse_enum (member_info&) + { + hg_.r_ = true; + } - traversal::inherits inherits_; + virtual void + traverse_set (member_info&) + { + hg_.r_ = true; + } + + private: + has_grow& hg_; }; } @@ -175,20 +190,37 @@ namespace mysql if (c.count ("mysql::grow")) return c.get ("mysql::grow"); - has_grow t (*this); - return t.dispatch (c); + has_grow ct; + has_grow_member mt (*this, ct); + traversal::names names; + ct >> names >> mt; + + return ct.dispatch (c); + } + + bool context:: + grow (semantics::data_member& m, semantics::type& t, string const& kp) + { + has_grow ct; + has_grow_member mt (*this, ct, t, kp); + traversal::names names; + ct >> names >> mt; + + return mt.dispatch (m); } // // SQL type parsing. // - string context:: - column_type_impl (semantics::data_member& m) const + string context::data:: + column_type_impl (semantics::type& t, + string const& type, + semantics::context* ctx) const { - string r (::context::column_type_impl (m)); + string r (::context::data::column_type_impl (t, type, ctx)); - if (m.count ("auto")) + if (!r.empty () && ctx != 0 && ctx->count ("auto")) r += " AUTO_INCREMENT"; return r; @@ -198,12 +230,14 @@ namespace mysql parse_sql_type (semantics::data_member& m, std::string const& sql); sql_type const& context:: - db_type (semantics::data_member& m) + db_type (semantics::data_member& m, string const& kp) { - if (!m.count ("db-type")) - m.set ("db-type", parse_sql_type (m, column_type (m))); + string key (kp.empty () ? string ("db-type") : kp + "-db-type"); + + if (!m.count (key)) + m.set (key, parse_sql_type (m, column_type (m, kp))); - return m.get ("db-type"); + return m.get (key); } static sql_type diff --git a/odb/mysql/context.hxx b/odb/mysql/context.hxx index 40facae..9a6beec 100644 --- a/odb/mysql/context.hxx +++ b/odb/mysql/context.hxx @@ -86,25 +86,32 @@ namespace mysql bool grow (semantics::class_&); + // The same for a member's value type. + // + bool + grow (semantics::data_member&, semantics::type&, string const& key_prefix); + // // public: sql_type const& - db_type (semantics::data_member&); + db_type (semantics::data_member&, string const& key_prefix = string ()); private: typedef ::context base_context; struct data: base_context::data { + virtual string + column_type_impl (semantics::type&, + string const& type, + semantics::context*) const; }; private: data* data_; public: - virtual string - column_type_impl (semantics::data_member&) const; public: context (std::ostream&, semantics::unit&, options_type const&); diff --git a/odb/mysql/header.cxx b/odb/mysql/header.cxx index 2544ff3..b4781f9 100644 --- a/odb/mysql/header.cxx +++ b/odb/mysql/header.cxx @@ -14,46 +14,59 @@ namespace mysql { struct image_member: member_base { - image_member (context& c, bool id) - : member_base (c, id), member_image_type_ (c, id) + image_member (context& c, string const& var = string ()) + : member_base (c, var), member_image_type_ (c) + { + } + + image_member (context& c, + string const& var, + semantics::type& t, + string const& fq_type, + string const& key_prefix) + : member_base (c, var, t, fq_type, key_prefix), + member_image_type_ (c, t, fq_type, key_prefix) { } virtual void - pre (type& m) + pre (member_info& mi) { - image_type = member_image_type_.image_type (m); + if (container (mi.t)) + return; - if (!id_) - os << "// " << m.name () << endl + image_type = member_image_type_.image_type (mi.m); + + if (var_override_.empty ()) + os << "// " << mi.m.name () << endl << "//" << endl; } virtual void - traverse_composite (type&) + traverse_composite (member_info& mi) { - os << image_type << " " << var << "value;" + os << image_type << " " << mi.var << "value;" << endl; } virtual void - traverse_integer (type&, sql_type const&) + traverse_integer (member_info& mi) { - os << image_type << " " << var << "value;" - << "my_bool " << var << "null;" + os << image_type << " " << mi.var << "value;" + << "my_bool " << mi.var << "null;" << endl; } virtual void - traverse_float (type&, sql_type const&) + traverse_float (member_info& mi) { - os << image_type << " " << var << "value;" - << "my_bool " << var << "null;" + os << image_type << " " << mi.var << "value;" + << "my_bool " << mi.var << "null;" << endl; } virtual void - traverse_decimal (type&, sql_type const&) + traverse_decimal (member_info& mi) { // Exchanged as strings. Can have up to 65 digits not counting // '-' and '.'. If range is not specified, the default is 10. @@ -61,83 +74,83 @@ namespace mysql /* @@ Disabled. - os << "char " << var << "value[" << + os << "char " << mi.var << "value[" << (t.range ? t.range_value : 10) + 3 << "];" */ - os << image_type << " " << var << "value;" - << "unsigned long " << var << "size;" - << "my_bool " << var << "null;" + os << image_type << " " << mi.var << "value;" + << "unsigned long " << mi.var << "size;" + << "my_bool " << mi.var << "null;" << endl; } virtual void - traverse_date_time (type&, sql_type const&) + traverse_date_time (member_info& mi) { - os << image_type << " " << var << "value;" - << "my_bool " << var << "null;" + os << image_type << " " << mi.var << "value;" + << "my_bool " << mi.var << "null;" << endl; } virtual void - traverse_short_string (type&, sql_type const&) + traverse_short_string (member_info& mi) { // If range is not specified, the default buffer size is 255. // /* @@ Disabled. - os << "char " << var << "value[" << + os << "char " << mi.var << "value[" << (t.range ? t.range_value : 255) + 1 << "];" */ - os << image_type << " " << var << "value;" - << "unsigned long " << var << "size;" - << "my_bool " << var << "null;" + os << image_type << " " << mi.var << "value;" + << "unsigned long " << mi.var << "size;" + << "my_bool " << mi.var << "null;" << endl; } virtual void - traverse_long_string (type&, sql_type const&) + traverse_long_string (member_info& mi) { - os << image_type << " " << var << "value;" - << "unsigned long " << var << "size;" - << "my_bool " << var << "null;" + os << image_type << " " << mi.var << "value;" + << "unsigned long " << mi.var << "size;" + << "my_bool " << mi.var << "null;" << endl; } virtual void - traverse_bit (type&, sql_type const& t) + traverse_bit (member_info& mi) { // Valid range is 1 to 64. // - unsigned int n (t.range / 8 + (t.range % 8 ? 1 : 0)); + unsigned int n (mi.st->range / 8 + (mi.st->range % 8 ? 1 : 0)); - os << "unsigned char " << var << "value[" << n << "];" - << "unsigned long " << var << "size;" - << "my_bool " << var << "null;" + os << "unsigned char " << mi.var << "value[" << n << "];" + << "unsigned long " << mi.var << "size;" + << "my_bool " << mi.var << "null;" << endl; } virtual void - traverse_enum (type&, sql_type const&) + traverse_enum (member_info& mi) { // Represented as string. // - os << image_type << " " << var << "value;" - << "unsigned long " << var << "size;" - << "my_bool " << var << "null;" + os << image_type << " " << mi.var << "value;" + << "unsigned long " << mi.var << "size;" + << "my_bool " << mi.var << "null;" << endl; } virtual void - traverse_set (type&, sql_type const&) + traverse_set (member_info& mi) { // Represented as string. // - os << image_type << " " << var << "value;" - << "unsigned long " << var << "size;" - << "my_bool " << var << "null;" + os << image_type << " " << mi.var << "value;" + << "unsigned long " << mi.var << "size;" + << "my_bool " << mi.var << "null;" << endl; } @@ -175,7 +188,7 @@ namespace mysql struct image_type: traversal::class_, context { image_type (context& c) - : context (c), member_ (c, false) + : context (c), member_ (c) { *this >> names_member_ >> member_; } @@ -203,36 +216,437 @@ namespace mysql traversal::names names_member_; }; - struct id_image_type: traversal::class_, context + // Member-specific traits types for container members. + // + struct container_traits: object_members_base, context { - id_image_type (context& c) - : context (c), image_member_ (c, true) + container_traits (context& c) + : object_members_base (c, true, false), context (c) { - *this >> names_image_member_ >> image_member_; } virtual void - traverse (type& c) + container (semantics::data_member& m) { - os << "struct id_image_type" + using semantics::type; + using semantics::class_; + + type& t (m.type ()); + container_kind_type ck (container_kind (t)); + + type& vt (container_vt (t)); + type* it (0); + type* kt (0); + + switch (ck) + { + case ck_ordered: + { + it = &container_it (t); + break; + } + case ck_map: + case ck_multimap: + { + kt = &container_kt (t); + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + string name (prefix_ + public_name (m) + "_traits"); + + // Figure out column counts. + // + size_t data_columns (1), cond_columns (1); // One for object id. + + switch (ck) + { + case ck_ordered: + { + // Add one for the index. + // + data_columns++; + cond_columns++; + break; + } + case ck_map: + case ck_multimap: + { + // Add some for the key. + // + size_t n; + + if (class_* kc = comp_value (*kt)) + n = column_count (*kc); + else + n = 1; + + data_columns += n; + cond_columns += n; + break; + } + case ck_set: + case ck_multiset: + { + // Value is also a key. + // + if (class_* vc = comp_value (vt)) + cond_columns += column_count (*vc); + else + cond_columns++; + + break; + } + } + + if (class_* vc = comp_value (vt)) + data_columns += column_count (*vc); + else + data_columns++; + + // Store column counts for the source generator. + // + m.set ("cond-column-count", cond_columns); + m.set ("data-column-count", data_columns); + + os << "// " << m.name () << endl + << "//" << endl + << "struct " << name << "{"; - names (c); + // container_type + // index_type + // key_type + // value_type + // + + os << "typedef " << t.fq_name (m.belongs ().hint ()) << + " container_type;"; + + switch (ck) + { + case ck_ordered: + { + os << "typedef " << container_fq_it (m) << " index_type;"; + break; + } + case ck_map: + case ck_multimap: + { + os << "typedef " << container_fq_kt (m) << " key_type;"; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + os << "typedef " << container_fq_vt (m) << " value_type;" + << endl; + + os << "typedef odb::access::container_traits< container_type > " << + "container_traits;"; + + // functions_type + // + switch (ck) + { + case ck_ordered: + { + os << "typedef ordered_functions " << + "functions_type;"; + break; + } + case ck_map: + case ck_multimap: + { + os << "typedef map_functions " << + "functions_type;"; + break; + } + case ck_set: + case ck_multiset: + { + os << "typedef set_functions functions_type;"; + break; + } + } + + os << "typedef mysql::container_statements< " << name << + " > statements_type;" + << endl; + + // column_count + // + os << "static const std::size_t cond_column_count = " << + cond_columns << "UL;" + << "static const std::size_t data_column_count = " << + data_columns << "UL;" + << endl; + + // cond_image_type (object id is taken from the object image) + // + os << "struct cond_image_type" + << "{"; + + switch (ck) + { + case ck_ordered: + { + os << "// index" << endl + << "//" << endl; + image_member im (*this, "index_", *it, "index_type", "index"); + im.traverse (m); + break; + } + case ck_map: + case ck_multimap: + { + os << "// key" << endl + << "//" << endl; + image_member im (*this, "key_", *kt, "key_type", "key"); + im.traverse (m); + break; + } + case ck_set: + case ck_multiset: + { + os << "// value" << endl + << "//" << endl; + image_member im (*this, "value_", vt, "value_type", "value"); + im.traverse (m); + break; + } + } os << "};"; - } - private: - image_member image_member_; - traversal::names names_image_member_; + // data_image_type (object id is taken from the object image) + // + os << "struct data_image_type" + << "{"; + + switch (ck) + { + case ck_ordered: + { + os << "// index" << endl + << "//" << endl; + image_member im (*this, "index_", *it, "index_type", "index"); + im.traverse (m); + break; + } + case ck_map: + case ck_multimap: + { + os << "// key" << endl + << "//" << endl; + image_member im (*this, "key_", *kt, "key_type", "key"); + im.traverse (m); + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + os << "// value" << endl + << "//" << endl; + image_member im (*this, "value_", vt, "value_type", "value"); + im.traverse (m); + + os << "};"; + + // Statements. + // + os << "static const char* const insert_one_statement;" + << "static const char* const select_all_statement;" + << "static const char* const delete_all_statement;" + << endl; + + // bind (cond_image) + // + os << "static void" << endl + << "bind (MYSQL_BIND*, id_image_type*, cond_image_type&);" + << endl; + + // bind (data_image) + // + os << "static void" << endl + << "bind (MYSQL_BIND*, id_image_type*, data_image_type&);" + << endl; + + // grow() + // + os << "static bool" << endl + << "grow (data_image_type&, my_bool*);" + << endl; + + // init (data_image) + // + os << "static bool" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "init (data_image_type&, index_type, const value_type&);"; + break; + } + case ck_map: + case ck_multimap: + { + os << "init (data_image_type&, const key_type&, const value_type&);"; + break; + } + case ck_set: + case ck_multiset: + { + os << "init (data_image_type&, const value_type&);"; + break; + } + } + + os << endl; + + // init (data) + // + os << "static void" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "init (index_type&, value_type&, const data_image_type&);"; + break; + } + case ck_map: + case ck_multimap: + { + os << "init (key_type&, value_type&, const data_image_type&);"; + break; + } + case ck_set: + case ck_multiset: + { + os << "init (value_type&, const data_image_type&);"; + break; + } + } + + os << endl; + + // insert_one + // + os << "static void" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "insert_one (index_type, const value_type&, void*);"; + break; + } + case ck_map: + case ck_multimap: + { + os << "insert_one (const key_type&, const value_type&, void*);"; + break; + } + case ck_set: + case ck_multiset: + { + os << "insert_one (const value_type&, void*);"; + break; + } + } + + os << endl; + + // load_all + // + os << "static bool" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "load_all (index_type&, value_type&, void*);"; + break; + } + case ck_map: + case ck_multimap: + { + os << "load_all (key_type&, value_type&, void*);"; + break; + } + case ck_set: + case ck_multiset: + { + os << "load_all (value_type&, void*);"; + break; + } + } + + os << endl; + + // delete_all + // + os << "static void" << endl + << "delete_all (void*);" + << endl; + + // persist + // + os << "static void" << endl + << "persist (const container_type&," << endl + << "id_image_type&," << endl + << "bool," << endl + << "statements_type&);" + << endl; + + // load + // + os << "static void" << endl + << "load (container_type&," << endl + << "id_image_type&," << endl + << "bool," << endl + << "statements_type&);" + << endl; + + // update + // + os << "static void" << endl + << "update (const container_type&," << endl + << "id_image_type&," << endl + << "bool," << endl + << "statements_type&);" + << endl; + + // erase + // + os << "static void" << endl + << "erase (id_image_type&, bool, statements_type&);" + << endl; + + os << "};"; + } }; + // + // struct class_: traversal::class_, context { class_ (context& c) - : context (c), - image_type_ (c), - id_image_type_ (c) + : context (c), image_type_ (c), id_image_member_ (c, "id_") { } @@ -254,8 +668,7 @@ namespace mysql string const& type (c.fq_name ()); bool def_ctor (TYPE_HAS_DEFAULT_CONSTRUCTOR (c.tree_node ())); - id_member_.traverse (c); - semantics::data_member& id (*id_member_.member ()); + semantics::data_member& id (id_member (c)); bool auto_id (id.count ("auto")); os << "// " << c.name () << endl @@ -284,7 +697,12 @@ namespace mysql // id_image_type // - id_image_type_.traverse (c); + os << "struct id_image_type" + << "{"; + + id_image_member_.traverse (id); + + os << "};"; // query_type & query_base_type // @@ -317,7 +735,7 @@ namespace mysql column_count (c) << "UL;" << endl; - // Queries. + // Statements. // os << "static const char* const persist_statement;" << "static const char* const find_statement;" @@ -329,6 +747,28 @@ namespace mysql os << endl; + // + // Containers. + // + + // Traits types. + // + { + // @@ Make it class members? + // + container_traits t (*this); + t.traverse (c); + } + + // Statement cache (forward declaration). + // + os << "struct container_statement_cache_type;" + << endl; + + // + // Functions. + // + // id () // os << "static id_type" << endl @@ -406,7 +846,9 @@ namespace mysql // os << "private:" << endl << "static bool" << endl - << "find (mysql::object_statements&, const id_type&);"; + << "find (mysql::object_statements&," << endl + << "const id_type&," << endl + << "bool&);"; os << "};"; } @@ -461,9 +903,8 @@ namespace mysql } private: - id_member id_member_; image_type image_type_; - id_image_type id_image_type_; + image_member id_image_member_; }; } diff --git a/odb/mysql/inline.cxx b/odb/mysql/inline.cxx index 47766e2..948caac 100644 --- a/odb/mysql/inline.cxx +++ b/odb/mysql/inline.cxx @@ -34,10 +34,7 @@ namespace mysql { string const& type (c.fq_name ()); string traits ("access::object_traits< " + type + " >"); - - id_member t; - t.traverse (c); - semantics::data_member& id (*t.member ()); + semantics::data_member& id (id_member (c)); os << "// " << c.name () << endl << "//" << endl diff --git a/odb/mysql/schema.cxx b/odb/mysql/schema.cxx index 3ef412b..1dfeb1f 100644 --- a/odb/mysql/schema.cxx +++ b/odb/mysql/schema.cxx @@ -8,10 +8,14 @@ #include #include +using namespace std; + namespace mysql { namespace { + typedef set tables; + struct object_columns: object_columns_base, context { object_columns (context& c) @@ -32,6 +36,118 @@ namespace mysql } }; + struct member_create: object_members_base, context + { + member_create (context& c, semantics::class_& object, tables& t) + : object_members_base (c, false, true), + context (c), + object_ (object), + id_member_ (id_member (object)), + tables_ (t) + { + } + + virtual void + container (semantics::data_member& m) + { + using semantics::type; + using semantics::data_member; + + type& t (m.type ()); + container_kind_type ck (container_kind (t)); + type& vt (container_vt (t)); + + string const& name (table_name (m, table_prefix_)); + + if (tables_.count (name)) + return; + + os << "CREATE TABLE `" << name << "` (" << endl; + + // object_id (simple value) + // + string id_name (column_name (m, "id", "object_id")); + os << " `" << id_name << "` " << column_type (id_member_); + + // index (simple value) + // + string index_name; + if (ck == ck_ordered) + { + index_name = column_name (m, "index", "index"); + + os << "," << endl + << " `" << index_name << "` " << column_type (m, "index"); + } + + // key (simple or composite value) + // + if (ck == ck_map || ck == ck_multimap) + { + type& kt (container_kt (t)); + + os << "," << endl; + + if (comp_value (kt)) + { + object_columns oc (*this); + oc.traverse_composite (m, kt, "key", "key"); + } + else + { + string const& name (column_name (m, "key", "key")); + os << " `" << name << "` " << column_type (m, "key"); + } + } + + // value (simple or composite value) + // + { + os << "," << endl; + + if (comp_value (vt)) + { + object_columns oc (*this); + oc.traverse_composite (m, vt, "value", "value"); + } + else + { + string const& name (column_name (m, "value", "value")); + os << " `" << name << "` " << column_type (m, "value"); + } + } + + // object_id index + // + os << "," << endl + << " INDEX (`" << id_name << "`)"; + + // index index + // + if (ck == ck_ordered) + os << "," << endl + << " INDEX (`" << index_name << "`)"; + + os << ")"; + + string const& engine (options.mysql_engine ()); + + if (engine != "default") + os << endl + << " ENGINE=" << engine; + + os << ";" << endl + << endl; + + tables_.insert (name); + } + + private: + semantics::class_& object_; + semantics::data_member& id_member_; + tables& tables_; + }; + struct class_create: traversal::class_, context { class_create (context& c) @@ -59,8 +175,8 @@ namespace mysql os << "CREATE TABLE `" << name << "` (" << endl; { - object_columns t (*this); - t.traverse (c); + object_columns oc (*this); + oc.traverse (c); } os << ")"; @@ -74,11 +190,45 @@ namespace mysql os << ";" << endl << endl; + // Create tables for members. + // + { + member_create mc (*this, c, tables_); + mc.traverse (c); + } + tables_.insert (name); } private: - std::set tables_; + tables tables_; + }; + + struct member_drop: object_members_base, context + { + member_drop (context& c, semantics::class_& object, tables& t) + : object_members_base (c, false, true), + context (c), + object_ (object), + tables_ (t) + { + } + + virtual void + container (semantics::data_member& m) + { + string const& name (table_name (m, table_prefix_)); + + if (tables_.count (name)) + return; + + os << "DROP TABLE IF EXISTS `" << name << "`;" << endl; + tables_.insert (name); + } + + private: + semantics::class_& object_; + tables& tables_; }; struct class_drop: traversal::class_, context @@ -104,11 +254,18 @@ namespace mysql os << "DROP TABLE IF EXISTS `" << name << "`;" << endl; + // Drop tables for members. + // + { + member_drop mc (*this, c, tables_); + mc.traverse (c); + } + tables_.insert (name); } private: - std::set tables_; + tables tables_; }; static char const file_header[] = diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx index d572560..29495df 100644 --- a/odb/mysql/source.cxx +++ b/odb/mysql/source.cxx @@ -18,21 +18,33 @@ namespace mysql { struct object_columns: object_columns_base, context { - object_columns (context& c, string const& suffix = "") - : object_columns_base (c), context (c), suffix_ (suffix) + object_columns (context& c, char const* suffix = "") + : object_columns_base (c), + context (c), + first_ (true), + suffix_ (suffix) + { + } + + object_columns (context& c, bool first, char const* suffix = "") + : object_columns_base (c), + context (c), + first_ (first), + suffix_ (suffix) { } virtual void column (semantics::data_member&, string const& name, bool first) { - if (!first) + if (!first || !first_) os << ",\"" << endl; os << "\"`" << name << "`" << suffix_; } private: + bool first_; string suffix_; }; @@ -82,43 +94,66 @@ namespace mysql struct bind_member: member_base { - bind_member (context& c, size_t& index, bool id) - : member_base (c, id), index_ (index) + bind_member (context& c, + size_t& index, + string const& var = string (), + string const& arg = string ()) + : member_base (c, var), index_ (index), arg_override_ (arg) + { + } + + bind_member (context& c, + size_t& index, + string const& var, + string const& arg, + semantics::type& t, + string const& fq_type, + string const& key_prefix) + : member_base (c, var, t, fq_type, key_prefix), + index_ (index), + arg_override_ (arg) { } virtual void - pre (type& m) + pre (member_info& mi) { + if (container (mi.t)) + return; + ostringstream ostr; ostr << "b[" << index_ << "UL]"; b = ostr.str (); - if (!id_) - os << "// " << m.name () << endl + arg = arg_override_.empty () ? string ("i") : arg_override_; + + if (var_override_.empty ()) + os << "// " << mi.m.name () << endl << "//" << endl; } virtual void - post (type& m) + post (member_info& mi) { - if (semantics::class_* c = comp_value (m.type ())) + if (container (mi.t)) + return; + else if (semantics::class_* c = comp_value (mi.t)) index_ += column_count (*c); else index_++; } virtual void - traverse_composite (type& m) + traverse_composite (member_info& mi) { - os << "composite_value_traits< " << m.type ().fq_name () << + os << "composite_value_traits< " << mi.fq_type () << " >::bind (" << endl - << "b + " << index_ << "UL, i." << var << "value);" + << "b + " << index_ << "UL, " << arg << "." << mi.var << "value);" << endl; } virtual void - traverse_integer (type&, sql_type const& t) + traverse_integer (member_info& mi) { // While the is_unsigned should indicate whether the // buffer variable is unsigned, rather than whether the @@ -126,51 +161,51 @@ namespace mysql // this is the same. // os << b << ".buffer_type = " << - integer_buffer_types[t.type - sql_type::TINYINT] << ";" - << b << ".is_unsigned = " << (t.unsign ? "1" : "0") << ";" - << b << ".buffer = &i." << var << "value;" - << b << ".is_null = &i." << var << "null;" + integer_buffer_types[mi.st->type - sql_type::TINYINT] << ";" + << b << ".is_unsigned = " << (mi.st->unsign ? "1" : "0") << ";" + << b << ".buffer = &" << arg << "." << mi.var << "value;" + << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } virtual void - traverse_float (type&, sql_type const& t) + traverse_float (member_info& mi) { os << b << ".buffer_type = " << - float_buffer_types[t.type - sql_type::FLOAT] << ";" - << b << ".buffer = &i." << var << "value;" - << b << ".is_null = &i." << var << "null;" + float_buffer_types[mi.st->type - sql_type::FLOAT] << ";" + << b << ".buffer = &" << arg << "." << mi.var << "value;" + << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } virtual void - traverse_decimal (type&, sql_type const&) + traverse_decimal (member_info& mi) { os << b << ".buffer_type = MYSQL_TYPE_NEWDECIMAL;" - << b << ".buffer = i." << var << "value.data ();" + << b << ".buffer = " << arg << "." << mi.var << "value.data ();" << b << ".buffer_length = static_cast (" << endl - << "i." << var << "value.capacity ());" - << b << ".length = &i." << var << "size;" - << b << ".is_null = &i." << var << "null;" + << "" << arg << "." << mi.var << "value.capacity ());" + << b << ".length = &" << arg << "." << mi.var << "size;" + << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } virtual void - traverse_date_time (type&, sql_type const& t) + traverse_date_time (member_info& mi) { os << b << ".buffer_type = " << - date_time_buffer_types[t.type - sql_type::DATE] << ";" - << b << ".buffer = &i." << var << "value;"; + date_time_buffer_types[mi.st->type - sql_type::DATE] << ";" + << b << ".buffer = &" << arg << "." << mi.var << "value;"; - if (t.type == sql_type::YEAR) + if (mi.st->type == sql_type::YEAR) os << b << ".is_unsigned = 0;"; - os << b << ".is_null = &i." << var << "null;" + os << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } virtual void - traverse_short_string (type&, sql_type const& t) + traverse_short_string (member_info& mi) { // MySQL documentation is quite confusing about the use of // buffer_length and length when it comes to input parameters. @@ -178,73 +213,76 @@ namespace mysql // only if length is NULL. // os << b << ".buffer_type = " << - char_bin_buffer_types[t.type - sql_type::CHAR] << ";" - << b << ".buffer = i." << var << "value.data ();" + char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";" + << b << ".buffer = " << arg << "." << mi.var << "value.data ();" << b << ".buffer_length = static_cast (" << endl - << "i." << var << "value.capacity ());" - << b << ".length = &i." << var << "size;" - << b << ".is_null = &i." << var << "null;" + << "" << arg << "." << mi.var << "value.capacity ());" + << b << ".length = &" << arg << "." << mi.var << "size;" + << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } virtual void - traverse_long_string (type&, sql_type const& t) + traverse_long_string (member_info& mi) { os << b << ".buffer_type = " << - char_bin_buffer_types[t.type - sql_type::CHAR] << ";" - << b << ".buffer = i." << var << "value.data ();" + char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";" + << b << ".buffer = " << arg << "." << mi.var << "value.data ();" << b << ".buffer_length = static_cast (" << endl - << "i." << var << "value.capacity ());" - << b << ".length = &i." << var << "size;" - << b << ".is_null = &i." << var << "null;" + << "" << arg << "." << mi.var << "value.capacity ());" + << b << ".length = &" << arg << "." << mi.var << "size;" + << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } virtual void - traverse_bit (type&, sql_type const&) + traverse_bit (member_info& mi) { // Treated as a BLOB. // os << b << ".buffer_type = MYSQL_TYPE_BLOB;" - << b << ".buffer = i." << var << "value;" + << b << ".buffer = " << arg << "." << mi.var << "value;" << b << ".buffer_length = static_cast (" << endl - << "sizeof (i." << var << "value));" - << b << ".length = &i." << var << "size;" - << b << ".is_null = &i." << var << "null;" + << "sizeof (" << arg << "." << mi.var << "value));" + << b << ".length = &" << arg << "." << mi.var << "size;" + << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } virtual void - traverse_enum (type&, sql_type const&) + traverse_enum (member_info& mi) { // Represented as a string. // os << b << ".buffer_type = MYSQL_TYPE_STRING;" - << b << ".buffer = i." << var << "value.data ();" + << b << ".buffer = " << arg << "." << mi.var << "value.data ();" << b << ".buffer_length = static_cast (" << endl - << "i." << var << "value.capacity ());" - << b << ".length = &i." << var << "size;" - << b << ".is_null = &i." << var << "null;" + << "" << arg << "." << mi.var << "value.capacity ());" + << b << ".length = &" << arg << "." << mi.var << "size;" + << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } virtual void - traverse_set (type&, sql_type const&) + traverse_set (member_info& mi) { // Represented as a string. // os << b << ".buffer_type = MYSQL_TYPE_STRING;" - << b << ".buffer = i." << var << "value.data ();" + << b << ".buffer = " << arg << "." << mi.var << "value.data ();" << b << ".buffer_length = static_cast (" << endl - << "i." << var << "value.capacity ());" - << b << ".length = &i." << var << "size;" - << b << ".is_null = &i." << var << "null;" + << "" << arg << "." << mi.var << "value.capacity ());" + << b << ".length = &" << arg << "." << mi.var << "size;" + << b << ".is_null = &" << arg << "." << mi.var << "null;" << endl; } private: - string b; size_t& index_; + + string b; + string arg; + string arg_override_; }; struct bind_base: traversal::class_, context @@ -277,123 +315,139 @@ namespace mysql struct grow_member: member_base { grow_member (context& c, size_t& index) - : member_base (c, false), index_ (index) + : member_base (c), index_ (index) + { + } + + grow_member (context& c, + size_t& index, + string const& var, + semantics::type& t, + string const& fq_type, + string const& key_prefix) + : member_base (c, var, t, fq_type, key_prefix), index_ (index) { } virtual void - pre (type& m) + pre (member_info& mi) { + if (container (mi.t)) + return; + ostringstream ostr; ostr << "e[" << index_ << "UL]"; e = ostr.str (); - os << "// " << m.name () << endl - << "//" << endl; + if (var_override_.empty ()) + os << "// " << mi.m.name () << endl + << "//" << endl; } virtual void - post (type& m) + post (member_info& mi) { - if (semantics::class_* c = comp_value (m.type ())) + if (container (mi.t)) + return; + else if (semantics::class_* c = comp_value (mi.t)) index_ += column_count (*c); else index_++; } virtual void - traverse_composite (type& m) + traverse_composite (member_info& mi) { - os << "if (composite_value_traits< " << m.type ().fq_name () << + os << "if (composite_value_traits< " << mi.fq_type () << " >::grow (" << endl - << "i." << var << "value, e + " << index_ << "UL))" + << "i." << mi.var << "value, e + " << index_ << "UL))" << "{" << "r = true;" << "}"; } virtual void - traverse_integer (type&, sql_type const&) + traverse_integer (member_info&) { os << e << " = 0;" << endl; } virtual void - traverse_float (type&, sql_type const&) + traverse_float (member_info&) { os << e << " = 0;" << endl; } virtual void - traverse_decimal (type&, sql_type const&) + traverse_decimal (member_info& mi) { // @@ Optimization disabled. // os << "if (" << e << ")" << endl << "{" - << "i." << var << "value.capacity (i." << var << "size);" + << "i." << mi.var << "value.capacity (i." << mi.var << "size);" << "r = true;" << "}"; } virtual void - traverse_date_time (type&, sql_type const&) + traverse_date_time (member_info&) { os << e << " = 0;" << endl; } virtual void - traverse_short_string (type&, sql_type const&) + traverse_short_string (member_info& mi) { // @@ Optimization disabled. // os << "if (" << e << ")" << endl << "{" - << "i." << var << "value.capacity (i." << var << "size);" + << "i." << mi.var << "value.capacity (i." << mi.var << "size);" << "r = true;" << "}"; } virtual void - traverse_long_string (type&, sql_type const&) + traverse_long_string (member_info& mi) { os << "if (" << e << ")" << endl << "{" - << "i." << var << "value.capacity (i." << var << "size);" + << "i." << mi.var << "value.capacity (i." << mi.var << "size);" << "r = true;" << "}"; } virtual void - traverse_bit (type&, sql_type const&) + traverse_bit (member_info&) { os << e << " = 0;" << endl; } virtual void - traverse_enum (type&, sql_type const&) + traverse_enum (member_info& mi) { // Represented as a string. // os << "if (" << e << ")" << endl << "{" - << "i." << var << "value.capacity (i." << var << "size);" + << "i." << mi.var << "value.capacity (i." << mi.var << "size);" << "r = true;" << "}"; } virtual void - traverse_set (type&, sql_type const&) + traverse_set (member_info& mi) { // Represented as a string. // os << "if (" << e << ")" << endl << "{" - << "i." << var << "value.capacity (i." << var << "size);" + << "i." << mi.var << "value.capacity (i." << mi.var << "size);" << "r = true;" << "}"; } @@ -434,25 +488,41 @@ namespace mysql struct init_image_member: member_base { - init_image_member (context& c, bool id) - : member_base (c, id), - member_image_type_ (c, id), - member_database_type_ (c) + init_image_member (context& c, + string const& var = string (), + string const& member = string ()) + : member_base (c, var), + member_image_type_ (c), + member_database_type_ (c), + member_override_ (member) { } - virtual void - pre (type& m) + init_image_member (context& c, + string const& var, + string const& member, + semantics::type& t, + string const& fq_type, + string const& key_prefix) + : member_base (c, var, t, fq_type, key_prefix), + member_image_type_ (c, t, fq_type, key_prefix), + member_database_type_ (c, t, fq_type, key_prefix), + member_override_ (member) { - semantics::type& t (m.type ()); + } - if (comp_value (t)) - traits = "composite_value_traits< " + t.fq_name () + " >"; + virtual void + pre (member_info& mi) + { + if (container (mi.t)) + return; + else if (comp_value (mi.t)) + traits = "composite_value_traits< " + mi.fq_type () + " >"; else { - type = t.fq_name (m.belongs ().hint ()); - image_type = member_image_type_.image_type (m); - db_type = member_database_type_.database_type (m); + type = mi.fq_type (); + image_type = member_image_type_.image_type (mi.m); + db_type = member_database_type_.database_type (mi.m); traits = "mysql::value_traits< " + type + ", " @@ -460,11 +530,11 @@ namespace mysql + db_type + " >"; } - if (id_) - member = "id"; + if (!member_override_.empty ()) + member = member_override_; else { - string const& name (m.name ()); + string const& name (mi.m.name ()); member = "o." + name; os << "// " << name << endl @@ -473,9 +543,9 @@ namespace mysql } virtual void - traverse_composite (type&) + traverse_composite (member_info& mi) { - os << "if (" << traits << "::init (i." << var << "value, " << + os << "if (" << traits << "::init (i." << mi.var << "value, " << member << "))" << "{" << "grew = true;" @@ -483,98 +553,98 @@ namespace mysql } virtual void - traverse_integer (type&, sql_type const&) + traverse_integer (member_info& mi) { os << "{" << "bool is_null;" << traits << "::set_image (" << endl - << "i." << var << "value, is_null, " << member << ");" - << "i." << var << "null = is_null;" + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;" << "}"; } virtual void - traverse_float (type&, sql_type const&) + traverse_float (member_info& mi) { os << "{" << "bool is_null;" << traits << "::set_image (" << endl - << "i." << var << "value, is_null, " << member << ");" - << "i." << var << "null = is_null;" + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;" << "}"; } virtual void - traverse_decimal (type&, sql_type const&) + traverse_decimal (member_info& mi) { // @@ Optimization: can remove growth check if buffer is fixed. // os << "{" << "bool is_null;" << "std::size_t size;" - << "std::size_t cap (i." << var << "value.capacity ());" + << "std::size_t cap (i." << mi.var << "value.capacity ());" << traits << "::set_image (" << endl - << "i." << var << "value," << endl + << "i." << mi.var << "value," << endl << "size," << endl << "is_null," << endl << member << ");" - << "i." << var << "size = static_cast (size);" - << "i." << var << "null = is_null;" - << "grew = grew || (cap != i." << var << "value.capacity ());" + << "i." << mi.var << "size = static_cast (size);" + << "i." << mi.var << "null = is_null;" + << "grew = grew || (cap != i." << mi.var << "value.capacity ());" << "}"; } virtual void - traverse_date_time (type&, sql_type const&) + traverse_date_time (member_info& mi) { os << "{" << "bool is_null;" << traits << "::set_image (" << endl - << "i." << var << "value, is_null, " << member << ");" - << "i." << var << "null = is_null;" + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;" << "}"; } virtual void - traverse_short_string (type&, sql_type const&) + traverse_short_string (member_info& mi) { // @@ Optimization: can remove growth check if buffer is fixed. // os << "{" << "bool is_null;" << "std::size_t size;" - << "std::size_t cap (i." << var << "value.capacity ());" + << "std::size_t cap (i." << mi.var << "value.capacity ());" << traits << "::set_image (" << endl - << "i." << var << "value," << endl + << "i." << mi.var << "value," << endl << "size," << endl << "is_null," << endl << member << ");" - << "i." << var << "size = static_cast (size);" - << "i." << var << "null = is_null;" - << "grew = grew || (cap != i." << var << "value.capacity ());" + << "i." << mi.var << "size = static_cast (size);" + << "i." << mi.var << "null = is_null;" + << "grew = grew || (cap != i." << mi.var << "value.capacity ());" << "}"; } virtual void - traverse_long_string (type&, sql_type const&) + traverse_long_string (member_info& mi) { os << "{" << "bool is_null;" << "std::size_t size;" - << "std::size_t cap (i." << var << "value.capacity ());" + << "std::size_t cap (i." << mi.var << "value.capacity ());" << traits << "::set_image (" << endl - << "i." << var << "value," << endl + << "i." << mi.var << "value," << endl << "size," << endl << "is_null," << endl << member << ");" - << "i." << var << "size = static_cast (size);" - << "i." << var << "null = is_null;" - << "grew = grew || (cap != i." << var << "value.capacity ());" + << "i." << mi.var << "size = static_cast (size);" + << "i." << mi.var << "null = is_null;" + << "grew = grew || (cap != i." << mi.var << "value.capacity ());" << "}"; } virtual void - traverse_bit (type&, sql_type const&) + traverse_bit (member_info& mi) { // Represented as a BLOB. // @@ -582,53 +652,53 @@ namespace mysql << "bool is_null;" << "std::size_t size;" << traits << "::set_image (" << endl - << "i." << var << "value," << endl - << "sizeof (i." << var << "value)," << endl + << "i." << mi.var << "value," << endl + << "sizeof (i." << mi.var << "value)," << endl << "size," << endl << "is_null," << endl << member << ");" - << "i." << var << "size = static_cast (size);" - << "i." << var << "null = is_null;" + << "i." << mi.var << "size = static_cast (size);" + << "i." << mi.var << "null = is_null;" << "}"; } virtual void - traverse_enum (type&, sql_type const&) + traverse_enum (member_info& mi) { // Represented as a string. // os << "{" << "bool is_null;" << "std::size_t size;" - << "std::size_t cap (i." << var << "value.capacity ());" + << "std::size_t cap (i." << mi.var << "value.capacity ());" << traits << "::set_image (" << endl - << "i." << var << "value," << endl + << "i." << mi.var << "value," << endl << "size," << endl << "is_null," << endl << member << ");" - << "i." << var << "size = static_cast (size);" - << "i." << var << "null = is_null;" - << "grew = grew || (cap != i." << var << "value.capacity ());" + << "i." << mi.var << "size = static_cast (size);" + << "i." << mi.var << "null = is_null;" + << "grew = grew || (cap != i." << mi.var << "value.capacity ());" << "}"; } virtual void - traverse_set (type&, sql_type const&) + traverse_set (member_info& mi) { // Represented as a string. // os << "{" << "bool is_null;" << "std::size_t size;" - << "std::size_t cap (i." << var << "value.capacity ());" + << "std::size_t cap (i." << mi.var << "value.capacity ());" << traits << "::set_image (" << endl - << "i." << var << "value," << endl + << "i." << mi.var << "value," << endl << "size," << endl << "is_null," << endl << member << ");" - << "i." << var << "size = static_cast (size);" - << "i." << var << "null = is_null;" - << "grew = grew || (cap != i." << var << "value.capacity ());" + << "i." << mi.var << "size = static_cast (size);" + << "i." << mi.var << "null = is_null;" + << "grew = grew || (cap != i." << mi.var << "value.capacity ());" << "}"; } @@ -641,6 +711,8 @@ namespace mysql member_image_type member_image_type_; member_database_type member_database_type_; + + string member_override_; }; struct init_image_base: traversal::class_, context @@ -670,24 +742,37 @@ namespace mysql struct init_value_member: member_base { init_value_member (context& c) - : member_base (c, false), - member_image_type_ (c, false), + : member_base (c), + member_image_type_ (c), member_database_type_ (c) { } - virtual void - pre (type& m) + init_value_member (context& c, + string const& var, + string const& member, + semantics::type& t, + string const& fq_type, + string const& key_prefix) + : member_base (c, var, t, fq_type, key_prefix), + member_image_type_ (c, t, fq_type, key_prefix), + member_database_type_ (c, t, fq_type, key_prefix), + member_override_ (member) { - semantics::type& t (m.type ()); + } - if (comp_value (t)) - traits = "composite_value_traits< " + t.fq_name () + " >"; + virtual void + pre (member_info& mi) + { + if (container (mi.t)) + return; + else if (comp_value (mi.t)) + traits = "composite_value_traits< " + mi.fq_type () + " >"; else { - type = m.type ().fq_name (m.belongs ().hint ()); - image_type = member_image_type_.image_type (m); - db_type = member_database_type_.database_type (m); + type = mi.fq_type (); + image_type = member_image_type_.image_type (mi.m); + db_type = member_database_type_.database_type (mi.m); traits = "mysql::value_traits< " + type + ", " @@ -695,113 +780,122 @@ namespace mysql + db_type + " >"; } - os << "// " << m.name () << endl - << "//" << endl; + if (!member_override_.empty ()) + member = member_override_; + else + { + string const& name (mi.m.name ()); + member = "o." + name; + + os << "// " << name << endl + << "//" << endl; + } } virtual void - traverse_composite (type& m) + traverse_composite (member_info& mi) { - os << traits << "::init (o." << m.name () << ", i." << var << "value);" + os << traits << "::init (" << member << ", i." << + mi.var << "value);" << endl; } virtual void - traverse_integer (type& m, sql_type const&) + traverse_integer (member_info& mi) { os << traits << "::set_value (" << endl - << "o." << m.name () << ", i." << var << "value, " << - "i." << var << "null);" + << member << ", i." << mi.var << "value, " << + "i." << mi.var << "null);" << endl; } virtual void - traverse_float (type& m, sql_type const&) + traverse_float (member_info& mi) { os << traits << "::set_value (" << endl - << "o." << m.name () << ", i." << var << "value, " << - "i." << var << "null);" + << member << ", i." << mi.var << "value, " << + "i." << mi.var << "null);" << endl; } virtual void - traverse_decimal (type& m, sql_type const&) + traverse_decimal (member_info& mi) { os << traits << "::set_value (" << endl - << "o." << m.name () << "," << endl - << "i." << var << "value," << endl - << "i." << var << "size," << endl - << "i." << var << "null);" + << member << "," << endl + << "i." << mi.var << "value," << endl + << "i." << mi.var << "size," << endl + << "i." << mi.var << "null);" << endl; } virtual void - traverse_date_time (type& m, sql_type const&) + traverse_date_time (member_info& mi) { os << traits << "::set_value (" << endl - << "o." << m.name () << ", i." << var << "value, " << - "i." << var << "null);" + << member << ", i." << mi.var << "value, " << + "i." << mi.var << "null);" << endl; } virtual void - traverse_short_string (type& m, sql_type const&) + traverse_short_string (member_info& mi) { os << traits << "::set_value (" << endl - << "o." << m.name () << "," << endl - << "i." << var << "value," << endl - << "i." << var << "size," << endl - << "i." << var << "null);" + << member << "," << endl + << "i." << mi.var << "value," << endl + << "i." << mi.var << "size," << endl + << "i." << mi.var << "null);" << endl; } virtual void - traverse_long_string (type& m, sql_type const&) + traverse_long_string (member_info& mi) { os << traits << "::set_value (" << endl - << "o." << m.name () << "," << endl - << "i." << var << "value," << endl - << "i." << var << "size," << endl - << "i." << var << "null);" + << member << "," << endl + << "i." << mi.var << "value," << endl + << "i." << mi.var << "size," << endl + << "i." << mi.var << "null);" << endl; } virtual void - traverse_bit (type& m, sql_type const&) + traverse_bit (member_info& mi) { // Represented as a BLOB. // os << traits << "::set_value (" << endl - << "o." << m.name () << "," << endl - << "i." << var << "value," << endl - << "i." << var << "size," << endl - << "i." << var << "null);" + << member << "," << endl + << "i." << mi.var << "value," << endl + << "i." << mi.var << "size," << endl + << "i." << mi.var << "null);" << endl; } virtual void - traverse_enum (type& m, sql_type const&) + traverse_enum (member_info& mi) { // Represented as a string. // os << traits << "::set_value (" << endl - << "o." << m.name () << "," << endl - << "i." << var << "value," << endl - << "i." << var << "size," << endl - << "i." << var << "null);" + << member << "," << endl + << "i." << mi.var << "value," << endl + << "i." << mi.var << "size," << endl + << "i." << mi.var << "null);" << endl; } virtual void - traverse_set (type& m, sql_type const&) + traverse_set (member_info& mi) { // Represented as a string. // os << traits << "::set_value (" << endl - << "o." << m.name () << "," << endl - << "i." << var << "value," << endl - << "i." << var << "size," << endl - << "i." << var << "null);" + << member << "," << endl + << "i." << mi.var << "value," << endl + << "i." << mi.var << "size," << endl + << "i." << mi.var << "null);" << endl; } @@ -810,9 +904,12 @@ namespace mysql string db_type; string image_type; string traits; + string member; member_image_type member_image_type_; member_database_type member_database_type_; + + string member_override_; }; struct init_value_base: traversal::class_, context @@ -832,6 +929,872 @@ namespace mysql } }; + // Member-specific traits types for container members. + // + struct container_traits: object_members_base, context + { + container_traits (context& c, semantics::class_& obj) + : object_members_base (c, true, true), + context (c), + object_ (obj), + id_member_ (id_member (obj)) + { + obj_scope_ = "access::object_traits< " + obj.fq_name () + " >"; + } + + virtual void + container (semantics::data_member& m) + { + using semantics::type; + + type& t (m.type ()); + container_kind_type ck (container_kind (t)); + + type& vt (container_vt (t)); + type* it (0); + type* kt (0); + + bool grow (false); + + switch (ck) + { + case ck_ordered: + { + it = &container_it (t); + grow = grow || context::grow (m, *it, "index"); + break; + } + case ck_map: + case ck_multimap: + { + kt = &container_kt (t); + grow = grow || context::grow (m, *kt, "key"); + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + grow = grow || context::grow (m, vt, "value"); + + string name (prefix_ + public_name (m) + "_traits"); + string scope (obj_scope_ + "::" + name); + + os << "// " << m.name () << endl + << "//" << endl + << endl; + + // + // Statements. + // + string table (table_name (m, table_prefix_)); + + // insert_one_statement + // + os << "const char* const " << scope << "::insert_one_statement =" << endl + << "\"INSERT INTO `" << table << "` (\"" << endl + << "\"`" << column_name (m, "id", "object_id") << "`"; + + switch (ck) + { + case ck_ordered: + { + os << ",\"" << endl + << "\"`" << column_name (m, "index", "index") << "`"; + break; + } + case ck_map: + case ck_multimap: + { + if (comp_value (*kt)) + { + object_columns t (*this, false); + t.traverse_composite (m, *kt, "key", "key"); + } + else + { + os << ",\"" << endl + << "\"`" << column_name (m, "key", "key") << "`"; + } + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + if (comp_value (vt)) + { + object_columns t (*this, false); + t.traverse_composite (m, vt, "value", "value"); + } + else + { + os << ",\"" << endl + << "\"`" << column_name (m, "value", "value") << "`"; + } + + os << "\"" << endl + << "\") VALUES ("; + + for (size_t i (0), n (m.get ("data-column-count")); i < n; ++i) + os << (i != 0 ? "," : "") << '?'; + + os << ")\";" + << endl; + + // select_all_statement + // + os << "const char* const " << scope << "::select_all_statement =" << endl + << "\"SELECT \"" << endl + << "\"`" << column_name (m, "id", "object_id") << "`"; + + switch (ck) + { + case ck_ordered: + { + os << ",\"" << endl + << "\"`" << column_name (m, "index", "index") << "`"; + break; + } + case ck_map: + case ck_multimap: + { + if (comp_value (*kt)) + { + object_columns t (*this, false); + t.traverse_composite (m, *kt, "key", "key"); + } + else + { + os << ",\"" << endl + << "\"`" << column_name (m, "key", "key") << "`"; + } + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + if (comp_value (vt)) + { + object_columns t (*this, false); + t.traverse_composite (m, vt, "value", "value"); + } + else + { + os << ",\"" << endl + << "\"`" << column_name (m, "value", "value") << "`"; + } + + os << "\"" << endl + << "\" FROM `" << table << "` WHERE `" << + column_name (m, "id", "object_id") << "` = ?\"" << endl; + + if (ck == ck_ordered) + os << "\" ORDER BY `" << column_name (m, "index", "index") << "`\""; + + os << ";" + << endl; + + // delete_all_statement + // + os << "const char* const " << scope << "::delete_all_statement =" << endl + << "\"DELETE FROM `" << table << "`\"" << endl + << "\" WHERE `" << column_name (m, "id", "object_id") << "` = ?\";" + << endl; + + // + // Functions. + // + + // bind() + // + { + size_t index; + bind_member bind_id (*this, index, "id_", "id"); + + // bind (cond_image_type) + // + os << "void " << scope << "::" << endl + << "bind (MYSQL_BIND* b, id_image_type* p, cond_image_type& c)" + << "{"; + + index = 0; + + os << "// object_id" << endl + << "//" << endl + << "if (p != 0)" + << "{" + << "id_image_type& id (*p);"; + bind_id.traverse (id_member_); + os << "}"; + + switch (ck) + { + case ck_ordered: + { + os << "// index" << endl + << "//" << endl; + bind_member bm ( + *this, index, "index_", "c", *it, "index_type", "index"); + bm.traverse (m); + break; + } + case ck_map: + case ck_multimap: + { + os << "// key" << endl + << "//" << endl; + bind_member bm ( + *this, index, "key_", "c", *kt, "key_type", "key"); + bm.traverse (m); + break; + } + case ck_set: + case ck_multiset: + { + os << "// value" << endl + << "//" << endl; + bind_member bm ( + *this, index, "value_", "c", vt, "value_type", "value"); + bm.traverse (m); + break; + } + } + + os << "}"; + + // bind (data_image_type) + // + os << "void " << scope << "::" << endl + << "bind (MYSQL_BIND* b, id_image_type* p, data_image_type& d)" + << "{"; + + index = 0; + + os << "// object_id" << endl + << "//" << endl + << "if (p != 0)" + << "{" + << "id_image_type& id (*p);"; + bind_id.traverse (id_member_); + os << "}"; + + switch (ck) + { + case ck_ordered: + { + os << "// index" << endl + << "//" << endl; + bind_member bm ( + *this, index, "index_", "d", *it, "index_type", "index"); + bm.traverse (m); + break; + } + case ck_map: + case ck_multimap: + { + os << "// key" << endl + << "//" << endl; + bind_member bm ( + *this, index, "key_", "d", *kt, "key_type", "key"); + bm.traverse (m); + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + os << "// value" << endl + << "//" << endl; + bind_member bm ( + *this, index, "value_", "d", vt, "value_type", "value"); + bm.traverse (m); + + os << "}"; + } + + // grow () + // + { + size_t index (0); + + os << "bool " << scope << "::" << endl + << "grow (data_image_type&" << (grow ? " i" : "") << ", my_bool* e)" + << "{" + << "bool r (false);" + << endl; + + switch (ck) + { + case ck_ordered: + { + os << "// index" << endl + << "//" << endl; + grow_member gm ( + *this, index, "index_", *it, "index_type", "index"); + gm.traverse (m); + break; + } + case ck_map: + case ck_multimap: + { + os << "// key" << endl + << "//" << endl; + grow_member gm (*this, index, "key_", *kt, "key_type", "key"); + gm.traverse (m); + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + os << "// value" << endl + << "//" << endl; + grow_member gm (*this, index, "value_", vt, "value_type", "value"); + gm.traverse (m); + + os << "return r;" + << "}"; + } + + // init (data_image) + // + os << "bool " << scope << "::" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "init (data_image_type& i, index_type j, const value_type& v)" + << "{" + << "bool grew (false);" + << endl + << "// index" << endl + << "//" << endl; + + init_image_member im ( + *this, "index_", "j", *it, "index_type", "index"); + im.traverse (m); + + break; + } + case ck_map: + case ck_multimap: + { + os << "init (data_image_type& i, const key_type& k, " << + "const value_type& v)" + << "{" + << "bool grew (false);" + << endl + << "// key" << endl + << "//" << endl; + + init_image_member im (*this, "key_", "k", *kt, "key_type", "key"); + im.traverse (m); + + break; + } + case ck_set: + case ck_multiset: + { + os << "init (data_image_type& i, const value_type& v)" + << "{" + << "bool grew (false);" + << endl; + break; + } + } + + os << "// value" << endl + << "//" << endl; + { + init_image_member im ( + *this, "value_", "v", vt, "value_type", "value"); + im.traverse (m); + } + os << "return grew;" + << "}"; + + // init (data) + // + os << "void " << scope << "::" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "init (index_type& j, value_type& v, const data_image_type& i)" + << "{" + << "// index" << endl + << "//" << endl; + + init_value_member im ( + *this, "index_", "j", *it, "index_type", "index"); + im.traverse (m); + + break; + } + case ck_map: + case ck_multimap: + { + os << "init (key_type& k, value_type& v, const data_image_type& i)" + << "{" + << "// key" << endl + << "//" << endl; + + init_value_member im (*this, "key_", "k", *kt, "key_type", "key"); + im.traverse (m); + + break; + } + case ck_set: + case ck_multiset: + { + os << "init (value_type& v, const data_image_type& i)" + << "{"; + break; + } + } + + os << "// value" << endl + << "//" << endl; + { + init_value_member im ( + *this, "value_", "v", vt, "value_type", "value"); + im.traverse (m); + } + os << "}"; + + // insert_one + // + os << "void " << scope << "::" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "insert_one (index_type i, const value_type& v, void* d)"; + break; + } + case ck_map: + case ck_multimap: + { + os << "insert_one (const key_type& k, const value_type& v, void* d)"; + break; + } + case ck_set: + case ck_multiset: + { + os << "insert_one (const value_type& v, void* d)"; + break; + } + } + + os << "{" + << "using namespace mysql;" + << endl + << "typedef container_statements< " << name << " > statements;" + << "statements& sts (*static_cast< statements* > (d));" + << "binding& b (sts.data_image_binding ());" + << "data_image_type& di (sts.data_image ());" + << endl + << "if ("; + + switch (ck) + { + case ck_ordered: + { + os << "init (di, i, v)"; + break; + } + case ck_map: + case ck_multimap: + { + os << "init (di, k, v)"; + break; + } + case ck_set: + case ck_multiset: + { + os << "init (di, v)"; + break; + } + } + + os << " || b.version == 0)" + << "{" + << "bind (b.bind, 0, di);" + << "b.version++;" + << "}" + << "if (!sts.insert_one_statement ().execute ())" << endl + << "throw object_already_persistent ();" + << "}"; + + + // load_all + // + os << "bool " << scope << "::" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "load_all (index_type& i, value_type& v, void* d)"; + break; + } + case ck_map: + case ck_multimap: + { + os << "load_all (key_type& k, value_type& v, void* d)"; + break; + } + case ck_set: + case ck_multiset: + { + os << "load_all (value_type& v, void* d)"; + break; + } + } + + os << "{" + << "using namespace mysql;" + << endl + << "typedef container_statements< " << name << " > statements;" + << "statements& sts (*static_cast< statements* > (d));" + << "data_image_type& di (sts.data_image ());"; + + // Extract current element. + // + switch (ck) + { + case ck_ordered: + { + os << "init (i, v, di);"; + break; + } + case ck_map: + case ck_multimap: + { + os << "init (k, v, di);"; + break; + } + case ck_set: + case ck_multiset: + { + os << "init (v, di);"; + break; + } + } + + // Fetch next. + // + os << endl + << "select_statement& st (sts.select_all_statement ());" + << "select_statement::result r (st.fetch ());"; + + if (grow) + os << endl + << "if (r == select_statement::truncated)" + << "{" + << "if (grow (di, sts.data_image_error ()))" + << "{" + << "binding& db (sts.data_image_binding ());" + << "bind (db.bind, 0, di);" + << "db.version++;" + << "st.refetch ();" + << "}" + << "}"; + + os << "if (r == select_statement::no_data)" + << "{" + << "st.free_result ();" + << "return false;" + << "}" + << "return true;" + << "}"; + + // delete_all + // + os << "void " << scope << "::" << endl + << "delete_all (void* d)" + << "{" + << "using namespace mysql;" + << endl + << "typedef container_statements< " << name << " > statements;" + << "statements& sts (*static_cast< statements* > (d));" + << "sts.delete_all_statement ().execute ();" + << "}"; + + // persist + // + os << "void " << scope << "::" << endl + << "persist (const container_type& c," << endl + << "id_image_type& id," << endl + << "bool rebind," << endl + << "statements_type& sts)" + << "{" + << "using namespace mysql;" + << endl + << "binding& b (sts.data_image_binding ());" + << "if (rebind || b.version == 0)" + << "{" + << "bind (b.bind, &id, sts.data_image ());" + << "b.version++;" + << "}" + << "if (rebind)" // We don't need it, just don't miss the event. + << "{" + << "binding& cb (sts.cond_image_binding ());" + << "bind (cb.bind, &id, sts.cond_image ());" + << "cb.version++;" + << "}" + << "container_traits::persist (c, sts.functions ());" + << "}"; + + // load + // + os << "void " << scope << "::" << endl + << "load (container_type& c," << endl + << "id_image_type& id," << endl + << "bool rebind," << endl + << "statements_type& sts)" + << "{" + << "using namespace mysql;" + << endl + << "binding& db (sts.data_image_binding ());" + << "if (rebind || db.version == 0)" + << "{" + << "bind (db.bind, &id, sts.data_image ());" + << "db.version++;" + << "}" + << "binding& cb (sts.cond_image_binding ());" + << "if (rebind || cb.version == 0)" + << "{" + << "bind (cb.bind, &id, sts.cond_image ());" + << "cb.version++;" + << "}" + << "select_statement& st (sts.select_all_statement ());" + << "st.execute ();" + << "select_statement::result r (st.fetch ());"; + + if (grow) + os << endl + << "if (r == select_statement::truncated)" + << "{" + << "if (grow (sts.data_image (), sts.data_image_error ()))" + << "{" + << "bind (db.bind, 0, sts.data_image ());" + << "db.version++;" + << "st.refetch ();" + << "}" + << "}"; + + os << "bool more (r != select_statement::no_data);" + << endl + << "if (!more)" << endl + << "st.free_result ();" + << endl + << "container_traits::load (c, more, sts.functions ());" + << "}"; + + // update + // + os << "void " << scope << "::" << endl + << "update (const container_type& c," << endl + << "id_image_type& id," << endl + << "bool rebind," << endl + << "statements_type& sts)" + << "{" + << "using namespace mysql;" + << endl + << "binding& db (sts.data_image_binding ());" + << "if (rebind || db.version == 0)" + << "{" + << "bind (db.bind, &id, sts.data_image ());" + << "db.version++;" + << "}" + << "binding& cb (sts.cond_image_binding ());" + << "if (rebind || cb.version == 0)" // We may need it (delete_all). + << "{" + << "bind (cb.bind, &id, sts.cond_image ());" + << "cb.version++;" + << "}" + << "container_traits::update (c, sts.functions ());" + << "}"; + + // erase + // + os << "void " << scope << "::" << endl + << "erase (id_image_type& id, bool rebind, statements_type& sts)" + << "{" + << "using namespace mysql;" + << endl + << "binding& b (sts.cond_image_binding ());" + << "if (rebind || b.version == 0)" + << "{" + << "bind (b.bind, &id, sts.cond_image ());" + << "b.version++;" + << "}" + << "if (rebind)" + << "{" + << "binding& db (sts.data_image_binding ());" + << "bind (db.bind, &id, sts.data_image ());" + << "db.version++;" + << "}" + << "container_traits::erase (sts.functions ());" + << "}"; + } + + private: + string obj_scope_; + semantics::class_& object_; + semantics::data_member& id_member_; + }; + + // Container statement cache members. + // + struct container_cache_members: object_members_base, context + { + container_cache_members (context& c) + : object_members_base (c, true, false), + context (c), + containers_ (false) + { + } + + bool + containers () const + { + return containers_; + } + + virtual void + container (semantics::data_member& m) + { + string traits (prefix_ + public_name (m) + "_traits"); + os << "mysql::container_statements< " << traits << " > " << + prefix_ << m.name () << ";"; + + containers_ = true; + } + + private: + bool containers_; + }; + + struct container_cache_init_members: object_members_base, context + { + container_cache_init_members (context& c) + : object_members_base (c, true, false), context (c), first_ (true) + { + } + + virtual void + container (semantics::data_member& m) + { + if (first_) + { + os << endl + << ": "; + first_ = false; + } + else + os << "," << endl + << " "; + + os << prefix_ << m.name () << " (c)"; + } + + private: + bool first_; + }; + + // Calls for container members. + // + struct container_calls: object_members_base, context + { + enum call_type + { + persist_call, + load_call, + update_call, + erase_call + }; + + container_calls (context& c, call_type call) + : object_members_base (c, true, false), context (c), call_ (call) + { + } + + virtual void + composite (semantics::data_member& m, semantics::type& t) + { + string old (obj_prefix_); + obj_prefix_ += m.name (); + obj_prefix_ += '.'; + object_members_base::composite (m, t); + obj_prefix_ = old; + } + + virtual void + container (semantics::data_member& m) + { + using semantics::type; + + string const& name (m.name ()); + string obj_name (obj_prefix_ + name); + string sts_name (prefix_ + name); + string traits (prefix_ + public_name (m) + "_traits"); + + switch (call_) + { + case persist_call: + { + os << traits << "::persist (obj." << obj_name << ", i, grew, " << + "sts.container_statment_cache ()." << sts_name << ");"; + break; + } + case load_call: + { + os << traits << "::load (obj." << obj_name << ", i, grew, " << + "sts.container_statment_cache ()." << sts_name << ");"; + break; + } + case update_call: + { + os << traits << "::update (obj." << obj_name << ", i, grew, " << + "sts.container_statment_cache ()." << sts_name << ");"; + break; + } + case erase_call: + { + os << traits << "::erase (i, grew, " << + "sts.container_statment_cache ()." << sts_name << ");"; + break; + } + } + } + + private: + call_type call_; + string obj_prefix_; + }; + // // struct class_: traversal::class_, context @@ -841,11 +1804,11 @@ namespace mysql grow_base_ (c, index_), grow_member_ (c, index_), bind_base_ (c, index_), - bind_member_ (c, index_, false), - bind_id_member_ (c, index_, true), + bind_member_ (c, index_), + bind_id_member_ (c, index_, "id_"), init_image_base_ (c), - init_image_member_ (c, false), - init_id_image_member_ (c, true), + init_image_member_ (c), + init_id_image_member_ (c, "id_", "id"), init_value_base_ (c), init_value_member_ (c) { @@ -854,13 +1817,10 @@ namespace mysql bind_base_inherits_ >> bind_base_; bind_member_names_ >> bind_member_; - bind_id_member_names_ >> bind_id_member_; init_image_base_inherits_ >> init_image_base_; init_image_member_names_ >> init_image_member_; - init_id_image_member_names_ >> init_id_image_member_; - init_value_base_inherits_ >> init_value_base_; init_value_member_names_ >> init_value_member_; } @@ -886,14 +1846,48 @@ namespace mysql bool grow (context::grow (c)); bool def_ctor (TYPE_HAS_DEFAULT_CONSTRUCTOR (c.tree_node ())); - id_member_.traverse (c); - semantics::data_member& id (*id_member_.member ()); + semantics::data_member& id (id_member (c)); bool auto_id (id.count ("auto")); os << "// " << c.name () << endl << "//" << endl << endl; + // + // Containers. + // + + // Statement cache (definition). + // + bool containers; + { + os << "struct " << traits << "::container_statement_cache_type" + << "{"; + + container_cache_members cm (*this); + cm.traverse (c); + containers = cm.containers (); + + os << (containers ? "\n" : "") + << "container_statement_cache_type (mysql::connection&" << + (containers ? " c" : "") << ")"; + + container_cache_init_members im (*this); + im.traverse (c); + + os << "{" + << "}" + << "};"; + } + + // Traits types. + // + if (containers) + { + container_traits t (*this, c); + t.traverse (c); + } + // query columns // if (options.generate_query ()) @@ -1008,7 +2002,7 @@ namespace mysql << "{"; index_ = 0; - names (c, bind_id_member_names_); + bind_id_member_.traverse (id); os << "}"; @@ -1060,11 +2054,36 @@ namespace mysql << "bind (b.bind, sts.image ());" << "b.version++;" << "}" - << "mysql::persist_statement& st (sts.persist_statement ());" - << "st.execute ();"; + << "insert_statement& st (sts.persist_statement ());" + << "if (!st.execute ())" << endl + << "throw object_already_persistent ();" + << endl; if (auto_id) - os << "obj." << id.name () << " = static_cast (st.id ());"; + os << "obj." << id.name () << " = static_cast (st.id ());" + << endl; + + if (containers) + { + // Initialize id_image. + // + os << "{" + << "bool grew (false);" + << "const id_type& id (obj." << id.name () << ");" + << "id_image_type& i (sts.id_image ());"; + init_id_image_member_.traverse (id); + os << "binding& idb (sts.id_image_binding ());" + << "if (grew && idb.version != 0)" + << "{" + << "bind (idb.bind, i);" + << "idb.version++;" + << "}"; + + container_calls t (*this, container_calls::persist_call); + t.traverse (c); + + os << "}"; + } os << "}"; @@ -1082,7 +2101,7 @@ namespace mysql << "bool grew (false);" << "const id_type& id (object_traits::id (obj));" << "id_image_type& i (sts.id_image ());"; - names (c, init_id_image_member_names_); + init_id_image_member_.traverse (id); os << "binding& idb (sts.id_image_binding ());" << "if (grew || idb.version == 0)" << "{" @@ -1095,8 +2114,16 @@ namespace mysql << "bind (imb.bind, sts.image ());" << "imb.version++;" << "}" - << "sts.update_statement ().execute ();" - << "}"; + << "sts.update_statement ().execute ();"; + + if (containers) + { + os << endl; + container_calls t (*this, container_calls::update_call); + t.traverse (c); + } + + os << "}"; // erase () // @@ -1111,19 +2138,29 @@ namespace mysql << endl << "bool grew (false);" << "id_image_type& i (sts.id_image ());"; - names (c, init_id_image_member_names_); + init_id_image_member_.traverse (id); os << "binding& idb (sts.id_image_binding ());" << "if (grew || idb.version == 0)" << "{" << "bind (idb.bind, i);" << "idb.version++;" << "}" - << "sts.erase_statement ().execute ();" - << "}"; + << "if (sts.erase_statement ().execute () != 1)" << endl + << "throw object_not_persistent ();"; + + if (containers) + { + os << endl; + container_calls t (*this, container_calls::erase_call); + t.traverse (c); + } + + os << "}"; // find () // if (def_ctor) + { os << traits << "::pointer_type" << endl << traits << "::" << endl << "find (database&, const id_type& id)" @@ -1134,18 +2171,30 @@ namespace mysql << "object_statements& sts (" << endl << "conn.statement_cache ().find ());" << endl - << "if (find (sts, id))" + << "bool grew (false);" + << "if (find (sts, id, grew))" << "{" << "pointer_type p (access::object_factory< " << type << " >::create ());" << "pointer_traits< pointer_type >::guard g (p);" - << "init (pointer_traits< pointer_type >::get_ref (p), " << - "sts.image ());" - << "g.release ();" + << "object_type& obj (pointer_traits< pointer_type >::get_ref (p));" + << "init (obj, sts.image ());"; + + if (containers) + { + os << endl + << "id_image_type& i (sts.id_image ());"; + container_calls t (*this, container_calls::load_call); + t.traverse (c); + os << endl; + } + + os << "g.release ();" << "return p;" << "}" << "return pointer_type ();" << "}"; + } os << "bool " << traits << "::" << endl << "find (database&, const id_type& id, object_type& obj)" @@ -1156,23 +2205,34 @@ namespace mysql << "object_statements& sts (" << endl << "conn.statement_cache ().find ());" << endl - << "if (find (sts, id))" + << "bool grew (false);" + << "if (find (sts, id, grew))" << "{" - << "init (obj, sts.image ());" - << "return true;" + << "init (obj, sts.image ());"; + + if (containers) + { + os << endl + << "id_image_type& i (sts.id_image ());"; + container_calls t (*this, container_calls::load_call); + t.traverse (c); + os << endl; + } + + os << "return true;" << "}" << "return false;" << "}"; os << "bool " << traits << "::" << endl - << "find (mysql::object_statements& sts, " << - "const id_type& id)" + << "find (mysql::object_statements& sts," << endl + << "const id_type& id," << endl + << "bool& grew)" << "{" << "using namespace mysql;" << endl - << "bool grew (false);" << "id_image_type& i (sts.id_image ());"; - names (c, init_id_image_member_names_); + init_id_image_member_.traverse (id); os << "binding& idb (sts.id_image_binding ());" << "if (grew || idb.version == 0)" << "{" @@ -1185,15 +2245,13 @@ namespace mysql << "bind (imb.bind, sts.image ());" << "imb.version++;" << "}" - << "mysql::find_statement& st (sts.find_statement ());" - << "mysql::find_statement::result r (st.execute ());" - << endl - << "if (r == mysql::find_statement::no_data)" << endl - << "return false;" - << endl; + << "select_statement& st (sts.find_statement ());" + << "st.execute ();" + << "select_statement::result r (st.fetch ());"; if (grow) - os << "if (r == mysql::find_statement::truncated)" + os << endl + << "if (r == select_statement::truncated)" << "{" << "if (grow (sts.image (), sts.image_error ()))" << "{" @@ -1204,7 +2262,7 @@ namespace mysql << "}"; os << "st.free_result ();" - << "return true;" + << "return r != select_statement::no_data;" << "}"; // query () @@ -1227,11 +2285,11 @@ namespace mysql << "bind (imb.bind, sts.image ());" << "imb.version++;" << "}" - << "details::shared_ptr st (" << endl - << "new (details::shared) query_statement (conn," << endl + << "details::shared_ptr st (" << endl + << "new (details::shared) select_statement (conn," << endl << "query_clause + q.clause ()," << endl - << "imb," << endl - << "q.parameters ()));" + << "q.parameters ()," << endl + << "imb));" << "st->execute ();" << endl << "details::shared_ptr > r (" << endl @@ -1244,6 +2302,9 @@ namespace mysql virtual void traverse_value (type& c) { + bool columns (column_count (c) != 0); + bool grow (columns && context::grow (c)); + string const& type (c.fq_name ()); string traits ("access::composite_value_traits< " + type + " >"); @@ -1254,7 +2315,8 @@ namespace mysql // grow () // os << "bool " << traits << "::" << endl - << "grow (image_type&" << (grow (c) ? " i" : "") << ", my_bool* e)" + << "grow (image_type&" << (grow ? " i" : "") << ", " << + "my_bool*" << (columns ? " e" : "") << ")" << "{" << "bool r (false);" << endl; @@ -1269,7 +2331,8 @@ namespace mysql // bind (image_type) // os << "void " << traits << "::" << endl - << "bind (MYSQL_BIND* b, image_type& i)" + << "bind (MYSQL_BIND*" << (columns ? " b" : "") << ", " << + "image_type&" << (columns ? " i" : "") << ")" << "{"; index_ = 0; @@ -1281,7 +2344,8 @@ namespace mysql // init (image, object) // os << "bool " << traits << "::" << endl - << "init (image_type& i, const value_type& o)" + << "init (image_type&" << (columns ? " i" : "") << ", " << + "const value_type&" << (columns ? " o" : "") << ")" << "{" << "bool grew (false);" << endl; @@ -1295,7 +2359,8 @@ namespace mysql // init (object, image) // os << "void " << traits << "::" << endl - << "init (value_type& o, const image_type& i)" + << "init (value_type&" << (columns ? " o" : "") << ", " << + "const image_type&" << (columns ? " i" : "") << ")" << "{"; inherits (c, init_value_base_inherits_); @@ -1305,8 +2370,6 @@ namespace mysql } private: - id_member id_member_; - bool id_; size_t index_; @@ -1320,7 +2383,6 @@ namespace mysql bind_member bind_member_; traversal::names bind_member_names_; bind_member bind_id_member_; - traversal::names bind_id_member_names_; init_image_base init_image_base_; traversal::inherits init_image_base_inherits_; @@ -1328,7 +2390,6 @@ namespace mysql traversal::names init_image_member_names_; init_image_member init_id_image_member_; - traversal::names init_id_image_member_names_; init_value_base init_value_base_; traversal::inherits init_value_base_inherits_; @@ -1359,6 +2420,9 @@ namespace mysql << "#include " << endl << "#include " << endl << "#include " << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl << "#include " << endl; if (ctx.options.generate_query ()) -- cgit v1.1