mirror of
https://github.com/pocoproject/poco.git
synced 2025-04-02 09:49:48 +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/Dynamic/Var.h"
|
||||||
#include "Poco/Nullable.h"
|
#include "Poco/Nullable.h"
|
||||||
#include "Poco/UTFString.h"
|
#include "Poco/UTFString.h"
|
||||||
|
#include "Poco/TextEncoding.h"
|
||||||
|
#include "Poco/TextConverter.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||||
@ -53,7 +55,8 @@ public:
|
|||||||
typedef Preparator::Ptr PreparatorPtr;
|
typedef Preparator::Ptr PreparatorPtr;
|
||||||
|
|
||||||
Extractor(const StatementHandle& rStmt,
|
Extractor(const StatementHandle& rStmt,
|
||||||
Preparator::Ptr pPreparator);
|
Preparator::Ptr pPreparator,
|
||||||
|
Poco::TextEncoding::Ptr pDBEncoding = nullptr);
|
||||||
/// Creates the Extractor.
|
/// Creates the Extractor.
|
||||||
|
|
||||||
~Extractor();
|
~Extractor();
|
||||||
@ -580,6 +583,40 @@ private:
|
|||||||
return false;
|
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;
|
bool isNullLengthIndicator(SQLLEN val) const;
|
||||||
/// The reason for this utility wrapper are platforms where
|
/// The reason for this utility wrapper are platforms where
|
||||||
/// SQLLEN macro (a.k.a. SQLINTEGER) yields 64-bit value,
|
/// SQLLEN macro (a.k.a. SQLINTEGER) yields 64-bit value,
|
||||||
@ -591,6 +628,9 @@ private:
|
|||||||
PreparatorPtr _pPreparator;
|
PreparatorPtr _pPreparator;
|
||||||
Preparator::DataExtraction _dataExtraction;
|
Preparator::DataExtraction _dataExtraction;
|
||||||
std::vector<SQLLEN> _lengths;
|
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
|
/// Called whenever SQLExecute returns SQL_NEED_DATA. This is expected
|
||||||
/// behavior for PB_AT_EXEC binding mode.
|
/// behavior for PB_AT_EXEC binding mode.
|
||||||
|
|
||||||
void getData();
|
|
||||||
|
|
||||||
void addPreparator();
|
void addPreparator();
|
||||||
void fillColumns();
|
void fillColumns();
|
||||||
void checkError(SQLRETURN rc, const std::string& msg="");
|
void checkError(SQLRETURN rc, const std::string& msg="");
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "Poco/Data/ODBC/Handle.h"
|
#include "Poco/Data/ODBC/Handle.h"
|
||||||
#include "Poco/Data/ODBC/ODBCException.h"
|
#include "Poco/Data/ODBC/ODBCException.h"
|
||||||
#include "Poco/Data/AbstractSessionImpl.h"
|
#include "Poco/Data/AbstractSessionImpl.h"
|
||||||
|
#include "Poco/TextEncoding.h"
|
||||||
#include "Poco/SharedPtr.h"
|
#include "Poco/SharedPtr.h"
|
||||||
#include "Poco/Mutex.h"
|
#include "Poco/Mutex.h"
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||||
@ -162,6 +163,16 @@ public:
|
|||||||
/// Returns the timeout (in seconds) for queries,
|
/// Returns the timeout (in seconds) for queries,
|
||||||
/// or -1 if no timeout has been set.
|
/// 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;
|
const ConnectionHandle& dbc() const;
|
||||||
/// Returns the connection handle.
|
/// Returns the connection handle.
|
||||||
|
|
||||||
@ -193,6 +204,7 @@ private:
|
|||||||
mutable char _canTransact;
|
mutable char _canTransact;
|
||||||
bool _inTransaction;
|
bool _inTransaction;
|
||||||
int _queryTimeout;
|
int _queryTimeout;
|
||||||
|
std::string _dbEncoding;
|
||||||
Poco::FastMutex _mutex;
|
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
|
} } } // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#include "Poco/Data/ODBC/ODBCException.h"
|
#include "Poco/Data/ODBC/ODBCException.h"
|
||||||
#include "Poco/Data/LOB.h"
|
#include "Poco/Data/LOB.h"
|
||||||
#include "Poco/Buffer.h"
|
#include "Poco/Buffer.h"
|
||||||
#include "Poco/Exception.h"
|
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
|
|
||||||
@ -35,10 +34,14 @@ const std::string Extractor::FLD_SIZE_EXCEEDED_FMT = "Specified data size (%z by
|
|||||||
|
|
||||||
|
|
||||||
Extractor::Extractor(const StatementHandle& rStmt,
|
Extractor::Extractor(const StatementHandle& rStmt,
|
||||||
Preparator::Ptr pPreparator):
|
Preparator::Ptr pPreparator,
|
||||||
|
TextEncoding::Ptr pDBEncoding):
|
||||||
_rStmt(rStmt),
|
_rStmt(rStmt),
|
||||||
_pPreparator(pPreparator),
|
_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)
|
bool Extractor::extract(std::size_t pos, std::string& val)
|
||||||
{
|
{
|
||||||
if (Preparator::DE_MANUAL == _dataExtraction)
|
bool ret = false;
|
||||||
return extractManualImpl(pos, val, SQL_C_CHAR);
|
|
||||||
|
if (!_transcode)
|
||||||
|
{
|
||||||
|
if (Preparator::DE_MANUAL == _dataExtraction)
|
||||||
|
ret = extractManualImpl(pos, val, SQL_C_CHAR);
|
||||||
|
else
|
||||||
|
ret = extractBoundImpl(pos, val);
|
||||||
|
}
|
||||||
else
|
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)
|
bool Extractor::extract(std::size_t pos, std::vector<std::string>& val)
|
||||||
{
|
{
|
||||||
if (Preparator::DE_BOUND == _dataExtraction)
|
return stringContainerExtract(pos, val);
|
||||||
return extractBoundImplContainer(pos, val);
|
|
||||||
else
|
|
||||||
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, std::deque<std::string>& val)
|
bool Extractor::extract(std::size_t pos, std::deque<std::string>& val)
|
||||||
{
|
{
|
||||||
if (Preparator::DE_BOUND == _dataExtraction)
|
return stringContainerExtract(pos, val);
|
||||||
return extractBoundImplContainer(pos, val);
|
|
||||||
else
|
|
||||||
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, std::list<std::string>& val)
|
bool Extractor::extract(std::size_t pos, std::list<std::string>& val)
|
||||||
{
|
{
|
||||||
if (Preparator::DE_BOUND == _dataExtraction)
|
return stringContainerExtract(pos, val);
|
||||||
return extractBoundImplContainer(pos, val);
|
|
||||||
else
|
|
||||||
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,7 +145,8 @@ void ODBCStatementImpl::addPreparator()
|
|||||||
else
|
else
|
||||||
_preparations.push_back(new Preparator(*_preparations[0]));
|
_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),
|
_autoExtract(autoExtract),
|
||||||
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
||||||
_inTransaction(false),
|
_inTransaction(false),
|
||||||
_queryTimeout(-1)
|
_queryTimeout(-1),
|
||||||
|
_dbEncoding("UTF-8")
|
||||||
{
|
{
|
||||||
setFeature("bulk", true);
|
setFeature("bulk", true);
|
||||||
open();
|
open();
|
||||||
@ -58,7 +59,8 @@ SessionImpl::SessionImpl(const std::string& connect,
|
|||||||
_autoExtract(autoExtract),
|
_autoExtract(autoExtract),
|
||||||
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
|
||||||
_inTransaction(false),
|
_inTransaction(false),
|
||||||
_queryTimeout(-1)
|
_queryTimeout(-1),
|
||||||
|
_dbEncoding("UTF-8")
|
||||||
{
|
{
|
||||||
setFeature("bulk", true);
|
setFeature("bulk", true);
|
||||||
open();
|
open();
|
||||||
@ -158,12 +160,24 @@ void SessionImpl::open(const std::string& connect)
|
|||||||
&SessionImpl::setQueryTimeout,
|
&SessionImpl::setQueryTimeout,
|
||||||
&SessionImpl::getQueryTimeout);
|
&SessionImpl::getQueryTimeout);
|
||||||
|
|
||||||
|
addProperty("dbEncoding",
|
||||||
|
&SessionImpl::setDBEncoding,
|
||||||
|
&SessionImpl::getDBEncoding);
|
||||||
|
|
||||||
Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_ATTR_QUIET_MODE, 0, 0);
|
Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_ATTR_QUIET_MODE, 0, 0);
|
||||||
|
|
||||||
if (!canTransact()) autoCommit("", true);
|
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
|
bool SessionImpl::isConnected() const
|
||||||
{
|
{
|
||||||
SQLULEN value = 0;
|
SQLULEN value = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user