diff --git a/Data/ODBC/src/Binder.cpp b/Data/ODBC/src/Binder.cpp index 79cccc7dd..b6a592881 100644 --- a/Data/ODBC/src/Binder.cpp +++ b/Data/ODBC/src/Binder.cpp @@ -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(&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(&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) diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp index d08cf03d3..c26d82ecf 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp @@ -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"); + } }