mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-17 11:05:03 +02:00
GH #290: Unicode support
This commit is contained in:
@@ -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);
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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]);
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -69,6 +69,7 @@ private:
|
||||
void recreateBoolTable();
|
||||
void recreateMiscTable();
|
||||
void recreateLogTable();
|
||||
void recreateUnicodeTable();
|
||||
|
||||
void configurePLPgSQL();
|
||||
/// Configures PL/pgSQL in the database. A reasonable defaults
|
||||
|
@@ -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;
|
||||
|
@@ -74,6 +74,7 @@ private:
|
||||
void recreateBoolTable();
|
||||
void recreateMiscTable();
|
||||
void recreateLogTable();
|
||||
void recreateUnicodeTable();
|
||||
|
||||
static SessionPtr _pSession;
|
||||
static ExecPtr _pExecutor;
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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));
|
||||
}
|
@@ -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:
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -44,7 +44,7 @@ public:
|
||||
/// Destroys the AbstractPreparation.
|
||||
|
||||
virtual void prepare() = 0;
|
||||
/// Preparations data.
|
||||
/// Prepares data.
|
||||
|
||||
protected:
|
||||
AbstractPreparation();
|
||||
|
@@ -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;
|
||||
|
@@ -46,6 +46,7 @@ public:
|
||||
FDT_FLOAT,
|
||||
FDT_DOUBLE,
|
||||
FDT_STRING,
|
||||
FDT_WSTRING,
|
||||
FDT_BLOB,
|
||||
FDT_CLOB,
|
||||
FDT_DATE,
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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))
|
||||
|
@@ -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
|
||||
|
@@ -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.");
|
||||
|
@@ -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.");
|
||||
|
@@ -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);
|
||||
|
@@ -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:
|
||||
|
@@ -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)
|
||||
{
|
||||
}
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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&)
|
||||
{
|
||||
}
|
||||
|
@@ -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.
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user