From 64cc9e9f0ed1ac6742ce9d5b370bf7de7b1cb461 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 20 Jan 2012 10:30:22 +0200 Subject: Work around SQL Server 2005 bug with long data and OUTPUT clause --- odb/relational/mssql/common.hxx | 63 +++++++++++++++++++++++++++++++++++++++++ odb/relational/mssql/source.cxx | 35 +++++++++++++++++++++-- 2 files changed, 95 insertions(+), 3 deletions(-) (limited to 'odb/relational') diff --git a/odb/relational/mssql/common.hxx b/odb/relational/mssql/common.hxx index 5bd37f5..eacc435 100644 --- a/odb/relational/mssql/common.hxx +++ b/odb/relational/mssql/common.hxx @@ -357,6 +357,69 @@ namespace relational private: string type_id_; }; + + struct has_long_data: object_columns_base, context + { + has_long_data (bool& r): r_ (r) {} + + virtual bool + traverse_column (semantics::data_member& m, string const&, bool) + { + if (inverse (m)) + return false; + + sql_type const& st (column_sql_type (m)); + + switch (st.type) + { + case sql_type::CHAR: + case sql_type::VARCHAR: + { + // Zero precision means max in VARCHAR(max). + // + if (st.prec == 0 || st.prec > options.mssql_short_limit ()) + r_ = true; + + break; + } + case sql_type::NCHAR: + case sql_type::NVARCHAR: + { + // Zero precision means max in NVARCHAR(max). Note that + // the precision is in 2-byte UCS-2 characters, not bytes. + // + if (st.prec == 0 || st.prec * 2 > options.mssql_short_limit ()) + r_ = true; + + break; + } + case sql_type::BINARY: + case sql_type::VARBINARY: + { + // Zero precision means max in VARCHAR(max). + // + if (st.prec == 0 || st.prec > options.mssql_short_limit ()) + r_ = true; + + break; + } + case sql_type::TEXT: + case sql_type::NTEXT: + case sql_type::IMAGE: + { + r_ = true; + break; + } + default: + break; + } + + return true; + } + + private: + bool& r_; + }; } } #endif // ODB_RELATIONAL_MSSQL_COMMON_HXX diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx index 0e449dd..afb5887 100644 --- a/odb/relational/mssql/source.cxx +++ b/odb/relational/mssql/source.cxx @@ -1297,12 +1297,41 @@ namespace relational relational::query_parameters&, persist_position p) { - if (p != persist_after_columns) + semantics::data_member* id (id_member (c)); + + if (id == 0 || !auto_ (*id)) return; - semantics::data_member* id (id_member (c)); + // SQL Server 2005 has a bug that causes it to fail on an + // INSERT statement with the OUTPUT clause if data for one + // of the inserted columns is supplied at execution (long + // data). To work around this problem we use the less + // efficient batch of INSERT and SELECT statements. + // + if (options.mssql_server_version () <= mssql_version (9, 0)) + { + bool ld (false); + + if (c.count ("mssql-has-long-data")) + ld = c.get ("mssql-has-long-data"); + else + { + has_long_data t (ld); + t.traverse (c); + c.set ("mssql-has-long-data", ld); + } + + if (ld) + { + if (p == persist_after_values) + os << endl + << strlit ("; SELECT SCOPE_IDENTITY()"); + + return; + } + } - if (id != 0 && id->count ("auto")) + if (p == persist_after_columns) os << strlit (" OUTPUT INSERTED." + column_qname (*id)) << endl; } -- cgit v1.1