From c6d92f2f979eae471f49d9af1768b7b05f3a6f6f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 21 Dec 2011 11:19:25 +0200 Subject: ODB compiler implementation, traits, and types test for SQL Server --- odb/relational/source.hxx | 389 +++++++++++++++++++++++++++++----------------- 1 file changed, 246 insertions(+), 143 deletions(-) (limited to 'odb/relational/source.hxx') diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 6e92607..ecdd5d1 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -22,11 +23,31 @@ namespace relational { namespace source { + // Column literal in a statement (e.g., in select-list, etc). + // + struct statement_column + { + statement_column (): member (0) {} + statement_column (std::string const& c, + semantics::data_member& m, + std::string const& kp = "") + : column (c), member (&m), key_prefix (kp) + { + } + + std::string column; + semantics::data_member* member; + std::string key_prefix; + }; + + typedef std::list statement_columns; + // Query parameter generator. A new instance is created for each // query, so the customized version can have a counter to implement, // for example, numbered parameters (e.g., $1, $2, etc). The auto_id() // function is called instead of next() for the automatically-assigned - // object id member when generating the persist statement. + // object id member when generating the persist statement. If empty + // string is returned, then parameter is ignored. // struct query_parameters: virtual context { @@ -50,23 +71,21 @@ namespace relational typedef object_columns base; object_columns (statement_kind sk, - bool last = true, + statement_columns& sc, query_parameters* param = 0) - : sk_ (sk), param_ (param), last_ (last) + : sk_ (sk), sc_ (sc), param_ (param) { } object_columns (std::string const& table_qname, statement_kind sk, - bool last = true) - : sk_ (sk), param_ (0), table_name_ (table_qname), last_ (last) + statement_columns& sc) + : sk_ (sk), sc_ (sc), param_ (0), table_name_ (table_qname) { } virtual bool - traverse_column (semantics::data_member& m, - string const& name, - bool first) + traverse_column (semantics::data_member& m, string const& name, bool) { semantics::data_member* im (inverse (m)); @@ -82,25 +101,6 @@ namespace relational sk_ == statement_update) return false; - if (!first) - { - line_ += ','; - os << strlit (line_) << endl; - } - - line_.clear (); - - // Version column (optimistic concurrency) requires special - // handling in the UPDATE statement. - // - // - if (sk_ == statement_update && version (m)) - { - string const& qname (quote_id (name)); - line_ = qname + "=" + qname + "+1"; - return true; - } - // Inverse object pointers come from a joined table. // if (im != 0) @@ -114,12 +114,12 @@ namespace relational // aliases for container tables so use the actual table name. // column ( - *im, "id", + *im, + "id", table_name_.empty () ? table_name_ : table_qname (*im, table_prefix (table_name (*c) + "_", 1)), column_qname (*im, "id", "object_id")); - } else { @@ -128,65 +128,64 @@ namespace relational // Use the join alias (column name) instead of the actual // table name unless we are handling a container. // - column (id, "", - table_name_.empty () ? table_name_ : quote_id (name), - column_qname (id)); + column ( + id, + "", + table_name_.empty () ? table_name_ : quote_id (name), + column_qname (id)); } } else column (m, "", table_name_, quote_id (name)); - if (param_ != 0) - { - line_ += '='; - line_ += param_->next (); - } - return true; } virtual void - column (semantics::data_member&, - string const& /*key_prefix*/, + column (semantics::data_member& m, + string const& key_prefix, string const& table, string const& column) { + string r; + if (!table.empty ()) { - line_ += table; - line_ += '.'; + r += table; // Already quoted. + r += '.'; } - line_ += column; // Already quoted. - } + r += column; // Already quoted. - virtual void - flush () - { - if (!last_) - line_ += ','; - - if (!line_.empty ()) - os << strlit (line_); + // Version column (optimistic concurrency) requires special + // handling in the UPDATE statement. + // + // + if (sk_ == statement_update && version (m)) + { + r += "=" + r + "+1"; + } + else if (param_ != 0) + { + r += '='; + r += param_->next (); + } - os << endl; + sc_.push_back (statement_column (r, m, key_prefix)); } protected: statement_kind sk_; + statement_columns& sc_; query_parameters* param_; - string line_; string table_name_; - - private: - bool last_; }; struct view_columns: object_columns_base, virtual context { typedef view_columns base; - view_columns (): in_composite_ (false) {} + view_columns (statement_columns& sc): sc_ (sc), in_composite_ (false) {} virtual void traverse_composite (semantics::data_member* pm, semantics::class_& c) @@ -261,18 +260,8 @@ namespace relational } virtual bool - traverse_column (semantics::data_member& m, - string const& name, - bool first) + traverse_column (semantics::data_member& m, string const& name, bool) { - if (!first) - { - line_ += ','; - os << strlit (line_) << endl; - } - - line_.clear (); - string col; // If we are inside a composite value, use the standard @@ -346,7 +335,6 @@ namespace relational } column (m, col); - return true; } @@ -354,20 +342,13 @@ namespace relational // expression. // virtual void - column (semantics::data_member&, string const& column) + column (semantics::data_member& m, string const& column) { - line_ += column; - } - - virtual void - flush () - { - if (!line_.empty ()) - os << strlit (line_) << endl; + sc_.push_back (statement_column (column, m)); } protected: - string line_; + statement_columns& sc_; bool in_composite_; string table_prefix_; // Table corresponding to column_prefix_; }; @@ -810,8 +791,8 @@ namespace relational os << statement << ".cache ();"; } - // Additional statements that need to be executed follow the call to init - // that initializes the query result image can be made here. + // Additional code that need to be executed following the call to + // init_value. // virtual void init_value_extra () @@ -819,6 +800,11 @@ namespace relational } virtual void + process_statement_columns (statement_columns&, statement_kind) + { + } + + virtual void traverse_composite (semantics::data_member* m, semantics::class_& c) { if (object (c_)) @@ -946,6 +932,7 @@ namespace relational string inv_table; // Other table name. string inv_id; // Other id column. string inv_fid; // Other foreign id column (ref to us). + statement_columns sc; if (container (*im)) { @@ -959,22 +946,39 @@ namespace relational inv_table = table_qname (*im, tp); inv_id = column_qname (*im, "id", "object_id"); inv_fid = column_qname (*im, "value", "value"); + + sc.push_back (statement_column ( + inv_table + "." + inv_fid, *im, "value")); + sc.push_back (statement_column ( + inv_table + "." + inv_id, *im, "id")); } else { // many(i)-to-one // + semantics::data_member& id (*id_member (*c)); + inv_table = table_qname (*c); - inv_id = column_qname (*id_member (*c)); + inv_id = column_qname (id); inv_fid = column_qname (*im); + + sc.push_back (statement_column (inv_table + "." + inv_fid, *im)); + sc.push_back (statement_column (inv_table + "." + inv_id, id)); } - instance qp; + process_statement_columns (sc, statement_select); + + os << strlit ("SELECT ") << endl; - os << strlit ("SELECT ") << endl - << strlit (inv_table + "." + inv_fid + ',') << endl - << strlit (inv_table + "." + inv_id) << endl - << strlit (" FROM " + inv_table + + for (statement_columns::const_iterator i (sc.begin ()), + e (sc.end ()); i != e;) + { + string const& c (i->column); + os << strlit (c + (++i != e ? "," : "")) << endl; + } + + instance qp; + os << strlit (" FROM " + inv_table + " WHERE " + inv_table + "." + inv_fid + "=" + qp->next ()); } @@ -982,8 +986,11 @@ namespace relational { string const& id_col (column_qname (m, "id", "object_id")); - os << strlit ("SELECT ") << endl - << strlit (table + "." + id_col + ',') << endl; + statement_columns sc; + sc.push_back (statement_column (table + "." + id_col, m, "id")); + + statement_kind sk (statement_select); // Imperfect forwarding. + instance t (table, sk, sc); switch (ck) { @@ -991,25 +998,20 @@ namespace relational { if (ordered) { - instance t (table, statement_select, false); string const& col (column_qname (m, "index", "index")); t->column (m, "index", table, col); - t->flush (); } break; } case ck_map: case ck_multimap: { - instance t (table, statement_select, false); - if (semantics::class_* ckt = composite_wrapper (*kt)) t->traverse (m, *ckt, "key", "key"); else { string const& col (column_qname (m, "key", "key")); t->column (m, "key", table, col); - t->flush (); } break; } @@ -1020,15 +1022,23 @@ namespace relational } } - instance t (table, statement_select); - if (semantics::class_* cvt = composite_wrapper (vt)) t->traverse (m, *cvt, "value", "value"); else { string const& col (column_qname (m, "value", "value")); t->column (m, "value", table, col); - t->flush (); + } + + process_statement_columns (sc, statement_select); + + os << 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; } instance qp; @@ -1059,33 +1069,30 @@ namespace relational << endl; else { - os << strlit ("INSERT INTO " + table + " (") << endl - << strlit (column_qname (m, "id", "object_id") + ',') << endl; + statement_columns sc; + sc.push_back ( + statement_column ( + column_qname (m, "id", "object_id"), m, "id")); + + statement_kind sk (statement_insert); // Imperfect forwarding. + instance t (sk, sc); switch (ck) { case ck_ordered: { if (ordered) - { - instance t (statement_insert, false); - t->column (m, "index", "", column_qname (m, "index", "index")); - t->flush (); - } + t->column ( + m, "index", "", column_qname (m, "index", "index")); break; } case ck_map: case ck_multimap: { - instance t (statement_insert, false); - if (semantics::class_* ckt = composite_wrapper (*kt)) t->traverse (m, *ckt, "key", "key"); else - { t->column (m, "key", "", column_qname (m, "key", "key")); - t->flush (); - } break; } case ck_set: @@ -1095,14 +1102,20 @@ namespace relational } } - instance t (statement_insert); - if (semantics::class_* cvt = composite_wrapper (vt)) t->traverse (m, *cvt, "value", "value"); else - { t->column (m, "value", "", column_qname (m, "value", "value")); - t->flush (); + + process_statement_columns (sc, statement_insert); + + os << strlit ("INSERT INTO " + table + " (") << 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; } string values; @@ -1116,7 +1129,7 @@ namespace relational values += qp->next (); } - os << strlit (") VALUES (" + values + ")") << ";" + os << strlit (" VALUES (" + values + ")") << ";" << endl; } @@ -2108,15 +2121,22 @@ namespace relational { if (!inverse (m)) { - if (count_++ != 0) - params_ += ','; + string p; if (version (m)) - params_ += "1"; - else if (m.count ("id") && m.count ("auto")) - params_ += qp_.auto_id (); + p = "1"; + else if (id (m) && auto_ (m)) + p = qp_.auto_id (); else - params_ += qp_.next (); + p = qp_.next (); + + if (!p.empty ()) + { + if (count_++ != 0) + params_ += ','; + + params_ += p; + } } } @@ -2247,8 +2267,14 @@ namespace relational // statements // + enum persist_position + { + persist_after_columns, + persist_after_values + }; + virtual void - persist_stmt_extra (type&, query_parameters&) + persist_statement_extra (type&, query_parameters&, persist_position) { } @@ -2261,6 +2287,11 @@ namespace relational { } + virtual void + process_statement_columns (statement_columns&, statement_kind) + { + } + // // object // @@ -2271,6 +2302,12 @@ namespace relational } virtual void + free_statement_result () + { + os << "st.free_result ();"; + } + + virtual void object_query_statement_ctor_args (type&) { os << "sts.connection ()," << endl @@ -2575,21 +2612,43 @@ namespace relational // persist_statement // { + statement_columns sc; + { + statement_kind sk (statement_insert); // Imperfect forwarding. + instance ct (sk, sc); + ct->traverse (c); + process_statement_columns (sc, statement_insert); + } + + bool dv (sc.empty ()); // The DEFAULT VALUES syntax. + os << "const char " << traits << "::persist_statement[] " << "=" << endl - << strlit ("INSERT INTO " + table_qname(c) + " (") << endl; + << strlit ("INSERT INTO " + table_qname(c) + + (dv ? "" : " (")) << endl; - instance ct (statement_insert); - ct->traverse (c); + for (statement_columns::const_iterator i (sc.begin ()), + e (sc.end ()); i != e;) + { + string const& c (i->column); + os << strlit (c + (++i != e ? "," : ")")) << endl; + } - string values; instance qp; - instance pt (values, *qp); - pt->traverse (c); - os << strlit (") VALUES (" + values + ")"); + persist_statement_extra (c, *qp, persist_after_columns); - persist_stmt_extra (c, *qp); + if (!dv) + { + string values; + instance pt (values, *qp); + pt->traverse (c); + os << strlit (" VALUES (" + values + ")"); + } + else + os << strlit (" DEFAULT VALUES"); + + persist_statement_extra (c, *qp, persist_after_values); os << ";" << endl; @@ -2602,11 +2661,23 @@ namespace relational // find_statement // { + statement_columns sc; + { + statement_kind sk (statement_select); // Imperfect forwarding. + instance t (table, sk, sc); + t->traverse (c); + process_statement_columns (sc, statement_select); + } + os << "const char " << traits << "::find_statement[] =" << endl << strlit ("SELECT ") << endl; - instance t (table, statement_select); - t->traverse (c); + 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 " + table) << endl; @@ -2625,13 +2696,27 @@ namespace relational // if (cc.total != cc.id + cc.inverse + cc.readonly) { + instance qp; + + statement_columns sc; + { + query_parameters* p (qp.get ()); // Imperfect forwarding. + statement_kind sk (statement_update); // Imperfect forwarding. + instance t (sk, sc, p); + t->traverse (c); + process_statement_columns (sc, statement_update); + } + os << "const char " << traits << "::update_statement[] " << "=" << endl << strlit ("UPDATE " + table + " SET ") << endl; - instance qp; - instance t (statement_update, true, qp.get ()); - t->traverse (c); + for (statement_columns::const_iterator i (sc.begin ()), + e (sc.end ()); i != e;) + { + string const& c (i->column); + os << strlit (c + (++i != e ? "," : "")) << endl; + } string where (" WHERE " + id_col + "=" + qp->next ()); @@ -2672,6 +2757,14 @@ namespace relational { // query_statement // + statement_columns sc; + { + statement_kind sk (statement_select); // Imperfect forwarding. + instance oc (table, sk, sc); + oc->traverse (c); + process_statement_columns (sc, statement_select); + } + bool t (true); instance oj (c, t); //@@ (im)perfect forwarding oj->traverse (c); @@ -2679,9 +2772,11 @@ namespace relational os << "const char " << traits << "::query_statement[] =" << endl << strlit ("SELECT ") << endl; + for (statement_columns::const_iterator i (sc.begin ()), + e (sc.end ()); i != e;) { - instance oc (table, statement_select); - oc->traverse (c); + string const& c (i->column); + os << strlit (c + (++i != e ? "," : "")) << endl; } os << strlit (" FROM " + table) << endl; @@ -3235,8 +3330,9 @@ namespace relational << "}" << "}"; - os << "st.free_result ();" - << "return r != select_statement::no_data;" + free_statement_result (); + + os << "return r != select_statement::no_data;" << "}"; } @@ -3695,14 +3791,21 @@ namespace relational } else // vq.kind == view_query::condition { + statement_columns sc; + { + instance t (sc); + t->traverse (c); + process_statement_columns (sc, statement_select); + } + os << "query_base_type r (" << endl << strlit ("SELECT ") << endl; - // Generate select-list. - // + for (statement_columns::const_iterator i (sc.begin ()), + e (sc.end ()); i != e;) { - instance t; - t->traverse (c); + string const& c (i->column); + os << strlit (c + (++i != e ? "," : "")) << endl; } os << ");" -- cgit v1.1