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/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 +++++++-------------------------------- 6 files changed, 111 insertions(+), 571 deletions(-) (limited to 'odb/relational/pgsql') 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"; -- cgit v1.1