From 5b27e12cc00c3faf4f8171d4f41a0ec5d155db48 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 5 Feb 2013 15:50:07 +0200 Subject: Add support for change-tracking containers ODB now supports "smart" ordered containers. Such containers get extra functions for updating and deleting individual elements. Based on this functionality implement two change-tracking containers: odb::vector (equivalent to std::vector) and QOdbList (equivalent to QList). New tests: common/container/change-tracking and qt/common/container/change- tracking. --- odb/context.cxx | 19 +- odb/context.hxx | 7 + odb/processor.cxx | 85 +++++- odb/relational/header.hxx | 280 ++++++++++++----- odb/relational/inline.hxx | 3 +- odb/relational/mssql/source.cxx | 2 +- odb/relational/oracle/source.cxx | 2 +- odb/relational/pgsql/header.cxx | 28 +- odb/relational/pgsql/source.cxx | 127 ++++++-- odb/relational/source.cxx | 301 +++++++++++-------- odb/relational/source.hxx | 634 +++++++++++++++++++++++++++++---------- 11 files changed, 1072 insertions(+), 416 deletions(-) diff --git a/odb/context.cxx b/odb/context.cxx index 515e9a8..e419aba 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -2274,7 +2274,8 @@ namespace unsigned short f (flags_ & (context::test_container | context::test_straight_container | context::test_inverse_container | - context::test_readonly_container)); + context::test_readonly_container | + context::test_smart_container)); if (context::is_a (member_path_, member_scope_, @@ -2319,22 +2320,28 @@ is_a (data_member_path const& mp, if (f & test_lazy_pointer) r = r || (object_pointer (t) && lazy_pointer (t)); + semantics::type* c; if ((f & (test_container | test_straight_container | test_inverse_container | - test_readonly_container)) != 0) + test_readonly_container | + test_smart_container)) != 0 && + (c = container (m)) != 0) { if (f & test_container) - r = r || container (m); + r = r || true; if (f & test_straight_container) - r = r || (container(m) && !inverse (m, kp)); + r = r || !inverse (m, kp); if (f & test_inverse_container) - r = r || (container (m) && inverse (m, kp)); + r = r || inverse (m, kp); if (f & test_readonly_container) - r = r || (container (m) && readonly (mp, ms)); + r = r || readonly (mp, ms); + + if (f & test_smart_container) + r = r || (!inverse (m, kp) && !unordered (m) && container_smart (*c)); } return r; diff --git a/odb/context.hxx b/odb/context.hxx index aa604e4..db8d217 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -866,6 +866,12 @@ public: return c.get ("container-kind"); } + static bool + container_smart (semantics::type& c) + { + return c.get ("container-smart"); + } + static semantics::type& container_idt (semantics::data_member& m) { @@ -913,6 +919,7 @@ public: static unsigned short const test_straight_container = 0x10; static unsigned short const test_inverse_container = 0x20; static unsigned short const test_readonly_container = 0x40; + static unsigned short const test_smart_container = 0x80; // By default the test goes into bases for non-polymorphic // hierarchies and doesn't go for polymorphic. The following diff --git a/odb/processor.cxx b/odb/processor.cxx index c290cca..2e94bc6 100644 --- a/odb/processor.cxx +++ b/odb/processor.cxx @@ -1106,6 +1106,7 @@ namespace // container_kind_type ck; + bool smart; semantics::type* vt (0); semantics::type* it (0); semantics::type* kt (0); @@ -1117,6 +1118,7 @@ namespace if (t.count ("container-kind")) { ck = t.get ("container-kind"); + smart = t.get ("container-smart"); vt = t.get ("value-tree-type"); vh = t.get ("value-tree-hint"); @@ -1151,22 +1153,21 @@ namespace // try { - tree kind ( + tree decl ( lookup_qualified_name ( inst, get_identifier ("kind"), false, false)); - if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL) + if (decl == error_mark_node || TREE_CODE (decl) != VAR_DECL) throw operation_failed (); - // Instantiate this decalaration so that we can get its value. // - if (DECL_TEMPLATE_INSTANTIATION (kind) && - !DECL_TEMPLATE_INSTANTIATED (kind) && - !DECL_EXPLICIT_INSTANTIATION (kind)) - instantiate_decl (kind, false, false); + if (DECL_TEMPLATE_INSTANTIATION (decl) && + !DECL_TEMPLATE_INSTANTIATED (decl) && + !DECL_EXPLICIT_INSTANTIATION (decl)) + instantiate_decl (decl, false, false); - tree init (DECL_INITIAL (kind)); + tree init (DECL_INITIAL (decl)); if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) throw operation_failed (); @@ -1197,6 +1198,63 @@ namespace t.set ("container-kind", ck); + // See if it is a smart container. + // + try + { + tree decl ( + lookup_qualified_name ( + inst, get_identifier ("smart"), false, false)); + + if (decl == error_mark_node || TREE_CODE (decl) != VAR_DECL) + throw operation_failed (); + + // Instantiate this decalaration so that we can get its value. + // + if (DECL_TEMPLATE_INSTANTIATION (decl) && + !DECL_TEMPLATE_INSTANTIATED (decl) && + !DECL_EXPLICIT_INSTANTIATION (decl)) + instantiate_decl (decl, false, false); + + tree init (DECL_INITIAL (decl)); + + if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) + throw operation_failed (); + + unsigned long long e; + + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); + + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + e = (h << width) + l; + } + + smart = static_cast (e); + } + catch (operation_failed const&) + { + os << f << ":" << l << ":" << c << ": error: " + << "container_traits specialization does not define the " + << "'smart' constant" << endl; + throw; + } + + // For now we only support ordered smart containers. + // + if (smart && ck != ck_ordered) + { + os << f << ":" << l << ":" << c << ": error: only ordered smart " << + "containers are currently supported" << endl; + throw operation_failed (); + } + + t.set ("container-smart", smart); + // Mark id column as not null. // t.set ("id-not-null", true); @@ -1370,6 +1428,16 @@ namespace if (ck == ck_ordered && m.count ("value-inverse")) m.set ("unordered", true); + // Issue an error if we have a non-inverse smart unordered container. + // + if (smart && ck == ck_ordered && unordered (m) && + !m.count ("value-inverse")) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ":" + << " error: smart ordered container cannot be unordered" << endl; + throw operation_failed (); + } + // Issue an error if we have a null column in a set container. // This can only happen if the value is declared as null in // the member. @@ -1378,7 +1446,6 @@ namespace { os << m.file () << ":" << m.line () << ":" << m.column () << ":" << " error: set container cannot contain null values" << endl; - throw operation_failed (); } diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 3e0480f..cc36761 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -168,12 +168,12 @@ namespace relational } virtual void - container_public_extra_pre (semantics::data_member&) + container_public_extra_pre (semantics::data_member&, semantics::type&) { } virtual void - container_public_extra_post (semantics::data_member&) + container_public_extra_post (semantics::data_member&, semantics::type&) { } @@ -233,11 +233,15 @@ namespace relational } } + bool smart (!inverse && + (ck != ck_ordered || ordered) && + container_smart (c)); + string name (flat_prefix_ + public_name (m) + "_traits"); // Figure out column counts. // - size_t id_columns, data_columns, cond_columns; + size_t id_columns, value_columns, data_columns, cond_columns; if (!reuse_abst) { @@ -260,9 +264,8 @@ namespace relational { data_columns++; - // Index is not currently used (see also bind()). - // - // cond_columns++; + if (smart) + cond_columns++; } break; } @@ -313,14 +316,17 @@ namespace relational semantics::type& t (ptr == 0 ? vt : utype (*id_member (*ptr))); if (class_* comp = composite_wrapper (t)) - data_columns += column_count (*comp).total; + value_columns = column_count (*comp).total; else - data_columns++; + value_columns = 1; + + data_columns += value_columns; } // Store column counts for the source generator. // m.set ("id-column-count", id_columns); + m.set ("value-column-count", value_columns); m.set ("cond-column-count", cond_columns); m.set ("data-column-count", data_columns); } @@ -344,31 +350,40 @@ namespace relational os << "{"; - container_public_extra_pre (m); + container_public_extra_pre (m, c); if (!reuse_abst) { // column_count // os << "static const std::size_t id_column_count = " << - id_columns << "UL;" - << "static const std::size_t cond_column_count = " << - cond_columns << "UL;" - << "static const std::size_t data_column_count = " << + id_columns << "UL;"; + + if (smart) + os << "static const std::size_t value_column_count = " << + value_columns << "UL;" + << "static const std::size_t cond_column_count = " << + cond_columns << "UL;"; + + os << "static const std::size_t data_column_count = " << data_columns << "UL;" << endl; // Statements. // - os << "static const char insert_one_statement[];" - << "static const char select_all_statement[];" - << "static const char delete_all_statement[];" + os << "static const char insert_statement[];" + << "static const char select_statement[];"; + + if (smart) + os << "static const char update_statement[];"; + + os << "static const char delete_statement[];" << endl; } if (base) { - container_public_extra_post (m); + container_public_extra_post (m, c); os << "};"; return; @@ -437,8 +452,8 @@ namespace relational { case ck_ordered: { - os << "typedef ordered_functions " << - "functions_type;"; + os << "typedef " << (smart ? "smart_" : "") << + "ordered_functions functions_type;"; break; } case ck_map: @@ -456,50 +471,56 @@ namespace relational } } - os << "typedef " << db << "::container_statements< " << name << - " > statements_type;" + os << "typedef " << db << "::" << (smart ? "smart_" : "") + << "container_statements< " << name << " > statements_type;" << endl; - // cond_image_type (object id is taken from the object image) + // cond_image_type (object id is taken from the object image). // - os << "struct cond_image_type" - << "{"; - - switch (ck) + // For dumb containers we use the id binding directly. + // + if (smart) { - case ck_ordered: + os << "struct cond_image_type" + << "{"; + + switch (ck) { - if (ordered) + case ck_ordered: { - os << "// index" << endl + if (ordered) + { + os << "// index" << endl + << "//" << endl; + instance im ( + "index_", *it, "index_type", "index"); + im->traverse (m); + } + break; + } + case ck_map: + case ck_multimap: + { + os << "// key" << endl << "//" << endl; - instance im ("index_", *it, "index_type", "index"); + instance im ("key_", *kt, "key_type", "key"); im->traverse (m); + break; + } + case ck_set: + case ck_multiset: + { + os << "// value" << endl + << "//" << endl; + instance im ("value_", vt, "value_type", "value"); + im->traverse (m); + break; } - break; - } - case ck_map: - case ck_multimap: - { - os << "// key" << endl - << "//" << endl; - instance im ("key_", *kt, "key_type", "key"); - im->traverse (m); - break; - } - case ck_set: - case ck_multiset: - { - os << "// value" << endl - << "//" << endl; - instance im ("value_", vt, "value_type", "value"); - im->traverse (m); - break; } - } - os << "std::size_t version;" - << "};"; + os << "std::size_t version;" + << "};"; + } // data_image_type (object id is taken from the object image) // @@ -545,12 +566,13 @@ namespace relational // bind (cond_image) // - os << "static void" << endl - << "bind (" << bind_vector << "," << endl - << "const " << bind_vector << " id," << endl - << "std::size_t id_size," << endl - << "cond_image_type&);" - << endl; + if (smart) + os << "static void" << endl + << "bind (" << bind_vector << "," << endl + << "const " << bind_vector << " id," << endl + << "std::size_t id_size," << endl + << "cond_image_type&);" + << endl; // bind (data_image) // @@ -561,6 +583,17 @@ namespace relational << "data_image_type&);" << endl; + // bind (cond_image, data_image) (update) + // + if (smart) + os << "static void" << endl + << "bind (" << bind_vector << "," << endl + << "const " << bind_vector << " id," << endl + << "std::size_t id_size," << endl + << "cond_image_type&," << endl + << "data_image_type&);" + << endl; + // grow () // if (generate_grow) @@ -581,7 +614,7 @@ namespace relational case ck_ordered: { if (ordered) - os << "init (data_image_type&, index_type, const value_type&);"; + os << "init (data_image_type&, index_type*, const value_type&);"; else os << "init (data_image_type&, const value_type&);"; break; @@ -589,7 +622,7 @@ namespace relational case ck_map: case ck_multimap: { - os << "init (data_image_type&, const key_type&, const value_type&);"; + os << "init (data_image_type&, const key_type*, const value_type&);"; break; } case ck_set: @@ -603,6 +636,36 @@ namespace relational os << endl; } + // init (cond_image) + // + if (smart) + { + os << "static void" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "init (cond_image_type&, index_type);"; + break; + } + case ck_map: + case ck_multimap: + { + // os << "init (data_image_type&, const key_type&);"; + break; + } + case ck_set: + case ck_multiset: + { + // os << "init (data_image_type&, const value_type&);"; + break; + } + } + + os << endl; + } + // init (data) // os << "static void" << endl; @@ -634,7 +697,7 @@ namespace relational os << "const data_image_type&, database*);" << endl; - // insert_one + // insert // os << "static void" << endl; @@ -642,26 +705,26 @@ namespace relational { case ck_ordered: { - os << "insert_one (index_type, const value_type&, void*);"; + os << "insert (index_type, const value_type&, void*);"; break; } case ck_map: case ck_multimap: { - os << "insert_one (const key_type&, const value_type&, void*);"; + os << "insert (const key_type&, const value_type&, void*);"; break; } case ck_set: case ck_multiset: { - os << "insert_one (const value_type&, void*);"; + os << "insert (const value_type&, void*);"; break; } } os << endl; - // load_all + // select // os << "static bool" << endl; @@ -669,65 +732,120 @@ namespace relational { case ck_ordered: { - os << "load_all (index_type&, value_type&, void*);"; + os << "select (index_type&, value_type&, void*);"; break; } case ck_map: case ck_multimap: { - os << "load_all (key_type&, value_type&, void*);"; + os << "select (key_type&, value_type&, void*);"; break; } case ck_set: case ck_multiset: { - os << "load_all (value_type&, void*);"; + os << "select (value_type&, void*);"; break; } } os << endl; - // delete_all + // update + // + if (smart) + { + os << "static void" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "update (index_type, const value_type&, void*);"; + break; + } + case ck_map: + case ck_multimap: + { + //os << "update (const key_type&, const value_type&, void*);"; + break; + } + case ck_set: + case ck_multiset: + { + //os << "update (const value_type&, const value_type&, void*);"; + break; + } + } + + os << endl; + } + + // delete_ // os << "static void" << endl - << "delete_all (void*);" + << "delete_ ("; + + if (smart) + { + switch (ck) + { + case ck_ordered: + { + os << "index_type, "; + break; + } + case ck_map: + case ck_multimap: + { + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + } + + os << "void*);" << endl; // persist // if (!inverse) os << "static void" << endl - << "persist (const container_type&," << endl - << "const " << db << "::binding& id," << endl - << "statements_type&);" + << "persist (const container_type&, statements_type&);" << endl; // load // os << "static void" << endl - << "load (container_type&," << endl - << "const " << db << "::binding& id," << endl - << "statements_type&);" + << "load (container_type&, statements_type&);" << endl; // update // if (!(inverse || readonly (member_path_, member_scope_))) os << "static void" << endl - << "update (const container_type&," << endl - << "const " << db << "::binding& id," << endl - << "statements_type&);" + << "update (const container_type&, statements_type&);" << endl; // erase // if (!inverse) + { os << "static void" << endl - << "erase (const " << db << "::binding& id, statements_type&);" + << "erase ("; + + if (smart) + os << "const container_type*, "; + + os << "statements_type&);" << endl; + } - container_public_extra_post (m); + container_public_extra_post (m, c); os << "};"; } diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx index 466e348..24e3a08 100644 --- a/odb/relational/inline.hxx +++ b/odb/relational/inline.hxx @@ -305,7 +305,8 @@ namespace relational // erase (object_type) // - if (id != 0 && !poly && optimistic == 0) + if (id != 0 && !poly && optimistic == 0 && + !has_a (c, test_smart_container)) { os << "inline" << endl << "void " << traits << "::" << endl diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx index 5d29b27..a5bc360 100644 --- a/odb/relational/mssql/source.cxx +++ b/odb/relational/mssql/source.cxx @@ -833,7 +833,7 @@ namespace relational virtual void init_value_extra () { - os << "sts.select_all_statement ().stream_result ();" + os << "sts.select_statement ().stream_result ();" << endl; } diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx index f6cdfcd..8c03966 100644 --- a/odb/relational/oracle/source.cxx +++ b/odb/relational/oracle/source.cxx @@ -540,7 +540,7 @@ namespace relational virtual void init_value_extra () { - os << "sts.select_all_statement ().stream_result ();" + os << "sts.select_statement ().stream_result ();" << endl; } }; diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx index 5141c6c..ef0f018 100644 --- a/odb/relational/pgsql/header.cxx +++ b/odb/relational/pgsql/header.cxx @@ -103,24 +103,36 @@ namespace relational container_traits (base const& x): base (x) {} virtual void - container_public_extra_pre (semantics::data_member&) + container_public_extra_pre (semantics::data_member& m, + semantics::type& t) { if (!object (c_) || (abstract (c_) && !polymorphic (c_))) return; + bool smart (!inverse (m, "value") && !unordered (m) && + container_smart (t)); + // Container statement names. // - os << "static const char select_all_name[];" - << "static const char insert_one_name[];" - << "static const char delete_all_name[];" + os << "static const char select_name[];" + << "static const char insert_name[];"; + + if (smart) + os << "static const char update_name[];"; + + os << "static const char delete_name[];" << endl; // Container statement types. // - os << "static const unsigned int select_all_types[];" - << "static const unsigned int insert_one_types[];" - << "static const unsigned int delete_all_types[];" - << endl; + os << "static const unsigned int select_types[];" + << "static const unsigned int insert_types[];"; + + if (smart) + os << "static const unsigned int update_types[];" + << "static const unsigned int delete_types[];"; + + os << endl; } }; entry container_traits_; diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index e106758..46a0594 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -791,6 +791,14 @@ namespace relational } virtual void + container_cache_extra_args (bool used) + { + os << "," << endl + << db << "::native_binding&" << (used ? " idn" : "") << "," << endl + << "const unsigned int*" << (used ? " idt" : ""); + } + + virtual void view_extra (type& c) { string const& n (class_fq_name (c)); @@ -866,10 +874,16 @@ namespace relational if (!object (c_) || (abstract (c_) && !polymorphic (c_))) return; + container_kind_type ck (container_kind (t)); string const& pn (public_name (m)); string scope (scope_ + "::" + flat_prefix_ + pn + "_traits"); + semantics::data_member* inv_m (inverse (m, "value")); + bool inv (inv_m != 0); + + bool smart (!inv && !unordered (m) && container_smart (t)); + // Statment names. // @@ -881,29 +895,32 @@ namespace relational class_fq_name (*top_object) + "_" + flat_prefix_ + pn)); os << "const char " << scope << "::" << endl - << "select_all_name[] = " << strlit (fn + "_select_all") << ";" + << "select_name[] = " << strlit (fn + "_select") << ";" << endl << "const char " << scope << "::" << endl - << "insert_one_name[] = " << strlit (fn + "_insert_one") << ";" - << endl - << "const char " << scope << "::" << endl - << "delete_all_name[] = " << strlit (fn + "_delete_all") << ";" + << "insert_name[] = " << strlit (fn + "_insert") << ";" + << endl; + + if (smart) + os << "const char " << scope << "::" << endl + << "update_name[] = " << strlit (fn + "_update") << ";" + << endl; + + os << "const char " << scope << "::" << endl + << "delete_name[] = " << strlit (fn + "_delete") << ";" << endl; // Statement types. // - semantics::data_member* inv_m (inverse (m, "value")); - bool inv (inv_m != 0); - semantics::type& vt (container_vt (t)); semantics::type& idt (container_idt (m)); - // select_all statement types. + // select statement types. // { os << "const unsigned int " << scope << "::" << endl - << "select_all_types[] =" + << "select_types[] =" << "{"; statement_oids so (statement_where); @@ -926,11 +943,11 @@ namespace relational os << "};"; } - // insert_one statement types. + // insert statement types. // { os << "const unsigned int " << scope << "::" << endl - << "insert_one_types[] =" + << "insert_types[] =" << "{"; if (!inv) @@ -939,7 +956,7 @@ namespace relational so.traverse (m, idt, "id", "object_id"); - switch (container_kind (t)) + switch (ck) { case ck_ordered: { @@ -971,26 +988,96 @@ namespace relational os << "};"; } - // delete_all statement types. + // update statement types. // + if (smart) { os << "const unsigned int " << scope << "::" << endl - << "delete_all_types[] =" + << "update_types[] =" << "{"; - if (!inv) + statement_oids so (statement_where); + + so.traverse (m, vt, "value", "value"); + so.traverse (m, idt, "id", "object_id"); + + switch (ck) { - statement_oids so (statement_where); - so.traverse (m, idt, "id", "object_id"); + case ck_ordered: + { + if (!unordered (m)) + so.traverse (m, container_it (t), "index", "index"); + break; + } + case ck_map: + case ck_multimap: + { + //so.traverse (m, container_kt (t), "key", "key"); + break; + } + case ck_set: + case ck_multiset: + { + //so.traverse (m, vt, "value", "value"); + break; + } + } + + os << "};"; + } + + // delete statement types. + // + if (smart) + { + os << "const unsigned int " << scope << "::" << endl + << "delete_types[] =" + << "{"; + + statement_oids so (statement_where); + so.traverse (m, idt, "id", "object_id"); + + switch (ck) + { + case ck_ordered: + { + if (!unordered (m)) + so.traverse (m, container_it (t), "index", "index"); + break; + } + case ck_map: + case ck_multimap: + { + //so.traverse (m, container_kt (t), "key", "key"); + break; + } + case ck_set: + case ck_multiset: + { + //so.traverse (m, vt, "value", "value"); + break; + } } - else - os << "0"; os << "};"; } } }; entry container_traits_; + + struct container_cache_init_members: + relational::container_cache_init_members + { + container_cache_init_members (base const& x): base (x) {} + + virtual void + extra_members () + { + os << ", idn, idt"; + } + }; + entry container_cache_init_members_; + } } } diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 661db71..fe6bbbd 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -73,6 +73,7 @@ traverse_object (type& c) bool containers (has_a (c, test_container)); bool straight_containers (false); bool straight_readwrite_containers (false); + bool smart_containers (false); if (containers) { @@ -85,6 +86,10 @@ traverse_object (type& c) // Inverse containers cannot be marked readonly. // straight_readwrite_containers = scn > has_a (c, test_readonly_container); + + // Inverse containers cannot be smart. + // + smart_containers = has_a (c, test_smart_container); } } @@ -418,8 +423,13 @@ traverse_object (type& c) cm->traverse (c); os << (containers ? "\n" : "") - << "container_statement_cache_type (" << db << "::connection&" << - (containers ? " c" : "") << ")"; + << "container_statement_cache_type (" << endl + << db << "::connection&" << (containers ? " c" : "") << "," << endl + << db << "::binding&" << (containers ? " id" : ""); + + container_cache_extra_args (containers); + + os << ")"; instance im; im->traverse (c); @@ -1187,8 +1197,7 @@ traverse_object (type& c) << "}"; } - if (cc.total != cc.id + cc.inverse + cc.readonly || - straight_readwrite_containers) + if (cc.total != cc.id + cc.inverse + cc.readonly) { os << "const binding& idb (sts.id_image_binding ());" << endl; @@ -1395,10 +1404,6 @@ traverse_object (type& c) if (delay_freeing_statement_result) os << "sts.find_statement ().free_result ();"; } - - if (straight_readwrite_containers) - os << "binding& idb (sts.id_image_binding ());" - << endl; } if (straight_readwrite_containers) @@ -1565,11 +1570,7 @@ traverse_object (type& c) // if (straight_containers) { - if (poly) - os << "binding& idb (sts.id_image_binding ());" - << endl; - - instance t (container_calls::erase_call); + instance t (container_calls::erase_id_call); t->traverse (c); } @@ -1601,7 +1602,7 @@ traverse_object (type& c) // erase (object) // - if (id != 0 && (poly || opt != 0)) + if (id != 0 && (poly || opt != 0 || smart_containers)) { os << "void " << traits << "::" << endl << "erase (database& db, const object_type& obj"; @@ -1632,22 +1633,14 @@ traverse_object (type& c) << "}"; // If we are database-poly-abstract but not C++-abstract, then make - // sure we are not trying to persist an instance of an abstract class. + // sure we are not trying to erase an instance of an abstract class. // if (abst && !c.abstract ()) os << "if (top)" << endl << "throw abstract_class ();" << endl; - // Determine the dynamic type of this object. - // - if (opt == 0) - { - os << "callback (db, obj, callback_event::pre_erase);" - << "erase (db, id (obj), true, false);" - << "callback (db, obj, callback_event::post_erase);"; - } - else + if (opt != 0 || smart_containers) { string rsts (poly_derived ? "rsts" : "sts"); @@ -1684,135 +1677,179 @@ traverse_object (type& c) << endl; } - // Initialize id + managed column image. + // Smart containers case. // - os << "binding& idb (" << rsts << ".id_image_binding ());" - << endl; - - if (!abst) // If we are poly-abstract, then top will always be false. + if (opt == 0) { - if (poly) - os << "if (top)" - << "{"; + // Initialize id image. + // + if (!abst) // If we are poly-abstract, then top will always be false. + { + if (poly) + os << "if (top)" + << "{"; - if (!opt_ma_get->synthesized) - os << "// From " << location_string (opt_ma_get->loc, true) << endl; + os << "id_image_type& i (" << rsts << ".id_image ());" + << "init (i, id);" + << endl; - os << "const version_type& v (" << endl - << opt_ma_get->translate ("obj") << ");" - << "id_image_type& i (" << rsts << ".id_image ());" - << "init (i, id, &v);" - << endl; + os << "binding& idb (" << rsts << ".id_image_binding ());" + << "if (i.version != " << rsts << ".id_image_version () || " << + "idb.version == 0)" + << "{" + << "bind (idb.bind, i);" + << rsts << ".id_image_version (i.version);" + << "idb.version++;" + << "}"; + + if (poly) + os << "}"; + } - // To update the id part of the optimistic id binding we have - // to do it indirectly via the id binding, since both id and - // optimistic id bindings just point to the suffix of the - // update bind array (see object_statements). + // Erase containers first so that there are no reference + // violations (we don't want to rely on ON DELETE CASCADE + // here since in case of a custom schema, it might not be + // there). // - os << "binding& oidb (" << rsts << ".optimistic_id_image_binding ());" - << "if (i.version != " << rsts << - ".optimistic_id_image_version () ||" << endl - << "oidb.version == 0)" - << "{" - // If the id binding is up-to-date, then that means optimistic - // id binding is too and we just need to update the versions. - // - << "if (i.version != " << rsts << ".id_image_version () ||" << endl - << "idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - // Update the id binding versions since we may use them later - // to delete containers. - // - << rsts << ".id_image_version (i.version);" - << "idb.version++;" - << "}" - << rsts << ".optimistic_id_image_version (i.version);" - << "oidb.version++;" - << "}"; + instance t (container_calls::erase_obj_call); + t->traverse (c); - if (poly) - os << "}"; // if (top) + os << "if (sts.erase_statement ().execute () != 1)" << endl + << "throw object_not_persistent ();" + << endl; } - - // If this is a derived type in a polymorphic hierarchy, then we - // need to check the version (stored in root) before we go ahead - // and start deleting things. Also use the same code for root with - // containers since it is more efficient than the find_() method - // below. + // Optimistic case. // - if (poly_derived || (poly && straight_containers)) + else { - // Only do the check in the top-level call. + // Initialize id + managed column image. // if (!abst) // If we are poly-abstract, then top will always be false. { - os << "if (top)" - << "{" - << "version_type v;" - << "root_traits::discriminator_ (" << rsts << ", id, 0, &v);" - << endl; + if (poly) + os << "if (top)" + << "{"; if (!opt_ma_get->synthesized) os << "// From " << location_string (opt_ma_get->loc, true) << endl; - os << "if (v != " << opt_ma_get->translate ("obj") << ")" << endl - << "throw object_changed ();" + os << "const version_type& v (" << endl + << opt_ma_get->translate ("obj") << ");" + << "id_image_type& i (" << rsts << ".id_image ());" + << "init (i, id, &v);" + << endl; + + // To update the id part of the optimistic id binding we have + // to do it indirectly via the id binding, since both id and + // optimistic id bindings just point to the suffix of the + // update bind array (see object_statements). + // + os << "binding& oidb (" << rsts << ".optimistic_id_image_binding ());" + << "if (i.version != " << rsts << + ".optimistic_id_image_version () ||" << endl + << "oidb.version == 0)" + << "{" + // If the id binding is up-to-date, then that means optimistic + // id binding is too and we just need to update the versions. + // + << "binding& idb (" << rsts << ".id_image_binding ());" + << "if (i.version != " << rsts << ".id_image_version () ||" << endl + << "idb.version == 0)" + << "{" + << "bind (idb.bind, i);" + // Update the id binding versions since we may use them later + // to delete containers. + // + << rsts << ".id_image_version (i.version);" + << "idb.version++;" + << "}" + << rsts << ".optimistic_id_image_version (i.version);" + << "oidb.version++;" << "}"; + + if (poly) + os << "}"; // if (top) } - } - else if (straight_containers) - { - // Things get complicated here: we don't want to trash the - // containers and then find out that the versions don't match - // and we therefore cannot delete the object. After all, there - // is no guarantee that the user will abort the transaction. - // In fact, a perfectly reasonable scenario is to reload the - // object, re-check the condition, decide not to delete the - // object, and then commit the transaction. - // - // There doesn't seem to be anything better than first making - // sure we can delete the object, then deleting the container - // data, and then deleting the object. To check that we can - // delete the object we are going to use find_() and then - // compare the versions. A special-purpose SELECT query would - // have been more efficient but it would complicated and bloat - // things significantly. + + // If this is a derived type in a polymorphic hierarchy, then we + // need to check the version (stored in root) before we go ahead + // and start deleting things. Also use the same code for root with + // containers since it is more efficient than the find_() method + // below. // - os << "if (!find_ (sts, &id))" << endl - << "throw object_changed ();" - << endl; + if (poly_derived || (poly && straight_containers)) + { + // Only do the check in the top-level call. + // + if (!abst) // If we are poly-abstract, then top will always be false. + { + os << "if (top)" + << "{" + << "version_type v;" + << "root_traits::discriminator_ (" << rsts << ", id, 0, &v);" + << endl; - if (delay_freeing_statement_result) - os << "sts.find_statement ().free_result ();" + if (!opt_ma_get->synthesized) + os << "// From " << location_string (opt_ma_get->loc, true) << endl; + + os << "if (v != " << opt_ma_get->translate ("obj") << ")" << endl + << "throw object_changed ();" + << "}"; + } + } + else if (straight_containers) + { + // Things get complicated here: we don't want to trash the + // containers and then find out that the versions don't match + // and we therefore cannot delete the object. After all, there + // is no guarantee that the user will abort the transaction. + // In fact, a perfectly reasonable scenario is to reload the + // object, re-check the condition, decide not to delete the + // object, and then commit the transaction. + // + // There doesn't seem to be anything better than first making + // sure we can delete the object, then deleting the container + // data, and then deleting the object. To check that we can + // delete the object we are going to use find_() and then + // compare the versions. A special-purpose SELECT query would + // have been more efficient but it would complicated and bloat + // things significantly. + // + os << "if (!find_ (sts, &id))" << endl + << "throw object_changed ();" << endl; - if (!opt_ma_get->synthesized) - os << "// From " << location_string (opt_ma_get->loc, true) << endl; + if (delay_freeing_statement_result) + os << "sts.find_statement ().free_result ();" + << endl; - os << "if (version (sts.image ()) != " << - opt_ma_get->translate ("obj") << ")" << endl - << "throw object_changed ();" - << endl; - } + if (!opt_ma_get->synthesized) + os << "// From " << location_string (opt_ma_get->loc, true) << endl; - // Erase containers first so that there are no reference - // violations (we don't want to rely on ON DELETE CASCADE - // here since in case of a custom schema, it might not be - // there). - // - if (straight_containers) - { - instance t (container_calls::erase_call); - t->traverse (c); - } + os << "if (version (sts.image ()) != " << + opt_ma_get->translate ("obj") << ")" << endl + << "throw object_changed ();" + << endl; + } - const char* st ( - poly_derived ? "erase_statement" : "optimistic_erase_statement"); + // Erase containers first so that there are no reference + // violations (we don't want to rely on ON DELETE CASCADE + // here since in case of a custom schema, it might not be + // there). + // + if (straight_containers) + { + instance t (container_calls::erase_obj_call); + t->traverse (c); + } - os << "if (sts." << st << " ().execute () != 1)" << endl - << "throw object_changed ();" - << endl; + const char* st ( + poly_derived ? "erase_statement" : "optimistic_erase_statement"); + + os << "if (sts." << st << " ().execute () != 1)" << endl + << "throw object_changed ();" + << endl; + } if (poly_derived) { @@ -1841,6 +1878,16 @@ traverse_object (type& c) os << "}"; } } + else if (smart_containers) + { + + } + else + { + os << "callback (db, obj, callback_event::pre_erase);" + << "erase (db, id (obj), true, false);" + << "callback (db, obj, callback_event::post_erase);"; + } os << "}"; } @@ -2390,8 +2437,6 @@ traverse_object (type& c) if (containers) { - os << db << "::binding& idb (sts.id_image_binding ());" - << endl; instance t (container_calls::load_call); t->traverse (c); } diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index dfa6ebf..717d91d 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -1889,6 +1889,10 @@ namespace relational } } + bool smart (!inverse && + (ck != ck_ordered || ordered) && + container_smart (t)); + if (generate_grow) grow = grow || context::grow (m, vt, "value"); @@ -1922,11 +1926,34 @@ namespace relational qname table (table_name (m, table_prefix_)); string qtable (quote_id (table)); instance id_cols; + instance ik_cols; // index/key columns + + if (smart) + { + switch (ck) + { + case ck_ordered: + { + ik_cols->traverse (m, *it, "index", "index"); + break; + } + case ck_map: + case ck_multimap: + { + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + } - // select_all_statement + // select_statement // os << "const char " << scope << "::" << endl - << "select_all_statement[] =" << endl; + << "select_statement[] =" << endl; if (inverse) { @@ -2083,10 +2110,10 @@ namespace relational os << ";" << endl; - // insert_one_statement + // insert_statement // os << "const char " << scope << "::" << endl - << "insert_one_statement[] =" << endl; + << "insert_statement[] =" << endl; if (inverse) os << strlit ("") << ";" @@ -2148,10 +2175,57 @@ namespace relational << endl; } - // delete_all_statement + // update_statement + // + if (smart) + { + os << "const char " << scope << "::" << endl + << "update_statement[] =" << endl + << strlit ("UPDATE " + qtable + " SET "); + + instance qp (table); + statement_columns sc; + { + query_parameters* p (qp.get ()); // Imperfect forwarding. + statement_kind sk (statement_update); // Imperfect forwarding. + instance t (sk, sc, p); + t->traverse (m, vt, "value", "value"); + process_statement_columns (sc, statement_update); + } + + for (statement_columns::const_iterator i (sc.begin ()), + e (sc.end ()); i != e;) + { + string const& c (i->column); + os << endl + << strlit (c + (++i != e ? "," : "")); + } + + 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) + "=" + + convert_to (qp->next (), i->type, *i->member)); + } + + for (object_columns_list::iterator b (ik_cols->begin ()), i (b); + i != ik_cols->end (); ++i) + { + os << endl + << strlit (" AND " + quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member)); + } + + os << ";" + << endl; + } + + // delete_statement // os << "const char " << scope << "::" << endl - << "delete_all_statement[] =" << endl; + << "delete_statement[] =" << endl; if (inverse) os << strlit ("") << ";" @@ -2171,6 +2245,18 @@ namespace relational convert_to (qp->next (), i->type, *i->member)); } + if (smart) + { + for (object_columns_list::iterator b (ik_cols->begin ()), i (b); + i != ik_cols->end (); ++i) + { + os << endl + << strlit (" AND " + quote_id (i->name) + + (ck == ck_ordered ? ">=" : "=") + + convert_to (qp->next (), i->type, *i->member)); + } + } + os << ";" << endl; } @@ -2183,18 +2269,20 @@ namespace relational // Functions. // - // bind() + // bind (cond_image_type) // + if (smart) { - // bind (cond_image_type) - // os << "void " << scope << "::" << endl << "bind (" << bind_vector << " b," << endl << "const " << bind_vector << " id," << endl << "std::size_t id_size," << endl << "cond_image_type& c)" << "{" - << "ODB_POTENTIALLY_UNUSED (c);" + << "using namespace " << db << ";" + << endl + << "statement_kind sk (statement_select);" + << "ODB_POTENTIALLY_UNUSED (sk);" << endl << "std::size_t n (0);" << endl; @@ -2209,11 +2297,6 @@ namespace relational // We don't need to update the bind index since this is the // last element. // - // Index/key is currently not used (see also cond_column_count). - // -#if 0 - // Would need statement_kind if this is enabled. - // switch (ck) { case ck_ordered: @@ -2248,12 +2331,12 @@ namespace relational break; } } -#endif - os << "}"; + } - // bind (data_image_type) - // + // bind (data_image_type) + // + { os << "void " << scope << "::" << endl << "bind (" << bind_vector << " b," << endl << "const " << bind_vector << " id," << endl @@ -2329,6 +2412,84 @@ namespace relational os << "}"; } + // bind (cond_image, data_image) (update) + // + if (smart) + { + os << "void " << scope << "::" << endl + << "bind (" << bind_vector << " b," << endl + << "const " << bind_vector << " id," << endl + << "std::size_t id_size," << endl + << "cond_image_type& c," << endl + << "data_image_type& d)" + << "{" + << "using namespace " << db << ";" + << endl + << "statement_kind sk (statement_update);" + << "ODB_POTENTIALLY_UNUSED (sk);" + << endl + << "std::size_t n (0);" + << endl; + + os << "// key" << endl + << "//" << endl; + instance bm ("value_", "d", vt, "value_type", "value"); + bm->traverse (m); + + if (semantics::class_* c = composite_wrapper (vt)) + os << "n += " << column_count (*c).total << "UL;" + << endl; + else + os << "n++;" + << endl; + + os << "// object_id" << endl + << "//" << endl + << "if (id != 0)" << endl + << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));" + << "n += id_size;" + << endl; + + // We don't need to update the bind index since this is the + // last element. + // + switch (ck) + { + case ck_ordered: + { + if (ordered) + { + os << "// index" << endl + << "//" << endl; + instance bm ( + "index_", "c", *it, "index_type", "index"); + bm->traverse (m); + } + break; + } + case ck_map: + case ck_multimap: + { + os << "// key" << endl + << "//" << endl; + instance bm ("key_", "c", *kt, "key_type", "key"); + bm->traverse (m); + break; + } + case ck_set: + case ck_multiset: + { + os << "// value" << endl + << "//" << endl; + instance bm ( + "value_", "c", vt, "value_type", "value"); + bm->traverse (m); + break; + } + } + os << "}"; + } + // grow () // if (generate_grow) @@ -2393,7 +2554,7 @@ namespace relational case ck_ordered: { if (ordered) - os << "init (data_image_type& i, index_type j, " << + os << "init (data_image_type& i, index_type* j, " << "const value_type& v)"; else os << "init (data_image_type& i, const value_type& v)"; @@ -2402,7 +2563,7 @@ namespace relational case ck_map: case ck_multimap: { - os << "init (data_image_type& i, const key_type& k, " << + os << "init (data_image_type& i, const key_type* k, " << "const value_type& v)"; break; } @@ -2432,10 +2593,11 @@ namespace relational if (ordered) { os << "// index" << endl - << "//" << endl; + << "//" << endl + << "if (j != 0)"; instance im ( - "index_", "j", *it, "index_type", "index"); + "index_", "*j", *it, "index_type", "index"); im->traverse (m); } break; @@ -2444,10 +2606,11 @@ namespace relational case ck_multimap: { os << "// key" << endl - << "//" << endl; + << "//" << endl + << "if (k != 0)"; instance im ( - "key_", "k", *kt, "key_type", "key"); + "key_", "*k", *kt, "key_type", "key"); im->traverse (m); break; @@ -2474,6 +2637,52 @@ namespace relational os << "}"; } + // init (cond_image) + // + if (smart) + { + os << "void " << scope << "::" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "init (cond_image_type& i, index_type j)" + << "{" + << "using namespace " << db << ";" + << endl + << "statement_kind sk (statement_select);" + << "ODB_POTENTIALLY_UNUSED (sk);" + << endl; + + instance im ( + "index_", "j", *it, "index_type", "index"); + im->traverse (m); + + os << "}"; + break; + } + case ck_map: + case ck_multimap: + { + // Need to handle growth. + // + // os << "init (data_image_type&, const key_type&);"; + break; + } + case ck_set: + case ck_multiset: + { + // Need to handle growth. + // + // os << "init (data_image_type&, const value_type&);"; + break; + } + } + + os << endl; + } + // init (data) // os << "void " << scope << "::" << endl; @@ -2546,7 +2755,7 @@ namespace relational } os << "}"; - // insert_one + // insert // { string ia, ka, va, da; @@ -2565,7 +2774,7 @@ namespace relational { case ck_ordered: { - os << "insert_one (index_type" << ia << ", " << + os << "insert (index_type" << ia << ", " << "const value_type&" << va << ", " << "void*" << da << ")"; break; @@ -2573,7 +2782,7 @@ namespace relational case ck_map: case ck_multimap: { - os << "insert_one (const key_type&" << ka << ", " << + os << "insert (const key_type&" << ka << ", " << "const value_type&" << va << ", " << "void*" << da << ")"; break; @@ -2581,7 +2790,7 @@ namespace relational case ck_set: case ck_multiset: { - os << "insert_one (const value_type&" << va << ", " << + os << "insert (const value_type&" << va << ", " << "void*" << da << ")"; break; } @@ -2594,7 +2803,6 @@ namespace relational os << "using namespace " << db << ";" << endl << "statements_type& sts (*static_cast< statements_type* > (d));" - << "binding& b (sts.data_image_binding ());" << "data_image_type& di (sts.data_image ());" << endl; @@ -2602,13 +2810,13 @@ namespace relational { case ck_ordered: { - os << "init (di, " << (ordered ? "i, " : "") << "v);"; + os << "init (di, " << (ordered ? "&i, " : "") << "v);"; break; } case ck_map: case ck_multimap: { - os << "init (di, k, v);"; + os << "init (di, &k, v);"; break; } case ck_set: @@ -2620,22 +2828,89 @@ namespace relational } os << endl - << "if (di.version != sts.data_image_version ())" + << "if (sts.data_binding_test_version ())" << "{" - << "bind (b.bind, 0, sts.id_binding ().count, di);" - << "sts.data_image_version (di.version);" - << "b.version++;" - << "sts.select_image_binding ().version++;" + << "const binding& id (sts.id_binding ());" + << "bind (sts.data_bind (), id.bind, id.count, di);" + << "sts.data_binding_update_version ();" << "}" - << "if (!sts.insert_one_statement ().execute ())" << endl + << "if (!sts.insert_statement ().execute ())" << endl << "throw object_already_persistent ();"; } os << "}"; } + // update + // + if (smart) + { + os << "void " << scope << "::" << endl; + + switch (ck) + { + case ck_ordered: + { + os << "update (index_type i, const value_type& v, void* d)"; + break; + } + case ck_map: + case ck_multimap: + { + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } - // load_all + os << "{"; + + os << "using namespace " << db << ";" + << endl + << "statements_type& sts (*static_cast< statements_type* > (d));" + << "cond_image_type& ci (sts.cond_image ());" + << "data_image_type& di (sts.data_image ());" + << endl; + + switch (ck) + { + case ck_ordered: + { + os << "init (ci, i);"; + os << "init (di, 0, v);"; + break; + } + case ck_map: + case ck_multimap: + { + //os << "init (di, 0, v);"; + break; + } + case ck_set: + case ck_multiset: + { + //os << "init (di, v);"; + break; + } + } + + os << endl + << "if (sts.update_binding_test_version ())" + << "{" + << "const binding& id (sts.id_binding ());" + << "bind (sts.update_bind (), id.bind, id.count, ci, di);" + << "sts.update_binding_update_version ();" + << "}"; + + os << "if (sts.update_statement ().execute () == 0)" << endl + << "throw object_not_persistent ();" + << "}"; + } + + // select // os << "bool " << scope << "::" << endl; @@ -2643,26 +2918,27 @@ namespace relational { case ck_ordered: { - os << "load_all (index_type&" << (ordered ? " i" : "") << + os << "select (index_type&" << (ordered ? " i" : "") << ", value_type& v, void* d)"; break; } case ck_map: case ck_multimap: { - os << "load_all (key_type& k, value_type& v, void* d)"; + os << "select (key_type& k, value_type& v, void* d)"; break; } case ck_set: case ck_multiset: { - os << "load_all (value_type& v, void* d)"; + os << "select (value_type& v, void* d)"; break; } } os << "{" << "using namespace " << db << ";" + << "using " << db << "::select_statement;" // Conflicts. << endl << "statements_type& sts (*static_cast< statements_type* > (d));" << "data_image_type& di (sts.data_image ());"; @@ -2698,27 +2974,21 @@ namespace relational // If we are loading an eager pointer, then the call to init // above executes other statements which potentially could - // change the image. + // change the image, including the id. // if (eager_ptr) { - os << "const binding& idb (sts.id_binding ());" - << endl - << "if (di.version != sts.data_image_version () ||" << endl - << "idb.version != sts.data_id_binding_version ())" + os << "if (sts.data_binding_test_version ())" << "{" - << "binding& b (sts.data_image_binding ());" - << "bind (b.bind, idb.bind, idb.count, di);" - << "sts.data_image_version (di.version);" - << "sts.data_id_binding_version (idb.version);" - << "b.version++;" - << "sts.select_image_binding ().version++;" + << "const binding& id (sts.id_binding ());" + << "bind (sts.data_bind (), id.bind, id.count, di);" + << "sts.data_binding_update_version ();" << "}"; } // Fetch next. // - os << "select_statement& st (sts.select_all_statement ());" + os << "select_statement& st (sts.select_statement ());" << "select_statement::result r (st.fetch ());"; if (grow) @@ -2727,13 +2997,12 @@ namespace relational << "{" << "grow (di, sts.select_image_truncated ());" << endl - << "if (di.version != sts.data_image_version ())" + << "if (sts.data_binding_test_version ())" << "{" - << "binding& b (sts.data_image_binding ());" - << "bind (b.bind, 0, sts.id_binding ().count, di);" - << "sts.data_image_version (di.version);" - << "b.version++;" - << "sts.select_image_binding ().version++;" + // Id cannot change. + // + << "bind (sts.data_bind (), 0, sts.id_binding ().count, di);" + << "sts.data_binding_update_version ();" << "st.refetch ();" << "}" << "}"; @@ -2741,17 +3010,77 @@ namespace relational os << "return r != select_statement::no_data;" << "}"; - // delete_all + // delete_ // os << "void " << scope << "::" << endl - << "delete_all (void*" << (inverse ? "" : " d") << ")" + << "delete_ ("; + + if (smart) + { + switch (ck) + { + case ck_ordered: + { + os << "index_type i, "; + break; + } + case ck_map: + case ck_multimap: + { + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + } + + os << "void*" << (inverse ? "" : " d") << ")" << "{"; if (!inverse) + { os << "using namespace " << db << ";" << endl - << "statements_type& sts (*static_cast< statements_type* > (d));" - << "sts.delete_all_statement ().execute ();"; + << "statements_type& sts (*static_cast< statements_type* > (d));"; + + if (smart) + { + os << "cond_image_type& ci (sts.cond_image ());" + << endl; + + switch (ck) + { + case ck_ordered: + { + os << "init (ci, i);"; + break; + } + case ck_map: + case ck_multimap: + { + break; + } + case ck_set: + case ck_multiset: + { + break; + } + } + + os << endl + << "if (sts.cond_binding_test_version ())" + << "{" + << "const binding& id (sts.id_binding ());" + << "bind (sts.cond_bind (), id.bind, id.count, ci);" + << "sts.cond_binding_update_version ();" + << "}"; + } + + os << "sts.delete_statement ().execute ();"; + } os << "}"; @@ -2760,26 +3089,14 @@ namespace relational if (!inverse) { os << "void " << scope << "::" << endl - << "persist (const container_type& c," << endl - << "const " << db << "::binding& id," << endl - << "statements_type& sts)" + << "persist (const container_type& c, statements_type& sts)" << "{" << "using namespace " << db << ";" << endl - << "binding& b (sts.data_image_binding ());" - << "if (id.version != sts.data_id_binding_version () || " << - "b.version == 0)" - << "{" - << "bind (b.bind, id.bind, id.count, sts.data_image ());" - << "sts.data_id_binding_version (id.version);" - << "b.version++;" - << "sts.select_image_binding ().version++;" - << "}" - << "sts.id_binding (id);" << "functions_type& fs (sts.functions ());"; - if (ck == ck_ordered) - os << "fs.ordered (" << (ordered ? "true" : "false") << ");"; + if (!smart && ck == ck_ordered) + os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";"; os << "container_traits_type::persist (c, fs);" << "}"; @@ -2788,30 +3105,21 @@ namespace relational // load // os << "void " << scope << "::" << endl - << "load (container_type& c," << endl - << "const " << db << "::binding& id," << endl - << "statements_type& sts)" + << "load (container_type& c, statements_type& sts)" << "{" << "using namespace " << db << ";" + << "using " << db << "::select_statement;" // Conflicts. << endl - << "binding& db (sts.data_image_binding ());" - << "if (id.version != sts.data_id_binding_version () || " << - "db.version == 0)" - << "{" - << "bind (db.bind, id.bind, id.count, sts.data_image ());" - << "sts.data_id_binding_version (id.version);" - << "db.version++;" - << "sts.select_image_binding ().version++;" - << "}" - << "binding& cb (sts.cond_image_binding ());" - << "if (id.version != sts.cond_id_binding_version () || " << - "cb.version == 0)" + << "const binding& id (sts.id_binding ());" + << endl + << "if (sts.data_binding_test_version ())" << "{" - << "bind (cb.bind, id.bind, id.count, sts.cond_image ());" - << "sts.cond_id_binding_version (id.version);" - << "cb.version++;" + << "bind (sts.data_bind (), id.bind, id.count, sts.data_image ());" + << "sts.data_binding_update_version ();" << "}" - << "select_statement& st (sts.select_all_statement ());" + // We use the id binding directly so no need to check cond binding. + // + << "select_statement& st (sts.select_statement ());" << "st.execute ();" << "auto_result ar (st);"; @@ -2830,23 +3138,22 @@ namespace relational << "data_image_type& di (sts.data_image ());" << "grow (di, sts.select_image_truncated ());" << endl - << "if (di.version != sts.data_image_version ())" + << "if (sts.data_binding_test_version ())" << "{" - << "bind (db.bind, 0, id.count, sts.data_image ());" - << "sts.data_image_version (di.version);" - << "db.version++;" - << "sts.select_image_binding ().version++;" + // Id cannot change. + // + << "bind (sts.data_bind (), 0, id.count, di);" + << "sts.data_binding_update_version ();" << "st.refetch ();" << "}" << "}"; os << "bool more (r != select_statement::no_data);" << endl - << "sts.id_binding (id);" << "functions_type& fs (sts.functions ());"; - if (ck == ck_ordered) - os << "fs.ordered (" << (ordered ? "true" : "false") << ");"; + if (!smart && ck == ck_ordered) + os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";"; os << "container_traits_type::load (c, more, fs);" << "}"; @@ -2856,37 +3163,21 @@ namespace relational if (!(inverse || readonly (member_path_, member_scope_))) { os << "void " << scope << "::" << endl - << "update (const container_type& c," << endl - << "const " << db << "::binding& id," << endl - << "statements_type& sts)" + << "update (const container_type& c, statements_type& sts)" << "{" << "using namespace " << db << ";" << endl - << "binding& db (sts.data_image_binding ());" - << "if (id.version != sts.data_id_binding_version () || " << - "db.version == 0)" - << "{" - << "bind (db.bind, id.bind, id.count, sts.data_image ());" - << "sts.data_id_binding_version (id.version);" - << "db.version++;" - << "sts.select_image_binding ().version++;" - << "}" - // - // We may need cond if the specialization calls delete_all. - // - << "binding& cb (sts.cond_image_binding ());" - << "if (id.version != sts.cond_id_binding_version () || " << - "cb.version == 0)" + << "const binding& id (sts.id_binding ());" + << endl + << "if (sts.data_binding_test_version ())" << "{" - << "bind (cb.bind, id.bind, id.count, sts.cond_image ());" - << "sts.cond_id_binding_version (id.version);" - << "cb.version++;" + << "bind (sts.data_bind (), id.bind, id.count, sts.data_image ());" + << "sts.data_binding_update_version ();" << "}" - << "sts.id_binding (id);" << "functions_type& fs (sts.functions ());"; - if (ck == ck_ordered) - os << "fs.ordered (" << (ordered ? "true" : "false") << ");"; + if (!smart && ck == ck_ordered) + os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";"; os << "container_traits_type::update (c, fs);" << "}"; @@ -2897,25 +3188,21 @@ namespace relational if (!inverse) { os << "void " << scope << "::" << endl - << "erase (const " << db << "::binding& id, statements_type& sts)" + << "erase ("; + + if (smart) + os << "const container_type* c, "; + + os << "statements_type& sts)" << "{" << "using namespace " << db << ";" << endl - << "binding& b (sts.cond_image_binding ());" - << "if (id.version != sts.cond_id_binding_version () || " << - "b.version == 0)" - << "{" - << "bind (b.bind, id.bind, id.count, sts.cond_image ());" - << "sts.cond_id_binding_version (id.version);" - << "b.version++;" - << "}" - << "sts.id_binding (id);" << "functions_type& fs (sts.functions ());"; - if (ck == ck_ordered) - os << "fs.ordered (" << (ordered ? "true" : "false") << ");"; + if (!smart && ck == ck_ordered) + os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";"; - os << "container_traits_type::erase (fs);" + os << "container_traits_type::erase (" << (smart ? "c, " : "") << "fs);" << "}"; } } @@ -2937,10 +3224,16 @@ namespace relational } virtual void - traverse_container (semantics::data_member& m, semantics::type&) + traverse_container (semantics::data_member& m, semantics::type& c) { + bool smart (!context::inverse (m, "value") && + !unordered (m) && + container_smart (c)); + string traits (flat_prefix_ + public_name (m) + "_traits"); - os << db << "::container_statements_impl< " << traits << " > " << + + os << db << "::" << (smart ? "smart_" : "") << + "container_statements_impl< " << traits << " > " << flat_prefix_ << m.name () << ";"; } }; @@ -2967,9 +3260,14 @@ namespace relational os << "," << endl << " "; - os << flat_prefix_ << m.name () << " (c)"; + os << flat_prefix_ << m.name () << " (c, id"; + extra_members (); + os << ")"; } + virtual void + extra_members () {} + protected: bool first_; }; @@ -2985,7 +3283,8 @@ namespace relational persist_call, load_call, update_call, - erase_call + erase_obj_call, + erase_id_call }; container_calls (call_type call) @@ -3001,7 +3300,7 @@ namespace relational semantics::class_& c, semantics::type* w) { - if (m == 0 || call_ == erase_call || modifier_ != 0) + if (m == 0 || call_ == erase_id_call || modifier_ != 0) { object_members_base::traverse_composite (m, c); return; @@ -3075,11 +3374,12 @@ namespace relational } virtual void - traverse_container (semantics::data_member& m, semantics::type&) + traverse_container (semantics::data_member& m, semantics::type& c) { using semantics::type; bool inverse (context::inverse (m, "value")); + bool smart (!inverse && !unordered (m) && container_smart (c)); // In certain cases we don't need to do anything. // @@ -3112,7 +3412,7 @@ namespace relational throw operation_failed (); } - if (call_ != erase_call) + if (call_ != erase_id_call && (call_ != erase_obj_call || smart)) { os << "{"; @@ -3178,7 +3478,6 @@ namespace relational { os << traits << "::persist (" << endl << var << "," << endl - << "idb," << endl << "sts.container_statment_cache ()." << sts_name << ");"; break; } @@ -3186,7 +3485,6 @@ namespace relational { os << traits << "::load (" << endl << var << "," << endl - << "idb," << endl << "sts.container_statment_cache ()." << sts_name << ");"; break; } @@ -3194,21 +3492,34 @@ namespace relational { os << traits << "::update (" << endl << var << "," << endl - << "idb," << endl << "sts.container_statment_cache ()." << sts_name << ");"; break; } - case erase_call: + case erase_obj_call: { - os << traits << "::erase (" << endl - << "idb," << endl - << "sts.container_statment_cache ()." << sts_name << ");" + os << traits << "::erase (" << endl; + + if (smart) + os << "&" << var << "," << endl; + + os << "sts.container_statment_cache ()." << sts_name << ");" + << endl; + break; + } + case erase_id_call: + { + os << traits << "::erase (" << endl; + + if (smart) + os << "0," << endl; + + os << "sts.container_statment_cache ()." << sts_name << ");" << endl; break; } } - if (call_ != erase_call) + if (call_ != erase_id_call && (call_ != erase_obj_call || smart)) { // Call the modifier if we are using a proper one. // @@ -3435,9 +3746,10 @@ namespace relational // virtual void - object_extra (type&) - { - } + object_extra (type&) {} + + virtual void + container_cache_extra_args (bool /*used*/) {} virtual void object_query_statement_ctor_args (type&, -- cgit v1.1