mirror of
https://github.com/pocoproject/poco.git
synced 2025-03-31 07:58:24 +02:00
#3321: manually merge ODBC text encoding support
This commit is contained in:
parent
970182b57d
commit
7f720ee6e1
@ -32,6 +32,8 @@
|
||||
#include "Poco/Dynamic/Var.h"
|
||||
#include "Poco/Nullable.h"
|
||||
#include "Poco/UTFString.h"
|
||||
#include "Poco/TextEncoding.h"
|
||||
#include "Poco/TextConverter.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <map>
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
@ -53,7 +55,8 @@ public:
|
||||
typedef Preparator::Ptr PreparatorPtr;
|
||||
|
||||
Extractor(const StatementHandle& rStmt,
|
||||
Preparator::Ptr pPreparator);
|
||||
Preparator::Ptr pPreparator,
|
||||
Poco::TextEncoding::Ptr pDBEncoding = nullptr);
|
||||
/// Creates the Extractor.
|
||||
|
||||
~Extractor();
|
||||
@ -580,6 +583,40 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
bool stringContainerExtractConvert(std::size_t pos, C& val)
|
||||
{
|
||||
bool ret = false;
|
||||
C res;
|
||||
ret = extractBoundImplContainer(pos, res);
|
||||
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);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
bool stringContainerExtract(std::size_t pos, C& val)
|
||||
{
|
||||
bool ret = false;
|
||||
if (Preparator::DE_BOUND == _dataExtraction)
|
||||
{
|
||||
if (!_transcode)
|
||||
ret = extractBoundImplContainer(pos, val);
|
||||
else
|
||||
ret = stringContainerExtractConvert(pos, val);
|
||||
}
|
||||
else
|
||||
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool isNullLengthIndicator(SQLLEN val) const;
|
||||
/// The reason for this utility wrapper are platforms where
|
||||
/// SQLLEN macro (a.k.a. SQLINTEGER) yields 64-bit value,
|
||||
@ -591,6 +628,9 @@ private:
|
||||
PreparatorPtr _pPreparator;
|
||||
Preparator::DataExtraction _dataExtraction;
|
||||
std::vector<SQLLEN> _lengths;
|
||||
Poco::TextEncoding::Ptr _pDBEncoding;
|
||||
bool _transcode;
|
||||
Poco::TextEncoding::Ptr _pToEncoding;
|
||||
};
|
||||
|
||||
|
||||
|
@ -136,8 +136,6 @@ private:
|
||||
/// Called whenever SQLExecute returns SQL_NEED_DATA. This is expected
|
||||
/// behavior for PB_AT_EXEC binding mode.
|
||||
|
||||
void getData();
|
||||
|
||||
void addPreparator();
|
||||
void fillColumns();
|
||||
void checkError(SQLRETURN rc, const std::string& msg="");
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "Poco/Data/ODBC/Handle.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Data/AbstractSessionImpl.h"
|
||||
#include "Poco/TextEncoding.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include "Poco/Mutex.h"
|
||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||
@ -162,6 +163,16 @@ public:
|
||||
/// Returns the timeout (in seconds) for queries,
|
||||
/// or -1 if no timeout has been set.
|
||||
|
||||
void setDBEncoding(const std::string&, const Poco::Any& value);
|
||||
/// Sets the database encoding.
|
||||
/// Value must be of type std::string.
|
||||
|
||||
Poco::Any getDBEncoding(const std::string&) const;
|
||||
/// Returns the database encoding.
|
||||
|
||||
const std::string& dbEncoding() const;
|
||||
/// Returns the database encoding.
|
||||
|
||||
const ConnectionHandle& dbc() const;
|
||||
/// Returns the connection handle.
|
||||
|
||||
@ -193,6 +204,7 @@ private:
|
||||
mutable char _canTransact;
|
||||
bool _inTransaction;
|
||||
int _queryTimeout;
|
||||
std::string _dbEncoding;
|
||||
Poco::FastMutex _mutex;
|
||||
};
|
||||
|
||||
@ -291,6 +303,18 @@ inline int SessionImpl::queryTimeout() const
|
||||
}
|
||||
|
||||
|
||||
inline Poco::Any SessionImpl::getDBEncoding(const std::string&) const
|
||||
{
|
||||
return _dbEncoding;
|
||||
}
|
||||
|
||||
|
||||
inline const std::string& SessionImpl::dbEncoding() const
|
||||
{
|
||||
return _dbEncoding;
|
||||
}
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Data/LOB.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <typeinfo>
|
||||
|
||||
|
||||
@ -35,10 +34,14 @@ const std::string Extractor::FLD_SIZE_EXCEEDED_FMT = "Specified data size (%z by
|
||||
|
||||
|
||||
Extractor::Extractor(const StatementHandle& rStmt,
|
||||
Preparator::Ptr pPreparator):
|
||||
Preparator::Ptr pPreparator,
|
||||
TextEncoding::Ptr pDBEncoding):
|
||||
_rStmt(rStmt),
|
||||
_pPreparator(pPreparator),
|
||||
_dataExtraction(pPreparator->getDataExtraction())
|
||||
_dataExtraction(pPreparator->getDataExtraction()),
|
||||
_pDBEncoding(pDBEncoding),
|
||||
_transcode(_pDBEncoding && !_pDBEncoding->isA("UTF-8")),
|
||||
_pToEncoding(_transcode ? Poco::TextEncoding::find("UTF-8") : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -702,37 +705,45 @@ bool Extractor::extract(std::size_t pos, std::list<double>& val)
|
||||
|
||||
bool Extractor::extract(std::size_t pos, std::string& val)
|
||||
{
|
||||
if (Preparator::DE_MANUAL == _dataExtraction)
|
||||
return extractManualImpl(pos, val, SQL_C_CHAR);
|
||||
bool ret = false;
|
||||
|
||||
if (!_transcode)
|
||||
{
|
||||
if (Preparator::DE_MANUAL == _dataExtraction)
|
||||
ret = extractManualImpl(pos, val, SQL_C_CHAR);
|
||||
else
|
||||
ret = extractBoundImpl(pos, val);
|
||||
}
|
||||
else
|
||||
return extractBoundImpl(pos, val);
|
||||
{
|
||||
std::string result;
|
||||
if (Preparator::DE_MANUAL == _dataExtraction)
|
||||
ret = extractManualImpl(pos, result, SQL_C_CHAR);
|
||||
else
|
||||
ret = extractBoundImpl(pos, result);
|
||||
Poco::TextConverter converter(*_pDBEncoding, *_pToEncoding);
|
||||
converter.convert(result, val);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool Extractor::extract(std::size_t pos, std::vector<std::string>& val)
|
||||
{
|
||||
if (Preparator::DE_BOUND == _dataExtraction)
|
||||
return extractBoundImplContainer(pos, val);
|
||||
else
|
||||
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
|
||||
return stringContainerExtract(pos, val);
|
||||
}
|
||||
|
||||
|
||||
bool Extractor::extract(std::size_t pos, std::deque<std::string>& val)
|
||||
{
|
||||
if (Preparator::DE_BOUND == _dataExtraction)
|
||||
return extractBoundImplContainer(pos, val);
|
||||
else
|
||||
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
|
||||
return stringContainerExtract(pos, val);
|
||||
}
|
||||
|
||||
|
||||
bool Extractor::extract(std::size_t pos, std::list<std::string>& val)
|
||||
{
|
||||
if (Preparator::DE_BOUND == _dataExtraction)
|
||||
return extractBoundImplContainer(pos, val);
|
||||
else
|
||||
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
|
||||
return stringContainerExtract(pos, val);
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,7 +145,8 @@ void ODBCStatementImpl::addPreparator()
|
||||
else
|
||||
_preparations.push_back(new Preparator(*_preparations[0]));
|
||||
|
||||
_extractors.push_back(new Extractor(_stmt, _preparations.back()));
|
||||
_extractors.push_back(new Extractor(_stmt, _preparations.back(),
|
||||
TextEncoding::find(Poco::RefAnyCast<std::string>(session().getProperty("dbEncoding")))));
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,7 +39,8 @@ SessionImpl::SessionImpl(const std::string& connect,
|
||||
_autoExtract(autoExtract),
|
||||
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
||||
_inTransaction(false),
|
||||
_queryTimeout(-1)
|
||||
_queryTimeout(-1),
|
||||
_dbEncoding("UTF-8")
|
||||
{
|
||||
setFeature("bulk", true);
|
||||
open();
|
||||
@ -58,7 +59,8 @@ SessionImpl::SessionImpl(const std::string& connect,
|
||||
_autoExtract(autoExtract),
|
||||
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
||||
_inTransaction(false),
|
||||
_queryTimeout(-1)
|
||||
_queryTimeout(-1),
|
||||
_dbEncoding("UTF-8")
|
||||
{
|
||||
setFeature("bulk", true);
|
||||
open();
|
||||
@ -158,12 +160,24 @@ void SessionImpl::open(const std::string& connect)
|
||||
&SessionImpl::setQueryTimeout,
|
||||
&SessionImpl::getQueryTimeout);
|
||||
|
||||
addProperty("dbEncoding",
|
||||
&SessionImpl::setDBEncoding,
|
||||
&SessionImpl::getDBEncoding);
|
||||
|
||||
Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_ATTR_QUIET_MODE, 0, 0);
|
||||
|
||||
if (!canTransact()) autoCommit("", true);
|
||||
}
|
||||
|
||||
|
||||
void SessionImpl::setDBEncoding(const std::string&, const Poco::Any& value)
|
||||
{
|
||||
const std::string& enc = Poco::RefAnyCast<std::string>(value);
|
||||
Poco::TextEncoding::byName(enc); // throws if not found
|
||||
_dbEncoding = enc;
|
||||
}
|
||||
|
||||
|
||||
bool SessionImpl::isConnected() const
|
||||
{
|
||||
SQLULEN value = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user