mirror of
https://github.com/pocoproject/poco.git
synced 2025-01-19 00:46:03 +01:00
#3318: Data: Support Poco::UUID for data binding
This commit is contained in:
parent
a95c591e0a
commit
7569ccf82b
@ -19,7 +19,6 @@
|
|||||||
#include "Poco/ActiveRecord/ActiveRecordLib.h"
|
#include "Poco/ActiveRecord/ActiveRecordLib.h"
|
||||||
#include "Poco/ActiveRecord/Context.h"
|
#include "Poco/ActiveRecord/Context.h"
|
||||||
#include "Poco/ActiveRecord/IDTraits.h"
|
#include "Poco/ActiveRecord/IDTraits.h"
|
||||||
#include "Poco/ActiveRecord/TypeHandler.h"
|
|
||||||
#include "Poco/DateTime.h"
|
#include "Poco/DateTime.h"
|
||||||
#include "Poco/RefCountedObject.h"
|
#include "Poco/RefCountedObject.h"
|
||||||
#include "Poco/AutoPtr.h"
|
#include "Poco/AutoPtr.h"
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
//
|
|
||||||
// TypeHandler.h
|
|
||||||
//
|
|
||||||
// Library: ActiveRecord
|
|
||||||
// Package: ActiveRecord
|
|
||||||
// Module: TypeHandler
|
|
||||||
//
|
|
||||||
// Copyright (c) 2020, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef ActiveRecord_TypeHandler_INCLUDED
|
|
||||||
#define ActiveRecord_TypeHandler_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/TypeHandler.h"
|
|
||||||
#include "Poco/ThreadLocal.h"
|
|
||||||
#include "Poco/UUID.h"
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace Data {
|
|
||||||
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class TypeHandler<Poco::UUID>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using UUIDMap = std::map<std::size_t, std::string>;
|
|
||||||
|
|
||||||
static std::size_t size()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bind(std::size_t pos, const Poco::UUID& uuid, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir)
|
|
||||||
{
|
|
||||||
static Poco::ThreadLocal<UUIDMap> uuidMap;
|
|
||||||
std::string& uuidString = (*uuidMap)[pos];
|
|
||||||
uuidString = uuid.toString();
|
|
||||||
TypeHandler<std::string>::bind(pos++, uuidString, pBinder, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void extract(std::size_t pos, Poco::UUID& uuid, const Poco::UUID& deflt, AbstractExtractor::Ptr pExtr)
|
|
||||||
{
|
|
||||||
std::string defltString = deflt.toString();
|
|
||||||
std::string uuidString;
|
|
||||||
TypeHandler<std::string>::extract(pos++, uuidString, defltString, pExtr);
|
|
||||||
uuid.parse(uuidString);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prepare(std::size_t pos, const Poco::UUID& uuid, AbstractPreparator::Ptr pPrep)
|
|
||||||
{
|
|
||||||
static Poco::ThreadLocal<UUIDMap> uuidMap;
|
|
||||||
std::string& uuidString = (*uuidMap)[pos];
|
|
||||||
uuidString = uuid.toString();
|
|
||||||
TypeHandler<std::string>::prepare(pos++, uuidString, pPrep);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Data
|
|
||||||
|
|
||||||
|
|
||||||
#endif // ActiveRecord_TypeHandler_INCLUDED
|
|
||||||
|
|
@ -104,6 +104,9 @@ public:
|
|||||||
virtual void bind(std::size_t pos, const Time& val, Direction dir);
|
virtual void bind(std::size_t pos, const Time& val, Direction dir);
|
||||||
/// Binds a Time.
|
/// Binds a Time.
|
||||||
|
|
||||||
|
virtual void bind(std::size_t pos, const UUID& val, Direction dir);
|
||||||
|
/// Binds a UUID.
|
||||||
|
|
||||||
virtual void bind(std::size_t pos, const NullData& val, Direction dir);
|
virtual void bind(std::size_t pos, const NullData& val, Direction dir);
|
||||||
/// Binds a null.
|
/// Binds a null.
|
||||||
|
|
||||||
|
@ -110,6 +110,9 @@ public:
|
|||||||
virtual bool extract(std::size_t pos, Time& val);
|
virtual bool extract(std::size_t pos, Time& val);
|
||||||
/// Extracts a Time. Returns false if null was received.
|
/// Extracts a Time. Returns false if null was received.
|
||||||
|
|
||||||
|
virtual bool extract(std::size_t pos, UUID& val);
|
||||||
|
/// Extracts a UUID. Returns false if null was received.
|
||||||
|
|
||||||
virtual bool extract(std::size_t pos, Any& val);
|
virtual bool extract(std::size_t pos, Any& val);
|
||||||
/// Extracts an Any. Returns false if null was received.
|
/// Extracts an Any. Returns false if null was received.
|
||||||
|
|
||||||
|
@ -211,6 +211,13 @@ void Binder::bind(std::size_t pos, const Time& val, Direction dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
|
||||||
|
{
|
||||||
|
std::string str = val.toString();
|
||||||
|
bind(pos, str, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Binder::bind(std::size_t pos, const NullData&, Direction dir)
|
void Binder::bind(std::size_t pos, const NullData&, Direction dir)
|
||||||
{
|
{
|
||||||
poco_assert(dir == PD_IN);
|
poco_assert(dir == PD_IN);
|
||||||
|
@ -204,6 +204,18 @@ bool Extractor::extract(std::size_t pos, Time& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Extractor::extract(std::size_t pos, UUID& val)
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
if (extract(pos, str))
|
||||||
|
{
|
||||||
|
val.parse(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, Any& val)
|
bool Extractor::extract(std::size_t pos, Any& val)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -496,6 +496,15 @@ void MySQLTest::testDouble()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MySQLTest::testUUID()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
recreateUUIDsTable();
|
||||||
|
_pExecutor->uuids();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MySQLTest::testTuple()
|
void MySQLTest::testTuple()
|
||||||
{
|
{
|
||||||
if (!_pSession) fail ("Test not available.");
|
if (!_pSession) fail ("Test not available.");
|
||||||
@ -779,6 +788,15 @@ void MySQLTest::recreateFloatsTable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MySQLTest::recreateUUIDsTable()
|
||||||
|
{
|
||||||
|
dropTable("Strings");
|
||||||
|
try { *_pSession << "CREATE TABLE Strings (str CHAR(36))", now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateUUIDsTable()"); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateUUIDsTable()"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MySQLTest::recreateTuplesTable()
|
void MySQLTest::recreateTuplesTable()
|
||||||
{
|
{
|
||||||
dropTable("Tuples");
|
dropTable("Tuples");
|
||||||
@ -904,6 +922,7 @@ CppUnit::Test* MySQLTest::suite()
|
|||||||
CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts);
|
CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts);
|
||||||
CppUnit_addTest(pSuite, MySQLTest, testFloat);
|
CppUnit_addTest(pSuite, MySQLTest, testFloat);
|
||||||
CppUnit_addTest(pSuite, MySQLTest, testDouble);
|
CppUnit_addTest(pSuite, MySQLTest, testDouble);
|
||||||
|
CppUnit_addTest(pSuite, MySQLTest, testUUID);
|
||||||
CppUnit_addTest(pSuite, MySQLTest, testTuple);
|
CppUnit_addTest(pSuite, MySQLTest, testTuple);
|
||||||
CppUnit_addTest(pSuite, MySQLTest, testTupleVector);
|
CppUnit_addTest(pSuite, MySQLTest, testTupleVector);
|
||||||
CppUnit_addTest(pSuite, MySQLTest, testInternalExtraction);
|
CppUnit_addTest(pSuite, MySQLTest, testInternalExtraction);
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
class MySQLTest: public CppUnit::TestCase
|
class MySQLTest: public CppUnit::TestCase
|
||||||
/// MySQL test class
|
/// MySQL test class
|
||||||
/// Tested:
|
/// Tested:
|
||||||
///
|
///
|
||||||
/// Driver | DB | OS
|
/// Driver | DB | OS
|
||||||
/// ----------------+---------------------------+------------------------------------------
|
/// ----------------+---------------------------+------------------------------------------
|
||||||
/// 03.51.12.00 | MySQL 5.0.27-community-nt | MS Windows XP Professional x64 v.2003/SP1
|
/// 03.51.12.00 | MySQL 5.0.27-community-nt | MS Windows XP Professional x64 v.2003/SP1
|
||||||
@ -84,6 +84,8 @@ public:
|
|||||||
void testFloat();
|
void testFloat();
|
||||||
void testDouble();
|
void testDouble();
|
||||||
|
|
||||||
|
void testUUID();
|
||||||
|
|
||||||
void testTuple();
|
void testTuple();
|
||||||
void testTupleVector();
|
void testTupleVector();
|
||||||
|
|
||||||
@ -119,6 +121,7 @@ private:
|
|||||||
void recreateIntsTable();
|
void recreateIntsTable();
|
||||||
void recreateUnsignedIntsTable();
|
void recreateUnsignedIntsTable();
|
||||||
void recreateFloatsTable();
|
void recreateFloatsTable();
|
||||||
|
void recreateUUIDsTable();
|
||||||
void recreateTuplesTable();
|
void recreateTuplesTable();
|
||||||
void recreateVectorsTable();
|
void recreateVectorsTable();
|
||||||
void recreateNullableIntTable();
|
void recreateNullableIntTable();
|
||||||
|
@ -545,6 +545,29 @@ void SQLExecutor::doubles()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::uuids()
|
||||||
|
{
|
||||||
|
std::string funct = "uuids()";
|
||||||
|
Poco::UUID data("da8b9c4d-faa0-44e1-b834-ece1e7d31cd5");
|
||||||
|
Poco::UUID ret;
|
||||||
|
|
||||||
|
try { *_pSession << "INSERT INTO Strings VALUES (?)", use(data), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
assertTrue (count == 1);
|
||||||
|
|
||||||
|
try { *_pSession << "SELECT str FROM Strings", into(ret), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
assertTrue (ret == data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SQLExecutor::insertSingleBulkVec()
|
void SQLExecutor::insertSingleBulkVec()
|
||||||
{
|
{
|
||||||
std::string funct = "insertSingleBulkVec()";
|
std::string funct = "insertSingleBulkVec()";
|
||||||
|
@ -26,7 +26,7 @@ public:
|
|||||||
PB_IMMEDIATE,
|
PB_IMMEDIATE,
|
||||||
PB_AT_EXEC
|
PB_AT_EXEC
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DataExtraction
|
enum DataExtraction
|
||||||
{
|
{
|
||||||
DE_MANUAL,
|
DE_MANUAL,
|
||||||
@ -37,7 +37,7 @@ public:
|
|||||||
~SQLExecutor();
|
~SQLExecutor();
|
||||||
|
|
||||||
void bareboneMySQLTest(const char* host, const char* user, const char* pwd, const char* db, int port, const char* tableCreateString);
|
void bareboneMySQLTest(const char* host, const char* user, const char* pwd, const char* db, int port, const char* tableCreateString);
|
||||||
/// This function uses "bare bone" MySQL API calls (i.e. calls are not
|
/// This function uses "bare bone" MySQL API calls (i.e. calls are not
|
||||||
/// "wrapped" in PocoData framework structures).
|
/// "wrapped" in PocoData framework structures).
|
||||||
/// The purpose of the function is to verify that driver behaves
|
/// The purpose of the function is to verify that driver behaves
|
||||||
/// correctly. If this test passes, subsequent tests failures are likely ours.
|
/// correctly. If this test passes, subsequent tests failures are likely ours.
|
||||||
@ -86,6 +86,7 @@ public:
|
|||||||
void unsignedInts();
|
void unsignedInts();
|
||||||
void floats();
|
void floats();
|
||||||
void doubles();
|
void doubles();
|
||||||
|
void uuids();
|
||||||
void tuples();
|
void tuples();
|
||||||
void tupleVector();
|
void tupleVector();
|
||||||
|
|
||||||
|
@ -322,6 +322,9 @@ public:
|
|||||||
void bind(std::size_t pos, const std::list<DateTime>& val, Direction dir);
|
void bind(std::size_t pos, const std::list<DateTime>& val, Direction dir);
|
||||||
/// Binds a DateTime list.
|
/// Binds a DateTime list.
|
||||||
|
|
||||||
|
void bind(std::size_t pos, const UUID& val, Direction dir);
|
||||||
|
/// Binds a UUID.
|
||||||
|
|
||||||
void bind(std::size_t pos, const NullData& val, Direction dir);
|
void bind(std::size_t pos, const NullData& val, Direction dir);
|
||||||
/// Binds a null. In-bound only.
|
/// Binds a null. In-bound only.
|
||||||
|
|
||||||
@ -367,6 +370,7 @@ private:
|
|||||||
typedef std::vector<AnyVec> AnyVecVec;
|
typedef std::vector<AnyVec> AnyVecVec;
|
||||||
typedef std::map<char*, std::string*> StringMap;
|
typedef std::map<char*, std::string*> StringMap;
|
||||||
typedef std::map<UTF16String::value_type*, UTF16String*> UTF16StringMap;
|
typedef std::map<UTF16String::value_type*, UTF16String*> UTF16StringMap;
|
||||||
|
typedef std::map<char*, UUID*> UUIDMap;
|
||||||
typedef std::map<SQL_DATE_STRUCT*, Date*> DateMap;
|
typedef std::map<SQL_DATE_STRUCT*, Date*> DateMap;
|
||||||
typedef std::map<SQL_TIME_STRUCT*, Time*> TimeMap;
|
typedef std::map<SQL_TIME_STRUCT*, Time*> TimeMap;
|
||||||
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
|
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
|
||||||
@ -998,6 +1002,7 @@ private:
|
|||||||
TimestampMap _timestamps;
|
TimestampMap _timestamps;
|
||||||
StringMap _strings;
|
StringMap _strings;
|
||||||
UTF16StringMap _utf16Strings;
|
UTF16StringMap _utf16Strings;
|
||||||
|
UUIDMap _uuids;
|
||||||
|
|
||||||
DateVecVec _dateVecVec;
|
DateVecVec _dateVecVec;
|
||||||
TimeVecVec _timeVecVec;
|
TimeVecVec _timeVecVec;
|
||||||
|
@ -305,6 +305,9 @@ public:
|
|||||||
bool extract(std::size_t pos, std::list<Poco::DateTime>& val);
|
bool extract(std::size_t pos, std::list<Poco::DateTime>& val);
|
||||||
/// Extracts a DateTime list.
|
/// Extracts a DateTime list.
|
||||||
|
|
||||||
|
bool extract(std::size_t pos, Poco::UUID& val);
|
||||||
|
/// Extracts a UUID.
|
||||||
|
|
||||||
bool extract(std::size_t pos, Poco::Any& val);
|
bool extract(std::size_t pos, Poco::Any& val);
|
||||||
/// Extracts an Any.
|
/// Extracts an Any.
|
||||||
|
|
||||||
@ -567,6 +570,9 @@ private:
|
|||||||
case MetaColumn::FDT_TIMESTAMP:
|
case MetaColumn::FDT_TIMESTAMP:
|
||||||
{ return extAny<T, Poco::DateTime>(pos, val); }
|
{ return extAny<T, Poco::DateTime>(pos, val); }
|
||||||
|
|
||||||
|
case MetaColumn::FDT_UUID:
|
||||||
|
{ return extAny<T, Poco::UUID>(pos, val); }
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw DataFormatException("Unsupported data type.");
|
throw DataFormatException("Unsupported data type.");
|
||||||
}
|
}
|
||||||
|
@ -353,6 +353,9 @@ public:
|
|||||||
void prepare(std::size_t pos, const std::list<Poco::DateTime>& val);
|
void prepare(std::size_t pos, const std::list<Poco::DateTime>& val);
|
||||||
/// Prepares a DateTime list.
|
/// Prepares a DateTime list.
|
||||||
|
|
||||||
|
void prepare(std::size_t pos, const Poco::UUID& val);
|
||||||
|
/// Prepares a UUID.
|
||||||
|
|
||||||
void prepare(std::size_t pos, const Poco::Any& val);
|
void prepare(std::size_t pos, const Poco::Any& val);
|
||||||
/// Prepares an Any.
|
/// Prepares an Any.
|
||||||
|
|
||||||
@ -548,6 +551,12 @@ private:
|
|||||||
else
|
else
|
||||||
return prepareFixedSize<DateTime>(pos, SQL_C_TYPE_TIMESTAMP);
|
return prepareFixedSize<DateTime>(pos, SQL_C_TYPE_TIMESTAMP);
|
||||||
|
|
||||||
|
case MetaColumn::FDT_UUID:
|
||||||
|
if (pVal)
|
||||||
|
return prepareFixedSize<DateTime>(pos, SQL_C_BINARY, 16);
|
||||||
|
else
|
||||||
|
return prepareFixedSize<DateTime>(pos, SQL_C_BINARY);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw DataFormatException("Unsupported data type.");
|
throw DataFormatException("Unsupported data type.");
|
||||||
}
|
}
|
||||||
@ -1173,6 +1182,12 @@ inline void Preparator::prepare(std::size_t pos, const std::list<Poco::DateTime>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Preparator::prepare(std::size_t pos, const Poco::UUID&)
|
||||||
|
{
|
||||||
|
prepareCharArray<char, DT_CHAR_ARRAY>(pos, SQL_C_BINARY, 16, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void Preparator::prepare(std::size_t pos, const Poco::Any& val)
|
inline void Preparator::prepare(std::size_t pos, const Poco::Any& val)
|
||||||
{
|
{
|
||||||
prepareImpl<std::vector<Poco::Any> >(pos);
|
prepareImpl<std::vector<Poco::Any> >(pos);
|
||||||
|
@ -80,6 +80,10 @@ void Binder::freeMemory()
|
|||||||
UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end();
|
UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end();
|
||||||
for (; itUTF16Chr != endUTF16Chr; ++itUTF16Chr) std::free(*itUTF16Chr);
|
for (; itUTF16Chr != endUTF16Chr; ++itUTF16Chr) std::free(*itUTF16Chr);
|
||||||
|
|
||||||
|
UUIDMap::iterator itUUID = _uuids.begin();
|
||||||
|
UUIDMap::iterator itUUIDEnd = _uuids.end();
|
||||||
|
for(; itUUID != itUUIDEnd; ++itUUID) std::free(itUUID->first);
|
||||||
|
|
||||||
BoolPtrVec::iterator itBool = _boolPtrs.begin();
|
BoolPtrVec::iterator itBool = _boolPtrs.begin();
|
||||||
BoolPtrVec::iterator endBool = _boolPtrs.end();
|
BoolPtrVec::iterator endBool = _boolPtrs.end();
|
||||||
for (; itBool != endBool; ++itBool) delete [] *itBool;
|
for (; itBool != endBool; ++itBool) delete [] *itBool;
|
||||||
@ -129,15 +133,15 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
|
|||||||
|
|
||||||
_lengthIndicator.push_back(pLenIn);
|
_lengthIndicator.push_back(pLenIn);
|
||||||
|
|
||||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||||
(SQLUSMALLINT) pos + 1,
|
(SQLUSMALLINT) pos + 1,
|
||||||
toODBCDirection(dir),
|
toODBCDirection(dir),
|
||||||
SQL_C_CHAR,
|
SQL_C_CHAR,
|
||||||
Connector::stringBoundToLongVarChar() ? SQL_LONGVARCHAR : SQL_VARCHAR,
|
Connector::stringBoundToLongVarChar() ? SQL_LONGVARCHAR : SQL_VARCHAR,
|
||||||
(SQLUINTEGER) colSize,
|
(SQLUINTEGER) colSize,
|
||||||
0,
|
0,
|
||||||
pVal,
|
pVal,
|
||||||
(SQLINTEGER) size,
|
(SQLINTEGER) size,
|
||||||
_lengthIndicator.back())))
|
_lengthIndicator.back())))
|
||||||
{
|
{
|
||||||
throw StatementException(_rStmt, "SQLBindParameter(std::string)");
|
throw StatementException(_rStmt, "SQLBindParameter(std::string)");
|
||||||
@ -206,22 +210,22 @@ void Binder::bind(std::size_t pos, const Date& val, Direction dir)
|
|||||||
|
|
||||||
SQL_DATE_STRUCT* pDS = new SQL_DATE_STRUCT;
|
SQL_DATE_STRUCT* pDS = new SQL_DATE_STRUCT;
|
||||||
Utility::dateSync(*pDS, val);
|
Utility::dateSync(*pDS, val);
|
||||||
|
|
||||||
_dates.insert(DateMap::value_type(pDS, const_cast<Date*>(&val)));
|
_dates.insert(DateMap::value_type(pDS, const_cast<Date*>(&val)));
|
||||||
|
|
||||||
SQLINTEGER colSize = 0;
|
SQLINTEGER colSize = 0;
|
||||||
SQLSMALLINT decDigits = 0;
|
SQLSMALLINT decDigits = 0;
|
||||||
getColSizeAndPrecision(pos, SQL_TYPE_DATE, colSize, decDigits);
|
getColSizeAndPrecision(pos, SQL_TYPE_DATE, colSize, decDigits);
|
||||||
|
|
||||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||||
(SQLUSMALLINT) pos + 1,
|
(SQLUSMALLINT) pos + 1,
|
||||||
toODBCDirection(dir),
|
toODBCDirection(dir),
|
||||||
SQL_C_TYPE_DATE,
|
SQL_C_TYPE_DATE,
|
||||||
SQL_TYPE_DATE,
|
SQL_TYPE_DATE,
|
||||||
colSize,
|
colSize,
|
||||||
decDigits,
|
decDigits,
|
||||||
(SQLPOINTER) pDS,
|
(SQLPOINTER) pDS,
|
||||||
0,
|
0,
|
||||||
_lengthIndicator.back())))
|
_lengthIndicator.back())))
|
||||||
{
|
{
|
||||||
throw StatementException(_rStmt, "SQLBindParameter(Date)");
|
throw StatementException(_rStmt, "SQLBindParameter(Date)");
|
||||||
@ -239,22 +243,22 @@ void Binder::bind(std::size_t pos, const Time& val, Direction dir)
|
|||||||
|
|
||||||
SQL_TIME_STRUCT* pTS = new SQL_TIME_STRUCT;
|
SQL_TIME_STRUCT* pTS = new SQL_TIME_STRUCT;
|
||||||
Utility::timeSync(*pTS, val);
|
Utility::timeSync(*pTS, val);
|
||||||
|
|
||||||
_times.insert(TimeMap::value_type(pTS, const_cast<Time*>(&val)));
|
_times.insert(TimeMap::value_type(pTS, const_cast<Time*>(&val)));
|
||||||
|
|
||||||
SQLINTEGER colSize = 0;
|
SQLINTEGER colSize = 0;
|
||||||
SQLSMALLINT decDigits = 0;
|
SQLSMALLINT decDigits = 0;
|
||||||
getColSizeAndPrecision(pos, SQL_TYPE_TIME, colSize, decDigits);
|
getColSizeAndPrecision(pos, SQL_TYPE_TIME, colSize, decDigits);
|
||||||
|
|
||||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||||
(SQLUSMALLINT) pos + 1,
|
(SQLUSMALLINT) pos + 1,
|
||||||
toODBCDirection(dir),
|
toODBCDirection(dir),
|
||||||
SQL_C_TYPE_TIME,
|
SQL_C_TYPE_TIME,
|
||||||
SQL_TYPE_TIME,
|
SQL_TYPE_TIME,
|
||||||
colSize,
|
colSize,
|
||||||
decDigits,
|
decDigits,
|
||||||
(SQLPOINTER) pTS,
|
(SQLPOINTER) pTS,
|
||||||
0,
|
0,
|
||||||
_lengthIndicator.back())))
|
_lengthIndicator.back())))
|
||||||
{
|
{
|
||||||
throw StatementException(_rStmt, "SQLBindParameter(Time)");
|
throw StatementException(_rStmt, "SQLBindParameter(Time)");
|
||||||
@ -279,15 +283,15 @@ void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir)
|
|||||||
SQLSMALLINT decDigits = 0;
|
SQLSMALLINT decDigits = 0;
|
||||||
getColSizeAndPrecision(pos, SQL_TYPE_TIMESTAMP, colSize, decDigits);
|
getColSizeAndPrecision(pos, SQL_TYPE_TIMESTAMP, colSize, decDigits);
|
||||||
|
|
||||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||||
(SQLUSMALLINT) pos + 1,
|
(SQLUSMALLINT) pos + 1,
|
||||||
toODBCDirection(dir),
|
toODBCDirection(dir),
|
||||||
SQL_C_TYPE_TIMESTAMP,
|
SQL_C_TYPE_TIMESTAMP,
|
||||||
SQL_TYPE_TIMESTAMP,
|
SQL_TYPE_TIMESTAMP,
|
||||||
colSize,
|
colSize,
|
||||||
decDigits,
|
decDigits,
|
||||||
(SQLPOINTER) pTS,
|
(SQLPOINTER) pTS,
|
||||||
0,
|
0,
|
||||||
_lengthIndicator.back())))
|
_lengthIndicator.back())))
|
||||||
{
|
{
|
||||||
throw StatementException(_rStmt, "SQLBindParameter(DateTime)");
|
throw StatementException(_rStmt, "SQLBindParameter(DateTime)");
|
||||||
@ -295,6 +299,38 @@ void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
|
||||||
|
{
|
||||||
|
SQLINTEGER size = (SQLINTEGER) 16;
|
||||||
|
SQLLEN* pLenIn = new SQLLEN;
|
||||||
|
*pLenIn = size;
|
||||||
|
|
||||||
|
_lengthIndicator.push_back(pLenIn);
|
||||||
|
|
||||||
|
char* pUUID = new char[16];
|
||||||
|
val.copyTo(pUUID);
|
||||||
|
|
||||||
|
_uuids.insert(UUIDMap::value_type(pUUID, const_cast<UUID*>(&val)));
|
||||||
|
|
||||||
|
SQLINTEGER colSize = 0;
|
||||||
|
SQLSMALLINT decDigits = 0;
|
||||||
|
|
||||||
|
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||||
|
(SQLUSMALLINT) pos + 1,
|
||||||
|
toODBCDirection(dir),
|
||||||
|
SQL_C_BINARY,
|
||||||
|
SQL_GUID,
|
||||||
|
colSize,
|
||||||
|
decDigits,
|
||||||
|
(SQLPOINTER) pUUID,
|
||||||
|
0,
|
||||||
|
_lengthIndicator.back())))
|
||||||
|
{
|
||||||
|
throw StatementException(_rStmt, "SQLBindParameter(UUID)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
|
void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
|
||||||
{
|
{
|
||||||
if (isOutBound(dir) || !isInBound(dir))
|
if (isOutBound(dir) || !isInBound(dir))
|
||||||
@ -311,15 +347,15 @@ void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
|
|||||||
SQLSMALLINT decDigits = 0;
|
SQLSMALLINT decDigits = 0;
|
||||||
getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits);
|
getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits);
|
||||||
|
|
||||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||||
(SQLUSMALLINT) pos + 1,
|
(SQLUSMALLINT) pos + 1,
|
||||||
SQL_PARAM_INPUT,
|
SQL_PARAM_INPUT,
|
||||||
SQL_C_STINYINT,
|
SQL_C_STINYINT,
|
||||||
Utility::sqlDataType(SQL_C_STINYINT),
|
Utility::sqlDataType(SQL_C_STINYINT),
|
||||||
colSize,
|
colSize,
|
||||||
decDigits,
|
decDigits,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
_lengthIndicator.back())))
|
_lengthIndicator.back())))
|
||||||
{
|
{
|
||||||
throw StatementException(_rStmt, "SQLBindParameter()");
|
throw StatementException(_rStmt, "SQLBindParameter()");
|
||||||
@ -334,7 +370,7 @@ std::size_t Binder::parameterSize(SQLPOINTER pAddr) const
|
|||||||
|
|
||||||
it = _outParams.find(pAddr);
|
it = _outParams.find(pAddr);
|
||||||
if (it != _outParams.end()) return it->second;
|
if (it != _outParams.end()) return it->second;
|
||||||
|
|
||||||
throw NotFoundException("Requested data size not found.");
|
throw NotFoundException("Requested data size not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +386,7 @@ SQLSMALLINT Binder::toODBCDirection(Direction dir) const
|
|||||||
bool in = isInBound(dir);
|
bool in = isInBound(dir);
|
||||||
bool out = isOutBound(dir);
|
bool out = isOutBound(dir);
|
||||||
SQLSMALLINT ioType = SQL_PARAM_TYPE_UNKNOWN;
|
SQLSMALLINT ioType = SQL_PARAM_TYPE_UNKNOWN;
|
||||||
if (in && out) ioType = SQL_PARAM_INPUT_OUTPUT;
|
if (in && out) ioType = SQL_PARAM_INPUT_OUTPUT;
|
||||||
else if(in) ioType = SQL_PARAM_INPUT;
|
else if(in) ioType = SQL_PARAM_INPUT;
|
||||||
else if(out) ioType = SQL_PARAM_OUTPUT;
|
else if(out) ioType = SQL_PARAM_OUTPUT;
|
||||||
else throw Poco::IllegalStateException("Binder not bound (must be [in] OR [out]).");
|
else throw Poco::IllegalStateException("Binder not bound (must be [in] OR [out]).");
|
||||||
@ -365,7 +401,7 @@ void Binder::synchronize()
|
|||||||
{
|
{
|
||||||
DateMap::iterator it = _dates.begin();
|
DateMap::iterator it = _dates.begin();
|
||||||
DateMap::iterator end = _dates.end();
|
DateMap::iterator end = _dates.end();
|
||||||
for(; it != end; ++it)
|
for(; it != end; ++it)
|
||||||
Utility::dateSync(*it->second, *it->first);
|
Utility::dateSync(*it->second, *it->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,7 +409,7 @@ void Binder::synchronize()
|
|||||||
{
|
{
|
||||||
TimeMap::iterator it = _times.begin();
|
TimeMap::iterator it = _times.begin();
|
||||||
TimeMap::iterator end = _times.end();
|
TimeMap::iterator end = _times.end();
|
||||||
for(; it != end; ++it)
|
for(; it != end; ++it)
|
||||||
Utility::timeSync(*it->second, *it->first);
|
Utility::timeSync(*it->second, *it->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +417,7 @@ void Binder::synchronize()
|
|||||||
{
|
{
|
||||||
TimestampMap::iterator it = _timestamps.begin();
|
TimestampMap::iterator it = _timestamps.begin();
|
||||||
TimestampMap::iterator end = _timestamps.end();
|
TimestampMap::iterator end = _timestamps.end();
|
||||||
for(; it != end; ++it)
|
for(; it != end; ++it)
|
||||||
Utility::dateTimeSync(*it->second, *it->first);
|
Utility::dateTimeSync(*it->second, *it->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,6 +428,14 @@ void Binder::synchronize()
|
|||||||
for(; it != end; ++it)
|
for(; it != end; ++it)
|
||||||
it->second->assign(it->first, std::strlen(it->first));
|
it->second->assign(it->first, std::strlen(it->first));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_uuids.size())
|
||||||
|
{
|
||||||
|
UUIDMap::iterator it = _uuids.begin();
|
||||||
|
UUIDMap::iterator end = _uuids.end();
|
||||||
|
for(; it != end; ++it)
|
||||||
|
it->second->copyFrom(it->first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -405,6 +449,7 @@ void Binder::reset()
|
|||||||
_times.clear();
|
_times.clear();
|
||||||
_timestamps.clear();
|
_timestamps.clear();
|
||||||
_strings.clear();
|
_strings.clear();
|
||||||
|
_uuids.clear();
|
||||||
_dateVecVec.clear();
|
_dateVecVec.clear();
|
||||||
_timeVecVec.clear();
|
_timeVecVec.clear();
|
||||||
_dateTimeVecVec.clear();
|
_dateTimeVecVec.clear();
|
||||||
@ -415,9 +460,9 @@ void Binder::reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Binder::getColSizeAndPrecision(std::size_t pos,
|
void Binder::getColSizeAndPrecision(std::size_t pos,
|
||||||
SQLSMALLINT cDataType,
|
SQLSMALLINT cDataType,
|
||||||
SQLINTEGER& colSize,
|
SQLINTEGER& colSize,
|
||||||
SQLSMALLINT& decDigits,
|
SQLSMALLINT& decDigits,
|
||||||
std::size_t actualSize)
|
std::size_t actualSize)
|
||||||
{
|
{
|
||||||
@ -448,9 +493,9 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
|
|||||||
colSize = (SQLINTEGER) p.columnSize();
|
colSize = (SQLINTEGER) p.columnSize();
|
||||||
decDigits = (SQLSMALLINT) p.decimalDigits();
|
decDigits = (SQLSMALLINT) p.decimalDigits();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (StatementException&)
|
catch (StatementException&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -459,9 +504,9 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
|
|||||||
colSize = (SQLINTEGER) c.length();
|
colSize = (SQLINTEGER) c.length();
|
||||||
decDigits = (SQLSMALLINT) c.precision();
|
decDigits = (SQLSMALLINT) c.precision();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (StatementException&)
|
catch (StatementException&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// last check, just in case
|
// last check, just in case
|
||||||
@ -505,7 +550,7 @@ void Binder::getColumnOrParameterSize(std::size_t pos, SQLINTEGER& size)
|
|||||||
if (!Utility::isError(SQLGetStmtAttr(_rStmt, SQL_ATTR_IMP_PARAM_DESC, &hIPD, SQL_IS_POINTER, 0)))
|
if (!Utility::isError(SQLGetStmtAttr(_rStmt, SQL_ATTR_IMP_PARAM_DESC, &hIPD, SQL_IS_POINTER, 0)))
|
||||||
{
|
{
|
||||||
SQLUINTEGER sz = 0;
|
SQLUINTEGER sz = 0;
|
||||||
if (!Utility::isError(SQLGetDescField(hIPD, (SQLSMALLINT) pos + 1, SQL_DESC_LENGTH, &sz, SQL_IS_UINTEGER, 0)) &&
|
if (!Utility::isError(SQLGetDescField(hIPD, (SQLSMALLINT) pos + 1, SQL_DESC_LENGTH, &sz, SQL_IS_UINTEGER, 0)) &&
|
||||||
sz > 0)
|
sz > 0)
|
||||||
{
|
{
|
||||||
size = sz;
|
size = sz;
|
||||||
@ -529,7 +574,7 @@ void Binder::setParamSetSize(std::size_t length)
|
|||||||
{
|
{
|
||||||
if (0 == _paramSetSize)
|
if (0 == _paramSetSize)
|
||||||
{
|
{
|
||||||
if (Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, SQL_IS_UINTEGER)) ||
|
if (Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, SQL_IS_UINTEGER)) ||
|
||||||
Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) length, SQL_IS_UINTEGER)))
|
Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) length, SQL_IS_UINTEGER)))
|
||||||
throw StatementException(_rStmt, "SQLSetStmtAttr()");
|
throw StatementException(_rStmt, "SQLSetStmtAttr()");
|
||||||
|
|
||||||
|
@ -224,6 +224,20 @@ bool Extractor::extractBoundImplContainer<std::list<Poco::DateTime> >(std::size_
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool Extractor::extractBoundImpl<Poco::UUID>(std::size_t pos, Poco::UUID& val)
|
||||||
|
{
|
||||||
|
if (isNull(pos)) return false;
|
||||||
|
|
||||||
|
std::size_t dataSize = _pPreparator->actualDataSize(pos);
|
||||||
|
checkDataSize(dataSize);
|
||||||
|
char* pBuffer = *AnyCast<char*>(&_pPreparator->at(pos));
|
||||||
|
val.copyFrom(pBuffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
bool Extractor::extractBoundImplContainer<std::vector<bool> >(std::size_t pos,
|
bool Extractor::extractBoundImplContainer<std::vector<bool> >(std::size_t pos,
|
||||||
std::vector<bool>& val)
|
std::vector<bool>& val)
|
||||||
@ -504,6 +518,33 @@ bool Extractor::extractManualImpl<Poco::DateTime>(std::size_t pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool Extractor::extractManualImpl<Poco::UUID>(std::size_t pos,
|
||||||
|
Poco::UUID& val,
|
||||||
|
SQLSMALLINT cType)
|
||||||
|
{
|
||||||
|
char buffer[16];
|
||||||
|
resizeLengths(pos);
|
||||||
|
|
||||||
|
SQLRETURN rc = SQLGetData(_rStmt,
|
||||||
|
(SQLUSMALLINT) pos + 1,
|
||||||
|
cType, //C data type
|
||||||
|
&buffer, //returned value
|
||||||
|
sizeof(buffer), //buffer length
|
||||||
|
&_lengths[pos]); //length indicator
|
||||||
|
|
||||||
|
if (Utility::isError(rc))
|
||||||
|
throw StatementException(_rStmt, "SQLGetData()");
|
||||||
|
|
||||||
|
if (isNullLengthIndicator(_lengths[pos]))
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
val.copyFrom(buffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, Poco::Int32& val)
|
bool Extractor::extract(std::size_t pos, Poco::Int32& val)
|
||||||
{
|
{
|
||||||
if (Preparator::DE_MANUAL == _dataExtraction)
|
if (Preparator::DE_MANUAL == _dataExtraction)
|
||||||
@ -911,6 +952,15 @@ bool Extractor::extract(std::size_t pos, std::list<Poco::DateTime>& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Extractor::extract(std::size_t pos, Poco::UUID& val)
|
||||||
|
{
|
||||||
|
if (Preparator::DE_MANUAL == _dataExtraction)
|
||||||
|
return extractManualImpl(pos, val, SQL_C_BINARY);
|
||||||
|
else
|
||||||
|
return extractBoundImpl(pos, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, Poco::Int8& val)
|
bool Extractor::extract(std::size_t pos, Poco::Int8& val)
|
||||||
{
|
{
|
||||||
if (Preparator::DE_MANUAL == _dataExtraction)
|
if (Preparator::DE_MANUAL == _dataExtraction)
|
||||||
|
@ -102,9 +102,6 @@ void ODBCMetaColumn::init()
|
|||||||
case SQL_CHAR:
|
case SQL_CHAR:
|
||||||
case SQL_VARCHAR:
|
case SQL_VARCHAR:
|
||||||
case SQL_LONGVARCHAR:
|
case SQL_LONGVARCHAR:
|
||||||
#ifdef SQL_GUID
|
|
||||||
case SQL_GUID:
|
|
||||||
#endif
|
|
||||||
setType(MetaColumn::FDT_STRING); break;
|
setType(MetaColumn::FDT_STRING); break;
|
||||||
|
|
||||||
case SQL_WCHAR:
|
case SQL_WCHAR:
|
||||||
@ -168,6 +165,9 @@ void ODBCMetaColumn::init()
|
|||||||
case SQL_TYPE_TIMESTAMP:
|
case SQL_TYPE_TIMESTAMP:
|
||||||
setType(MetaColumn::FDT_TIMESTAMP); break;
|
setType(MetaColumn::FDT_TIMESTAMP); break;
|
||||||
|
|
||||||
|
case SQL_GUID:
|
||||||
|
setType(MetaColumn::FDT_UUID); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw DataFormatException("Unsupported data type.");
|
throw DataFormatException("Unsupported data type.");
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,9 @@ endif
|
|||||||
ifeq (0, $(shell test -e /opt/postgresql/lib$(LIB64SUFFIX); echo $$?))
|
ifeq (0, $(shell test -e /opt/postgresql/lib$(LIB64SUFFIX); echo $$?))
|
||||||
SYSLIBS += -L/opt/postgresql/lib$(LIB64SUFFIX)
|
SYSLIBS += -L/opt/postgresql/lib$(LIB64SUFFIX)
|
||||||
endif
|
endif
|
||||||
|
ifeq (0, $(shell test -e /usr/local/opt/libpq/lib; echo $$?))
|
||||||
|
SYSLIBS += -L/usr/local/opt/libpq/lib$(LIB64SUFFIX)
|
||||||
|
endif
|
||||||
SYSLIBS += -lpq
|
SYSLIBS += -lpq
|
||||||
|
|
||||||
objects = Extractor Binder SessionImpl Connector \
|
objects = Extractor Binder SessionImpl Connector \
|
||||||
|
@ -108,6 +108,9 @@ public:
|
|||||||
virtual void bind(std::size_t pos, const Time& val, Direction dir = PD_IN);
|
virtual void bind(std::size_t pos, const Time& val, Direction dir = PD_IN);
|
||||||
/// Binds a Time.
|
/// Binds a Time.
|
||||||
|
|
||||||
|
virtual void bind(std::size_t pos, const UUID& val, Direction dir = PD_IN);
|
||||||
|
/// Binds a UUID.
|
||||||
|
|
||||||
virtual void bind(std::size_t pos, const NullData& val, Direction dir = PD_IN);
|
virtual void bind(std::size_t pos, const NullData& val, Direction dir = PD_IN);
|
||||||
/// Binds a null.
|
/// Binds a null.
|
||||||
|
|
||||||
|
@ -109,6 +109,9 @@ public:
|
|||||||
virtual bool extract(std::size_t pos, Time& val);
|
virtual bool extract(std::size_t pos, Time& val);
|
||||||
/// Extracts a Time. Returns false if null was received.
|
/// Extracts a Time. Returns false if null was received.
|
||||||
|
|
||||||
|
virtual bool extract(std::size_t pos, UUID& val);
|
||||||
|
/// Extracts a UUID. Returns false if null was received.
|
||||||
|
|
||||||
virtual bool extract(std::size_t pos, Any& val);
|
virtual bool extract(std::size_t pos, Any& val);
|
||||||
/// Extracts an Any. Returns false if null was received.
|
/// Extracts an Any. Returns false if null was received.
|
||||||
|
|
||||||
|
@ -271,6 +271,7 @@ inline const void* InputParameter::pInternalRepresentation() const
|
|||||||
case Poco::Data::MetaColumn::FDT_DATE:
|
case Poco::Data::MetaColumn::FDT_DATE:
|
||||||
case Poco::Data::MetaColumn::FDT_TIME:
|
case Poco::Data::MetaColumn::FDT_TIME:
|
||||||
case Poco::Data::MetaColumn::FDT_TIMESTAMP:
|
case Poco::Data::MetaColumn::FDT_TIMESTAMP:
|
||||||
|
case Poco::Data::MetaColumn::FDT_UUID:
|
||||||
return _stringVersionRepresentation.c_str();
|
return _stringVersionRepresentation.c_str();
|
||||||
|
|
||||||
case Poco::Data::MetaColumn::FDT_BLOB:
|
case Poco::Data::MetaColumn::FDT_BLOB:
|
||||||
|
@ -176,6 +176,13 @@ void Binder::bind(std::size_t pos, const Time& val, Direction dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
|
||||||
|
{
|
||||||
|
poco_assert(dir == PD_IN);
|
||||||
|
realBind(pos, Poco::Data::MetaColumn::FDT_UUID, &val, sizeof(UUID));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Binder::bind(std::size_t pos, const NullData&, Direction dir)
|
void Binder::bind(std::size_t pos, const NullData&, Direction dir)
|
||||||
{
|
{
|
||||||
poco_assert(dir == PD_IN);
|
poco_assert(dir == PD_IN);
|
||||||
@ -293,6 +300,14 @@ void Binder::updateBindVectorToCurrentValues()
|
|||||||
const Poco::Data::CLOB& clob = * static_cast<const Poco::Data::CLOB*>(itr->pData());
|
const Poco::Data::CLOB& clob = * static_cast<const Poco::Data::CLOB*>(itr->pData());
|
||||||
itr->setNonStringVersionRepresentation(static_cast<const void*> (clob.rawContent()), clob.size());
|
itr->setNonStringVersionRepresentation(static_cast<const void*> (clob.rawContent()), clob.size());
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Poco::Data::MetaColumn::FDT_UUID:
|
||||||
|
{
|
||||||
|
const Poco::UUID& uuid = * static_cast<const Poco::UUID*>(itr->pData());
|
||||||
|
itr->setStringVersionRepresentation(uuid.toString());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Poco::Data::MetaColumn::FDT_UNKNOWN:
|
case Poco::Data::MetaColumn::FDT_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
|
@ -432,6 +432,19 @@ bool Extractor::extract(std::size_t pos, Time& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Extractor::extract(std::size_t pos, UUID& val)
|
||||||
|
{
|
||||||
|
OutputParameter outputParameter = extractPreamble(pos);
|
||||||
|
|
||||||
|
if (isColumnNull(outputParameter))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val.tryParse(outputParameter.pData());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, Any& val)
|
bool Extractor::extract(std::size_t pos, Any& val)
|
||||||
{
|
{
|
||||||
return extractStringImpl(pos, val);
|
return extractStringImpl(pos, val);
|
||||||
@ -583,6 +596,14 @@ bool Extractor::extractToDynamic(std::size_t pos, Dynamic::Var& val)
|
|||||||
val = dt;
|
val = dt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case UUIDOID:
|
||||||
|
{
|
||||||
|
UUID uuid;
|
||||||
|
success = extract(pos, uuid);
|
||||||
|
if (success)
|
||||||
|
val = uuid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
@ -94,6 +94,11 @@ Poco::Data::MetaColumn::ColumnDataType oidToColumnDataType(const Oid anOID)
|
|||||||
cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP;
|
cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
//uuid
|
||||||
|
case UUIDOID:
|
||||||
|
cdt = Poco::Data::MetaColumn::FDT_BLOB;
|
||||||
|
break;
|
||||||
|
|
||||||
// everything else is a string
|
// everything else is a string
|
||||||
default:
|
default:
|
||||||
cdt = Poco::Data::MetaColumn::FDT_STRING;
|
cdt = Poco::Data::MetaColumn::FDT_STRING;
|
||||||
|
@ -37,6 +37,9 @@ endif
|
|||||||
ifeq (0, $(shell test -e /opt/postgresql/lib$(LIB64SUFFIX); echo $$?))
|
ifeq (0, $(shell test -e /opt/postgresql/lib$(LIB64SUFFIX); echo $$?))
|
||||||
SYSLIBS += -L/opt/postgresql/lib$(LIB64SUFFIX)
|
SYSLIBS += -L/opt/postgresql/lib$(LIB64SUFFIX)
|
||||||
endif
|
endif
|
||||||
|
ifeq (0, $(shell test -e /usr/local/opt/libpq/lib; echo $$?))
|
||||||
|
SYSLIBS += -L/usr/local/opt/libpq/lib$(LIB64SUFFIX)
|
||||||
|
endif
|
||||||
|
|
||||||
# Note: linking order is important, do not change it.
|
# Note: linking order is important, do not change it.
|
||||||
SYSLIBS += -lpq -lz -lpthread -ldl
|
SYSLIBS += -lpq -lz -lpthread -ldl
|
||||||
|
@ -690,6 +690,14 @@ void PostgreSQLTest::testDouble()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PostgreSQLTest::testUUID()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
recreateUUIDsTable();
|
||||||
|
_pExecutor->uuids();
|
||||||
|
}
|
||||||
|
|
||||||
void PostgreSQLTest::testTuple()
|
void PostgreSQLTest::testTuple()
|
||||||
{
|
{
|
||||||
if (!_pSession) fail ("Test not available.");
|
if (!_pSession) fail ("Test not available.");
|
||||||
@ -986,6 +994,15 @@ void PostgreSQLTest::recreateFloatsTable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PostgreSQLTest::recreateUUIDsTable()
|
||||||
|
{
|
||||||
|
dropTable("Strings");
|
||||||
|
try { *_pSession << "CREATE TABLE Strings (str UUID)", now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateUUIDsTable()"); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateUUIDsTable()"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PostgreSQLTest::recreateTuplesTable()
|
void PostgreSQLTest::recreateTuplesTable()
|
||||||
{
|
{
|
||||||
dropTable("Tuples");
|
dropTable("Tuples");
|
||||||
@ -1110,6 +1127,7 @@ CppUnit::Test* PostgreSQLTest::suite()
|
|||||||
CppUnit_addTest(pSuite, PostgreSQLTest, testUnsignedInts);
|
CppUnit_addTest(pSuite, PostgreSQLTest, testUnsignedInts);
|
||||||
CppUnit_addTest(pSuite, PostgreSQLTest, testFloat);
|
CppUnit_addTest(pSuite, PostgreSQLTest, testFloat);
|
||||||
CppUnit_addTest(pSuite, PostgreSQLTest, testDouble);
|
CppUnit_addTest(pSuite, PostgreSQLTest, testDouble);
|
||||||
|
CppUnit_addTest(pSuite, PostgreSQLTest, testUUID);
|
||||||
CppUnit_addTest(pSuite, PostgreSQLTest, testTuple);
|
CppUnit_addTest(pSuite, PostgreSQLTest, testTuple);
|
||||||
CppUnit_addTest(pSuite, PostgreSQLTest, testTupleVector);
|
CppUnit_addTest(pSuite, PostgreSQLTest, testTupleVector);
|
||||||
CppUnit_addTest(pSuite, PostgreSQLTest, testInternalExtraction);
|
CppUnit_addTest(pSuite, PostgreSQLTest, testInternalExtraction);
|
||||||
|
@ -82,6 +82,7 @@ public:
|
|||||||
void testUnsignedInts();
|
void testUnsignedInts();
|
||||||
void testFloat();
|
void testFloat();
|
||||||
void testDouble();
|
void testDouble();
|
||||||
|
void testUUID();
|
||||||
|
|
||||||
void testTuple();
|
void testTuple();
|
||||||
void testTupleVector();
|
void testTupleVector();
|
||||||
@ -118,6 +119,7 @@ private:
|
|||||||
void recreateIntsTable();
|
void recreateIntsTable();
|
||||||
void recreateUnsignedIntsTable();
|
void recreateUnsignedIntsTable();
|
||||||
void recreateFloatsTable();
|
void recreateFloatsTable();
|
||||||
|
void recreateUUIDsTable();
|
||||||
void recreateTuplesTable();
|
void recreateTuplesTable();
|
||||||
void recreateVectorsTable();
|
void recreateVectorsTable();
|
||||||
void recreateNullableIntTable();
|
void recreateNullableIntTable();
|
||||||
|
@ -712,6 +712,29 @@ void SQLExecutor::floats()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::uuids()
|
||||||
|
{
|
||||||
|
std::string funct = "uuids()";
|
||||||
|
Poco::UUID data("264a1c6f-7af5-43a5-a593-377aff3d2d7d");
|
||||||
|
Poco::UUID ret;
|
||||||
|
|
||||||
|
try { *_pSession << "INSERT INTO Strings VALUES ($1)", use(data), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
assertTrue (count == 1);
|
||||||
|
|
||||||
|
try { *_pSession << "SELECT str FROM Strings", into(ret), now; }
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
|
||||||
|
assertTrue (ret == data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SQLExecutor::doubles()
|
void SQLExecutor::doubles()
|
||||||
{
|
{
|
||||||
std::string funct = "floats()";
|
std::string funct = "floats()";
|
||||||
@ -1611,7 +1634,7 @@ void SQLExecutor::blobStmt()
|
|||||||
std::string lastName("lastname");
|
std::string lastName("lastname");
|
||||||
std::string firstName("firstname");
|
std::string firstName("firstname");
|
||||||
std::string address("Address");
|
std::string address("Address");
|
||||||
unsigned char BLOBData[ 10 ] = { 0,1,2,3,4,5,6,7,14,15 };
|
unsigned char BLOBData[ 10 ] = { 0,1,2,3,4,5,6,7,14,15 };
|
||||||
Poco::Data::BLOB blob(BLOBData, 10);
|
Poco::Data::BLOB blob(BLOBData, 10);
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -25,7 +25,7 @@ public:
|
|||||||
PB_IMMEDIATE,
|
PB_IMMEDIATE,
|
||||||
PB_AT_EXEC
|
PB_AT_EXEC
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DataExtraction
|
enum DataExtraction
|
||||||
{
|
{
|
||||||
DE_MANUAL,
|
DE_MANUAL,
|
||||||
@ -37,7 +37,7 @@ public:
|
|||||||
|
|
||||||
void oidPostgreSQLTest(std::string host, std::string user, std::string pwd, std::string db, std::string port, const char* tableCreateString, const Oid anOIDArray[]);
|
void oidPostgreSQLTest(std::string host, std::string user, std::string pwd, std::string db, std::string port, const char* tableCreateString, const Oid anOIDArray[]);
|
||||||
/// This function verifies the PostgreSQL Column type OIDs are consistent between releases
|
/// This function verifies the PostgreSQL Column type OIDs are consistent between releases
|
||||||
|
|
||||||
void barebonePostgreSQLTest(std::string host, std::string user, std::string pwd, std::string db, std::string port, const char* tableCreateString);
|
void barebonePostgreSQLTest(std::string host, std::string user, std::string pwd, std::string db, std::string port, const char* tableCreateString);
|
||||||
/// This function uses "bare bone" API calls (i.e. calls are not
|
/// This function uses "bare bone" API calls (i.e. calls are not
|
||||||
/// "wrapped" in PocoSQL framework structures).
|
/// "wrapped" in PocoSQL framework structures).
|
||||||
@ -89,6 +89,7 @@ public:
|
|||||||
void unsignedInts();
|
void unsignedInts();
|
||||||
void floats();
|
void floats();
|
||||||
void doubles();
|
void doubles();
|
||||||
|
void uuids();
|
||||||
void tuples();
|
void tuples();
|
||||||
void tupleVector();
|
void tupleVector();
|
||||||
|
|
||||||
|
@ -106,6 +106,9 @@ public:
|
|||||||
void bind(std::size_t pos, const DateTime& val, Direction dir);
|
void bind(std::size_t pos, const DateTime& val, Direction dir);
|
||||||
/// Binds a DateTime.
|
/// Binds a DateTime.
|
||||||
|
|
||||||
|
void bind(std::size_t pos, const UUID& val, Direction dir);
|
||||||
|
/// Binds a UUID.
|
||||||
|
|
||||||
void bind(std::size_t pos, const NullData& val, Direction dir);
|
void bind(std::size_t pos, const NullData& val, Direction dir);
|
||||||
/// Binds a null.
|
/// Binds a null.
|
||||||
|
|
||||||
|
@ -116,6 +116,9 @@ public:
|
|||||||
bool extract(std::size_t pos, Poco::DateTime& val);
|
bool extract(std::size_t pos, Poco::DateTime& val);
|
||||||
/// Extracts a DateTime.
|
/// Extracts a DateTime.
|
||||||
|
|
||||||
|
bool extract(std::size_t pos, Poco::UUID& val);
|
||||||
|
/// Extracts a Time.
|
||||||
|
|
||||||
bool extract(std::size_t pos, Poco::Any& val);
|
bool extract(std::size_t pos, Poco::Any& val);
|
||||||
/// Extracts an Any.
|
/// Extracts an Any.
|
||||||
|
|
||||||
@ -264,6 +267,13 @@ private:
|
|||||||
val = dt;
|
val = dt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MetaColumn::FDT_UUID:
|
||||||
|
{
|
||||||
|
UUID uuid;
|
||||||
|
ret = extract(pos, uuid);
|
||||||
|
val = uuid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw Poco::Data::UnknownTypeException("Unknown type during extraction");
|
throw Poco::Data::UnknownTypeException("Unknown type during extraction");
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,13 @@ void Binder::bind(std::size_t pos, const DateTime& val, Direction dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
|
||||||
|
{
|
||||||
|
std::string str(val.toString());
|
||||||
|
bind(pos, str, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Binder::bind(std::size_t pos, const NullData&, Direction)
|
void Binder::bind(std::size_t pos, const NullData&, Direction)
|
||||||
{
|
{
|
||||||
sqlite3_bind_null(_pStmt, static_cast<int>(pos));
|
sqlite3_bind_null(_pStmt, static_cast<int>(pos));
|
||||||
|
@ -208,6 +208,16 @@ bool Extractor::extract(std::size_t pos, DateTime& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Extractor::extract(std::size_t pos, UUID& val)
|
||||||
|
{
|
||||||
|
if (isNull(pos)) return false;
|
||||||
|
std::string str;
|
||||||
|
extract(pos, str);
|
||||||
|
val.parse(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, Poco::Any& val)
|
bool Extractor::extract(std::size_t pos, Poco::Any& val)
|
||||||
{
|
{
|
||||||
return extractImpl(pos, val);
|
return extractImpl(pos, val);
|
||||||
|
@ -134,6 +134,8 @@ Utility::Utility()
|
|||||||
_types.insert(TypeMap::value_type("TIME", MetaColumn::FDT_TIME));
|
_types.insert(TypeMap::value_type("TIME", MetaColumn::FDT_TIME));
|
||||||
_types.insert(TypeMap::value_type("DATETIME", MetaColumn::FDT_TIMESTAMP));
|
_types.insert(TypeMap::value_type("DATETIME", MetaColumn::FDT_TIMESTAMP));
|
||||||
_types.insert(TypeMap::value_type("TIMESTAMP", MetaColumn::FDT_TIMESTAMP));
|
_types.insert(TypeMap::value_type("TIMESTAMP", MetaColumn::FDT_TIMESTAMP));
|
||||||
|
_types.insert(TypeMap::value_type("UUID", MetaColumn::FDT_UUID));
|
||||||
|
_types.insert(TypeMap::value_type("GUID", MetaColumn::FDT_UUID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "Poco/Data/SQLite/SQLiteException.h"
|
#include "Poco/Data/SQLite/SQLiteException.h"
|
||||||
#include "Poco/Tuple.h"
|
#include "Poco/Tuple.h"
|
||||||
#include "Poco/Any.h"
|
#include "Poco/Any.h"
|
||||||
|
#include "Poco/UUIDGenerator.h"
|
||||||
#include "Poco/SharedPtr.h"
|
#include "Poco/SharedPtr.h"
|
||||||
#include "Poco/DynamicAny.h"
|
#include "Poco/DynamicAny.h"
|
||||||
#include "Poco/DateTime.h"
|
#include "Poco/DateTime.h"
|
||||||
@ -1916,6 +1917,21 @@ void SQLiteTest::testDateTime()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLiteTest::testUUID()
|
||||||
|
{
|
||||||
|
Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db");
|
||||||
|
tmp << "DROP TABLE IF EXISTS Ids", now;
|
||||||
|
tmp << "CREATE TABLE Ids (id0 UUID)", now;
|
||||||
|
|
||||||
|
Poco::UUID uuid = Poco::UUIDGenerator::defaultGenerator().createRandom();
|
||||||
|
tmp << "INSERT INTO Ids VALUES (?)", use(uuid), now;
|
||||||
|
|
||||||
|
Poco::UUID ruuid;
|
||||||
|
tmp << "SELECT * FROM Ids", into(ruuid), now;
|
||||||
|
assertTrue (ruuid == uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SQLiteTest::testInternalExtraction()
|
void SQLiteTest::testInternalExtraction()
|
||||||
{
|
{
|
||||||
Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db");
|
Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db");
|
||||||
@ -3453,6 +3469,7 @@ CppUnit::Test* SQLiteTest::suite()
|
|||||||
CppUnit_addTest(pSuite, SQLiteTest, testTuple1);
|
CppUnit_addTest(pSuite, SQLiteTest, testTuple1);
|
||||||
CppUnit_addTest(pSuite, SQLiteTest, testTupleVector1);
|
CppUnit_addTest(pSuite, SQLiteTest, testTupleVector1);
|
||||||
CppUnit_addTest(pSuite, SQLiteTest, testDateTime);
|
CppUnit_addTest(pSuite, SQLiteTest, testDateTime);
|
||||||
|
CppUnit_addTest(pSuite, SQLiteTest, testUUID);
|
||||||
CppUnit_addTest(pSuite, SQLiteTest, testInternalExtraction);
|
CppUnit_addTest(pSuite, SQLiteTest, testInternalExtraction);
|
||||||
CppUnit_addTest(pSuite, SQLiteTest, testPrimaryKeyConstraint);
|
CppUnit_addTest(pSuite, SQLiteTest, testPrimaryKeyConstraint);
|
||||||
CppUnit_addTest(pSuite, SQLiteTest, testNullable);
|
CppUnit_addTest(pSuite, SQLiteTest, testNullable);
|
||||||
|
@ -100,6 +100,8 @@ public:
|
|||||||
|
|
||||||
void testDateTime();
|
void testDateTime();
|
||||||
|
|
||||||
|
void testUUID();
|
||||||
|
|
||||||
void testInternalExtraction();
|
void testInternalExtraction();
|
||||||
void testPrimaryKeyConstraint();
|
void testPrimaryKeyConstraint();
|
||||||
void testNullable();
|
void testNullable();
|
||||||
|
@ -16,54 +16,54 @@ The following complete example shows how to use POCO Data:
|
|||||||
#include "Poco/Data/SQLite/Connector.h"
|
#include "Poco/Data/SQLite/Connector.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace Poco::Data::Keywords;
|
using namespace Poco::Data::Keywords;
|
||||||
using Poco::Data::Session;
|
using Poco::Data::Session;
|
||||||
using Poco::Data::Statement;
|
using Poco::Data::Statement;
|
||||||
|
|
||||||
struct Person
|
struct Person
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string address;
|
std::string address;
|
||||||
int age;
|
int age;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
// register SQLite connector
|
// register SQLite connector
|
||||||
Poco::Data::SQLite::Connector::registerConnector();
|
Poco::Data::SQLite::Connector::registerConnector();
|
||||||
|
|
||||||
// create a session
|
// create a session
|
||||||
Session session("SQLite", "sample.db");
|
Session session("SQLite", "sample.db");
|
||||||
|
|
||||||
// drop sample table, if it exists
|
// drop sample table, if it exists
|
||||||
session << "DROP TABLE IF EXISTS Person", now;
|
session << "DROP TABLE IF EXISTS Person", now;
|
||||||
|
|
||||||
// (re)create table
|
// (re)create table
|
||||||
session << "CREATE TABLE Person (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;
|
session << "CREATE TABLE Person (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;
|
||||||
|
|
||||||
// insert some rows
|
// insert some rows
|
||||||
Person person =
|
Person person =
|
||||||
{
|
{
|
||||||
"Bart Simpson",
|
"Bart Simpson",
|
||||||
"Springfield",
|
"Springfield",
|
||||||
12
|
12
|
||||||
};
|
};
|
||||||
|
|
||||||
Statement insert(session);
|
Statement insert(session);
|
||||||
insert << "INSERT INTO Person VALUES(?, ?, ?)",
|
insert << "INSERT INTO Person VALUES(?, ?, ?)",
|
||||||
use(person.name),
|
use(person.name),
|
||||||
use(person.address),
|
use(person.address),
|
||||||
use(person.age);
|
use(person.age);
|
||||||
|
|
||||||
insert.execute();
|
insert.execute();
|
||||||
|
|
||||||
person.name = "Lisa Simpson";
|
person.name = "Lisa Simpson";
|
||||||
person.address = "Springfield";
|
person.address = "Springfield";
|
||||||
person.age = 10;
|
person.age = 10;
|
||||||
|
|
||||||
insert.execute();
|
insert.execute();
|
||||||
|
|
||||||
// a simple query
|
// a simple query
|
||||||
Statement select(session);
|
Statement select(session);
|
||||||
select << "SELECT Name, Address, Age FROM Person",
|
select << "SELECT Name, Address, Age FROM Person",
|
||||||
@ -71,24 +71,24 @@ The following complete example shows how to use POCO Data:
|
|||||||
into(person.address),
|
into(person.address),
|
||||||
into(person.age),
|
into(person.age),
|
||||||
range(0, 1); // iterate over result set one row at a time
|
range(0, 1); // iterate over result set one row at a time
|
||||||
|
|
||||||
while (!select.done())
|
while (!select.done())
|
||||||
{
|
{
|
||||||
select.execute();
|
select.execute();
|
||||||
std::cout << person.name << " " << person.address << " " << person.age << std::endl;
|
std::cout << person.name << " " << person.address << " " << person.age << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
The above example is pretty much self explanatory.
|
The above example is pretty much self explanatory.
|
||||||
|
|
||||||
The <[using namespace Poco::Data ]> is for convenience only but highly
|
The <[using namespace Poco::Data ]> is for convenience only but highly
|
||||||
recommended for good readable code. While <[ses << "SELECT COUNT(*)
|
recommended for good readable code. While <[ses << "SELECT COUNT(*)
|
||||||
FROM PERSON", Poco::Data::Keywords::into(count), Poco::Data::Keywords::now;]>
|
FROM PERSON", Poco::Data::Keywords::into(count), Poco::Data::Keywords::now;]>
|
||||||
is valid, the aesthetic aspect of the code is improved by eliminating the need
|
is valid, the aesthetic aspect of the code is improved by eliminating the need
|
||||||
for full namespace qualification; this document uses convention introduced in
|
for full namespace qualification; this document uses convention introduced in
|
||||||
the example above.
|
the example above.
|
||||||
|
|
||||||
The remainder of this tutorial is split up into the following parts:
|
The remainder of this tutorial is split up into the following parts:
|
||||||
@ -117,12 +117,12 @@ parameter contains the connection string.
|
|||||||
|
|
||||||
In the case of SQLite, the path of the database file is sufficient as connection string.
|
In the case of SQLite, the path of the database file is sufficient as connection string.
|
||||||
|
|
||||||
For ODBC, the connection string may be a simple "DSN=MyDSNName" when a DSN is configured or
|
For ODBC, the connection string may be a simple "DSN=MyDSNName" when a DSN is configured or
|
||||||
a complete ODBC driver-specific connection string defining all the necessary connection parameters
|
a complete ODBC driver-specific connection string defining all the necessary connection parameters
|
||||||
(for details, consult your ODBC driver documentation).
|
(for details, consult your ODBC driver documentation).
|
||||||
|
|
||||||
For MySQL, the connection string is a semicolon-delimited list of name-value pairs
|
For MySQL, the connection string is a semicolon-delimited list of name-value pairs
|
||||||
specifying various parameters like host, port, user, password, database, compression and
|
specifying various parameters like host, port, user, password, database, compression and
|
||||||
automatic reconnect. Example: <["host=localhost;port=3306;db=mydb;user=alice;password=s3cr3t;compress=true;auto-reconnect=true"]>
|
automatic reconnect. Example: <["host=localhost;port=3306;db=mydb;user=alice;password=s3cr3t;compress=true;auto-reconnect=true"]>
|
||||||
|
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ automatic reconnect. Example: <["host=localhost;port=3306;db=mydb;user=alice;pas
|
|||||||
|
|
||||||
!!Single Data Sets
|
!!Single Data Sets
|
||||||
|
|
||||||
Inserting data works by <[using]> the content of other variables.
|
Inserting data works by <[using]> the content of other variables.
|
||||||
Assume we have a table that stores only forenames:
|
Assume we have a table that stores only forenames:
|
||||||
|
|
||||||
ForeName (Name VARCHAR(30))
|
ForeName (Name VARCHAR(30))
|
||||||
@ -159,8 +159,8 @@ Rewriting the above code now simply gives:
|
|||||||
----
|
----
|
||||||
|
|
||||||
In this example the <[use]> expression matches the placeholder with the
|
In this example the <[use]> expression matches the placeholder with the
|
||||||
<[Peter]> value. Note that apart from the nicer syntax, the real benefits of
|
<[Peter]> value. Note that apart from the nicer syntax, the real benefits of
|
||||||
placeholders -- which are performance and protection against SQL injection
|
placeholders -- which are performance and protection against SQL injection
|
||||||
attacks -- don't show here. Check the <[Statements]> section to find out more.
|
attacks -- don't show here. Check the <[Statements]> section to find out more.
|
||||||
|
|
||||||
Retrieving data from the Database works similar. The <[into]>
|
Retrieving data from the Database works similar. The <[into]>
|
||||||
@ -172,14 +172,14 @@ database:
|
|||||||
ses << "SELECT NAME FROM FORENAME", into(aName), now;
|
ses << "SELECT NAME FROM FORENAME", into(aName), now;
|
||||||
ses << "SELECT NAME FROM FORENAME", into(aName, 0, "default"), now;
|
ses << "SELECT NAME FROM FORENAME", into(aName, 0, "default"), now;
|
||||||
|
|
||||||
You'll note the integer zero argument in the second into() call. The reason for
|
You'll note the integer zero argument in the second into() call. The reason for
|
||||||
that is that Poco::Data supports multiple result sets for those databases/drivers
|
that is that Poco::Data supports multiple result sets for those databases/drivers
|
||||||
that have such capbility and we have to indicate the resultset we are referring to.
|
that have such capbility and we have to indicate the resultset we are referring to.
|
||||||
Attempting to create sufficient overloads of <[into()]> creates more trouble than
|
Attempting to create sufficient overloads of <[into()]> creates more trouble than
|
||||||
what it's worth and null values can effectively be dealt with through use of either
|
what it's worth and null values can effectively be dealt with through use of either
|
||||||
Poco::Nullable wrapper (see Handling Null Entries later in this document) or
|
Poco::Nullable wrapper (see Handling Null Entries later in this document) or
|
||||||
Poco::Dynamic::Var, which will be set as empty for null values when used as query
|
Poco::Dynamic::Var, which will be set as empty for null values when used as query
|
||||||
output target.
|
output target.
|
||||||
----
|
----
|
||||||
|
|
||||||
It is also possible to combine into and use expressions:
|
It is also possible to combine into and use expressions:
|
||||||
@ -224,18 +224,18 @@ To accomodate for NULL, use the Poco::Nullable template:
|
|||||||
if (!lastName.isNull()) { ... }
|
if (!lastName.isNull()) { ... }
|
||||||
----
|
----
|
||||||
|
|
||||||
The above used Poco::Nullable is a lightweight template class, wrapping any type
|
The above used Poco::Nullable is a lightweight template class, wrapping any type
|
||||||
for the purpose of allowing it to have null value.
|
for the purpose of allowing it to have null value.
|
||||||
|
|
||||||
If the returned value was null, age.isNull() will return true. Whether empty
|
If the returned value was null, age.isNull() will return true. Whether empty
|
||||||
string is null or not is more of a philosophical question (a topic for discussion
|
string is null or not is more of a philosophical question (a topic for discussion
|
||||||
in some other time and place); for the purpose of this document, suffice it to say
|
in some other time and place); for the purpose of this document, suffice it to say
|
||||||
that different databases handle it differently and Poco::Data provides a way to
|
that different databases handle it differently and Poco::Data provides a way to
|
||||||
tweak it to user's needs through folowing <[Session]> features:
|
tweak it to user's needs through folowing <[Session]> features:
|
||||||
|
|
||||||
*emptyStringIsNull
|
*emptyStringIsNull
|
||||||
*forceEmptyString
|
*forceEmptyString
|
||||||
|
|
||||||
So, if your database does not treat empty strings as null but you want Poco::Data
|
So, if your database does not treat empty strings as null but you want Poco::Data
|
||||||
to emulate such behavior, modify the session like this:
|
to emulate such behavior, modify the session like this:
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ set it belongs to:
|
|||||||
std::vector<Person> people;
|
std::vector<Person> people;
|
||||||
Person pHomer, pLisa;
|
Person pHomer, pLisa;
|
||||||
int aHomer(42), aLisa(10), aBart(0);
|
int aHomer(42), aLisa(10), aBart(0);
|
||||||
|
|
||||||
session << "SELECT * FROM Person WHERE Age = ?; "
|
session << "SELECT * FROM Person WHERE Age = ?; "
|
||||||
"SELECT Age FROM Person WHERE FirstName = 'Bart'; "
|
"SELECT Age FROM Person WHERE FirstName = 'Bart'; "
|
||||||
"SELECT * FROM Person WHERE Age = ?",
|
"SELECT * FROM Person WHERE Age = ?",
|
||||||
@ -293,7 +293,7 @@ More on statements and manipulators in the chapters that follow.
|
|||||||
Most of the modern database systems support stored procedures and/or
|
Most of the modern database systems support stored procedures and/or
|
||||||
functions. Does Poco::Data provide any support there? You bet.
|
functions. Does Poco::Data provide any support there? You bet.
|
||||||
While the specifics on what exactly is possible (e.g. the data types
|
While the specifics on what exactly is possible (e.g. the data types
|
||||||
passed in and out, automatic or manual data binding, binding direction,
|
passed in and out, automatic or manual data binding, binding direction,
|
||||||
etc.) is ultimately database dependent, POCO Data does it's
|
etc.) is ultimately database dependent, POCO Data does it's
|
||||||
best to provide reasonable access to such functionality through <[in]>,
|
best to provide reasonable access to such functionality through <[in]>,
|
||||||
<[out]> and <[io]> binding functions. As their names imply, these
|
<[out]> and <[io]> binding functions. As their names imply, these
|
||||||
@ -306,7 +306,7 @@ here's an Oracle ODBC example:
|
|||||||
" temp NUMBER := param1; "
|
" temp NUMBER := param1; "
|
||||||
" BEGIN param1 := param2; param2 := temp; RETURN(param1+param2); "
|
" BEGIN param1 := param2; param2 := temp; RETURN(param1+param2); "
|
||||||
" END storedFunction;" , now;
|
" END storedFunction;" , now;
|
||||||
|
|
||||||
int i = 1, j = 2, result = 0;
|
int i = 1, j = 2, result = 0;
|
||||||
session << "{? = call storedFunction(?, ?)}", out(result), io(i), io(j), now; // i = 2, j = 1, result = 3
|
session << "{? = call storedFunction(?, ?)}", out(result), io(i), io(j), now; // i = 2, j = 1, result = 3
|
||||||
----
|
----
|
||||||
@ -322,10 +322,10 @@ Stored procedures are allowed to return data sets (a.k.a. cursors):
|
|||||||
" ret SYS_REFCURSOR; "
|
" ret SYS_REFCURSOR; "
|
||||||
"BEGIN "
|
"BEGIN "
|
||||||
" OPEN ret FOR "
|
" OPEN ret FOR "
|
||||||
" SELECT * FROM Person WHERE Age < ageLimit; "
|
" SELECT * FROM Person WHERE Age < ageLimit; "
|
||||||
" RETURN ret; "
|
" RETURN ret; "
|
||||||
"END storedCursorFunction;" , now;
|
"END storedCursorFunction;" , now;
|
||||||
|
|
||||||
session << "{call storedCursorFunction(?)}", in(age), into(people), now;
|
session << "{call storedCursorFunction(?)}", in(age), into(people), now;
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -387,8 +387,8 @@ Here's how we control when to actually execute the statement:
|
|||||||
----
|
----
|
||||||
|
|
||||||
By calling <[execute]> we asserted that our query was executed and that
|
By calling <[execute]> we asserted that our query was executed and that
|
||||||
the value was inserted. The check to <[stmt.done()]> simply guarantees that the
|
the value was inserted. The check to <[stmt.done()]> simply guarantees that the
|
||||||
statement was fully completed.
|
statement was fully completed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -479,7 +479,7 @@ return value is because, for asynchronous statements, <[execute()]>
|
|||||||
always returns zero. This makes sense, because it does not know the
|
always returns zero. This makes sense, because it does not know the
|
||||||
number of returned rows (remember, asynchronous <[execute()]> call
|
number of returned rows (remember, asynchronous <[execute()]> call
|
||||||
returns <[immediately]> and does not wait for the completion of the
|
returns <[immediately]> and does not wait for the completion of the
|
||||||
execution).
|
execution).
|
||||||
|
|
||||||
!A Word of Warning
|
!A Word of Warning
|
||||||
|
|
||||||
@ -513,7 +513,7 @@ later during execution. Thus, one should never pass temporaries to <[use()]>:
|
|||||||
----
|
----
|
||||||
|
|
||||||
It is possible to use <[bind()]> instead of <[use()]>. The <[bind()]> call will always create a
|
It is possible to use <[bind()]> instead of <[use()]>. The <[bind()]> call will always create a
|
||||||
copy of the supplied argument. Also, it is possible to execute a statement returning
|
copy of the supplied argument. Also, it is possible to execute a statement returning
|
||||||
data without supplying the storage and have the statement itself store the returned
|
data without supplying the storage and have the statement itself store the returned
|
||||||
data for later retrieval through <[RecordSet]>. For details, see <[RecordSet]> chapter.
|
data for later retrieval through <[RecordSet]>. For details, see <[RecordSet]> chapter.
|
||||||
|
|
||||||
@ -538,7 +538,7 @@ well-known source of many security problems in C and C++ code, do not
|
|||||||
worry. Poco::format() family of functions is <[safe]> (and, admittedly,
|
worry. Poco::format() family of functions is <[safe]> (and, admittedly,
|
||||||
slower than printf).
|
slower than printf).
|
||||||
|
|
||||||
For cases where this type of formatting is used with queries containing
|
For cases where this type of formatting is used with queries containing
|
||||||
the percent sign, use double percent ("%%"):
|
the percent sign, use double percent ("%%"):
|
||||||
|
|
||||||
Statement stmt = (ses << "SELECT * FROM %s WHERE Name LIKE 'Simp%%'", "Person");
|
Statement stmt = (ses << "SELECT * FROM %s WHERE Name LIKE 'Simp%%'", "Person");
|
||||||
@ -696,13 +696,13 @@ object until <[statement.done()]> returns true.
|
|||||||
For the next example, we assume that our system knows about 101 forenames:
|
For the next example, we assume that our system knows about 101 forenames:
|
||||||
|
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
Statement stmt = (ses << "SELECT NAME FROM FORENAME", into(names), limit(50));
|
Statement stmt = (ses << "SELECT NAME FROM FORENAME", into(names), limit(50));
|
||||||
stmt.execute(); //names.size() == 50
|
stmt.execute(); //names.size() == 50
|
||||||
poco_assert (!stmt.done());
|
poco_assert (!stmt.done());
|
||||||
stmt.execute(); //names.size() == 100
|
stmt.execute(); //names.size() == 100
|
||||||
poco_assert (!stmt.done());
|
poco_assert (!stmt.done());
|
||||||
stmt.execute(); //names.size() == 101
|
stmt.execute(); //names.size() == 101
|
||||||
poco_assert (stmt.done());
|
poco_assert (stmt.done());
|
||||||
----
|
----
|
||||||
|
|
||||||
We previously stated that if no data is returned this is valid too. Thus, executing the following statement on an
|
We previously stated that if no data is returned this is valid too. Thus, executing the following statement on an
|
||||||
@ -750,14 +750,14 @@ off.
|
|||||||
|
|
||||||
The <[bulk]> keyword allows to boost performance for the connectors that
|
The <[bulk]> keyword allows to boost performance for the connectors that
|
||||||
support column-wise operation and arrays of values and/or parameters
|
support column-wise operation and arrays of values and/or parameters
|
||||||
(e.g. ODBC).
|
(e.g. ODBC).
|
||||||
Here's how to signal bulk insertion to the statement:
|
Here's how to signal bulk insertion to the statement:
|
||||||
|
|
||||||
std::vector<int> ints(100, 1);
|
std::vector<int> ints(100, 1);
|
||||||
session << "INSERT INTO Test VALUES (?)", use(ints, bulk), now;
|
session << "INSERT INTO Test VALUES (?)", use(ints, bulk), now;
|
||||||
----
|
----
|
||||||
|
|
||||||
The above code will execute a "one-shot" insertion into the target table.
|
The above code will execute a "one-shot" insertion into the target table.
|
||||||
|
|
||||||
|
|
||||||
Selection in bulk mode looks like this:
|
Selection in bulk mode looks like this:
|
||||||
@ -827,7 +827,7 @@ feature.
|
|||||||
!!! RecordSets, Iterators and Rows
|
!!! RecordSets, Iterators and Rows
|
||||||
|
|
||||||
In all the examples so far the programmer had to supply the storage for
|
In all the examples so far the programmer had to supply the storage for
|
||||||
data to be inserted or retrieved from a database.
|
data to be inserted or retrieved from a database.
|
||||||
|
|
||||||
It is usually desirable to avoid that and let the framework take care of
|
It is usually desirable to avoid that and let the framework take care of
|
||||||
it, something like this:
|
it, something like this:
|
||||||
@ -840,16 +840,16 @@ No worries -- that's what the RecordSet class does:
|
|||||||
Statement select(session); // we need a Statement for later RecordSet creation
|
Statement select(session); // we need a Statement for later RecordSet creation
|
||||||
select << "SELECT * FROM Person", now;
|
select << "SELECT * FROM Person", now;
|
||||||
|
|
||||||
// create a RecordSet
|
// create a RecordSet
|
||||||
RecordSet rs(select);
|
RecordSet rs(select);
|
||||||
std::size_t cols = rs.columnCount();
|
std::size_t cols = rs.columnCount();
|
||||||
|
|
||||||
// print all column names
|
// print all column names
|
||||||
for (std::size_t col = 0; col < cols; ++col)
|
for (std::size_t col = 0; col < cols; ++col)
|
||||||
std::cout << rs.columnName(col) << std::endl;
|
std::cout << rs.columnName(col) << std::endl;
|
||||||
|
|
||||||
// iterate over all rows and columns
|
// iterate over all rows and columns
|
||||||
for (RecordSet::Iterator it = rs.begin(); it != rs.end(); ++it)
|
for (RecordSet::Iterator it = rs.begin(); it != rs.end(); ++it)
|
||||||
std::cout << *it << " ";
|
std::cout << *it << " ";
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -889,7 +889,7 @@ used for sorting purposes. However, the sort criteria can be modified at
|
|||||||
runtime. For example, an additional field may be added to sort fields
|
runtime. For example, an additional field may be added to sort fields
|
||||||
(think "... ORDER BY Name ASC, Age DESC"):
|
(think "... ORDER BY Name ASC, Age DESC"):
|
||||||
|
|
||||||
row.addSortField("Field1"); // now Field0 and Field1 are used for sorting
|
row.addSortField("Field1"); // now Field0 and Field1 are used for sorting
|
||||||
row.replaceSortField("Field0", "Field2");// now Field1 and Field2 are used for sorting
|
row.replaceSortField("Field0", "Field2");// now Field1 and Field2 are used for sorting
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -914,7 +914,7 @@ Valid storage type manipulators are:
|
|||||||
|
|
||||||
So, if neither data storage, nor storage type are explicitly specified,
|
So, if neither data storage, nor storage type are explicitly specified,
|
||||||
the data will internally be kept in standard deques. This can be changed
|
the data will internally be kept in standard deques. This can be changed
|
||||||
through use of storage type manipulators.
|
through use of storage type manipulators.
|
||||||
|
|
||||||
|
|
||||||
!!!Complex Data Types
|
!!!Complex Data Types
|
||||||
@ -930,19 +930,19 @@ Assume you have a class Person:
|
|||||||
// default constructor+destr.
|
// default constructor+destr.
|
||||||
// getter and setter methods for all members
|
// getter and setter methods for all members
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
bool operator <(const Person& p) const
|
bool operator <(const Person& p) const
|
||||||
/// we need this for set and multiset support
|
/// we need this for set and multiset support
|
||||||
{
|
{
|
||||||
return _socialSecNr < p._socialSecNr;
|
return _socialSecNr < p._socialSecNr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::UInt64 operator()() const
|
Poco::UInt64 operator()() const
|
||||||
/// we need this operator to return the key for the map and multimap
|
/// we need this operator to return the key for the map and multimap
|
||||||
{
|
{
|
||||||
return _socialSecNr;
|
return _socialSecNr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _firstName;
|
std::string _firstName;
|
||||||
std::string _lastName;
|
std::string _lastName;
|
||||||
@ -953,12 +953,12 @@ Assume you have a class Person:
|
|||||||
Ideally, one would like to use a Person as simple as one used a string.
|
Ideally, one would like to use a Person as simple as one used a string.
|
||||||
All that is needed is a template specialization of the <[TypeHandler]>
|
All that is needed is a template specialization of the <[TypeHandler]>
|
||||||
template. Note that template specializations must be declared in the
|
template. Note that template specializations must be declared in the
|
||||||
<*same namespace*> as the original template, i.e. <[Poco::Data]>.
|
<*same namespace*> as the original template, i.e. <[Poco::Data]>.
|
||||||
The template specialization must implement the following methods:
|
The template specialization must implement the following methods:
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class TypeHandler<class Person>
|
class TypeHandler<class Person>
|
||||||
{
|
{
|
||||||
@ -972,12 +972,12 @@ The template specialization must implement the following methods:
|
|||||||
TypeHandler<std::string>::bind(pos++, obj.getLastName(), pBinder, dir);
|
TypeHandler<std::string>::bind(pos++, obj.getLastName(), pBinder, dir);
|
||||||
TypeHandler<Poco::UInt64>::bind(pos++, obj.getSocialSecNr(), pBinder, dir);
|
TypeHandler<Poco::UInt64>::bind(pos++, obj.getSocialSecNr(), pBinder, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::size_t size()
|
static std::size_t size()
|
||||||
{
|
{
|
||||||
return 3; // we handle three columns of the Table!
|
return 3; // we handle three columns of the Table!
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepare(std::size_t pos, const Person& obj, AbstractPreparator::Ptr pPrepare)
|
static void prepare(std::size_t pos, const Person& obj, AbstractPreparator::Ptr pPrepare)
|
||||||
{
|
{
|
||||||
poco_assert_dbg (!pPrepare.isNull());
|
poco_assert_dbg (!pPrepare.isNull());
|
||||||
@ -987,7 +987,7 @@ The template specialization must implement the following methods:
|
|||||||
TypeHandler<std::string>::prepare(pos++, obj.getLastName(), pPrepare);
|
TypeHandler<std::string>::prepare(pos++, obj.getLastName(), pPrepare);
|
||||||
TypeHandler<Poco::UInt64>::prepare(pos++, obj.getSocialSecNr(), pPrepare);
|
TypeHandler<Poco::UInt64>::prepare(pos++, obj.getSocialSecNr(), pPrepare);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void extract(std::size_t pos, Person& obj, const Person& defVal, AbstractExtractor::Ptr pExt)
|
static void extract(std::size_t pos, Person& obj, const Person& defVal, AbstractExtractor::Ptr pExt)
|
||||||
/// obj will contain the result, defVal contains values we should use when one column is NULL
|
/// obj will contain the result, defVal contains values we should use when one column is NULL
|
||||||
{
|
{
|
||||||
@ -1002,14 +1002,14 @@ The template specialization must implement the following methods:
|
|||||||
obj.setLastName(lastName);
|
obj.setLastName(lastName);
|
||||||
obj.setSocialSecNr(socialSecNr);
|
obj.setSocialSecNr(socialSecNr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypeHandler();
|
TypeHandler();
|
||||||
~TypeHandler();
|
~TypeHandler();
|
||||||
TypeHandler(const TypeHandler&);
|
TypeHandler(const TypeHandler&);
|
||||||
TypeHandler& operator=(const TypeHandler&);
|
TypeHandler& operator=(const TypeHandler&);
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace Poco::Data
|
} } // namespace Poco::Data
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -1022,8 +1022,9 @@ working with a string:
|
|||||||
|
|
||||||
|
|
||||||
!!!Session Pooling
|
!!!Session Pooling
|
||||||
|
|
||||||
Creating a connection to a database is often a time consuming
|
Creating a connection to a database is often a time consuming
|
||||||
operation. Therefore it makes sense to save a session object for
|
operation. Therefore it makes sense to save a session object for
|
||||||
later reuse once it is no longer needed.
|
later reuse once it is no longer needed.
|
||||||
|
|
||||||
A Poco::Data::SessionPool manages a collection of sessions.
|
A Poco::Data::SessionPool manages a collection of sessions.
|
||||||
@ -1046,7 +1047,7 @@ Pooled sessions are automatically returned to the pool when the
|
|||||||
Session variable holding them is destroyed.
|
Session variable holding them is destroyed.
|
||||||
|
|
||||||
One session pool, of course, holds sessions for one database
|
One session pool, of course, holds sessions for one database
|
||||||
connection. For sessions to multiple databases, there is
|
connection. For sessions to multiple databases, there is
|
||||||
SessionPoolContainer:
|
SessionPoolContainer:
|
||||||
|
|
||||||
SessionPoolContainer spc;
|
SessionPoolContainer spc;
|
||||||
@ -1060,15 +1061,15 @@ SessionPoolContainer:
|
|||||||
|
|
||||||
This document provides an overview of the most important features
|
This document provides an overview of the most important features
|
||||||
offered by the POCO Data framework. The framework also supports LOB
|
offered by the POCO Data framework. The framework also supports LOB
|
||||||
(specialized to BLOB and CLOB) type as well as Poco::DateTime binding.
|
(specialized to BLOB and CLOB) type as well as Poco::DateTime binding.
|
||||||
The usage of these data types is no different than any C++ type, so we
|
The usage of these data types is no different than any C++ type, so we
|
||||||
did not go into details here.
|
did not go into details here.
|
||||||
|
|
||||||
The great deal of <[RecordSet]> and <[Row]> runtime "magic" is achieved
|
The great deal of <[RecordSet]> and <[Row]> runtime "magic" is achieved
|
||||||
through employment of Poco::Dynamic::Var, which is the POCO
|
through employment of Poco::Dynamic::Var, which is the POCO
|
||||||
equivalent of dynamic language data type. Obviously, due to its nature,
|
equivalent of dynamic language data type. Obviously, due to its nature,
|
||||||
there is a run time performance penalty associated with Poco::Dynamic::Var,
|
there is a run time performance penalty associated with Poco::Dynamic::Var,
|
||||||
but the internal details are beyond the scope of this document.
|
but the internal details are beyond the scope of this document.
|
||||||
|
|
||||||
POCO Data tries to provide a broad spectrum of functionality,
|
POCO Data tries to provide a broad spectrum of functionality,
|
||||||
with configurable efficiency/convenience ratio, providing a solid
|
with configurable efficiency/convenience ratio, providing a solid
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "Poco/Data/LOB.h"
|
#include "Poco/Data/LOB.h"
|
||||||
#include "Poco/DateTime.h"
|
#include "Poco/DateTime.h"
|
||||||
#include "Poco/Nullable.h"
|
#include "Poco/Nullable.h"
|
||||||
|
#include "Poco/UUID.h"
|
||||||
#include "Poco/Any.h"
|
#include "Poco/Any.h"
|
||||||
#include "Poco/Dynamic/Var.h"
|
#include "Poco/Dynamic/Var.h"
|
||||||
#include "Poco/UTFString.h"
|
#include "Poco/UTFString.h"
|
||||||
@ -317,6 +318,18 @@ public:
|
|||||||
virtual void bind(std::size_t pos, const std::list<Time>& val, Direction dir = PD_IN);
|
virtual void bind(std::size_t pos, const std::list<Time>& val, Direction dir = PD_IN);
|
||||||
/// Binds a Time list.
|
/// Binds a Time list.
|
||||||
|
|
||||||
|
virtual void bind(std::size_t pos, const UUID& val, Direction dir = PD_IN) = 0;
|
||||||
|
/// Binds a UUID.
|
||||||
|
|
||||||
|
virtual void bind(std::size_t pos, const std::vector<UUID>& val, Direction dir = PD_IN);
|
||||||
|
/// Binds a UUID vector.
|
||||||
|
|
||||||
|
virtual void bind(std::size_t pos, const std::deque<UUID>& val, Direction dir = PD_IN);
|
||||||
|
/// Binds a UUID deque.
|
||||||
|
|
||||||
|
virtual void bind(std::size_t pos, const std::list<UUID>& val, Direction dir = PD_IN);
|
||||||
|
/// Binds a UUID list.
|
||||||
|
|
||||||
virtual void bind(std::size_t pos, const NullData& val, Direction dir = PD_IN) = 0;
|
virtual void bind(std::size_t pos, const NullData& val, Direction dir = PD_IN) = 0;
|
||||||
/// Binds a null.
|
/// Binds a null.
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "Poco/Data/Data.h"
|
#include "Poco/Data/Data.h"
|
||||||
#include "Poco/Data/Constants.h"
|
#include "Poco/Data/Constants.h"
|
||||||
#include "Poco/Data/LOB.h"
|
#include "Poco/Data/LOB.h"
|
||||||
|
#include "Poco/UUID.h"
|
||||||
#include "Poco/UTFString.h"
|
#include "Poco/UTFString.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
@ -304,6 +305,18 @@ public:
|
|||||||
virtual bool extract(std::size_t pos, std::list<Time>& val);
|
virtual bool extract(std::size_t pos, std::list<Time>& val);
|
||||||
/// Extracts a Time list.
|
/// Extracts a Time list.
|
||||||
|
|
||||||
|
virtual bool extract(std::size_t pos, UUID& val) = 0;
|
||||||
|
/// Extracts a UUID. Returns false if null was received.
|
||||||
|
|
||||||
|
virtual bool extract(std::size_t pos, std::vector<UUID>& val);
|
||||||
|
/// Extracts a UUID vector.
|
||||||
|
|
||||||
|
virtual bool extract(std::size_t pos, std::deque<UUID>& val);
|
||||||
|
/// Extracts a UUID deque.
|
||||||
|
|
||||||
|
virtual bool extract(std::size_t pos, std::list<UUID>& val);
|
||||||
|
/// Extracts a UUID list.
|
||||||
|
|
||||||
virtual bool extract(std::size_t pos, Any& val) = 0;
|
virtual bool extract(std::size_t pos, Any& val) = 0;
|
||||||
/// Extracts an Any. Returns false if null was received.
|
/// Extracts an Any. Returns false if null was received.
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "Poco/Data/Data.h"
|
#include "Poco/Data/Data.h"
|
||||||
#include "Poco/RefCountedObject.h"
|
#include "Poco/RefCountedObject.h"
|
||||||
#include "Poco/Data/LOB.h"
|
#include "Poco/Data/LOB.h"
|
||||||
|
#include "Poco/UUID.h"
|
||||||
#include "Poco/UTFString.h"
|
#include "Poco/UTFString.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
@ -310,6 +311,18 @@ public:
|
|||||||
virtual void prepare(std::size_t pos, const std::list<Time>& val);
|
virtual void prepare(std::size_t pos, const std::list<Time>& val);
|
||||||
/// Prepares a Time list.
|
/// Prepares a Time list.
|
||||||
|
|
||||||
|
virtual void prepare(std::size_t pos, const UUID&) = 0;
|
||||||
|
/// Prepares a UUID.
|
||||||
|
|
||||||
|
virtual void prepare(std::size_t pos, const std::vector<UUID>& val);
|
||||||
|
/// Prepares a UUID vector.
|
||||||
|
|
||||||
|
virtual void prepare(std::size_t pos, const std::deque<UUID>& val);
|
||||||
|
/// Prepares a UUID deque.
|
||||||
|
|
||||||
|
virtual void prepare(std::size_t pos, const std::list<UUID>& val);
|
||||||
|
/// Prepares a UUID list.
|
||||||
|
|
||||||
virtual void prepare(std::size_t pos, const Any&) = 0;
|
virtual void prepare(std::size_t pos, const Any&) = 0;
|
||||||
/// Prepares an Any.
|
/// Prepares an Any.
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ public:
|
|||||||
FDT_DATE,
|
FDT_DATE,
|
||||||
FDT_TIME,
|
FDT_TIME,
|
||||||
FDT_TIMESTAMP,
|
FDT_TIMESTAMP,
|
||||||
|
FDT_UUID,
|
||||||
FDT_UNKNOWN
|
FDT_UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -404,6 +404,24 @@ void AbstractBinder::bind(std::size_t pos, const std::list<Time>& val, Direction
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbstractBinder::bind(std::size_t pos, const std::vector<UUID>& val, Direction dir)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::vector binder must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbstractBinder::bind(std::size_t pos, const std::deque<UUID>& val, Direction dir)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::deque binder must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbstractBinder::bind(std::size_t pos, const std::list<UUID>& val, Direction dir)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::list binder must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AbstractBinder::bind(std::size_t pos, const std::vector<NullData>& val, Direction dir)
|
void AbstractBinder::bind(std::size_t pos, const std::vector<NullData>& val, Direction dir)
|
||||||
{
|
{
|
||||||
throw NotImplementedException("std::vector binder must be implemented.");
|
throw NotImplementedException("std::vector binder must be implemented.");
|
||||||
|
@ -398,6 +398,24 @@ bool AbstractExtractor::extract(std::size_t pos, std::list<Time>& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AbstractExtractor::extract(std::size_t pos, std::vector<UUID>& val)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::vector extractor must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AbstractExtractor::extract(std::size_t pos, std::deque<UUID>& val)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::deque extractor must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AbstractExtractor::extract(std::size_t pos, std::list<UUID>& val)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::list extractor must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool AbstractExtractor::extract(std::size_t pos, std::vector<Any>& val)
|
bool AbstractExtractor::extract(std::size_t pos, std::vector<Any>& val)
|
||||||
{
|
{
|
||||||
throw NotImplementedException("std::vector extractor must be implemented.");
|
throw NotImplementedException("std::vector extractor must be implemented.");
|
||||||
|
@ -399,6 +399,24 @@ void AbstractPreparator::prepare(std::size_t pos, const std::list<Time>& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbstractPreparator::prepare(std::size_t pos, const std::vector<UUID>& val)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::vector preparator must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbstractPreparator::prepare(std::size_t pos, const std::deque<UUID>& val)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::deque preparator must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbstractPreparator::prepare(std::size_t pos, const std::list<UUID>& val)
|
||||||
|
{
|
||||||
|
throw NotImplementedException("std::list preparator must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AbstractPreparator::prepare(std::size_t pos, const std::vector<Any>& val)
|
void AbstractPreparator::prepare(std::size_t pos, const std::vector<Any>& val)
|
||||||
{
|
{
|
||||||
throw NotImplementedException("std::vector preparator must be implemented.");
|
throw NotImplementedException("std::vector preparator must be implemented.");
|
||||||
|
@ -159,6 +159,7 @@ Poco::Dynamic::Var RecordSet::value(std::size_t col, std::size_t row, bool useFi
|
|||||||
case MetaColumn::FDT_DATE: return value<Date>(col, row, useFilter);
|
case MetaColumn::FDT_DATE: return value<Date>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_TIME: return value<Time>(col, row, useFilter);
|
case MetaColumn::FDT_TIME: return value<Time>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, row);
|
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, row);
|
||||||
|
case MetaColumn::FDT_UUID: return value<UUID>(col, row);
|
||||||
default:
|
default:
|
||||||
throw UnknownTypeException("Data type not supported.");
|
throw UnknownTypeException("Data type not supported.");
|
||||||
}
|
}
|
||||||
@ -192,6 +193,7 @@ Poco::Dynamic::Var RecordSet::value(const std::string& name, std::size_t row, bo
|
|||||||
case MetaColumn::FDT_DATE: return value<Date>(name, row, useFilter);
|
case MetaColumn::FDT_DATE: return value<Date>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_TIME: return value<Time>(name, row, useFilter);
|
case MetaColumn::FDT_TIME: return value<Time>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(name, row, useFilter);
|
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(name, row, useFilter);
|
||||||
|
case MetaColumn::FDT_UUID: return value<UUID>(name, row, useFilter);
|
||||||
default:
|
default:
|
||||||
throw UnknownTypeException("Data type not supported.");
|
throw UnknownTypeException("Data type not supported.");
|
||||||
}
|
}
|
||||||
|
@ -351,6 +351,8 @@ void StatementImpl::makeExtractors(std::size_t count)
|
|||||||
addInternalExtract<Time>(mc); break;
|
addInternalExtract<Time>(mc); break;
|
||||||
case MetaColumn::FDT_TIMESTAMP:
|
case MetaColumn::FDT_TIMESTAMP:
|
||||||
addInternalExtract<DateTime>(mc); break;
|
addInternalExtract<DateTime>(mc); break;
|
||||||
|
case MetaColumn::FDT_UUID:
|
||||||
|
addInternalExtract<UUID>(mc); break;
|
||||||
default:
|
default:
|
||||||
throw Poco::InvalidArgumentException("Data type not supported.");
|
throw Poco::InvalidArgumentException("Data type not supported.");
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,11 @@ void Binder::bind(std::size_t pos, const DateTime& val, Direction dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
|
void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,11 @@ public:
|
|||||||
void bind(std::size_t pos, const DateTime& val, Direction dir);
|
void bind(std::size_t pos, const DateTime& val, Direction dir);
|
||||||
/// Binds a DateTime.
|
/// Binds a DateTime.
|
||||||
|
|
||||||
|
void bind(std::size_t pos, const UUID& val, Direction dir);
|
||||||
|
/// Binds a UUID.
|
||||||
|
|
||||||
void bind(std::size_t pos, const NullData& val, Direction dir);
|
void bind(std::size_t pos, const NullData& val, Direction dir);
|
||||||
/// Binds a DateTime.
|
/// Binds a NullData.
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
|
@ -166,13 +166,18 @@ bool Extractor::extract(std::size_t pos, Poco::Data::Time& val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, Poco::DateTime& val)
|
bool Extractor::extract(std::size_t pos, Poco::DateTime& val)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Extractor::extract(std::size_t pos, Poco::UUID& val)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Extractor::extract(std::size_t pos, Poco::Any& val)
|
bool Extractor::extract(std::size_t pos, Poco::Any& val)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -100,9 +100,12 @@ public:
|
|||||||
bool extract(std::size_t pos, Time& val);
|
bool extract(std::size_t pos, Time& val);
|
||||||
/// Extracts a Time.
|
/// Extracts a Time.
|
||||||
|
|
||||||
bool extract(std::size_t pos, Poco::DateTime& val);
|
bool extract(std::size_t pos, DateTime& val);
|
||||||
/// Extracts a DateTime.
|
/// Extracts a DateTime.
|
||||||
|
|
||||||
|
bool extract(std::size_t pos, UUID& val);
|
||||||
|
/// Extracts a UUID.
|
||||||
|
|
||||||
bool isNull(std::size_t col, std::size_t row = -1);
|
bool isNull(std::size_t col, std::size_t row = -1);
|
||||||
/// Returns true if the current row value at pos column is null.
|
/// Returns true if the current row value at pos column is null.
|
||||||
|
|
||||||
|
@ -135,6 +135,11 @@ void Preparator::prepare(std::size_t pos, const Poco::DateTime&)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Preparator::prepare(std::size_t pos, const Poco::UUID&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Preparator::prepare(std::size_t pos, const Poco::Any&)
|
void Preparator::prepare(std::size_t pos, const Poco::Any&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,9 @@ public:
|
|||||||
void prepare(std::size_t pos, const Poco::DateTime&);
|
void prepare(std::size_t pos, const Poco::DateTime&);
|
||||||
/// Prepares a DateTime.
|
/// Prepares a DateTime.
|
||||||
|
|
||||||
|
void prepare(std::size_t pos, const Poco::UUID&);
|
||||||
|
/// Prepares a UUID.
|
||||||
|
|
||||||
void prepare(std::size_t pos, const Poco::Any&);
|
void prepare(std::size_t pos, const Poco::Any&);
|
||||||
/// Prepares an Any.
|
/// Prepares an Any.
|
||||||
|
|
||||||
|
@ -523,6 +523,9 @@ public:
|
|||||||
bool isDateTime() const;
|
bool isDateTime() const;
|
||||||
/// Returns true if stored value represents a date/time.
|
/// Returns true if stored value represents a date/time.
|
||||||
|
|
||||||
|
bool isUUID() const;
|
||||||
|
/// Returns true if stored value is a Poco::UUID.
|
||||||
|
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
/// Returns the size of this Var.
|
/// Returns the size of this Var.
|
||||||
/// This function returns 0 when Var is empty, 1 for POD or the size (i.e. length)
|
/// This function returns 0 when Var is empty, 1 for POD or the size (i.e. length)
|
||||||
@ -896,6 +899,13 @@ inline bool Var::isDateTime() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Var::isUUID() const
|
||||||
|
{
|
||||||
|
VarHolder* pHolder = content();
|
||||||
|
return pHolder ? pHolder->isUUID() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::size_t Var::size() const
|
inline std::size_t Var::size() const
|
||||||
{
|
{
|
||||||
VarHolder* pHolder = content();
|
VarHolder* pHolder = content();
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "Poco/UnicodeConverter.h"
|
#include "Poco/UnicodeConverter.h"
|
||||||
#include "Poco/UTFString.h"
|
#include "Poco/UTFString.h"
|
||||||
#include "Poco/UTF8String.h"
|
#include "Poco/UTF8String.h"
|
||||||
|
#include "Poco/UUID.h"
|
||||||
#include "Poco/Any.h"
|
#include "Poco/Any.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -178,6 +179,10 @@ public:
|
|||||||
/// Throws BadCastException. Must be overridden in a type
|
/// Throws BadCastException. Must be overridden in a type
|
||||||
/// specialization in order to support the conversion.
|
/// specialization in order to support the conversion.
|
||||||
|
|
||||||
|
virtual void convert(UUID& val) const;
|
||||||
|
/// Throws BadCastException. Must be overridden in a type
|
||||||
|
/// specialization in order to support the conversion.
|
||||||
|
|
||||||
#ifndef POCO_INT64_IS_LONG
|
#ifndef POCO_INT64_IS_LONG
|
||||||
|
|
||||||
void convert(long& val) const;
|
void convert(long& val) const;
|
||||||
@ -277,6 +282,10 @@ public:
|
|||||||
/// Returns false. Must be properly overridden in a type
|
/// Returns false. Must be properly overridden in a type
|
||||||
/// specialization in order to support the diagnostic.
|
/// specialization in order to support the diagnostic.
|
||||||
|
|
||||||
|
virtual bool isUUID() const;
|
||||||
|
/// Returns false. Must be properly overridden in a type
|
||||||
|
/// specialization in order to support the diagnostic.
|
||||||
|
|
||||||
virtual std::size_t size() const;
|
virtual std::size_t size() const;
|
||||||
/// Returns 1 iff Var is not empty or this function overridden.
|
/// Returns 1 iff Var is not empty or this function overridden.
|
||||||
|
|
||||||
@ -519,8 +528,16 @@ inline void VarHolder::convert(Timestamp& /*val*/) const
|
|||||||
throw BadCastException("Can not convert to Timestamp");
|
throw BadCastException("Can not convert to Timestamp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void VarHolder::convert(UUID& /*val*/) const
|
||||||
|
{
|
||||||
|
throw BadCastException("Can not convert to UUID");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef POCO_INT64_IS_LONG
|
#ifndef POCO_INT64_IS_LONG
|
||||||
|
|
||||||
|
|
||||||
inline void VarHolder::convert(long& val) const
|
inline void VarHolder::convert(long& val) const
|
||||||
{
|
{
|
||||||
Int32 tmp;
|
Int32 tmp;
|
||||||
@ -536,8 +553,10 @@ inline void VarHolder::convert(unsigned long& val) const
|
|||||||
val = tmp;
|
val = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
||||||
inline void VarHolder::convert(long long& /*val*/) const
|
inline void VarHolder::convert(long long& /*val*/) const
|
||||||
{
|
{
|
||||||
throw BadCastException("Can not convert to long long");
|
throw BadCastException("Can not convert to long long");
|
||||||
@ -549,8 +568,10 @@ inline void VarHolder::convert(unsigned long long& /*val*/) const
|
|||||||
throw BadCastException("Can not convert to unsigned long long");
|
throw BadCastException("Can not convert to unsigned long long");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
inline void VarHolder::convert(bool& /*val*/) const
|
inline void VarHolder::convert(bool& /*val*/) const
|
||||||
{
|
{
|
||||||
throw BadCastException("Can not convert to bool");
|
throw BadCastException("Can not convert to bool");
|
||||||
@ -671,6 +692,12 @@ inline bool VarHolder::isDateTime() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool VarHolder::isUUID() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::size_t VarHolder::size() const
|
inline std::size_t VarHolder::size() const
|
||||||
{
|
{
|
||||||
return 1u;
|
return 1u;
|
||||||
@ -1026,7 +1053,6 @@ public:
|
|||||||
return std::numeric_limits<Int16>::is_specialized;
|
return std::numeric_limits<Int16>::is_specialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isString() const
|
bool isString() const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -2750,6 +2776,11 @@ public:
|
|||||||
ts = tmp.timestamp();
|
ts = tmp.timestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void convert(UUID& uuid) const
|
||||||
|
{
|
||||||
|
uuid.parse(_val);
|
||||||
|
}
|
||||||
|
|
||||||
VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
|
VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
|
||||||
{
|
{
|
||||||
return cloneHolder(pVarHolder, _val);
|
return cloneHolder(pVarHolder, _val);
|
||||||
@ -3917,6 +3948,11 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isUUID() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VarHolderImpl();
|
VarHolderImpl();
|
||||||
VarHolderImpl(const VarHolderImpl&);
|
VarHolderImpl(const VarHolderImpl&);
|
||||||
@ -4047,6 +4083,11 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isUUID() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VarHolderImpl();
|
VarHolderImpl();
|
||||||
VarHolderImpl(const VarHolderImpl&);
|
VarHolderImpl(const VarHolderImpl&);
|
||||||
@ -4177,6 +4218,11 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isUUID() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VarHolderImpl();
|
VarHolderImpl();
|
||||||
VarHolderImpl(const VarHolderImpl&);
|
VarHolderImpl(const VarHolderImpl&);
|
||||||
@ -4186,6 +4232,102 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class VarHolderImpl<UUID>: public VarHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VarHolderImpl(const UUID& val): _val(val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~VarHolderImpl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::type_info& type() const
|
||||||
|
{
|
||||||
|
return typeid(UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void convert(std::string& val) const
|
||||||
|
{
|
||||||
|
val = _val.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
|
||||||
|
{
|
||||||
|
return cloneHolder(pVarHolder, _val);
|
||||||
|
}
|
||||||
|
|
||||||
|
const UUID& value() const
|
||||||
|
{
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isArray() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isStruct() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInteger() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSigned() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNumeric() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isBoolean() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isString() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDate() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTime() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDateTime() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isUUID() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VarHolderImpl();
|
||||||
|
VarHolderImpl(const VarHolderImpl&);
|
||||||
|
VarHolderImpl& operator = (const VarHolderImpl&);
|
||||||
|
|
||||||
|
Poco::UUID _val;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef std::vector<Var> Vector;
|
typedef std::vector<Var> Vector;
|
||||||
typedef std::deque<Var> Deque;
|
typedef std::deque<Var> Deque;
|
||||||
typedef std::list<Var> List;
|
typedef std::list<Var> List;
|
||||||
|
@ -47,7 +47,8 @@ bool isJSONString(const Var& any)
|
|||||||
any.type() == typeid(char*) ||
|
any.type() == typeid(char*) ||
|
||||||
any.type() == typeid(Poco::DateTime) ||
|
any.type() == typeid(Poco::DateTime) ||
|
||||||
any.type() == typeid(Poco::LocalDateTime) ||
|
any.type() == typeid(Poco::LocalDateTime) ||
|
||||||
any.type() == typeid(Poco::Timestamp);
|
any.type() == typeid(Poco::Timestamp) ||
|
||||||
|
any.type() == typeid(Poco::UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2859,6 +2859,32 @@ void VarTest::testDate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VarTest::testUUID()
|
||||||
|
{
|
||||||
|
Poco::UUID uuid("f1881be4-c3b7-4a47-9619-5169db5108a7");
|
||||||
|
|
||||||
|
Var vuuid(uuid);
|
||||||
|
assertTrue (vuuid.isUUID());
|
||||||
|
|
||||||
|
assert (vuuid.convert<std::string>() == "f1881be4-c3b7-4a47-9619-5169db5108a7");
|
||||||
|
|
||||||
|
assert (vuuid.extract<Poco::UUID>() == uuid);
|
||||||
|
|
||||||
|
Var vstr(std::string("f1881be4-c3b7-4a47-9619-5169db5108a7"));
|
||||||
|
assert (vstr.convert<Poco::UUID>() == uuid);
|
||||||
|
|
||||||
|
Var vstr2(std::string("notAnUUID"));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Poco::UUID uuid2 = vstr2.convert<Poco::UUID>();
|
||||||
|
fail("not a valid UUID, must fail");
|
||||||
|
}
|
||||||
|
catch (Poco::SyntaxException&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VarTest::testGetIdxNoThrow(Var& a1, std::vector<Var>::size_type n)
|
void VarTest::testGetIdxNoThrow(Var& a1, std::vector<Var>::size_type n)
|
||||||
{
|
{
|
||||||
Var val1 = a1[n];
|
Var val1 = a1[n];
|
||||||
@ -3104,6 +3130,7 @@ CppUnit::Test* VarTest::suite()
|
|||||||
CppUnit_addTest(pSuite, VarTest, testJSONDeserializeComplex);
|
CppUnit_addTest(pSuite, VarTest, testJSONDeserializeComplex);
|
||||||
CppUnit_addTest(pSuite, VarTest, testJSONRoundtripStruct);
|
CppUnit_addTest(pSuite, VarTest, testJSONRoundtripStruct);
|
||||||
CppUnit_addTest(pSuite, VarTest, testDate);
|
CppUnit_addTest(pSuite, VarTest, testDate);
|
||||||
|
CppUnit_addTest(pSuite, VarTest, testUUID);
|
||||||
CppUnit_addTest(pSuite, VarTest, testEmpty);
|
CppUnit_addTest(pSuite, VarTest, testEmpty);
|
||||||
CppUnit_addTest(pSuite, VarTest, testIterator);
|
CppUnit_addTest(pSuite, VarTest, testIterator);
|
||||||
|
|
||||||
|
@ -71,13 +71,13 @@ public:
|
|||||||
void testJSONDeserializePrimitives();
|
void testJSONDeserializePrimitives();
|
||||||
void testJSONDeserializeArray();
|
void testJSONDeserializeArray();
|
||||||
void testJSONDeserializeStruct();
|
void testJSONDeserializeStruct();
|
||||||
void testJSONRoundtripStruct();
|
void testJSONRoundtripStruct();
|
||||||
void testJSONDeserializeComplex();
|
void testJSONDeserializeComplex();
|
||||||
void testDate();
|
void testDate();
|
||||||
|
void testUUID();
|
||||||
void testEmpty();
|
void testEmpty();
|
||||||
void testIterator();
|
void testIterator();
|
||||||
|
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
static CppUnit::Test* suite();
|
static CppUnit::Test* suite();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user