diff --git a/Data/ODBC/include/Poco/Data/ODBC/Extractor.h b/Data/ODBC/include/Poco/Data/ODBC/Extractor.h index 1779cb618..814574264 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Extractor.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Extractor.h @@ -33,7 +33,6 @@ #include "Poco/Nullable.h" #include "Poco/UTFString.h" #include "Poco/TextEncoding.h" -#include "Poco/TextConverter.h" #include "Poco/Exception.h" #include #ifdef POCO_OS_FAMILY_WINDOWS @@ -592,11 +591,10 @@ private: val.clear(); if (ret) { - Poco::TextConverter conv(*_pDBEncoding, *_pToEncoding); val.resize(res.size()); typename C::iterator vIt = val.begin(); typename C::iterator it = res.begin(); - for (; it != res.end(); ++it, ++vIt) conv.convert(*it, *vIt); + for (; it != res.end(); ++it, ++vIt) transcode(*it, *vIt); } return ret; } @@ -607,7 +605,7 @@ private: bool ret = false; if (Preparator::DE_BOUND == _dataExtraction) { - if (!_transcode) + if (!transcodeRequired()) ret = extractBoundImplContainer(pos, val); else ret = stringContainerExtractConvert(pos, val); @@ -628,9 +626,6 @@ private: PreparatorPtr _pPreparator; Preparator::DataExtraction _dataExtraction; std::vector _lengths; - Poco::TextEncoding::Ptr _pDBEncoding; - bool _transcode; - Poco::TextEncoding::Ptr _pToEncoding; }; diff --git a/Data/ODBC/src/Extractor.cpp b/Data/ODBC/src/Extractor.cpp index 90da78517..2bed64a99 100644 --- a/Data/ODBC/src/Extractor.cpp +++ b/Data/ODBC/src/Extractor.cpp @@ -35,13 +35,10 @@ const std::string Extractor::FLD_SIZE_EXCEEDED_FMT = "Specified data size (%z by Extractor::Extractor(const StatementHandle& rStmt, Preparator::Ptr pPreparator, - TextEncoding::Ptr pDBEncoding): + TextEncoding::Ptr pDBEncoding): AbstractExtractor(pDBEncoding), _rStmt(rStmt), _pPreparator(pPreparator), - _dataExtraction(pPreparator->getDataExtraction()), - _pDBEncoding(pDBEncoding), - _transcode(_pDBEncoding && !_pDBEncoding->isA("UTF-8")), - _pToEncoding(_transcode ? Poco::TextEncoding::find("UTF-8") : nullptr) + _dataExtraction(pPreparator->getDataExtraction()) { } @@ -707,7 +704,7 @@ bool Extractor::extract(std::size_t pos, std::string& val) { bool ret = false; - if (!_transcode) + if (!transcodeRequired()) { if (Preparator::DE_MANUAL == _dataExtraction) ret = extractManualImpl(pos, val, SQL_C_CHAR); @@ -721,8 +718,7 @@ bool Extractor::extract(std::size_t pos, std::string& val) ret = extractManualImpl(pos, result, SQL_C_CHAR); else ret = extractBoundImpl(pos, result); - Poco::TextConverter converter(*_pDBEncoding, *_pToEncoding); - converter.convert(result, val); + transcode(result, val); } return ret; diff --git a/Data/include/Poco/Data/AbstractExtractor.h b/Data/include/Poco/Data/AbstractExtractor.h index 0ad868ab0..104ce6f11 100644 --- a/Data/include/Poco/Data/AbstractExtractor.h +++ b/Data/include/Poco/Data/AbstractExtractor.h @@ -23,6 +23,9 @@ #include "Poco/Data/LOB.h" #include "Poco/UUID.h" #include "Poco/UTFString.h" +#include "Poco/TextConverter.h" +#include "Poco/TextEncoding.h" +#include #include #include #include @@ -54,7 +57,8 @@ class Data_API AbstractExtractor public: using Ptr = SharedPtr; - AbstractExtractor(); + AbstractExtractor(Poco::TextEncoding::Ptr pDBEncoding = nullptr, + Poco::TextEncoding::Ptr pToEncoding = nullptr); /// Creates the AbstractExtractor. virtual ~AbstractExtractor(); @@ -346,6 +350,15 @@ public: virtual void reset(); /// Resets any information internally cached by the extractor. + +protected: + bool transcodeRequired() const; + void transcode(const std::string& val1, std::string& val2); + +private: + Poco::TextEncoding::Ptr _pDBEncoding; + Poco::TextEncoding::Ptr _pToEncoding; + std::unique_ptr _pConverter; }; @@ -358,6 +371,22 @@ 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); + } +} + + } } // namespace Poco::Data diff --git a/Data/src/AbstractExtractor.cpp b/Data/src/AbstractExtractor.cpp index b3ae3ae47..7875b263d 100644 --- a/Data/src/AbstractExtractor.cpp +++ b/Data/src/AbstractExtractor.cpp @@ -20,8 +20,18 @@ namespace Poco { namespace Data { -AbstractExtractor::AbstractExtractor() +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) { + poco_assert_dbg((!_pDBEncoding && !_pToEncoding) || + (_pDBEncoding && _pToEncoding)); } diff --git a/Data/testsuite/src/DataTest.cpp b/Data/testsuite/src/DataTest.cpp index 297d0acdb..9605f5c7d 100644 --- a/Data/testsuite/src/DataTest.cpp +++ b/Data/testsuite/src/DataTest.cpp @@ -9,6 +9,7 @@ #include "DataTest.h" +#include "Extractor.h" #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" #include "Poco/Data/Session.h" @@ -29,6 +30,7 @@ #include "Poco/Dynamic/Var.h" #include "Poco/Data/DynamicLOB.h" #include "Poco/Data/DynamicDateTime.h" +#include "Poco/Latin1Encoding.h" #include "Poco/Exception.h" #include #include @@ -45,6 +47,7 @@ using Poco::UInt32; using Poco::Int64; using Poco::UInt64; using Poco::DateTime; +using Poco::Latin1Encoding; using Poco::Dynamic::Var; using Poco::InvalidAccessException; using Poco::IllegalStateException; @@ -65,6 +68,7 @@ using Poco::Data::Row; using Poco::Data::SimpleRowFormatter; using Poco::Data::Date; using Poco::Data::Time; +using Poco::Data::AbstractExtractor; using Poco::Data::AbstractExtraction; using Poco::Data::AbstractExtractionVec; using Poco::Data::AbstractExtractionVecVec; @@ -1358,6 +1362,29 @@ void DataTest::testExternalBindingAndExtraction() } +void DataTest::testTranscode() +{ + Latin1Encoding::Ptr pL2E = new Latin1Encoding(); + + const unsigned char latin1Chars[] = { 'g', 252, 'n', 't', 'e', 'r', 0 }; + const unsigned char utf8Chars[] = { 'g', 195, 188, 'n', 't', 'e', 'r', 0 }; + std::string latin1Text((const char*)latin1Chars); + std::string utf8Text((const char*)utf8Chars); + + Poco::Data::Test::Extractor ext; + ext.setString(latin1Text); + std::string utf8Out; + assertTrue (ext.extract(0, utf8Out)); + assertTrue(utf8Out == latin1Text); + + Poco::Data::Test::Extractor ext2(new Latin1Encoding()); + ext2.setString(latin1Text); + utf8Out.clear(); + assertTrue(ext2.extract(0, utf8Out)); + assertTrue(utf8Out == utf8Text); +} + + void DataTest::setUp() { } @@ -1388,6 +1415,7 @@ CppUnit::Test* DataTest::suite() CppUnit_addTest(pSuite, DataTest, testRowFormat); CppUnit_addTest(pSuite, DataTest, testDateAndTime); CppUnit_addTest(pSuite, DataTest, testExternalBindingAndExtraction); + CppUnit_addTest(pSuite, DataTest, testTranscode); return pSuite; } diff --git a/Data/testsuite/src/DataTest.h b/Data/testsuite/src/DataTest.h index f530ab0df..6b5015616 100644 --- a/Data/testsuite/src/DataTest.h +++ b/Data/testsuite/src/DataTest.h @@ -43,6 +43,7 @@ public: void testRowFormat(); void testDateAndTime(); void testExternalBindingAndExtraction(); + void testTranscode(); void setUp(); void tearDown(); diff --git a/Data/testsuite/src/Extractor.cpp b/Data/testsuite/src/Extractor.cpp index fdc8df685..dcf046109 100644 --- a/Data/testsuite/src/Extractor.cpp +++ b/Data/testsuite/src/Extractor.cpp @@ -18,7 +18,8 @@ namespace Data { namespace Test { -Extractor::Extractor() +Extractor::Extractor(Poco::TextEncoding::Ptr pDBEncoding): + AbstractExtractor(pDBEncoding) { } @@ -130,7 +131,10 @@ bool Extractor::extract(std::size_t pos, char& val) bool Extractor::extract(std::size_t pos, std::string& val) { - val = ""; + if (!transcodeRequired()) + val = _stringValue; + else + transcode(_stringValue, val); return true; } diff --git a/Data/testsuite/src/Extractor.h b/Data/testsuite/src/Extractor.h index 2e7a2a4a3..86b80f05e 100644 --- a/Data/testsuite/src/Extractor.h +++ b/Data/testsuite/src/Extractor.h @@ -26,7 +26,7 @@ class Extractor: public Poco::Data::AbstractExtractor /// A no-op implementation of AbstractExtractor for testing. { public: - Extractor(); + Extractor(Poco::TextEncoding::Ptr pDBEncoding = nullptr); /// Creates the Extractor. ~Extractor(); @@ -110,6 +110,14 @@ public: /// Returns true if the current row value at pos column is null. void reset(); + + void setString(const std::string& str) + { + _stringValue = str; + } + +private: + std::string _stringValue; };