From 80b868be1e7c249daa714b0c7a5f87694edb8664 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 3 Jul 2015 18:23:51 +0200 Subject: Implement nested id support Now the 'id' specifier can optionally include the data member path to the id inside the composite value. For example: #pragma db id(first) std::pair p; Note that one somewhat counter-intuitive aspect of this new feature is that the whole member marked with id ('p' in the above example) and not just the actual id member ('p.first' in the above example) is treated as readonly. Such nested id also cannot be automatically assigned (auto specifier). --- odb/relational/common.txx | 6 ++-- odb/relational/header.cxx | 10 +++--- odb/relational/inline.hxx | 8 ++--- odb/relational/model.hxx | 8 ++--- odb/relational/mssql/source.cxx | 14 ++++---- odb/relational/oracle/source.cxx | 6 ++-- odb/relational/pgsql/header.cxx | 2 +- odb/relational/pgsql/source.cxx | 10 +++--- odb/relational/processor.cxx | 12 +++---- odb/relational/source.cxx | 76 ++++++++++++++++++++++++++++------------ odb/relational/source.hxx | 24 ++++++------- odb/relational/validator.cxx | 16 ++++----- 12 files changed, 111 insertions(+), 81 deletions(-) (limited to 'odb/relational') diff --git a/odb/relational/common.txx b/odb/relational/common.txx index 5e5c5ac..116cfc2 100644 --- a/odb/relational/common.txx +++ b/odb/relational/common.txx @@ -36,9 +36,9 @@ namespace relational { // A pointer in view might point to an object without id. // - semantics::data_member* idm (id_member (*c)); - semantics::type& t (utype (idm != 0 ? *idm : m, &ct)); - semantics::class_* comp (idm != 0 ? composite_wrapper (t) : 0); + data_member_path* id (id_member (*c)); + semantics::type& t (id != 0 ? utype (*id, &ct) : utype (m, &ct)); + semantics::class_* comp (id != 0 ? composite_wrapper (t) : 0); member_info mi (m, (comp != 0 ? *comp : t), diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx index 4b8b193..b64ab2a 100644 --- a/odb/relational/header.cxx +++ b/odb/relational/header.cxx @@ -12,9 +12,11 @@ traverse_object (type& c) { using semantics::data_member; - data_member* id (id_member (c)); + data_member_path* id (id_member (c)); + data_member* idf (id ? id->front () : 0); + data_member* idb (id ? id->back () : 0); bool auto_id (id && auto_ (*id)); - bool base_id (id && &id->scope () != &c); // Comes from base. + bool base_id (id && &idf->scope () != &c); // Comes from base. data_member* opt (context::optimistic (c)); @@ -120,7 +122,7 @@ traverse_object (type& c) else { semantics::class_& b ( - dynamic_cast (id->scope ())); + dynamic_cast (idf->scope ())); os << "typedef object_traits_impl< " << class_fq_name (b) << ", " << "id_" << db << " >::id_image_type id_image_type;" @@ -132,7 +134,7 @@ traverse_object (type& c) os << "struct id_image_type" << "{"; - id_image_member_->traverse (*id); + id_image_member_->traverse (*idb); if (opt != 0) version_image_member_->traverse (*opt); diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx index 090779f..583cb13 100644 --- a/odb/relational/inline.hxx +++ b/odb/relational/inline.hxx @@ -214,16 +214,16 @@ namespace relational { using semantics::data_member; - data_member* id (id_member (c)); + data_member_path* id (id_member (c)); + data_member* idf (id ? id->front () : 0); bool auto_id (id && auto_ (*id)); - bool base_id (id && &id->scope () != &c); // Comes from base. + bool base_id (id && &idf->scope () != &c); // Comes from base. data_member* optimistic (context::optimistic (c)); // Base class that contains the object id and version for optimistic // concurrency. // - type* base ( - id != 0 && base_id ? dynamic_cast (&id->scope ()) : 0); + type* base (base_id ? dynamic_cast (&idf->scope ()) : 0); type* poly_root (context::polymorphic (c)); bool poly (poly_root != 0); diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx index 00b3b46..13c67d7 100644 --- a/odb/relational/model.hxx +++ b/odb/relational/model.hxx @@ -342,10 +342,10 @@ namespace relational // Get referenced columns. // { - semantics::data_member& idm (*id_member (c)); + data_member_path& id (*id_member (c)); instance ocl; - ocl->traverse (idm); + ocl->traverse (id); for (object_columns_list::iterator i (ocl->begin ()); i != ocl->end (); ++i) @@ -634,10 +634,10 @@ namespace relational // Get referenced columns. // { - data_member& idm (*id_member (*context::top_object)); + data_member_path& id (*id_member (*context::top_object)); instance ocl; - ocl->traverse (idm); + ocl->traverse (id); for (object_columns_list::iterator i (ocl->begin ()); i != ocl->end (); ++i) diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx index 89b5702..42c29a7 100644 --- a/odb/relational/mssql/source.cxx +++ b/odb/relational/mssql/source.cxx @@ -44,10 +44,9 @@ namespace relational string const& column) { // Don't add a column for auto id in the INSERT statement. + // Only simple, direct id can be auto. // - if (sk_ == statement_insert && - key_prefix_.empty () && - context::id (m) && auto_(m)) // Only simple id can be auto. + if (sk_ == statement_insert && key_prefix_.empty () && auto_ (m)) return false; // Don't update the ROWVERSION column explicitly. @@ -987,7 +986,7 @@ namespace relational // See if we have auto id or ROWVERSION version. // - semantics::data_member* id (id_member (c)); + data_member_path* id (id_member (c)); semantics::data_member* ver (optimistic (c)); if (id != 0 && !auto_ (*id)) @@ -1047,7 +1046,8 @@ namespace relational throw operation_failed (); } - r = "; SELECT " + convert_from ("SCOPE_IDENTITY()", *id); + r = "; SELECT " + + convert_from ("SCOPE_IDENTITY()", *id->back ()); } return r; @@ -1061,8 +1061,8 @@ namespace relational // Top-level auto id column. // if (id != 0) - r += "INSERTED." + convert_from ( - column_qname (*id, column_prefix ()), *id); + r += "INSERTED." + + convert_from (column_qname (*id), *id->back ()); // Top-level version column. // diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx index 310eac6..802bc99 100644 --- a/odb/relational/oracle/source.cxx +++ b/odb/relational/oracle/source.cxx @@ -604,16 +604,16 @@ namespace relational if (p == persist_after_values) { - semantics::data_member* id (id_member (c)); + data_member_path* id (id_member (c)); type* poly_root (polymorphic (c)); bool poly_derived (poly_root != 0 && poly_root != &c); // Top-level auto id. // - if (id != 0 && !poly_derived && id->count ("auto")) + if (id != 0 && !poly_derived && auto_ (*id)) r = "RETURNING " + - convert_from (column_qname (*id, column_prefix ()), *id) + + convert_from (column_qname (*id), *id->back ()) + " INTO " + qp.next (); } diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx index 19fa573..b3566d8 100644 --- a/odb/relational/pgsql/header.cxx +++ b/odb/relational/pgsql/header.cxx @@ -31,7 +31,7 @@ namespace relational if (abst && !poly) return; - semantics::data_member* id (id_member (c)); + data_member_path* id (id_member (c)); semantics::data_member* optimistic (context::optimistic (c)); column_count_type const& cc (column_count (c)); diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index 2bbe232..b8270ac 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -583,16 +583,16 @@ namespace relational if (p == persist_after_values) { - semantics::data_member* id (id_member (c)); + data_member_path* id (id_member (c)); type* poly_root (polymorphic (c)); bool poly_derived (poly_root != 0 && poly_root != &c); // Top-level auto id. // - if (id != 0 && !poly_derived && id->count ("auto")) + if (id != 0 && !poly_derived && auto_ (*id)) r = "RETURNING " + - convert_from (column_qname (*id, column_prefix ()), *id); + convert_from (column_qname (*id), *id->back ()); } return r; @@ -610,7 +610,7 @@ namespace relational if (abst && !poly) return; - semantics::data_member* id (id_member (c)); + data_member_path* id (id_member (c)); semantics::data_member* optimistic (context::optimistic (c)); column_count_type const& cc (column_count (c)); @@ -706,7 +706,7 @@ namespace relational statement_oids st (statement_insert); st.traverse (c); - // Empty array are not portable. So add a dummy member if we + // Empty array is not portable. So add a dummy member if we // are not sending anything with the insert statement. // if (cc.total == cc.inverse + cc.optimistic_managed + diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index 2979a34..48ddba4 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -27,8 +27,8 @@ namespace relational id_column_type () { context& c (context::current ()); - semantics::data_member& id (*context::id_member (*c.top_object)); - return id.get ("column-type"); + data_member_path& id (*context::id_member (*c.top_object)); + return id.back ()->get ("column-id-type"); } struct data_member: traversal::data_member, context @@ -85,7 +85,7 @@ namespace relational // This is an object pointer. The column type is the pointed-to // object id type. // - semantics::data_member& id (*id_member (*c)); + semantics::data_member& id (*id_member (*c)->back ()); semantics::names* idhint; semantics::type& idt (utype (id, idhint)); @@ -220,7 +220,7 @@ namespace relational // { semantics::class_& r (*object_pointer (t)); - semantics::data_member& id (*id_member (r)); + semantics::data_member& id (*id_member (r)->front ()); if (id.count ("column")) m.set ("column", id.get ("column")); @@ -306,7 +306,7 @@ namespace relational // This is an object pointer. The column type is the pointed-to // object id type. // - semantics::data_member& id (*id_member (*c)); + semantics::data_member& id (*id_member (*c)->back ()); semantics::names* idhint; semantics::type& idt (utype (id, idhint)); @@ -824,7 +824,7 @@ namespace relational m.set ("column-type", src_m->get ("column-type")); else if (semantics::class_* c = object_pointer (utype (*src_m))) { - semantics::data_member& id (*id_member (*c)); + semantics::data_member& id (*id_member (*c)->back ()); if (id.count ("type")) m.set ("column-type", id.get ("column-type")); diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 83e3c40..3b96ab5 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -19,9 +19,11 @@ traverse_object (type& c) { using semantics::data_member; - data_member* id (id_member (c)); + data_member_path* id (id_member (c)); + data_member* idf (id ? id->front () : 0); + data_member* idb (id ? id->back () : 0); bool auto_id (id && auto_ (*id)); - bool base_id (id && &id->scope () != &c); // Comes from base. + bool base_id (id && &idf->scope () != &c); // Comes from base. data_member* opt (optimistic (c)); @@ -42,7 +44,7 @@ traverse_object (type& c) if (generate_grow) { grow = context::grow (c); - grow_id = (id ? context::grow (*id) : false) || + grow_id = (id ? context::grow (*idb) : false) || (opt ? context::grow (*opt) : false); } @@ -188,7 +190,7 @@ traverse_object (type& c) << "ODB_POTENTIALLY_UNUSED (db);" << endl << "id_type id;"; - init_id_value_member_id_image_->traverse (*id); + init_id_value_member_id_image_->traverse (*idb); os << "return id;" << "}"; } @@ -205,7 +207,35 @@ traverse_object (type& c) << "ODB_POTENTIALLY_UNUSED (db);" << endl << "id_type id;"; - init_id_value_member_->traverse (*id); + + // Handle nested id. + // + if (id->size () > 1) + { + string var; + + for (data_member_path::const_iterator i (id->begin ()); + i != id->end (); + ++i) + { + // The same logic as in member_base. + // + if (!var.empty ()) + var += "value."; // Composite. + + string const& name ((*i)->name ()); + var += name; + + if (name[name.size () - 1] != '_') + var += '_'; + } + + instance t ("id", var); + t->traverse (*idb); + } + else + init_id_value_member_->traverse (*idb); + os << "return id;" << "}"; } @@ -339,7 +369,7 @@ traverse_object (type& c) { // The id reference comes first in the insert statement. // - os << "// " << id->name () << endl + os << "// " << idf->name () << endl << "//" << endl << "if (sk == statement_insert)" << "{" @@ -358,7 +388,7 @@ traverse_object (type& c) // The id reference comes last in the update statement. // if (!readonly) - os << "// " << id->name () << endl + os << "// " << idf->name () << endl << "//" << endl << "if (sk == statement_update)" << "{" @@ -398,7 +428,7 @@ traverse_object (type& c) if (composite_wrapper (utype (*id))) os << db << "::statement_kind sk (" << db << "::statement_select);"; - bind_id_member_->traverse (*id); + bind_id_member_->traverse (*idb); if (opt != 0) { @@ -516,7 +546,7 @@ traverse_object (type& c) if (composite_wrapper (utype (*id))) os << db << "::statement_kind sk (" << db << "::statement_select);"; - init_id_image_member_->traverse (*id); + init_id_image_member_->traverse (*idb); if (opt != 0) { @@ -1222,9 +1252,9 @@ traverse_object (type& c) if (!poly_derived && auto_id && insert_send_auto_id) { - string const& n (id->name ()); + string const& n (idf->name ()); string var ("im." + n + (n[n.size () - 1] == '_' ? "" : "_")); - init_auto_id (*id, var); + init_auto_id (*idf, var); // idf == idb, since auto os << endl; } @@ -1278,9 +1308,9 @@ traverse_object (type& c) << "throw object_already_persistent ();" << endl; - if (!poly_derived && auto_id) + if (!poly_derived && auto_id) // idf == idb since auto { - set_member (*id, "obj", "id (sts.id_image ())", "db", "id_type"); + set_member (*idf, "obj", "id (sts.id_image ())", "db", "id_type"); os << endl; } @@ -1486,9 +1516,9 @@ traverse_object (type& c) // Extract auto id. // - if (auto_id) + if (auto_id) // idb == idf, since auto { - set_member (*id, "obj", "id (sts.id_image (i))", "db", "id_type"); + set_member (*idf, "obj", "id (sts.id_image (i))", "db", "id_type"); os << endl; } @@ -4867,7 +4897,7 @@ traverse_view (type& c) { // container.value = pointer.id // - semantics::data_member& id (*id_member (*e.vo->obj)); + data_member_path& id (*id_member (*e.vo->obj)); c_cols->traverse (imb, utype (id), "value", "value"); o_cols->traverse (id); @@ -4877,7 +4907,7 @@ traverse_view (type& c) { // container.id = pointed-to.id // - semantics::data_member& id (*id_member (*vo->obj)); + data_member_path& id (*id_member (*vo->obj)); c_cols->traverse (imb, utype (id), "id", "object_id", vo->obj); o_cols->traverse (id); @@ -4890,7 +4920,7 @@ traverse_view (type& c) { // container.id = pointer.id // - semantics::data_member& id (*id_member (*e.vo->obj)); + data_member_path& id (*id_member (*e.vo->obj)); c_cols->traverse ( m, utype (id), "id", "object_id", e.vo->obj); @@ -4901,7 +4931,7 @@ traverse_view (type& c) { // container.value = pointed-to.id // - semantics::data_member& id (*id_member (*vo->obj)); + data_member_path& id (*id_member (*vo->obj)); c_cols->traverse (m, utype (id), "value", "value"); o_cols->traverse (id); @@ -4961,7 +4991,7 @@ traverse_view (type& c) { // container.id = pointed-to.id // - semantics::data_member& id (*id_member (*vo->obj)); + data_member_path& id (*id_member (*vo->obj)); c_cols->traverse (imb, utype (id), "id", "object_id", vo->obj); o_cols->traverse (id); @@ -4971,7 +5001,7 @@ traverse_view (type& c) { // container.value = pointer.id // - semantics::data_member& id (*id_member (*e.vo->obj)); + data_member_path& id (*id_member (*e.vo->obj)); c_cols->traverse (imb, utype (id), "value", "value"); o_cols->traverse (id); @@ -4984,7 +5014,7 @@ traverse_view (type& c) { // container.value = pointed-to.id // - semantics::data_member& id (*id_member (*vo->obj)); + data_member_path& id (*id_member (*vo->obj)); c_cols->traverse (m, utype (id), "value", "value"); o_cols->traverse (id); @@ -4994,7 +5024,7 @@ traverse_view (type& c) { // container.id = pointer.id // - semantics::data_member& id (*id_member (*e.vo->obj)); + data_member_path& id (*id_member (*e.vo->obj)); c_cols->traverse (m, utype (id), "id", "object_id", e.vo->obj); o_cols->traverse (id); diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index e67931f..f495cef 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -211,7 +211,7 @@ namespace relational semantics::class_& imc ( poly ? dynamic_cast (imf.scope ()) : c); - semantics::data_member& id (*id_member (imc)); + data_member_path& id (*id_member (imc)); semantics::type& idt (utype (id)); if (container (imb)) @@ -484,7 +484,7 @@ namespace relational instance l_cols; // Our id columns. instance r_cols; // Other side id columns. - semantics::data_member& id (*id_member (*us.obj)); + data_member_path& id (*id_member (*us.obj)); l_cols->traverse (id); @@ -1018,7 +1018,7 @@ namespace relational dt = quote_id (table); da = quote_id (poly ? alias + "_" + table.uname () : alias); - semantics::data_member& id (*id_member (c)); + data_member_path& id (*id_member (c)); instance oid_cols, cid_cols; oid_cols->traverse (id); @@ -1171,7 +1171,7 @@ namespace relational bool query_; size_t depth_; string table_; - semantics::data_member& id_; + data_member_path& id_; instance id_cols_; }; @@ -1391,7 +1391,7 @@ namespace relational // Order of these tests is important. // - if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m)) + if (!insert_send_auto_id && auto_ (mi.m)) os << "if (sk != statement_insert && sk != statement_update)" << "{"; else if (section_ == 0 && separate_load (mi.m)) @@ -1567,7 +1567,7 @@ namespace relational // The same logic as in pre(). // - if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m)) + if (!insert_send_auto_id && auto_ (mi.m)) block = true; else if (section_ == 0 && separate_load (mi.m)) block = true; @@ -1673,7 +1673,7 @@ namespace relational size_t insert (cc.total - cc.inverse - cc.optimistic_managed); size_t update (insert - cc.id - cc.readonly - cc.separate_update); - semantics::data_member* id; + data_member_path* id; if (!insert_send_auto_id && (id = id_member (c)) != 0 && auto_ (*id)) insert -= cc.id; @@ -2041,7 +2041,7 @@ namespace relational // 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)) + if (!insert_send_auto_id && auto_ (mi.m)) return false; os << "// " << mi.m.name () << endl @@ -2985,7 +2985,7 @@ namespace relational bool poly_derived (poly && poly_root != &c); size_t poly_depth (poly_derived ? polymorphic_depth (c) : 1); - semantics::data_member* idm (id_member (poly ? *poly_root : c)); + data_member_path* idm (id_member (poly ? *poly_root : c)); os << "// " << mi.m.name () << (pre_ ? " pre" : " post") << endl << "//" << endl; @@ -3084,7 +3084,7 @@ namespace relational for (size_t i (0); i < poly_depth - 1; ++i) id_im += (i == 0 ? ".base" : "->base"); - string const& n (idm->name ()); + string const& n (idm->front ()->name ()); id_var = id_im + (poly_derived ? "->" : ".") + n + (n[n.size () - 1] == '_' ? "" : "_"); @@ -3563,7 +3563,7 @@ namespace relational if (polymorphic (*c)) c = &dynamic_cast (imf.scope ()); - semantics::data_member& inv_id (*id_member (*c)); + data_member_path& inv_id (*id_member (*c)); qname inv_table; // Other table name. string inv_qtable; @@ -6456,7 +6456,7 @@ namespace relational if (version (m)) p = version_value (m); - else if (context::id (m) && auto_ (m)) // Only simple id can be auto. + else if (auto_ (m)) // Only simple, direct id can be auto. p = qp_.auto_id (); else p = qp_.next (); diff --git a/odb/relational/validator.cxx b/odb/relational/validator.cxx index 5dea25f..f78c145 100644 --- a/odb/relational/validator.cxx +++ b/odb/relational/validator.cxx @@ -325,20 +325,20 @@ namespace relational virtual void traverse_object (type& c) { - semantics::data_member* id (id_member (c)); + data_member_path* id (id_member (c)); if (id != 0) { if (semantics::class_* cm = composite_wrapper (utype (*id))) { + location idl (id->front ()->location ()); + // Composite id cannot be auto. // if (auto_ (*id)) { - os << id->file () << ":" << id->line () << ":" << id->column () - << ": error: composite id cannot be automatically assigned" - << endl; - + error (idl) << "composite id cannot be automatically assigned" + << endl; valid_ = false; } @@ -350,8 +350,7 @@ namespace relational composite_id_members_.traverse (*cm); if (!valid_) - os << id->file () << ":" << id->line () << ":" << id->column () - << ": info: composite id is defined here" << endl; + info (idl) << "composite id is defined here" << endl; } // Check that the composite value type is default-constructible. @@ -366,8 +365,7 @@ namespace relational << ": info: provide default constructor for this value type" << endl; - os << id->file () << ":" << id->line () << ":" << id->column () - << ": info: composite id is defined here" << endl; + info (idl) << "composite id is defined here" << endl; valid_ = false; } -- cgit v1.1