From f3f682c074117fda84bf51a4ce9a378d950a04de Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 30 Aug 2013 06:06:26 +0200 Subject: Statement processing/optimization base work --- odb/context.cxx | 6 + odb/context.hxx | 2 + odb/header.cxx | 6 +- odb/relational/header.cxx | 7 +- odb/relational/header.hxx | 10 + odb/relational/mssql/header.cxx | 6 +- odb/relational/mssql/source.cxx | 54 ++--- odb/relational/oracle/source.cxx | 27 ++- odb/relational/pgsql/source.cxx | 42 ++-- odb/relational/source.cxx | 441 ++++++++++++++++++++++++--------------- odb/relational/source.hxx | 288 +++++++++++++++---------- 11 files changed, 547 insertions(+), 342 deletions(-) (limited to 'odb') diff --git a/odb/context.cxx b/odb/context.cxx index 35433c9..5fc14d4 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -630,12 +630,17 @@ context (ostream& os_, ops.schema_format ()[db].count (schema_format::separate)), multi_static (ops.multi_database () == multi_database::static_), multi_dynamic (ops.multi_database () == multi_database::dynamic), + force_versioned (false), top_object (data_->top_object_), cur_object (data_->cur_object_) { assert (current_ == 0); current_ = this; + // Write boolean values as true/false. + // + os.setf (ios_base::boolalpha); + // Export control. // if (!ops.export_symbol ()[db].empty ()) @@ -731,6 +736,7 @@ context () separate_schema (current ().separate_schema), multi_static (current ().multi_static), multi_dynamic (current ().multi_dynamic), + force_versioned (current ().force_versioned), top_object (current ().top_object), cur_object (current ().cur_object) { diff --git a/odb/context.hxx b/odb/context.hxx index be612f7..df32cdd 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -1460,6 +1460,8 @@ public: bool multi_static; bool multi_dynamic; + bool force_versioned; // Force statement processing for debugging. + // Outermost object or view currently being traversed. // semantics::class_*& top_object; diff --git a/odb/header.cxx b/odb/header.cxx index f09c1e8..4c58774 100644 --- a/odb/header.cxx +++ b/odb/header.cxx @@ -91,7 +91,7 @@ traverse_object (type& c) // polymorphic, root_type, base_type, etc. // - os << "static const bool polymorphic = " << (poly ? "true" : "false") << ";" + os << "static const bool polymorphic = " << poly << ";" << endl; if (poly) @@ -176,7 +176,7 @@ traverse_object (type& c) } os << endl - << "static const bool auto_id = " << (auto_id ? "true;" : "false;"); + << "static const bool auto_id = " << auto_id << ";"; } os << endl; @@ -193,7 +193,7 @@ traverse_object (type& c) // abstract // - os << "static const bool abstract = " << (abst ? "true" : "false") << ";" + os << "static const bool abstract = " << abst << ";" << endl; // id () diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx index da7f80c..9bf6f5e 100644 --- a/odb/relational/header.cxx +++ b/odb/relational/header.cxx @@ -27,7 +27,6 @@ traverse_object (type& c) bool reuse_abst (abst && !poly); string const& type (class_fq_name (c)); - column_count_type const& cc (column_count (c)); // Sections. // @@ -325,6 +324,9 @@ traverse_object (type& c) return; } + column_count_type const& cc (column_count (c)); + bool versioned (force_versioned); + // Statements typedefs. // if (poly) @@ -403,6 +405,9 @@ traverse_object (type& c) cc.separate_update << "UL;" << endl; + os << "static const bool versioned = " << versioned << ";" + << endl; + // Statements. // os << "static const char persist_statement[];"; diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 4616543..0620a98 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -242,6 +242,7 @@ namespace relational // Figure out column counts. // size_t id_columns, value_columns, data_columns, cond_columns; + bool versioned; if (!reuse_abst) { @@ -323,6 +324,8 @@ namespace relational data_columns += value_columns; } + versioned = force_versioned; + // Store column counts for the source generator. // m.set ("id-column-count", id_columns); @@ -369,6 +372,9 @@ namespace relational data_columns << "UL;" << endl; + os << "static const bool versioned = " << versioned << ";" + << endl; + // Statements. // os << "static const char insert_statement[];" @@ -986,6 +992,7 @@ namespace relational // column_count // column_count_type const& cc (column_count (poly ? *poly_root : c_)); + bool versioned (force_versioned); // Generate load and update column counts even when they are zero so // that we can instantiate section_statements. @@ -1003,6 +1010,9 @@ namespace relational (update ? s.total - s.inverse - s.readonly : 0) << "UL;" << endl; + os << "static const bool versioned = " << versioned << ";" + << endl; + // Statements. // if (load || load_opt) diff --git a/odb/relational/mssql/header.cxx b/odb/relational/mssql/header.cxx index 5601755..f943a8a 100644 --- a/odb/relational/mssql/header.cxx +++ b/odb/relational/mssql/header.cxx @@ -40,8 +40,7 @@ namespace relational rv = (t.type == sql_type::ROWVERSION); } - os << "static const bool rowversion = " << - (rv ? "true" : "false") << ";" + os << "static const bool rowversion = " << rv << ";" << endl; } }; @@ -66,8 +65,7 @@ namespace relational rv = (t.type == sql_type::ROWVERSION); } - os << "static const bool rowversion = " << - (rv ? "true" : "false") << ";" + os << "static const bool rowversion = " << rv << ";" << endl; } }; diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx index 837313a..ffc5897 100644 --- a/odb/relational/mssql/source.cxx +++ b/odb/relational/mssql/source.cxx @@ -873,22 +873,25 @@ namespace relational : "sts.update_statement ().version ()"; } - virtual void + virtual string update_statement_extra (user_section&) { + string r; + semantics::data_member* ver (optimistic (c_)); if (ver == 0 || parse_sql_type (column_type (*ver), *ver).type != sql_type::ROWVERSION) - return; + return r; // Long data & SQL Server 2005 incompatibility is detected // in persist_statement_extra. // - os << strlit ( - " OUTPUT INSERTED." + convert_from ( - column_qname (*ver, column_prefix ()), *ver)) << endl; + r = "OUTPUT INSERTED." + + convert_from (column_qname (*ver, column_prefix ()), *ver); + + return r; } }; entry section_traits_; @@ -930,11 +933,13 @@ namespace relational os << "st.stream_result ();"; } - virtual void + virtual string persist_statement_extra (type& c, relational::query_parameters&, persist_position p) { + string r; + type* poly_root (polymorphic (c)); bool poly_derived (poly_root != 0 && poly_root != &c); @@ -942,7 +947,7 @@ namespace relational // auto id/version are handled by the root. // if (poly_derived) - return; + return r; // See if we have auto id or ROWVERSION version. // @@ -960,7 +965,7 @@ namespace relational } if (id == 0 && ver == 0) - return; + return r; // SQL Server 2005 has a bug that causes it to fail on an // INSERT statement with the OUTPUT clause if data for one @@ -996,23 +1001,21 @@ namespace relational throw operation_failed (); } - os << endl - << strlit ("; SELECT " + - convert_from ("SCOPE_IDENTITY()", *id)); + r = "; SELECT " + convert_from ("SCOPE_IDENTITY()", *id); } - return; + return r; } } if (p == persist_after_columns) { - string s (" OUTPUT "); + r = "OUTPUT "; // Top-level auto id column. // if (id != 0) - s += "INSERTED." + convert_from ( + r += "INSERTED." + convert_from ( column_qname (*id, column_prefix ()), *id); // Top-level version column. @@ -1020,19 +1023,21 @@ namespace relational if (ver != 0) { if (id != 0) - s += ','; + r += ','; - s += "INSERTED." + convert_from ( + r += "INSERTED." + convert_from ( column_qname (*ver, column_prefix ()), *ver); } - - os << strlit (s) << endl; } + + return r; } - virtual void + virtual string update_statement_extra (type& c) { + string r; + type* poly_root (polymorphic (c)); bool poly_derived (poly_root != 0 && poly_root != &c); @@ -1040,21 +1045,22 @@ namespace relational // version is handled by the root. // if (poly_derived) - return; + return r; semantics::data_member* ver (optimistic (c)); if (ver == 0 || parse_sql_type (column_type (*ver), *ver).type != sql_type::ROWVERSION) - return; + return r; // Long data & SQL Server 2005 incompatibility is detected // in persist_statement_extra. // - os << strlit ( - " OUTPUT INSERTED." + convert_from ( - column_qname (*ver, column_prefix ()), *ver)) << endl; + r = "OUTPUT INSERTED." + + convert_from (column_qname (*ver, column_prefix ()), *ver); + + return r; } virtual void diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx index 2fc2ad2..3a6b46a 100644 --- a/odb/relational/oracle/source.cxx +++ b/odb/relational/oracle/source.cxx @@ -595,30 +595,29 @@ namespace relational os << "st.stream_result ();"; } - virtual void + virtual string persist_statement_extra (type& c, relational::query_parameters& qp, persist_position p) { - if (p != persist_after_values) - return; + string r; - semantics::data_member* id (id_member (c)); + if (p == persist_after_values) + { + semantics::data_member* id (id_member (c)); - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); + type* poly_root (polymorphic (c)); + bool poly_derived (poly_root != 0 && poly_root != &c); - if (id != 0 && !poly_derived && id->count ("auto")) - { // Top-level auto id. // - os << endl - << strlit (" RETURNING " + - convert_from (column_qname (*id, column_prefix ()), - *id) + - " INTO " + - qp.next ()); + if (id != 0 && !poly_derived && id->count ("auto")) + r = "RETURNING " + + convert_from (column_qname (*id, column_prefix ()), *id) + + " INTO " + qp.next (); } + + return r; } }; entry class_entry_; diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index d5fe8fd..7c5f2f6 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -631,28 +631,28 @@ namespace relational { class_ (base const& x): base (x) {} - virtual void + virtual string persist_statement_extra (type& c, relational::query_parameters&, persist_position p) { - if (p != persist_after_values) - return; + string r; - semantics::data_member* id (id_member (c)); + if (p == persist_after_values) + { + semantics::data_member* id (id_member (c)); - type* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); + type* poly_root (polymorphic (c)); + bool poly_derived (poly_root != 0 && poly_root != &c); - if (id != 0 && !poly_derived && id->count ("auto")) - { // Top-level auto id. // - os << endl - << strlit (" RETURNING " + - convert_from (column_qname (*id, column_prefix ()), - *id)); + if (id != 0 && !poly_derived && id->count ("auto")) + r = "RETURNING " + + convert_from (column_qname (*id, column_prefix ()), *id); } + + return r; } virtual void @@ -847,7 +847,10 @@ namespace relational } virtual void - object_query_statement_ctor_args (type&, string const& q, bool prep) + object_query_statement_ctor_args (type&, + string const& q, + bool process, + bool prep) { os << "sts.connection ()," << endl; @@ -856,7 +859,9 @@ namespace relational else os << "query_statement_name," << endl; - os << "query_statement + " << q << ".clause ()," << endl + os << "text," << endl + << process << "," << endl // Process. + << "true," << endl // Optimize. << q << ".parameter_types ()," << endl << q << ".parameter_count ()," << endl << q << ".parameters_binding ()," << endl @@ -868,14 +873,17 @@ namespace relational { os << "conn," << endl << "erase_query_statement_name," << endl - << "erase_query_statement + q.clause ()," << endl + << "text," << endl << "q.parameter_types ()," << endl << "q.parameter_count ()," << endl << "q.parameters_binding ()"; } virtual void - view_query_statement_ctor_args (type&, string const& q, bool prep) + view_query_statement_ctor_args (type&, + string const& q, + bool process, + bool prep) { os << "sts.connection ()," << endl; @@ -885,6 +893,8 @@ namespace relational os << "query_statement_name," << endl; os << q << ".clause ()," << endl + << process << "," << endl // Process. + << "true," << endl // Optimize. << q << ".parameter_types ()," << endl << q << ".parameter_count ()," << endl << q << ".parameters_binding ()," << endl diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index df804d2..3805be2 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -477,6 +477,8 @@ traverse_object (type& c) if (reuse_abst) return; + bool versioned (force_versioned); + // // Containers (concrete). // @@ -613,6 +615,8 @@ traverse_object (type& c) // persist_statement // { + string sep (versioned ? "\n" : " "); + statement_columns sc; { statement_kind sk (statement_insert); // Imperfect forwarding. @@ -624,30 +628,52 @@ traverse_object (type& c) bool dv (sc.empty ()); // The DEFAULT VALUES syntax. os << "const char " << traits << "::persist_statement[] =" << endl - << strlit ("INSERT INTO " + qtable + (dv ? "" : " (")) << endl; + << strlit ("INSERT INTO " + qtable + sep) << endl; - for (statement_columns::const_iterator i (sc.begin ()), + for (statement_columns::const_iterator b (sc.begin ()), i (b), e (sc.end ()); i != e;) { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : ")")) << endl; + string s; + + if (i == b) + s += '('; + s += i->column; + s += (++i != e ? ',' : ')'); + s += sep; + + os << strlit (s) << endl; } instance qp (table); - persist_statement_extra (c, *qp, persist_after_columns); + string extra (persist_statement_extra (c, *qp, persist_after_columns)); + + if (!extra.empty ()) + os << strlit (extra + sep) << endl; + string values; if (!dv) { - string values; - instance pt (values, *qp); + os << strlit ("VALUES" + sep) << endl; + + values += '('; + instance pt (values, *qp, sep); pt->traverse (c); - os << strlit (" VALUES (" + values + ")"); + values += ')'; } else - os << strlit (" DEFAULT VALUES"); + values = "DEFAULT VALUES"; + + extra = persist_statement_extra (c, *qp, persist_after_values); - persist_statement_extra (c, *qp, persist_after_values); + if (!extra.empty ()) + values += sep; + + os << strlit (values); + + if (!extra.empty ()) + os << endl + << strlit (extra); os << ";" << endl; @@ -662,6 +688,8 @@ traverse_object (type& c) if (id != 0) { + string sep (versioned ? "\n" : " "); + instance id_cols; id_cols->traverse (*id); @@ -689,22 +717,26 @@ traverse_object (type& c) if (sc.size () != 0) { - os << strlit ("SELECT ") << endl; + os << strlit ("SELECT" + sep) << endl; for (statement_columns::const_iterator i (sc.begin ()), e (sc.end ()); i != e;) { string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; + os << strlit (c + (++i != e ? "," : "") + sep) << endl; } - os << strlit (" FROM " + qtable) << endl; + os << strlit ("FROM " + qtable + sep) << endl; if (d != 1) { + bool f (false); // @@ (im)perfect forwarding size_t d1 (d - 1); //@@ (im)perfect forward. - instance j (c, d1); + instance j (c, f, d1); j->traverse (polymorphic_base (c)); + + for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) + os << strlit (*i + sep) << endl; } { @@ -714,19 +746,24 @@ traverse_object (type& c) object_section* s (&main_section); // @@ (im)perfect forwarding instance j (c, f, d, s); j->traverse (c); + + for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) + os << strlit (*i + sep) << endl; } + string where ("WHERE "); instance qp (table); for (object_columns_list::iterator b (id_cols->begin ()), i (b); i != id_cols->end (); ++i) { if (i != b) - os << endl; + where += " AND "; - os << strlit ((i == b ? " WHERE " : " AND ") + - qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (), i->type, *i->member)); + where += qtable + "." + quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } + + os << strlit (where); } else os << strlit (""); // Empty SELECT statement. @@ -791,24 +828,24 @@ traverse_object (type& c) e (sc.end ()); i != e;) { string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; + os << strlit (c + (++i != e ? ", " : " ")) << endl; } - os << strlit (" FROM " + qtable) << endl; + os << strlit ("FROM " + qtable + " ") << endl; + string where ("WHERE "); instance qp (table); for (object_columns_list::iterator b (id_cols->begin ()), i (b); i != id_cols->end (); ++i) { if (i != b) - os << endl; + where += " AND "; - os << strlit ((i == b ? " WHERE " : " AND ") + - qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (), i->type, *i->member)); + where += qtable + "." + quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } - os << ";" + os << strlit (where) << ";" << endl; } @@ -816,6 +853,8 @@ traverse_object (type& c) // if (update_columns != 0) { + string sep (versioned ? "\n" : " "); + instance qp (table); statement_columns sc; @@ -829,13 +868,14 @@ traverse_object (type& c) } os << "const char " << traits << "::update_statement[] =" << endl - << strlit ("UPDATE " + qtable + " SET ") << endl; + << strlit ("UPDATE " + qtable + sep) << endl + << strlit ("SET" + sep) << endl; for (statement_columns::const_iterator i (sc.begin ()), e (sc.end ()); i != e;) { string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; + os << strlit (c + (++i != e ? "," : "") + sep) << endl; } // This didn't work out: cannot change the identity column. @@ -850,29 +890,31 @@ traverse_object (type& c) // os << strlit (c + "=" + c) << endl; //} - update_statement_extra (c); + string extra (update_statement_extra (c)); + + if (!extra.empty ()) + os << strlit (extra + sep) << endl; + string where ("WHERE "); for (object_columns_list::iterator b (id_cols->begin ()), i (b); i != id_cols->end (); ++i) { if (i != b) - os << endl; + where += " AND "; - os << strlit ((i == b ? " WHERE " : " AND ") + - quote_id (i->name) + "=" + - convert_to (qp->next (), i->type, *i->member)); + where += quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } + // Top-level version column. + // if (opt != 0 && !poly_derived) { - // Top-level version column. - // - os << endl - << strlit (" AND " + column_qname (*opt, column_prefix ()) + "=" + - convert_to (qp->next (), *opt)); + where += " AND " + column_qname (*opt, column_prefix ()) + "=" + + convert_to (qp->next (), *opt); } - os << ";" + os << strlit (where) << ";" << endl; } @@ -881,19 +923,20 @@ traverse_object (type& c) { instance qp (table); os << "const char " << traits << "::erase_statement[] =" << endl - << strlit ("DELETE FROM " + qtable); + << strlit ("DELETE FROM " + qtable + " ") << endl; + string where ("WHERE "); for (object_columns_list::iterator b (id_cols->begin ()), i (b); i != id_cols->end (); ++i) { + if (i != b) + where += " AND "; - os << endl - << strlit ((i == b ? " WHERE " : " AND ") + - quote_id (i->name) + "=" + - convert_to (qp->next (), i->type, *i->member)); + where += quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } - os << ";" + os << strlit (where) << ";" << endl; } @@ -903,26 +946,32 @@ traverse_object (type& c) os << "const char " << traits << "::optimistic_erase_statement[] " << "=" << endl - << strlit ("DELETE FROM " + qtable); + << strlit ("DELETE FROM " + qtable + " ") << endl; + string where ("WHERE "); 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)); + if (i != b) + where += " AND "; + + where += quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } // Top-level version column. // - os << endl - << strlit (" AND " + column_qname (*opt, column_prefix ()) + "=" + - convert_to (qp->next (), *opt)) << ";" + where += " AND " + column_qname (*opt, column_prefix ()) + "=" + + convert_to (qp->next (), *opt); + + os << strlit (where) << ";" << endl; } } + // query_statement + // + bool query_optimize (false); if (options.generate_query ()) { // query_statement @@ -936,23 +985,14 @@ traverse_object (type& c) process_statement_columns (sc, statement_select); } - os << "const char " << traits << "::query_statement[] =" << endl - << strlit ("SELECT ") << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; - } - - os << strlit (" FROM " + qtable) << endl; - + strings joins; if (poly_depth != 1) { + bool t (true); //@@ (im)perfect forwarding size_t d (poly_depth - 1); //@@ (im)perfect forward. - instance j (c, d); + instance j (c, t, d); j->traverse (polymorphic_base (c)); + joins = j->joins; } if (id != 0) @@ -961,27 +1001,40 @@ traverse_object (type& c) // can be used in the WHERE clause. // bool t (true); //@@ (im)perfect forwarding - instance oj (c, t, poly_depth); - oj->traverse (c); + instance j (c, t, poly_depth); + j->traverse (c); + joins.insert (joins.end (), j->begin (), j->end ()); + } + + query_optimize = !joins.empty (); + + string sep (versioned || query_optimize ? "\n" : " "); + + os << "const char " << traits << "::query_statement[] =" << endl + << strlit ("SELECT" + sep) << endl; + + for (statement_columns::const_iterator i (sc.begin ()), + e (sc.end ()); i != e;) + { + string const& c (i->column); + os << strlit (c + (++i != e ? "," : "") + sep) << endl; } - os << strlit (" ") << ";" + string prev ("FROM " + qtable); + + for (strings::const_iterator i (joins.begin ()); i != joins.end (); ++i) + { + os << strlit (prev + sep) << endl; + prev = *i; + } + + os << strlit (prev) << ";" << endl; // erase_query_statement // os << "const char " << traits << "::erase_query_statement[] =" << endl - << strlit ("DELETE FROM " + qtable) << endl; - - // DELETE JOIN: - // - // MySQL: - // << strlit ("DELETE FROM " + qtable + " USING " + qtable) << endl; - // << strlit ("DELETE " + qtable + " FROM " + qtable) << endl; - // oj->write (); - // - - os << strlit (" ") << ";" + << strlit ("DELETE FROM " + qtable) << ";" << endl; // table_name @@ -1822,7 +1875,7 @@ traverse_object (type& c) base = true; // We have a readonly optimistic root. } - os << ", " << (base ? "true" : "false"); + os << ", " << base; } os << ");"; @@ -3444,6 +3497,8 @@ traverse_object (type& c) else result_type = "no_id_object_result_impl"; + string sep (versioned || query_optimize ? "\n" : " "); + // Unprepared. // if (!options.omit_unprepared ()) @@ -3494,10 +3549,18 @@ traverse_object (type& c) << "}"; } + os << "std::string text (query_statement);" + << "if (!q.empty ())" + << "{" + << "text += " << strlit (sep) << ";" + << "text += q.clause ();" + << "}"; + os << "q.init_parameters ();" << "shared_ptr st (" << endl << "new (shared) select_statement (" << endl; - object_query_statement_ctor_args (c, "q", false); + object_query_statement_ctor_args ( + c, "q", versioned || query_optimize, false); os << "));" << endl << "st->execute ();"; @@ -3532,6 +3595,12 @@ traverse_object (type& c) << db << "::connection& conn (" << endl << db << "::transaction::current ().connection ());" << endl + << "std::string text (erase_query_statement);" + << "if (!q.empty ())" + << "{" + << "text += ' ';" + << "text += q.clause ();" + << "}" << "q.init_parameters ();" << "delete_statement st (" << endl; object_erase_query_statement_ctor_args (c); @@ -3601,6 +3670,13 @@ traverse_object (type& c) << "}"; } + os << "std::string text (query_statement);" + << "if (!q.empty ())" + << "{" + << "text += " << strlit (sep) << ";" + << "text += q.clause ();" + << "}"; + os << "shared_ptr<" << db << "::prepared_query_impl> r (" << endl << "new (shared) " << db << "::prepared_query_impl (conn));" << "r->name = n;" @@ -3608,7 +3684,8 @@ traverse_object (type& c) << "r->query = q;" << "r->stmt.reset (" << endl << "new (shared) select_statement (" << endl; - object_query_statement_ctor_args (c, "r->query", true); + object_query_statement_ctor_args ( + c, "r->query", versioned || query_optimize, true); os << "));" << endl << "return r;" @@ -3790,6 +3867,18 @@ traverse_object (type& c) void relational::source::class_:: traverse_view (type& c) { + view_query& vq (c.get ("query")); + + // Only process the view query if it is versioned since the query text + // (e.g., in the native view) must be structured. Also, we probably + // shouldn't try to optimize JOINs since the objects are JOINed + // explicitly by the user, unless we are adding poly-bases/derived. + // + // When versioning is forced, don't do it for native views. + // + bool versioned (force_versioned && vq.kind == view_query::condition); + bool query_optimize (false); + string const& type (class_fq_name (c)); string traits ("access::view_traits_impl< " + type + ", id_" + db.string () + " >"); @@ -3862,8 +3951,6 @@ traverse_view (type& c) // query_statement() // - view_query& vq (c.get ("query")); - if (vq.kind != view_query::runtime) { os << traits << "::query_base_type" << endl @@ -3930,8 +4017,13 @@ traverse_view (type& c) // at the end. // if (!ph) - os << "r += q.clause_prefix ();" - << "r += q;"; + os << endl + << "if (!q.empty ())" + << "{" + << "r += " << strlit (versioned ? "\n" : " ") << ";" + << "r += q.clause_prefix ();" + << "r += q;" + << "}"; } else // vq.kind == view_query::condition { @@ -3942,21 +4034,9 @@ traverse_view (type& c) process_statement_columns (sc, statement_select); } - os << "query_base_type r (" << endl - << strlit ("SELECT ") << endl; - - for (statement_columns::const_iterator i (sc.begin ()), - e (sc.end ()); i != e;) - { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; - } - - os << ");" - << endl; - - // Generate from-list. + // Generate the from-list. // + strings from; view_objects const& objs (c.get ("objects")); for (view_objects::const_iterator i (objs.begin ()); @@ -3980,9 +4060,7 @@ traverse_view (type& c) if (!i->alias.empty ()) l += (need_alias_as ? " AS " : " ") + quote_id (i->alias); - os << "r += " << strlit (l) << ";" - << endl; - + from.push_back (l); continue; } @@ -4001,21 +4079,18 @@ traverse_view (type& c) if (e.kind != expression::literal) { - error (i->loc) - << "invalid join condition in db pragma table" << endl; - + error (i->loc) << "invalid join condition in db pragma " << + "table" << endl; throw operation_failed (); } l += " ON"; - // Output the pragma location for easier error tracking. + // Add the pragma location for easier error tracking. // - os << "r += " << strlit (l) << ";" - << "// From " << location_string (i->loc, true) << endl - << "r += " << e.value << ";" - << endl; - + from.push_back (l); + from.push_back ("// From " + location_string (i->loc, true)); + from.push_back (e.value); continue; } @@ -4044,18 +4119,18 @@ traverse_view (type& c) if (!alias.empty ()) l += (need_alias_as ? " AS " : " ") + quote_id (alias); - os << "r += " << strlit (l) << ";"; + from.push_back (l); if (poly_depth != 1) { + bool t (true); //@@ (im)perfect forwarding size_t d (poly_depth - 1); //@@ (im)perfect forward. - instance j ( - o, d, i->alias, "r += ", ";"); + instance j (o, t, d, i->alias); j->traverse (polymorphic_base (o)); - } - - os << endl; + from.insert (from.end (), j->begin (), j->end ()); + query_optimize = query_optimize || !j->joins.empty (); + } continue; } @@ -4078,22 +4153,22 @@ traverse_view (type& c) l += " ON"; - // Output the pragma location for easier error tracking. + // Add the pragma location for easier error tracking. // - os << "r += " << strlit (l) << ";" - << "// From " << location_string (i->loc, true) << endl - << "r += " << e.value << ";"; + from.push_back (l); + from.push_back ("// From " + location_string (i->loc, true)); + from.push_back (e.value); if (poly_depth != 1) { + bool t (true); //@@ (im)perfect forwarding size_t d (poly_depth - 1); //@@ (im)perfect forward. - instance j ( - o, d, i->alias, "r += ", ";"); + instance j (o, t, d, i->alias); j->traverse (polymorphic_base (o)); - } - - os << endl; + from.insert (from.end (), j->begin (), j->end ()); + query_optimize = query_optimize || !j->joins.empty (); + } continue; } @@ -4147,39 +4222,28 @@ traverse_view (type& c) // if (!ambig) { - error (i->loc) - << "pointed-to object '" << class_name (*c) << "' is " - << "ambiguous" << endl; - - info (i->loc) - << "candidates are:" << endl; - - info (vo->loc) - << " '" << vo->name () << "'" << endl; - + error (i->loc) << "pointed-to object '" << class_name (*c) << + "' is ambiguous" << endl; + info (i->loc) << "candidates are:" << endl; + info (vo->loc) << " '" << vo->name () << "'" << endl; ambig = true; } - info (j->loc) - << " '" << j->name () << "'" << endl; + info (j->loc) << " '" << j->name () << "'" << endl; } if (ambig) { - info (i->loc) - << "use the full join condition clause in db pragma " - << "object to resolve this ambiguity" << endl; - + info (i->loc) << "use the full join condition clause in db " << + "pragma object to resolve this ambiguity" << endl; throw operation_failed (); } if (vo == 0) { - error (i->loc) - << "pointed-to object '" << class_name (*c) << "' " - << "specified in the join condition has not been " - << "previously associated with this view" << endl; - + error (i->loc) << "pointed-to object '" << class_name (*c) << + "' specified in the join condition has not been " << + "previously associated with this view" << endl; throw operation_failed (); } } @@ -4253,7 +4317,7 @@ traverse_view (type& c) l = "LEFT JOIN "; l += ct; l += " ON"; - os << "r += " << strlit (l) << ";"; + from.push_back (l); // If we are the pointed-to object, then we have to turn // things around. This is necessary to have the proper @@ -4330,7 +4394,7 @@ traverse_view (type& c) l += '.'; l += quote_id (j->name); - os << "r += " << strlit (l) << ";"; + from.push_back (strlit (l)); } } @@ -4341,7 +4405,7 @@ traverse_view (type& c) l += (need_alias_as ? " AS " : " ") + quote_id (alias); l += " ON"; - os << "r += " << strlit (l) << ";"; + from.push_back (l); if (cont != 0) { @@ -4413,7 +4477,7 @@ traverse_view (type& c) l += '.'; l += quote_id (j->name); - os << "r += " << strlit (l) << ";"; + from.push_back (strlit (l)); } } else @@ -4457,27 +4521,60 @@ traverse_view (type& c) l += '.'; l += quote_id (j->name); - os << "r += " << strlit (l) << ";"; + from.push_back (strlit (l)); } } if (poly_depth != 1) { + bool t (true); //@@ (im)perfect forwarding size_t d (poly_depth - 1); //@@ (im)perfect forward. - instance j ( - o, d, i->alias, "r += ", ";"); + instance j (o, t, d, i->alias); j->traverse (polymorphic_base (o)); + + from.insert (from.end (), j->begin (), j->end ()); + query_optimize = query_optimize || !j->joins.empty (); } + } // End JOIN-generating for-loop. - os << endl; + string sep (versioned || query_optimize ? "\n" : " "); - } // End JOIN-generating for-loop. + os << "query_base_type r (" << endl + << strlit ("SELECT" + sep); + + for (statement_columns::const_iterator i (sc.begin ()), + e (sc.end ()); i != e;) + { + string const& c (i->column); + os << endl + << strlit (c + (++i != e ? "," : "") + sep); + } + + os << ");" + << endl; + + // It is much easier to add the separator at the beginning of the + // next line since the JOIN condition may not be a string literal. + // + for (strings::const_iterator i (from.begin ()); i != from.end (); ++i) + { + if (i->compare (0, 5, "FROM ") == 0) + os << "r += " << strlit (*i) << ";"; + else if (i->compare (0, 5, "LEFT ") == 0) + os << endl + << "r += " << strlit (sep + *i) << ";"; + else if (i->compare (0, 3, "// ") == 0) + os << *i << endl; + else + os << "r += " << *i << ";"; // Already a string literal. + } // Generate the query condition. // if (!vq.literal.empty () || !vq.expr.empty ()) { - os << "query_base_type c (" << endl; + os << endl + << "query_base_type c (" << endl; bool ph (false); @@ -4521,21 +4618,31 @@ traverse_view (type& c) // rid of useless clauses like WHERE TRUE. // if (ph) - os << "c.optimize ();"; + os << endl + << "c.optimize ();"; } if (!ph) - os << "c += q;"; + os << endl + << "c += q;"; - os << "r += c.clause_prefix ();" + os << endl + << "if (!c.empty ())" + << "{" + << "r += " << strlit (sep) << ";" + << "r += c.clause_prefix ();" << "r += c;" - << endl; + << "}"; } else { - os << "r += q.clause_prefix ();" + os << endl + << "if (!q.empty ())" + << "{" + << "r += " << strlit (sep) << ";" + << "r += q.clause_prefix ();" << "r += q;" - << endl; + << "}"; } } @@ -4579,7 +4686,8 @@ traverse_view (type& c) os << "qs.init_parameters ();" << "shared_ptr st (" << endl << "new (shared) select_statement (" << endl; - view_query_statement_ctor_args (c, "qs", false); + view_query_statement_ctor_args ( + c, "qs", versioned || query_optimize, false); os << "));" << endl << "st->execute ();"; @@ -4651,7 +4759,8 @@ traverse_view (type& c) os << "r->stmt.reset (" << endl << "new (shared) select_statement (" << endl; - view_query_statement_ctor_args (c, "r->query", true); + view_query_statement_ctor_args ( + c, "r->query", versioned || query_optimize, true); os << "));" << endl << "return r;" diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 3bf7c95..aae34da 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -490,35 +490,16 @@ namespace relational typedef polymorphic_object_joins base; polymorphic_object_joins (semantics::class_& obj, + bool query, size_t depth, string const& alias = "", - string const prefix = "", - string const& suffix = "\n") - : object_columns_base (true, true), - obj_ (obj), - depth_ (depth), - section_ (0), - alias_ (alias), - prefix_ (prefix), - suffix_ (suffix) - { - init (); - } - - polymorphic_object_joins (semantics::class_& obj, - size_t depth, - user_section& section) + user_section* section = 0) : object_columns_base (true, true), obj_ (obj), + query_ (query), depth_ (depth), - section_ (§ion), - suffix_ ("\n") - { - init (); - } - - void - init () + section_ (section), + alias_ (alias) { // Get the table and id columns. // @@ -553,6 +534,14 @@ namespace relational stop = true; // Stop at this base if there are no more overrides. } } + // Skip intermediates that don't add any data members. + // + else if (!query_) + { + column_count_type const& cc (column_count (c)); + if (cc.total == cc.id + cc.separate_load) + skip = true; + } if (!skip) { @@ -574,27 +563,35 @@ namespace relational cond << alias << '.' << qn << '=' << table_ << '.' << qn; } - string line (" LEFT JOIN " + quote_id (table)); + string line ("LEFT JOIN " + quote_id (table)); if (!alias_.empty ()) line += (need_alias_as ? " AS " : " ") + alias; line += " ON " + cond.str (); - os << prefix_ << strlit (line) << suffix_; + joins.push_back (line); } if (!stop && --depth_ != 0) inherits (c); } + public: + strings joins; + + strings::const_iterator + begin () const {return joins.begin ();} + + strings::const_iterator + end () const {return joins.end ();} + private: semantics::class_& obj_; + bool query_; size_t depth_; user_section* section_; string alias_; - string prefix_; - string suffix_; string table_; instance cols_; }; @@ -823,7 +820,7 @@ namespace relational if (!t.empty ()) { - string line (" LEFT JOIN "); + string line ("LEFT JOIN "); line += t; if (!a.empty ()) @@ -832,7 +829,7 @@ namespace relational line += " ON "; line += cond.str (); - os << strlit (line) << endl; + joins.push_back (line); } // Add dependent join (i.e., an object table join via the @@ -840,7 +837,7 @@ namespace relational // if (!dt.empty ()) { - string line (" LEFT JOIN "); + string line ("LEFT JOIN "); line += dt; if (!da.empty ()) @@ -849,12 +846,12 @@ namespace relational line += " ON "; line += dcond.str (); - os << strlit (line) << endl; + joins.push_back (line); } // If we joined the object that is part of a polymorphic type // hierarchy, then we may need join its bases as well as its - // derived types. + // derived types. This is only done for queries. // if (joined_obj != 0 && poly) { @@ -864,22 +861,35 @@ namespace relational // if (joined_obj != &c) { + bool t (true); //@@ (im)perfect forward. size_t d (polymorphic_depth (c) - depth); //@@ (im)perfect forward. - instance t (*joined_obj, d, alias); - t->traverse (c); + instance j (*joined_obj, t, d, alias); + j->traverse (c); + joins.insert (joins.end (), j->joins.begin (), j->joins.end ()); } // Join "down" (base). // if (joined_obj != poly_root) { + bool t (true); //@@ (im)perfect forward. size_t d (depth - 1); //@@ (im)perfect forward. - instance t (*joined_obj, d, alias); - t->traverse (polymorphic_base (*joined_obj)); + instance j (*joined_obj, t, d, alias); + j->traverse (polymorphic_base (*joined_obj)); + joins.insert (joins.end (), j->joins.begin (), j->joins.end ()); } } } + public: + strings joins; + + strings::const_iterator + begin () const {return joins.begin ();} + + strings::const_iterator + end () const {return joins.end ();} + private: bool query_; size_t depth_; @@ -1454,8 +1464,7 @@ namespace relational // Indicate to the value_traits whether this column can be NULL. // - os << "bool is_null (" << - (null (mi.m, key_prefix_) ? "true" : "false") << ");"; + os << "bool is_null (" << null (mi.m, key_prefix_) << ");"; } if (comp) @@ -2074,6 +2083,9 @@ namespace relational // if (!reuse_abst) { + bool versioned (force_versioned); + string sep (versioned ? "\n" : " "); + semantics::type& idt (container_idt (m)); qname table (table_name (m, table_prefix_)); @@ -2181,26 +2193,29 @@ namespace relational process_statement_columns (sc, statement_select); - os << strlit ("SELECT ") << endl; + os << strlit ("SELECT" + sep) << endl; for (statement_columns::const_iterator i (sc.begin ()), e (sc.end ()); i != e;) { string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; + os << strlit (c + (++i != e ? "," : "") + sep) << endl; } instance qp (inv_table); - os << strlit (" FROM " + inv_qtable); + os << strlit ("FROM " + inv_qtable + sep) << endl; + string where ("WHERE "); for (object_columns_list::iterator b (inv_fid_cols->begin ()), i (b); i != inv_fid_cols->end (); ++i) { - os << endl - << strlit ((i == b ? " WHERE " : " AND ") + - inv_qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (), i->type, *i->member)); + if (i != b) + where += " AND "; + + where += inv_qtable + "." + quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } + os << strlit (where); } else { @@ -2235,25 +2250,27 @@ namespace relational process_statement_columns (sc, statement_select); - os << strlit ("SELECT ") << endl; + os << strlit ("SELECT" + sep) << endl; for (statement_columns::const_iterator i (sc.begin ()), e (sc.end ()); i != e;) { string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; + os << strlit (c + (++i != e ? "," : "") + sep) << endl; } instance qp (table); - os << strlit (" FROM " + qtable); + os << strlit ("FROM " + qtable + sep) << endl; + string where ("WHERE "); for (object_columns_list::iterator b (id_cols->begin ()), i (b); i != id_cols->end (); ++i) { - os << endl - << strlit ((i == b ? " WHERE " : " AND ") + - qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (), i->type, *i->member)); + if (i != b) + where += " AND "; + + where += qtable + "." + quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } if (ordered) @@ -2263,9 +2280,10 @@ namespace relational string const& col ( column_qname (m, "index", "index", column_prefix ())); - os << endl - << strlit (" ORDER BY " + qtable + "." + col); + where += " ORDER BY " + qtable + "." + col; } + + os << strlit (where); } os << ";" @@ -2312,27 +2330,40 @@ namespace relational process_statement_columns (sc, statement_insert); - os << strlit ("INSERT INTO " + qtable + " (") << endl; + os << strlit ("INSERT INTO " + qtable + sep) << endl; - for (statement_columns::const_iterator i (sc.begin ()), + for (statement_columns::const_iterator b (sc.begin ()), i (b), e (sc.end ()); i != e;) { - string const& c (i->column); - os << strlit (c + (++i != e ? "," : ")")) << endl; + string s; + + if (i == b) + s += '('; + s += i->column; + s += (++i != e ? ',' : ')'); + s += sep; + + os << strlit (s) << endl; } - string values; + os << strlit ("VALUES" + sep) << endl; + + string values ("("); instance qp (table); for (statement_columns::const_iterator b (sc.begin ()), i (b), e (sc.end ()); i != e; ++i) { if (i != b) + { values += ','; + values += sep; + } values += convert_to (qp->next (), i->type, *i->member); } + values += ')'; - os << strlit (" VALUES (" + values + ")") << ";" + os << strlit (values) << ";" << endl; } @@ -2342,7 +2373,8 @@ namespace relational { os << "const char " << scope << "::" << endl << "update_statement[] =" << endl - << strlit ("UPDATE " + qtable + " SET "); + << strlit ("UPDATE " + qtable + sep) << endl + << strlit ("SET" + sep) << endl; instance qp (table); statement_columns sc; @@ -2358,28 +2390,28 @@ namespace relational e (sc.end ()); i != e;) { string const& c (i->column); - os << endl - << strlit (c + (++i != e ? "," : "")); + os << strlit (c + (++i != e ? "," : "") + sep) << endl; } + string where ("WHERE "); 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)); + if (i != b) + where += " AND "; + + where += 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)); + where += " AND " + quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } - os << ";" + os << strlit (where) << ";" << endl; } @@ -2395,15 +2427,17 @@ namespace relational { instance qp (table); - os << strlit ("DELETE FROM " + qtable); + os << strlit ("DELETE FROM " + qtable + " ") << endl; + string where ("WHERE "); 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)); + if (i != b) + where += " AND "; + + where += quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } if (smart) @@ -2411,14 +2445,13 @@ namespace relational 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)); + where += " AND " + quote_id (i->name) + + (ck == ck_ordered ? ">=" : "=") + + convert_to (qp->next (), i->type, *i->member); } } - os << ";" + os << strlit (where) << ";" << endl; } } @@ -3257,7 +3290,7 @@ namespace relational << "functions_type& fs (sts.functions ());"; if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";"; + os << "fs.ordered_ = " << ordered << ";"; os << "container_traits_type::persist (c, fs);" << "}"; @@ -3314,7 +3347,7 @@ namespace relational << "functions_type& fs (sts.functions ());"; if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";"; + os << "fs.ordered_ = " << ordered << ";"; os << "container_traits_type::load (c, more, fs);" << "}"; @@ -3338,7 +3371,7 @@ namespace relational << "functions_type& fs (sts.functions ());"; if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";"; + os << "fs.ordered_ = " << ordered << ";"; os << "container_traits_type::update (c, fs);" << "}"; @@ -3361,7 +3394,7 @@ namespace relational << "functions_type& fs (sts.functions ());"; if (!smart && ck == ck_ordered) - os << "fs.ordered_ = " << (ordered ? "true" : "false") << ";"; + os << "fs.ordered_ = " << ordered << ";"; os << "container_traits_type::erase (" << (smart ? "c, " : "") << "fs);" << "}"; @@ -3840,9 +3873,10 @@ namespace relational return "1"; } - virtual void + virtual string update_statement_extra (user_section&) { + return ""; } virtual void @@ -4215,6 +4249,9 @@ namespace relational return; } + bool versioned (force_versioned); + string sep (versioned ? "\n" : " "); + // Statements. // qname table (table_name (c_)); @@ -4240,25 +4277,28 @@ namespace relational os << "const char " << scope << "::" << endl << "select_statement[] =" << endl - << strlit ("SELECT ") << endl; + << strlit ("SELECT" + sep) << endl; for (statement_columns::const_iterator i (sc.begin ()), e (sc.end ()); i != e;) { string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; + os << strlit (c + (++i != e ? "," : "") + sep) << endl; } - os << strlit (" FROM " + qtable) << endl; + os << strlit ("FROM " + qtable + sep) << endl; // Join polymorphic bases. // if (depth != 1 && s.base != 0) { + bool f (false); //@@ (im)perfect forwarding size_t d (depth - 1); //@@ (im)perfect forward. - user_section& bs (*s.base); //@@ (im)perfect forward. - instance j (c_, d, bs); + instance j (c_, f, d, "", s.base); j->traverse (*poly_base); + + for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) + os << strlit (*i + sep) << endl; } // Join tables of inverse members belonging to this section. @@ -4268,21 +4308,24 @@ namespace relational object_section* ps (&s); // @@ (im)perfect forwarding instance j (c_, f, depth, ps); j->traverse (c_); + + for (strings::const_iterator i (j->begin ()); i != j->end (); ++i) + os << strlit (*i + sep) << endl; } + string where ("WHERE "); instance qp (table); for (object_columns_list::iterator b (id_cols->begin ()), i (b); i != id_cols->end (); ++i) { if (i != b) - os << endl; + where += " AND "; - os << strlit ((i == b ? " WHERE " : " AND ") + - qtable + "." + quote_id (i->name) + "=" + - convert_to (qp->next (), i->type, *i->member)); + where += qtable + "." + quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } - os << ";" + os << strlit (where) << ";" << endl; } @@ -4304,13 +4347,14 @@ namespace relational os << "const char " << scope << "::" << endl << "update_statement[] =" << endl - << strlit ("UPDATE " + qtable + " SET ") << endl; + << strlit ("UPDATE " + qtable + sep) << endl + << strlit ("SET" + sep) << endl; for (statement_columns::const_iterator i (sc.begin ()), e (sc.end ()); i != e;) { string const& c (i->column); - os << strlit (c + (++i != e ? "," : "")) << endl; + os << strlit (c + (++i != e ? "," : "") + sep) << endl; } // This didn't work out: cannot change the identity column. @@ -4325,27 +4369,29 @@ namespace relational // os << strlit (c + "=" + c) << endl; //} - update_statement_extra (s); + string extra (update_statement_extra (s)); + if (!extra.empty ()) + os << strlit (extra + sep) << endl; + + string where ("WHERE "); for (object_columns_list::iterator b (id_cols->begin ()), i (b); i != id_cols->end (); ++i) { if (i != b) - os << endl; + where += " AND "; - os << strlit ((i == b ? " WHERE " : " AND ") + - quote_id (i->name) + "=" + - convert_to (qp->next (), i->type, *i->member)); + where += quote_id (i->name) + "=" + + convert_to (qp->next (), i->type, *i->member); } if (s.optimistic ()) // Note: not update_opt. { - os << endl - << strlit (" AND " + column_qname (*opt, column_prefix ()) + - "=" + convert_to (qp->next (), *opt)); + where += " AND " + column_qname (*opt, column_prefix ()) + "=" + + convert_to (qp->next (), *opt); } - os << ";" + os << strlit (where) << ";" << endl; } @@ -4745,8 +4791,10 @@ namespace relational { typedef persist_statement_params base; - persist_statement_params (string& params, query_parameters& qp) - : params_ (params), qp_ (qp) + persist_statement_params (string& params, + query_parameters& qp, + const string& sep) + : params_ (params), qp_ (qp), sep_ (sep) { } @@ -4772,7 +4820,10 @@ namespace relational if (!p.empty ()) { if (!first) + { params_ += ','; + params_ += sep_; + } params_ += (p != "DEFAULT" ? convert_to (p, column_type (), m) : p); } @@ -4789,6 +4840,7 @@ namespace relational private: string& params_; query_parameters& qp_; + const string& sep_; }; // @@ -4908,14 +4960,16 @@ namespace relational persist_after_values }; - virtual void + virtual string persist_statement_extra (type&, query_parameters&, persist_position) { + return ""; } - virtual void + virtual string update_statement_extra (type&) { + return ""; } // @@ -4946,10 +5000,13 @@ namespace relational virtual void object_query_statement_ctor_args (type&, std::string const& q, + bool process, bool /*prepared*/) { os << "conn," << endl - << "query_statement + " << q << ".clause ()," << endl + << "text," << endl + << process << "," << endl // Process. + << "true," << endl // Optimize. << q << ".parameters_binding ()," << endl << "imb"; } @@ -4958,7 +5015,7 @@ namespace relational object_erase_query_statement_ctor_args (type&) { os << "conn," << endl - << "erase_query_statement + q.clause ()," << endl + << "text," << endl << "q.parameters_binding ()"; } @@ -4991,10 +5048,13 @@ namespace relational virtual void view_query_statement_ctor_args (type&, string const& q, + bool process, bool /*prepared*/) { os << "conn," << endl << q << ".clause ()," << endl + << process << "," << endl // Process. + << "true," << endl // Optimize. << q << ".parameters_binding ()," << endl << "imb"; } -- cgit v1.1