Fix for issue #1043 (#1725)

* Fix for issue #1043

The fix for this issue was partially implemented in development branch.
However, there are still some issue, that were not covered:
1. The std::string overload will sets SQL_LONGVARCHAR as fSqlType if the
output parameter is of type VARCHAR(MAX)
2. The UTF16String overload of bind method:
a) always resolves fSqlType using the size of formal parameter const
std::string& val.
b) allocates half of the size of the SP's output parameter.
3. The _utf16Strings member is not sychronized in Binder::synchronize()
method.
4. The _utf16Strings member is not reset in Binder::reset() method.

* Fixed compiler error for GCC

Fixed compiler error caused by improper getting of UTF16String length in
Binder::synchronize()

* Fix input param initialization in unit test
This commit is contained in:
Orlin Hristov 2017-07-06 01:06:10 +03:00 committed by Aleksandar Fabijanic
parent 3dfcc83257
commit 262079b0f0
2 changed files with 63 additions and 23 deletions

View File

@ -111,6 +111,13 @@ void Binder::freeMemory()
for (; itStr != itStrEnd; ++itStr) std::free(itStr->first);
}
if (_utf16Strings.size() > 0)
{
UTF16StringMap::iterator itStr = _utf16Strings.begin();
UTF16StringMap::iterator itStrEnd = _utf16Strings.end();
for (; itStr != itStrEnd; ++itStr) std::free(itStr->first);
}
if (_charPtrs.size() > 0)
{
CharPtrVec::iterator itChr = _charPtrs.begin();
@ -172,7 +179,6 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const
SQLPOINTER pVal = 0;
SQLINTEGER size = (SQLINTEGER) val.size();
SQLSMALLINT sqType = SQL_LONGVARCHAR;
if (isOutBound(dir))
{
getColumnOrParameterSize(pos, size);
@ -180,13 +186,11 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const
pVal = (SQLPOINTER) pChar;
_outParams.insert(ParamMap::value_type(pVal, size));
_strings.insert(StringMap::value_type(pChar, const_cast<std::string*>(&val)));
if (size < _maxCharColLength) sqType = SQL_VARCHAR;
}
else if (isInBound(dir))
{
pVal = (SQLPOINTER) val.c_str();
_inParams.insert(ParamMap::value_type(pVal, size));
if (size < _maxCharColLength) sqType = SQL_VARCHAR;
}
else
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
@ -204,6 +208,8 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const
_lengthIndicator.push_back(pLenIn);
SQLSMALLINT sqType = (size <= _maxCharColLength) ? SQL_VARCHAR : SQL_LONGVARCHAR;
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
@ -226,11 +232,11 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir, const
SQLPOINTER pVal = 0;
SQLINTEGER size = (SQLINTEGER)(val.size() * sizeof(CharT));
SQLSMALLINT sqType = (val.size() < _maxWCharColLength) ? SQL_WVARCHAR : SQL_WLONGVARCHAR;
if (isOutBound(dir))
{
getColumnOrParameterSize(pos, size);
CharT* pChar = (CharT*)std::calloc(size, 1);
CharT* pChar = (CharT*)std::calloc(size, sizeof(CharT));
pVal = (SQLPOINTER)pChar;
_outParams.insert(ParamMap::value_type(pVal, size));
_utf16Strings.insert(UTF16StringMap::value_type(pChar, const_cast<UTF16String*>(&val)));
@ -259,6 +265,8 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir, const
_lengthIndicator.push_back(pLenIn);
SQLSMALLINT sqType = (size <= _maxWCharColLength) ? SQL_WVARCHAR : SQL_WLONGVARCHAR;
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT)pos + 1,
toODBCDirection(dir),
@ -478,6 +486,14 @@ void Binder::synchronize()
it->second->assign(it->first, std::strlen(it->first));
}
if (_utf16Strings.size())
{
UTF16StringMap::iterator it = _utf16Strings.begin();
UTF16StringMap::iterator end = _utf16Strings.end();
for (; it != end; ++it)
it->second->assign(it->first, UTF16CharTraits::length((UTF16CharTraits::char_type*)it->first));
}
if (_nullCbMap.size())
{
NullCbMap::iterator it = _nullCbMap.begin();
@ -506,6 +522,8 @@ void Binder::reset()
_timestamps.clear();
if (_strings.size() > 0)
_strings.clear();
if (_utf16Strings.size() > 0)
_utf16Strings.clear();
if (_dateVecVec.size() > 0)
_dateVecVec.clear();
if (_timeVecVec.size() > 0)

View File

@ -18,6 +18,7 @@
#include "Poco/Any.h"
#include "Poco/DynamicAny.h"
#include "Poco/Tuple.h"
#include "Poco/UTFString.h"
#include "Poco/DateTime.h"
#include "Poco/Data/RecordSet.h"
#include "Poco/Data/ODBC/Diagnostics.h"
@ -41,6 +42,7 @@ using Poco::Any;
using Poco::AnyCast;
using Poco::DynamicAny;
using Poco::DateTime;
using Poco::UTF16String;
// uncomment to force FreeTDS on Windows
@ -297,27 +299,47 @@ void ODBCSQLServerTest::testStoredProcedure()
k += 2;
}
/*TODO - currently fails with following error:
[Microsoft][ODBC SQL Server Driver][SQL Server]Invalid parameter
2 (''): Data type 0x23 is a deprecated large object, or LOB, but is marked as output parameter.
Deprecated types are not supported as output parameters. Use current large object types instead.
{
session().setFeature("autoBind", true);
session() << "CREATE PROCEDURE storedProcedure(@inParam VARCHAR(MAX), @outParam VARCHAR(MAX) OUTPUT) AS "
"BEGIN "
"SET @outParam = @inParam; "
"END;"
, now;
session().setFeature("autoBind", true);
session() << "CREATE PROCEDURE storedProcedure(@inParam VARCHAR(MAX), @outParam VARCHAR(MAX) OUTPUT) AS "
"BEGIN "
"SET @outParam = @inParam; "
"END;"
, now;
std::string inParam = "123";
std::string outParam;
try {
session() << "{call storedProcedure(?, ?)}", in(inParam), out(outParam), now;
}
catch(StatementException& ex) {
std::cout << ex.toString();
}
assert(outParam == inParam);
dropObject("PROCEDURE", "storedProcedure");
}
std::string inParam = "123";
std::string outParam;
try{
session() << "{call storedProcedure(?, ?)}", in(inParam), out(outParam), now;
}catch(StatementException& ex){std::cout << ex.toString();}
assert(outParam == inParam);
dropObject("PROCEDURE", "storedProcedure");
*/
{
session().setFeature("autoBind", true);
session() << "CREATE PROCEDURE storedProcedure(@inParam NVARCHAR(MAX), @outParam NVARCHAR(MAX) OUTPUT) AS "
"BEGIN "
"SET @outParam = @inParam; "
"END;"
, now;
UTF16String::value_type cs[] = { L'1', L'2', L'3', L'\0' };
UTF16String inParam(cs);
UTF16String outParam;
try {
session() << "{call storedProcedure(?, ?)}", in(inParam), out(outParam), now;
}
catch (StatementException& ex) {
std::cout << ex.toString();
}
assert(outParam == inParam);
dropObject("PROCEDURE", "storedProcedure");
}
}