mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-12 10:13:51 +01:00
fix(Data): Poco::Data::ODBC-dbEncoding property not used for insert/update #3396
This commit is contained in:
parent
87a1294c75
commit
08d68ea474
@ -71,7 +71,9 @@ public:
|
||||
Binder(const StatementHandle& rStmt,
|
||||
std::size_t maxFieldSize,
|
||||
ParameterBinding dataBinding = PB_IMMEDIATE,
|
||||
const TypeInfo* pDataTypes = 0);
|
||||
const TypeInfo* pDataTypes = 0,
|
||||
Poco::TextEncoding::Ptr pFromEncoding = nullptr,
|
||||
Poco::TextEncoding::Ptr pDBEncoding = nullptr);
|
||||
/// Creates the Binder.
|
||||
|
||||
~Binder();
|
||||
@ -538,7 +540,7 @@ private:
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
void bindImplContainerString(std::size_t pos, const C& val, Direction dir)
|
||||
void bindImplContainerString(std::size_t pos, const C& valC, Direction dir)
|
||||
/// Utility function to bind containers of strings.
|
||||
{
|
||||
if (isOutBound(dir) || !isInBound(dir))
|
||||
@ -547,7 +549,19 @@ private:
|
||||
if (PB_IMMEDIATE != _paramBinding)
|
||||
throw InvalidAccessException("Containers can only be bound immediately.");
|
||||
|
||||
std::size_t length = val.size();
|
||||
const C* pVal = 0;
|
||||
if (!transcodeRequired()) pVal = &valC;
|
||||
else
|
||||
{
|
||||
pVal = new C(valC.size());
|
||||
typename C::const_iterator valIt = valC.begin();
|
||||
typename C::const_iterator valEnd = valC.end();
|
||||
typename C::iterator tcIt = const_cast<C*>(pVal)->begin();
|
||||
for (; valIt != valEnd; ++valIt, ++tcIt)
|
||||
transcode(*valIt, *tcIt);
|
||||
}
|
||||
|
||||
std::size_t length = pVal->size();
|
||||
|
||||
if (0 == length)
|
||||
throw InvalidArgumentException("Empty container not allowed.");
|
||||
@ -560,7 +574,7 @@ private:
|
||||
|
||||
if (size == _maxFieldSize)
|
||||
{
|
||||
getMinValueSize(val, size);
|
||||
getMinValueSize(*pVal, size);
|
||||
// accomodate for terminating zero
|
||||
if (size != _maxFieldSize) ++size;
|
||||
}
|
||||
@ -574,20 +588,25 @@ private:
|
||||
if (_charPtrs.size() <= pos)
|
||||
_charPtrs.resize(pos + 1, 0);
|
||||
|
||||
_charPtrs[pos] = (char*) std::calloc(val.size() * size, sizeof(char));
|
||||
_charPtrs[pos] = (char*) std::calloc(pVal->size() * size, sizeof(char));
|
||||
|
||||
std::string typeID = typeid(*pVal).name();
|
||||
std::size_t strSize;
|
||||
std::size_t offset = 0;
|
||||
typename C::const_iterator it = val.begin();
|
||||
typename C::const_iterator end = val.end();
|
||||
typename C::const_iterator it = pVal->begin();
|
||||
typename C::const_iterator end = pVal->end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
strSize = it->size();
|
||||
if (strSize > size)
|
||||
throw LengthExceededException("SQLBindParameter(std::vector<std::string>)");
|
||||
{
|
||||
if (transcodeRequired()) delete pVal;
|
||||
throw LengthExceededException(Poco::format("SQLBindParameter(%s)", typeID));
|
||||
}
|
||||
std::memcpy(_charPtrs[pos] + offset, it->c_str(), strSize);
|
||||
offset += size;
|
||||
}
|
||||
if (transcodeRequired()) delete pVal;
|
||||
|
||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
@ -600,7 +619,7 @@ private:
|
||||
(SQLINTEGER) size,
|
||||
&(*_vecLengthIndicator[pos])[0])))
|
||||
{
|
||||
throw StatementException(_rStmt, "SQLBindParameter(std::vector<std::string>)");
|
||||
throw StatementException(_rStmt, Poco::format("SQLBindParameter(%s)", typeID));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,8 @@ public:
|
||||
|
||||
Extractor(const StatementHandle& rStmt,
|
||||
Preparator::Ptr pPreparator,
|
||||
Poco::TextEncoding::Ptr pDBEncoding = nullptr);
|
||||
Poco::TextEncoding::Ptr pDBEncoding = nullptr,
|
||||
Poco::TextEncoding::Ptr pToEncoding = nullptr);
|
||||
/// Creates the Extractor.
|
||||
|
||||
~Extractor();
|
||||
|
@ -30,7 +30,10 @@ namespace ODBC {
|
||||
Binder::Binder(const StatementHandle& rStmt,
|
||||
std::size_t maxFieldSize,
|
||||
Binder::ParameterBinding dataBinding,
|
||||
const TypeInfo* pDataTypes):
|
||||
const TypeInfo* pDataTypes,
|
||||
Poco::TextEncoding::Ptr pFromEncoding,
|
||||
Poco::TextEncoding::Ptr pDBEncoding):
|
||||
Poco::Data::AbstractBinder(pFromEncoding, pDBEncoding),
|
||||
_rStmt(rStmt),
|
||||
_paramBinding(dataBinding),
|
||||
_pTypeInfo(pDataTypes),
|
||||
@ -99,13 +102,30 @@ void Binder::freeMemory()
|
||||
DateTimeVecVec::iterator itDateTimeVec = _dateTimeVecVec.begin();
|
||||
DateTimeVecVec::iterator itDateTimeVecEnd = _dateTimeVecVec.end();
|
||||
for (; itDateTimeVec != itDateTimeVecEnd; ++itDateTimeVec) delete *itDateTimeVec;
|
||||
|
||||
if (transcodeRequired() && _inParams.size())
|
||||
{
|
||||
ParamMap::iterator itInParams = _inParams.begin();
|
||||
ParamMap::iterator itInParamsEnd = _inParams.end();
|
||||
for (; itInParams != itInParamsEnd; ++itInParams) free(itInParams->first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
|
||||
{
|
||||
char* pTCVal = 0;
|
||||
SQLINTEGER size = 0;
|
||||
if (transcodeRequired())
|
||||
{
|
||||
std::string tcVal;
|
||||
transcode(val, tcVal);
|
||||
size = (SQLINTEGER)tcVal.size();
|
||||
pTCVal = reinterpret_cast<char*>(std::calloc((size_t)size+1, 1));
|
||||
std::memcpy(pTCVal, tcVal.data(), size);
|
||||
}
|
||||
else size = (SQLINTEGER)val.size();
|
||||
SQLPOINTER pVal = 0;
|
||||
SQLINTEGER size = (SQLINTEGER) val.size();
|
||||
SQLINTEGER colSize = 0;
|
||||
SQLSMALLINT decDigits = 0;
|
||||
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits, val.size());
|
||||
@ -120,8 +140,16 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
|
||||
}
|
||||
else if (isInBound(dir))
|
||||
{
|
||||
pVal = (SQLPOINTER) val.c_str();
|
||||
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||
if (!pTCVal)
|
||||
{
|
||||
pVal = (SQLPOINTER)val.c_str();
|
||||
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||
}
|
||||
else
|
||||
{
|
||||
pVal = (SQLPOINTER)pTCVal;
|
||||
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||
}
|
||||
}
|
||||
else
|
||||
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
|
||||
@ -421,12 +449,28 @@ void Binder::synchronize()
|
||||
Utility::dateTimeSync(*it->second, *it->first);
|
||||
}
|
||||
|
||||
if (_strings.size())
|
||||
if (!transcodeRequired())
|
||||
{
|
||||
StringMap::iterator it = _strings.begin();
|
||||
StringMap::iterator end = _strings.end();
|
||||
for(; it != end; ++it)
|
||||
it->second->assign(it->first, std::strlen(it->first));
|
||||
if (_strings.size())
|
||||
{
|
||||
StringMap::iterator it = _strings.begin();
|
||||
StringMap::iterator end = _strings.end();
|
||||
for (; it != end; ++it)
|
||||
it->second->assign(it->first, std::strlen(it->first));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_strings.size())
|
||||
{
|
||||
StringMap::iterator it = _strings.begin();
|
||||
StringMap::iterator end = _strings.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
std::string str(it->first, std::strlen(it->first));
|
||||
reverseTranscode(str, *it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_uuids.size())
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "Poco/Data/ODBC/ConnectionHandle.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Error.h"
|
||||
#include "Poco/Debugger.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -42,10 +44,11 @@ ConnectionHandle::~ConnectionHandle()
|
||||
{
|
||||
SQLDisconnect(_hdbc);
|
||||
SQLRETURN rc = SQLFreeHandle(SQL_HANDLE_DBC, _hdbc);
|
||||
|
||||
if (_ownsEnvironment) delete _pEnvironment;
|
||||
|
||||
poco_assert (!Utility::isError(rc));
|
||||
#if defined(_DEBUG)
|
||||
if (Utility::isError(rc))
|
||||
Debugger::enter(Poco::Error::getMessage(Poco::Error::last()), __FILE__, __LINE__);
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "Poco/Data/ODBC/EnvironmentHandle.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Error.h"
|
||||
#include "Poco/Debugger.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -42,7 +44,10 @@ EnvironmentHandle::~EnvironmentHandle()
|
||||
try
|
||||
{
|
||||
SQLRETURN rc = SQLFreeHandle(SQL_HANDLE_ENV, _henv);
|
||||
poco_assert (!Utility::isError(rc));
|
||||
#if defined(_DEBUG)
|
||||
if (Utility::isError(rc))
|
||||
Debugger::enter(Poco::Error::getMessage(Poco::Error::last()), __FILE__, __LINE__);
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -35,7 +35,8 @@ const std::string Extractor::FLD_SIZE_EXCEEDED_FMT = "Specified data size (%z by
|
||||
|
||||
Extractor::Extractor(const StatementHandle& rStmt,
|
||||
Preparator::Ptr pPreparator,
|
||||
TextEncoding::Ptr pDBEncoding): AbstractExtractor(pDBEncoding),
|
||||
TextEncoding::Ptr pDBEncoding,
|
||||
Poco::TextEncoding::Ptr pToEncoding): AbstractExtractor(pDBEncoding, pToEncoding),
|
||||
_rStmt(rStmt),
|
||||
_pPreparator(pPreparator),
|
||||
_dataExtraction(pPreparator->getDataExtraction())
|
||||
@ -719,6 +720,7 @@ bool Extractor::extract(std::size_t pos, std::string& val)
|
||||
else
|
||||
ret = extractBoundImpl(pos, result);
|
||||
transcode(result, val);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -98,7 +98,8 @@ void ODBCStatementImpl::compileImpl()
|
||||
|
||||
std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
|
||||
|
||||
_pBinder = new Binder(_stmt, maxFieldSize, bind, pDT);
|
||||
_pBinder = new Binder(_stmt, maxFieldSize, bind, pDT, TextEncoding::find("UTF-8"),
|
||||
TextEncoding::find(Poco::RefAnyCast<std::string>(session().getProperty("dbEncoding"))));
|
||||
|
||||
makeInternalExtractors();
|
||||
doPrepare();
|
||||
@ -146,7 +147,8 @@ void ODBCStatementImpl::addPreparator()
|
||||
_preparations.push_back(new Preparator(*_preparations[0]));
|
||||
|
||||
_extractors.push_back(new Extractor(_stmt, _preparations.back(),
|
||||
TextEncoding::find(Poco::RefAnyCast<std::string>(session().getProperty("dbEncoding")))));
|
||||
TextEncoding::find(Poco::RefAnyCast<std::string>(session().getProperty("dbEncoding"))),
|
||||
TextEncoding::find("UTF-8")));
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,6 +87,7 @@ using Poco::DateTime;
|
||||
|
||||
|
||||
ODBCTest::SessionPtr ODBCSQLServerTest::_pSession;
|
||||
ODBCTest::SessionPtr ODBCSQLServerTest::_pEncSession;
|
||||
ODBCTest::ExecPtr ODBCSQLServerTest::_pExecutor;
|
||||
std::string ODBCSQLServerTest::_driver = MS_SQL_SERVER_ODBC_DRIVER;
|
||||
std::string ODBCSQLServerTest::_dsn = MS_SQL_SERVER_DSN;
|
||||
@ -733,13 +734,28 @@ void ODBCSQLServerTest::recreateUnicodeTable()
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::recreateEncodingTables()
|
||||
{
|
||||
#if defined (POCO_ODBC_UNICODE)
|
||||
dropObject("TABLE", "Latin1Table");
|
||||
try { session() << "CREATE TABLE Latin1Table (str NVARCHAR(30))", now; }
|
||||
catch (ConnectionException& ce) { std::cout << ce.toString() << std::endl; fail("recreateEncodingTables()"); }
|
||||
catch (StatementException& se) { std::cout << se.toString() << std::endl; fail("recreateEncodingTables()"); }
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
{
|
||||
if ((_pSession = init(_driver, _dsn, _uid, _pwd, _connectString, _db)))
|
||||
{
|
||||
std::cout << "*** Connected to [" << _driver << "] test database." << std::endl;
|
||||
std::string enc = "Latin1";
|
||||
if ((_pEncSession = init(_driver, _dsn, _uid, _pwd, _connectString, _db, enc)))
|
||||
std::cout << "*** Connected to [" << _driver << "] test database, encoding: [" << enc << "]." << std::endl;
|
||||
// ...
|
||||
|
||||
_pExecutor = new SQLExecutor(_driver + " SQL Executor", _pSession);
|
||||
_pExecutor = new SQLExecutor(_driver + " SQL Executor", _pSession, _pEncSession);
|
||||
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCSQLServerTest");
|
||||
|
||||
@ -822,6 +838,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransactor);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNullable);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testUnicode);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testEncoding);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testReconnect);
|
||||
|
||||
return pSuite;
|
||||
|
@ -74,8 +74,10 @@ private:
|
||||
void recreateMiscTable();
|
||||
void recreateLogTable();
|
||||
void recreateUnicodeTable();
|
||||
void recreateEncodingTables();
|
||||
|
||||
static SessionPtr _pSession;
|
||||
static SessionPtr _pEncSession;
|
||||
static ExecPtr _pExecutor;
|
||||
static std::string _driver;
|
||||
static std::string _dsn;
|
||||
|
@ -1252,6 +1252,25 @@ void ODBCTest::testUnicode()
|
||||
}
|
||||
|
||||
|
||||
void ODBCTest::testEncoding()
|
||||
{
|
||||
#if defined (POCO_ODBC_UNICODE)
|
||||
if (!_pSession) fail("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateEncodingTables();
|
||||
_pSession->setFeature("autoBind", bindValue(i));
|
||||
_pSession->setFeature("autoExtract", bindValue(i + 1));
|
||||
_pExecutor->encoding(_rConnectString);
|
||||
i += 2;
|
||||
}
|
||||
#else
|
||||
std::cout << "Not an UNICODE build, skipping." << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void ODBCTest::testReconnect()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@ -1341,7 +1360,8 @@ ODBCTest::SessionPtr ODBCTest::init(const std::string& driver,
|
||||
std::string& uid,
|
||||
std::string& pwd,
|
||||
std::string& dbConnString,
|
||||
const std::string& db)
|
||||
const std::string& db,
|
||||
const std::string& dbEncoding)
|
||||
{
|
||||
Utility::drivers(_drivers);
|
||||
if (!canConnect(driver, dsn, uid, pwd, dbConnString, db)) return 0;
|
||||
@ -1349,7 +1369,10 @@ ODBCTest::SessionPtr ODBCTest::init(const std::string& driver,
|
||||
try
|
||||
{
|
||||
std::cout << "Conecting to [" << dbConnString << ']' << std::endl;
|
||||
return new Session(Poco::Data::ODBC::Connector::KEY, dbConnString, 5);
|
||||
SessionPtr ptr = new Session(Poco::Data::ODBC::Connector::KEY, dbConnString, 5);
|
||||
if (!dbEncoding.empty())
|
||||
ptr->setProperty("dbEncoding", dbEncoding);
|
||||
return ptr;
|
||||
}catch (ConnectionFailedException& ex)
|
||||
{
|
||||
std::cout << ex.displayText() << std::endl;
|
||||
|
@ -151,6 +151,7 @@ public:
|
||||
virtual void testNullable();
|
||||
|
||||
virtual void testUnicode();
|
||||
virtual void testEncoding();
|
||||
|
||||
virtual void testReconnect();
|
||||
|
||||
@ -177,13 +178,15 @@ protected:
|
||||
virtual void recreateMiscTable();
|
||||
virtual void recreateLogTable();
|
||||
virtual void recreateUnicodeTable();
|
||||
virtual void recreateEncodingTables();
|
||||
|
||||
static SessionPtr init(const std::string& driver,
|
||||
std::string& dsn,
|
||||
std::string& uid,
|
||||
std::string& pwd,
|
||||
std::string& dbConnString,
|
||||
const std::string& db = "");
|
||||
const std::string& db = "",
|
||||
const std::string& dbEncoding = "");
|
||||
|
||||
static bool canConnect(const std::string& driver,
|
||||
std::string& dsn,
|
||||
@ -374,6 +377,12 @@ inline void ODBCTest::recreateUnicodeTable()
|
||||
}
|
||||
|
||||
|
||||
inline void ODBCTest::recreateEncodingTables()
|
||||
{
|
||||
throw Poco::NotImplementedException("ODBCTest::recreateUnicodeTables()");
|
||||
}
|
||||
|
||||
|
||||
inline bool ODBCTest::bindValue(int i)
|
||||
{
|
||||
poco_assert (i < 8);
|
||||
|
@ -296,9 +296,10 @@ const std::string SQLExecutor::MULTI_SELECT =
|
||||
"SELECT * FROM Test WHERE First = '5';";
|
||||
|
||||
|
||||
SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession):
|
||||
SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession, Poco::Data::Session* pEncSession):
|
||||
CppUnit::TestCase(name),
|
||||
_pSession(pSession)
|
||||
_pSession(pSession),
|
||||
_pEncSession(pEncSession)
|
||||
{
|
||||
}
|
||||
|
||||
@ -3530,6 +3531,7 @@ void SQLExecutor::sqlLogger(const std::string& connect)
|
||||
rs.moveNext();
|
||||
assertTrue ("TestSQLChannel" == rs["Source"]);
|
||||
assertTrue ("b Warning message" == rs["Text"]);
|
||||
root.setChannel(nullptr);
|
||||
}
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("sqlLogger()"); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("sqlLogger()"); }
|
||||
@ -4033,4 +4035,55 @@ void SQLExecutor::unicode(const std::string& dbConnString)
|
||||
session() << "SELECT str FROM UnicodeTable", into(wtext), now;
|
||||
Poco::UnicodeConverter::convert(wtext, text);
|
||||
assertTrue (text == std::string((const char*)supp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::encoding(const std::string& dbConnString)
|
||||
{
|
||||
try
|
||||
{
|
||||
const unsigned char latinChars[] = { 'g', 252, 'n', 't', 'e', 'r', 0 };
|
||||
const unsigned char utf8Chars[] = { 'g', 195, 188, 'n', 't', 'e', 'r', 0 };
|
||||
std::string latinText((const char*)latinChars);
|
||||
std::string utf8TextIn((const char*)utf8Chars);
|
||||
|
||||
session(true) << "INSERT INTO Latin1Table VALUES (?)", use(utf8TextIn), now;
|
||||
|
||||
std::string latinTextOut;
|
||||
session() << "SELECT str FROM Latin1Table", into(latinTextOut), now;
|
||||
assertTrue(latinText == latinTextOut);
|
||||
|
||||
std::string utf8TextOut;
|
||||
session(true) << "SELECT str FROM Latin1Table", into(utf8TextOut), now;
|
||||
assertTrue(utf8TextIn == utf8TextOut);
|
||||
|
||||
const unsigned char latinChars2[] = { 'G', 220, 'N', 'T', 'E', 'R', 0 };
|
||||
const unsigned char utf8Chars2[] = { 'G', 195, 156, 'N', 'T', 'E', 'R', 0 };
|
||||
std::string latinText2 = (const char*)latinChars2;
|
||||
std::string utf8TextIn2 = (const char*)utf8Chars2;
|
||||
|
||||
session(true) << "INSERT INTO Latin1Table VALUES (?)", use(utf8TextIn2), now;
|
||||
|
||||
std::vector<std::string> textOutVec;
|
||||
session() << "SELECT str FROM Latin1Table", into(textOutVec), now;
|
||||
assertTrue(textOutVec.size() == 2);
|
||||
assertTrue(textOutVec[0] == latinText);
|
||||
assertTrue(textOutVec[1] == latinText2);
|
||||
|
||||
textOutVec.clear();
|
||||
session(true) << "SELECT str FROM Latin1Table", into(textOutVec), now;
|
||||
assertTrue(textOutVec.size() == 2);
|
||||
assertTrue(textOutVec[0] == utf8TextIn);
|
||||
assertTrue(textOutVec[1] == utf8TextIn2);
|
||||
}
|
||||
catch (Poco::Exception& ex)
|
||||
{
|
||||
std::cout << ex.displayText() << std::endl;
|
||||
throw;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << ex.what() << std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public:
|
||||
DE_BOUND
|
||||
};
|
||||
|
||||
SQLExecutor(const std::string& name, Poco::Data::Session* _pSession);
|
||||
SQLExecutor(const std::string& name, Poco::Data::Session* pSession, Poco::Data::Session* pEncSession = 0);
|
||||
~SQLExecutor();
|
||||
|
||||
void execute(const std::string& sql);
|
||||
@ -505,6 +505,7 @@ public:
|
||||
void nullable();
|
||||
|
||||
void unicode(const std::string& dbConnString);
|
||||
void encoding(const std::string& dbConnString);
|
||||
|
||||
void reconnect();
|
||||
|
||||
@ -514,15 +515,24 @@ private:
|
||||
|
||||
void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti);
|
||||
|
||||
Poco::Data::Session& session();
|
||||
Poco::Data::Session& session(bool enc = false);
|
||||
Poco::Data::Session* _pSession;
|
||||
Poco::Data::Session* _pEncSession;
|
||||
};
|
||||
|
||||
|
||||
inline Poco::Data::Session& SQLExecutor::session()
|
||||
inline Poco::Data::Session& SQLExecutor::session(bool enc)
|
||||
{
|
||||
poco_check_ptr (_pSession);
|
||||
return *_pSession;
|
||||
if (!enc)
|
||||
{
|
||||
poco_check_ptr(_pSession);
|
||||
return *_pSession;
|
||||
}
|
||||
else
|
||||
{
|
||||
poco_check_ptr(_pEncSession);
|
||||
return *_pEncSession;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "Poco/Any.h"
|
||||
#include "Poco/Dynamic/Var.h"
|
||||
#include "Poco/UTFString.h"
|
||||
#include "Poco/TextEncoding.h"
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
@ -39,7 +40,7 @@ namespace Data {
|
||||
|
||||
|
||||
using NullData = NullType;
|
||||
|
||||
class Transcoder;
|
||||
|
||||
namespace Keywords {
|
||||
|
||||
@ -64,7 +65,8 @@ public:
|
||||
PD_IN_OUT
|
||||
};
|
||||
|
||||
AbstractBinder();
|
||||
AbstractBinder(Poco::TextEncoding::Ptr pFromEncoding = nullptr,
|
||||
Poco::TextEncoding::Ptr pDBEncoding = nullptr);
|
||||
/// Creates the AbstractBinder.
|
||||
|
||||
virtual ~AbstractBinder();
|
||||
@ -356,6 +358,14 @@ public:
|
||||
|
||||
static bool isInBound(Direction dir);
|
||||
/// Returns true if direction is in bound;
|
||||
|
||||
protected:
|
||||
bool transcodeRequired() const;
|
||||
void transcode(const std::string& from, std::string& to);
|
||||
void reverseTranscode(const std::string& from, std::string& to);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Transcoder> _pTranscoder;
|
||||
};
|
||||
|
||||
|
||||
@ -380,6 +390,12 @@ inline bool AbstractBinder::isInBound(Direction dir)
|
||||
}
|
||||
|
||||
|
||||
inline bool AbstractBinder::transcodeRequired() const
|
||||
{
|
||||
return _pTranscoder.operator bool();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "Poco/Data/LOB.h"
|
||||
#include "Poco/UUID.h"
|
||||
#include "Poco/UTFString.h"
|
||||
#include "Poco/TextConverter.h"
|
||||
#include "Poco/TextEncoding.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@ -35,7 +34,6 @@
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
class DateTime;
|
||||
class Any;
|
||||
|
||||
@ -48,6 +46,7 @@ namespace Data {
|
||||
|
||||
class Date;
|
||||
class Time;
|
||||
class Transcoder;
|
||||
|
||||
|
||||
class Data_API AbstractExtractor
|
||||
@ -353,18 +352,18 @@ public:
|
||||
|
||||
protected:
|
||||
bool transcodeRequired() const;
|
||||
void transcode(const std::string& val1, std::string& val2);
|
||||
void transcode(const std::string& from, std::string& to);
|
||||
void reverseTranscode(const std::string& from, std::string& to);
|
||||
|
||||
private:
|
||||
Poco::TextEncoding::Ptr _pDBEncoding;
|
||||
Poco::TextEncoding::Ptr _pToEncoding;
|
||||
std::unique_ptr<Poco::TextConverter> _pConverter;
|
||||
std::unique_ptr<Transcoder> _pTranscoder;
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// inlines
|
||||
///
|
||||
|
||||
inline void AbstractExtractor::reset()
|
||||
{
|
||||
//default no-op
|
||||
@ -373,17 +372,7 @@ inline void AbstractExtractor::reset()
|
||||
|
||||
inline bool AbstractExtractor::transcodeRequired() const
|
||||
{
|
||||
return _pConverter.operator bool();
|
||||
}
|
||||
|
||||
|
||||
inline void AbstractExtractor::transcode(const std::string& val1, std::string& val2)
|
||||
{
|
||||
if (_pConverter)
|
||||
{
|
||||
val2.clear();
|
||||
_pConverter->convert(val1, val2);
|
||||
}
|
||||
return _pTranscoder.operator bool();
|
||||
}
|
||||
|
||||
|
||||
|
@ -47,7 +47,7 @@ class Binding: public AbstractBinding
|
||||
/// is passed to binding, the storage it refers to must be valid at the statement execution time.
|
||||
/// To pass a copy of a variable, constant or string literal, use utility function bind().
|
||||
/// Variables can be passed as either copies or references (i.e. using either use() or bind()).
|
||||
/// Constants, however, can only be passed as copies. this is best achieved using bind() utility
|
||||
/// Constants, however, can only be passed as copies. This is best achieved using bind() utility
|
||||
/// function. An attempt to pass a constant by reference shall result in compile-time error.
|
||||
{
|
||||
public:
|
||||
|
97
Data/include/Poco/Data/Transcoder.h
Normal file
97
Data/include/Poco/Data/Transcoder.h
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// Transcoder.h
|
||||
//
|
||||
// Library: Data
|
||||
// Package: DataCore
|
||||
// Module: Transcoder
|
||||
//
|
||||
// Definition of the Transcoder class.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef Data_Transcoder_INCLUDED
|
||||
#define Data_Transcoder_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Data/Data.h"
|
||||
#include "Poco/TextConverter.h"
|
||||
#include "Poco/TextEncoding.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
|
||||
class Data_API Transcoder
|
||||
/// Utility class used to convert string data encoding.
|
||||
///
|
||||
/// The purpose of this class is to help with deciding
|
||||
/// whether conversion is actually required, and to keep
|
||||
/// the encodings lifetimes aligned with the converter lifetime.
|
||||
{
|
||||
public:
|
||||
using Ptr = std::unique_ptr<Transcoder>;
|
||||
using ConverterPtr = std::unique_ptr<Poco::TextConverter>;
|
||||
|
||||
virtual ~Transcoder();
|
||||
/// Destroys the Transcoder.
|
||||
|
||||
static Ptr create(Poco::TextEncoding::Ptr pFromEncoding = nullptr,
|
||||
Poco::TextEncoding::Ptr pToEncoding = nullptr);
|
||||
/// Returns a unique pointer to Transcode instance;
|
||||
/// if there is no need for transcoding, null pointer
|
||||
/// is returned.
|
||||
|
||||
std::string fromEncoding() const;
|
||||
/// Returns "from" encoding canonical name.
|
||||
|
||||
std::string toEncoding() const;
|
||||
/// Returns "from" encoding canonical name.
|
||||
|
||||
void transcode(const std::string& from, std::string& to);
|
||||
/// Performs the conversion. Any prior content of the
|
||||
/// destination string is cleared.
|
||||
|
||||
void reverseTranscode(const std::string& from, std::string& to);
|
||||
/// Performs the reverse conversion. Any prior content of the
|
||||
/// destination string is cleared.
|
||||
|
||||
private:
|
||||
Transcoder(Poco::TextEncoding::Ptr pFromEncoding,
|
||||
Poco::TextEncoding::Ptr pToEncoding);
|
||||
/// Creates the Transcoder.
|
||||
|
||||
Poco::TextEncoding::Ptr _pFromEncoding;
|
||||
Poco::TextEncoding::Ptr _pToEncoding;
|
||||
ConverterPtr _pConverter;
|
||||
ConverterPtr _pReverseConverter;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
|
||||
inline std::string Transcoder::fromEncoding() const
|
||||
{
|
||||
return _pFromEncoding->canonicalName();
|
||||
}
|
||||
|
||||
|
||||
inline std::string Transcoder::toEncoding() const
|
||||
{
|
||||
return _pToEncoding->canonicalName();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
||||
|
||||
#endif // Data_Transcoder_INCLUDED
|
@ -16,6 +16,7 @@
|
||||
#include "Poco/Data/Date.h"
|
||||
#include "Poco/Data/Time.h"
|
||||
#include "Poco/Data/LOB.h"
|
||||
#include "Poco/Data/Transcoder.h"
|
||||
#include "Poco/Data/DataException.h"
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/Any.h"
|
||||
@ -26,7 +27,9 @@ namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
|
||||
AbstractBinder::AbstractBinder()
|
||||
AbstractBinder::AbstractBinder(Poco::TextEncoding::Ptr pFromEncoding,
|
||||
Poco::TextEncoding::Ptr pDBEncoding) :
|
||||
_pTranscoder(Transcoder::create(pFromEncoding, pDBEncoding))
|
||||
{
|
||||
}
|
||||
|
||||
@ -36,6 +39,20 @@ AbstractBinder::~AbstractBinder()
|
||||
}
|
||||
|
||||
|
||||
void AbstractBinder::transcode(const std::string& from, std::string& to)
|
||||
{
|
||||
if (_pTranscoder)
|
||||
_pTranscoder->transcode(from, to);
|
||||
}
|
||||
|
||||
|
||||
void AbstractBinder::reverseTranscode(const std::string& from, std::string& to)
|
||||
{
|
||||
if (_pTranscoder)
|
||||
_pTranscoder->reverseTranscode(from, to);
|
||||
}
|
||||
|
||||
|
||||
void AbstractBinder::bind(std::size_t pos, const std::vector<Poco::Int8>& val, Direction dir)
|
||||
{
|
||||
throw NotImplementedException("std::vector binder must be implemented.");
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
|
||||
#include "Poco/Data/AbstractExtractor.h"
|
||||
#include "Poco/Data/Transcoder.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
@ -22,16 +23,8 @@ namespace Data {
|
||||
|
||||
AbstractExtractor::AbstractExtractor(Poco::TextEncoding::Ptr pDBEncoding,
|
||||
Poco::TextEncoding::Ptr pToEncoding):
|
||||
_pDBEncoding(pDBEncoding),
|
||||
_pToEncoding(pToEncoding ?
|
||||
pToEncoding : _pDBEncoding ?
|
||||
Poco::TextEncoding::find("UTF-8") : nullptr),
|
||||
_pConverter(_pDBEncoding ?
|
||||
new Poco::TextConverter(*pDBEncoding, *_pToEncoding) :
|
||||
nullptr)
|
||||
_pTranscoder(Transcoder::create(pDBEncoding, pToEncoding))
|
||||
{
|
||||
poco_assert_dbg((!_pDBEncoding && !_pToEncoding) ||
|
||||
(_pDBEncoding && _pToEncoding));
|
||||
}
|
||||
|
||||
|
||||
@ -40,6 +33,20 @@ AbstractExtractor::~AbstractExtractor()
|
||||
}
|
||||
|
||||
|
||||
void AbstractExtractor::transcode(const std::string& from, std::string& to)
|
||||
{
|
||||
if (_pTranscoder)
|
||||
_pTranscoder->transcode(from, to);
|
||||
}
|
||||
|
||||
|
||||
void AbstractExtractor::reverseTranscode(const std::string& from, std::string& to)
|
||||
{
|
||||
if (_pTranscoder)
|
||||
_pTranscoder->reverseTranscode(from, to);
|
||||
}
|
||||
|
||||
|
||||
bool AbstractExtractor::extract(std::size_t pos, std::vector<Poco::Int8>& val)
|
||||
{
|
||||
throw NotImplementedException("std::vector extractor must be implemented.");
|
||||
|
76
Data/src/Transcoder.cpp
Normal file
76
Data/src/Transcoder.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
//
|
||||
// Transcoder.cpp
|
||||
//
|
||||
// Library: Data
|
||||
// Package: DataCore
|
||||
// Module: Transcoder
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Data/Transcoder.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
|
||||
Transcoder::Transcoder(Poco::TextEncoding::Ptr pFromEncoding,
|
||||
Poco::TextEncoding::Ptr pToEncoding):
|
||||
_pFromEncoding(pFromEncoding),
|
||||
_pToEncoding(pToEncoding),
|
||||
_pConverter(new Poco::TextConverter(*_pFromEncoding, *_pToEncoding)),
|
||||
_pReverseConverter(new Poco::TextConverter(*_pToEncoding, *_pFromEncoding))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Transcoder::~Transcoder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Transcoder::Ptr Transcoder::create(Poco::TextEncoding::Ptr pFromEncoding,
|
||||
Poco::TextEncoding::Ptr pToEncoding)
|
||||
{
|
||||
Ptr pTranscoder;
|
||||
|
||||
if (!pFromEncoding && !pToEncoding)
|
||||
return pTranscoder;
|
||||
|
||||
if (!pFromEncoding) pFromEncoding = Poco::TextEncoding::find("UTF-8");
|
||||
if (!pToEncoding) pToEncoding = Poco::TextEncoding::find("UTF-8");
|
||||
|
||||
if (pToEncoding->isA(pFromEncoding->canonicalName()))
|
||||
return pTranscoder;
|
||||
|
||||
pTranscoder.reset(new Transcoder(pFromEncoding, pToEncoding));
|
||||
return pTranscoder;
|
||||
}
|
||||
|
||||
|
||||
void Transcoder::transcode(const std::string& from, std::string& to)
|
||||
{
|
||||
if (_pConverter)
|
||||
{
|
||||
to.clear();
|
||||
_pConverter->convert(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Transcoder::reverseTranscode(const std::string& from, std::string& to)
|
||||
{
|
||||
if (_pConverter)
|
||||
{
|
||||
to.clear();
|
||||
_pReverseConverter->convert(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
@ -1377,6 +1377,9 @@ void DataTest::testTranscode()
|
||||
assertTrue (ext.extract(0, utf8Out));
|
||||
assertTrue(utf8Out == latin1Text);
|
||||
|
||||
Latin1Encoding::Ptr pe = new Latin1Encoding();
|
||||
auto pUTF8E = Poco::TextEncoding::find("UTF-8");
|
||||
|
||||
Poco::Data::Test::Extractor ext2(new Latin1Encoding());
|
||||
ext2.setString(latin1Text);
|
||||
utf8Out.clear();
|
||||
|
@ -7,25 +7,25 @@ progen.libsuffix.release_static_md = md.lib
|
||||
progen.libsuffix.release_static_mt = mt.lib
|
||||
progen.project.guidFromName.namespaceUUID = F4193868-E4EB-4090-9A01-344E7233004B
|
||||
|
||||
progen.postprocess.upgrade2008to2015.tool = ${system.env.VS140COMNTOOLS}\\..\\IDE\\DevEnv.exe
|
||||
progen.postprocess.upgrade2008to2015.tool = ${system.env.VS160COMNTOOLS}\\..\\IDE\\DevEnv.exe
|
||||
progen.postprocess.upgrade2008to2015.args = %;/Upgrade
|
||||
progen.postprocess.upgrade2008to2015.deleteOriginalFile = true
|
||||
progen.postprocess.upgrade2008to2015.deleteFiles = Backup;_UpgradeReport_Files;UpgradeLog.XML;UpgradeLog.htm
|
||||
progen.postprocess.upgrade2008to2015.fix2015ProjectFile = true
|
||||
|
||||
progen.postprocess.upgrade2008to2017.tool = ${system.env.VS150COMNTOOLS}\\..\\IDE\\DevEnv.exe
|
||||
progen.postprocess.upgrade2008to2017.tool = ${system.env.VS160COMNTOOLS}\\..\\IDE\\DevEnv.exe
|
||||
progen.postprocess.upgrade2008to2017.args = %;/Upgrade
|
||||
progen.postprocess.upgrade2008to2017.deleteOriginalFile = true
|
||||
progen.postprocess.upgrade2008to2017.deleteFiles = Backup;_UpgradeReport_Files;UpgradeLog.XML;UpgradeLog.htm
|
||||
progen.postprocess.upgrade2008to2017.fix2017ProjectFile = true
|
||||
|
||||
progen.postprocess.upgrade2008to2019.tool = ${system.env.VS150COMNTOOLS}\\..\\IDE\\DevEnv.exe
|
||||
progen.postprocess.upgrade2008to2019.tool = ${system.env.VS160COMNTOOLS}\\..\\IDE\\DevEnv.exe
|
||||
progen.postprocess.upgrade2008to2019.args = %;/Upgrade
|
||||
progen.postprocess.upgrade2008to2019.deleteOriginalFile = true
|
||||
progen.postprocess.upgrade2008to2019.deleteFiles = Backup;_UpgradeReport_Files;UpgradeLog.XML;UpgradeLog.htm
|
||||
progen.postprocess.upgrade2008to2019.fix2019ProjectFile = true
|
||||
|
||||
progen.postprocess.upgrade2008to2022.tool = ${system.env.VS150COMNTOOLS}\\..\\IDE\\DevEnv.exe
|
||||
progen.postprocess.upgrade2008to2022.tool = ${system.env.VS160COMNTOOLS}\\..\\IDE\\DevEnv.exe
|
||||
progen.postprocess.upgrade2008to2022.args = %;/Upgrade
|
||||
progen.postprocess.upgrade2008to2022.deleteOriginalFile = true
|
||||
progen.postprocess.upgrade2008to2022.deleteFiles = Backup;_UpgradeReport_Files;UpgradeLog.XML;UpgradeLog.htm
|
||||
|
Loading…
Reference in New Issue
Block a user