Commit be4f26fe authored by Vadim Zeitlin's avatar Vadim Zeitlin

Fix the length of strings in ODBC vector operations

Saving a string of length N in the database saved it as a string of
length N+1 with a trailing NUL explicitly written into the database and
reading it back resulted in a string of length N+1 too, i.e. it didn't
survive the round trip (notice that this bug only affected vector
operations, scalar ones worked correctly).

Fix this by not writing the trailing NUL in odbc_vector_use_type_backend
and fix the strings returned from odbc_vector_into_type_backend by not
assuming that they're NUL-terminated any more: in fact, they can be, but
they also can be right-padded with spaces, which need to be removed.

Notice that this does mean that we still have a problem with
inconsistent behaviour for the strings with the trailing spaces between
ODBC backend and others: ODBC one will strip them from the returned
strings, but other backends will not. It is not clear what can be done
about it, unfortunately.
parent 521a8408
......@@ -221,11 +221,33 @@ void odbc_vector_into_type_backend::post_fetch(bool gotData, indicator *ind)
std::vector<std::string> &v(*vp);
char *pos = buf_;
const char *pos = buf_;
std::size_t const vsize = v.size();
for (std::size_t i = 0; i != vsize; ++i)
{
v[i].assign(pos, strlen(pos));
// Find the actual length of the string: for a VARCHAR(N)
// column, it may be right-padded with spaces up to the length
// of the longest string in the result set. This happens with
// at least MS SQL (and the exact behaviour depends on the
// value of the ANSI_PADDING option) and it seems like some
// other ODBC drivers also have options like "PADVARCHAR", so
// it's probably not the only case when it does.
//
// So deal with this generically by just trimming all the
// spaces from the right hand-side.
const char* end = pos + indHolderVec_[i];
while (end != pos)
{
// Pre-decrement as "end" is one past the end, as usual.
if (*--end != ' ')
{
// We must count the last non-space character.
++end;
break;
}
}
v[i].assign(pos, end - pos);
pos += colSize_;
}
}
......
......@@ -165,18 +165,20 @@ void odbc_vector_use_type_backend::prepare_for_bind(void *&data, SQLUINTEGER &si
prepare_indicators(vecSize);
for (std::size_t i = 0; i != vecSize; ++i)
{
std::size_t sz = v[i].length() + 1; // add one for null
std::size_t sz = v[i].length();
indHolderVec_[i] = static_cast<long>(sz);
maxSize = sz > maxSize ? sz : maxSize;
}
maxSize++; // For terminating nul.
buf_ = new char[maxSize * vecSize];
memset(buf_, 0, maxSize * vecSize);
char *pos = buf_;
for (std::size_t i = 0; i != vecSize; ++i)
{
strncpy(pos, v[i].c_str(), v[i].length());
memcpy(pos, v[i].c_str(), v[i].length());
pos += maxSize;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment