From 6b2dc5fbc2c2ea8760ef6b09178c4f50b2b38879 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 1 Apr 2013 17:16:49 +0200 Subject: Handle inverse member in base class of polymorphic hierarchy --- odb/relational/source.cxx | 29 +++++++----- odb/relational/source.hxx | 117 +++++++++++++++++++++++++++++++--------------- 2 files changed, 97 insertions(+), 49 deletions(-) diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 22d2644..210d04b 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -581,10 +581,11 @@ traverse_object (type& c) os << strlit (" FROM " + qtable) << endl; - if (poly_derived) + if (d != 1) { - instance j (c, d); - j->traverse (c); + size_t d1 (d - 1); //@@ (im)perfect forward. + instance j (c, d1); + j->traverse (polymorphic_base (c)); } bool f (false); // @@ (im)perfect forwarding @@ -809,10 +810,11 @@ traverse_object (type& c) os << strlit (" FROM " + qtable) << endl; - if (poly_derived) + if (poly_depth != 1) { - instance j (c, poly_depth); - j->traverse (c); + size_t d (poly_depth - 1); //@@ (im)perfect forward. + instance j (c, d); + j->traverse (polymorphic_base (c)); } if (id != 0) @@ -3240,9 +3242,10 @@ traverse_view (type& c) if (poly_depth != 1) { + size_t d (poly_depth - 1); //@@ (im)perfect forward. instance j ( - o, poly_depth, i->alias, "r += ", ";"); - j->traverse (o); + o, d, i->alias, "r += ", ";"); + j->traverse (polymorphic_base (o)); } os << endl; @@ -3277,9 +3280,10 @@ traverse_view (type& c) if (poly_depth != 1) { + size_t d (poly_depth - 1); //@@ (im)perfect forward. instance j ( - o, poly_depth, i->alias, "r += ", ";"); - j->traverse (o); + o, d, i->alias, "r += ", ";"); + j->traverse (polymorphic_base (o)); } os << endl; @@ -3653,9 +3657,10 @@ traverse_view (type& c) if (poly_depth != 1) { + size_t d (poly_depth - 1); //@@ (im)perfect forward. instance j ( - o, poly_depth, i->alias, "r += ", ";"); - j->traverse (o); + o, d, i->alias, "r += ", ";"); + j->traverse (polymorphic_base (o)); } os << endl; diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index cba18c5..0b50788 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -142,7 +142,15 @@ namespace relational // if (im != 0) { - semantics::data_member& id (*id_member (c)); + bool poly (polymorphic (c) != 0); + + // In a polymorphic hierarchy the inverse member can be in + // the base class, in which case we should use that table. + // + semantics::class_& imc ( + poly ? dynamic_cast (im->scope ()) : c); + + semantics::data_member& id (*id_member (imc)); semantics::type& idt (utype (id)); if (container (*im)) @@ -158,10 +166,10 @@ namespace relational string table; if (!table_name_.empty ()) - table = table_qname (*im, table_prefix (c)); + table = table_qname (*im, table_prefix (imc)); instance oc (table, sk_, sc_); - oc->traverse (*im, idt, "id", "object_id", &c); + oc->traverse (*im, idt, "id", "object_id", &imc); } else { @@ -177,7 +185,7 @@ namespace relational // it is not; if table_name_ is empty then we are generating a // container table where we don't qualify columns with tables. // - string table; + string alias; if (!table_name_.empty ()) { @@ -198,10 +206,18 @@ namespace relational n = column_name (m, key_prefix_, default_name_, dummy); } - table = quote_id (compose_name (column_prefix_.prefix, n)); + alias = compose_name (column_prefix_.prefix, n); + + if (poly) + { + qname const& table (table_name (imc)); + alias = quote_id (alias + "_" + table.uname ()); + } + else + alias = quote_id (alias); } - instance oc (table, sk_, sc_); + instance oc (alias, sk_, sc_); oc->traverse (id); } } @@ -465,27 +481,18 @@ namespace relational prefix_ (prefix), suffix_ (suffix) { + // Get the table and id columns. + // + table_ = alias_.empty () + ? table_qname (obj) + : quote_id (alias_ + "_" + table_name (obj).uname ()); + + cols_->traverse (*id_member (obj)); } virtual void traverse_object (semantics::class_& c) { - if (&c == &obj_) - { - // Get the table and id columns. - // - table_ = alias_.empty () - ? table_qname (c) - : quote_id (alias_ + "_" + table_name (c).uname ()); - - cols_->traverse (*id_member (c)); - - if (--depth_ != 0) - inherits (c); - return; - } - - semantics::class_* poly_root (); std::ostringstream cond; qname table (table_name (c)); @@ -513,7 +520,7 @@ namespace relational os << prefix_ << strlit (line) << suffix_; - if (&c != polymorphic (c) && --depth_ != 0) + if (--depth_ != 0) inherits (c); } @@ -610,18 +617,23 @@ namespace relational semantics::class_* poly_root (polymorphic (c)); bool poly (poly_root != 0); - bool poly_derived (poly && poly_root != &c); - bool obj_joined (false); + semantics::class_* joined_obj (0); if (semantics::data_member* im = inverse (m, key_prefix_)) { + // In a polymorphic hierarchy the inverse member can be in + // the base class, in which case we should use that table. + // + semantics::class_& imc ( + poly ? dynamic_cast (im->scope ()) : c); + if (container (*im)) { // This container is a direct member of the class so the table // prefix is just the class table name. // - t = table_qname (*im, table_prefix (c)); + t = table_qname (*im, table_prefix (imc)); // Container's value is our id. // @@ -644,6 +656,9 @@ namespace relational // if (query_) { + // Here we can use the most derived class instead of the + // one containing the inverse member. + // qname const& table (table_name (c)); dt = quote_id (table); @@ -666,12 +681,12 @@ namespace relational t << '.' << quote_id (i->name); } - obj_joined = true; + joined_obj = &c; } } else { - qname const& table (table_name (c)); + qname const& table (table_name (imc)); t = quote_id (table); a = quote_id (poly ? alias + "_" + table.uname () : alias); @@ -682,7 +697,6 @@ namespace relational 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 "; @@ -690,7 +704,11 @@ namespace relational table_ << '.' << quote_id (j->name); } - obj_joined = true; + // If we are generating query, JOIN base/derived classes so + // that we can use their data in the WHERE clause. + // + if (query_) + joined_obj = &imc; } } else if (query_) @@ -720,7 +738,7 @@ namespace relational table_ << '.' << quote_id (j->name); } - obj_joined = true; + joined_obj = &c; } if (!t.empty ()) @@ -754,14 +772,31 @@ namespace relational os << strlit (line) << endl; } - // If we joined the object and it is a derived type in a - // polymorphic hierarchy, then join its bases as well. + // If we joined the object that is part of a polymorphic type + // hierarchy, then we may need join its bases as well as its + // derived types. // - if (obj_joined && poly_derived) + if (joined_obj != 0 && poly) { - size_t depth (polymorphic_depth (c)); - instance t (c, depth, alias); - t->traverse (c); + size_t depth (polymorphic_depth (*joined_obj)); + + // Join "up" (derived). + // + if (joined_obj != &c) + { + size_t d (polymorphic_depth (c) - depth); //@@ (im)perfect forward. + instance t (*joined_obj, d, alias); + t->traverse (c); + } + + // Join "down" (base). + // + if (joined_obj != poly_root) + { + size_t d (depth - 1); //@@ (im)perfect forward. + instance t (*joined_obj, d, alias); + t->traverse (polymorphic_base (*joined_obj)); + } } } @@ -1958,6 +1993,14 @@ namespace relational if (inverse) { semantics::class_* c (object_pointer (vt)); + + // In a polymorphic hierarchy the inverse member can be in + // the base class, in which case we should use that class + // for the table name, etc. + // + if (polymorphic (*c)) + c = &dynamic_cast (im->scope ()); + semantics::data_member& inv_id (*id_member (*c)); qname inv_table; // Other table name. -- cgit v1.1