Skip to content

Commit 1aa28e1

Browse files
committed
GH pocoproject#290: Unicode support
1 parent 8b39a87 commit 1aa28e1

46 files changed

Lines changed: 1168 additions & 114 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Release 1.5.3 (2014-05-xx)
6767
- fixed GH #442: Use correct prefix length field of Windows IP_ADAPTER_PREFIX structure
6868
- improved GH #328: NetworkInterface on Windows XP
6969
- fixed GH #154 Add support for MYSQL_TYPE_NEWDECIMAL to Poco::Data::MySQL
70+
- fixed GH #290: Unicode support
7071

7172
Release 1.5.2 (2013-09-16)
7273
==========================

‎Data/ODBC/include/Poco/Data/ODBC/Binder.h‎

Lines changed: 112 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,18 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
252252
void bind(std::size_t pos, const std::list<std::string>& val, Direction dir);
253253
/// Binds a string list.
254254

255+
void bind(std::size_t pos, const UTF16String& val, Direction dir);
256+
/// Binds a string.
257+
258+
void bind(std::size_t pos, const std::vector<UTF16String>& val, Direction dir);
259+
/// Binds a string vector.
260+
261+
void bind(std::size_t pos, const std::deque<UTF16String>& val, Direction dir);
262+
/// Binds a string deque.
263+
264+
void bind(std::size_t pos, const std::list<UTF16String>& val, Direction dir);
265+
/// Binds a string list.
266+
255267
void bind(std::size_t pos, const BLOB& val, Direction dir);
256268
/// Binds a BLOB. In-bound only.
257269

@@ -341,18 +353,20 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
341353
/// Clears the cached storage.
342354

343355
private:
344-
typedef std::vector<SQLLEN*> LengthVec;
345-
typedef std::vector<std::vector<SQLLEN> > LengthVecVec;
346-
typedef std::vector<char*> CharPtrVec;
347-
typedef std::vector<bool*> BoolPtrVec;
348-
typedef std::vector<std::vector<SQL_DATE_STRUCT> > DateVec;
349-
typedef std::vector<std::vector<SQL_TIME_STRUCT> > TimeVec;
350-
typedef std::vector<std::vector<SQL_TIMESTAMP_STRUCT> > DateTimeVec;
351-
typedef std::vector<std::vector<Poco::Any> > AnyVec;
352-
typedef std::map<char*, std::string*> StringMap;
353-
typedef std::map<SQL_DATE_STRUCT*, Date*> DateMap;
354-
typedef std::map<SQL_TIME_STRUCT*, Time*> TimeMap;
355-
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
356+
typedef std::vector<SQLLEN*> LengthVec;
357+
typedef std::vector<std::vector<SQLLEN> > LengthVecVec;
358+
typedef std::vector<char*> CharPtrVec;
359+
typedef std::vector<UTF16Char*> UTF16CharPtrVec;
360+
typedef std::vector<bool*> BoolPtrVec;
361+
typedef std::vector<std::vector<SQL_DATE_STRUCT> > DateVec;
362+
typedef std::vector<std::vector<SQL_TIME_STRUCT> > TimeVec;
363+
typedef std::vector<std::vector<SQL_TIMESTAMP_STRUCT> > DateTimeVec;
364+
typedef std::vector<std::vector<Poco::Any> > AnyVec;
365+
typedef std::map<char*, std::string*> StringMap;
366+
typedef std::map<UTF16String::value_type*, UTF16String*> UTF16StringMap;
367+
typedef std::map<SQL_DATE_STRUCT*, Date*> DateMap;
368+
typedef std::map<SQL_TIME_STRUCT*, Time*> TimeMap;
369+
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
356370

357371
void describeParameter(std::size_t pos);
358372
/// Sets the description field for the parameter, if needed.
@@ -581,6 +595,71 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
581595
}
582596
}
583597

598+
template <typename C>
599+
void bindImplContainerUTF16String(std::size_t pos, const C& val, Direction dir)
600+
/// Utility function to bind containers of strings.
601+
{
602+
if (isOutBound(dir) || !isInBound(dir))
603+
throw NotImplementedException("String container parameter type can only be inbound.");
604+
605+
if (PB_IMMEDIATE != _paramBinding)
606+
throw InvalidAccessException("Containers can only be bound immediately.");
607+
608+
if (0 == val.size())
609+
throw InvalidArgumentException("Empty container not allowed.");
610+
611+
setParamSetSize(val.size());
612+
613+
SQLINTEGER size = 0;
614+
getColumnOrParameterSize(pos, size);
615+
poco_assert(size > 0);
616+
617+
if (size == _maxFieldSize)
618+
{
619+
getMinValueSize(val, size);
620+
// accomodate for terminating zero
621+
if (size != _maxFieldSize) size += sizeof(UTF16Char);
622+
}
623+
624+
if (_vecLengthIndicator.size() <= pos)
625+
{
626+
_vecLengthIndicator.resize(pos + 1);
627+
_vecLengthIndicator[pos].resize(val.size(), SQL_NTS);
628+
}
629+
630+
if (_utf16CharPtrs.size() <= pos)
631+
_utf16CharPtrs.resize(pos + 1, 0);
632+
633+
_utf16CharPtrs[pos] = (UTF16Char*)std::calloc(val.size() * size, sizeof(UTF16Char));
634+
635+
std::size_t strSize;
636+
std::size_t offset = 0;
637+
typename C::const_iterator it = val.begin();
638+
typename C::const_iterator end = val.end();
639+
for (; it != end; ++it)
640+
{
641+
strSize = it->size() * sizeof(UTF16Char);
642+
if (strSize > size)
643+
throw LengthExceededException("SQLBindParameter(std::vector<UTF16String>)");
644+
std::memcpy(_utf16CharPtrs[pos] + offset, it->data(), strSize);
645+
offset += (size / sizeof(UTF16Char));
646+
}
647+
648+
if (Utility::isError(SQLBindParameter(_rStmt,
649+
(SQLUSMALLINT)pos + 1,
650+
toODBCDirection(dir),
651+
SQL_C_WCHAR,
652+
SQL_WLONGVARCHAR,
653+
(SQLUINTEGER)size - 1,
654+
0,
655+
_utf16CharPtrs[pos],
656+
(SQLINTEGER)size,
657+
&_vecLengthIndicator[pos][0])))
658+
{
659+
throw StatementException(_rStmt, "SQLBindParameter(std::vector<UTF16String>)");
660+
}
661+
}
662+
584663
template <typename C>
585664
void bindImplContainerLOB(std::size_t pos, const C& val, Direction dir)
586665
{
@@ -859,7 +938,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
859938
typename T::const_iterator end = val.end();
860939
for (; it != end; ++it)
861940
{
862-
std::size_t sz = it->size();
941+
std::size_t sz = it->size() * sizeof(T);
863942
if (sz > _maxFieldSize)
864943
throw LengthExceededException();
865944

@@ -888,11 +967,13 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
888967
TimeMap _times;
889968
TimestampMap _timestamps;
890969
StringMap _strings;
970+
UTF16StringMap _utf16Strings;
891971

892972
DateVec _dateVec;
893973
TimeVec _timeVec;
894974
DateTimeVec _dateTimeVec;
895975
CharPtrVec _charPtrs;
976+
UTF16CharPtrVec _utf16CharPtrs;
896977
BoolPtrVec _boolPtrs;
897978
const TypeInfo* _pTypeInfo;
898979
SQLINTEGER _paramSetSize;
@@ -1241,6 +1322,24 @@ inline void Binder::bind(std::size_t pos, const std::list<std::string>& val, Dir
12411322
bindImplContainerString(pos, val, dir);
12421323
}
12431324

1325+
1326+
inline void Binder::bind(std::size_t pos, const std::vector<UTF16String>& val, Direction dir)
1327+
{
1328+
bindImplContainerUTF16String(pos, val, dir);
1329+
}
1330+
1331+
1332+
inline void Binder::bind(std::size_t pos, const std::deque<UTF16String>& val, Direction dir)
1333+
{
1334+
bindImplContainerUTF16String(pos, val, dir);
1335+
}
1336+
1337+
1338+
inline void Binder::bind(std::size_t pos, const std::list<UTF16String>& val, Direction dir)
1339+
{
1340+
bindImplContainerUTF16String(pos, val, dir);
1341+
}
1342+
12441343
inline void Binder::bind(std::size_t pos, const BLOB& val, Direction dir)
12451344
{
12461345
bindImplLOB<BLOB>(pos, val, dir);

‎Data/ODBC/include/Poco/Data/ODBC/Extractor.h‎

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "Poco/Any.h"
3434
#include "Poco/Dynamic/Var.h"
3535
#include "Poco/Nullable.h"
36+
#include "Poco/UTFString.h"
3637
#include "Poco/Exception.h"
3738
#include <map>
3839
#ifdef POCO_OS_FAMILY_WINDOWS
@@ -232,6 +233,19 @@ class ODBC_API Extractor: public Poco::Data::AbstractExtractor
232233

233234
bool extract(std::size_t pos, std::list<std::string>& val);
234235
/// Extracts a string list.
236+
/// Extracts a single character list.
237+
238+
bool extract(std::size_t pos, UTF16String& val);
239+
/// Extracts a string.
240+
241+
bool extract(std::size_t pos, std::vector<UTF16String>& val);
242+
/// Extracts a string vector.
243+
244+
bool extract(std::size_t pos, std::deque<UTF16String>& val);
245+
/// Extracts a string deque.
246+
247+
bool extract(std::size_t pos, std::list<UTF16String>& val);
248+
/// Extracts a string list.
235249

236250
bool extract(std::size_t pos, Poco::Data::BLOB& val);
237251
/// Extracts a BLOB.
@@ -372,7 +386,10 @@ class ODBC_API Extractor: public Poco::Data::AbstractExtractor
372386

373387
bool extractBoundImplContainer(std::size_t pos, std::vector<std::string>& values);
374388
bool extractBoundImplContainer(std::size_t pos, std::deque<std::string>& values);
375-
bool extractBoundImplContainer(std::size_t pos, std::list<std::string>& values);
389+
bool extractBoundImplContainer(std::size_t pos, std::list<std::string>& values);
390+
bool extractBoundImplContainer(std::size_t pos, std::vector<Poco::UTF16String>& values);
391+
bool extractBoundImplContainer(std::size_t pos, std::deque<Poco::UTF16String>& values);
392+
bool extractBoundImplContainer(std::size_t pos, std::list<Poco::UTF16String>& values);
376393
bool extractBoundImplContainer(std::size_t pos, std::vector<Poco::Data::CLOB>& values);
377394
bool extractBoundImplContainer(std::size_t pos, std::deque<Poco::Data::CLOB>& values);
378395
bool extractBoundImplContainer(std::size_t pos, std::list<Poco::Data::CLOB>& values);
@@ -394,7 +411,19 @@ class ODBC_API Extractor: public Poco::Data::AbstractExtractor
394411
ItType it = values.begin();
395412
ItType end = values.end();
396413
for (int row = 0; it != end; ++it, ++row)
397-
it->assign(*pc + row * colWidth, _pPreparator->actualDataSize(pos, row));
414+
{
415+
it->assign(*pc + row * colWidth / sizeof(CharType), _pPreparator->actualDataSize(pos, row));
416+
// clean up superfluous null chars returned by some drivers
417+
typename StringType::size_type trimLen = 0;
418+
typename StringType::reverse_iterator sIt = it->rbegin();
419+
typename StringType::reverse_iterator sEnd = it->rend();
420+
for (; sIt != sEnd; ++sIt)
421+
{
422+
if (*sIt == '\0') ++trimLen;
423+
else break;
424+
}
425+
if (trimLen) it->assign(it->begin(), it->begin() + it->length() - trimLen);
426+
}
398427

399428
return true;
400429
}
@@ -522,6 +551,9 @@ class ODBC_API Extractor: public Poco::Data::AbstractExtractor
522551
case MetaColumn::FDT_STRING:
523552
{ return extAny<T, std::string>(pos, val); }
524553

554+
case MetaColumn::FDT_WSTRING:
555+
{ return extAny<T, Poco::UTF16String>(pos, val); }
556+
525557
case MetaColumn::FDT_BLOB:
526558
{ return extAny<T, Poco::Data::BLOB>(pos, val); }
527559

@@ -592,6 +624,24 @@ inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<std:
592624
}
593625

594626

627+
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::vector<Poco::UTF16String>& values)
628+
{
629+
return extractBoundImplContainerString(pos, values);
630+
}
631+
632+
633+
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::deque<Poco::UTF16String>& values)
634+
{
635+
return extractBoundImplContainerString(pos, values);
636+
}
637+
638+
639+
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<Poco::UTF16String>& values)
640+
{
641+
return extractBoundImplContainerString(pos, values);
642+
}
643+
644+
595645
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
596646
std::vector<Poco::Data::CLOB>& values)
597647
{

‎Data/ODBC/include/Poco/Data/ODBC/Preparator.h‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "Poco/DynamicAny.h"
3232
#include "Poco/DateTime.h"
3333
#include "Poco/SharedPtr.h"
34+
#include "Poco/UTFString.h"
3435
#include <vector>
3536
#ifdef POCO_OS_FAMILY_WINDOWS
3637
#include <windows.h>
@@ -87,8 +88,10 @@ class ODBC_API Preparator : public AbstractPreparator
8788
DT_BOOL,
8889
DT_BOOL_ARRAY,
8990
DT_CHAR,
91+
DT_WCHAR,
9092
DT_UCHAR,
9193
DT_CHAR_ARRAY,
94+
DT_WCHAR_ARRAY,
9295
DT_UCHAR_ARRAY,
9396
DT_DATE,
9497
DT_TIME,
@@ -280,6 +283,18 @@ class ODBC_API Preparator : public AbstractPreparator
280283
void prepare(std::size_t pos, const std::list<std::string>& val);
281284
/// Prepares a string list.
282285

286+
void prepare(std::size_t pos, const UTF16String& val);
287+
/// Prepares a string.
288+
289+
void prepare(std::size_t pos, const std::vector<UTF16String>& val);
290+
/// Prepares a string vector.
291+
292+
void prepare(std::size_t pos, const std::deque<UTF16String>& val);
293+
/// Prepares a string deque.
294+
295+
void prepare(std::size_t pos, const std::list<UTF16String>& val);
296+
/// Prepares a string list.
297+
283298
void prepare(std::size_t pos, const Poco::Data::BLOB& val);
284299
/// Prepares a BLOB.
285300

@@ -490,6 +505,15 @@ class ODBC_API Preparator : public AbstractPreparator
490505
else
491506
return prepareVariableLen<char>(pos, SQL_C_CHAR, maxDataSize(pos), DT_CHAR);
492507

508+
case MetaColumn::FDT_WSTRING:
509+
{
510+
typedef UTF16String::value_type CharType;
511+
if (pVal)
512+
return prepareCharArray<CharType, DT_WCHAR_ARRAY>(pos, SQL_C_WCHAR, maxDataSize(pos), pVal->size());
513+
else
514+
return prepareVariableLen<CharType>(pos, SQL_C_WCHAR, maxDataSize(pos), DT_WCHAR);
515+
}
516+
493517
case MetaColumn::FDT_BLOB:
494518
{
495519
typedef Poco::Data::BLOB::ValueType CharType;
@@ -1007,6 +1031,30 @@ inline void Preparator::prepare(std::size_t pos, const std::list<std::string>& v
10071031
}
10081032

10091033

1034+
inline void Preparator::prepare(std::size_t pos, const UTF16String&)
1035+
{
1036+
prepareVariableLen<UTF16String::value_type>(pos, SQL_C_WCHAR, maxDataSize(pos), DT_CHAR);
1037+
}
1038+
1039+
1040+
inline void Preparator::prepare(std::size_t pos, const std::vector<UTF16String>& val)
1041+
{
1042+
prepareCharArray<UTF16String::value_type, DT_WCHAR_ARRAY>(pos, SQL_C_WCHAR, maxDataSize(pos), val.size());
1043+
}
1044+
1045+
1046+
inline void Preparator::prepare(std::size_t pos, const std::deque<UTF16String>& val)
1047+
{
1048+
prepareCharArray<UTF16String::value_type, DT_WCHAR_ARRAY>(pos, SQL_C_WCHAR, maxDataSize(pos), val.size());
1049+
}
1050+
1051+
1052+
inline void Preparator::prepare(std::size_t pos, const std::list<UTF16String>& val)
1053+
{
1054+
prepareCharArray<UTF16String::value_type, DT_WCHAR_ARRAY>(pos, SQL_C_WCHAR, maxDataSize(pos), val.size());
1055+
}
1056+
1057+
10101058
inline void Preparator::prepare(std::size_t pos, const Poco::Data::BLOB&)
10111059
{
10121060
prepareVariableLen<Poco::Data::BLOB::ValueType>(pos, SQL_C_BINARY, maxDataSize(pos), DT_UCHAR);

0 commit comments

Comments
 (0)