diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2013-01-14 16:01:06 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2013-01-14 16:01:06 +0200 |
commit | 0e6be616e40c86ff03df7c0806bcbd0cc3c4489f (patch) | |
tree | 410e7ab2e10bb3dd0df30aab2135ed4544555157 /odb/relational/mssql | |
parent | 604517928701b3ef2783ede9a0b3b2f80c92ec92 (diff) |
Add support for MSSQL ROWVERSION
ODB can now use ROWVERSION column as an optimistic concurrency version.
Diffstat (limited to 'odb/relational/mssql')
-rw-r--r-- | odb/relational/mssql/header.cxx | 32 | ||||
-rw-r--r-- | odb/relational/mssql/source.cxx | 143 |
2 files changed, 157 insertions, 18 deletions
diff --git a/odb/relational/mssql/header.cxx b/odb/relational/mssql/header.cxx index 957f880..54bb6e1 100644 --- a/odb/relational/mssql/header.cxx +++ b/odb/relational/mssql/header.cxx @@ -15,6 +15,38 @@ namespace relational { namespace relational = relational::header; + struct class1: relational::class1, context + { + class1 (base const& x): base (x) {} + + virtual void + object_public_extra_pre (type& c) + { + bool abst (abstract (c)); + + type* poly_root (polymorphic (c)); + bool poly (poly_root != 0); + bool poly_derived (poly && poly_root != &c); + + if (poly_derived || (abst && !poly)) + return; + + // rowvesion + // + bool rv (false); + if (semantics::data_member* m = optimistic (c)) + { + sql_type t (parse_sql_type (column_type (*m), *m)); + rv = (t.type == sql_type::ROWVERSION); + } + + os << "static const bool rowversion = " << + (rv ? "true" : "false") << ";" + << endl; + } + }; + entry<class1> class1_entry_; + struct image_type: relational::image_type, context { image_type (base const& x): base (x) {}; diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx index 5d0c594..5d29b27 100644 --- a/odb/relational/mssql/source.cxx +++ b/odb/relational/mssql/source.cxx @@ -37,24 +37,49 @@ namespace relational { object_columns (base const& x): base (x) {} - virtual void + virtual bool column (semantics::data_member& m, string const& table, string const& column) { // Don't add a column for auto id in the INSERT statement. // - if (!(sk_ == statement_insert && - key_prefix_.empty () && - context::id (m) && auto_(m))) // Only simple id can be auto. + if (sk_ == statement_insert && + key_prefix_.empty () && + context::id (m) && auto_(m)) // Only simple id can be auto. + return false; + + // Don't update the ROWVERSION column explicitly. + // + if (sk_ == statement_update) { - base::column (m, table, column); + sql_type t (parse_sql_type (column_type (), m)); + if (t.type == sql_type::ROWVERSION) + return false; } + + return base::column (m, table, column); } }; entry<object_columns> object_columns_; // + // + struct persist_statement_params: relational::persist_statement_params, + context + { + persist_statement_params (base const& x): base (x) {} + + virtual string + version_value (semantics::data_member& m) + { + sql_type t (parse_sql_type (column_type (), m)); + return t.type == sql_type::ROWVERSION ? "DEFAULT" : "1"; + } + }; + entry<persist_statement_params> persist_statement_params_; + + // // bind // @@ -863,20 +888,32 @@ namespace relational relational::query_parameters&, persist_position p) { - semantics::data_member* id (id_member (c)); - type* poly_root (polymorphic (c)); bool poly_derived (poly_root != 0 && poly_root != &c); - if (id == 0 || poly_derived || !auto_ (*id)) + // If we are a derived type in a polymorphic hierarchy, then + // auto id/version are handled by the root. + // + if (poly_derived) return; - // If we are a derived type in a polymorphic hierarchy, then - // auto id is handled by the root. + // See if we have auto id or ROWVERSION version. // - if (type* root = polymorphic (c)) - if (root != &c) - return; + semantics::data_member* id (id_member (c)); + semantics::data_member* ver (optimistic (c)); + + if (id != 0 && !auto_ (*id)) + id = 0; + + if (ver != 0) + { + sql_type t (parse_sql_type (column_type (*ver), *ver)); + if (t.type != sql_type::ROWVERSION) + ver = 0; + } + + if (id == 0 && ver == 0) + return; // SQL Server 2005 has a bug that causes it to fail on an // INSERT statement with the OUTPUT clause if data for one @@ -900,9 +937,22 @@ namespace relational if (ld) { if (p == persist_after_values) + { + // SQL Server 2005 has no eqivalent of SCOPE_IDENTITY for + // ROWVERSION. + // + if (ver != 0) + { + error (c.location ()) << "in SQL Server 2005 ROWVERSION " << + "value cannot be retrieved for a persistent class " << + "containing long data" << endl; + throw operation_failed (); + } + os << endl << strlit ("; SELECT " + convert_from ("SCOPE_IDENTITY()", *id)); + } return; } @@ -910,21 +960,78 @@ namespace relational if (p == persist_after_columns) { - // Top-level auto id. + string s (" OUTPUT "); + + // Top-level auto id column. // - os << strlit ( - " OUTPUT " + convert_from ( - "INSERTED." + column_qname ( - *id, column_prefix ()), *id)) << endl; + if (id != 0) + s += "INSERTED." + convert_from ( + column_qname (*id, column_prefix ()), *id); + + // Top-level version column. + // + if (ver != 0) + { + if (id != 0) + s += ','; + + s += "INSERTED." + convert_from ( + column_qname (*ver, column_prefix ()), *ver); + } + + os << strlit (s) << endl; } } virtual void + update_statement_extra (type& c) + { + type* poly_root (polymorphic (c)); + bool poly_derived (poly_root != 0 && poly_root != &c); + + // If we are a derived type in a polymorphic hierarchy, then + // version is handled by the root. + // + if (poly_derived) + return; + + semantics::data_member* ver (optimistic (c)); + + if (ver == 0 || + parse_sql_type (column_type (*ver), *ver).type != + sql_type::ROWVERSION) + return; + + // 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; + } + + virtual void process_statement_columns (relational::statement_columns& cols, statement_kind sk) { statement_columns_common::process (cols, sk); } + + virtual string + optimimistic_version_init (semantics::data_member& m) + { + sql_type t (parse_sql_type (column_type (m), m)); + return t.type != sql_type::ROWVERSION ? "1" : "st.version ()"; + } + + virtual string + optimimistic_version_increment (semantics::data_member& m) + { + sql_type t (parse_sql_type (column_type (m), m)); + return t.type != sql_type::ROWVERSION + ? "1" + : "sts.update_statement ().version ()"; + } }; entry<class_> class_entry_; } |