From 587db8c7ca28d5cd1722307073aa31aed5b89d0a Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 22 Apr 2011 14:07:32 +0200 Subject: Initial support for non-polymorphic inheritance Every class gets a separate table. New test: common/inheritance. --- odb/common.cxx | 46 ++++++++--- odb/common.hxx | 20 +++-- odb/context.cxx | 49 ----------- odb/context.hxx | 15 +++- odb/relational/common.cxx | 53 ++++++++++-- odb/relational/common.hxx | 6 +- odb/relational/header.hxx | 138 ++++++++++++++++++++++++------- odb/relational/inline.hxx | 54 +++++++++++- odb/relational/mysql/source.cxx | 4 +- odb/relational/source.hxx | 176 ++++++++++++++++++++++++---------------- odb/validator.cxx | 160 ++++++++++++++++++++++++++---------- 11 files changed, 496 insertions(+), 225 deletions(-) (limited to 'odb') diff --git a/odb/common.cxx b/odb/common.cxx index f82d3d9..bf163d4 100644 --- a/odb/common.cxx +++ b/odb/common.cxx @@ -53,15 +53,26 @@ traverse (semantics::class_& c) if (obj && build_table_prefix_) { - table_prefix_.prefix = table_name (c); - table_prefix_.prefix += '_'; - table_prefix_.level = 1; + // Don't reset the table prefix if we are traversing a base. + // + bool tb (false); + + if (table_prefix_.level == 0) + { + table_prefix_.prefix = table_name (c); + table_prefix_.prefix += '_'; + table_prefix_.level = 1; + tb = true; + } inherits (c); names (c); - table_prefix_.level = 0; - table_prefix_.prefix.clear (); + if (tb) + { + table_prefix_.level = 0; + table_prefix_.prefix.clear (); + } } else { @@ -154,7 +165,14 @@ flush () } void object_columns_base:: -composite (semantics::data_member&, semantics::class_& c) +composite (semantics::data_member*, semantics::class_& c) +{ + inherits (c); + names (c); +} + +void object_columns_base:: +object (semantics::class_& c) { inherits (c); names (c); @@ -182,7 +200,7 @@ traverse_composite (semantics::data_member& m, member_.prefix_ += '_'; } - composite (m, c); + composite (&m, c); if (!member_.first_) flush (); @@ -206,15 +224,17 @@ traverse (semantics::class_& c) semantics::class_* prev; if (obj) { - prev = object; - object = &c; + prev = context::object; + context::object = &c; } - inherits (c); - names (c); + if (obj) + object (c); + else + composite (0, c); if (obj) - object = prev; + context::object = prev; if (f && !member_.first_) flush (); @@ -248,7 +268,7 @@ traverse (semantics::data_member& m) prefix_ += '_'; } - oc_.composite (m, *comp); + oc_.composite (&m, *comp); prefix_ = old_prefix; } diff --git a/odb/common.hxx b/odb/common.hxx index f0c2d5a..2d220b8 100644 --- a/odb/common.hxx +++ b/odb/common.hxx @@ -93,7 +93,8 @@ private: traversal::inherits inherits_; }; -// Traverse object columns recursively by going into composite members. +// Traverse object columns recursively by going into composite members +// and bases. // struct object_columns_base: traversal::class_, virtual context { @@ -103,12 +104,20 @@ struct object_columns_base: traversal::class_, virtual context virtual bool column (semantics::data_member&, std::string const& name, bool first) = 0; - // If you override this function, always call the base. The second argument - // is the actual composite type, which is not necessarily the same as - // m.type (). + // If you override this function, you can call the base to traverse + // bases and members. The first argument is the data member and can + // be NULL if we are traversing the root type or a base. The second + // argument is the actual composite type, which is not necessarily + // the same as m.type (). // virtual void - composite (semantics::data_member&, semantics::class_&); + composite (semantics::data_member*, semantics::class_&); + + // If you override this function, you can call the base to traverse + // bases and members. + // + virtual void + object (semantics::class_&); // Called after the last column, provided at least one column hasn't // been ignored. @@ -139,7 +148,6 @@ public: semantics::class_&, std::string const& key_prefix, std::string const& default_name); - private: void init () diff --git a/odb/context.cxx b/odb/context.cxx index 31f0865..2d64885 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -629,55 +629,6 @@ out_column_count (semantics::class_& c) namespace { - // Find id member. - // - struct id_member_impl: traversal::class_ - { - id_member_impl () - { - *this >> names_ >> member_; - } - - virtual void - traverse (semantics::class_& c) - { - member_.m_ = 0; - names (c); - c.set ("id-member", member_.m_); - } - - private: - struct member: traversal::data_member - { - virtual void - traverse (semantics::data_member& m) - { - if (m.count ("id")) - m_ = &m; - } - - semantics::data_member* m_; - }; - - member member_; - traversal::names names_; - }; -} - -semantics::data_member& context:: -id_member (semantics::class_& c) -{ - if (!c.count ("id-member")) - { - id_member_impl t; - t.traverse (c); - } - - return *c.get ("id-member"); -} - -namespace -{ struct has_a_impl: object_members_base { has_a_impl (unsigned short flags) diff --git a/odb/context.hxx b/odb/context.hxx index f08878d..a09d040 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -102,6 +102,12 @@ public: return t.get ("element-type", 0); } + static bool + abstract (semantics::class_& c) + { + return c.count ("abstract"); + } + // Database names and types. // public: @@ -112,7 +118,7 @@ public: // struct table_prefix { - table_prefix () {} + table_prefix (): level (0) {} table_prefix (string const& p, size_t l): prefix (p), level (l) {} string prefix; @@ -174,7 +180,12 @@ public: out_column_count (semantics::class_&); static semantics::data_member& - id_member (semantics::class_&); + id_member (semantics::class_& c) + { + // Set by the validator. + // + return *c.get ("id-member"); + } // Object pointer information. // diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx index 3e6461b..6032548 100644 --- a/odb/relational/common.cxx +++ b/odb/relational/common.cxx @@ -25,17 +25,37 @@ namespace relational } query_columns:: - query_columns (semantics::class_& cl) //@@ context::object + query_columns (semantics::class_& c) //@@ context::object : ptr_ (true), decl_ (false) { - scope_ = "access::object_traits< " + cl.fq_name () + " >::query_type"; - table_ = table_qname (cl); + scope_ = "access::object_traits< " + c.fq_name () + " >::query_columns"; + table_ = table_qname (c); } void query_columns:: - composite (semantics::data_member& m, semantics::class_& c) + object (semantics::class_& c) { - string name (public_name (m)); + // We only want members for objects unless we are traversing a + // pointer, in which case we need the whole thing. + // + if (!ptr_) + inherits (c); + + names (c); + } + + void query_columns:: + composite (semantics::data_member* m, semantics::class_& c) + { + // Base type. + // + if (m == 0) + { + object_columns_base::composite (m, c); + return; + } + + string name (public_name (*m)); if (decl_) { @@ -73,6 +93,16 @@ namespace relational // in queries). So we will have to duplicate the columns (sans // the pointers). // + // There are a number of problems with this approach: Regarding (1), + // the class have to be defined during ODB compilation in which + // case the ODB compiler will hunt down the #include statement + // and add it to the generated code. Regarding (2), things get + // complicated really quickly once we bring inheritance into + // the picture (name conflicts, etc). Plus, it is nice to reuse + // things. So the long-term solution is probably to make it a + // template with the table name as an argument. + // + if (ptr_) { ptr_ = false; @@ -123,7 +153,18 @@ namespace relational } else { - string column (table_ + '.' + quote_id (col_name)); + // Use the default table alias unless we are generating members + // for a referenced object. + // + string column; + + if (!ptr_) + column = table_; + else + column = "_"; + + column += '.'; + column += quote_id (col_name); os << "const " << db << "::query_column<" << endl << " " << type << "," << endl diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx index c7c1c44..6d8ef1a 100644 --- a/odb/relational/common.hxx +++ b/odb/relational/common.hxx @@ -68,12 +68,14 @@ namespace relational } virtual void - composite (semantics::data_member&, semantics::class_&); + object (semantics::class_&); + + virtual void + composite (semantics::data_member*, semantics::class_&); virtual bool column (semantics::data_member&, string const&, bool); - protected: bool ptr_; bool decl_; diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 662e3cb..c0661fb 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -13,6 +13,10 @@ namespace relational { namespace header { + // + // image_type + // + struct image_member: virtual member_base { typedef image_member base; @@ -40,9 +44,11 @@ namespace relational virtual void traverse (type& c) { + bool obj (c.count ("object")); + // Ignore transient bases. // - if (!(c.count ("object") || comp_value (c))) + if (!(obj || comp_value (c))) return; if (first_) @@ -56,7 +62,10 @@ namespace relational << " "; } - os << "composite_value_traits< " << c.fq_name () << " >::image_type"; + if (obj) + os << "object_traits< " << c.fq_name () << " >::image_type"; + else + os << "composite_value_traits< " << c.fq_name () << " >::image_type"; } private: @@ -104,6 +113,68 @@ namespace relational traversal::names names_member_; }; + // + // query_type + // + + struct query_base: traversal::class_, virtual context + { + typedef query_base base; + + query_base (): first_ (true) {} + + virtual void + traverse (type& c) + { + // Ignore transient bases. + // + if (!c.count ("object")) + return; + + if (first_) + { + os << ": "; + first_ = false; + } + else + { + os << "," << endl + << " "; + } + + os << "object_traits< " << c.fq_name () << " >::query_columns"; + } + + private: + bool first_; + }; + + struct query_type: traversal::class_, virtual context + { + typedef query_type base; + + virtual void + traverse (type& c) + { + os << "struct query_columns"; + + { + instance b; + traversal::inherits i (*b); + inherits (c, i); + } + + os << "{"; + + { + instance t; + t->traverse (c); + } + + os << "};"; + } + }; + // Member-specific traits types for container members. // struct container_traits: object_members_base, virtual context @@ -611,6 +682,7 @@ namespace relational semantics::data_member& id (id_member (c)); bool auto_id (id.count ("auto")); + bool base_id (&id.scope () != &c); // Id comes from a base class. os << "// " << c.name () << endl << "//" << endl; @@ -625,30 +697,45 @@ namespace relational os << "typedef " << type << " object_type;" << "typedef " << c.get ("object-pointer") << " pointer_type;"; - // id_type + // id_type & id_image_type // - os << "typedef " << id.type ().fq_name (id.belongs ().hint ()) << - " id_type;" - << endl; + if (base_id) + { + string const& base (id.scope ().fq_name ()); - // image_type - // - image_type_->traverse (c); + os << "typedef object_traits< " << base << " >::id_type id_type;" + << endl + << "typedef object_traits< " << base << " >::id_image_type " << + "id_image_type;" + << endl; + } + else + { + os << "typedef " << id.type ().fq_name (id.belongs ().hint ()) << + " id_type;" + << endl; - // id_image_type - // - os << "struct id_image_type" - << "{"; + os << "struct id_image_type" + << "{"; - id_image_member_->traverse (id); + id_image_member_->traverse (id); - os << "std::size_t version;" - << "};"; + os << "std::size_t version;" + << "};"; + } + + // image_type + // + image_type_->traverse (c); - // query_type & query_base_type + // query types // if (options.generate_query ()) { + // query_columns + // + query_type_->traverse (c); + // query_base_type // os << "typedef " << db << "::query query_base_type;" @@ -656,15 +743,9 @@ namespace relational // query_type // - os << "struct query_type: query_base_type" - << "{"; - - { - instance t; - t->traverse (c); - } - - os << "query_type ();" + os << "struct query_type: query_base_type, query_columns" + << "{" + << "query_type ();" << "query_type (const std::string&);" << "query_type (const query_base_type&);" << "};"; @@ -723,7 +804,7 @@ namespace relational // grow () // - os << "static void" << endl + os << "static bool" << endl << "grow (image_type&, " << truncated_vector << ");" << endl; @@ -741,7 +822,7 @@ namespace relational // init (image, object) // - os << "static void" << endl + os << "static bool" << endl << "init (image_type&, const object_type&);" << endl; @@ -886,6 +967,7 @@ namespace relational private: instance image_type_; + instance query_type_; instance id_image_member_; }; diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx index 1b3c492..9e76dea 100644 --- a/odb/relational/inline.hxx +++ b/odb/relational/inline.hxx @@ -34,7 +34,9 @@ namespace relational { string const& type (c.fq_name ()); string traits ("access::object_traits< " + type + " >"); + semantics::data_member& id (id_member (c)); + bool base_id (&id.scope () != &c); // Id comes from a base class. os << "// " << c.name () << endl << "//" << endl @@ -65,15 +67,59 @@ namespace relational << "}"; } - // id () + // id (object_type) // os << "inline" << endl << traits << "::id_type" << endl << traits << "::" << endl << "id (const object_type& obj)" - << "{" - << "return obj." << id.name () << ";" << endl - << "}"; + << "{"; + + if (base_id) + os << "return object_traits< " << id.scope ().fq_name () << + " >::id (obj);"; + else + os << "return obj." << id.name () << ";"; + + os << "}"; + + // id (image_type) + // + if (options.generate_query () && base_id) + { + os << "inline" << endl + << traits << "::id_type" << endl + << traits << "::" << endl + << "id (const image_type& i)" + << "{" + << "return object_traits< " << id.scope ().fq_name () << + " >::id (i);" + << "}"; + } + + // bind (id_image_type) + // + if (base_id) + { + os << "inline" << endl + << "void " << traits << "::" << endl + << "bind (" << bind_vector << " b, id_image_type& i)" + << "{" + << "object_traits< " << id.scope ().fq_name () << + " >::bind (b, i);" + << "}"; + } + + if (base_id) + { + os << "inline" << endl + << "void " << traits << "::" << endl + << "init (id_image_type& i, const id_type& id)" + << "{" + << "object_traits< " << id.scope ().fq_name () << + " >::init (i, id);" + << "}"; + } // load_() // diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx index 825a67e..17bffdc 100644 --- a/odb/relational/mysql/source.cxx +++ b/odb/relational/mysql/source.cxx @@ -122,7 +122,7 @@ namespace relational if (!table.empty ()) { - line_ += table; + line_ += table == table_name_ ? "_" : table; line_ += '.'; } @@ -131,7 +131,7 @@ namespace relational if (!table.empty ()) { - line_ += table; + line_ += table == table_name_ ? "_" : table; line_ += '.'; } diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 44c4959..f3d9db9 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -132,7 +132,9 @@ namespace relational { if (!table.empty ()) { - line_ += table; + // Use alias for the main table. + // + line_ += table == table_name_ ? "_" : table; line_ += '.'; } @@ -155,9 +157,9 @@ namespace relational bool out_; string suffix_; string line_; + string table_name_; private: - string table_name_; bool last_; }; @@ -228,8 +230,7 @@ namespace relational t = table_qname (*im, tp); string const& val (column_qname (*im, "value", "value")); - cond << t << '.' << val << " = " << table_ << '.' << - column_qname (id_); + cond << t << '.' << val << " = _." << column_qname (id_); // Add the join for the object itself so that we are able to // use it in the WHERE clause. @@ -247,8 +248,8 @@ namespace relational { t = table_qname (*c); - cond << t << '.' << column_qname (*im) << " = " << - table_ << '.' << column_qname (id_); + cond << t << '.' << column_qname (*im) << " = _." << + column_qname (id_); } } else if (query_) @@ -258,8 +259,8 @@ namespace relational // t = table_qname (*c); - cond << t << '.' << column_qname (id_member (*c)) << " = " << - table_ << '.' << quote_id (col_name); + cond << t << '.' << column_qname (id_member (*c)) << " = _." << + quote_id (col_name); } if (!t.empty ()) @@ -311,7 +312,7 @@ namespace relational private: bool query_; - string table_; + string table_; //@@ No longer used because of the _ alias. semantics::data_member& id_; typedef std::set conditions; @@ -372,16 +373,24 @@ namespace relational virtual void traverse (type& c) { + bool obj (c.count ("object")); + // Ignore transient bases. // - if (!(c.count ("object") || comp_value (c))) + if (!(obj || comp_value (c))) return; os << "// " << c.name () << " base" << endl - << "//" << endl - << "composite_value_traits< " << c.fq_name () << - " >::bind (b + n, i);" - << "n += " << in_column_count (c) << "UL;" + << "//" << endl; + + if (obj) + os << "object_traits< " << c.fq_name () << + " >::bind (b + n, i, out);"; + else + os << "composite_value_traits< " << c.fq_name () << + " >::bind (b + n, i);"; + + os << "n += " << in_column_count (c) << "UL;" << endl; } }; @@ -421,18 +430,20 @@ namespace relational virtual void traverse (type& c) { + bool obj (c.count ("object")); + // Ignore transient bases. // - if (!(c.count ("object") || comp_value (c))) + if (!(obj || comp_value (c))) return; os << "// " << c.name () << " base" << endl - << "//" << endl - << "if (composite_value_traits< " << c.fq_name () << - " >::grow (i, t + " << index_ << "UL))" - << "{" + << "//" << endl; + + os << "if (" << (obj ? "object" : "composite_value") << "_traits< " << + c.fq_name () << " >::grow (i, t + " << index_ << "UL))" << endl << "grew = true;" - << "}"; + << endl; index_ += in_column_count (c); } @@ -477,18 +488,19 @@ namespace relational virtual void traverse (type& c) { + bool obj (c.count ("object")); + // Ignore transient bases. // - if (!(c.count ("object") || comp_value (c))) + if (!(obj || comp_value (c))) return; os << "// " << c.name () << " base" << endl << "//" << endl - << "if (composite_value_traits< " << c.fq_name () << - " >::init (i, o))" - << "{" + << "if (" << (obj ? "object" : "composite_value") << "_traits< " << + c.fq_name () << " >::init (i, o))" << endl << "grew = true;" - << "}"; + << endl; } }; @@ -527,15 +539,17 @@ namespace relational virtual void traverse (type& c) { + bool obj (c.count ("object")); + // Ignore transient bases. // - if (!(c.count ("object") || comp_value (c))) + if (!(obj || comp_value (c))) return; os << "// " << c.name () << " base" << endl << "//" << endl - << "composite_value_traits< " << c.fq_name () << - " >::init (o, i, db);" + << (obj ? "object" : "composite_value") << "_traits< " << + c.fq_name () << " >::init (o, i, db);" << endl; } }; @@ -660,17 +674,17 @@ namespace relational } os << strlit ("SELECT ") << endl - << strlit (inv_table + '.' + inv_fid + ',') << endl - << strlit (inv_table + '.' + inv_id) << endl - << strlit (" FROM " + inv_table + - " WHERE " + inv_table + '.' + inv_fid + " = ?"); + << strlit ("_." + inv_fid + ',') << endl + << strlit ("_." + inv_id) << endl + << strlit (" FROM " + inv_table + " AS _" + " WHERE _." + inv_fid + " = ?"); } else { string const& id_col (column_qname (m, "id", "object_id")); os << strlit ("SELECT ") << endl - << strlit (table + '.' + id_col + ',') << endl; + << strlit ("_." + id_col + ',') << endl; switch (ck) { @@ -718,13 +732,15 @@ namespace relational t->flush (); } - os << strlit (" FROM " + table + - " WHERE " + table + '.' + id_col + " = ?") << endl; + os << strlit (" FROM " + table + " AS _" + " WHERE _." + id_col + " = ?"); if (ordered) { string const& col (column_qname (m, "index", "index")); - os << strlit (" ORDER BY " + table + '.' + col) << endl; + + os << endl + << strlit (" ORDER BY _." + col) << endl; } } @@ -1747,6 +1763,7 @@ namespace relational semantics::data_member& id (id_member (c)); bool auto_id (id.count ("auto")); bool grow_id (context::grow (id)); + bool base_id (&id.scope () != &c); // Id comes from a base class. os << "// " << c.name () << endl << "//" << endl @@ -1825,7 +1842,7 @@ namespace relational t->traverse (c); } - os << strlit (" FROM " + table) << endl; + os << strlit (" FROM " + table + " AS _") << endl; { bool f (false); @@ -1834,7 +1851,7 @@ namespace relational t->write (); } - os << strlit (" WHERE " + table + '.' + id_col + " = ?") << ";" + os << strlit (" WHERE _." + id_col + " = ?") << ";" << endl; // update_statement @@ -1847,14 +1864,14 @@ namespace relational t->traverse (c); } - os << strlit (" WHERE " + table + '.' + id_col + " = ?") << ";" + os << strlit (" WHERE " + id_col + " = ?") << ";" << endl; // erase_statement // os << "const char* const " << traits << "::erase_statement =" << endl << strlit ("DELETE FROM " + table) << endl - << strlit (" WHERE " + table + '.' + id_col + " = ?") << ";" + << strlit (" WHERE " + id_col + " = ?") << ";" << endl; // query_clause @@ -1876,15 +1893,15 @@ namespace relational oc->traverse (c); } - os << strlit (" FROM " + table) << endl; + os << strlit (" FROM " + table + " AS _") << endl; oj->write (); os << strlit (" ") << ";" << endl; } - // id + // id (image_type) // - if (options.generate_query ()) + if (options.generate_query () && !base_id) { os << traits << "::id_type" << endl << traits << "::" << endl @@ -1898,9 +1915,12 @@ namespace relational // grow () // - os << "void " << traits << "::" << endl + os << "bool " << traits << "::" << endl << "grow (image_type& i, " << truncated_vector << " t)" << "{" + << "ODB_POTENTIALLY_UNUSED (i);" + << "ODB_POTENTIALLY_UNUSED (t);" + << endl << "bool grew (false);" << endl; @@ -1908,8 +1928,7 @@ namespace relational inherits (c, grow_base_inherits_); names (c, grow_member_names_); - os << "if (grew)" << endl - << "i.version++;" << endl + os << "return grew;" << "}"; // bind (image_type) @@ -1929,26 +1948,31 @@ namespace relational // bind (id_image_type) // - os << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b, id_image_type& i)" - << "{" - << "std::size_t n (0);"; - bind_id_member_->traverse (id); - os << "}"; + if (!base_id) + { + os << "void " << traits << "::" << endl + << "bind (" << bind_vector << " b, id_image_type& i)" + << "{" + << "std::size_t n (0);"; + bind_id_member_->traverse (id); + os << "}"; + } // init (image, object) // - os << "void " << traits << "::" << endl + os << "bool " << traits << "::" << endl << "init (image_type& i, const object_type& o)" << "{" + << "ODB_POTENTIALLY_UNUSED (i);" + << "ODB_POTENTIALLY_UNUSED (o);" + << endl << "bool grew (false);" << endl; inherits (c, init_image_base_inherits_); names (c, init_image_member_names_); - os << "if (grew)" << endl - << "i.version++;" << endl + os << "return grew;" << "}"; // init (object, image) @@ -1956,6 +1980,8 @@ namespace relational os << "void " << traits << "::" << endl << "init (object_type& o, const image_type& i, database& db)" << "{" + << "ODB_POTENTIALLY_UNUSED (o);" + << "ODB_POTENTIALLY_UNUSED (i);" << "ODB_POTENTIALLY_UNUSED (db);" << endl; @@ -1966,21 +1992,24 @@ namespace relational // init (id_image, id) // - os << "void " << traits << "::" << endl - << "init (id_image_type& i, const id_type& id)" - << "{"; + if (!base_id) + { + os << "void " << traits << "::" << endl + << "init (id_image_type& i, const id_type& id)" + << "{"; - if (grow_id) - os << "bool grew (false);"; + if (grow_id) + os << "bool grew (false);"; - init_id_image_member_->traverse (id); + init_id_image_member_->traverse (id); - if (grow_id) - os << endl - << "if (grew)" << endl - << "i.version++;"; + if (grow_id) + os << endl + << "if (grew)" << endl + << "i.version++;"; - os << "}"; + os << "}"; + } // persist () // @@ -1997,17 +2026,19 @@ namespace relational << "image_type& im (sts.image ());" << "binding& imb (sts.in_image_binding ());" << endl - << "init (im, obj);"; + << "if (init (im, obj))" << endl + << "im.version++;" + << endl; if (auto_id) { string const& n (id.name ()); string var ("im." + n + (n[n.size () - 1] == '_' ? "" : "_")); init_auto_id (id, var); + os << endl; } - os << endl - << "if (im.version != sts.in_image_version () || imb.version == 0)" + os << "if (im.version != sts.in_image_version () || imb.version == 0)" << "{" << "bind (imb.bind, im, false);" << "sts.in_image_version (im.version);" @@ -2067,7 +2098,9 @@ namespace relational // os << "image_type& im (sts.image ());" << "binding& imb (sts.in_image_binding ());" - << "init (im, obj);" + << endl + << "if (init (im, obj))" << endl + << "im.version++;" << endl << "if (im.version != sts.in_image_version () || imb.version == 0)" << "{" @@ -2245,7 +2278,8 @@ namespace relational os << endl << "if (r == select_statement::truncated)" << "{" - << "grow (im, sts.out_image_truncated ());" + << "if (grow (im, sts.out_image_truncated ()))" << endl + << "im.version++;" << endl << "if (im.version != sts.out_image_version ())" << "{" diff --git a/odb/validator.cxx b/odb/validator.cxx index 6c62ea8..998bd8b 100644 --- a/odb/validator.cxx +++ b/odb/validator.cxx @@ -40,29 +40,83 @@ namespace valid_ = false; } + } + + bool& valid_; + size_t count_; + }; - if (m.count ("id")) + // Find id member. + // + struct id_member: traversal::class_ + { + id_member (bool object, bool& valid, semantics::data_member*& m) + : object_ (object), member_ (valid, m) + { + *this >> inherits_ >> *this; + *this >> names_ >> member_; + } + + virtual void + traverse (semantics::class_& c) + { + // Skip transient bases. + // + if (object_) { - if (id_ != 0) - { - cerr << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " error: multiple object id members" << endl; + if (!c.count ("object")) + return; + } + else + { + if (!context::comp_value (c)) + return; + } - cerr << id_->file () << ":" << id_->line () << ":" << id_->column () - << ": info: previous id member declared here" << endl; + inherits (c); + names (c); + } - valid_ = false; - } + private: + struct member: traversal::data_member + { + member (bool& valid, semantics::data_member*& m) + : valid_ (valid), m_ (m) + { + } - id_ = &m; + virtual void + traverse (semantics::data_member& m) + { + if (m.count ("id")) + { + if (m_ != 0) + { + cerr << m.file () << ":" << m.line () << ":" << m.column () << ":" + << " error: multiple object id members" << endl; + + cerr << m_->file () << ":" << m_->line () << ":" << m_->column () + << ": info: previous id member declared here" << endl; + + valid_ = false; + } + else + m_ = &m; + } } - } - bool& valid_; - size_t count_; - semantics::data_member* id_; + bool& valid_; + semantics::data_member*& m_; + }; + + bool object_; + member member_; + traversal::names names_; + traversal::inherits inherits_; }; + // + // struct class_: traversal::class_ { class_ (bool& valid, semantics::unit& unit) @@ -84,6 +138,8 @@ namespace virtual void traverse_object (type& c) { + bool base (false); + for (type::inherits_iterator i (c.inherits_begin ()); i != c.inherits_end (); ++i) @@ -91,13 +147,8 @@ namespace type& b (i->base ()); if (b.count ("object")) - { - cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: object inheritance is not yet supported" << endl; - - valid_ = false; - } - else if (context::comp_value (b)) + base = true; + if (context::comp_value (b)) { // @@ Should we use hint here? // @@ -117,24 +168,37 @@ namespace } } - member_.count_ = 0; - member_.id_ = 0; - - names (c); + // Check id. + // + semantics::data_member* id (0); + { + id_member t (true, valid_, id); + t.traverse (c); + } - if (member_.id_ == 0) + if (id == 0) { - cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: no data member designated as object id" << endl; + if (!context::abstract (c)) + { + cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" + << " error: no data member designated as object id" << endl; - cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " info: use '#pragma db id' to specify object id member" - << endl; + cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" + << " info: use '#pragma db id' to specify object id member" + << endl; - valid_ = false; + valid_ = false; + } } + else + c.set ("id-member", id); + + // Check members. + // + member_.count_ = 0; + names (c); - if (member_.count_ == 0) + if (member_.count_ == 0 && !base) { cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" << " error: no persistent data members in the class" << endl; @@ -146,13 +210,17 @@ namespace virtual void traverse_value (type& c) { + bool base (false); + for (type::inherits_iterator i (c.inherits_begin ()); i != c.inherits_end (); ++i) { type& b (i->base ()); - if (b.count ("object")) + if (context::comp_value (b)) + base = true; + else if (b.count ("object")) { // @@ Should we use hint here? // @@ -173,21 +241,29 @@ namespace } } - member_.count_ = 0; - member_.id_ = 0; - - names (c); + // Check id. + // + semantics::data_member* id (0); + { + id_member t (false, valid_, id); + t.traverse (c); + } - if (member_.id_ != 0) + if (id != 0) { - cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: value type data member cannot be designated as " + cerr << id->file () << ":" << id->line () << ":" << id->column () + << ": error: value type data member cannot be designated as " << "object id" << endl; valid_ = false; } - if (member_.count_ == 0) + // Check members. + // + member_.count_ = 0; + names (c); + + if (member_.count_ == 0 && !base) { cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" << " error: no persistent data members in the class" << endl; -- cgit v1.1