Mentions légales du service

Skip to content
Snippets Groups Projects
Commit c025cc86 authored by Vadim Zeitlin's avatar Vadim Zeitlin
Browse files

Fix inserting strings longer than 8000 bytes with ODBC/MS SQL.

Use SQL_LONGVARCHAR and SQL_SS_LENGTH_UNLIMITED for such strings, otherwise
they were silently truncated when inserting them into an nvarchar(max) column.

See #287.
parent ba453c7d
Branches
Tags
No related merge requests found
...@@ -11,6 +11,9 @@ Version 4.0.0 differs from 3.2.x in the following ways: ...@@ -11,6 +11,9 @@ Version 4.0.0 differs from 3.2.x in the following ways:
-- Add SOCI_FIREBIRD_EMBEDDED option to allow building with embedded library. -- Add SOCI_FIREBIRD_EMBEDDED option to allow building with embedded library.
-- Throw an exception instead of truncating too long VARCHAR columns values. -- Throw an exception instead of truncating too long VARCHAR columns values.
- ODBC/MS SQL
-- Fix inserting strings of length greater than 8000 bytes into database.
- Oracle - Oracle
-- Use SQLT_BDOUBLE for floating point values instead of SQLT_FLT. -- Use SQLT_BDOUBLE for floating point values instead of SQLT_FLT.
......
...@@ -99,6 +99,15 @@ void* odbc_standard_use_type_backend::prepare_for_bind( ...@@ -99,6 +99,15 @@ void* odbc_standard_use_type_backend::prepare_for_bind(
memcpy(buf_, s.c_str(), size); memcpy(buf_, s.c_str(), size);
buf_[size++] = '\0'; buf_[size++] = '\0';
indHolder_ = SQL_NTS; indHolder_ = SQL_NTS;
// Strings of greater length are silently truncated at 8000 limit by MS
// SQL unless SQL_SS_LENGTH_UNLIMITED (which is defined as 0, but not
// available in all headers) is used.
if (size > 8000)
{
sqlType = SQL_LONGVARCHAR;
size = 0 /* SQL_SS_LENGTH_UNLIMITED */;
}
} }
break; break;
case x_stdtm: case x_stdtm:
......
...@@ -19,6 +19,60 @@ using namespace soci::tests; ...@@ -19,6 +19,60 @@ using namespace soci::tests;
std::string connectString; std::string connectString;
backend_factory const &backEnd = *soci::factory_odbc(); backend_factory const &backEnd = *soci::factory_odbc();
// MS SQL-specific tests
TEST_CASE("MS SQL long string", "[odbc][mssql][long]")
{
session sql(backEnd, connectString);
struct long_text_table_creator : public table_creator_base
{
explicit long_text_table_creator(session& sql)
: table_creator_base(sql)
{
// Notice that 4000 is the maximal length of an nvarchar() column,
// at least when using FreeTDS ODBC driver.
sql << "create table soci_test ("
"long_text nvarchar(max) null, "
"fixed_text nvarchar(4000) null"
")";
}
} long_text_table_creator(sql);
// Build a string at least 8000 characters long to test that it survives
// the round trip unscathed.
std::ostringstream os;
for ( int n = 0; n < 1000; ++n )
{
os << "Line #" << n << "\n";
}
std::string const str_in = os.str();
sql << "insert into soci_test(long_text) values(:str)", use(str_in);
std::string str_out;
sql << "select long_text from soci_test", into(str_out);
// Don't just compare the strings because the error message in case they
// differ is completely unreadable due to their size, so give a better
// error in the common failure case.
if (str_out.length() != str_in.length())
{
FAIL("Read back string of length " << str_out.length() <<
" instead of expected " << str_in.length());
}
else
{
CHECK(str_out == str_in);
}
// The long string should be truncated when inserting it into a fixed size
// column.
CHECK_THROWS_AS(
(sql << "insert into soci_test(fixed_text) values(:str)", use(str_in)),
soci_error
);
}
// DDL Creation objects for common tests // DDL Creation objects for common tests
struct table_creator_one : public table_creator_base struct table_creator_one : public table_creator_base
{ {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment