GH #290: Unicode support

This commit is contained in:
Alex Fabijanic
2014-05-21 03:28:24 -05:00
parent 8b39a87fd6
commit 1aa28e1491
46 changed files with 1168 additions and 114 deletions

View File

@@ -252,6 +252,18 @@ public:
void bind(std::size_t pos, const std::list<std::string>& val, Direction dir);
/// Binds a string list.
void bind(std::size_t pos, const UTF16String& val, Direction dir);
/// Binds a string.
void bind(std::size_t pos, const std::vector<UTF16String>& val, Direction dir);
/// Binds a string vector.
void bind(std::size_t pos, const std::deque<UTF16String>& val, Direction dir);
/// Binds a string deque.
void bind(std::size_t pos, const std::list<UTF16String>& val, Direction dir);
/// Binds a string list.
void bind(std::size_t pos, const BLOB& val, Direction dir);
/// Binds a BLOB. In-bound only.
@@ -341,18 +353,20 @@ public:
/// Clears the cached storage.
private:
typedef std::vector<SQLLEN*> LengthVec;
typedef std::vector<std::vector<SQLLEN> > LengthVecVec;
typedef std::vector<char*> CharPtrVec;
typedef std::vector<bool*> BoolPtrVec;
typedef std::vector<std::vector<SQL_DATE_STRUCT> > DateVec;
typedef std::vector<std::vector<SQL_TIME_STRUCT> > TimeVec;
typedef std::vector<std::vector<SQL_TIMESTAMP_STRUCT> > DateTimeVec;
typedef std::vector<std::vector<Poco::Any> > AnyVec;
typedef std::map<char*, std::string*> StringMap;
typedef std::map<SQL_DATE_STRUCT*, Date*> DateMap;
typedef std::map<SQL_TIME_STRUCT*, Time*> TimeMap;
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
typedef std::vector<SQLLEN*> LengthVec;
typedef std::vector<std::vector<SQLLEN> > LengthVecVec;
typedef std::vector<char*> CharPtrVec;
typedef std::vector<UTF16Char*> UTF16CharPtrVec;
typedef std::vector<bool*> BoolPtrVec;
typedef std::vector<std::vector<SQL_DATE_STRUCT> > DateVec;
typedef std::vector<std::vector<SQL_TIME_STRUCT> > TimeVec;
typedef std::vector<std::vector<SQL_TIMESTAMP_STRUCT> > DateTimeVec;
typedef std::vector<std::vector<Poco::Any> > AnyVec;
typedef std::map<char*, std::string*> StringMap;
typedef std::map<UTF16String::value_type*, UTF16String*> UTF16StringMap;
typedef std::map<SQL_DATE_STRUCT*, Date*> DateMap;
typedef std::map<SQL_TIME_STRUCT*, Time*> TimeMap;
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
void describeParameter(std::size_t pos);
/// Sets the description field for the parameter, if needed.
@@ -581,6 +595,71 @@ private:
}
}
template <typename C>
void bindImplContainerUTF16String(std::size_t pos, const C& val, Direction dir)
/// Utility function to bind containers of strings.
{
if (isOutBound(dir) || !isInBound(dir))
throw NotImplementedException("String container parameter type can only be inbound.");
if (PB_IMMEDIATE != _paramBinding)
throw InvalidAccessException("Containers can only be bound immediately.");
if (0 == val.size())
throw InvalidArgumentException("Empty container not allowed.");
setParamSetSize(val.size());
SQLINTEGER size = 0;
getColumnOrParameterSize(pos, size);
poco_assert(size > 0);
if (size == _maxFieldSize)
{
getMinValueSize(val, size);
// accomodate for terminating zero
if (size != _maxFieldSize) size += sizeof(UTF16Char);
}
if (_vecLengthIndicator.size() <= pos)
{
_vecLengthIndicator.resize(pos + 1);
_vecLengthIndicator[pos].resize(val.size(), SQL_NTS);
}
if (_utf16CharPtrs.size() <= pos)
_utf16CharPtrs.resize(pos + 1, 0);
_utf16CharPtrs[pos] = (UTF16Char*)std::calloc(val.size() * size, sizeof(UTF16Char));
std::size_t strSize;
std::size_t offset = 0;
typename C::const_iterator it = val.begin();
typename C::const_iterator end = val.end();
for (; it != end; ++it)
{
strSize = it->size() * sizeof(UTF16Char);
if (strSize > size)
throw LengthExceededException("SQLBindParameter(std::vector<UTF16String>)");
std::memcpy(_utf16CharPtrs[pos] + offset, it->data(), strSize);
offset += (size / sizeof(UTF16Char));
}
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT)pos + 1,
toODBCDirection(dir),
SQL_C_WCHAR,
SQL_WLONGVARCHAR,
(SQLUINTEGER)size - 1,
0,
_utf16CharPtrs[pos],
(SQLINTEGER)size,
&_vecLengthIndicator[pos][0])))
{
throw StatementException(_rStmt, "SQLBindParameter(std::vector<UTF16String>)");
}
}
template <typename C>
void bindImplContainerLOB(std::size_t pos, const C& val, Direction dir)
{
@@ -859,7 +938,7 @@ private:
typename T::const_iterator end = val.end();
for (; it != end; ++it)
{
std::size_t sz = it->size();
std::size_t sz = it->size() * sizeof(T);
if (sz > _maxFieldSize)
throw LengthExceededException();
@@ -888,11 +967,13 @@ private:
TimeMap _times;
TimestampMap _timestamps;
StringMap _strings;
UTF16StringMap _utf16Strings;
DateVec _dateVec;
TimeVec _timeVec;
DateTimeVec _dateTimeVec;
CharPtrVec _charPtrs;
UTF16CharPtrVec _utf16CharPtrs;
BoolPtrVec _boolPtrs;
const TypeInfo* _pTypeInfo;
SQLINTEGER _paramSetSize;
@@ -1241,6 +1322,24 @@ inline void Binder::bind(std::size_t pos, const std::list<std::string>& val, Dir
bindImplContainerString(pos, val, dir);
}
inline void Binder::bind(std::size_t pos, const std::vector<UTF16String>& val, Direction dir)
{
bindImplContainerUTF16String(pos, val, dir);
}
inline void Binder::bind(std::size_t pos, const std::deque<UTF16String>& val, Direction dir)
{
bindImplContainerUTF16String(pos, val, dir);
}
inline void Binder::bind(std::size_t pos, const std::list<UTF16String>& val, Direction dir)
{
bindImplContainerUTF16String(pos, val, dir);
}
inline void Binder::bind(std::size_t pos, const BLOB& val, Direction dir)
{
bindImplLOB<BLOB>(pos, val, dir);

View File

@@ -33,6 +33,7 @@
#include "Poco/Any.h"
#include "Poco/Dynamic/Var.h"
#include "Poco/Nullable.h"
#include "Poco/UTFString.h"
#include "Poco/Exception.h"
#include <map>
#ifdef POCO_OS_FAMILY_WINDOWS
@@ -232,6 +233,19 @@ public:
bool extract(std::size_t pos, std::list<std::string>& val);
/// Extracts a string list.
/// Extracts a single character list.
bool extract(std::size_t pos, UTF16String& val);
/// Extracts a string.
bool extract(std::size_t pos, std::vector<UTF16String>& val);
/// Extracts a string vector.
bool extract(std::size_t pos, std::deque<UTF16String>& val);
/// Extracts a string deque.
bool extract(std::size_t pos, std::list<UTF16String>& val);
/// Extracts a string list.
bool extract(std::size_t pos, Poco::Data::BLOB& val);
/// Extracts a BLOB.
@@ -372,7 +386,10 @@ private:
bool extractBoundImplContainer(std::size_t pos, std::vector<std::string>& values);
bool extractBoundImplContainer(std::size_t pos, std::deque<std::string>& values);
bool extractBoundImplContainer(std::size_t pos, std::list<std::string>& values);
bool extractBoundImplContainer(std::size_t pos, std::list<std::string>& values);
bool extractBoundImplContainer(std::size_t pos, std::vector<Poco::UTF16String>& values);
bool extractBoundImplContainer(std::size_t pos, std::deque<Poco::UTF16String>& values);
bool extractBoundImplContainer(std::size_t pos, std::list<Poco::UTF16String>& values);
bool extractBoundImplContainer(std::size_t pos, std::vector<Poco::Data::CLOB>& values);
bool extractBoundImplContainer(std::size_t pos, std::deque<Poco::Data::CLOB>& values);
bool extractBoundImplContainer(std::size_t pos, std::list<Poco::Data::CLOB>& values);
@@ -394,7 +411,19 @@ private:
ItType it = values.begin();
ItType end = values.end();
for (int row = 0; it != end; ++it, ++row)
it->assign(*pc + row * colWidth, _pPreparator->actualDataSize(pos, row));
{
it->assign(*pc + row * colWidth / sizeof(CharType), _pPreparator->actualDataSize(pos, row));
// clean up superfluous null chars returned by some drivers
typename StringType::size_type trimLen = 0;
typename StringType::reverse_iterator sIt = it->rbegin();
typename StringType::reverse_iterator sEnd = it->rend();
for (; sIt != sEnd; ++sIt)
{
if (*sIt == '\0') ++trimLen;
else break;
}
if (trimLen) it->assign(it->begin(), it->begin() + it->length() - trimLen);
}
return true;
}
@@ -522,6 +551,9 @@ private:
case MetaColumn::FDT_STRING:
{ return extAny<T, std::string>(pos, val); }
case MetaColumn::FDT_WSTRING:
{ return extAny<T, Poco::UTF16String>(pos, val); }
case MetaColumn::FDT_BLOB:
{ return extAny<T, Poco::Data::BLOB>(pos, val); }
@@ -592,6 +624,24 @@ inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<std:
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::vector<Poco::UTF16String>& values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::deque<Poco::UTF16String>& values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<Poco::UTF16String>& values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
std::vector<Poco::Data::CLOB>& values)
{

View File

@@ -31,6 +31,7 @@
#include "Poco/DynamicAny.h"
#include "Poco/DateTime.h"
#include "Poco/SharedPtr.h"
#include "Poco/UTFString.h"
#include <vector>
#ifdef POCO_OS_FAMILY_WINDOWS
#include <windows.h>
@@ -87,8 +88,10 @@ public:
DT_BOOL,
DT_BOOL_ARRAY,
DT_CHAR,
DT_WCHAR,
DT_UCHAR,
DT_CHAR_ARRAY,
DT_WCHAR_ARRAY,
DT_UCHAR_ARRAY,
DT_DATE,
DT_TIME,
@@ -280,6 +283,18 @@ public:
void prepare(std::size_t pos, const std::list<std::string>& val);
/// Prepares a string list.
void prepare(std::size_t pos, const UTF16String& val);
/// Prepares a string.
void prepare(std::size_t pos, const std::vector<UTF16String>& val);
/// Prepares a string vector.
void prepare(std::size_t pos, const std::deque<UTF16String>& val);
/// Prepares a string deque.
void prepare(std::size_t pos, const std::list<UTF16String>& val);
/// Prepares a string list.
void prepare(std::size_t pos, const Poco::Data::BLOB& val);
/// Prepares a BLOB.
@@ -490,6 +505,15 @@ private:
else
return prepareVariableLen<char>(pos, SQL_C_CHAR, maxDataSize(pos), DT_CHAR);
case MetaColumn::FDT_WSTRING:
{
typedef UTF16String::value_type CharType;
if (pVal)
return prepareCharArray<CharType, DT_WCHAR_ARRAY>(pos, SQL_C_WCHAR, maxDataSize(pos), pVal->size());
else
return prepareVariableLen<CharType>(pos, SQL_C_WCHAR, maxDataSize(pos), DT_WCHAR);
}
case MetaColumn::FDT_BLOB:
{
typedef Poco::Data::BLOB::ValueType CharType;
@@ -1007,6 +1031,30 @@ inline void Preparator::prepare(std::size_t pos, const std::list<std::string>& v
}
inline void Preparator::prepare(std::size_t pos, const UTF16String&)
{
prepareVariableLen<UTF16String::value_type>(pos, SQL_C_WCHAR, maxDataSize(pos), DT_CHAR);
}
inline void Preparator::prepare(std::size_t pos, const std::vector<UTF16String>& val)
{
prepareCharArray<UTF16String::value_type, DT_WCHAR_ARRAY>(pos, SQL_C_WCHAR, maxDataSize(pos), val.size());
}
inline void Preparator::prepare(std::size_t pos, const std::deque<UTF16String>& val)
{
prepareCharArray<UTF16String::value_type, DT_WCHAR_ARRAY>(pos, SQL_C_WCHAR, maxDataSize(pos), val.size());
}
inline void Preparator::prepare(std::size_t pos, const std::list<UTF16String>& val)
{
prepareCharArray<UTF16String::value_type, DT_WCHAR_ARRAY>(pos, SQL_C_WCHAR, maxDataSize(pos), val.size());
}
inline void Preparator::prepare(std::size_t pos, const Poco::Data::BLOB&)
{
prepareVariableLen<Poco::Data::BLOB::ValueType>(pos, SQL_C_BINARY, maxDataSize(pos), DT_UCHAR);

View File

@@ -73,6 +73,10 @@ void Binder::freeMemory()
CharPtrVec::iterator endChr = _charPtrs.end();
for (; itChr != endChr; ++itChr) std::free(*itChr);
UTF16CharPtrVec::iterator itUTF16Chr = _utf16CharPtrs.begin();
UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end();
for (; itUTF16Chr != endUTF16Chr; ++itUTF16Chr) std::free(*itUTF16Chr);
BoolPtrVec::iterator itBool = _boolPtrs.begin();
BoolPtrVec::iterator endBool = _boolPtrs.end();
for (; itBool != endBool; ++itBool) delete [] *itBool;
@@ -127,6 +131,58 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
}
void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir)
{
typedef UTF16String::value_type CharT;
SQLPOINTER pVal = 0;
SQLINTEGER size = (SQLINTEGER)(val.size() * sizeof(CharT));
if (isOutBound(dir))
{
getColumnOrParameterSize(pos, size);
CharT* pChar = (CharT*)std::calloc(size, 1);
pVal = (SQLPOINTER)pChar;
_outParams.insert(ParamMap::value_type(pVal, size));
_utf16Strings.insert(UTF16StringMap::value_type(pChar, const_cast<UTF16String*>(&val)));
}
else if (isInBound(dir))
{
pVal = (SQLPOINTER)val.c_str();
_inParams.insert(ParamMap::value_type(pVal, size));
}
else
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
SQLLEN* pLenIn = new SQLLEN;
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_WCHAR, colSize, decDigits);
*pLenIn = SQL_NTS;
if (PB_AT_EXEC == _paramBinding)
{
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
}
_lengthIndicator.push_back(pLenIn);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT)pos + 1,
toODBCDirection(dir),
SQL_C_WCHAR,
SQL_WLONGVARCHAR,
(SQLUINTEGER)colSize,
0,
pVal,
(SQLINTEGER)size,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter(std::string)");
}
}
void Binder::bind(std::size_t pos, const Date& val, Direction dir)
{
SQLINTEGER size = (SQLINTEGER) sizeof(SQL_DATE_STRUCT);

View File

@@ -64,6 +64,22 @@ bool Extractor::extractBoundImpl<std::string>(std::size_t pos, std::string& val)
}
template<>
bool Extractor::extractBoundImpl<UTF16String>(std::size_t pos, UTF16String& val)
{
typedef UTF16String::value_type CharT;
if (isNull(pos)) return false;
std::size_t dataSize = _pPreparator->actualDataSize(pos);
CharT* sp = AnyCast<CharT*>(_pPreparator->at(pos));
std::size_t len = Poco::UnicodeConverter::UTFStrlen(sp);
if (len < dataSize) dataSize = len;
checkDataSize(dataSize);
val.assign(sp, dataSize);
return true;
}
template<>
bool Extractor::extractBoundImpl<Poco::Data::Date>(std::size_t pos, Poco::Data::Date& val)
{
@@ -280,6 +296,61 @@ bool Extractor::extractManualImpl<std::string>(std::size_t pos, std::string& val
}
template<>
bool Extractor::extractManualImpl<UTF16String>(std::size_t pos, UTF16String& val, SQLSMALLINT cType)
{
std::size_t maxSize = _pPreparator->getMaxFieldSize();
std::size_t fetchedSize = 0;
std::size_t totalSize = 0;
SQLLEN len;
const int bufSize = CHUNK_SIZE;
Poco::Buffer<UTF16String::value_type> apChar(bufSize);
UTF16String::value_type* pChar = apChar.begin();
SQLRETURN rc = 0;
val.clear();
resizeLengths(pos);
do
{
std::memset(pChar, 0, bufSize);
len = 0;
rc = SQLGetData(_rStmt,
(SQLUSMALLINT)pos + 1,
cType, //C data type
pChar, //returned value
bufSize, //buffer length
&len); //length indicator
if (SQL_NO_DATA != rc && Utility::isError(rc))
throw StatementException(_rStmt, "SQLGetData()");
if (SQL_NO_TOTAL == len)//unknown length, throw
throw UnknownDataLengthException("Could not determine returned data length.");
if (isNullLengthIndicator(len))
{
_lengths[pos] = len;
return false;
}
if (SQL_NO_DATA == rc || !len)
break;
_lengths[pos] += len;
fetchedSize = _lengths[pos] > CHUNK_SIZE ? CHUNK_SIZE : _lengths[pos];
totalSize += fetchedSize;
if (totalSize <= maxSize)
val.append(pChar, fetchedSize / sizeof(UTF16Char));
else
throw DataException(format(FLD_SIZE_EXCEEDED_FMT, fetchedSize, maxSize));
} while (true);
return true;
}
template<>
bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos,
Poco::Data::CLOB& val,
@@ -608,6 +679,42 @@ bool Extractor::extract(std::size_t pos, std::list<std::string>& val)
}
bool Extractor::extract(std::size_t pos, UTF16String& val)
{
if (Preparator::DE_MANUAL == _dataExtraction)
return extractManualImpl(pos, val, SQL_C_WCHAR);
else
return extractBoundImpl(pos, val);
}
bool Extractor::extract(std::size_t pos, std::vector<UTF16String>& val)
{
if (Preparator::DE_BOUND == _dataExtraction)
return extractBoundImplContainer(pos, val);
else
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
}
bool Extractor::extract(std::size_t pos, std::deque<UTF16String>& val)
{
if (Preparator::DE_BOUND == _dataExtraction)
return extractBoundImplContainer(pos, val);
else
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
}
bool Extractor::extract(std::size_t pos, std::list<UTF16String>& val)
{
if (Preparator::DE_BOUND == _dataExtraction)
return extractBoundImplContainer(pos, val);
else
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
}
bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val)
{
if (Preparator::DE_MANUAL == _dataExtraction)

View File

@@ -83,14 +83,16 @@ void ODBCMetaColumn::init()
{
case SQL_BIT:
setType(MetaColumn::FDT_BOOL); break;
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case -8:// PostgreSQL CHAR (with size specified - psqlODBC)
case -9:// SQL Server NVARCHAR
case -10:// PostgreSQL VARCHAR (without size specified)
setType(MetaColumn::FDT_STRING); break;
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
setType(MetaColumn::FDT_WSTRING); break;
case SQL_TINYINT:
setType(MetaColumn::FDT_INT8); break;

View File

@@ -72,6 +72,10 @@ void Preparator::freeMemory() const
deleteCachedArray<char>(it->first);
break;
case DT_WCHAR:
deleteCachedArray<UTF16String>(it->first);
break;
case DT_UCHAR:
deleteCachedArray<unsigned char>(it->first);
break;
@@ -83,6 +87,13 @@ void Preparator::freeMemory() const
break;
}
case DT_WCHAR_ARRAY:
{
UTF16String::value_type** pc = AnyCast<UTF16String::value_type*>(&_values[it->first]);
if (pc) std::free(*pc);
break;
}
case DT_UCHAR_ARRAY:
{
unsigned char** pc = AnyCast<unsigned char*>(&_values[it->first]);

View File

@@ -834,6 +834,17 @@ void ODBCOracleTest::recreateLogTable()
}
void ODBCOracleTest::recreateUnicodeTable()
{
#if defined (POCO_ODBC_UNICODE)
dropObject("TABLE", "UnicodeTable");
try { session() << "CREATE TABLE UnicodeTable (str NVARCHAR2(30))", now; }
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateUnicodeTable()"); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateUnicodeTable()"); }
#endif
}
CppUnit::Test* ODBCOracleTest::suite()
{
if ((_pSession = init(_driver, _dsn, _uid, _pwd, _connectString)))
@@ -923,6 +934,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testTransaction);
CppUnit_addTest(pSuite, ODBCOracleTest, testTransactor);
CppUnit_addTest(pSuite, ODBCOracleTest, testNullable);
CppUnit_addTest(pSuite, ODBCOracleTest, testUnicode);
CppUnit_addTest(pSuite, ODBCOracleTest, testReconnect);
return pSuite;

View File

@@ -70,6 +70,7 @@ private:
void recreateNullsTable(const std::string& notNull = "");
void recreateMiscTable();
void recreateLogTable();
void recreateUnicodeTable();
static ODBCTest::SessionPtr _pSession;
static ODBCTest::ExecPtr _pExecutor;

View File

@@ -53,6 +53,10 @@ using Poco::DateTime;
#define POSTGRESQL_DSN "PocoDataPgSQLTest"
#endif
#if defined(POCO_OS_FAMILY_WINDOWS)
#pragma message ("Using " POSTGRESQL_ODBC_DRIVER " driver.")
#endif
#define POSTGRESQL_SERVER POCO_ODBC_TEST_DATABASE_SERVER
#define POSTGRESQL_PORT "5432"
#define POSTGRESQL_DB "postgres"
@@ -559,6 +563,17 @@ void ODBCPostgreSQLTest::recreateLogTable()
}
void ODBCPostgreSQLTest::recreateUnicodeTable()
{
#if defined (POCO_ODBC_UNICODE)
dropObject("TABLE", "UnicodeTable");
try { session() << "CREATE TABLE UnicodeTable (str TEXT)", now; }
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateUnicodeTable()"); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateUnicodeTable()"); }
#endif
}
CppUnit::Test* ODBCPostgreSQLTest::suite()
{
if ((_pSession = init(_driver, _dsn, _uid, _pwd, _connectString)))
@@ -659,6 +674,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransaction);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransactor);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testNullable);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testUnicode);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testReconnect);
return pSuite;

View File

@@ -69,6 +69,7 @@ private:
void recreateBoolTable();
void recreateMiscTable();
void recreateLogTable();
void recreateUnicodeTable();
void configurePLPgSQL();
/// Configures PL/pgSQL in the database. A reasonable defaults

View File

@@ -715,6 +715,17 @@ void ODBCSQLServerTest::recreateLogTable()
}
void ODBCSQLServerTest::recreateUnicodeTable()
{
#if defined (POCO_ODBC_UNICODE)
dropObject("TABLE", "UnicodeTable");
try { session() << "CREATE TABLE UnicodeTable (str NVARCHAR(30))", now; }
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateUnicodeTable()"); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateUnicodeTable()"); }
#endif
}
CppUnit::Test* ODBCSQLServerTest::suite()
{
if ((_pSession = init(_driver, _dsn, _uid, _pwd, _connectString, _db)))
@@ -801,6 +812,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransaction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTransactor);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNullable);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testUnicode);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testReconnect);
return pSuite;

View File

@@ -74,6 +74,7 @@ private:
void recreateBoolTable();
void recreateMiscTable();
void recreateLogTable();
void recreateUnicodeTable();
static SessionPtr _pSession;
static ExecPtr _pExecutor;

View File

@@ -969,7 +969,11 @@ void ODBCTest::testInternalBulkExtraction()
recreatePersonTable();
_pSession->setFeature("autoBind", true);
_pSession->setFeature("autoExtract", true);
#ifdef POCO_ODBC_UNICODE
_pExecutor->internalBulkExtractionUTF16();
#else
_pExecutor->internalBulkExtraction();
#endif
}
@@ -1199,6 +1203,25 @@ void ODBCTest::testNullable()
}
void ODBCTest::testUnicode()
{
#if defined (POCO_ODBC_UNICODE)
if (!_pSession) fail("Test not available.");
for (int i = 0; i < 8;)
{
recreateUnicodeTable();
_pSession->setFeature("autoBind", bindValue(i));
_pSession->setFeature("autoExtract", bindValue(i + 1));
_pExecutor->unicode(_rConnectString);
i += 2;
}
#else
std::cout << "Not an UNICODE build, skipping." << std::endl;
#endif
}
void ODBCTest::testReconnect()
{
if (!_pSession) fail ("Test not available.");
@@ -1296,7 +1319,7 @@ 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);
return new Session(Poco::Data::ODBC::Connector::KEY, dbConnString, 5);
}catch (ConnectionFailedException& ex)
{
std::cout << ex.displayText() << std::endl;

View File

@@ -149,6 +149,8 @@ public:
virtual void testTransactor();
virtual void testNullable();
virtual void testUnicode();
virtual void testReconnect();
protected:
@@ -172,6 +174,7 @@ protected:
virtual void recreateBoolTable();
virtual void recreateMiscTable();
virtual void recreateLogTable();
virtual void recreateUnicodeTable();
static SessionPtr init(const std::string& driver,
std::string& dsn,
@@ -357,6 +360,12 @@ inline void ODBCTest::recreateLogTable()
}
inline void ODBCTest::recreateUnicodeTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateUnicodeTable()");
}
inline bool ODBCTest::bindValue(int i)
{
poco_assert (i < 8);

View File

@@ -46,6 +46,8 @@
#include "Poco/Data/ODBC/Preparator.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/ODBC/ODBCStatementImpl.h"
#include "Poco/UnicodeConverter.h"
#include "Poco/UTFString.h"
#include <sqltypes.h>
#include <iostream>
#include <sstream>
@@ -94,7 +96,9 @@ using Poco::NotImplementedException;
using Poco::BadCastException;
using Poco::RangeException;
using Poco::TimeoutException;
using Poco::UnicodeConverter;
using Poco::UTF16String;
using Poco::UTF32String;
struct Person
{
@@ -2441,24 +2445,24 @@ void SQLExecutor::dateTime()
DateTime born(1965, 6, 18, 5, 35, 1);
int count = 0;
try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(born), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); }
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
assert (count == 1);
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); }
assert(count == 1);
DateTime res;
try { session() << "SELECT Born FROM Person", into(res), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
assert (res == born);
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); }
assert(res == born);
Statement stmt = (session() << "SELECT Born FROM Person", now);
RecordSet rset(stmt);
res = rset["Born"].convert<DateTime>();
assert (res == born);
assert(res == born);
}
@@ -2619,7 +2623,7 @@ void SQLExecutor::internalExtraction()
rset.moveFirst();
assert (rset["str0"] == "3");
rset.moveLast();
assert (rset["str0"] == "6");
assert(rset["str0"] == "6");
RecordSet rset2(rset);
assert (3 == rset2.columnCount());
@@ -2645,8 +2649,17 @@ void SQLExecutor::internalExtraction()
assert (2.5 == f);
}
s = rset.value<std::string>(2,2);
assert ("5" == s);
try
{
s = rset.value<std::string>(2, 2);
}
catch (BadCastException&)
{
UTF16String us = rset.value<Poco::UTF16String>(2, 2);
Poco::UnicodeConverter::convert(us, s);
}
assert("5" == s);
i = rset.value("str0", 2);
assert (5 == i);
@@ -2815,8 +2828,11 @@ void SQLExecutor::internalBulkExtraction()
Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now);
RecordSet rset(stmt);
assert (size == rset.rowCount());
assert ("LN0" == rset["LastName"]);
assert("LN0" == rset["LastName"]);
assert (0 == rset["Age"]);
rset.moveNext();
assert("LN1" == rset["LastName"]);
assert(1 == rset["Age"]);
rset.moveLast();
assert (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assert (size - 1 == rset["Age"]);
@@ -2840,6 +2856,68 @@ void SQLExecutor::internalBulkExtraction()
}
void SQLExecutor::internalBulkExtractionUTF16()
{
std::string funct = "internalBulkExtraction()";
int size = 100;
std::vector<UTF16String> lastName(size);
std::vector<UTF16String> firstName(size);
std::vector<UTF16String> address(size);
std::vector<int> age(size);
for (int i = 0; i < size; ++i)
{
lastName[i] = Poco::UnicodeConverter::to<UTF16String>("LN" + NumberFormatter::format(i));
firstName[i] = Poco::UnicodeConverter::to<UTF16String>("FN" + NumberFormatter::format(i));
address[i] = Poco::UnicodeConverter::to<UTF16String>("Addr" + NumberFormatter::format(i));
age[i] = i;
}
try
{
session() << "INSERT INTO Person VALUES (?,?,?,?)",
use(lastName, bulk),
use(firstName, bulk),
use(address, bulk),
use(age, bulk),
now;
}
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); }
try
{
Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now);
RecordSet rset(stmt);
assert(size == rset.rowCount());
assert(Poco::UnicodeConverter::to<UTF16String>("LN0") == rset["LastName"]);
assert(0 == rset["Age"]);
rset.moveNext();
assert(Poco::UnicodeConverter::to<UTF16String>("LN1") == rset["LastName"]);
assert(1 == rset["Age"]);
rset.moveLast();
assert(std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assert(size - 1 == rset["Age"]);
}
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); }
try
{
Statement stmt = (session() << "SELECT * FROM Person", limit(size), bulk, now);
RecordSet rset(stmt);
assert(size == rset.rowCount());
assert("LN0" == rset["LastName"]);
assert(0 == rset["Age"]);
rset.moveLast();
assert(std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assert(size - 1 == rset["Age"]);
}
catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); }
}
void SQLExecutor::internalStorageType()
{
std::string funct = "internalStorageType()";
@@ -3247,8 +3325,13 @@ void SQLExecutor::any()
{
Any i = 42;
Any f = 42.5;
Any s = std::string("42");
std::string ss("42");
Any s = ss;
#ifdef POCO_ODBC_UNICODE
UTF16String us;
Poco::UnicodeConverter::convert(ss, us);
s = us;
#endif
Session tmp = session();
tmp << "INSERT INTO Anys VALUES (?, ?, ?)", use(i), use(f), use(s), now;
@@ -3263,7 +3346,19 @@ void SQLExecutor::any()
tmp << "SELECT * FROM Anys", into(i), into(f), into(s), now;
assert (AnyCast<int>(i) == 42);
assert (AnyCast<double>(f) == 42.5);
#ifdef POCO_ODBC_UNICODE
// drivers may behave differently here
try
{
assert(AnyCast<UTF16String>(s) == us);
}
catch (BadCastException&)
{
assert (AnyCast<std::string>(s) == "42");
}
#else
assert (AnyCast<std::string>(s) == "42");
#endif
}
@@ -3830,7 +3925,7 @@ void SQLExecutor::nullable()
assert (rs.isNull("EmptyInteger"));
assert (rs.isNull("EmptyFloat"));
assert (rs.isNull("EmptyDateTime"));
Var di = 1;
Var df = 1.5;
Var ds = "abc";
@@ -3840,8 +3935,8 @@ void SQLExecutor::nullable()
assert (!df.isEmpty());
assert (!ds.isEmpty());
assert (!dd.isEmpty());
session() << "SELECT EmptyString, EmptyInteger, EmptyFloat, EmptyDateTime FROM NullableTest", into(di), into(df), into(ds), into(dd), now;
Statement stmt = (session() << "SELECT EmptyString, EmptyInteger, EmptyFloat, EmptyDateTime FROM NullableTest", into(ds), into(di), into(df), into(dd), now);
assert (di.isEmpty());
assert (df.isEmpty());
@@ -3889,3 +3984,19 @@ void SQLExecutor::reconnect()
assert (count == age);
assert (session().isConnected());
}
void SQLExecutor::unicode(const std::string& dbConnString)
{
const unsigned char supp[] = { 0x41, 0x42, 0xf0, 0x90, 0x82, 0xa4, 0xf0, 0xaf, 0xa6, 0xa0, 0xf0, 0xaf, 0xa8, 0x9d, 0x00 };
std::string text((const char*) supp);
UTF16String wtext;
Poco::UnicodeConverter::convert(text, wtext);
session() << "INSERT INTO UnicodeTable VALUES (?)", use(wtext), now;
wtext.clear();
text.clear();
session() << "SELECT str FROM UnicodeTable", into(wtext), now;
Poco::UnicodeConverter::convert(wtext, text);
assert(text == std::string((const char*)supp));
}

View File

@@ -479,6 +479,7 @@ public:
const std::string& intFldName = "int0");
void internalBulkExtraction();
void internalBulkExtractionUTF16();
void internalStorageType();
void nulls();
void notNulls(const std::string& sqlState = "23502");
@@ -503,6 +504,8 @@ public:
void transactor();
void nullable();
void unicode(const std::string& dbConnString);
void reconnect();
private:

View File

@@ -28,6 +28,7 @@
#include "Poco/Nullable.h"
#include "Poco/Any.h"
#include "Poco/Dynamic/Var.h"
#include "Poco/UTFString.h"
#include <vector>
#include <deque>
#include <list>
@@ -246,6 +247,18 @@ public:
virtual void bind(std::size_t pos, const std::list<std::string>& val, Direction dir = PD_IN);
/// Binds a string list.
virtual void bind(std::size_t pos, const UTF16String& val, Direction dir = PD_IN) = 0;
/// Binds a string.
virtual void bind(std::size_t pos, const std::vector<UTF16String>& val, Direction dir = PD_IN);
/// Binds a string vector.
virtual void bind(std::size_t pos, const std::deque<UTF16String>& val, Direction dir = PD_IN);
/// Binds a string deque.
virtual void bind(std::size_t pos, const std::list<UTF16String>& val, Direction dir = PD_IN);
/// Binds a string list.
virtual void bind(std::size_t pos, const BLOB& val, Direction dir = PD_IN) = 0;
/// Binds a BLOB.

View File

@@ -25,6 +25,7 @@
#include "Poco/Data/AbstractPreparation.h"
#include "Poco/Data/Limit.h"
#include "Poco/RefCountedObject.h"
#include "Poco/UTFString.h"
#include "Poco/AutoPtr.h"
#include <vector>
#include <deque>
@@ -144,7 +145,26 @@ public:
/// - string is empty
/// - getEmptyStringIsNull() returns true
bool isValueNull(const Poco::UTF16String& str, bool deflt);
/// Overload for const reference to UTF16String.
///
/// Returns true when folowing conditions are met:
///
/// - string is empty
/// - getEmptyStringIsNull() returns true
private:
template <typename S>
bool isStringNull(const S& str, bool deflt)
{
if (getForceEmptyString()) return false;
if (getEmptyStringIsNull() && str.empty())
return true;
return deflt;
}
ExtractorPtr _pExtractor;
Poco::UInt32 _limit;
Poco::UInt32 _position;
@@ -242,6 +262,18 @@ inline bool AbstractExtraction::getForceEmptyString() const
}
inline bool AbstractExtraction::isValueNull(const std::string& str, bool deflt)
{
return isStringNull(str, deflt);
}
inline bool AbstractExtraction::isValueNull(const Poco::UTF16String& str, bool deflt)
{
return isStringNull(str, deflt);
}
} } // namespace Poco::Data

View File

@@ -23,6 +23,7 @@
#include "Poco/Data/Data.h"
#include "Poco/Data/Constants.h"
#include "Poco/Data/LOB.h"
#include "Poco/UTFString.h"
#include <vector>
#include <deque>
#include <list>
@@ -233,6 +234,18 @@ public:
virtual bool extract(std::size_t pos, std::list<std::string>& val);
/// Extracts a string list.
virtual bool extract(std::size_t pos, UTF16String& val) = 0;
/// Extracts a string. Returns false if null was received.
virtual bool extract(std::size_t pos, std::vector<UTF16String>& val);
/// Extracts a string vector.
virtual bool extract(std::size_t pos, std::deque<UTF16String>& val);
/// Extracts a string deque.
virtual bool extract(std::size_t pos, std::list<UTF16String>& val);
/// Extracts a string list.
virtual bool extract(std::size_t pos, BLOB& val) = 0;
/// Extracts a BLOB. Returns false if null was received.

View File

@@ -44,7 +44,7 @@ public:
/// Destroys the AbstractPreparation.
virtual void prepare() = 0;
/// Preparations data.
/// Prepares data.
protected:
AbstractPreparation();

View File

@@ -23,6 +23,7 @@
#include "Poco/Data/Data.h"
#include "Poco/RefCountedObject.h"
#include "Poco/Data/LOB.h"
#include "Poco/UTFString.h"
#include <vector>
#include <deque>
#include <list>
@@ -237,6 +238,18 @@ public:
/// Prepares a string deque.
virtual void prepare(std::size_t pos, const std::list<std::string>& val);
/// Prepares a character list.
virtual void prepare(std::size_t pos, const UTF16String&) = 0;
/// Prepares a string.
virtual void prepare(std::size_t pos, const std::vector<UTF16String>& val);
/// Prepares a string vector.
virtual void prepare(std::size_t pos, const std::deque<UTF16String>& val);
/// Prepares a string deque.
virtual void prepare(std::size_t pos, const std::list<UTF16String>& val);
/// Prepares a string list.
virtual void prepare(std::size_t pos, const BLOB&) = 0;

View File

@@ -46,6 +46,7 @@ public:
FDT_FLOAT,
FDT_DOUBLE,
FDT_STRING,
FDT_WSTRING,
FDT_BLOB,
FDT_CLOB,
FDT_DATE,

View File

@@ -50,7 +50,7 @@ public:
}
void prepare()
/// Preparations data.
/// Prepares data.
{
TypeHandler<T>::prepare(_pos, _val, preparation());
}
@@ -82,7 +82,7 @@ public:
}
void prepare()
/// Preparations data.
/// Prepares data.
{
TypeHandler<std::vector<T> >::prepare(_pos, _val, preparation());
}
@@ -114,7 +114,7 @@ public:
}
void prepare()
/// Preparations data.
/// Prepares data.
{
TypeHandler<std::deque<T> >::prepare(_pos, _val, preparation());
}
@@ -146,7 +146,7 @@ public:
}
void prepare()
/// Preparations data.
/// Prepares data.
{
TypeHandler<std::list<T> >::prepare(_pos, _val, preparation());
}

View File

@@ -292,6 +292,24 @@ void AbstractBinder::bind(std::size_t pos, const std::list<std::string>& val, Di
}
void AbstractBinder::bind(std::size_t pos, const std::vector<UTF16String>& val, Direction dir)
{
throw NotImplementedException("std::vector binder must be implemented.");
}
void AbstractBinder::bind(std::size_t pos, const std::deque<UTF16String>& val, Direction dir)
{
throw NotImplementedException("std::deque binder must be implemented.");
}
void AbstractBinder::bind(std::size_t pos, const std::list<UTF16String>& val, Direction dir)
{
throw NotImplementedException("std::list binder must be implemented.");
}
void AbstractBinder::bind(std::size_t pos, const std::vector<BLOB>& val, Direction dir)
{
throw NotImplementedException("std::vector binder must be implemented.");
@@ -408,6 +426,8 @@ void AbstractBinder::bind(std::size_t pos, const Any& val, Direction dir)
bind(pos, RefAnyCast<Int32>(val), dir);
else if(type == typeid(std::string))
bind(pos, RefAnyCast<std::string>(val), dir);
else if (type == typeid(Poco::UTF16String))
bind(pos, RefAnyCast<Poco::UTF16String>(val), dir);
else if (type == typeid(bool))
bind(pos, RefAnyCast<bool>(val), dir);
else if(type == typeid(char))
@@ -457,6 +477,8 @@ void AbstractBinder::bind(std::size_t pos, const Poco::Dynamic::Var& val, Direct
bind(pos, val.extract<Int32>(), dir);
else if(type == typeid(std::string))
bind(pos, val.extract<std::string>(), dir);
else if (type == typeid(Poco::UTF16String))
bind(pos, val.extract<Poco::UTF16String>(), dir);
else if (type == typeid(bool))
bind(pos, val.extract<bool>(), dir);
else if(type == typeid(char))

View File

@@ -39,15 +39,4 @@ AbstractExtraction::~AbstractExtraction()
}
bool AbstractExtraction::isValueNull(const std::string& str, bool deflt)
{
if (getForceEmptyString()) return false;
if (getEmptyStringIsNull() && str.empty())
return true;
return deflt;
}
} } // namespace Poco::Data

View File

@@ -286,6 +286,24 @@ bool AbstractExtractor::extract(std::size_t pos, std::list<std::string>& val)
}
bool AbstractExtractor::extract(std::size_t pos, std::vector<UTF16String>& val)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool AbstractExtractor::extract(std::size_t pos, std::deque<UTF16String>& val)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool AbstractExtractor::extract(std::size_t pos, std::list<UTF16String>& val)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool AbstractExtractor::extract(std::size_t pos, std::vector<BLOB>& val)
{
throw NotImplementedException("std::vector extractor must be implemented.");

View File

@@ -287,6 +287,24 @@ void AbstractPreparator::prepare(std::size_t pos, const std::list<std::string>&
}
void AbstractPreparator::prepare(std::size_t pos, const std::vector<UTF16String>& val)
{
throw NotImplementedException("std::vector preparator must be implemented.");
}
void AbstractPreparator::prepare(std::size_t pos, const std::deque<UTF16String>& val)
{
throw NotImplementedException("std::deque preparator must be implemented.");
}
void AbstractPreparator::prepare(std::size_t pos, const std::list<UTF16String>& val)
{
throw NotImplementedException("std::list preparator must be implemented.");
}
void AbstractPreparator::prepare(std::size_t pos, const std::vector<BLOB>& val)
{
throw NotImplementedException("std::vector preparator must be implemented.");

View File

@@ -20,10 +20,12 @@
#include "Poco/Data/Time.h"
#include "Poco/Data/DataException.h"
#include "Poco/DateTime.h"
#include "Poco/UTFString.h"
using namespace Poco::Data::Keywords;
using Poco::DateTime;
using Poco::UTF16String;
namespace Poco {
@@ -104,6 +106,7 @@ Poco::Dynamic::Var RecordSet::value(std::size_t col, std::size_t row, bool useFi
case MetaColumn::FDT_FLOAT: return value<float>(col, row, useFilter);
case MetaColumn::FDT_DOUBLE: return value<double>(col, row, useFilter);
case MetaColumn::FDT_STRING: return value<std::string>(col, row, useFilter);
case MetaColumn::FDT_WSTRING: return value<UTF16String>(col, row, useFilter);
case MetaColumn::FDT_BLOB: return value<BLOB>(col, row, useFilter);
case MetaColumn::FDT_CLOB: return value<CLOB>(col, row, useFilter);
case MetaColumn::FDT_DATE: return value<Date>(col, row, useFilter);
@@ -136,6 +139,7 @@ Poco::Dynamic::Var RecordSet::value(const std::string& name, std::size_t row, bo
case MetaColumn::FDT_FLOAT: return value<float>(name, row, useFilter);
case MetaColumn::FDT_DOUBLE: return value<double>(name, row, useFilter);
case MetaColumn::FDT_STRING: return value<std::string>(name, row, useFilter);
case MetaColumn::FDT_WSTRING: return value<UTF16String>(name, row, useFilter);
case MetaColumn::FDT_BLOB: return value<BLOB>(name, row, useFilter);
case MetaColumn::FDT_DATE: return value<Date>(name, row, useFilter);
case MetaColumn::FDT_TIME: return value<Time>(name, row, useFilter);

View File

@@ -327,6 +327,8 @@ void StatementImpl::makeExtractors(std::size_t count)
addInternalExtract<double>(mc); break;
case MetaColumn::FDT_STRING:
addInternalExtract<std::string>(mc); break;
case MetaColumn::FDT_WSTRING:
addInternalExtract<Poco::UTF16String>(mc); break;
case MetaColumn::FDT_BLOB:
addInternalExtract<BLOB>(mc); break;
case MetaColumn::FDT_DATE:

View File

@@ -112,6 +112,11 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
}
void Binder::bind(std::size_t pos, const Poco::UTF16String& val, Direction dir)
{
}
void Binder::bind(std::size_t pos, const BLOB& val, Direction dir)
{
}

View File

@@ -84,6 +84,9 @@ public:
void bind(std::size_t pos, const std::string& val, Direction dir);
/// Binds a string.
void bind(std::size_t pos, const Poco::UTF16String& val, Direction dir);
/// Binds a UTF16String.
void bind(std::size_t pos, const BLOB& val, Direction dir);
/// Binds a BLOB.

View File

@@ -137,6 +137,14 @@ bool Extractor::extract(std::size_t pos, std::string& val)
}
bool Extractor::extract(std::size_t pos, Poco::UTF16String& val)
{
std::string str("");
Poco::UnicodeConverter::convert(str, val);
return true;
}
bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val)
{
return true;

View File

@@ -87,6 +87,9 @@ public:
bool extract(std::size_t pos, std::string& val);
/// Extracts a string.
bool extract(std::size_t pos, Poco::UTF16String& val);
/// Extracts a UTF16String.
bool extract(std::size_t pos, Poco::Data::BLOB& val);
/// Extracts a BLOB.

View File

@@ -107,6 +107,11 @@ void Preparator::prepare(std::size_t pos, const std::string&)
}
void Preparator::prepare(std::size_t pos, const Poco::UTF16String&)
{
}
void Preparator::prepare(std::size_t pos, const Poco::Data::BLOB&)
{
}

View File

@@ -36,72 +36,75 @@ public:
/// Destroys the Preparator.
void prepare(std::size_t pos, const Poco::Int8&);
/// Preparations an Int8.
/// Prepares an Int8.
void prepare(std::size_t pos, const Poco::UInt8&);
/// Preparations an UInt8.
/// Prepares an UInt8.
void prepare(std::size_t pos, const Poco::Int16&);
/// Preparations an Int16.
/// Prepares an Int16.
void prepare(std::size_t pos, const Poco::UInt16&);
/// Preparations an UInt16.
/// Prepares an UInt16.
void prepare(std::size_t pos, const Poco::Int32&);
/// Preparations an Int32.
/// Prepares an Int32.
void prepare(std::size_t pos, const Poco::UInt32&);
/// Preparations an UInt32.
/// Prepares an UInt32.
void prepare(std::size_t pos, const Poco::Int64&);
/// Preparations an Int64.
/// Prepares an Int64.
void prepare(std::size_t pos, const Poco::UInt64&);
/// Preparations an UInt64.
/// Prepares an UInt64.
#ifndef POCO_LONG_IS_64_BIT
void prepare(std::size_t pos, const long&);
/// Preparations a long.
/// Prepares a long.
void prepare(std::size_t pos, const unsigned long&);
/// Preparations an unsigned long.
/// Prepares an unsigned long.
#endif
void prepare(std::size_t pos, const bool&);
/// Preparations a boolean.
/// Prepares a boolean.
void prepare(std::size_t pos, const float&);
/// Preparations a float.
/// Prepares a float.
void prepare(std::size_t pos, const double&);
/// Preparations a double.
/// Prepares a double.
void prepare(std::size_t pos, const char&);
/// Preparations a single character.
/// Prepares a single character.
void prepare(std::size_t pos, const std::string&);
/// Preparations a string.
/// Prepares a string.
void prepare(std::size_t pos, const Poco::UTF16String&);
/// Prepares a UTF16String.
void prepare(std::size_t pos, const Poco::Data::BLOB&);
/// Preparations a BLOB.
/// Prepares a BLOB.
void prepare(std::size_t pos, const Poco::Data::CLOB&);
/// Preparations a CLOB.
/// Prepares a CLOB.
void prepare(std::size_t pos, const Poco::Data::Date&);
/// Preparations a Date.
/// Prepares a Date.
void prepare(std::size_t pos, const Poco::Data::Time&);
/// Preparations a Time.
/// Prepares a Time.
void prepare(std::size_t pos, const Poco::DateTime&);
/// Preparations a DateTime.
/// Prepares a DateTime.
void prepare(std::size_t pos, const Poco::Any&);
/// Preparations an Any.
/// Prepares an Any.
void prepare(std::size_t pos, const Poco::Dynamic::Var&);
/// Preparations a Var.
/// Prepares a Var.
};