From 3a1eed21d4d5d0e7f6a9f400420fdc28d7be9b61 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 17 Feb 2012 10:08:18 +0200 Subject: Add support for composite object ids New pragma id_type (member). New test: common/composite-id. The composite example has also been updated. --- odb/relational/common.cxx | 259 ++++++--- odb/relational/common.hxx | 189 ++++++- odb/relational/common.txx | 112 ++++ odb/relational/header.hxx | 41 +- odb/relational/model.hxx | 328 ++++++----- odb/relational/mssql/common.cxx | 103 +--- odb/relational/mssql/common.hxx | 132 +---- odb/relational/mssql/context.cxx | 17 +- odb/relational/mssql/context.hxx | 8 +- odb/relational/mssql/model.cxx | 2 +- odb/relational/mssql/source.cxx | 343 +----------- odb/relational/mysql/common.cxx | 103 +--- odb/relational/mysql/common.hxx | 118 +--- odb/relational/mysql/context.cxx | 17 +- odb/relational/mysql/context.hxx | 7 +- odb/relational/mysql/model.cxx | 2 +- odb/relational/mysql/source.cxx | 361 ++---------- odb/relational/oracle/common.cxx | 101 +--- odb/relational/oracle/common.hxx | 118 +--- odb/relational/oracle/context.cxx | 17 +- odb/relational/oracle/context.hxx | 8 +- odb/relational/oracle/model.cxx | 4 +- odb/relational/oracle/source.cxx | 356 ++---------- odb/relational/pgsql/common.cxx | 101 +--- odb/relational/pgsql/common.hxx | 118 +--- odb/relational/pgsql/context.cxx | 17 +- odb/relational/pgsql/context.hxx | 8 +- odb/relational/pgsql/model.cxx | 2 +- odb/relational/pgsql/source.cxx | 436 +++------------ odb/relational/processor.cxx | 147 +++-- odb/relational/source.hxx | 1096 ++++++++++++++++++++++++++++--------- odb/relational/sqlite/common.cxx | 103 +--- odb/relational/sqlite/common.hxx | 118 +--- odb/relational/sqlite/context.cxx | 17 +- odb/relational/sqlite/context.hxx | 8 +- odb/relational/sqlite/model.cxx | 2 +- odb/relational/sqlite/source.cxx | 340 +----------- 37 files changed, 2062 insertions(+), 3197 deletions(-) create mode 100644 odb/relational/common.txx (limited to 'odb/relational') diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx index bf325f7..381d77f 100644 --- a/odb/relational/common.cxx +++ b/odb/relational/common.cxx @@ -78,16 +78,11 @@ namespace relational } } - bool query_columns_base:: - traverse_column (semantics::data_member& m, string const& column, bool) + void query_columns_base:: + traverse_pointer (semantics::data_member& m, semantics::class_& c) { - semantics::class_* ptr (object_pointer (utype (m))); - - if (ptr == 0) - return false; - string name (public_name (m)); - bool inv (inverse (m)); + bool inv (inverse (m, key_prefix_)); if (decl_) { @@ -101,7 +96,7 @@ namespace relational os << "typedef" << endl << "odb::query_pointer<" << endl << " odb::pointer_query_columns<" << endl - << " " << class_fq_name (*ptr) << "," << endl + << " " << class_fq_name (c) << "," << endl << " " << name << "_alias_ > >" << endl << name << "_type_ ;" << endl @@ -111,11 +106,32 @@ namespace relational } else { - // For now use column name as table alias. - // @@ This will become problematic when we add support for composite ids. + // Come up with a table alias. Generally, we want it to be based + // on the column name. This is straightforward for single-column + // references. In case of a composite id, we will need to use the + // column prefix which is based on the data member name, unless + // overridden by the user. In the latter case the prefix can be + // empty, in which case we will just fall back on the member's + // public name. // + string alias; + + if (composite_wrapper (utype ((*id_member (c))))) + { + string p (column_prefix (m, key_prefix_, default_name_)); + + if (p.empty ()) + p = public_name_db (m); + else + p.resize (p.size () - 1); // Remove trailing underscore. + + alias = column_prefix_ + p; + } + else + alias = column_prefix_ + column_name (m, key_prefix_, default_name_); + os << "const char " << scope_ << "::" << name << "_alias_[] = " << - strlit (quote_id (column)) << ";" + strlit (quote_id (alias)) << ";" << endl; if (inv) @@ -123,8 +139,6 @@ namespace relational << scope_ << "::" << name << ";" << endl; } - - return true; } // query_columns @@ -132,13 +146,13 @@ namespace relational query_columns:: query_columns (bool ptr) - : ptr_ (ptr), decl_ (true) + : ptr_ (ptr), decl_ (true), in_ptr_ (false) { } query_columns:: query_columns (bool ptr, semantics::class_& c) //@@ context::{cur,top}_object - : ptr_ (ptr), decl_ (false) + : ptr_ (ptr), decl_ (false), in_ptr_ (false) { scope_ = ptr ? "pointer_query_columns" : "query_columns"; scope_ += "< " + class_fq_name (c) + ", table >"; @@ -164,12 +178,13 @@ namespace relational } string name (public_name (*m)); + string suffix (in_ptr_ ? "_column_type_" : "_type_"); if (decl_) { os << "// " << name << endl << "//" << endl - << "struct " << name << "_type_"; + << "struct " << name << suffix; // Derive from the base in query_columns_base. It contains columns // data for the pointer members. @@ -178,27 +193,29 @@ namespace relational os << ": " << name << "_base_"; os << "{" - << name << "_type_ (){}"; // For some reason GCC needs this c-tor - // if we make the static member const. + << name << suffix << " (){}"; // For some reason GCC needs this c-tor + // if we make the static member const. object_columns_base::traverse_composite (m, c); - os << "};" - << "static const " << name << "_type_ " << name << ";" - << endl; + os << "};"; + + if (!in_ptr_) + os << "static const " << name << "_type_ " << name << ";" + << endl; } else { // Handle nested members first. // string old_scope (scope_); - scope_ += "::" + name + "_type_"; + scope_ += "::" + name + suffix; object_columns_base::traverse_composite (m, c); scope_ = old_scope; - // Composite member. + // Composite member. Note that here we don't use suffix. // os << "template " << endl << "const typename " << scope_ << "::" << name << "_type_" << endl @@ -216,39 +233,16 @@ namespace relational << "}"; } - bool query_columns:: - traverse_column (semantics::data_member& m, string const& column, bool) + void query_columns:: + column_common (semantics::data_member& m, + string const& type, + string const& column, + string const& suffix) { - semantics::names* hint; - semantics::type& t (utype (m, hint)); - semantics::class_* ptr (object_pointer (t)); - - if (ptr != 0) - { - // If this is for the pointer_query_columns and the member is not - // inverse, then create the normal member corresponding to the id - // column. This will allow the user to check it for NULL or to - // compare ids. In case this is for query_columns, then for the - // inverse member everything has been generated in query_columns_base. - // - if (inverse (m)) - return false; - } - string name (public_name (m)); if (decl_) { - string type; - if (ptr != 0) - { - semantics::data_member& id (*id_member (*ptr)); - semantics::type& t (utype (id, hint)); - type = t.fq_name (hint); - } - else - type = t.fq_name (hint); - string type_id (database_type_id (m)); os << "// " << name << endl @@ -259,43 +253,14 @@ namespace relational << " " << db << "::value_traits<" << endl << " " << type << "," << endl << " " << type_id << " >::query_type," << endl - << " " << type_id << " >" << endl; - - if (ptr == 0 || ptr_) - os << name << "_type_;" - << endl; - else - { - os << name << "_column_type_;" - << endl - << "typedef" << endl - << "odb::query_pointer<" << endl - << " odb::pointer_query_columns<" << endl - << " " << class_fq_name (*ptr) << "," << endl - << " " << name << "_alias_ > >" << endl - << name << "_pointer_type_;" - << endl; - - // If this is a non-inverse relationship, then make the column have - // a dual interface: that of an object pointer and of an id column. - // The latter allows the user to, for example, use the is_null() - // test in a natural way. For inverse relationships there is no - // column and so the column interface is not available. - // - os << "struct " << name << "_type_: " << - name << "_pointer_type_, " << name << "_column_type_" - << "{"; - - column_ctor (name + "_type_", name + "_column_type_"); - - os << "};"; - } - - os << "static const " << name << "_type_ " << name << ";" + << " " << type_id << " >" << endl + << name << suffix << ";" << endl; } else { + // Note that here we don't use suffix. + // os << "template " << endl << "const typename " << scope_ << "::" << name << "_type_" << endl << scope_ << "::" << name << " (" << "table, " << @@ -306,10 +271,134 @@ namespace relational os << ");" << endl; } + } + + bool query_columns:: + traverse_column (semantics::data_member& m, string const& column, bool) + { + semantics::names* hint; + semantics::type& t (utype (m, hint)); + + column_common (m, t.fq_name (hint), column); + + if (decl_) + { + string name (public_name (m)); + + os << "static const " << name << "_type_ " << name << ";" + << endl; + } return true; } + void query_columns:: + traverse_pointer (semantics::data_member& m, semantics::class_& c) + { + // If this is for the pointer_query_columns and the member is not + // inverse, then create the normal member corresponding to the id + // column. This will allow the user to check it for NULL or to + // compare ids. In case this is for query_columns, then for the + // inverse member everything has been generated in query_columns_base. + // + if (inverse (m, key_prefix_)) + return; + + string name (public_name (m)); + + semantics::data_member& id (*id_member (c)); + semantics::names* hint; + semantics::type& t (utype (id, hint)); + + if (composite_wrapper (t)) + { + // Composite id. + // + + // For pointer_query_columns generate normal composite mapping. + // + if (ptr_) + object_columns_base::traverse_pointer (m, c); + else + { + // If this is a non-inverse relationship, then make the column have + // a dual interface: that of an object pointer and of an id column. + // The latter allows the user to, for example, use the is_null() + // test in a natural way. For inverse relationships there is no + // column and so the column interface is not available. + // + in_ptr_ = true; + object_columns_base::traverse_pointer (m, c); + in_ptr_ = false; + + if (decl_) + { + os << "typedef" << endl + << "odb::query_pointer<" << endl + << " odb::pointer_query_columns<" << endl + << " " << class_fq_name (c) << "," << endl + << " " << name << "_alias_ > >" << endl + << name << "_pointer_type_;" + << endl; + + os << "struct " << name << "_type_: " << + name << "_pointer_type_, " << name << "_column_type_" + << "{" + << "};"; + + os << "static const " << name << "_type_ " << name << ";" + << endl; + } + } + } + else + { + // Simple id. + // + string type (t.fq_name (hint)); + string column (column_prefix_ + + column_name (m, key_prefix_, default_name_)); + + // For pointer_query_columns generate normal column mapping. + // + if (ptr_) + column_common (m, type, column); + else + { + // If this is a non-inverse relationship, then make the column have + // a dual interface: that of an object pointer and of an id column. + // The latter allows the user to, for example, use the is_null() + // test in a natural way. For inverse relationships there is no + // column and so the column interface is not available. + // + column_common (m, type, column, "_column_type_"); + + if (decl_) + { + os << "typedef" << endl + << "odb::query_pointer<" << endl + << " odb::pointer_query_columns<" << endl + << " " << class_fq_name (c) << "," << endl + << " " << name << "_alias_ > >" << endl + << name << "_pointer_type_;" + << endl; + + os << "struct " << name << "_type_: " << + name << "_pointer_type_, " << name << "_column_type_" + << "{"; + + column_ctor (name + "_type_", name + "_column_type_"); + + os << "};"; + } + } + + if (decl_) + os << "static const " << name << "_type_ " << name << ";" + << endl; + } + } + // // Dynamic traversal support. // diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx index d552a72..276868c 100644 --- a/odb/relational/common.hxx +++ b/odb/relational/common.hxx @@ -42,7 +42,7 @@ namespace relational protected: // For virtual inheritance only. Should not be actually called. // - member_base (); // {assert (false);} + member_base (); protected: string var_override_; @@ -51,6 +51,176 @@ namespace relational string key_prefix_; }; + // Template argument is the database SQL type (sql_type). + // + template + struct member_base_impl: virtual member_base + { + typedef member_base_impl base_impl; + + member_base_impl (base const& x): base (x) {} + + protected: + member_base_impl () {} + + public: + virtual T const& + member_sql_type (semantics::data_member&) = 0; + + virtual void + traverse (semantics::data_member&); + + struct member_info + { + semantics::data_member& m; // Member. + semantics::type& t; // Cvr-unqualified member C++ type, note + // that m.type () may not be the same as t. + semantics::class_* ptr; // Pointed-to object if m is an object + // pointer. In this case t is the id type + // while fq_type_ is the pointer fq-type. + semantics::type* wrapper; // Wrapper type if member is a composite or + // container wrapper, also cvr-unqualified. + // In this case t is the wrapped type. + bool cq; // True if the original (wrapper) type + // is const-qualified. + T const* st; // Member SQL type (only simple values). + string& var; // Member variable name with trailing '_'. + + // C++ type fq-name. + // + string + fq_type (bool unwrap = true) const + { + semantics::names* hint; + + if (wrapper != 0 && unwrap) + { + // Use the hint from the wrapper unless the wrapped type + // is qualified. + // + hint = wrapper->get ("wrapper-hint"); + utype (*context::wrapper (*wrapper), hint); + return t.fq_name (hint); + } + + // Use the original type from 'm' instead of 't' since the hint may + // be invalid for a different type. Plus, if a type is overriden, + // then the fq_type must be as well. + // + if (ptr != 0) + { + semantics::type& t (utype (*id_member (*ptr), hint)); + return t.fq_name (hint); + } + else if (fq_type_.empty ()) + { + semantics::type& t (utype (m, hint)); + return t.fq_name (hint); + } + else + return fq_type_; + } + + string + ptr_fq_type () const + { + assert (ptr != 0); + + if (fq_type_.empty ()) + { + // If type is overridden so should fq_type so it is safe to + // get the type from the member. + // + semantics::names* hint; + semantics::type& t (utype (m, hint)); + return t.fq_name (hint); + } + else + return fq_type_; + } + + string const& fq_type_; + + member_info (semantics::data_member& m_, + semantics::type& t_, + semantics::type* wrapper_, + bool cq_, + string& var_, + string const& fq_type) + : m (m_), + t (t_), + ptr (0), + wrapper (wrapper_), + cq (cq_), + st (0), + var (var_), + fq_type_ (fq_type) + { + } + }; + + bool + container (member_info& mi) + { + // This cannot be a container if we have a type override. + // + return type_override_ == 0 && context::container (mi.m); + } + + // The false return value indicates that no further callbacks + // should be called for this member. + // + virtual bool + pre (member_info&) + { + return true; + } + + virtual void + post (member_info&) + { + } + + virtual void + traverse_composite (member_info&) + { + } + + virtual void + traverse_container (member_info&) + { + } + + // Note that by default traverse_object_pointer() will traverse the + // pointed-to object id type. + // + virtual void + traverse_object_pointer (member_info&); + + virtual void + traverse_simple (member_info&) = 0; + }; + + // + // + struct member_database_type_id: virtual member_base + { + typedef member_database_type_id base; + + member_database_type_id (semantics::type* type = 0, + string const& fq_type = string (), + string const& key_prefix = string ()) + : member_base (type, fq_type, key_prefix) + { + } + + virtual string + database_type_id (semantics::data_member&) + { + assert (false); + } + }; + // // struct query_columns_base: object_columns_base, virtual context @@ -66,8 +236,8 @@ namespace relational virtual void traverse_composite (semantics::data_member*, semantics::class_&); - virtual bool - traverse_column (semantics::data_member&, string const&, bool); + virtual void + traverse_pointer (semantics::data_member&, semantics::class_&); protected: bool decl_; @@ -103,13 +273,24 @@ namespace relational virtual void traverse_composite (semantics::data_member*, semantics::class_&); + virtual void + column_common (semantics::data_member&, + string const& type, + string const& column, + string const& suffix = "_type_"); + virtual bool traverse_column (semantics::data_member&, string const&, bool); + virtual void + traverse_pointer (semantics::data_member&, semantics::class_&); + protected: bool ptr_; bool decl_; + bool in_ptr_; // True if we are "inside" an object pointer. + string scope_; string table_; string default_table_; @@ -349,4 +530,6 @@ namespace relational } } +#include + #endif // ODB_RELATIONAL_COMMON_HXX diff --git a/odb/relational/common.txx b/odb/relational/common.txx new file mode 100644 index 0000000..1d3ecbf --- /dev/null +++ b/odb/relational/common.txx @@ -0,0 +1,112 @@ +// file : odb/relational/common.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +namespace relational +{ + // + // member_base_impl + // + + template + void member_base_impl:: + traverse (semantics::data_member& m) + { + if (transient (m)) + return; + + string var; + + if (!var_override_.empty ()) + var = var_override_; + else + { + string const& name (m.name ()); + var = name + (name[name.size () - 1] == '_' ? "" : "_"); + } + + bool cq (type_override_ != 0 ? false : const_type (m.type ())); + semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m)); + + semantics::type* cont; + if (semantics::class_* c = object_pointer (t)) + { + semantics::type& t (utype (*id_member (*c))); + semantics::class_* comp (composite_wrapper (t)); + + member_info mi (m, + (comp != 0 ? *comp : t), + (comp != 0 && wrapper (t) ? &t : 0), + cq, + var, + fq_type_override_); // Pointer type. + + mi.ptr = c; + + if (comp == 0) + mi.st = &member_sql_type (m); + + if (pre (mi)) + { + traverse_object_pointer (mi); + post (mi); + } + } + else if (semantics::class_* c = composite_wrapper (t)) + { + // If t is a wrapper, pass the wrapped type. Also pass the + // original, wrapper type. + // + member_info mi (m, + *c, + (wrapper (t) ? &t : 0), + cq, + var, + fq_type_override_); + if (pre (mi)) + { + traverse_composite (mi); + post (mi); + } + } + // This cannot be a container if we have a type override. + // + else if (type_override_ == 0 && (cont = context::container (m))) + { + // The same unwrapping logic as for composite values. + // + member_info mi (m, + *cont, + (wrapper (t) ? &t : 0), + cq, + var, + fq_type_override_); + if (pre (mi)) + { + traverse_container (mi); + post (mi); + } + } + else + { + member_info mi (m, t, 0, cq, var, fq_type_override_); + mi.st = &member_sql_type (m); + + if (pre (mi)) + { + traverse_simple (mi); + post (mi); + } + } + } + + template + void member_base_impl:: + traverse_object_pointer (member_info& mi) + { + if (composite (mi.t)) // Already unwrapped. + traverse_composite (mi); + else + traverse_simple (mi); + } +} diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index cf103b5..dda9e2a 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -441,8 +441,11 @@ namespace relational // size_t n; - if (class_* kc = composite_wrapper (*kt)) - n = column_count (*kc).total; + class_* ptr (object_pointer (*kt)); + semantics::type& t (ptr == 0 ? *kt : utype (*id_member (*ptr))); + + if (class_* comp = composite_wrapper (t)) + n = column_count (*comp).total; else n = 1; @@ -461,19 +464,27 @@ namespace relational // // Value is also a key. // - //if (class_* vc = composite_wrapper (vt)) - // cond_columns += column_count (*vc).total; - //else - // cond_columns++; - + // class_* ptr (object_pointer (vt)); + // semantics::type& t (ptr == 0 ? vt : utype (*id_member (*ptr))); + // + // if (class_* comp = composite_wrapper (t)) + // cond_columns += column_count (*comp).total; + // else + // cond_columns++; + // break; } } - if (class_* vc = composite_wrapper (vt)) - data_columns += column_count (*vc).total; - else - data_columns++; + { + class_* ptr (object_pointer (vt)); + semantics::type& t (ptr == 0 ? vt : utype (*id_member (*ptr))); + + if (class_* comp = composite_wrapper (t)) + data_columns += column_count (*comp).total; + else + data_columns++; + } // Store column counts for the source generator. // @@ -786,7 +797,7 @@ namespace relational } } - os << "const data_image_type&, database&);" + os << "const data_image_type&, database*);" << endl; // insert_one @@ -1138,7 +1149,7 @@ namespace relational // init (object, image) // os << "static void" << endl - << "init (object_type&, const image_type&, database&);" + << "init (object_type&, const image_type&, database*);" << endl; // init (id_image, id) @@ -1503,7 +1514,7 @@ namespace relational // init (view, image) // os << "static void" << endl - << "init (view_type&, const image_type&, database&);" + << "init (view_type&, const image_type&, database*);" << endl; // column_count @@ -1605,7 +1616,7 @@ namespace relational // init (value, image) // os << "static void" << endl - << "init (value_type&, const image_type&, database&);" + << "init (value_type&, const image_type&, database*);" << endl; os << "};"; diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx index 5f6470d..66db3d6 100644 --- a/odb/relational/model.hxx +++ b/odb/relational/model.hxx @@ -26,12 +26,10 @@ namespace relational { typedef object_columns base; - object_columns (sema_rel::model& model, - sema_rel::table& table, - string const& prefix = string ()) + object_columns (sema_rel::model& model, sema_rel::table& table) : model_ (model), table_ (table), - prefix_ (prefix), + pkey_ (0), id_override_ (false) { } @@ -77,20 +75,25 @@ namespace relational virtual void traverse (semantics::data_member& m, - semantics::class_& c, - std::string const& kp, - std::string const& dn) + semantics::type& t, + string const& kp, + string const& dn, + semantics::class_* to = 0) { // This overrides the member name for a composite container value // or key. // if (!kp.empty ()) { - id_prefix_ = kp + "."; - id_override_ = true; + semantics::class_* c (object_pointer (t)); + if (composite_wrapper (c == 0 ? t : utype (*id_member (*c)))) + { + id_prefix_ = kp + "."; + id_override_ = true; + } } - object_columns_base::traverse (m, c, kp, dn); + object_columns_base::traverse (m, t, kp, dn, to); } using object_columns_base::traverse; @@ -98,23 +101,22 @@ namespace relational virtual bool traverse_column (semantics::data_member& m, string const& name, bool) { - // Ignore inverse object pointers. - // - if (inverse (m)) - return false; + bool id (object_columns_base::id ()); // Id or part of. + bool null (!id && context::null (m, key_prefix_)); - string id (id_prefix_ + (prefix_.empty () ? m.name () : prefix_)); + string col_id (id_prefix_ + + (key_prefix_.empty () ? m.name () : key_prefix_)); sema_rel::column& c ( - model_.new_node ( - id, column_type (m, prefix_), context::null (m, prefix_))); + model_.new_node (col_id, column_type (), null)); + c.set ("cxx-node", static_cast (&m)); model_.new_edge (table_, c, name); // An id member cannot have a default value. // - if (!context::id (m)) + if (!id) { string const& d (default_ (m)); @@ -124,14 +126,12 @@ namespace relational // If we have options, add them. // - string const& o (column_options (m, prefix_)); + string const& o (column_options (m, key_prefix_)); if (!o.empty ()) c.options (o); - constraints (m, name, id, c); - reference (m, name, id, c); - + constraints (m, name, col_id, c); return true; } @@ -188,58 +188,129 @@ namespace relational string const& /* id */, sema_rel::column& c) { - if (!id (m)) - return; - - sema_rel::primary_key& pk ( - model_.new_node (m.count ("auto"))); - pk.set ("cxx-node", static_cast (&m)); - - model_.new_edge (pk, c); - - // In most databases the primary key constraint can be manipulated - // without an explicit name. So we use the special empty name for - // primary keys in order not to clash with columns and other - // constraints. If the target database does not support unnamed - // primary key manipulation, then the database-specific code will - // have to come up with a suitable name. - // - model_.new_edge (table_, pk, ""); + if (table_.is_a ()) + { + if (semantics::data_member* idm = id ()) + { + if (pkey_ == 0) + { + pkey_ = &model_.new_node ( + m.count ("auto")); + pkey_->set ("cxx-node", static_cast (idm)); + + // In most databases the primary key constraint can be + // manipulated without an explicit name. So we use the special + // empty name for primary keys in order not to clash with + // columns and other constraints. If the target database does + // not support unnamed primary key manipulation, then the + // database-specific code will have to come up with a suitable + // name. + // + model_.new_edge (table_, *pkey_, ""); + } + + model_.new_edge (*pkey_, c); + } + } } virtual void - reference (semantics::data_member& m, - string const& name, - string const& id, - sema_rel::column& c) + traverse_pointer (semantics::data_member& m, semantics::class_& c) { - semantics::class_* p (object_pointer (member_utype (m, prefix_))); + using sema_rel::column; - if (p == 0) + // Ignore inverse object pointers. + // + if (inverse (m, key_prefix_)) return; + string id (id_prefix_ + + (key_prefix_.empty () ? m.name () : key_prefix_)); + sema_rel::foreign_key& fk ( model_.new_node ( id, - table_name (*p), + table_name (c), true)); // deferred fk.set ("cxx-node", static_cast (&m)); - fk.referenced_columns ().push_back (column_name (*id_member (*p))); + bool simple; + + // Get referenced columns. + // + { + semantics::data_member& idm (*id_member (c)); + + instance ocl; + ocl->traverse (idm); + + for (object_columns_list::iterator i (ocl->begin ()); + i != ocl->end (); ++i) + fk.referenced_columns ().push_back (i->name); + + simple = (fk.referenced_columns ().size () == 1); + } + + // Get the position of the last column. + // + sema_rel::table::names_iterator i (table_.names_end ()); + + while (i != table_.names_begin ()) + { + --i; + + if (i->nameable ().is_a ()) + break; + } + + // Traverse the object pointer as columns. + // + object_columns_base::traverse_pointer (m, c); - model_.new_edge (fk, c); + // Add the newly added columns to the foreign key. + // + if (i != table_.names_end ()) + ++i; + else + i = table_.names_begin (); + + for (; i != table_.names_end (); ++i) + { + if (column* c = dynamic_cast (&i->nameable ())) + model_.new_edge (fk, *c); + else + break; + } // Derive the constraint name. Generally, we want it to be based - // on the column name. This is straightforward for single column - // references. In case of the composite ids, we will need to use - // the column prefix which is based on the data member name, - // unless overridden (see how the column pragma works for members - // of composite value types). @@ This is a TODO. Perhaps use the - // up-to-and-including composite member prefix? Though it can be - // empty. + // on the column name. This is straightforward for single-column + // references. In case of a composite id, we will need to use the + // column prefix which is based on the data member name, unless + // overridden by the user. In the latter case the prefix can be + // empty, in which case we will just fall back on the member's + // public name. // - model_.new_edge (table_, fk, name + "_fk"); + string name; + + if (simple) + name = fk.contains_begin ()->column ().name (); + else + { + string p (column_prefix (m, key_prefix_, default_name_)); + + if (p.empty ()) + p = public_name_db (m); + + name = column_prefix_ + p; + } + + // Add an underscore unless we already have one. + // + if (name[name.size () - 1] != '_') + name += '_'; + + model_.new_edge (table_, fk, name + "fk"); } protected: @@ -249,7 +320,7 @@ namespace relational protected: sema_rel::model& model_; sema_rel::table& table_; - string prefix_; + sema_rel::primary_key* pkey_; string id_prefix_; bool id_override_; }; @@ -310,13 +381,15 @@ namespace relational using semantics::type; using semantics::data_member; + using sema_rel::index; + using sema_rel::column; + // Ignore inverse containers of object pointers. // if (inverse (m, "value")) return; container_kind_type ck (container_kind (ct)); - type& vt (container_vt (ct)); qname const& name (table_name (m, table_prefix_)); @@ -332,15 +405,14 @@ namespace relational model_.new_edge (model_, t, name); - // object_id (simple value, for now) + // object_id // - string id_name (column_name (m, "id", "object_id")); { - instance oc (model_, t, "id"); - oc->traverse_column (m, id_name, true); + instance oc (model_, t); + oc->traverse (m, container_idt (m), "id", "object_id"); } - // Foreign key for the object id. + // Foreign key and index for the object id. // { sema_rel::foreign_key& fk ( @@ -349,105 +421,91 @@ namespace relational table_name (*context::top_object), false, // immediate sema_rel::foreign_key::cascade)); - fk.set ("cxx-node", static_cast (&m)); - fk.referenced_columns ().push_back ( - column_name ( - *id_member (*context::top_object))); + index& in (model_.new_node (id + ".id")); + in.set ("cxx-node", static_cast (&m)); + + // Get referenced columns. + // + { + data_member& idm (*id_member (*context::top_object)); + + instance ocl; + ocl->traverse (idm); + + for (object_columns_list::iterator i (ocl->begin ()); + i != ocl->end (); ++i) + fk.referenced_columns ().push_back (i->name); + } // All the columns we have in this table so far are for the - // object id. + // object id. Add them to the foreign key and the index. // for (sema_rel::table::names_iterator i (t.names_begin ()); i != t.names_end (); ++i) - model_.new_edge ( - fk, dynamic_cast (i->nameable ())); + { + column& c (dynamic_cast (i->nameable ())); - // Derive the constraint name. See the comment for the other - // foreign key code above. + model_.new_edge (fk, c); + model_.new_edge (in, c); + } + + // Derive the names. See the comment for the other foreign key + // code above. // - model_.new_edge (t, fk, id_name + "_fk"); - } + // Note also that id_name can be a column prefix (if id is + // composite), in which case it can be empty and if not, then + // it will most likely already contain a trailing underscore. + // + string id_name (column_name (m, "id", "object_id")); - // index (simple value) - // - string index_name; - bool ordered (ck == ck_ordered && !unordered (m)); - if (ordered) - { - instance oc (model_, t, "index"); - index_name = column_name (m, "index", "index"); - oc->traverse_column (m, index_name, true); - } + if (id_name.empty ()) + id_name = "object_id"; - // key (simple or composite value) - // - if (ck == ck_map || ck == ck_multimap) - { - type& kt (container_kt (ct)); + if (id_name[id_name.size () - 1] != '_') + id_name += '_'; - if (semantics::class_* ckt = composite_wrapper (kt)) - { - instance oc (model_, t); - oc->traverse (m, *ckt, "key", "key"); - } - else - { - instance oc (model_, t, "key"); - string const& name (column_name (m, "key", "key")); - oc->traverse_column (m, name, true); - } + model_.new_edge (t, fk, id_name + "fk"); + + model_.new_edge ( + model_, in, name + "_" + id_name + "i"); } - // value (simple or composite value) + // index (simple value) // + bool ordered (ck == ck_ordered && !unordered (m)); + if (ordered) { - if (semantics::class_* cvt = composite_wrapper (vt)) - { - instance oc (model_, t); - oc->traverse (m, *cvt, "value", "value"); - } - else - { - instance oc (model_, t, "value"); - string const& name (column_name (m, "value", "value")); - oc->traverse_column (m, name, true); - } - } + instance oc (model_, t); + oc->traverse (m, container_it (ct), "index", "index"); - // Create indexes. - // - using sema_rel::index; - using sema_rel::column; + string col_name (column_name (m, "index", "index")); - { - index& i (model_.new_node (id + ".id")); - i.set ("cxx-node", static_cast (&m)); + index& in (model_.new_node (id + ".index")); + in.set ("cxx-node", static_cast (&m)); model_.new_edge ( - i, dynamic_cast (t.find (id_name)->nameable ())); + in, dynamic_cast (t.find (col_name)->nameable ())); - //@@ Once id can be composite, we need to revise this (see - // a comment for the foreign key generation above). - // model_.new_edge ( - model_, i, name + "_" + id_name + "_i"); + model_, in, name + "_" + col_name + "_i"); } - if (ordered) + // key + // + if (ck == ck_map || ck == ck_multimap) { - index& i (model_.new_node (id + ".index")); - i.set ("cxx-node", static_cast (&m)); - - model_.new_edge ( - i, dynamic_cast (t.find (index_name)->nameable ())); + instance oc (model_, t); + oc->traverse (m, container_kt (ct), "key", "key"); + } - // This is always a single column (simple value). - // - model_.new_edge ( - model_, i, name + "_" + index_name + "_i"); + // value + // + { + instance oc (model_, t); + oc->traverse (m, container_vt (ct), "value", "value"); } } diff --git a/odb/relational/mssql/common.cxx b/odb/relational/mssql/common.cxx index f4ce42e..20be733 100644 --- a/odb/relational/mssql/common.cxx +++ b/odb/relational/mssql/common.cxx @@ -16,91 +16,10 @@ namespace relational // member_base // - void member_base:: - traverse (semantics::data_member& m) + sql_type const& member_base:: + member_sql_type (semantics::data_member& m) { - if (transient (m)) - return; - - string var; - - if (!var_override_.empty ()) - var = var_override_; - else - { - string const& name (m.name ()); - var = name + (name[name.size () - 1] == '_' ? "" : "_"); - } - - bool cq (type_override_ != 0 ? false : const_type (m.type ())); - semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m)); - - semantics::type* cont; - if (semantics::class_* c = composite_wrapper (t)) - { - // If t is a wrapper, pass the wrapped type. Also pass the - // original, wrapper type. - // - member_info mi (m, - *c, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_composite (mi); - post (mi); - } - } - // This cannot be a container if we have a type override. - // - else if (type_override_ == 0 && (cont = context::container (m))) - { - // The same unwrapping logic as for composite values. - // - member_info mi (m, - *cont, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_container (mi); - post (mi); - } - } - else - { - sql_type const& st (column_sql_type (m, key_prefix_)); - - if (semantics::class_* c = object_pointer (t)) - { - member_info mi (m, - utype (*id_member (*c)), - 0, - cq, - var, - fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_object_pointer (mi); - post (mi); - } - } - else - { - member_info mi (m, t, 0, cq, var, fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_simple (mi); - post (mi); - } - } - } + return parse_sql_type (column_type (m, key_prefix_), m); } void member_base:: @@ -406,15 +325,23 @@ namespace relational }; member_database_type_id:: + member_database_type_id (base const& x) + : member_base::base (x), // virtual base + base (x) + { + } + + member_database_type_id:: member_database_type_id (semantics::type* type, string const& fq_type, string const& key_prefix) - : relational::member_base (type, fq_type, key_prefix) + : member_base::base (type, fq_type, key_prefix), // virtual base + base (type, fq_type, key_prefix) { } string member_database_type_id:: - database_type_id (type& m) + database_type_id (semantics::data_member& m) { type_id_.clear (); member_base::traverse (m); @@ -535,6 +462,8 @@ namespace relational type_id_ = "mssql::id_rowversion"; } + entry member_database_type_id_; + // // query_columns // @@ -566,7 +495,7 @@ namespace relational { // For some types we need to pass precision and scale. // - sql_type const& st (column_sql_type (m)); + sql_type const& st (parse_sql_type (column_type (), m)); switch (st.type) { diff --git a/odb/relational/mssql/common.hxx b/odb/relational/mssql/common.hxx index 7f2009a..a04c9a3 100644 --- a/odb/relational/mssql/common.hxx +++ b/odb/relational/mssql/common.hxx @@ -12,118 +12,18 @@ namespace relational { namespace mssql { - struct member_base: virtual relational::member_base, context + struct member_base: virtual relational::member_base_impl, context { - member_base (base const& x): base (x) {} + member_base (base const& x): base (x), base_impl (x) {} // This c-tor is for the direct use inside the mssql namespace. // If you do use this c-tor, you should also explicitly call - // relational::member_base. + // relational::member_base (aka base). // member_base () {} - virtual void - traverse (semantics::data_member& m); - - struct member_info - { - semantics::data_member& m; // Member. - semantics::type& t; // Cvr-unqualified member C++ type, note - // that m.type () may not be the same as t. - semantics::type* wrapper; // Wrapper type if member is a composite or - // container wrapper, also cvr-unqualified. - // In this case t is the wrapped type. - bool cq; // True if the original (wrapper) type - // is const-qualified. - sql_type const* st; // Member SQL type (only simple values). - string& var; // Member variable name with trailing '_'. - - // C++ type fq-name. - // - string - fq_type (bool unwrap = true) const - { - semantics::names* hint; - - if (wrapper != 0 && unwrap) - { - // Use the hint from the wrapper unless the wrapped type - // is qualified. - // - hint = wrapper->get ("wrapper-hint"); - utype (*context::wrapper (*wrapper), hint); - return t.fq_name (hint); - } - - // Use the original type from 'm' instead of 't' since the hint - // may be invalid for a different type. Plus, if a type is - // overriden, then the fq_type must be as well. - // - if (fq_type_.empty ()) - { - semantics::type& t (utype (m, hint)); - return t.fq_name (hint); - } - else - return fq_type_; - } - - string const& fq_type_; - - member_info (semantics::data_member& m_, - semantics::type& t_, - semantics::type* wrapper_, - bool cq_, - string& var_, - string const& fq_type) - : m (m_), - t (t_), - wrapper (wrapper_), - cq (cq_), - st (0), - var (var_), - fq_type_ (fq_type) - { - } - }; - - bool - container (member_info& mi) - { - // This cannot be a container if we have a type override. - // - return type_override_ == 0 && context::container (mi.m); - } - - // The false return value indicates that no further callbacks - // should be called for this member. - // - virtual bool - pre (member_info&) - { - return true; - } - - virtual void - post (member_info&) - { - } - - virtual void - traverse_composite (member_info&) - { - } - - virtual void - traverse_container (member_info&) - { - } - - virtual void - traverse_object_pointer (member_info& mi) - { - traverse_simple (mi); - } + virtual sql_type const& + member_sql_type (semantics::data_member&); virtual void traverse_simple (member_info&); @@ -288,13 +188,17 @@ namespace relational string type_; }; - struct member_database_type_id: member_base + struct member_database_type_id: relational::member_database_type_id, + member_base { + member_database_type_id (base const&); + member_database_type_id (semantics::type* type = 0, string const& fq_type = string (), string const& key_prefix = string ()); - string - database_type_id (type&); + + virtual string + database_type_id (semantics::data_member&); virtual void traverse_composite (member_info&); @@ -361,13 +265,17 @@ namespace relational { has_long_data (bool& r): r_ (r) {} + virtual void + traverse_pointer (semantics::data_member& m, semantics::class_& c) + { + if (!inverse (m, key_prefix_)) + object_columns_base::traverse_pointer (m, c); + } + virtual bool traverse_column (semantics::data_member& m, string const&, bool) { - if (inverse (m)) - return false; - - sql_type const& st (column_sql_type (m)); + sql_type const& st (parse_sql_type (column_type (), m)); switch (st.type) { diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx index e882ba3..312cc03 100644 --- a/odb/relational/mssql/context.cxx +++ b/odb/relational/mssql/context.cxx @@ -557,17 +557,20 @@ namespace relational } sql_type const& context:: - column_sql_type (semantics::data_member& m, string const& kp) + parse_sql_type (string const& t, semantics::data_member& m) { - string key (kp.empty () - ? string ("mssql-column-sql-type") - : "mssql-" + kp + "-column-sql-type"); + // If this proves to be too expensive, we can maintain a + // cache of parsed types. + // + data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - if (!m.count (key)) + if (i != data_->sql_type_cache_.end ()) + return i->second; + else { try { - m.set (key, parse_sql_type (column_type (m, kp))); + return (data_->sql_type_cache_[t] = parse_sql_type (t)); } catch (invalid_sql_type const& e) { @@ -577,8 +580,6 @@ namespace relational throw operation_failed (); } } - - return m.get (key); } sql_type context:: diff --git a/odb/relational/mssql/context.hxx b/odb/relational/mssql/context.hxx index 7530a9f..fe30746 100644 --- a/odb/relational/mssql/context.hxx +++ b/odb/relational/mssql/context.hxx @@ -5,6 +5,8 @@ #ifndef ODB_RELATIONAL_MSSQL_CONTEXT_HXX #define ODB_RELATIONAL_MSSQL_CONTEXT_HXX +#include + #include namespace relational @@ -83,8 +85,7 @@ namespace relational { public: sql_type const& - column_sql_type (semantics::data_member&, - string const& key_prefix = string ()); + parse_sql_type (string const&, semantics::data_member&); public: struct invalid_sql_type @@ -132,6 +133,9 @@ namespace relational struct data: base_context::data { data (std::ostream& os): base_context::data (os) {} + + typedef std::map sql_type_cache; + sql_type_cache sql_type_cache_; }; data* data_; }; diff --git a/odb/relational/mssql/model.cxx b/odb/relational/mssql/model.cxx index aec027c..c3f4948 100644 --- a/odb/relational/mssql/model.cxx +++ b/odb/relational/mssql/model.cxx @@ -28,7 +28,7 @@ namespace relational { // Make sure the column is mapped to an integer or DECIMAL type. // - switch (column_sql_type (m).type) + switch (parse_sql_type (column_type (), m).type) { case sql_type::BIT: case sql_type::TINYINT: diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx index 1c11984..1b800aa 100644 --- a/odb/relational/mssql/source.cxx +++ b/odb/relational/mssql/source.cxx @@ -41,17 +41,16 @@ namespace relational virtual void column (semantics::data_member& m, - string const& key_prefix, string const& table, string const& column) { // Don't add a column for auto id in the INSERT statement. // if (!(sk_ == statement_insert && - key_prefix.empty () && - id (m) && auto_(m))) + key_prefix_.empty () && + context::id (m) && auto_(m))) // Only simple id can be auto. { - base::column (m, key_prefix, table, column); + base::column (m, table, column); } } }; @@ -413,181 +412,21 @@ namespace relational // init image // - struct init_image_member: relational::init_image_member, member_base + struct init_image_member: relational::init_image_member_impl, + member_base { init_image_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in this binding). - // - if (container (mi) || inverse (mi.m, key_prefix_)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - // If we are generating standard init() and this member - // contains version, ignore it. - // - if (version (mi.m)) - return false; - - // For SQL Server we don't send auto id in INSERT statement - // (nor in UPDATE, as for other databases). So ignore it - // altogether. - // - if (id (mi.m) && auto_ (mi.m)) - return false; - - string const& name (mi.m.name ()); - member = "o." + name; - - os << "// " << name << endl - << "//" << endl; - - // If the whole class is readonly, then we will never be - // called with sk == statement_update. - // - if (!readonly (*context::top_object)) - { - semantics::class_* c; - - if (id (mi.m) || - readonly (mi.m) || - ((c = composite (mi.t)) && readonly (*c))) - os << "if (sk == statement_insert)"; - } - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "get_ref (" + member + ")"; - } - - if (composite (mi.t)) - { - os << "{"; - traits = "composite_value_traits< " + mi.fq_type () + " >"; - } - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;"; - - if (weak_pointer (mt)) - { - os << "typedef pointer_traits< " << mi.fq_type () << - " > wptr_traits;" - << "typedef pointer_traits< wptr_traits::" << - "strong_pointer_type > ptr_traits;" - << endl - << "wptr_traits::strong_pointer_type sp (" << - "wptr_traits::lock (" << member << "));"; - - member = "sp"; - } - else - os << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl; - - os << "bool is_null (ptr_traits::null_ptr (" << member << "));" - << "if (!is_null)" - << "{" - << "const " << type << "& id (" << endl; - - if (lazy_pointer (mt)) - os << "ptr_traits::object_id< ptr_traits::element_type > (" << - member << ")"; - else - os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; - - os << ");" - << endl; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - - os << "{" - << "bool is_null;"; - } - - traits = "mssql::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; } virtual void - post (member_info& mi) + set_null (member_info& mi) { - if (composite (mi.t)) - os << "}"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - if (object_pointer (member_utype (mi.m, key_prefix_))) - { - os << "}" - << "else" << endl; - - if (!null (mi.m, key_prefix_)) - os << "throw null_pointer ();"; - else - os << "i." << mi.var << "size_ind = SQL_NULL_DATA;"; - } - - os << "}"; - } - } - - virtual void - traverse_composite (member_info& mi) - { - os << traits << "::init (" << endl - << "i." << mi.var << "value," << endl - << member << "," << endl - << "sk);"; + os << "i." << mi.var << "size_ind = SQL_NULL_DATA;"; } virtual void @@ -800,14 +639,6 @@ namespace relational << "i." << mi.var << "value, is_null, " << member << ");" << "i." << mi.var << "size_ind = is_null ? SQL_NULL_DATA : 8;"; } - - private: - string type; - string db_type_id; - string member; - string traits; - - member_database_type_id member_database_type_id_; }; entry init_image_member_; @@ -815,147 +646,21 @@ namespace relational // init value // - struct init_value_member: relational::init_value_member, member_base + struct init_value_member: relational::init_value_member_impl, + member_base { init_value_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - string const& name (mi.m.name ()); - member = "o." + name; - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - - os << "// " << name << endl - << "//" << endl; - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "set_ref (\n" + member + ")"; - } - - if (composite (mi.t)) - traits = "composite_value_traits< " + mi.fq_type () + " >"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;" - << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl - << "if (i." << mi.var << "size_ind == SQL_NULL_DATA)" << endl; - - if (null (mi.m, key_prefix_)) - os << member << " = ptr_traits::pointer_type ();"; - else - os << "throw null_pointer ();"; - - os << "else" - << "{" - << type << " id;"; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - } - - traits = "mssql::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - if (composite (mi.t)) - return; - - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (object_pointer (mt)) - { - if (!member_override_.empty ()) - member = member_override_; - else - { - member = "o." + mi.m.name (); - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - } - - if (lazy_pointer (mt)) - os << member << " = ptr_traits::pointer_type (db, id);"; - else - os << "// If a compiler error points to the line below, then" << endl - << "// it most likely means that a pointer used in a member" << endl - << "// cannot be initialized from an object pointer." << endl - << "//" << endl - << member << " = ptr_traits::pointer_type (" << endl - << "db.load< obj_traits::object_type > (id));"; - - os << "}" - << "}"; - } } virtual void - traverse_composite (member_info& mi) + get_null (member_info& mi) { - os << traits << "::init (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "db);" - << endl; + os << "i." << mi.var << "size_ind == SQL_NULL_DATA"; } virtual void @@ -1141,14 +846,6 @@ namespace relational << "i." << mi.var << "size_ind == SQL_NULL_DATA);" << endl; } - - private: - string type; - string db_type_id; - string traits; - string member; - - member_database_type_id member_database_type_id_; }; entry init_value_member_; @@ -1172,7 +869,7 @@ namespace relational size_t n (cols.size ()); for (statement_columns::iterator i (cols.begin ()); n != 0; --n) { - sql_type const& st (column_sql_type (*i->member, i->key_prefix)); + sql_type const& st (parse_sql_type (i->type, *i->member)); bool l (false); diff --git a/odb/relational/mysql/common.cxx b/odb/relational/mysql/common.cxx index c8bad12..b8fa4c3 100644 --- a/odb/relational/mysql/common.cxx +++ b/odb/relational/mysql/common.cxx @@ -16,91 +16,10 @@ namespace relational // member_base // - void member_base:: - traverse (semantics::data_member& m) + sql_type const& member_base:: + member_sql_type (semantics::data_member& m) { - if (transient (m)) - return; - - string var; - - if (!var_override_.empty ()) - var = var_override_; - else - { - string const& name (m.name ()); - var = name + (name[name.size () - 1] == '_' ? "" : "_"); - } - - bool cq (type_override_ != 0 ? false : const_type (m.type ())); - semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m)); - - semantics::type* cont; - if (semantics::class_* c = composite_wrapper (t)) - { - // If t is a wrapper, pass the wrapped type. Also pass the - // original, wrapper type. - // - member_info mi (m, - *c, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_composite (mi); - post (mi); - } - } - // This cannot be a container if we have a type override. - // - else if (type_override_ == 0 && (cont = context::container (m))) - { - // The same unwrapping logic as for composite values. - // - member_info mi (m, - *cont, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_container (mi); - post (mi); - } - } - else - { - sql_type const& st (column_sql_type (m, key_prefix_)); - - if (semantics::class_* c = object_pointer (t)) - { - member_info mi (m, - utype (*id_member (*c)), - 0, - cq, - var, - fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_object_pointer (mi); - post (mi); - } - } - else - { - member_info mi (m, t, 0, cq, var, fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_simple (mi); - post (mi); - } - } - } + return parse_sql_type (column_type (m, key_prefix_), m); } void member_base:: @@ -363,10 +282,18 @@ namespace relational }; member_database_type_id:: + member_database_type_id (base const& x) + : member_base::base (x), // virtual base + base (x) + { + } + + member_database_type_id:: member_database_type_id (semantics::type* type, - string const& fq_type, - string const& key_prefix) - : relational::member_base (type, fq_type, key_prefix) + string const& fq_type, + string const& key_prefix) + : member_base::base (type, fq_type, key_prefix), // virtual base + base (type, fq_type, key_prefix) { } @@ -437,6 +364,8 @@ namespace relational type_id_ = "mysql::id_set"; } + entry member_database_type_id_; + // // query_columns // diff --git a/odb/relational/mysql/common.hxx b/odb/relational/mysql/common.hxx index c49bd09..93f5fbd 100644 --- a/odb/relational/mysql/common.hxx +++ b/odb/relational/mysql/common.hxx @@ -12,118 +12,18 @@ namespace relational { namespace mysql { - struct member_base: virtual relational::member_base, context + struct member_base: virtual relational::member_base_impl, context { - member_base (base const& x): base (x) {} + member_base (base const& x): base (x), base_impl (x) {} // This c-tor is for the direct use inside the mysql namespace. // If you do use this c-tor, you should also explicitly call - // relational::member_base. + // relational::member_base (aka base). // member_base () {} - virtual void - traverse (semantics::data_member& m); - - struct member_info - { - semantics::data_member& m; // Member. - semantics::type& t; // Cvr-unqualified member C++ type, note - // that m.type () may not be the same as t. - semantics::type* wrapper; // Wrapper type if member is a composite or - // container wrapper, also cvr-unqualified. - // In this case t is the wrapped type. - bool cq; // True if the original (wrapper) type - // is const-qualified. - sql_type const* st; // Member SQL type (only simple values). - string& var; // Member variable name with trailing '_'. - - // C++ type fq-name. - // - string - fq_type (bool unwrap = true) const - { - semantics::names* hint; - - if (wrapper != 0 && unwrap) - { - // Use the hint from the wrapper unless the wrapped type - // is qualified. - // - hint = wrapper->get ("wrapper-hint"); - utype (*context::wrapper (*wrapper), hint); - return t.fq_name (hint); - } - - // Use the original type from 'm' instead of 't' since the hint - // may be invalid for a different type. Plus, if a type is - // overriden, then the fq_type must be as well. - // - if (fq_type_.empty ()) - { - semantics::type& t (utype (m, hint)); - return t.fq_name (hint); - } - else - return fq_type_; - } - - string const& fq_type_; - - member_info (semantics::data_member& m_, - semantics::type& t_, - semantics::type* wrapper_, - bool cq_, - string& var_, - string const& fq_type) - : m (m_), - t (t_), - wrapper (wrapper_), - cq (cq_), - st (0), - var (var_), - fq_type_ (fq_type) - { - } - }; - - bool - container (member_info& mi) - { - // This cannot be a container if we have a type override. - // - return type_override_ == 0 && context::container (mi.m); - } - - // The false return value indicates that no further callbacks - // should be called for this member. - // - virtual bool - pre (member_info&) - { - return true; - } - - virtual void - post (member_info&) - { - } - - virtual void - traverse_composite (member_info&) - { - } - - virtual void - traverse_container (member_info&) - { - } - - virtual void - traverse_object_pointer (member_info& mi) - { - traverse_simple (mi); - } + virtual sql_type const& + member_sql_type (semantics::data_member&); virtual void traverse_simple (member_info&); @@ -220,12 +120,16 @@ namespace relational string type_; }; - struct member_database_type_id: member_base + struct member_database_type_id: relational::member_database_type_id, + member_base { + member_database_type_id (base const&); + member_database_type_id (semantics::type* type = 0, string const& fq_type = string (), string const& key_prefix = string ()); - string + + virtual string database_type_id (type&); virtual void diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx index b8327eb..ad7236c 100644 --- a/odb/relational/mysql/context.cxx +++ b/odb/relational/mysql/context.cxx @@ -316,17 +316,20 @@ namespace relational // sql_type const& context:: - column_sql_type (semantics::data_member& m, string const& kp) + parse_sql_type (string const& t, semantics::data_member& m) { - string key (kp.empty () - ? string ("mysql-column-sql-type") - : "mysql-" + kp + "-column-sql-type"); + // If this proves to be too expensive, we can maintain a + // cache of parsed types. + // + data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - if (!m.count (key)) + if (i != data_->sql_type_cache_.end ()) + return i->second; + else { try { - m.set (key, parse_sql_type (column_type (m, kp))); + return (data_->sql_type_cache_[t] = parse_sql_type (t)); } catch (invalid_sql_type const& e) { @@ -336,8 +339,6 @@ namespace relational throw operation_failed (); } } - - return m.get (key); } sql_type context:: diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx index 49b825e..294b5d1 100644 --- a/odb/relational/mysql/context.hxx +++ b/odb/relational/mysql/context.hxx @@ -5,6 +5,7 @@ #ifndef ODB_RELATIONAL_MYSQL_CONTEXT_HXX #define ODB_RELATIONAL_MYSQL_CONTEXT_HXX +#include #include #include @@ -80,8 +81,7 @@ namespace relational { public: sql_type const& - column_sql_type (semantics::data_member&, - string const& key_prefix = string ()); + parse_sql_type (string const&, semantics::data_member&); public: struct invalid_sql_type @@ -138,6 +138,9 @@ namespace relational struct data: base_context::data { data (std::ostream& os): base_context::data (os) {} + + typedef std::map sql_type_cache; + sql_type_cache sql_type_cache_; }; data* data_; }; diff --git a/odb/relational/mysql/model.cxx b/odb/relational/mysql/model.cxx index 8e07f38..11ca157 100644 --- a/odb/relational/mysql/model.cxx +++ b/odb/relational/mysql/model.cxx @@ -35,7 +35,7 @@ namespace relational { // Make sure the column is mapped to an ENUM or integer type. // - sql_type const& t (column_sql_type (m)); + sql_type const& t (parse_sql_type (column_type (), m)); switch (t.type) { diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx index 91b3061..3a784af 100644 --- a/odb/relational/mysql/source.cxx +++ b/odb/relational/mysql/source.cxx @@ -68,7 +68,6 @@ namespace relational virtual void column (semantics::data_member& m, - string const& key_prefix, string const& table, string const& column) { @@ -110,10 +109,12 @@ namespace relational // to value_traits. // + string type (column_type ()); + if (sk_ != statement_select || - column_sql_type (m, key_prefix).type != sql_type::ENUM) + parse_sql_type (type, m).type != sql_type::ENUM) { - base::column (m, key_prefix, table, column); + base::column (m, table, column); return; } @@ -140,7 +141,8 @@ namespace relational r += ")"; - sc_.push_back (relational::statement_column (r, m, key_prefix)); + sc_.push_back ( + relational::statement_column (r, type, m, key_prefix_)); } }; entry object_columns_; @@ -154,7 +156,9 @@ namespace relational { // The same idea as in object_columns. // - if (column_sql_type (m).type != sql_type::ENUM) + string type (column_type ()); + + if (parse_sql_type (type, m).type != sql_type::ENUM) { base::column (m, column); return; @@ -168,7 +172,7 @@ namespace relational r += column; r += ")"; - sc_.push_back (relational::statement_column (r, m)); + sc_.push_back (relational::statement_column (r, type, m)); } }; entry view_columns_; @@ -568,188 +572,37 @@ namespace relational // init image // - struct init_image_member: relational::init_image_member, member_base + struct init_image_member: relational::init_image_member_impl, + member_base { init_image_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { } - virtual bool - pre (member_info& mi) - { - // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in this binding). - // - if (container (mi) || inverse (mi.m, key_prefix_)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - // If we are generating standard init() and this member - // contains version, ignore it. - // - if (version (mi.m)) - return false; - - string const& name (mi.m.name ()); - member = "o." + name; - - os << "// " << name << endl - << "//" << endl; - - // If the whole class is readonly, then we will never be - // called with sk == statement_update. - // - if (!readonly (*context::top_object)) - { - semantics::class_* c; - - if (id (mi.m) || - readonly (mi.m) || - ((c = composite (mi.t)) && readonly (*c))) - os << "if (sk == statement_insert)"; - } - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "get_ref (" + member + ")"; - } - - if (composite (mi.t)) - { - os << "{"; - traits = "composite_value_traits< " + mi.fq_type () + " >"; - } - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;"; - - if (weak_pointer (mt)) - { - os << "typedef pointer_traits< " << mi.fq_type () << - " > wptr_traits;" - << "typedef pointer_traits< wptr_traits::" << - "strong_pointer_type > ptr_traits;" - << endl - << "wptr_traits::strong_pointer_type sp (" << - "wptr_traits::lock (" << member << "));"; - - member = "sp"; - } - else - os << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl; - - os << "bool is_null (ptr_traits::null_ptr (" << member << "));" - << "if (!is_null)" - << "{" - << "const " << type << "& id (" << endl; - - if (lazy_pointer (mt)) - os << "ptr_traits::object_id< ptr_traits::element_type > (" << - member << ")"; - else - os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; - - os << ");" - << endl; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - - os << "{" - << "bool is_null;"; - } - - traits = "mysql::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - virtual void - post (member_info& mi) + set_null (member_info& mi) { - if (composite (mi.t)) - os << "}"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - if (object_pointer (member_utype (mi.m, key_prefix_))) - { - os << "}"; - - if (!null (mi.m, key_prefix_)) - os << "else" << endl - << "throw null_pointer ();"; - } - - os << "i." << mi.var << "null = is_null;" - << "}"; - } - } - - virtual void - traverse_composite (member_info& mi) - { - os << "if (" << traits << "::init (" << endl - << "i." << mi.var << "value," << endl - << member << "," << endl - << "sk))" << endl - << "grew = true;"; + os << "i." << mi.var << "null = 1;"; } virtual void traverse_integer (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;"; } virtual void traverse_float (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;"; } virtual void @@ -764,6 +617,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = static_cast (size);" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } @@ -772,7 +626,8 @@ namespace relational traverse_date_time (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;"; } virtual void @@ -787,6 +642,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = static_cast (size);" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } @@ -801,6 +657,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = static_cast (size);" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } @@ -817,6 +674,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = static_cast (size);"; } @@ -830,7 +688,9 @@ namespace relational << "i." << mi.var << "size," << endl << "is_null," << endl << member << "))" << endl - << "grew = true;"; + << "grew = true;" + << endl + << "i." << mi.var << "null = is_null;"; } virtual void @@ -845,17 +705,10 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = static_cast (size);" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } - - private: - string type; - string db_type_id; - string member; - string traits; - - member_database_type_id member_database_type_id_; }; entry init_image_member_; @@ -863,147 +716,21 @@ namespace relational // init value // - struct init_value_member: relational::init_value_member, member_base + struct init_value_member: relational::init_value_member_impl, + member_base { init_value_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - string const& name (mi.m.name ()); - member = "o." + name; - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - - os << "// " << name << endl - << "//" << endl; - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "set_ref (\n" + member + ")"; - } - - if (composite (mi.t)) - traits = "composite_value_traits< " + mi.fq_type () + " >"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;" - << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl - << "if (i." << mi.var << "null)" << endl; - - if (null (mi.m, key_prefix_)) - os << member << " = ptr_traits::pointer_type ();"; - else - os << "throw null_pointer ();"; - - os << "else" - << "{" - << type << " id;"; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - } - - traits = "mysql::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - if (composite (mi.t)) - return; - - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (object_pointer (mt)) - { - if (!member_override_.empty ()) - member = member_override_; - else - { - member = "o." + mi.m.name (); - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - } - - if (lazy_pointer (mt)) - os << member << " = ptr_traits::pointer_type (db, id);"; - else - os << "// If a compiler error points to the line below, then" << endl - << "// it most likely means that a pointer used in a member" << endl - << "// cannot be initialized from an object pointer." << endl - << "//" << endl - << member << " = ptr_traits::pointer_type (" << endl - << "db.load< obj_traits::object_type > (id));"; - - os << "}" - << "}"; - } } virtual void - traverse_composite (member_info& mi) + get_null (member_info& mi) { - os << traits << "::init (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "db);" - << endl; + os << "i." << mi.var << "null"; } virtual void @@ -1107,14 +834,6 @@ namespace relational << "i." << mi.var << "null);" << endl; } - - private: - string type; - string db_type_id; - string traits; - string member; - - member_database_type_id member_database_type_id_; }; entry init_value_member_; diff --git a/odb/relational/oracle/common.cxx b/odb/relational/oracle/common.cxx index 88183cf..661bb4e 100644 --- a/odb/relational/oracle/common.cxx +++ b/odb/relational/oracle/common.cxx @@ -16,91 +16,10 @@ namespace relational // member_base // - void member_base:: - traverse (semantics::data_member& m) + sql_type const& member_base:: + member_sql_type (semantics::data_member& m) { - if (transient (m)) - return; - - string var; - - if (!var_override_.empty ()) - var = var_override_; - else - { - string const& name (m.name ()); - var = name + (name[name.size () - 1] == '_' ? "" : "_"); - } - - bool cq (type_override_ != 0 ? false : const_type (m.type ())); - semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m)); - - semantics::type* cont; - if (semantics::class_* c = composite_wrapper (t)) - { - // If t is a wrapper, pass the wrapped type. Also pass the - // original, wrapper type. - // - member_info mi (m, - *c, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_composite (mi); - post (mi); - } - } - // This cannot be a container if we have a type override. - // - else if (type_override_ == 0 && (cont = context::container (m))) - { - // The same unwrapping logic as for composite values. - // - member_info mi (m, - *cont, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_container (mi); - post (mi); - } - } - else - { - sql_type const& st (column_sql_type (m, key_prefix_)); - - if (semantics::class_* c = object_pointer (t)) - { - member_info mi (m, - utype (*id_member (*c)), - 0, - cq, - var, - fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_object_pointer (mi); - post (mi); - } - } - else - { - member_info mi (m, t, 0, cq, var, fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_simple (mi); - post (mi); - } - } - } + return parse_sql_type (column_type (m, key_prefix_), m); } void member_base:: @@ -374,10 +293,18 @@ namespace relational } member_database_type_id:: + member_database_type_id (base const& x) + : member_base::base (x), // virtual base + base (x) + { + } + + member_database_type_id:: member_database_type_id (semantics::type* type, string const& fq_type, string const& key_prefix) - : relational::member_base (type, fq_type, key_prefix) + : member_base::base (type, fq_type, key_prefix), // virtual base + base (type, fq_type, key_prefix) { } @@ -469,6 +396,8 @@ namespace relational lob_database_id[mi.st->type - sql_type::BLOB]; } + entry member_database_type_id_; + // // query_columns // @@ -494,7 +423,7 @@ namespace relational { // For some types we need to pass precision and scale. // - sql_type const& st (column_sql_type (m)); + sql_type const& st (parse_sql_type (column_type (), m)); switch (st.type) { diff --git a/odb/relational/oracle/common.hxx b/odb/relational/oracle/common.hxx index 0f4517d..15120fd 100644 --- a/odb/relational/oracle/common.hxx +++ b/odb/relational/oracle/common.hxx @@ -12,118 +12,18 @@ namespace relational { namespace oracle { - struct member_base: virtual relational::member_base, context + struct member_base: virtual relational::member_base_impl, context { - member_base (base const& x): base (x) {} + member_base (base const& x): base (x), base_impl (x) {} // This c-tor is for the direct use inside the oracle namespace. // If you do use this c-tor, you should also explicitly call - // relational::member_base. + // relational::member_base (aka base). // member_base () {} - virtual void - traverse (semantics::data_member& m); - - struct member_info - { - semantics::data_member& m; // Member. - semantics::type& t; // Cvr-unqualified member C++ type, note - // that m.type () may not be the same as t. - semantics::type* wrapper; // Wrapper type if member is a composite or - // container wrapper, also cvr-unqualified. - // In this case t is the wrapped type. - bool cq; // True if the original (wrapper) type - // is const-qualified. - sql_type const* st; // Member SQL type (only simple values). - string& var; // Member variable name with trailing '_'. - - // C++ type fq-name. - // - string - fq_type (bool unwrap = true) const - { - semantics::names* hint; - - if (wrapper != 0 && unwrap) - { - // Use the hint from the wrapper unless the wrapped type - // is qualified. - // - hint = wrapper->get ("wrapper-hint"); - utype (*context::wrapper (*wrapper), hint); - return t.fq_name (hint); - } - - // Use the original type from 'm' instead of 't' since the hint - // may be invalid for a different type. Plus, if a type is - // overriden, then the fq_type must be as well. - // - if (fq_type_.empty ()) - { - semantics::type& t (utype (m, hint)); - return t.fq_name (hint); - } - else - return fq_type_; - } - - string const& fq_type_; - - member_info (semantics::data_member& m_, - semantics::type& t_, - semantics::type* wrapper_, - bool cq_, - string& var_, - string const& fq_type) - : m (m_), - t (t_), - wrapper (wrapper_), - cq (cq_), - st (0), - var (var_), - fq_type_ (fq_type) - { - } - }; - - bool - container (member_info& mi) - { - // This cannot be a container if we have a type override. - // - return type_override_ == 0 && context::container (mi.m); - } - - // The false return value indicates that no further callbacks - // should be called for this member. - // - virtual bool - pre (member_info&) - { - return true; - } - - virtual void - post (member_info&) - { - } - - virtual void - traverse_composite (member_info&) - { - } - - virtual void - traverse_container (member_info&) - { - } - - virtual void - traverse_object_pointer (member_info& mi) - { - traverse_simple (mi); - } + virtual sql_type const& + member_sql_type (semantics::data_member&); virtual void traverse_simple (member_info&); @@ -240,12 +140,16 @@ namespace relational string type_; }; - struct member_database_type_id: member_base + struct member_database_type_id: relational::member_database_type_id, + member_base { + member_database_type_id (base const&); + member_database_type_id (semantics::type* type = 0, string const& fq_type = string (), string const& key_prefix = string ()); - string + + virtual string database_type_id (type&); virtual void diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx index 3d87729..dbe61af 100644 --- a/odb/relational/oracle/context.cxx +++ b/odb/relational/oracle/context.cxx @@ -159,17 +159,20 @@ namespace relational // sql_type const& context:: - column_sql_type (semantics::data_member& m, string const& kp) + parse_sql_type (string const& t, semantics::data_member& m) { - string key (kp.empty () - ? string ("oracle-column-sql-type") - : "oracle-" + kp + "-column-sql-type"); + // If this proves to be too expensive, we can maintain a + // cache of parsed types. + // + data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - if (!m.count (key)) + if (i != data_->sql_type_cache_.end ()) + return i->second; + else { try { - m.set (key, parse_sql_type (column_type (m, kp))); + return (data_->sql_type_cache_[t] = parse_sql_type (t)); } catch (invalid_sql_type const& e) { @@ -179,8 +182,6 @@ namespace relational throw operation_failed (); } } - - return m.get (key); } sql_type context:: diff --git a/odb/relational/oracle/context.hxx b/odb/relational/oracle/context.hxx index 273f0e5..37716f0 100644 --- a/odb/relational/oracle/context.hxx +++ b/odb/relational/oracle/context.hxx @@ -5,6 +5,8 @@ #ifndef ODB_RELATIONAL_ORACLE_CONTEXT_HXX #define ODB_RELATIONAL_ORACLE_CONTEXT_HXX +#include + #include namespace relational @@ -73,8 +75,7 @@ namespace relational { public: sql_type const& - column_sql_type (semantics::data_member&, - string const& key_prefix = string ()); + parse_sql_type (string const&, semantics::data_member&); public: struct invalid_sql_type @@ -126,6 +127,9 @@ namespace relational struct data: base_context::data { data (std::ostream& os): base_context::data (os) {} + + typedef std::map sql_type_cache; + sql_type_cache sql_type_cache_; }; data* data_; }; diff --git a/odb/relational/oracle/model.cxx b/odb/relational/oracle/model.cxx index 347ea37..4b874c8 100644 --- a/odb/relational/oracle/model.cxx +++ b/odb/relational/oracle/model.cxx @@ -28,9 +28,7 @@ namespace relational { // Make sure the column is mapped to Oracle NUMBER. // - sql_type t (column_sql_type (m)); - - if (t.type != sql_type::NUMBER) + if (parse_sql_type (column_type (), m).type != sql_type::NUMBER) { cerr << m.file () << ":" << m.line () << ":" << m.column () << ": error: column with default value specified as C++ " diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx index fb0984a..1d7d81f 100644 --- a/odb/relational/oracle/source.cxx +++ b/odb/relational/oracle/source.cxx @@ -316,187 +316,37 @@ namespace relational // init image // - struct init_image_member: relational::init_image_member, member_base + struct init_image_member: relational::init_image_member_impl, + member_base { init_image_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) - { - // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in this binding). - // - if (container (mi) || inverse (mi.m, key_prefix_)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - // If we are generating standard init() and this member - // contains version, ignore it. - // - if (version (mi.m)) - return false; - - string const& name (mi.m.name ()); - member = "o." + name; - - os << "// " << name << endl - << "//" << endl; - - // If the whole class is readonly, then we will never be - // called with sk == statement_update. - // - if (!readonly (*context::top_object)) - { - semantics::class_* c; - - if (id (mi.m) || - readonly (mi.m) || - ((c = composite (mi.t)) && readonly (*c))) - os << "if (sk == statement_insert)"; - } - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "get_ref (" + member + ")"; - } - - if (composite (mi.t)) - { - os << "{"; - traits = "composite_value_traits< " + mi.fq_type () + " >"; - } - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;"; - - if (weak_pointer (mt)) - { - os << "typedef pointer_traits< " << mi.fq_type () << - " > wptr_traits;" - << "typedef pointer_traits< wptr_traits::" << - "strong_pointer_type > ptr_traits;" - << endl - << "wptr_traits::strong_pointer_type sp (" << - "wptr_traits::lock (" << member << "));"; - - member = "sp"; - } - else - os << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl; - - os << "bool is_null (ptr_traits::null_ptr (" << member << "));" - << "if (!is_null)" - << "{" - << "const " << type << "& id (" << endl; - - if (lazy_pointer (mt)) - os << "ptr_traits::object_id< ptr_traits::element_type > (" << - member << ")"; - else - os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; - - os << ");" - << endl; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - - os << "{" - << "bool is_null;"; - } - - traits = "oracle::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - if (composite (mi.t)) - os << "}"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - if (object_pointer (member_utype (mi.m, key_prefix_))) - { - os << "}"; - - if (!null (mi.m, key_prefix_)) - os << "else" << endl - << "throw null_pointer ();"; - } - - os << "i." << mi.var << "indicator = is_null ? -1 : 0;" - << "}"; - } } virtual void - traverse_composite (member_info& mi) + set_null (member_info& mi) { - os << traits << "::init (" << endl - << "i." << mi.var << "value," << endl - << member << "," << endl - << "sk);"; + os << "i." << mi.var << "indicator = -1;"; } virtual void traverse_int32 (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } virtual void traverse_int64 (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } virtual void @@ -508,6 +358,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;" << "i." << mi.var << "size = static_cast (size);"; } @@ -515,14 +366,16 @@ namespace relational traverse_float (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } virtual void traverse_double (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } virtual void @@ -535,6 +388,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;" << "i." << mi.var << "size = static_cast (size);"; } @@ -542,28 +396,32 @@ namespace relational traverse_date (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } virtual void traverse_timestamp (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } virtual void traverse_interval_ym (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } virtual void traverse_interval_ds (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } virtual void @@ -576,6 +434,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;" << "i." << mi.var << "size = static_cast (size);"; } @@ -587,16 +446,9 @@ namespace relational << "i." << mi.var << "callback.callback.param," << endl << "i." << mi.var << "callback.context.param," << endl << "is_null," << endl - << member << ");"; + << member << ");" + << "i." << mi.var << "indicator = is_null ? -1 : 0;"; } - - private: - string type; - string db_type_id; - string member; - string traits; - - member_database_type_id member_database_type_id_; }; entry init_image_member_; @@ -604,147 +456,21 @@ namespace relational // init value // - struct init_value_member: relational::init_value_member, member_base + struct init_value_member: relational::init_value_member_impl, + member_base { init_value_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - string const& name (mi.m.name ()); - member = "o." + name; - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - - os << "// " << name << endl - << "//" << endl; - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "set_ref (\n" + member + ")"; - } - - if (composite (mi.t)) - traits = "composite_value_traits< " + mi.fq_type () + " >"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;" - << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl - << "if (i." << mi.var << "indicator == -1)" << endl; - - if (null (mi.m, key_prefix_)) - os << member << " = ptr_traits::pointer_type ();"; - else - os << "throw null_pointer ();"; - - os << "else" - << "{" - << type << " id;"; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - } - - traits = "oracle::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - if (composite (mi.t)) - return; - - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (object_pointer (mt)) - { - if (!member_override_.empty ()) - member = member_override_; - else - { - member = "o." + mi.m.name (); - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - } - - if (lazy_pointer (mt)) - os << member << " = ptr_traits::pointer_type (db, id);"; - else - os << "// If a compiler error points to the line below, then" << endl - << "// it most likely means that a pointer used in a member" << endl - << "// cannot be initialized from an object pointer." << endl - << "//" << endl - << member << " = ptr_traits::pointer_type (" << endl - << "db.load< obj_traits::object_type > (id));"; - - os << "}" - << "}"; - } } virtual void - traverse_composite (member_info& mi) + get_null (member_info& mi) { - os << traits << "::init (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "db);" - << endl; + os << "i." << mi.var << "indicator == -1"; } virtual void @@ -870,14 +596,6 @@ namespace relational << "i." << mi.var << "indicator == -1);" << endl; } - - private: - string type; - string db_type_id; - string traits; - string member; - - member_database_type_id member_database_type_id_; }; entry init_value_member_; diff --git a/odb/relational/pgsql/common.cxx b/odb/relational/pgsql/common.cxx index 0ec9f7c..3d7e01e 100644 --- a/odb/relational/pgsql/common.cxx +++ b/odb/relational/pgsql/common.cxx @@ -16,91 +16,10 @@ namespace relational // member_base // - void member_base:: - traverse (semantics::data_member& m) + sql_type const& member_base:: + member_sql_type (semantics::data_member& m) { - if (transient (m)) - return; - - string var; - - if (!var_override_.empty ()) - var = var_override_; - else - { - string const& name (m.name ()); - var = name + (name[name.size () - 1] == '_' ? "" : "_"); - } - - bool cq (type_override_ != 0 ? false : const_type (m.type ())); - semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m)); - - semantics::type* cont; - if (semantics::class_* c = composite_wrapper (t)) - { - // If t is a wrapper, pass the wrapped type. Also pass the - // original, wrapper type. - // - member_info mi (m, - *c, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_composite (mi); - post (mi); - } - } - // This cannot be a container if we have a type override. - // - else if (type_override_ == 0 && (cont = context::container (m))) - { - // The same unwrapping logic as for composite values. - // - member_info mi (m, - *cont, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_container (mi); - post (mi); - } - } - else - { - sql_type const& st (column_sql_type (m, key_prefix_)); - - if (semantics::class_* c = object_pointer (t)) - { - member_info mi (m, - utype (*id_member (*c)), - 0, - cq, - var, - fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_object_pointer (mi); - post (mi); - } - } - else - { - member_info mi (m, t, 0, cq, var, fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_simple (mi); - post (mi); - } - } - } + return parse_sql_type (column_type (m, key_prefix_), m); } void member_base:: @@ -310,13 +229,21 @@ namespace relational "id_string", // TEXT, "id_bytea" // BYTEA }; - } + } + + member_database_type_id:: + member_database_type_id (base const& x) + : member_base::base (x), // virtual base + base (x) + { + } member_database_type_id:: member_database_type_id (semantics::type* type, string const& fq_type, string const& key_prefix) - : relational::member_base (type, fq_type, key_prefix) + : member_base::base (type, fq_type, key_prefix), // virtual base + base (type, fq_type, key_prefix) { } @@ -386,6 +313,8 @@ namespace relational type_id_ = "pgsql::id_uuid"; } + entry member_database_type_id_; + // // query_columns // diff --git a/odb/relational/pgsql/common.hxx b/odb/relational/pgsql/common.hxx index 4f3ee4d..4b9bbd5 100644 --- a/odb/relational/pgsql/common.hxx +++ b/odb/relational/pgsql/common.hxx @@ -12,118 +12,18 @@ namespace relational { namespace pgsql { - struct member_base: virtual relational::member_base, context + struct member_base: virtual relational::member_base_impl, context { - member_base (base const& x): base (x) {} + member_base (base const& x): base (x), base_impl (x) {} // This c-tor is for the direct use inside the pgsql namespace. // If you do use this c-tor, you should also explicitly call - // relational::member_base. + // relational::member_base (aka base). // member_base () {} - virtual void - traverse (semantics::data_member& m); - - struct member_info - { - semantics::data_member& m; // Member. - semantics::type& t; // Cvr-unqualified member C++ type, note - // that m.type () may not be the same as t. - semantics::type* wrapper; // Wrapper type if member is a composite or - // container wrapper, also cvr-unqualified. - // In this case t is the wrapped type. - bool cq; // True if the original (wrapper) type - // is const-qualified. - sql_type const* st; // Member SQL type (only simple values). - string& var; // Member variable name with trailing '_'. - - // C++ type fq-name. - // - string - fq_type (bool unwrap = true) const - { - semantics::names* hint; - - if (wrapper != 0 && unwrap) - { - // Use the hint from the wrapper unless the wrapped type - // is qualified. - // - hint = wrapper->get ("wrapper-hint"); - utype (*context::wrapper (*wrapper), hint); - return t.fq_name (hint); - } - - // Use the original type from 'm' instead of 't' since the hint - // may be invalid for a different type. Plus, if a type is - // overriden, then the fq_type must be as well. - // - if (fq_type_.empty ()) - { - semantics::type& t (utype (m, hint)); - return t.fq_name (hint); - } - else - return fq_type_; - } - - string const& fq_type_; - - member_info (semantics::data_member& m_, - semantics::type& t_, - semantics::type* wrapper_, - bool cq_, - string& var_, - string const& fq_type) - : m (m_), - t (t_), - wrapper (wrapper_), - cq (cq_), - st (0), - var (var_), - fq_type_ (fq_type) - { - } - }; - - bool - container (member_info& mi) - { - // This cannot be a container if we have a type override. - // - return type_override_ == 0 && context::container (mi.m); - } - - // The false return value indicates that no further callbacks - // should be called for this member. - // - virtual bool - pre (member_info&) - { - return true; - } - - virtual void - post (member_info&) - { - } - - virtual void - traverse_composite (member_info&) - { - } - - virtual void - traverse_container (member_info&) - { - } - - virtual void - traverse_object_pointer (member_info& mi) - { - traverse_simple (mi); - } + virtual sql_type const& + member_sql_type (semantics::data_member&); virtual void traverse_simple (member_info&); @@ -208,12 +108,16 @@ namespace relational string type_; }; - struct member_database_type_id: member_base + struct member_database_type_id: relational::member_database_type_id, + member_base { + member_database_type_id (base const&); + member_database_type_id (semantics::type* type = 0, string const& fq_type = string (), string const& key_prefix = string ()); - string + + virtual string database_type_id (type&); virtual void diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx index 8cc4eca..17ceaaa 100644 --- a/odb/relational/pgsql/context.cxx +++ b/odb/relational/pgsql/context.cxx @@ -236,17 +236,20 @@ namespace relational // sql_type const& context:: - column_sql_type (semantics::data_member& m, string const& kp) + parse_sql_type (string const& t, semantics::data_member& m) { - string key (kp.empty () - ? string ("pgsql-column-sql-type") - : "pgsql-" + kp + "-column-sql-type"); + // If this proves to be too expensive, we can maintain a + // cache of parsed types. + // + data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - if (!m.count (key)) + if (i != data_->sql_type_cache_.end ()) + return i->second; + else { try { - m.set (key, parse_sql_type (column_type (m, kp))); + return (data_->sql_type_cache_[t] = parse_sql_type (t)); } catch (invalid_sql_type const& e) { @@ -256,8 +259,6 @@ namespace relational throw operation_failed (); } } - - return m.get (key); } sql_type context:: diff --git a/odb/relational/pgsql/context.hxx b/odb/relational/pgsql/context.hxx index a79cceb..1da353a 100644 --- a/odb/relational/pgsql/context.hxx +++ b/odb/relational/pgsql/context.hxx @@ -5,6 +5,8 @@ #ifndef ODB_RELATIONAL_PGSQL_CONTEXT_HXX #define ODB_RELATIONAL_PGSQL_CONTEXT_HXX +#include + #include namespace relational @@ -69,8 +71,7 @@ namespace relational { public: sql_type const& - column_sql_type (semantics::data_member&, - string const& key_prefix = string ()); + parse_sql_type (string const&, semantics::data_member&); public: struct invalid_sql_type @@ -124,6 +125,9 @@ namespace relational struct data: base_context::data { data (std::ostream& os): base_context::data (os) {} + + typedef std::map sql_type_cache; + sql_type_cache sql_type_cache_; }; data* data_; }; diff --git a/odb/relational/pgsql/model.cxx b/odb/relational/pgsql/model.cxx index ebd04af..06a7dde 100644 --- a/odb/relational/pgsql/model.cxx +++ b/odb/relational/pgsql/model.cxx @@ -34,7 +34,7 @@ namespace relational { // Make sure the column is mapped to an integer type. // - switch (column_sql_type (m).type) + switch (parse_sql_type (column_type (), m).type) { case sql_type::SMALLINT: case sql_type::INTEGER: diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index ceb7dbd..ae19e05 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -103,7 +103,21 @@ namespace relational struct statement_oids: object_columns_base, context { - statement_oids (statement_kind sk): sk_ (sk) {} + statement_oids (statement_kind sk, bool first = true) + : object_columns_base (first), sk_ (sk) + { + } + + virtual void + traverse_pointer (semantics::data_member& m, semantics::class_& c) + { + // Ignore certain columns depending on what kind statement we are + // generating. See object_columns in common source generator for + // details. + // + if (!(inverse (m, key_prefix_) && sk_ != statement_select)) + object_columns_base::traverse_pointer (m, c); + } virtual bool traverse_column (semantics::data_member& m, @@ -114,10 +128,7 @@ namespace relational // generating. See object_columns in common source generator for // details. // - if (inverse (m) && sk_ != statement_select) - return false; - - if ((id (m) || readonly (member_path_, member_scope_)) && + if ((id () || readonly (member_path_, member_scope_)) && sk_ == statement_update) return false; @@ -128,7 +139,7 @@ namespace relational if (!first) os << ',' << endl; - os << oids[column_sql_type (m).type]; + os << oids[parse_sql_type (column_type (), m).type]; return true; } @@ -471,188 +482,37 @@ namespace relational // init image // - struct init_image_member: relational::init_image_member, member_base + struct init_image_member: relational::init_image_member_impl, + member_base { init_image_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) - { - // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in this binding). - // - if (container (mi) || inverse (mi.m, key_prefix_)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - // If we are generating standard init() and this member - // contains version, ignore it. - // - if (version (mi.m)) - return false; - - string const& name (mi.m.name ()); - member = "o." + name; - - os << "// " << name << endl - << "//" << endl; - - // If the whole class is readonly, then we will never be - // called with sk == statement_update. - // - if (!readonly (*context::top_object)) - { - semantics::class_* c; - - if (id (mi.m) || - readonly (mi.m) || - ((c = composite (mi.t)) && readonly (*c))) - os << "if (sk == statement_insert)"; - } - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "get_ref (" + member + ")"; - } - - if (composite (mi.t)) - { - os << "{"; - traits = "composite_value_traits< " + mi.fq_type () + " >"; - } - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;"; - - if (weak_pointer (mt)) - { - os << "typedef pointer_traits< " << mi.fq_type () << - " > wptr_traits;" - << "typedef pointer_traits< wptr_traits::" << - "strong_pointer_type > ptr_traits;" - << endl - << "wptr_traits::strong_pointer_type sp (" << - "wptr_traits::lock (" << member << "));"; - - member = "sp"; - } - else - os << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl; - - os << "bool is_null (ptr_traits::null_ptr (" << member << "));" - << "if (!is_null)" - << "{" - << "const " << type << "& id (" << endl; - - if (lazy_pointer (mt)) - os << "ptr_traits::object_id< ptr_traits::element_type > (" << - member << ")"; - else - os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; - - os << ");" - << endl; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - - os << "{" - << "bool is_null;"; - } - - traits = "pgsql::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - if (composite (mi.t)) - os << "}"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - if (object_pointer (member_utype (mi.m, key_prefix_))) - { - os << "}"; - - if (!null (mi.m, key_prefix_)) - os << "else" << endl - << "throw null_pointer ();"; - } - - os << "i." << mi.var << "null = is_null;" - << "}"; - } } virtual void - traverse_composite (member_info& mi) + set_null (member_info& mi) { - os << "if (" << traits << "::init (" << endl - << "i." << mi.var << "value," << endl - << member << "," << endl - << "sk))" << endl - << "grew = true;"; + os << "i." << mi.var << "null = true;"; } virtual void traverse_integer (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;"; } virtual void traverse_float (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;"; } virtual void @@ -667,6 +527,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = size;" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } @@ -675,7 +536,8 @@ namespace relational traverse_date_time (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;"; } virtual void @@ -688,6 +550,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = size;" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } @@ -702,6 +565,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = size;"; } @@ -715,6 +579,7 @@ namespace relational << "size," << endl << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "i." << mi.var << "size = size;" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } @@ -723,16 +588,9 @@ namespace relational traverse_uuid (member_info& mi) { os << traits << "::set_image (" << endl - << "i." << mi.var << "value, is_null, " << member << ");"; + << "i." << mi.var << "value, is_null, " << member << ");" + << "i." << mi.var << "null = is_null;"; } - - private: - string type; - string db_type_id; - string member; - string traits; - - member_database_type_id member_database_type_id_; }; entry init_image_member_; @@ -740,147 +598,21 @@ namespace relational // init value // - struct init_value_member: relational::init_value_member, member_base + struct init_value_member: relational::init_value_member_impl, + member_base { init_value_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - string const& name (mi.m.name ()); - member = "o." + name; - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - - os << "// " << name << endl - << "//" << endl; - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "set_ref (\n" + member + ")"; - } - - if (composite (mi.t)) - traits = "composite_value_traits< " + mi.fq_type () + " >"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;" - << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl - << "if (i." << mi.var << "null)" << endl; - - if (null (mi.m, key_prefix_)) - os << member << " = ptr_traits::pointer_type ();"; - else - os << "throw null_pointer ();"; - - os << "else" - << "{" - << type << " id;"; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - } - - traits = "pgsql::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - if (composite (mi.t)) - return; - - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (object_pointer (mt)) - { - if (!member_override_.empty ()) - member = member_override_; - else - { - member = "o." + mi.m.name (); - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - } - - if (lazy_pointer (mt)) - os << member << " = ptr_traits::pointer_type (db, id);"; - else - os << "// If a compiler error points to the line below, then" << endl - << "// it most likely means that a pointer used in a member" << endl - << "// cannot be initialized from an object pointer." << endl - << "//" << endl - << member << " = ptr_traits::pointer_type (" << endl - << "db.load< obj_traits::object_type > (id));"; - - os << "}" - << "}"; - } } virtual void - traverse_composite (member_info& mi) + get_null (member_info& mi) { - os << traits << "::init (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "db);" - << endl; + os << "i." << mi.var << "null"; } virtual void @@ -970,14 +702,6 @@ namespace relational << "i." << mi.var << "null);" << endl; } - - private: - string type; - string db_type_id; - string traits; - string member; - - member_database_type_id member_database_type_id_; }; entry init_value_member_; @@ -1090,7 +814,7 @@ namespace relational << "{"; instance st (statement_select); - st->traverse_column (*id, "", true); + st->traverse (*id); os << "};"; } @@ -1111,16 +835,11 @@ namespace relational bool first (cc.total == cc.id + cc.inverse + cc.readonly + cc.optimistic_managed); - { - instance st (statement_where); - st->traverse_column (*id, "", first); - } + instance st (statement_where, first); + st->traverse (*id); if (optimistic != 0) - { - instance st (statement_where); - st->traverse_column (*optimistic, "", false); - } + st->traverse (*optimistic); os << "};"; } @@ -1134,7 +853,7 @@ namespace relational << "{"; instance st (statement_where); - st->traverse_column (*id, "", true); + st->traverse (*id); os << "};"; } @@ -1145,15 +864,9 @@ namespace relational << "optimistic_erase_statement_types[] =" << "{"; - { - instance st (statement_where); - st->traverse_column (*id, "", true); - } - - { - instance st (statement_where); - st->traverse_column (*optimistic, "", false); - } + instance st (statement_where); + st->traverse (*id); + st->traverse (*optimistic); os << "};"; } @@ -1258,8 +971,7 @@ namespace relational bool inv (inv_m != 0); semantics::type& vt (container_vt (t)); - - string id_oid (oids[column_sql_type (m, "id").type]); + semantics::type& idt (container_idt (m)); // select_all statement types. // @@ -1268,20 +980,22 @@ namespace relational << "select_all_types[] =" << "{"; + instance so (statement_where); + if (inv) { // many(i)-to-many // if (container (*inv_m)) - os << oids[column_sql_type (*inv_m, "value").type]; + so->traverse (*inv_m, idt, "value", "value"); // many(i)-to-one // else - os << oids[column_sql_type (*inv_m).type]; + so->traverse (*inv_m); } else - os << id_oid; + so->traverse (m, idt, "id", "object_id"); os << "};"; } @@ -1295,30 +1009,22 @@ namespace relational if (!inv) { - os << id_oid << ","; + instance so (statement_insert); + + so->traverse (m, idt, "id", "object_id"); switch (container_kind (t)) { case ck_ordered: { if (!unordered (m)) - os << oids[column_sql_type (m, "index").type] << ","; - + so->traverse (m, container_it (t), "index", "index"); break; } case ck_map: case ck_multimap: { - if (semantics::class_* ktc = - composite_wrapper (container_kt (t))) - { - instance st (statement_insert); - st->traverse (m, *ktc, "key", "key"); - os << ","; - } - else - os << oids[column_sql_type (m, "key").type] << ","; - + so->traverse (m, container_kt (t), "key", "key"); break; } case ck_set: @@ -1328,14 +1034,7 @@ namespace relational } } - if (semantics::class_* vtc = composite_wrapper (vt)) - { - instance st (statement_insert); - st->traverse (m, *vtc, "value", "value"); - } - else - os << oids[column_sql_type (m, "value").type]; - + so->traverse (m, vt, "value", "value"); } else // MSVC does not allow zero length arrays or uninitialized @@ -1354,7 +1053,10 @@ namespace relational << "{"; if (!inv) - os << id_oid; + { + instance so (statement_where); + so->traverse (m, idt, "id", "object_id"); + } else os << "0"; diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index 8c18f02..0bede14 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -142,7 +142,7 @@ namespace relational // const auto_ptr - can modify by changing the pointed-to value // if (const_type (m.type ()) && - !(m.count ("id") || m.count ("version") || m.count ("inverse"))) + !(id (m) || version (m) || m.count ("inverse"))) { if (qwt == 0 || const_type (*qwt)) m.set ("readonly", true); @@ -153,11 +153,19 @@ namespace relational if (composite_wrapper (t)) return; - string type, ref_type; + string type, id_type; + + if (m.count ("id-type")) + id_type = m.get ("id-type"); if (m.count ("type")) + { type = m.get ("type"); + if (id_type.empty ()) + id_type = type; + } + if (semantics::class_* c = process_object_pointer (m, t)) { // This is an object pointer. The column type is the pointed-to @@ -168,26 +176,55 @@ namespace relational semantics::names* idhint; semantics::type& idt (utype (id, idhint)); + semantics::type* wt (0); + semantics::names* whint (0); + if (process_wrapper (idt)) + { + whint = idt.get ("wrapper-hint"); + wt = &utype (*idt.get ("wrapper-type"), whint); + } + + // Nothing to do if this is a composite value type. + // + if (composite_wrapper (idt)) + return; + + if (type.empty () && id.count ("id-type")) + type = id.get ("id-type"); + if (type.empty () && id.count ("type")) type = id.get ("type"); + // The rest should be identical to the code for the id_type in + // the else block. + // if (type.empty () && idt.count ("id-type")) type = idt.get ("id-type"); + if (type.empty () && wt != 0 && wt->count ("id-type")) + type = wt->get ("id-type"); + if (type.empty () && idt.count ("type")) type = idt.get ("type"); + if (type.empty () && wt != 0 && wt->count ("type")) + type = wt->get ("type"); + if (type.empty ()) type = database_type (idt, idhint, true); + + if (type.empty () && wt != 0) + type = database_type (*wt, whint, true); + + id_type = type; } else { - if (type.empty () && m.count ("id") && t.count ("id-type")) - type = t.get ("id-type"); + if (id_type.empty () && t.count ("id-type")) + id_type = t.get ("id-type"); - if (type.empty () && wt != 0 && m.count ("id") && - wt->count ("id-type")) - type = wt->get ("id-type"); + if (id_type.empty () && wt != 0 && wt->count ("id-type")) + id_type = wt->get ("id-type"); if (type.empty () && t.count ("type")) type = t.get ("type"); @@ -195,16 +232,29 @@ namespace relational if (type.empty () && wt != 0 && wt->count ("type")) type = wt->get ("type"); + if (id_type.empty ()) + id_type = type; + + if (id_type.empty ()) + id_type = database_type (t, hint, true); + if (type.empty ()) - type = database_type (t, hint, m.count ("id")); + type = database_type (t, hint, false); + + if (id_type.empty () && wt != 0) + id_type = database_type (*wt, whint, true); if (type.empty () && wt != 0) - type = database_type (*wt, whint, m.count ("id")); + type = database_type (*wt, whint, false); + + if (id (m)) + type = id_type; } if (!type.empty ()) { m.set ("column-type", type); + m.set ("column-id-type", id_type); // Issue a warning if we are relaxing null-ness. // @@ -274,24 +324,53 @@ namespace relational if (obj_ptr && (c = process_object_pointer (m, t, prefix))) { // This is an object pointer. The column type is the pointed-to - // object id type. Except by default it can be NULL. + // object id type. // semantics::data_member& id (*id_member (*c)); - semantics::names* hint; - semantics::type& idt (utype (id, hint)); + semantics::names* idhint; + semantics::type& idt (utype (id, idhint)); + + semantics::type* wt (0); + semantics::names* whint (0); + if (process_wrapper (idt)) + { + whint = idt.get ("wrapper-hint"); + wt = &utype (*idt.get ("wrapper-type"), whint); + } + + // Nothing to do if this is a composite value type. + // + if (composite_wrapper (idt)) + return; + + if (type.empty () && id.count ("id-type")) + type = id.get ("id-type"); if (type.empty () && id.count ("type")) type = id.get ("type"); + // The rest of the code is identical to the else block except here + // we have to check for "id-type" before checking for "type". + // + if (type.empty () && idt.count ("id-type")) type = idt.get ("id-type"); + if (type.empty () && wt != 0 && wt->count ("id-type")) + type = wt->get ("id-type"); + if (type.empty () && idt.count ("type")) type = idt.get ("type"); + if (type.empty () && wt != 0 && wt->count ("type")) + type = wt->get ("type"); + if (type.empty ()) - type = database_type (idt, hint, true); + type = database_type (idt, idhint, true); + + if (type.empty () && wt != 0) + type = database_type (*wt, whint, true); } else { @@ -311,6 +390,7 @@ namespace relational if (!type.empty ()) { m.set (prefix + "-column-type", type); + m.set (prefix + "-column-id-type", type); return; } @@ -1094,7 +1174,7 @@ namespace relational TREE_VEC_ELT (args, 0) = arg; // This step should succeed regardles of whether there is a - // container traits specialization for this type. + // specialization for this type. // tree inst ( lookup_template_class (t, args, 0, 0, 0, tf_warning_or_error)); @@ -1939,30 +2019,27 @@ namespace relational } virtual void - traverse_simple (semantics::data_member& m) + traverse_pointer (semantics::data_member& m, semantics::class_& c) { - if (semantics::class_* c = object_pointer (utype (m))) - { - // Ignore inverse sides of the same relationship to avoid - // phony conflicts caused by the direct side that will end - // up in the relationship list as well. - // - if (inverse (m)) - return; + // Ignore inverse sides of the same relationship to avoid + // phony conflicts caused by the direct side that will end + // up in the relationship list as well. + // + if (inverse (m)) + return; - // Ignore self-pointers if requested. - // - if (!self_pointer_ && pointer_->obj == c) - return; + // Ignore self-pointers if requested. + // + if (!self_pointer_ && pointer_->obj == &c) + return; - if (pointee_.obj == c) - { - relationships_.push_back (relationship ()); - relationships_.back ().member = &m; - relationships_.back ().name = member_prefix_ + m.name (); - relationships_.back ().pointer = pointer_; - relationships_.back ().pointee = &pointee_; - } + if (pointee_.obj == &c) + { + relationships_.push_back (relationship ()); + relationships_.back ().member = &m; + relationships_.back ().name = member_prefix_ + m.name (); + relationships_.back ().pointer = pointer_; + relationships_.back ().pointee = &pointee_; } } diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 52ff093..7f94410 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -28,13 +28,15 @@ namespace relational { statement_column (): member (0) {} statement_column (std::string const& c, + std::string const& t, semantics::data_member& m, std::string const& kp = "") - : column (c), member (&m), key_prefix (kp) + : column (c), type (t), member (&m), key_prefix (kp) { } - std::string column; + std::string column; // Column name. + std::string type; // Column SQL type. semantics::data_member* member; std::string key_prefix; }; @@ -83,73 +85,108 @@ namespace relational { } - virtual bool - traverse_column (semantics::data_member& m, string const& name, bool) + virtual void + traverse_pointer (semantics::data_member& m, semantics::class_& c) { - semantics::data_member* im (inverse (m)); + semantics::data_member* im (inverse (m, key_prefix_)); // Ignore certain columns depending on what kind statement we are // generating. Columns corresponding to the inverse members are - // only present in the select statements while the id and readonly - // columns are not present in the update statements. + // only present in the select statements. // if (im != 0 && sk_ != statement_select) - return false; - - if ((id (m) || readonly (member_path_, member_scope_)) && - sk_ == statement_update) - return false; + return; // Inverse object pointers come from a joined table. // if (im != 0) { - semantics::class_* c (object_pointer (utype (m))); + semantics::data_member& id (*id_member (c)); + semantics::type& idt (utype (id)); if (container (*im)) { // This container is a direct member of the class so the table // prefix is just the class table name. We don't assign join // aliases for container tables so use the actual table name. - // Note that the (table_name_.empty () ? :) test may look wrong - // at first but it is no. + // Note that the if(!table_name_.empty ()) test may look wrong + // at first but it is not; if table_name_ is empty then we are + // generating a container table where we don't qualify columns + // with tables. // - column ( - *im, - "id", - table_name_.empty () - ? table_name_ - : table_qname (*im, - table_prefix (schema (c->scope ()), - table_name (*c) + "_", - 1)), - column_qname (*im, "id", "object_id")); + string table; + + if (!table_name_.empty ()) + { + table_prefix tp (schema (c.scope ()), table_name (c) + "_", 1); + table = table_qname (*im, tp); + } + + instance oc (table, sk_, sc_); + oc->traverse (*im, idt, "id", "object_id", &c); } else { - semantics::data_member& id (*id_member (*c)); - - // Use the join alias (column name) instead of the actual - // table name unless we are handling a container. Note that - // the (table_name_.empty () ? :) test may look wrong at - // first but it is no. + // Use the join alias instead of the actual table name unless we + // are handling a container. Generally, we want the join alias + // to be based on the column name. This is straightforward for + // single-column references. In case of a composite id, we will + // need to use the column prefix which is based on the data + // member name, unless overridden by the user. In the latter + // case the prefix can be empty, in which case we will just + // fall back on the member's public name. Note that the + // if(!table_name_.empty ()) test may look wrong at first but + // it is not; if table_name_ is empty then we are generating a + // container table where we don't qualify columns with tables. // - column ( - id, - "", - table_name_.empty () ? table_name_ : quote_id (name), - column_qname (id)); + string table; + + if (!table_name_.empty ()) + { + if (composite_wrapper (idt)) + { + string p (column_prefix (m, key_prefix_, default_name_)); + + if (p.empty ()) + p = public_name_db (m); + else + p.resize (p.size () - 1); // Remove trailing underscore. + + table = column_prefix_ + p; + } + else + table = column_prefix_ + + column_name (m, key_prefix_, default_name_); + + table = quote_id (table); + } + + instance oc (table, sk_, sc_); + oc->traverse (id); } } else - column (m, "", table_name_, quote_id (name)); + object_columns_base::traverse_pointer (m, c); + } + + virtual bool + traverse_column (semantics::data_member& m, string const& name, bool) + { + // Ignore certain columns depending on what kind statement we are + // generating. Id and readonly columns are not present in the update + // statements. + // + if ((id () || readonly (member_path_, member_scope_)) && + sk_ == statement_update) + return false; + + column (m, table_name_, quote_id (name)); return true; } virtual void column (semantics::data_member& m, - string const& key_prefix, string const& table, string const& column) { @@ -177,7 +214,7 @@ namespace relational r += param_->next (); } - sc_.push_back (statement_column (r, m, key_prefix)); + sc_.push_back (statement_column (r, column_type (), m, key_prefix_)); } protected: @@ -350,7 +387,7 @@ namespace relational virtual void column (semantics::data_member& m, string const& column) { - sc_.push_back (statement_column (column, m)); + sc_.push_back (statement_column (column, column_type (), m)); } protected: @@ -370,6 +407,7 @@ namespace relational table_ (table_qname (scope)), id_ (*id_member (scope)) { + id_cols_->traverse (id_); } size_t @@ -399,31 +437,63 @@ namespace relational } } - virtual bool - traverse_column (semantics::data_member& m, string const& column, bool) + virtual void + traverse_pointer (semantics::data_member& m, semantics::class_& c) { - semantics::class_* c (object_pointer (utype (m))); - - if (c == 0) - return false; - string t, a, dt, da; std::ostringstream cond, dcond; // @@ diversion? - if (semantics::data_member* im = inverse (m)) + // Derive table alias for this member. Generally, we want the + // alias to be based on the column name. This is straightforward + // for single-column references. In case of a composite id, we + // will need to use the column prefix which is based on the data + // member name, unless overridden by the user. In the latter + // case the prefix can be empty, in which case we will just + // fall back on the member's public name. + // + string alias; + + if (composite_wrapper (utype (*id_member (c)))) + { + string p (column_prefix (m, key_prefix_, default_name_)); + + if (p.empty ()) + p = public_name_db (m); + else + p.resize (p.size () - 1); // Remove trailing underscore. + + alias = column_prefix_ + p; + } + else + alias = column_prefix_ + + column_name (m, key_prefix_, default_name_); + + if (semantics::data_member* im = inverse (m, key_prefix_)) { if (container (*im)) { // This container is a direct member of the class so the table // prefix is just the class table name. // - qname const& ct (table_name (*c)); - table_prefix tp (schema (c->scope ()), ct + "_", 1); + qname const& ct (table_name (c)); + table_prefix tp (schema (c.scope ()), ct + "_", 1); t = table_qname (*im, tp); - string const& val (column_qname (*im, "value", "value")); - cond << t << '.' << val << " = " << - table_ << "." << column_qname (id_); + // Container's value is our id. + // + instance id_cols; + id_cols->traverse (*im, utype (id_), "value", "value"); + + for (object_columns_list::iterator b (id_cols->begin ()), i (b), + j (id_cols_->begin ()); i != id_cols->end (); ++i, ++j) + { + + if (i != b) + cond << " AND "; + + cond << t << '.' << quote_id (i->name) << '=' << + table_ << '.' << quote_id (j->name); + } // Add the join for the object itself so that we are able to // use it in the WHERE clause. @@ -431,21 +501,44 @@ namespace relational if (query_) { dt = quote_id (ct); - da = quote_id (column); + da = quote_id (alias); + + semantics::data_member& id (*id_member (c)); + + instance oid_cols, cid_cols; + oid_cols->traverse (id); + cid_cols->traverse (*im, utype (id), "id", "object_id", &c); + + for (object_columns_list::iterator b (cid_cols->begin ()), i (b), + j (oid_cols->begin ()); i != cid_cols->end (); ++i, ++j) + { - string const& id (column_qname (*im, "id", "object_id")); + if (i != b) + dcond << " AND "; - dcond << da << '.' << column_qname (*id_member (*c)) << " = " << - t << '.' << id; + dcond << da << '.' << quote_id (j->name) << '=' << + t << '.' << quote_id (i->name); + } } } else { - t = table_qname (*c); - a = quote_id (column); + t = table_qname (c); + a = quote_id (alias); + + instance id_cols; + id_cols->traverse (*im); + + for (object_columns_list::iterator b (id_cols->begin ()), i (b), + j (id_cols_->begin ()); i != id_cols->end (); ++i, ++j) + { + + if (i != b) + cond << " AND "; - cond << a << '.' << column_qname (*im) << " = " << - table_ << "." << column_qname (id_); + cond << a << '.' << quote_id (i->name) << '=' << + table_ << '.' << quote_id (j->name); + } } } else if (query_) @@ -453,11 +546,25 @@ namespace relational // We need the join to be able to use the referenced object // in the WHERE clause. // - t = table_qname (*c); - a = quote_id (column); + t = table_qname (c); + a = quote_id (alias); - cond << a << '.' << column_qname (*id_member (*c)) << " = " << - table_ << "." << quote_id (column); + instance oid_cols (column_prefix_); + oid_cols->traverse (m); + + instance pid_cols; + pid_cols->traverse (*id_member (c)); + + for (object_columns_list::iterator b (pid_cols->begin ()), i (b), + j (oid_cols->begin ()); i != pid_cols->end (); ++i, ++j) + { + + if (i != b) + cond << " AND "; + + cond << a << '.' << quote_id (i->name) << '=' << + table_ << '.' << quote_id (j->name); + } } if (!t.empty ()) @@ -478,14 +585,13 @@ namespace relational joins_.back ().alias = da; joins_.back ().cond = dcond.str (); } - - return true; } private: bool query_; string table_; semantics::data_member& id_; + instance id_cols_; struct join { @@ -690,6 +796,207 @@ namespace relational string member_override_; }; + template + struct init_image_member_impl: init_image_member, + virtual member_base_impl + { + typedef init_image_member_impl base_impl; + + init_image_member_impl (base const& x) + : base (x), + member_database_type_id_ (base::type_override_, + base::fq_type_override_, + base::key_prefix_) + { + } + + typedef typename member_base_impl::member_info member_info; + + virtual void + set_null (member_info&) = 0; + + virtual bool + pre (member_info& mi) + { + // Ignore containers (they get their own table) and inverse + // object pointers (they are not present in this binding). + // + if (container (mi) || inverse (mi.m, key_prefix_)) + return false; + + if (!member_override_.empty ()) + member = member_override_; + else + { + // If we are generating standard init() and this member + // contains version, ignore it. + // + if (version (mi.m)) + return false; + + // If we don't send auto id in INSERT statement, ignore this + // member altogether (we never send auto id in UPDATE). + // + if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m)) + return false; + + string const& name (mi.m.name ()); + member = "o." + name; + + os << "// " << name << endl + << "//" << endl; + + // If the whole class is readonly, then we will never be + // called with sk == statement_update. + // + if (!readonly (*context::top_object)) + { + semantics::class_* c; + + if (id (mi.m) || + readonly (mi.m) || + ((c = composite (mi.t)) && readonly (*c))) // Can't be id. + os << "if (sk == statement_insert)"; + } + } + + bool comp (composite (mi.t)); + + // If this is a wrapped composite value, then we need to "unwrap" + // it. For simple values this is taken care of by the value_traits + // specializations. + // + if (mi.wrapper != 0 && comp) + { + // Here we need the wrapper type, not the wrapped type. + // + member = "wrapper_traits< " + mi.fq_type (false) + " >::" + + "get_ref (" + member + ")"; + } + + if (mi.ptr != 0) + { + // When handling a pointer, mi.t is the id type of the referenced + // object. + // + semantics::type& pt (member_utype (mi.m, key_prefix_)); + + type = "obj_traits::id_type"; + + // Handle NULL pointers and extract the id. + // + os << "{" + << "typedef object_traits< " << class_fq_name (*mi.ptr) << + " > obj_traits;"; + + if (weak_pointer (pt)) + { + os << "typedef pointer_traits< " << mi.ptr_fq_type () << + " > wptr_traits;" + << "typedef pointer_traits< wptr_traits::" << + "strong_pointer_type > ptr_traits;" + << endl + << "wptr_traits::strong_pointer_type sp (" << + "wptr_traits::lock (" << member << "));"; + + member = "sp"; + } + else + os << "typedef pointer_traits< " << mi.ptr_fq_type () << + " > ptr_traits;" + << endl; + + os << "bool is_null (ptr_traits::null_ptr (" << member << "));" + << "if (!is_null)" + << "{" + << "const " << type << "& id (" << endl; + + if (lazy_pointer (pt)) + os << "ptr_traits::object_id< ptr_traits::element_type > (" << + member << ")"; + else + os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; + + os << ");" + << endl; + + member = "id"; + } + else if (comp) + { + type = mi.fq_type (); + + os << "{"; + } + else + { + type = mi.fq_type (); + + os << "{" + << "bool is_null;"; + } + + if (comp) + traits = "composite_value_traits< " + type + " >"; + else + { + db_type_id = member_database_type_id_->database_type_id (mi.m); + traits = string (db.string ()) + "::value_traits<\n " + + type + ",\n " + + db_type_id + " >"; + } + + return true; + } + + virtual void + post (member_info& mi) + { + if (mi.ptr != 0) + { + os << "}" + << "else" << endl; + + // @@ Composite value currently cannot be NULL. + // + if (!null (mi.m, key_prefix_) || composite (mi.t)) + os << "throw null_pointer ();"; + else + set_null (mi); + } + + os << "}"; + } + + virtual void + traverse_composite (member_info& mi) + { + bool grow (generate_grow && context::grow (mi.m, mi.t, key_prefix_)); + + if (grow) + os << "if ("; + + os << traits << "::init (" << endl + << "i." << mi.var << "value," << endl + << member << "," << endl + << "sk)"; + + if (grow) + os << ")" << endl + << "grew = true"; + + os << ";"; + } + + protected: + string type; + string db_type_id; + string member; + string traits; + + instance member_database_type_id_; + }; + struct init_image_base: traversal::class_, virtual context { typedef init_image_base base; @@ -755,6 +1062,171 @@ namespace relational string member_override_; }; + template + struct init_value_member_impl: init_value_member, + virtual member_base_impl + { + typedef init_value_member_impl base_impl; + + init_value_member_impl (base const& x) + : base (x), + member_database_type_id_ (base::type_override_, + base::fq_type_override_, + base::key_prefix_) + { + } + + typedef typename member_base_impl::member_info member_info; + + virtual void + get_null (member_info&) = 0; + + virtual bool + pre (member_info& mi) + { + if (container (mi)) + return false; + + if (!member_override_.empty ()) + member = member_override_; + else + { + string const& name (mi.m.name ()); + member = "o." + name; + + if (mi.cq) + { + string t (mi.ptr == 0 ? mi.fq_type (false) : mi.ptr_fq_type ()); + member = "const_cast< " + t + "& > (" + member + ")"; + } + + os << "// " << name << endl + << "//" << endl; + } + + bool comp (composite (mi.t)); + + // If this is a wrapped composite value, then we need to + // "unwrap" it. For simple values this is taken care of + // by the value_traits specializations. + // + if (mi.wrapper != 0 && comp) + { + // Here we need the wrapper type, not the wrapped type. + // + member = "wrapper_traits< " + mi.fq_type (false) + " >::" + + "set_ref (\n" + member + ")"; + } + + if (mi.ptr != 0) + { + type = "obj_traits::id_type"; + + // Handle NULL pointers and extract the id. + // + os << "{" + << "typedef object_traits< " << class_fq_name (*mi.ptr) << + " > obj_traits;" + << "typedef pointer_traits< " << mi.ptr_fq_type () << + " > ptr_traits;" + << endl; + + // @@ Composite value currently cannot be NULL. + // + if (!comp) + { + os << "if ("; + get_null (mi); + os << ")" << endl; + + if (!null (mi.m, key_prefix_) ) + os << "throw null_pointer ();"; + else + os << member << " = ptr_traits::pointer_type ();"; + + os << "else" + << "{"; + } + + os << type << " id;"; + + member = "id"; + } + else + type = mi.fq_type (); + + if (comp) + traits = "composite_value_traits< " + type + " >"; + else + { + db_type_id = member_database_type_id_->database_type_id (mi.m); + traits = string (db.string ()) + "::value_traits<\n " + + type + ",\n " + + db_type_id + " >"; + } + + return true; + } + + virtual void + post (member_info& mi) + { + if (mi.ptr != 0) + { + if (!member_override_.empty ()) + member = member_override_; + else + { + member = "o." + mi.m.name (); + + if (mi.cq) + member = "const_cast< " + mi.ptr_fq_type () + + "& > (" + member + ")"; + } + + // When handling a pointer, mi.t is the id type of the referenced + // object. + // + semantics::type& pt (member_utype (mi.m, key_prefix_)); + + if (lazy_pointer (pt)) + os << member << " = ptr_traits::pointer_type (*db, id);"; + else + os << "// If a compiler error points to the line below, then" << endl + << "// it most likely means that a pointer used in a member" << endl + << "// cannot be initialized from an object pointer." << endl + << "//" << endl + << member << " = ptr_traits::pointer_type (" << endl + << "db->load< obj_traits::object_type > (id));"; + + // @@ Composite value currently cannot be NULL. + // + if (!composite (mi.t)) + os << "}"; + + os << "}"; + } + } + + virtual void + traverse_composite (member_info& mi) + { + os << traits << "::init (" << endl + << member << "," << endl + << "i." << mi.var << "value," << endl + << "db);" + << endl; + } + + protected: + string type; + string db_type_id; + string traits; + string member; + + instance member_database_type_id_; + }; + struct init_value_base: traversal::class_, virtual context { typedef init_value_base base; @@ -930,7 +1402,10 @@ namespace relational // if (!abst) { + semantics::type& idt (container_idt (m)); + string table (table_qname (m, table_prefix_)); + instance id_cols; // select_all_statement // @@ -940,10 +1415,12 @@ namespace relational if (inverse) { semantics::class_* c (object_pointer (vt)); + semantics::data_member& inv_id (*id_member (*c)); - string inv_table; // Other table name. - string inv_id; // Other id column. - string inv_fid; // Other foreign id column (ref to us). + string inv_table; // Other table name. + instance inv_id_cols; // Other id column. + instance inv_fid_cols; // Other foreign id + // column (ref to us). statement_columns sc; if (container (*im)) @@ -956,23 +1433,42 @@ namespace relational // table_prefix tp (schema (c->scope ()), table_name (*c) + "_", 1); inv_table = table_qname (*im, tp); - inv_id = column_qname (*im, "id", "object_id"); - inv_fid = column_qname (*im, "value", "value"); - sc.push_back (statement_column ( - inv_table + "." + inv_id, *im, "id")); + inv_id_cols->traverse (*im, utype (inv_id), "id", "object_id", c); + inv_fid_cols->traverse (*im, idt, "value", "value"); + + for (object_columns_list::iterator i (inv_id_cols->begin ()); + i != inv_id_cols->end (); ++i) + { + // If this is a simple id, then pass the "id" key prefix. If + // it is a composite id, then the members have no prefix. + // + sc.push_back ( + statement_column ( + inv_table + "." + quote_id (i->name), + i->type, + *i->member, + inv_id_cols->size () == 1 ? "id" : "")); + } } else { // many(i)-to-one // - semantics::data_member& id (*id_member (*c)); - inv_table = table_qname (*c); - inv_id = column_qname (id); - inv_fid = column_qname (*im); - sc.push_back (statement_column (inv_table + "." + inv_id, id)); + inv_id_cols->traverse (inv_id); + inv_fid_cols->traverse (*im); + + for (object_columns_list::iterator i (inv_id_cols->begin ()); + i != inv_id_cols->end (); ++i) + { + sc.push_back ( + statement_column ( + inv_table + "." + quote_id (i->name), + i->type, + *i->member)); + } } process_statement_columns (sc, statement_select); @@ -987,12 +1483,20 @@ namespace relational } instance qp; - os << strlit (" FROM " + inv_table + - " WHERE " + inv_table + "." + inv_fid + "=" + - qp->next ()); + os << strlit (" FROM " + inv_table); + + for (object_columns_list::iterator b (inv_fid_cols->begin ()), + i (b); i != inv_fid_cols->end (); ++i) + { + os << endl + << strlit ((i == b ? " WHERE " : " AND ") + inv_table + "." + + quote_id (i->name) + "=" + qp->next ()); + } } else { + id_cols->traverse (m, idt, "id", "object_id"); + statement_columns sc; statement_kind sk (statement_select); // Imperfect forwarding. instance t (table, sk, sc); @@ -1002,22 +1506,13 @@ namespace relational case ck_ordered: { if (ordered) - { - string const& col (column_qname (m, "index", "index")); - t->column (m, "index", table, col); - } + t->traverse (m, *it, "index", "index"); break; } case ck_map: case ck_multimap: { - if (semantics::class_* ckt = composite_wrapper (*kt)) - t->traverse (m, *ckt, "key", "key"); - else - { - string const& col (column_qname (m, "key", "key")); - t->column (m, "key", table, col); - } + t->traverse (m, *kt, "key", "key"); break; } case ck_set: @@ -1027,13 +1522,7 @@ namespace relational } } - if (semantics::class_* cvt = composite_wrapper (vt)) - t->traverse (m, *cvt, "value", "value"); - else - { - string const& col (column_qname (m, "value", "value")); - t->column (m, "value", table, col); - } + t->traverse (m, vt, "value", "value"); process_statement_columns (sc, statement_select); @@ -1047,18 +1536,22 @@ namespace relational } instance qp; - string const& id_col (column_qname (m, "id", "object_id")); + os << strlit (" FROM " + table); - os << strlit (" FROM " + table + - " WHERE " + table + "." + id_col + "=" + - qp->next ()); + for (object_columns_list::iterator b (id_cols->begin ()), i (b); + i != id_cols->end (); ++i) + { + os << endl + << strlit ((i == b ? " WHERE " : " AND ") + table + "." + + quote_id (i->name) + "=" + qp->next ()); + } if (ordered) { string const& col (column_qname (m, "index", "index")); os << endl - << strlit (" ORDER BY " + table + "." + col) << endl; + << strlit (" ORDER BY " + table + "." + col); } } @@ -1076,29 +1569,23 @@ namespace relational else { statement_columns sc; - sc.push_back ( - statement_column ( - column_qname (m, "id", "object_id"), m, "id")); - statement_kind sk (statement_insert); // Imperfect forwarding. instance t (sk, sc); + t->traverse (m, idt, "id", "object_id"); + switch (ck) { case ck_ordered: { if (ordered) - t->column ( - m, "index", "", column_qname (m, "index", "index")); + t->traverse (m, *it, "index", "index"); break; } case ck_map: case ck_multimap: { - if (semantics::class_* ckt = composite_wrapper (*kt)) - t->traverse (m, *ckt, "key", "key"); - else - t->column (m, "key", "", column_qname (m, "key", "key")); + t->traverse (m, *kt, "key", "key"); break; } case ck_set: @@ -1108,10 +1595,7 @@ namespace relational } } - if (semantics::class_* cvt = composite_wrapper (vt)) - t->traverse (m, *cvt, "value", "value"); - else - t->column (m, "value", "", column_qname (m, "value", "value")); + t->traverse (m, vt, "value", "value"); process_statement_columns (sc, statement_insert); @@ -1151,9 +1635,17 @@ namespace relational { instance qp; - os << strlit ("DELETE FROM " + table) << endl - << strlit (" WHERE " + column_qname (m, "id", "object_id") + - "=" + qp->next ()) << ";" + os << strlit ("DELETE FROM " + table); + + for (object_columns_list::iterator b (id_cols->begin ()), i (b); + i != id_cols->end (); ++i) + { + os << endl + << strlit ((i == b ? " WHERE " : " AND ") + + quote_id (i->name) + "=" + qp->next ()); + } + + os << ";" << endl; } } @@ -1462,10 +1954,10 @@ namespace relational { if (ordered) os << "init (index_type& j, value_type& v, " << - "const data_image_type& i, database& db)"; + "const data_image_type& i, database* db)"; else os << "init (value_type& v, const data_image_type& i, " << - "database& db)"; + "database* db)"; os << "{" << "ODB_POTENTIALLY_UNUSED (db);" @@ -1487,7 +1979,7 @@ namespace relational case ck_multimap: { os << "init (key_type& k, value_type& v, " << - "const data_image_type& i, database& db)" + "const data_image_type& i, database* db)" << "{" << "ODB_POTENTIALLY_UNUSED (db);" << endl @@ -1504,7 +1996,7 @@ namespace relational case ck_multiset: { os << "init (value_type& v, const data_image_type& i, " << - "database& db)" + "database* db)" << "{" << "ODB_POTENTIALLY_UNUSED (db);" << endl; @@ -1652,21 +2144,21 @@ namespace relational case ck_ordered: { os << "init (" << (ordered ? "i, " : "") << - "v, di, sts.connection ().database ());" + "v, di, &sts.connection ().database ());" << endl; break; } case ck_map: case ck_multimap: { - os << "init (k, v, di, sts.connection ().database ());" + os << "init (k, v, di, &sts.connection ().database ());" << endl; break; } case ck_set: case ck_multiset: { - os << "init (v, di, sts.connection ().database ());" + os << "init (v, di, &sts.connection ().database ());" << endl; break; } @@ -2130,26 +2622,30 @@ namespace relational } virtual void - traverse_simple (semantics::data_member& m) + traverse_pointer (semantics::data_member& m, semantics::class_& c) { if (!inverse (m)) - { - string p; + object_members_base::traverse_pointer (m, c); + } - if (version (m)) - p = "1"; - else if (id (m) && auto_ (m)) - p = qp_.auto_id (); - else - p = qp_.next (); + virtual void + traverse_simple (semantics::data_member& m) + { + string p; - if (!p.empty ()) - { - if (count_++ != 0) - params_ += ','; + if (version (m)) + p = "1"; + else if (context::id (m) && auto_ (m)) // Only simple id can be auto. + p = qp_.auto_id (); + else + p = qp_.next (); - params_ += p; - } + if (!p.empty ()) + { + if (count_++ != 0) + params_ += ','; + + params_ += p; } } @@ -2434,6 +2930,9 @@ namespace relational << traits << "::" << endl << "id (const image_type& i)" << "{" + << db << "::database* db (0);" + << "ODB_POTENTIALLY_UNUSED (db);" + << endl << "id_type id;"; init_id_value_member_->traverse (*id); os << "return id;" @@ -2505,11 +3004,14 @@ namespace relational << "{" << "std::size_t n (0);"; + if (composite_wrapper (utype (*id))) + os << db << "::statement_kind sk (" << db << "::statement_select);"; + bind_id_member_->traverse (*id); if (optimistic != 0) { - os << "n++;" //@@ composite id + os << "n += " << column_count (c).id << ";" << endl; bind_version_member_->traverse (*optimistic); @@ -2549,7 +3051,7 @@ namespace relational // init (object, image) // os << "void " << traits << "::" << endl - << "init (object_type& o, const image_type& i, database& db)" + << "init (object_type& o, const image_type& i, database* db)" << "{" << "ODB_POTENTIALLY_UNUSED (o);" << "ODB_POTENTIALLY_UNUSED (i);" @@ -2571,8 +3073,10 @@ namespace relational << "{"; if (grow_id) - os << "bool grew (false);" - << endl; + os << "bool grew (false);"; + + if (composite_wrapper (utype (*id))) + os << db << "::statement_kind sk (" << db << "::statement_select);"; init_id_image_member_->traverse (*id); @@ -2677,7 +3181,8 @@ namespace relational if (id != 0) { - string const& id_col (column_qname (*id)); + instance id_cols; + id_cols->traverse (*id); // find_statement // @@ -2702,14 +3207,23 @@ namespace relational os << strlit (" FROM " + table) << endl; - bool f (false); + bool f (false); // @@ (im)perfect forwarding instance j (c, f); // @@ (im)perfect forwarding j->traverse (c); j->write (); instance qp; - os << strlit (" WHERE " + table + "." + id_col + "=" + - qp->next ()) << ";" + for (object_columns_list::iterator b (id_cols->begin ()), i (b); + i != id_cols->end (); ++i) + { + if (i != b) + os << endl; + + os << strlit ((i == b ? " WHERE " : " AND ") + table + "." + + quote_id (i->name) + "=" + qp->next ()); + } + + os << ";" << endl; } @@ -2739,13 +3253,22 @@ namespace relational os << strlit (c + (++i != e ? "," : "")) << endl; } - string where (" WHERE " + id_col + "=" + qp->next ()); + for (object_columns_list::iterator b (id_cols->begin ()), i (b); + i != id_cols->end (); ++i) + { + if (i != b) + os << endl; + + os << strlit ((i == b ? " WHERE " : " AND ") + + quote_id (i->name) + "=" + qp->next ()); + } if (optimistic != 0) - where += " AND " + column_qname (*optimistic) + "=" + - qp->next (); + os << endl + << strlit (" AND " + column_qname (*optimistic) + + "=" + qp->next ()); - os << strlit (where) << ";" + os << ";" << endl; } @@ -2754,8 +3277,18 @@ namespace relational { instance qp; os << "const char " << traits << "::erase_statement[] =" << endl - << strlit ("DELETE FROM " + table) << endl - << strlit (" WHERE " + id_col + "=" + qp->next ()) << ";" + << strlit ("DELETE FROM " + table); + + for (object_columns_list::iterator b (id_cols->begin ()), i (b); + i != id_cols->end (); ++i) + { + + os << endl + << strlit ((i == b ? " WHERE " : " AND ") + + quote_id (i->name) + "=" + qp->next ()); + } + + os << ";" << endl; } @@ -2763,13 +3296,21 @@ namespace relational { instance qp; - string where (" WHERE " + id_col + "=" + qp->next ()); - where += " AND " + column_qname (*optimistic) + "=" + qp->next (); - os << "const char " << traits << "::optimistic_erase_statement[] =" << endl - << strlit ("DELETE FROM " + table) << endl - << strlit (where) << ";" + << strlit ("DELETE FROM " + table); + + for (object_columns_list::iterator b (id_cols->begin ()), i (b); + i != id_cols->end (); ++i) + { + os << endl + << strlit ((i == b ? " WHERE " : " AND ") + + quote_id (i->name) + "=" + qp->next ()); + } + + os << endl + << strlit (" AND " + column_qname (*optimistic) + + "=" + qp->next ()) << ";" << endl; } } @@ -2786,10 +3327,6 @@ namespace relational process_statement_columns (sc, statement_select); } - bool t (true); - instance oj (c, t); //@@ (im)perfect forwarding - oj->traverse (c); - os << "const char " << traits << "::query_statement[] =" << endl << strlit ("SELECT ") << endl; @@ -2801,7 +3338,15 @@ namespace relational } os << strlit (" FROM " + table) << endl; - oj->write (); + + if (id != 0) + { + bool t (true); //@@ (im)perfect forwarding + instance oj (c, t); //@@ (im)perfect forwarding + oj->traverse (c); + oj->write (); + } + os << strlit (" ") << ";" << endl; @@ -3202,7 +3747,7 @@ namespace relational << "if (l.locked ())" << "{" << "callback (db, obj, callback_event::pre_load);" - << "init (obj, sts.image (), db);"; + << "init (obj, sts.image (), &db);"; init_value_extra (); free_statement_result_delayed (); @@ -3248,7 +3793,7 @@ namespace relational << "reference_cache_traits< object_type >::insert (db, id, obj));" << endl << "callback (db, obj, callback_event::pre_load);" - << "init (obj, sts.image (), db);"; + << "init (obj, sts.image (), &db);"; init_value_extra (); free_statement_result_delayed (); @@ -3298,7 +3843,7 @@ namespace relational } os << "callback (db, obj, callback_event::pre_load);" - << "init (obj, sts.image (), db);"; + << "init (obj, sts.image (), &db);"; init_value_extra (); free_statement_result_delayed (); @@ -3766,7 +4311,7 @@ namespace relational // init (view, image) // os << "void " << traits << "::" << endl - << "init (view_type& o, const image_type& i, database& db)" + << "init (view_type& o, const image_type& i, database* db)" << "{" << "ODB_POTENTIALLY_UNUSED (o);" << "ODB_POTENTIALLY_UNUSED (i);" @@ -4080,7 +4625,7 @@ namespace relational if (im != 0) { // For now a direct member can only be directly in - // the object scope. When this changes, the inverse() + // the object scope. If this changes, the inverse() // function would have to return a member path instead // of just a single member. // @@ -4102,34 +4647,36 @@ namespace relational // If we are the pointed-to object, then we have to turn // things around. This is necessary to have the proper - // JOIN order. There seems to be a pattern there but - // it is not yet intuitively clear what it means. + // JOIN order. There seems to be a pattern there but it + // is not yet intuitively clear what it means. // + instance c_cols; // Container columns. + instance o_cols; // Object columns. + + qname* ot; // Object table (either lt or rt). + if (im != 0) { if (i->obj == c) { // container.value = pointer.id // - l = ct; - l += '.'; - l += column_qname (*im, "value", "value"); - l += "="; - l += quote_id (lt); - l += '.'; - l += column_qname (*id_member (*e.vo->obj)); + semantics::data_member& id (*id_member (*e.vo->obj)); + + c_cols->traverse (*im, utype (id), "value", "value"); + o_cols->traverse (id); + ot = < } else { // container.id = pointed-to.id // - l = ct; - l += '.'; - l += column_qname (*im, "id", "object_id"); - l += "="; - l += quote_id (rt); - l += '.'; - l += column_qname (*id_member (*vo->obj)); + semantics::data_member& id (*id_member (*vo->obj)); + + c_cols->traverse ( + *im, utype (id), "id", "object_id", vo->obj); + o_cols->traverse (id); + ot = &rt; } } else @@ -4138,29 +4685,43 @@ namespace relational { // container.id = pointer.id // - l = ct; - l += '.'; - l += column_qname (m, "id", "object_id"); - l += "="; - l += quote_id (lt); - l += '.'; - l += column_qname (*id_member (*e.vo->obj)); + semantics::data_member& id (*id_member (*e.vo->obj)); + + c_cols->traverse ( + m, utype (id), "id", "object_id", e.vo->obj); + o_cols->traverse (id); + ot = < } else { // container.value = pointed-to.id // - l = ct; - l += '.'; - l += column_qname (m, "value", "value"); - l += "="; - l += quote_id (rt); - l += '.'; - l += column_qname (*id_member (*vo->obj)); + semantics::data_member& id (*id_member (*vo->obj)); + + c_cols->traverse (m, utype (id), "value", "value"); + o_cols->traverse (id); + ot = &rt; } } - os << "r += " << strlit (l) << ";"; + for (object_columns_list::iterator b (c_cols->begin ()), i (b), + j (o_cols->begin ()); i != c_cols->end (); ++i, ++j) + { + l.clear (); + + if (i != b) + l += "AND "; + + l += ct; + l += '.'; + l += quote_id (i->name); + l += '='; + l += quote_id (*ot); + l += '.'; + l += quote_id (j->name); + + os << "r += " << strlit (l) << ";"; + } } l = "LEFT JOIN "; @@ -4174,31 +4735,33 @@ namespace relational if (cont != 0) { + instance c_cols; // Container columns. + instance o_cols; // Object columns. + + qname* ot; // Object table (either lt or rt). + if (im != 0) { if (i->obj == c) { // container.id = pointed-to.id // - l = ct; - l += '.'; - l += column_qname (*im, "id", "object_id"); - l += "="; - l += quote_id (rt); - l += '.'; - l += column_qname (*id_member (*vo->obj)); + semantics::data_member& id (*id_member (*vo->obj)); + + c_cols->traverse ( + *im, utype (id), "id", "object_id", vo->obj); + o_cols->traverse (id); + ot = &rt; } else { // container.value = pointer.id // - l = ct; - l += '.'; - l += column_qname (*im, "value", "value"); - l += "="; - l += quote_id (lt); - l += '.'; - l += column_qname (*id_member (*e.vo->obj)); + semantics::data_member& id (*id_member (*e.vo->obj)); + + c_cols->traverse (*im, utype (id), "value", "value"); + o_cols->traverse (id); + ot = < } } else @@ -4207,58 +4770,91 @@ namespace relational { // container.value = pointed-to.id // - l = ct; - l += '.'; - l += column_qname (m, "value", "value"); - l += "="; - l += quote_id (rt); - l += '.'; - l += column_qname (*id_member (*vo->obj)); + semantics::data_member& id (*id_member (*vo->obj)); + + c_cols->traverse (m, utype (id), "value", "value"); + o_cols->traverse (id); + ot = &rt; } else { // container.id = pointer.id // - l = ct; - l += '.'; - l += column_qname (m, "id", "object_id"); - l += "="; - l += quote_id (lt); - l += '.'; - l += column_qname (*id_member (*e.vo->obj)); + semantics::data_member& id (*id_member (*e.vo->obj)); + + c_cols->traverse ( + m, utype (id), "id", "object_id", e.vo->obj); + o_cols->traverse (id); + ot = < } } + + for (object_columns_list::iterator b (c_cols->begin ()), i (b), + j (o_cols->begin ()); i != c_cols->end (); ++i, ++j) + { + l.clear (); + + if (i != b) + l += "AND "; + + l += ct; + l += '.'; + l += quote_id (i->name); + l += '='; + l += quote_id (*ot); + l += '.'; + l += quote_id (j->name); + + os << "r += " << strlit (l) << ";"; + } } else { + string col_prefix; + + if (im == 0) + col_prefix = + object_columns_base::column_prefix (e.member_path); + + instance l_cols (col_prefix); + instance r_cols; + if (im != 0) { // our.id = pointed-to.pointer // - l = quote_id (lt); - l += '.'; - l += column_qname (*id_member (*e.vo->obj)); - l += " = "; - l += quote_id (rt); - l += '.'; - l += column_qname (*im); + l_cols->traverse (*id_member (*e.vo->obj)); + r_cols->traverse (*im); } else { // our.pointer = pointed-to.id // - l = quote_id (lt); + l_cols->traverse (*e.member_path.back ()); + r_cols->traverse (*id_member (*vo->obj)); + } + + for (object_columns_list::iterator b (l_cols->begin ()), i (b), + j (r_cols->begin ()); i != l_cols->end (); ++i, ++j) + { + l.clear (); + + if (i != b) + l += "AND "; + + l += quote_id (lt); l += '.'; - l += column_qname (e.member_path); - l += " = "; + l += quote_id (i->name); + l += '='; l += quote_id (rt); l += '.'; - l += column_qname (*id_member (*vo->obj)); + l += quote_id (j->name); + + os << "r += " << strlit (l) << ";"; } } - os << "r += " << strlit (l) << ";" - << endl; + os << endl; } // Generate the query condition. @@ -4499,7 +5095,7 @@ namespace relational // init (value, image) // os << "void " << traits << "::" << endl - << "init (value_type& o, const image_type& i, database& db)" + << "init (value_type& o, const image_type& i, database* db)" << "{" << "ODB_POTENTIALLY_UNUSED (o);" << "ODB_POTENTIALLY_UNUSED (i);" @@ -4588,8 +5184,12 @@ namespace relational << "#include " << endl << "#include " << endl << "#include " << endl - << "#include " << endl - << "#include " << endl + << "#include " << endl; + + if (options.generate_query ()) + os << "#include " << endl; + + os << "#include " << endl << "#include " << endl; if (options.generate_query ()) diff --git a/odb/relational/sqlite/common.cxx b/odb/relational/sqlite/common.cxx index 480b69a..7164ef3 100644 --- a/odb/relational/sqlite/common.cxx +++ b/odb/relational/sqlite/common.cxx @@ -16,91 +16,10 @@ namespace relational // member_base // - void member_base:: - traverse (semantics::data_member& m) + sql_type const& member_base:: + member_sql_type (semantics::data_member& m) { - if (transient (m)) - return; - - string var; - - if (!var_override_.empty ()) - var = var_override_; - else - { - string const& name (m.name ()); - var = name + (name[name.size () - 1] == '_' ? "" : "_"); - } - - bool cq (type_override_ != 0 ? false : const_type (m.type ())); - semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m)); - - semantics::type* cont; - if (semantics::class_* c = composite_wrapper (t)) - { - // If t is a wrapper, pass the wrapped type. Also pass the - // original, wrapper type. - // - member_info mi (m, - *c, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_composite (mi); - post (mi); - } - } - // This cannot be a container if we have a type override. - // - else if (type_override_ == 0 && (cont = context::container (m))) - { - // The same unwrapping logic as for composite values. - // - member_info mi (m, - *cont, - (wrapper (t) ? &t : 0), - cq, - var, - fq_type_override_); - if (pre (mi)) - { - traverse_container (mi); - post (mi); - } - } - else - { - sql_type const& st (column_sql_type (m, key_prefix_)); - - if (semantics::class_* c = object_pointer (t)) - { - member_info mi (m, - utype (*id_member (*c)), - 0, - cq, - var, - fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_object_pointer (mi); - post (mi); - } - } - else - { - member_info mi (m, t, 0, cq, var, fq_type_override_); - mi.st = &st; - if (pre (mi)) - { - traverse_simple (mi); - post (mi); - } - } - } + return parse_sql_type (column_type (m, key_prefix_), m); } void member_base:: @@ -185,10 +104,18 @@ namespace relational // member_database_type_id:: + member_database_type_id (base const& x) + : member_base::base (x), // virtual base + base (x) + { + } + + member_database_type_id:: member_database_type_id (semantics::type* type, - string const& fq_type, - string const& key_prefix) - : relational::member_base (type, fq_type, key_prefix) + string const& fq_type, + string const& key_prefix) + : member_base::base (type, fq_type, key_prefix), // virtual base + base (type, fq_type, key_prefix) { } @@ -230,6 +157,8 @@ namespace relational type_id_ = "sqlite::id_blob"; } + entry member_database_type_id_; + // // query_columns // diff --git a/odb/relational/sqlite/common.hxx b/odb/relational/sqlite/common.hxx index 7885a04..941e200 100644 --- a/odb/relational/sqlite/common.hxx +++ b/odb/relational/sqlite/common.hxx @@ -12,118 +12,18 @@ namespace relational { namespace sqlite { - struct member_base: virtual relational::member_base, context + struct member_base: virtual relational::member_base_impl, context { - member_base (base const& x): base (x) {} + member_base (base const& x): base (x), base_impl (x) {} // This c-tor is for the direct use inside the sqlite namespace. // If you do use this c-tor, you should also explicitly call - // relational::member_base. + // relational::member_base (aka base). // member_base () {} - virtual void - traverse (semantics::data_member& m); - - struct member_info - { - semantics::data_member& m; // Member. - semantics::type& t; // Cvr-unqualified member C++ type, note - // that m.type () may not be the same as t. - semantics::type* wrapper; // Wrapper type if member is a composite or - // container wrapper, also cvr-unqualified. - // In this case t is the wrapped type. - bool cq; // True if the original (wrapper) type - // is const-qualified. - sql_type const* st; // Member SQL type (only simple values). - string& var; // Member variable name with trailing '_'. - - // C++ type fq-name. - // - string - fq_type (bool unwrap = true) const - { - semantics::names* hint; - - if (wrapper != 0 && unwrap) - { - // Use the hint from the wrapper unless the wrapped type - // is qualified. - // - hint = wrapper->get ("wrapper-hint"); - utype (*context::wrapper (*wrapper), hint); - return t.fq_name (hint); - } - - // Use the original type from 'm' instead of 't' since the hint - // may be invalid for a different type. Plus, if a type is - // overriden, then the fq_type must be as well. - // - if (fq_type_.empty ()) - { - semantics::type& t (utype (m, hint)); - return t.fq_name (hint); - } - else - return fq_type_; - } - - string const& fq_type_; - - member_info (semantics::data_member& m_, - semantics::type& t_, - semantics::type* wrapper_, - bool cq_, - string& var_, - string const& fq_type) - : m (m_), - t (t_), - wrapper (wrapper_), - cq (cq_), - st (0), - var (var_), - fq_type_ (fq_type) - { - } - }; - - bool - container (member_info& mi) - { - // This cannot be a container if we have a type override. - // - return type_override_ == 0 && context::container (mi.m); - } - - // The false return value indicates that no further callbacks - // should be called for this member. - // - virtual bool - pre (member_info&) - { - return true; - } - - virtual void - post (member_info&) - { - } - - virtual void - traverse_composite (member_info&) - { - } - - virtual void - traverse_container (member_info&) - { - } - - virtual void - traverse_object_pointer (member_info& mi) - { - traverse_simple (mi); - } + virtual sql_type const& + member_sql_type (semantics::data_member&); virtual void traverse_simple (member_info&); @@ -182,12 +82,16 @@ namespace relational string type_; }; - struct member_database_type_id: member_base + struct member_database_type_id: relational::member_database_type_id, + member_base { + member_database_type_id (base const&); + member_database_type_id (semantics::type* type = 0, string const& fq_type = string (), string const& key_prefix = string ()); - string + + virtual string database_type_id (type&); virtual void diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx index b04dcb9..46689bd 100644 --- a/odb/relational/sqlite/context.cxx +++ b/odb/relational/sqlite/context.cxx @@ -365,17 +365,20 @@ namespace relational } sql_type const& context:: - column_sql_type (semantics::data_member& m, string const& kp) + parse_sql_type (string const& t, semantics::data_member& m) { - string key (kp.empty () - ? string ("sqlite-column-sql-type") - : "sqlite-" + kp + "-column-sql-type"); + // If this proves to be too expensive, we can maintain a + // cache of parsed types. + // + data::sql_type_cache::iterator i (data_->sql_type_cache_.find (t)); - if (!m.count (key)) + if (i != data_->sql_type_cache_.end ()) + return i->second; + else { try { - m.set (key, parse_sql_type (column_type (m, kp))); + return (data_->sql_type_cache_[t] = parse_sql_type (t)); } catch (invalid_sql_type const& e) { @@ -385,8 +388,6 @@ namespace relational throw operation_failed (); } } - - return m.get (key); } sql_type context:: diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx index e9f755c..4123b0c 100644 --- a/odb/relational/sqlite/context.hxx +++ b/odb/relational/sqlite/context.hxx @@ -5,6 +5,8 @@ #ifndef ODB_RELATIONAL_SQLITE_CONTEXT_HXX #define ODB_RELATIONAL_SQLITE_CONTEXT_HXX +#include + #include namespace relational @@ -33,8 +35,7 @@ namespace relational { public: sql_type const& - column_sql_type (semantics::data_member&, - string const& key_prefix = string ()); + parse_sql_type (string const&, semantics::data_member&); public: struct invalid_sql_type @@ -87,6 +88,9 @@ namespace relational struct data: base_context::data { data (std::ostream& os): base_context::data (os) {} + + typedef std::map sql_type_cache; + sql_type_cache sql_type_cache_; }; data* data_; diff --git a/odb/relational/sqlite/model.cxx b/odb/relational/sqlite/model.cxx index 60522a3..41d5d6c 100644 --- a/odb/relational/sqlite/model.cxx +++ b/odb/relational/sqlite/model.cxx @@ -28,7 +28,7 @@ namespace relational { // Make sure the column is mapped to INTEGER. // - if (column_sql_type (m).type != sql_type::INTEGER) + if (parse_sql_type (column_type (), m).type != sql_type::INTEGER) { cerr << m.file () << ":" << m.line () << ":" << m.column () << ": error: column with default value specified as C++ " diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx index 024694f..c170904 100644 --- a/odb/relational/sqlite/source.cxx +++ b/odb/relational/sqlite/source.cxx @@ -269,173 +269,21 @@ namespace relational // init image // - struct init_image_member: relational::init_image_member, member_base + struct init_image_member: relational::init_image_member_impl, + member_base { init_image_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) - { - // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in this binding). - // - if (container (mi) || inverse (mi.m, key_prefix_)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - // If we are generating standard init() and this member - // contains version, ignore it. - // - if (version (mi.m)) - return false; - - string const& name (mi.m.name ()); - member = "o." + name; - - os << "// " << name << endl - << "//" << endl; - - // If the whole class is readonly, then we will never be - // called with sk == statement_update. - // - if (!readonly (*context::top_object)) - { - semantics::class_* c; - - if (id (mi.m) || - readonly (mi.m) || - ((c = composite (mi.t)) && readonly (*c))) - os << "if (sk == statement_insert)"; - } - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "get_ref (" + member + ")"; - } - - if (composite (mi.t)) - { - os << "{"; - traits = "composite_value_traits< " + mi.fq_type () + " >"; - } - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;"; - - if (weak_pointer (mt)) - { - os << "typedef pointer_traits< " << mi.fq_type () << - " > wptr_traits;" - << "typedef pointer_traits< wptr_traits::" << - "strong_pointer_type > ptr_traits;" - << endl - << "wptr_traits::strong_pointer_type sp (" << - "wptr_traits::lock (" << member << "));"; - - member = "sp"; - } - else - os << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl; - - os << "i." << mi.var << "null = ptr_traits::null_ptr (" << - member << ");" - << "if (!i." << mi.var << "null)" - << "{" - << "const " << type << "& id (" << endl; - - if (lazy_pointer (mt)) - os << "ptr_traits::object_id< ptr_traits::element_type > (" << - member << ")"; - else - os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; - - os << ");" - << endl; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - - os << "{"; - } - - traits = "sqlite::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - if (composite (mi.t)) - os << "}"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - if (object_pointer (member_utype (mi.m, key_prefix_))) - { - os << "}"; - - if (!null (mi.m, key_prefix_)) - os << "else" << endl - << "throw null_pointer ();"; - } - - os << "}"; - } } virtual void - traverse_composite (member_info& mi) + set_null (member_info& mi) { - os << "if (" << traits << "::init (" << endl - << "i." << mi.var << "value," << endl - << member << "," << endl - << "sk))" << endl - << "grew = true;"; + os << "i." << mi.var << "null = true;"; } virtual void @@ -443,8 +291,9 @@ namespace relational { os << traits << "::set_image (" << endl << "i." << mi.var << "value," << endl - << "i." << mi.var << "null," << endl - << member << ");"; + << "is_null," << endl + << member << ");" + << "i." << mi.var << "null = is_null;"; } virtual void @@ -452,8 +301,9 @@ namespace relational { os << traits << "::set_image (" << endl << "i." << mi.var << "value," << endl - << "i." << mi.var << "null," << endl - << member << ");"; + << "is_null," << endl + << member << ");" + << "i." << mi.var << "null = is_null;"; } virtual void @@ -463,18 +313,11 @@ namespace relational << traits << "::set_image (" << endl << "i." << mi.var << "value," << endl << "i." << mi.var << "size," << endl - << "i." << mi.var << "null," << endl + << "is_null," << endl << member << ");" + << "i." << mi.var << "null = is_null;" << "grew = grew || (cap != i." << mi.var << "value.capacity ());"; } - - private: - string type; - string db_type_id; - string member; - string traits; - - member_database_type_id member_database_type_id_; }; entry init_image_member_; @@ -482,147 +325,21 @@ namespace relational // init value // - struct init_value_member: relational::init_value_member, member_base + struct init_value_member: relational::init_value_member_impl, + member_base { init_value_member (base const& x) - : member_base::base (x), // virtual base - base (x), - member_base (x), - member_database_type_id_ (base::type_override_, - base::fq_type_override_, - base::key_prefix_) - { - } - - virtual bool - pre (member_info& mi) - { - if (container (mi)) - return false; - - if (!member_override_.empty ()) - member = member_override_; - else - { - string const& name (mi.m.name ()); - member = "o." + name; - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - - os << "// " << name << endl - << "//" << endl; - } - - // If this is a wrapped composite value, then we need to - // "unwrap" it. For simple values this is taken care of - // by the value_traits specializations. - // - if (mi.wrapper != 0 && composite (mi.t)) - { - // Here we need the wrapper type, not the wrapped type. - // - member = "wrapper_traits< " + mi.fq_type (false) + " >::" + - "set_ref (\n" + member + ")"; - } - - if (composite (mi.t)) - traits = "composite_value_traits< " + mi.fq_type () + " >"; - else - { - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (semantics::class_* c = object_pointer (mt)) - { - type = "obj_traits::id_type"; - db_type_id = member_database_type_id_.database_type_id (mi.m); - - // Handle NULL pointers and extract the id. - // - os << "{" - << "typedef object_traits< " << class_fq_name (*c) << - " > obj_traits;" - << "typedef pointer_traits< " << mi.fq_type () << - " > ptr_traits;" - << endl - << "if (i." << mi.var << "null)" << endl; - - if (null (mi.m, key_prefix_)) - os << member << " = ptr_traits::pointer_type ();"; - else - os << "throw null_pointer ();"; - - os << "else" - << "{" - << type << " id;"; - - member = "id"; - } - else - { - type = mi.fq_type (); - db_type_id = member_database_type_id_.database_type_id (mi.m); - } - - traits = "sqlite::value_traits<\n " - + type + ",\n " - + db_type_id + " >"; - } - - return true; - } - - virtual void - post (member_info& mi) + : member_base::base (x), // virtual base + member_base::base_impl (x), // virtual base + base_impl (x), + member_base (x) { - if (composite (mi.t)) - return; - - // When handling a pointer, mi.t is the id type of the referenced - // object. - // - semantics::type& mt (member_utype (mi.m, key_prefix_)); - - if (object_pointer (mt)) - { - if (!member_override_.empty ()) - member = member_override_; - else - { - member = "o." + mi.m.name (); - - if (mi.cq) - member = "const_cast< " + mi.fq_type (false) + "& > (" + - member + ")"; - } - - if (lazy_pointer (mt)) - os << member << " = ptr_traits::pointer_type (db, id);"; - else - os << "// If a compiler error points to the line below, then" << endl - << "// it most likely means that a pointer used in a member" << endl - << "// cannot be initialized from an object pointer." << endl - << "//" << endl - << member << " = ptr_traits::pointer_type (" << endl - << "db.load< obj_traits::object_type > (id));"; - - os << "}" - << "}"; - } } virtual void - traverse_composite (member_info& mi) + get_null (member_info& mi) { - os << traits << "::init (" << endl - << member << "," << endl - << "i." << mi.var << "value," << endl - << "db);" - << endl; + os << "i." << mi.var << "null"; } virtual void @@ -655,14 +372,6 @@ namespace relational << "i." << mi.var << "null);" << endl; } - - private: - string type; - string db_type_id; - string traits; - string member; - - member_database_type_id member_database_type_id_; }; entry init_value_member_; @@ -680,7 +389,6 @@ namespace relational }; entry container_traits_; - struct class_: relational::class_, context { class_ (base const& x): base (x) {} -- cgit v1.1