From b2f0cd834b8f5651985357f8acbe82edd7d11c63 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 11 Oct 2011 16:52:45 +0200 Subject: Split 'in' binding into insert/update pair; rename 'out' to select Also add the initial infrastructure for the readonly members support. Right now the split insert/update bindings allows us to avoid sending object id in UPDATE statements. It will also allows us to support readonly members. --- odb/context.cxx | 60 ++++---- odb/context.hxx | 47 +++++-- odb/relational/context.hxx | 8 ++ odb/relational/header.hxx | 143 +++++++++++-------- odb/relational/mysql/source.cxx | 61 ++++++-- odb/relational/oracle/source.cxx | 55 +++++++- odb/relational/pgsql/header.cxx | 21 ++- odb/relational/pgsql/source.cxx | 111 +++++++++++---- odb/relational/source.hxx | 295 ++++++++++++++++++++++++++------------- odb/relational/sqlite/source.cxx | 56 +++++++- 10 files changed, 598 insertions(+), 259 deletions(-) diff --git a/odb/context.cxx b/odb/context.cxx index fec6457..45dd55b 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -968,61 +968,61 @@ namespace { struct column_count_impl: object_members_base { - column_count_impl (bool out) - : out_ (out), count_ (0) - { - } + typedef context::column_count_type count_type; virtual void traverse (semantics::class_& c) { - char const* key (out_ ? "out-column-count" : "in-column-count"); + if (c.count ("column-count")) + { + count_type const& bc (c.get ("column-count")); - if (c.count (key)) - count_ += c.get (key); + c_.total += bc.total; + c_.id += bc.id; + c_.inverse += bc.inverse; + c_.readonly += bc.readonly; + } else { - size_t n (count_); + count_type t (c_); object_members_base::traverse (c); - c.set (key, count_ - n); + + t.total = c_.total - t.total; + t.id = c_.id - t.id; + t.inverse = c_.inverse - t.inverse; + t.readonly = c_.readonly - t.readonly; + + c.set ("column-count", t); } } virtual void traverse_simple (semantics::data_member& m) { - if (out_ || !context::inverse (m)) - count_++; + c_.total++; + + if (m.count ("id")) + c_.id++; + + if (context::inverse (m)) + c_.inverse++; } private: - bool out_; - size_t count_; + count_type c_; }; } -size_t context:: -in_column_count (semantics::class_& c) -{ - if (!c.count ("in-column-count")) - { - column_count_impl t (false); - t.traverse (c); - } - - return c.get ("in-column-count"); -} - -size_t context:: -out_column_count (semantics::class_& c) +context::column_count_type context:: +column_count (semantics::class_& c) { - if (!c.count ("out-column-count")) + if (!c.count ("column-count")) { - column_count_impl t (true); + column_count_impl t; t.traverse (c); } - return c.get ("out-column-count"); + return c.get ("column-count"); } namespace diff --git a/odb/context.hxx b/odb/context.hxx index f91568a..ffafb43 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -216,7 +216,7 @@ public: upcase (string const&); public: - semantics::type& + static semantics::type& member_type (semantics::data_member& m, string const& key_prefix); // Predicates. @@ -234,12 +234,6 @@ public: return t.count ("view"); } - static bool - transient (semantics::data_member& m) - { - return m.count ("transient"); - } - // Check whether the type is a wrapper. Return the wrapped type if // it is a wrapper and NULL otherwise. // @@ -322,6 +316,24 @@ public: return c.abstract () || c.count ("abstract"); } + static bool + transient (semantics::data_member& m) + { + return m.count ("transient"); + } + + static bool + id (semantics::data_member& m) + { + return m.count ("id"); + } + + bool + readonly (semantics::data_member& m) + { + return m.count ("readonly"); + } + bool null (semantics::data_member&); @@ -412,11 +424,18 @@ public: // Counts and other information. // public: - static size_t - in_column_count (semantics::class_&); + struct column_count_type + { + column_count_type (): total (0), id (0), inverse (0), readonly (0) {} + + size_t total; + size_t id; + size_t inverse; + size_t readonly; + }; - static size_t - out_column_count (semantics::class_&); + static column_count_type + column_count (semantics::class_&); static semantics::data_member* id_member (semantics::class_& c) @@ -480,9 +499,9 @@ public: } static semantics::type& - container_idt (semantics::type& c) + container_idt (semantics::data_member& m) { - return *c.get ("id-tree-type"); + return member_type (m, "id"); } static semantics::type& @@ -578,7 +597,7 @@ private: composite_ (semantics::class_&); template - X + static X indirect_value (semantics::context const& c, string const& key) { typedef X (*func) (); diff --git a/odb/relational/context.hxx b/odb/relational/context.hxx index 7bff5b1..cd2bce5 100644 --- a/odb/relational/context.hxx +++ b/odb/relational/context.hxx @@ -10,6 +10,14 @@ namespace relational { + enum statement_kind + { + statement_select, + statement_insert, + statement_update, + statement_where // WHERE clause. + }; + class context: public virtual ::context { public: diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 0806042..4351db9 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -394,69 +394,79 @@ namespace relational // Figure out column counts. // - size_t data_columns (1), cond_columns (1); // One for object id. + size_t data_columns, cond_columns; - switch (ck) + if (!abst) { - case ck_ordered: + type& idt (container_idt (m)); + + if (class_* idc = composite_wrapper (idt)) + data_columns = cond_columns = column_count (*idc).total; + else + data_columns = cond_columns = 1; + + switch (ck) { - // Add one for the index. - // - if (ordered) + case ck_ordered: { - data_columns++; - - // Index is not currently used (see also bind()). + // Add one for the index. // - // cond_columns++; + if (ordered) + { + data_columns++; + + // Index is not currently used (see also bind()). + // + // cond_columns++; + } + break; } - break; - } - case ck_map: - case ck_multimap: - { - // Add some for the key. - // - size_t n; + case ck_map: + case ck_multimap: + { + // Add some for the key. + // + size_t n; - if (class_* kc = composite_wrapper (*kt)) - n = in_column_count (*kc); - else - n = 1; + if (class_* kc = composite_wrapper (*kt)) + n = column_count (*kc).total; + else + n = 1; - data_columns += n; + data_columns += n; - // Key is not currently used (see also bind()). - // - // cond_columns += n; + // Key is not currently used (see also bind()). + // + // cond_columns += n; - break; - } - case ck_set: - case ck_multiset: - { - // Not currently used (see also bind()) - // - // Value is also a key. - // - //if (class_* vc = composite_wrapper (vt)) - // cond_columns += in_column_count (*vc); - //else - // cond_columns++; + break; + } + case ck_set: + case ck_multiset: + { + // Not currently used (see also bind()) + // + // Value is also a key. + // + //if (class_* vc = composite_wrapper (vt)) + // cond_columns += column_count (*vc).total; + //else + // cond_columns++; - break; + break; + } } - } - if (class_* vc = composite_wrapper (vt)) - data_columns += in_column_count (*vc); - else - data_columns++; + if (class_* vc = composite_wrapper (vt)) + data_columns += column_count (*vc).total; + else + data_columns++; - // Store column counts for the source generator. - // - m.set ("cond-column-count", cond_columns); - m.set ("data-column-count", data_columns); + // Store column counts for the source generator. + // + m.set ("cond-column-count", cond_columns); + m.set ("data-column-count", data_columns); + } os << "// " << m.name () << endl << "//" << endl @@ -913,6 +923,8 @@ namespace relational bool auto_id (id ? id->count ("auto") : false); bool base_id (id ? &id->scope () != &c : false); // Comes from base. + column_count_type const& cc (column_count (c)); + os << "// " << c.name () << endl << "//" << endl; @@ -1034,7 +1046,8 @@ namespace relational // bind (image_type) // os << "static void" << endl - << "bind (" << bind_vector << ", image_type&, bool);" + << "bind (" << bind_vector << ", image_type&, " + << db << "::statement_kind);" << endl; // bind (id_image_type) @@ -1049,7 +1062,8 @@ namespace relational // init (image, object) // os << "static bool" << endl - << "init (image_type&, const object_type&);" + << "init (image_type&, const object_type&, " << + db << "::statement_kind);" << endl; // init (object, image) @@ -1104,18 +1118,23 @@ namespace relational // column_count // - os << "static const std::size_t in_column_count = " << - in_column_count (c) << "UL;" - << "static const std::size_t out_column_count = " << - out_column_count (c) << "UL;" + os << "static const std::size_t column_count = " << cc.total << "UL;" + << "static const std::size_t id_column_count = " << cc.id << "UL;" + << "static const std::size_t inverse_column_count = " << + cc.inverse << "UL;" + << "static const std::size_t readonly_column_count = " << + cc.readonly << "UL;" << endl; // Statements. // os << "static const char persist_statement[];" - << "static const char find_statement[];" - << "static const char update_statement[];" - << "static const char erase_statement[];"; + << "static const char find_statement[];"; + + if (cc.total != cc.id + cc.inverse + cc.readonly) + os << "static const char update_statement[];"; + + os << "static const char erase_statement[];"; if (options.generate_query ()) { @@ -1393,7 +1412,7 @@ namespace relational // column_count // os << "static const std::size_t column_count = " << - out_column_count (c) << "UL;" + column_count (c).total << "UL;" << endl; // Statements. @@ -1475,13 +1494,15 @@ namespace relational // bind (image_type) // os << "static void" << endl - << "bind (" << bind_vector << ", image_type&);" + << "bind (" << bind_vector << ", image_type&, " << + db << "::statement_kind);" << endl; // init (image, value) // os << "static bool" << endl - << "init (image_type&, const value_type&);" + << "init (image_type&, const value_type&, " << + db << "::statement_kind);" << endl; // init (value, image) diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx index bea559e..103c301 100644 --- a/odb/relational/mysql/source.cxx +++ b/odb/relational/mysql/source.cxx @@ -77,7 +77,7 @@ namespace relational // When we store a ENUM column in the MySQL database, if we bind // an integer parameter, then it is treated as an index and if we // bind a string, then it is treated as a enumerator. Everything - // would have worked well if the same logic applied to the load + // would have worked well if the same logic applied to the select // operation. That is, if we bind integer, then the database sends // the index and if we bind string then the database sends the // enumerator. Unfortunately, MySQL always sends the enumerator @@ -112,7 +112,8 @@ namespace relational // to value_traits. // - if (!out_ || column_sql_type (m, key_prefix).type != sql_type::ENUM) + if (sk_ != statement_select || + column_sql_type (m, key_prefix).type != sql_type::ENUM) { base::column (m, key_prefix, table, column); return; @@ -197,7 +198,10 @@ namespace relational << "//" << endl; if (inverse (mi.m, key_prefix_)) - os << "if (out)" + os << "if (sk == statement_select)" + << "{"; + else if (id (mi.m) || readonly (mi.m)) + os << "if (sk != statement_update)" << "{"; } @@ -210,11 +214,42 @@ namespace relational if (var_override_.empty ()) { if (semantics::class_* c = composite (mi.t)) - os << "n += " << in_column_count (*c) << "UL;"; + { + column_count_type const& cc (column_count (*c)); + + os << "n += " << cc.total << "UL"; + + // select = total + // insert = total - inverse + // update = total - inverse - readonly + // + if (cc.inverse != 0 || cc.readonly != 0) + { + os << " - (" << endl + << "sk == statement_select ? 0 : "; + + if (cc.inverse != 0) + os << cc.inverse << "UL" << endl; + + if (cc.readonly != 0) + { + if (cc.inverse != 0) + os << " + "; + + os << "(" << endl + << "sk == statement_insert ? 0 : " << + cc.readonly << "UL)"; + } + + os << ")"; + } + + os << ";"; + } else os << "n++;"; - if (inverse (mi.m, key_prefix_)) + if (inverse (mi.m, key_prefix_) || id (mi.m) || readonly (mi.m)) os << "}"; else os << endl; @@ -225,7 +260,7 @@ namespace relational traverse_composite (member_info& mi) { os << "composite_value_traits< " << mi.fq_type () << - " >::bind (b + n, " << arg << "." << mi.var << "value);"; + " >::bind (b + n, " << arg << "." << mi.var << "value, sk);"; } virtual void @@ -382,7 +417,7 @@ namespace relational post (member_info& mi) { if (semantics::class_* c = composite (mi.t)) - index_ += in_column_count (*c); + index_ += column_count (*c).total; else index_++; } @@ -514,7 +549,7 @@ namespace relational pre (member_info& mi) { // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in the 'in' binding). + // object pointers (they are not present in this binding). // if (container (mi.t) || inverse (mi.m, key_prefix_)) return false; @@ -528,6 +563,11 @@ namespace relational os << "// " << name << endl << "//" << endl; + + if (id (mi.m) || readonly (mi.m)) + // The block scope is added later, if necessary. + // + os << "if (sk == statement_insert)"; } // If this is a wrapped composite value, then we need to @@ -637,9 +677,12 @@ namespace relational virtual void traverse_composite (member_info& mi) { + // Should be a single statement or a block. + // os << "if (" << traits << "::init (" << endl << "i." << mi.var << "value," << endl - << member << "))" + << member << "," << endl + << "sk))" << "{" << "grew = true;" << "}"; diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx index e026214..dd3fe8b 100644 --- a/odb/relational/oracle/source.cxx +++ b/odb/relational/oracle/source.cxx @@ -91,7 +91,10 @@ namespace relational << "//" << endl; if (inverse (mi.m, key_prefix_)) - os << "if (out)" + os << "if (sk == statement_select)" + << "{"; + else if (id (mi.m) || readonly (mi.m)) + os << "if (sk != statement_update)" << "{"; } @@ -104,11 +107,43 @@ namespace relational if (var_override_.empty ()) { if (semantics::class_* c = composite (mi.t)) - os << "n += " << in_column_count (*c) << "UL;"; + + { + column_count_type const& cc (column_count (*c)); + + os << "n += " << cc.total << "UL"; + + // select = total + // insert = total - inverse + // update = total - inverse - readonly + // + if (cc.inverse != 0 || cc.readonly != 0) + { + os << " - (" << endl + << "sk == statement_select ? 0 : "; + + if (cc.inverse != 0) + os << cc.inverse << "UL" << endl; + + if (cc.readonly != 0) + { + if (cc.inverse != 0) + os << " + "; + + os << "(" << endl + << "sk == statement_insert ? 0 : " << + cc.readonly << "UL)"; + } + + os << ")"; + } + + os << ";"; + } else os << "n++;"; - if (inverse (mi.m, key_prefix_)) + if (inverse (mi.m, key_prefix_) || id (mi.m) || readonly (mi.m)) os << "}"; else os << endl; @@ -119,7 +154,7 @@ namespace relational traverse_composite (member_info& mi) { os << "composite_value_traits< " << mi.fq_type () << - " >::bind (b + n, " << arg << "." << mi.var << "value);"; + " >::bind (b + n, " << arg << "." << mi.var << "value, sk);"; } virtual void @@ -229,7 +264,7 @@ namespace relational << b << ".callback = &" << arg << "." << mi.var << "callback;" << b << ".context = &" << arg << "." << mi.var << "context;" - << "if (out)" << endl + << "if (sk == statement_select)" << endl << b << ".buffer = &" << arg << "." << mi.var << "lob;" << "else" << endl << b << ".size = reinterpret_cast (&" << arg << "." << @@ -263,7 +298,7 @@ namespace relational pre (member_info& mi) { // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in the 'in' binding). + // object pointers (they are not present in this binding). // if (container (mi.t) || inverse (mi.m, key_prefix_)) return false; @@ -277,6 +312,11 @@ namespace relational os << "// " << name << endl << "//" << endl; + + if (id (mi.m) || readonly (mi.m)) + // The block scope is added later, if necessary. + // + os << "if (sk == statement_insert)"; } // If this is a wrapped composite value, then we need to @@ -388,7 +428,8 @@ namespace relational { os << traits << "::init (" << endl << "i." << mi.var << "value," << endl - << member << ");"; + << member << "," << endl + << "sk);"; } virtual void diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx index 4043809..474b69c 100644 --- a/odb/relational/pgsql/header.cxx +++ b/odb/relational/pgsql/header.cxx @@ -26,12 +26,17 @@ namespace relational if (abstract (c)) return; + column_count_type const& cc (column_count (c)); + // Statement names. // os << "static const char persist_statement_name[];" - << "static const char find_statement_name[];" - << "static const char update_statement_name[];" - << "static const char erase_statement_name[];"; + << "static const char find_statement_name[];"; + + if (cc.total != cc.id + cc.inverse + cc.readonly) + os << "static const char update_statement_name[];"; + + os << "static const char erase_statement_name[];"; // Query statement name. // @@ -44,11 +49,13 @@ namespace relational // Statement types. // os << "static const unsigned int persist_statement_types[];" - << "static const unsigned int find_statement_types[];" - << "static const unsigned int update_statement_types[];" - << "static const unsigned int erase_statement_types[];" - << endl; + << "static const unsigned int find_statement_types[];"; + + if (cc.total != cc.id + cc.inverse + cc.readonly) + os << "static const unsigned int update_statement_types[];"; + os << "static const unsigned int erase_statement_types[];" + << endl; } virtual void diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index c56e1e7..c5df9bd 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -104,16 +104,21 @@ namespace relational struct statement_oids: object_columns_base, context { - statement_oids (bool out): out_ (out) {} + statement_oids (statement_kind sk): sk_ (sk) {} virtual bool traverse_column (semantics::data_member& m, std::string const&, bool first) { - // Ignore inverse object pointers if we are generating 'in' columns. + // Ignore certain columns depending on what kind statement we are + // generating. See object_columns in common source generator for + // details. // - if (!out_ && inverse (m) != 0) + if (inverse (m) && sk_ != statement_select) + return false; + + if ((id (m) || readonly (m)) && sk_ == statement_update) return false; if (!first) @@ -125,7 +130,7 @@ namespace relational } private: - bool out_; + statement_kind sk_; }; // @@ -159,7 +164,10 @@ namespace relational << "//" << endl; if (inverse (mi.m, key_prefix_)) - os << "if (out)" + os << "if (sk == statement_select)" + << "{"; + else if (id (mi.m) || readonly (mi.m)) + os << "if (sk != statement_update)" << "{"; } @@ -172,11 +180,42 @@ namespace relational if (var_override_.empty ()) { if (semantics::class_* c = composite (mi.t)) - os << "n += " << in_column_count (*c) << "UL;"; + { + column_count_type const& cc (column_count (*c)); + + os << "n += " << cc.total << "UL"; + + // select = total + // insert = total - inverse + // update = total - inverse - readonly + // + if (cc.inverse != 0 || cc.readonly != 0) + { + os << " - (" << endl + << "sk == statement_select ? 0 : "; + + if (cc.inverse != 0) + os << cc.inverse << "UL" << endl; + + if (cc.readonly != 0) + { + if (cc.inverse != 0) + os << " + "; + + os << "(" << endl + << "sk == statement_insert ? 0 : " << + cc.readonly << "UL)"; + } + + os << ")"; + } + + os << ";"; + } else os << "n++;"; - if (inverse (mi.m, key_prefix_)) + if (inverse (mi.m, key_prefix_) || id (mi.m) || readonly (mi.m)) os << "}"; else os << endl; @@ -187,7 +226,7 @@ namespace relational traverse_composite (member_info& mi) { os << "composite_value_traits< " << mi.fq_type () << - " >::bind (b + n, " << arg << "." << mi.var << "value);"; + " >::bind (b + n, " << arg << "." << mi.var << "value, sk);"; } virtual void @@ -309,7 +348,7 @@ namespace relational post (member_info& mi) { if (semantics::class_* c = composite (mi.t)) - index_ += in_column_count (*c); + index_ += column_count (*c).total; else index_++; } @@ -415,7 +454,7 @@ namespace relational pre (member_info& mi) { // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in the 'in' binding). + // object pointers (they are not present in this binding). // if (container (mi.t) || inverse (mi.m, key_prefix_)) return false; @@ -429,6 +468,11 @@ namespace relational os << "// " << name << endl << "//" << endl; + + if (id (mi.m) || readonly (mi.m)) + // The block scope is added later, if necessary. + // + os << "if (sk == statement_insert)"; } // If this is a wrapped composite value, then we need to @@ -538,9 +582,12 @@ namespace relational virtual void traverse_composite (member_info& mi) { + // Should be a single statement or a block. + // os << "if (" << traits << "::init (" << endl << "i." << mi.var << "value," << endl - << member << "))" + << member << "," << endl + << "sk))" << "{" << "grew = true;" << "}"; @@ -887,21 +934,28 @@ namespace relational if (abstract (c)) return; + column_count_type const& cc (column_count (c)); + string const& n (c.fq_name ()); string traits ("access::object_traits< " + n + " >::"); string const& fn (flat_name (n)); string name_decl ("const char " + traits); os << name_decl << endl - << "persist_statement_name[] = " << strlit (fn + "_persist") << ";" + << "persist_statement_name[] = " << strlit (fn + "_persist") << + ";" << endl << name_decl << endl << "find_statement_name[] = " << strlit (fn + "_find") << ";" - << endl - << name_decl << endl - << "update_statement_name[] = " << strlit (fn + "_update") << ";" - << endl - << name_decl << endl + << endl; + + if (cc.total != cc.id + cc.inverse + cc.readonly) + os << name_decl << endl + << "update_statement_name[] = " << strlit (fn + "_update") << + ";" + << endl; + + os << name_decl << endl << "erase_statement_name[] = " << strlit (fn + "_erase") << ";" << endl; @@ -930,7 +984,7 @@ namespace relational << "persist_statement_types[] =" << "{"; - instance st (false); + instance st (statement_insert); st->traverse (c); os << "};"; @@ -943,7 +997,7 @@ namespace relational << "find_statement_types[] =" << "{"; - instance st (true); + instance st (statement_select); st->traverse_column (*id_m, "", true); os << "};"; @@ -951,14 +1005,21 @@ namespace relational // update_statement_types. // + if (cc.total != cc.id + cc.inverse + cc.readonly) { os << oid_decl << endl << "update_statement_types[] =" << "{"; - instance st (false); - st->traverse (c); - st->traverse_column (*id_m, "", false); + { + instance st (statement_update); + st->traverse (c); + } + + { + instance st (statement_where); + st->traverse_column (*id_m, "", false); + } os << "};"; } @@ -970,7 +1031,7 @@ namespace relational << "erase_statement_types[] =" << "{"; - instance st (true); + instance st (statement_where); st->traverse_column (*id_m, "", true); os << "};"; @@ -1130,7 +1191,7 @@ namespace relational if (semantics::class_* ktc = composite_wrapper (container_kt (t))) { - instance st (false); + instance st (statement_insert); st->traverse (m, *ktc, "key", "key"); os << ","; } @@ -1148,7 +1209,7 @@ namespace relational if (semantics::class_* vtc = composite_wrapper (vt)) { - instance st (false); + instance st (statement_insert); st->traverse (m, *vtc, "value", "value"); } else diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 99f6073..55f94f5 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -49,17 +49,17 @@ namespace relational { typedef object_columns base; - object_columns (bool out, + object_columns (statement_kind sk, bool last = true, query_parameters* param = 0) - : out_ (out), param_ (param), last_ (last) + : sk_ (sk), param_ (param), last_ (last) { } object_columns (std::string const& table_qname, - bool out, + statement_kind sk, bool last = true) - : out_ (out), param_ (0), table_name_ (table_qname), last_ (last) + : sk_ (sk), param_ (0), table_name_ (table_qname), last_ (last) { } @@ -70,9 +70,15 @@ namespace relational { semantics::data_member* im (inverse (m)); - // Ignore inverse object pointers if we are generating 'in' columns. + // Ignore certain columns depending on what kind statement we are + // generating. Columns corresponding to the inverse members are + // only present in the select statements while the id and readonly + // columns are not present in the update statements. // - if (im != 0 && !out_) + if (im != 0 && sk_ != statement_select) + return false; + + if ((id (m) || readonly (m)) && sk_ == statement_update) return false; if (!first) @@ -155,7 +161,7 @@ namespace relational } protected: - bool out_; + statement_kind sk_; query_parameters* param_; string line_; string table_name_; @@ -540,14 +546,39 @@ namespace relational os << "// " << c.name () << " base" << endl << "//" << 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 << (obj ? "object" : "composite_value") << "_traits< " << + c.fq_name () << " >::bind (b + n, i, sk);"; + + column_count_type const& cc (column_count (c)); + + os << "n += " << cc.total << "UL"; + + // select = total + // insert = total - inverse + // update = total - inverse - id - readonly + // + if (cc.inverse != 0 || cc.id != 0 || cc.readonly != 0) + { + os << " - (" << endl + << "sk == statement_select ? 0 : "; + + if (cc.inverse != 0) + os << cc.inverse << "UL" << endl; + + if (cc.id != 0 || cc.readonly != 0) + { + if (cc.inverse != 0) + os << " + "; + + os << "(" << endl + << "sk == statement_insert ? 0 : " << + cc.id + cc.readonly << "UL)"; + } + + os << ")"; + } - os << "n += " << in_column_count (c) << "UL;" + os << ";" << endl; } }; @@ -602,7 +633,7 @@ namespace relational << "grew = true;" << endl; - index_ += in_column_count (c); + index_ += column_count (c).total; } protected: @@ -655,7 +686,7 @@ namespace relational os << "// " << c.name () << " base" << endl << "//" << endl << "if (" << (obj ? "object" : "composite_value") << "_traits< " << - c.fq_name () << " >::init (i, o))" << endl + c.fq_name () << " >::init (i, o, sk))" << endl << "grew = true;" << endl; } @@ -905,7 +936,7 @@ namespace relational { if (ordered) { - instance t (table, false, false); + instance t (table, statement_select, false); string const& col (column_qname (m, "index", "index")); t->column (m, "index", table, col); t->flush (); @@ -915,7 +946,7 @@ namespace relational case ck_map: case ck_multimap: { - instance t (table, false, false); + instance t (table, statement_select, false); if (semantics::class_* ckt = composite_wrapper (*kt)) t->traverse (m, *ckt, "key", "key"); @@ -934,7 +965,7 @@ namespace relational } } - instance t (table, false); + instance t (table, statement_select); if (semantics::class_* cvt = composite_wrapper (vt)) t->traverse (m, *cvt, "value", "value"); @@ -982,7 +1013,7 @@ namespace relational { if (ordered) { - instance t (false, false); + instance t (statement_insert, false); t->column (m, "index", "", column_qname (m, "index", "index")); t->flush (); } @@ -991,7 +1022,7 @@ namespace relational case ck_map: case ck_multimap: { - instance t (false, false); + instance t (statement_insert, false); if (semantics::class_* ckt = composite_wrapper (*kt)) t->traverse (m, *ckt, "key", "key"); @@ -1009,7 +1040,7 @@ namespace relational } } - instance t (false); + instance t (statement_insert); if (semantics::class_* cvt = composite_wrapper (vt)) t->traverse (m, *cvt, "value", "value"); @@ -1089,6 +1120,8 @@ namespace relational // 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: @@ -1135,6 +1168,15 @@ namespace relational << "std::size_t id_size," << endl << "data_image_type& d)" << "{" + << "using namespace " << db << ";" + << endl + // In the case of containers, insert and select column sets are + // the same since we can't have inverse members as container + // elements. + // + << "statement_kind sk (statement_select);" + << "ODB_POTENTIALLY_UNUSED (sk);" + << endl << "size_t n (0);" << endl; @@ -1170,7 +1212,7 @@ namespace relational bm->traverse (m); if (semantics::class_* c = composite_wrapper (*kt)) - os << "n += " << in_column_count (*c) << "UL;" + os << "n += " << column_count (*c).total << "UL;" << endl; else os << "n++;" @@ -1263,11 +1305,36 @@ namespace relational "const value_type& v)"; else os << "init (data_image_type& i, const value_type& v)"; + break; + } + case ck_map: + case ck_multimap: + { + os << "init (data_image_type& i, const key_type& k, " << + "const value_type& v)"; + break; + } + case ck_set: + case ck_multiset: + { + os << "init (data_image_type& i, const value_type& v)"; + break; + } + } - os << "{" - << "bool grew (false);" - << endl; + os << "{" + << "using namespace " << db << ";" + << endl + << "statement_kind sk (statement_insert);" + << "ODB_POTENTIALLY_UNUSED (sk);" + << endl + << "bool grew (false);" + << endl; + switch (ck) + { + case ck_ordered: + { if (ordered) { os << "// index" << endl @@ -1277,18 +1344,12 @@ namespace relational "index_", "j", *it, "index_type", "index"); im->traverse (m); } - break; } case ck_map: case ck_multimap: { - os << "init (data_image_type& i, const key_type& k, " << - "const value_type& v)" - << "{" - << "bool grew (false);" - << endl - << "// key" << endl + os << "// key" << endl << "//" << endl; instance im ( @@ -1300,11 +1361,6 @@ namespace relational case ck_set: case ck_multiset: { - os << "init (data_image_type& i, const value_type& v)" - << "{" - << "bool grew (false);" - << endl; - break; } } @@ -2124,6 +2180,8 @@ namespace relational grow_id = id ? context::grow (*id) : false; } + column_count_type const& cc (column_count (c)); + os << "// " << c.name () << endl << "//" << endl << endl; @@ -2199,9 +2257,12 @@ namespace relational // bind (image_type) // os << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b, image_type& i, bool out)" + << "bind (" << bind_vector << " b, image_type& i, " << + db << "::statement_kind sk)" << "{" - << "ODB_POTENTIALLY_UNUSED (out);" + << "ODB_POTENTIALLY_UNUSED (sk);" + << endl + << "using namespace " << db << ";" << endl << "std::size_t n (0);" << endl; @@ -2226,10 +2287,14 @@ namespace relational // init (image, object) // os << "bool " << traits << "::" << endl - << "init (image_type& i, const object_type& o)" + << "init (image_type& i, const object_type& o, " << + db << "::statement_kind sk)" << "{" << "ODB_POTENTIALLY_UNUSED (i);" << "ODB_POTENTIALLY_UNUSED (o);" + << "ODB_POTENTIALLY_UNUSED (sk);" + << endl + << "using namespace " << db << ";" << endl << "bool grew (false);" << endl; @@ -2321,7 +2386,7 @@ namespace relational "=" << endl << strlit ("INSERT INTO " + table_qname(c) + " (") << endl; - instance ct (false); + instance ct (statement_insert); ct->traverse (c); string values; @@ -2343,7 +2408,7 @@ namespace relational os << "const char " << traits << "::find_statement[] =" << endl << strlit ("SELECT ") << endl; - instance t (table, true); + instance t (table, statement_select); t->traverse (c); os << strlit (" FROM " + table) << endl; @@ -2361,13 +2426,14 @@ namespace relational // update_statement // + if (cc.total != cc.id + cc.inverse + cc.readonly) { os << "const char " << traits << "::update_statement[] " << "=" << endl << strlit ("UPDATE " + table + " SET ") << endl; instance qp; - instance t (false, true, qp.get ()); + instance t (statement_update, true, qp.get ()); t->traverse (c); os << strlit (" WHERE " + id_col + "=" + qp->next ()) << ";" @@ -2396,7 +2462,7 @@ namespace relational << strlit ("SELECT ") << endl; { - instance oc (table, true); + instance oc (table, statement_select); oc->traverse (c); } @@ -2441,9 +2507,9 @@ namespace relational << "object_statements< object_type >& sts (" << endl << "conn.statement_cache ().find_object ());" << "image_type& im (sts.image ());" - << "binding& imb (sts.in_image_binding ());" + << "binding& imb (sts.insert_image_binding ());" << endl - << "if (init (im, obj))" << endl + << "if (init (im, obj, statement_insert))" << endl << "im.version++;" << endl; @@ -2455,10 +2521,11 @@ namespace relational os << endl; } - os << "if (im.version != sts.in_image_version () || imb.version == 0)" + os << "if (im.version != sts.insert_image_version () || " << + "imb.version == 0)" << "{" - << "bind (imb.bind, im, false);" - << "sts.in_image_version (im.version);" + << "bind (imb.bind, im, statement_insert);" + << "sts.insert_image_version (im.version);" << "imb.version++;" << "}" << "insert_statement& st (sts.persist_statement ());" @@ -2504,42 +2571,59 @@ namespace relational << "conn.statement_cache ().find_object ());" << endl; - // Initialize id image. - // - os << "id_image_type& i (sts.id_image ());" - << "init (i, obj." << id->name () << ");" - << endl; + if (cc.total != cc.id + cc.inverse + cc.readonly) + { + // Initialize id image. + // + os << "id_image_type& i (sts.id_image ());" + << "init (i, obj." << id->name () << ");" + << endl; - os << "binding& idb (sts.id_image_binding ());" - << "if (i.version != sts.id_image_version () || idb.version == 0)" - << "{" - << "bind (idb.bind, i);" - << "sts.id_image_version (i.version);" - << "idb.version++;" - << "}"; + os << "binding& idb (sts.id_image_binding ());" + << "if (i.version != sts.id_image_version () || idb.version == 0)" + << "{" + << "bind (idb.bind, i);" + << "sts.id_image_version (i.version);" + << "idb.version++;" + << "}"; - // Initialize data image. - // - os << "image_type& im (sts.image ());" - << "binding& imb (sts.in_image_binding ());" - << endl - << "if (init (im, obj))" << endl - << "im.version++;" - << endl - << "if (im.version != sts.in_image_version () || imb.version == 0)" - << "{" - << "bind (imb.bind, im, false);" - << "sts.in_image_version (im.version);" - << "imb.version++;" - << "}" - << "sts.update_statement ().execute ();"; + // Initialize data image. + // + os << "image_type& im (sts.image ());" + << "binding& imb (sts.update_image_binding ());" + << endl + << "if (init (im, obj, statement_update))" << endl + << "im.version++;" + << endl + << "if (im.version != sts.update_image_version () || " << + "imb.version == 0)" + << "{" + << "bind (imb.bind, im, statement_update);" + << "sts.update_image_version (im.version);" + << "imb.version++;" + << "}" + << "sts.update_statement ().execute ();"; + } + else + { + // We don't have any columns to update. Note that we still have + // to make sure this object exists in the database. For that we + // will run the SELECT query using the find_() function. + // + os << "if (!find_ (sts, obj." << id->name () << "))" << endl + << "throw object_not_persistent ();"; if (straight_containers) - { - os << endl; - instance t (container_calls::update_call); - t->traverse (c); - } + os << endl + << "binding& idb (sts.id_image_binding ());"; + } + + if (straight_containers) + { + os << endl; + instance t (container_calls::update_call); + t->traverse (c); + } os << "}"; @@ -2702,12 +2786,13 @@ namespace relational // Rebind data image. // os << "image_type& im (sts.image ());" - << "binding& imb (sts.out_image_binding ());" + << "binding& imb (sts.select_image_binding ());" << endl - << "if (im.version != sts.out_image_version () || imb.version == 0)" + << "if (im.version != sts.select_image_version () || " << + "imb.version == 0)" << "{" - << "bind (imb.bind, im, true);" - << "sts.out_image_version (im.version);" + << "bind (imb.bind, im, statement_select);" + << "sts.select_image_version (im.version);" << "imb.version++;" << "}" << "select_statement& st (sts.find_statement ());" @@ -2718,13 +2803,13 @@ namespace relational os << endl << "if (r == select_statement::truncated)" << "{" - << "if (grow (im, sts.out_image_truncated ()))" << endl + << "if (grow (im, sts.select_image_truncated ()))" << endl << "im.version++;" << endl - << "if (im.version != sts.out_image_version ())" + << "if (im.version != sts.select_image_version ())" << "{" - << "bind (imb.bind, im, true);" - << "sts.out_image_version (im.version);" + << "bind (imb.bind, im, statement_select);" + << "sts.select_image_version (im.version);" << "imb.version++;" << "st.refetch ();" << "}" @@ -2768,12 +2853,13 @@ namespace relational << "conn.statement_cache ().find_object ());" << endl << "image_type& im (sts.image ());" - << "binding& imb (sts.out_image_binding ());" + << "binding& imb (sts.select_image_binding ());" << endl - << "if (im.version != sts.out_image_version () || imb.version == 0)" + << "if (im.version != sts.select_image_version () || " << + "imb.version == 0)" << "{" - << "bind (imb.bind, im, true);" - << "sts.out_image_version (im.version);" + << "bind (imb.bind, im, statement_select);" + << "sts.select_image_version (im.version);" << "imb.version++;" << "}" << "shared_ptr st (" << endl @@ -3077,8 +3163,10 @@ namespace relational os << "void " << traits << "::" << endl << "bind (" << bind_vector << " b, image_type& i)" << "{" - << "bool out (true);" //@@ Try to get rid of this. - << "ODB_POTENTIALLY_UNUSED (out);" + << "using namespace " << db << ";" + << endl + << db << "::statement_kind sk (statement_select);" + << "ODB_POTENTIALLY_UNUSED (sk);" << endl << "std::size_t n (0);" << endl; @@ -3765,10 +3853,14 @@ namespace relational // bind (image_type) // os << "void " << traits << "::" << endl - << "bind (" << bind_vector << " b, image_type& i)" + << "bind (" << bind_vector << " b, image_type& i, " << + db << "::statement_kind sk)" << "{" << "ODB_POTENTIALLY_UNUSED (b);" << "ODB_POTENTIALLY_UNUSED (i);" + << "ODB_POTENTIALLY_UNUSED (sk);" + << endl + << "using namespace " << db << ";" << endl << "std::size_t n (0);" << "ODB_POTENTIALLY_UNUSED (n);" @@ -3782,10 +3874,14 @@ namespace relational // init (image, value) // os << "bool " << traits << "::" << endl - << "init (image_type& i, const value_type& o)" + << "init (image_type& i, const value_type& o, " << + db << "::statement_kind sk)" << "{" << "ODB_POTENTIALLY_UNUSED (i);" << "ODB_POTENTIALLY_UNUSED (o);" + << "ODB_POTENTIALLY_UNUSED (sk);" + << endl + << "using namespace " << db << ";" << endl << "bool grew (false);" << endl; @@ -3867,7 +3963,8 @@ namespace relational os << endl; - os << "#include " << endl + os << "#include " << endl + << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx index 8b02e6c..89173dd 100644 --- a/odb/relational/sqlite/source.cxx +++ b/odb/relational/sqlite/source.cxx @@ -49,7 +49,10 @@ namespace relational << "//" << endl; if (inverse (mi.m, key_prefix_)) - os << "if (out)" + os << "if (sk == statement_select)" + << "{"; + else if (id (mi.m) || readonly (mi.m)) + os << "if (sk != statement_update)" << "{"; } @@ -62,11 +65,42 @@ namespace relational if (var_override_.empty ()) { if (semantics::class_* c = composite (mi.t)) - os << "n += " << in_column_count (*c) << "UL;"; + { + column_count_type const& cc (column_count (*c)); + + os << "n += " << cc.total << "UL"; + + // select = total + // insert = total - inverse + // update = total - inverse - readonly + // + if (cc.inverse != 0 || cc.readonly != 0) + { + os << " - (" << endl + << "sk == statement_select ? 0 : "; + + if (cc.inverse != 0) + os << cc.inverse << "UL" << endl; + + if (cc.readonly != 0) + { + if (cc.inverse != 0) + os << " + "; + + os << "(" << endl + << "sk == statement_insert ? 0 : " << + cc.readonly << "UL)"; + } + + os << ")"; + } + + os << ";"; + } else os << "n++;"; - if (inverse (mi.m, key_prefix_)) + if (inverse (mi.m, key_prefix_) || id (mi.m) || readonly (mi.m)) os << "}"; else os << endl; @@ -77,7 +111,7 @@ namespace relational traverse_composite (member_info& mi) { os << "composite_value_traits< " << mi.fq_type () << - " >::bind (b + n, " << arg << "." << mi.var << "value);"; + " >::bind (b + n, " << arg << "." << mi.var << "value, sk);"; } virtual void @@ -158,7 +192,7 @@ namespace relational post (member_info& mi) { if (semantics::class_* c = composite (mi.t)) - index_ += in_column_count (*c); + index_ += column_count (*c).total; else index_++; } @@ -223,7 +257,7 @@ namespace relational pre (member_info& mi) { // Ignore containers (they get their own table) and inverse - // object pointers (they are not present in the 'in' binding). + // object pointers (they are not present in this binding). // if (container (mi.t) || inverse (mi.m, key_prefix_)) return false; @@ -237,6 +271,11 @@ namespace relational os << "// " << name << endl << "//" << endl; + + if (id (mi.m) || readonly (mi.m)) + // The block scope is added later, if necessary. + // + os << "if (sk == statement_insert)"; } // If this is a wrapped composite value, then we need to @@ -345,9 +384,12 @@ namespace relational virtual void traverse_composite (member_info& mi) { + // Should be a single statement or a block. + // os << "if (" << traits << "::init (" << endl << "i." << mi.var << "value," << endl - << member << "))" + << member << "," << endl + << "sk))" << "{" << "grew = true;" << "}"; -- cgit v1.1