1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-12-20 23:17:18 +01:00

Update POCO to 1.11.0

This commit is contained in:
Sandu Liviu Catalin
2021-08-22 18:07:06 +03:00
parent 151077c799
commit 7a3d92d1d1
450 changed files with 25219 additions and 6528 deletions

View File

@@ -6,8 +6,9 @@
include $(POCO_BASE)/build/rules/global
SYSLIBS += -L/usr/local/lib -L/usr/local/lib$(LIB64SUFFIX)/mysql -L/usr/lib$(LIB64SUFFIX)/mysql -L/usr/mysql/lib$(LIB64SUFFIX) -L/usr/mysql/lib$(LIB64SUFFIX)/mysql -L/usr/local/mysql/lib$(LIB64SUFFIX) -lmysqlclient
INCLUDE += -I/usr/local/include/mysql/ -I/usr/include/mysql/ -I/usr/mysql/include/mysql -I/usr/local/mysql/include
include MySQL.make
SYSLIBS += -lmysqlclient
SYSFLAGS += -DTHREADSAFE -DNO_TCL
objects = Binder Extractor SessionImpl Connector \

32
vendor/POCO/Data/MySQL/MySQL.make vendored Normal file
View File

@@ -0,0 +1,32 @@
#
# MySQL.make
#
# Makefile fragment for finding MySQL library
#
ifndef POCO_MYSQL_INCLUDE
ifeq (0, $(shell test -d /usr/local/include/mysql; echo $$?))
POCO_MYSQL_INCLUDE = /usr/local/include
else
ifeq (0, $(shell test -d /usr/local/opt/mysql-client/include; echo $$?))
POCO_MYSQL_INCLUDE = /usr/local/opt/mysql-client/include
endif
endif
endif
ifndef POCO_MYSQL_LIB
ifeq (0, $(shell test -d /usr/local/include/mysql; echo $$?))
POCO_MYSQL_LIB = /usr/local/lib
else
ifeq (0, $(shell test -d /usr/local/opt/mysql-client/lib; echo $$?))
POCO_MYSQL_LIB = /usr/local/opt/mysql-client/lib
endif
endif
endif
ifdef POCO_MYSQL_INCLUDE
INCLUDE += -I$(POCO_MYSQL_INCLUDE)
endif
ifdef POCO_MYSQL_LIB
SYSLIBS += -L$(POCO_MYSQL_LIB)
endif

View File

@@ -22,7 +22,7 @@
#include "Poco/Data/AbstractBinder.h"
#include "Poco/Data/LOB.h"
#include "Poco/Data/MySQL/MySQLException.h"
#include <mysql.h>
#include <mysql/mysql.h>
namespace Poco {
@@ -72,7 +72,7 @@ public:
virtual void bind(std::size_t pos, const unsigned long& val, Direction dir = PD_IN);
/// Binds an unsigned long.
#endif
#endif
virtual void bind(std::size_t pos, const bool& val, Direction dir);
/// Binds a boolean.
@@ -104,6 +104,9 @@ public:
virtual void bind(std::size_t pos, const Time& val, Direction dir);
/// 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);
/// Binds a null.

View File

@@ -110,6 +110,9 @@ public:
virtual bool extract(std::size_t pos, Time& val);
/// 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);
/// Extracts an Any. Returns false if null was received.

View File

@@ -19,6 +19,7 @@
#include "Poco/Foundation.h"
#include <mysql/mysql.h>
//
@@ -54,7 +55,11 @@
#if !defined(MySQL_EXPORTS)
#pragma comment(lib, "PocoDataMySQL" POCO_LIB_SUFFIX)
#endif
#pragma comment(lib, "libmysql")
#if defined(LIBMARIADB)
#pragma comment(lib, "libmariadb")
#else
#pragma comment(lib, "libmysql")
#endif
#endif

View File

@@ -20,9 +20,9 @@
#include "Poco/Data/MySQL/MySQL.h"
#include "Poco/Data/DataException.h"
#include <mysql/mysql.h>
#include <typeinfo>
#include <string>
#include <mysql.h>
namespace Poco {

View File

@@ -18,9 +18,9 @@
#define Data_MySQL_ResultMetadata_INCLUDED
#include <mysql.h>
#include <vector>
#include "Poco/Data/MetaColumn.h"
#include <mysql/mysql.h>
#include <vector>
#if LIBMYSQL_VERSION_ID >= 80000

View File

@@ -18,8 +18,8 @@
#define Data_MySQL_SessionHandle_INCLUDED
#include <mysql.h>
#include "Poco/Data/MySQL/MySQLException.h"
#include <mysql/mysql.h>
namespace Poco {

View File

@@ -18,8 +18,8 @@
#define Data_MySQL_StatementHandle_INCLUDED
#include <mysql.h>
#include "Poco/Data/MySQL/MySQLException.h"
#include <mysql/mysql.h>
namespace Poco {
@@ -66,7 +66,7 @@ public:
/// Fetches the column.
int getAffectedRowCount() const;
operator MYSQL_STMT* ();
/// Cast operator to native handle type.

View File

@@ -20,7 +20,7 @@
#include "Poco/Data/MySQL/MySQL.h"
#include "Poco/Data/Session.h"
#include <mysql.h>
#include <mysql/mysql.h>
namespace Poco {

View File

@@ -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)
{
poco_assert(dir == PD_IN);

View File

@@ -16,7 +16,7 @@
#include "Poco/Data/MySQL/SessionImpl.h"
#include "Poco/Data/SessionFactory.h"
#include "Poco/Exception.h"
#include <mysql.h>
#include <mysql/mysql.h>
namespace Poco {
@@ -46,7 +46,7 @@ const std::string& Connector::name() const
Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::string& connectionString,
std::size_t timeout)
{
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString, timeout));
return Poco::AutoPtr<Poco::Data::SessionImpl>(new SessionImpl(connectionString, timeout));
}

View File

@@ -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)
{
return false;

View File

@@ -12,8 +12,13 @@
//
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "Poco/Data/MySQL/MySQLException.h"
#include <mysql.h>
#include <mysql/mysql.h>
#include <stdio.h>

View File

@@ -183,6 +183,7 @@ void SessionHandle::rollback()
void SessionHandle::reset()
{
//#if ((defined (MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID >= 50700)) || ((defined (MARIADB_PACKAGE_VERSION_ID)) && (MARIADB_PACKAGE_VERSION_ID >= 30000))
#if ((POCO_OS == POCO_OS_LINUX) && defined (HAVE_MYSQL_RESET_CONNECTION)) && (((defined (MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID >= 50700)) || ((defined (MARIADB_PACKAGE_VERSION_ID)) && (MARIADB_PACKAGE_VERSION_ID >= 30000)))
if (mysql_reset_connection(_pHandle) != 0)
#else

View File

@@ -12,9 +12,9 @@
//
#include <mysql.h>
#include "Poco/Data/MySQL/StatementExecutor.h"
#include "Poco/Format.h"
#include <mysql/mysql.h>
namespace Poco {
@@ -52,7 +52,7 @@ void StatementExecutor::prepare(const std::string& query)
_state = STMT_COMPILED;
return;
}
int rc = mysql_stmt_prepare(_pHandle, query.c_str(), static_cast<unsigned int>(query.length()));
if (rc != 0)
{
@@ -119,7 +119,7 @@ bool StatementExecutor::fetch()
int res = mysql_stmt_fetch(_pHandle);
// we have specified zero buffers for BLOBs, so DATA_TRUNCATED is normal in this case
if ((res != 0) && (res != MYSQL_NO_DATA) && (res != MYSQL_DATA_TRUNCATED))
if ((res != 0) && (res != MYSQL_NO_DATA) && (res != MYSQL_DATA_TRUNCATED))
throw StatementException("mysql_stmt_fetch error", _pHandle, _query);
return (res == 0) || (res == MYSQL_DATA_TRUNCATED);

View File

@@ -15,7 +15,7 @@
#include "Poco/Data/MySQL/Utility.h"
#include <mysql.h>
#include <mysql/mysql.h>
namespace Poco {

View File

@@ -6,10 +6,10 @@
include $(POCO_BASE)/build/rules/global
INCLUDE += -I./../include -I/usr/local/include/mysql -I/usr/include/mysql/ -I/usr/mysql/include/mysql -I/usr/local/mysql/include
include $(POCO_BASE)/Data/MySQL/MySQL.make
# Note: linking order is important, do not change it.
SYSLIBS += -L/usr/local/lib -L/usr/local/lib$(LIB64SUFFIX)/mysql -L/usr/lib$(LIB64SUFFIX)/mysql -L/usr/mysql/lib$(LIB64SUFFIX) -L/usr/mysql/lib$(LIB64SUFFIX)/mysql -L/usr/local/mysql/lib$(LIB64SUFFIX) -lmysqlclient -lz -lpthread -ldl
SYSLIBS += -lmysqlclient -lz -lpthread -ldl
objects = MySQLTestSuite Driver MySQLTest SQLExecutor

View File

@@ -45,7 +45,9 @@ Poco::SharedPtr<SQLExecutor> MySQLTest::_pExecutor = 0;
#define MYSQL_USER "pocotest"
#define MYSQL_PWD "pocotest"
#define MYSQL_HOST "127.0.0.1"
#ifndef MYSQL_PORT
#define MYSQL_PORT 3306
#endif
#define MYSQL_DB "pocotest"
//
@@ -494,6 +496,15 @@ void MySQLTest::testDouble()
}
void MySQLTest::testUUID()
{
if (!_pSession) fail ("Test not available.");
recreateUUIDsTable();
_pExecutor->uuids();
}
void MySQLTest::testTuple()
{
if (!_pSession) fail ("Test not available.");
@@ -777,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()
{
dropTable("Tuples");
@@ -902,6 +922,7 @@ CppUnit::Test* MySQLTest::suite()
CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts);
CppUnit_addTest(pSuite, MySQLTest, testFloat);
CppUnit_addTest(pSuite, MySQLTest, testDouble);
CppUnit_addTest(pSuite, MySQLTest, testUUID);
CppUnit_addTest(pSuite, MySQLTest, testTuple);
CppUnit_addTest(pSuite, MySQLTest, testTupleVector);
CppUnit_addTest(pSuite, MySQLTest, testInternalExtraction);

View File

@@ -24,7 +24,7 @@
class MySQLTest: public CppUnit::TestCase
/// MySQL test class
/// Tested:
///
///
/// Driver | DB | OS
/// ----------------+---------------------------+------------------------------------------
/// 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 testDouble();
void testUUID();
void testTuple();
void testTupleVector();
@@ -119,6 +121,7 @@ private:
void recreateIntsTable();
void recreateUnsignedIntsTable();
void recreateFloatsTable();
void recreateUUIDsTable();
void recreateTuplesTable();
void recreateVectorsTable();
void recreateNullableIntTable();

View File

@@ -11,6 +11,7 @@
#include "MySQLTestSuite.h"
#include "MySQLTest.h"
CppUnit::Test* MySQLTestSuite::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("MySQLTestSuite");

View File

@@ -27,9 +27,9 @@
#ifdef _WIN32
#include <Winsock2.h>
#endif
#endif
#include <mysql.h>
#include <mysql/mysql.h>
#include <iostream>
#include <limits>
@@ -141,7 +141,7 @@ private:
} } // namespace Poco::Data
SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession):
SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession):
CppUnit::TestCase(name),
_pSession(pSession)
{
@@ -161,22 +161,22 @@ void SQLExecutor::bareboneMySQLTest(const char* host, const char* user, const ch
MYSQL* tmp = mysql_real_connect(hsession, host, user, pwd, db, port, 0, 0);
assertTrue (tmp == hsession);
MYSQL_STMT* hstmt = mysql_stmt_init(hsession);
assertTrue (hstmt != 0);
std::string sql = "DROP TABLE Test";
mysql_real_query(hsession, sql.c_str(), static_cast<unsigned long>(sql.length()));
sql = tableCreateString;
rc = mysql_stmt_prepare(hstmt, sql.c_str(), static_cast<unsigned long>(sql.length()));
rc = mysql_stmt_prepare(hstmt, sql.c_str(), static_cast<unsigned long>(sql.length()));
assertTrue (rc == 0);
rc = mysql_stmt_execute(hstmt);
assertTrue (rc == 0);
sql = "INSERT INTO Test VALUES (?,?,?,?,?)";
rc = mysql_stmt_prepare(hstmt, sql.c_str(), static_cast<unsigned long>(sql.length()));
rc = mysql_stmt_prepare(hstmt, sql.c_str(), static_cast<unsigned long>(sql.length()));
assertTrue (rc == 0);
std::string str[3] = { "111", "222", "333" };
@@ -219,7 +219,7 @@ void SQLExecutor::bareboneMySQLTest(const char* host, const char* user, const ch
fifth = 0.0f;
MYSQL_BIND bind_result[5] = {{0}};
bind_result[0].buffer = chr[0];
bind_result[0].buffer_length = sizeof(chr[0]);
bind_result[0].buffer_type = MYSQL_TYPE_STRING;
@@ -279,15 +279,15 @@ void SQLExecutor::simpleAccess()
std::string result;
count = 0;
try
{
try
{
Statement stmt(*_pSession);
stmt << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age);//, now;
stmt << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age);//, now;
stmt.execute();
}
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
try { *_pSession << "SELECT COUNT(*) FROM Person", 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); }
@@ -545,11 +545,34 @@ 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()
{
std::string funct = "insertSingleBulkVec()";
std::vector<int> data;
for (int x = 0; x < 100; ++x)
data.push_back(x);
@@ -938,7 +961,7 @@ void SQLExecutor::multiMapComplex()
people.insert(std::make_pair("LN1", p1));
people.insert(std::make_pair("LN1", p1));
people.insert(std::make_pair("LN2", p2));
try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
@@ -1000,7 +1023,7 @@ void SQLExecutor::selectIntoSingleStep()
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
assertTrue (count == 2);
Person result;
Statement stmt = (*_pSession << "SELECT * FROM Person", into(result), limit(1));
Statement stmt = (*_pSession << "SELECT * FROM Person", into(result), limit(1));
stmt.execute();
assertTrue (result == p1);
assertTrue (!stmt.done());
@@ -1264,7 +1287,7 @@ void SQLExecutor::dateTime()
std::string firstName("Simpson");
std::string address("Springfield");
DateTime birthday(1980, 4, 1, 5, 45, 12, 354, 879);
int count = 0;
try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(birthday), now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
@@ -1273,14 +1296,14 @@ void SQLExecutor::dateTime()
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);
DateTime bd;
assertTrue (bd != birthday);
try { *_pSession << "SELECT Birthday FROM Person", into(bd), now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
assertTrue (bd == birthday);
std::cout << std::endl << RecordSet(*_pSession, "SELECT * FROM Person");
}
@@ -1292,7 +1315,7 @@ void SQLExecutor::date()
std::string firstName("Simpson");
std::string address("Springfield");
Date birthday(1980, 4, 1);
int count = 0;
try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(birthday), now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
@@ -1301,14 +1324,14 @@ void SQLExecutor::date()
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);
Date bd;
assertTrue (bd != birthday);
try { *_pSession << "SELECT Birthday FROM Person", into(bd), now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
assertTrue (bd == birthday);
std::cout << std::endl << RecordSet(*_pSession, "SELECT * FROM Person");
}
@@ -1320,7 +1343,7 @@ void SQLExecutor::time()
std::string firstName("Simpson");
std::string address("Springfield");
Time birthday(1, 2, 3);
int count = 0;
try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(birthday), now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
@@ -1329,14 +1352,14 @@ void SQLExecutor::time()
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);
Time bd;
assertTrue (bd != birthday);
try { *_pSession << "SELECT Birthday FROM Person", into(bd), now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
assertTrue (bd == birthday);
std::cout << std::endl << RecordSet(*_pSession, "SELECT * FROM Person");
}
@@ -1436,7 +1459,7 @@ void SQLExecutor::tupleVector()
typedef Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> TupleType;
std::string funct = "tupleVector()";
TupleType t(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int>
Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int>
t10(10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29);
TupleType t100(100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119);
std::vector<TupleType> v;
@@ -1475,8 +1498,8 @@ void SQLExecutor::internalExtraction()
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
try
{
try
{
Statement stmt = (*_pSession << "SELECT * FROM Vectors", now);
RecordSet rset(stmt);
@@ -1523,7 +1546,7 @@ void SQLExecutor::internalExtraction()
assertTrue ("5" == s);
i = rset.value("str0", 2);
assertTrue (5 == i);
const Column<int>& col = rset.column<int>(0);
Column<int>::Iterator it = col.begin();
Column<int>::Iterator end = col.end();
@@ -1563,7 +1586,7 @@ void SQLExecutor::internalExtraction()
try { rset.value<std::string>(0,0); fail ("must fail"); }
catch (BadCastException&) { }
stmt = (*_pSession << "DELETE FROM Vectors", now);
rset = stmt;
@@ -1579,10 +1602,10 @@ void SQLExecutor::internalExtraction()
void SQLExecutor::doNull()
{
std::string funct = "null()";
*_pSession << "INSERT INTO Vectors VALUES (?, ?, ?)",
use(Poco::Data::Keywords::null),
use(Poco::Data::Keywords::null),
*_pSession << "INSERT INTO Vectors VALUES (?, ?, ?)",
use(Poco::Data::Keywords::null),
use(Poco::Data::Keywords::null),
use(Poco::Data::Keywords::null), now;
int count = 0;
@@ -1615,19 +1638,19 @@ void SQLExecutor::doNull()
void SQLExecutor::setTransactionIsolation(Session& session, Poco::UInt32 ti)
{
{
if (session.hasTransactionIsolation(ti))
{
std::string funct = "setTransactionIsolation()";
try
try
{
Transaction t(session, false);
t.setIsolation(ti);
assertTrue (ti == t.getIsolation());
assertTrue (t.isIsolation(ti));
assertTrue (ti == session.getTransactionIsolation());
assertTrue (session.isTransactionIsolation(ti));
}
@@ -1789,11 +1812,11 @@ void SQLExecutor::transaction(const std::string& connect)
Transaction trans((*_pSession));
assertTrue (trans.isActive());
assertTrue (_pSession->isTransaction());
try { (*_pSession) << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; }
catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
assertTrue (_pSession->isTransaction());
assertTrue (trans.isActive());
@@ -1885,7 +1908,7 @@ void SQLExecutor::transaction(const std::string& connect)
assertTrue (0 == count);
trans.execute(sql);
local << "SELECT COUNT(*) FROM Person", into(locCount), now;
assertTrue (2 == locCount);
@@ -1921,9 +1944,9 @@ void SQLExecutor::reconnect()
assertTrue (_pSession->isConnected());
_pSession->close();
assertTrue (!_pSession->isConnected());
try
try
{
(*_pSession) << "SELECT LastName FROM Person", into(result), now;
(*_pSession) << "SELECT LastName FROM Person", into(result), now;
fail ("must fail");
}
catch(NotConnectedException&){ }

View File

@@ -26,7 +26,7 @@ public:
PB_IMMEDIATE,
PB_AT_EXEC
};
enum DataExtraction
{
DE_MANUAL,
@@ -37,7 +37,7 @@ public:
~SQLExecutor();
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).
/// The purpose of the function is to verify that driver behaves
/// correctly. If this test passes, subsequent tests failures are likely ours.
@@ -86,6 +86,7 @@ public:
void unsignedInts();
void floats();
void doubles();
void uuids();
void tuples();
void tupleVector();

View File

@@ -56,9 +56,6 @@ else ifeq (0, $(shell test -e $(POCO_ODBC_LIB)/libiodbc$(LIBLINKEXT); echo $$?))
SYSLIBS += -liodbc -liodbcinst
COMMONFLAGS += -DPOCO_IODBC -I/usr/include/iodbc
# TODO: OSX >= 10.8 deprecated non-Unicode ODBC API functions, silence warnings until iODBC Unicode support
COMMONFLAGS += -Wno-deprecated-declarations
else
$(error No ODBC library found. Please install unixODBC or iODBC or specify POCO_ODBC_LIB and try again)
endif

View File

@@ -322,6 +322,9 @@ public:
void bind(std::size_t pos, const std::list<DateTime>& val, Direction dir);
/// 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);
/// Binds a null. In-bound only.
@@ -367,6 +370,7 @@ private:
typedef std::vector<AnyVec> AnyVecVec;
typedef std::map<char*, std::string*> StringMap;
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_TIME_STRUCT*, Time*> TimeMap;
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
@@ -998,6 +1002,7 @@ private:
TimestampMap _timestamps;
StringMap _strings;
UTF16StringMap _utf16Strings;
UUIDMap _uuids;
DateVecVec _dateVecVec;
TimeVecVec _timeVecVec;

View File

@@ -18,13 +18,13 @@
#define Data_ODBC_Extractor_INCLUDED
#include "Poco/Data/Constants.h"
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/AbstractExtractor.h"
#include "Poco/Data/ODBC/Preparator.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Error.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/AbstractExtractor.h"
#include "Poco/Data/Constants.h"
#include "Poco/Data/Date.h"
#include "Poco/Data/Time.h"
#include "Poco/DateTime.h"
@@ -32,6 +32,8 @@
#include "Poco/Dynamic/Var.h"
#include "Poco/Nullable.h"
#include "Poco/UTFString.h"
#include "Poco/TextEncoding.h"
#include "Poco/TextConverter.h"
#include "Poco/Exception.h"
#include <map>
#ifdef POCO_OS_FAMILY_WINDOWS
@@ -52,8 +54,9 @@ class ODBC_API Extractor: public Poco::Data::AbstractExtractor
public:
typedef Preparator::Ptr PreparatorPtr;
Extractor(const StatementHandle& rStmt,
Preparator::Ptr pPreparator);
Extractor(const StatementHandle& rStmt,
Preparator::Ptr pPreparator,
Poco::TextEncoding::Ptr pDBEncoding = nullptr);
/// Creates the Extractor.
~Extractor();
@@ -304,7 +307,10 @@ public:
bool extract(std::size_t pos, std::list<Poco::DateTime>& val);
/// 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);
/// Extracts an Any.
@@ -339,7 +345,7 @@ public:
/// Returns true if the value at [col,row] is null.
void reset();
/// Resets the internally cached length indicators.
/// Resets the internally cached length indicators.
private:
static const int CHUNK_SIZE = 1024;
@@ -365,7 +371,7 @@ private:
{
if (isNull(pos)) return false;
poco_assert_dbg (typeid(T) == _pPreparator->at(pos).type());
val = *AnyCast<T>(&_pPreparator->at(pos));
val = *AnyCast<T>(&_pPreparator->at(pos));
return true;
}
@@ -384,7 +390,7 @@ private:
bool extractBoundImplContainer(std::size_t pos, std::vector<std::string>& values);
bool extractBoundImplContainer(std::size_t pos, std::deque<std::string>& values);
bool extractBoundImplContainer(std::size_t pos, std::list<std::string>& values);
bool extractBoundImplContainer(std::size_t pos, std::list<std::string>& values);
bool extractBoundImplContainer(std::size_t pos, std::vector<Poco::UTF16String>& values);
bool extractBoundImplContainer(std::size_t pos, std::deque<Poco::UTF16String>& values);
bool extractBoundImplContainer(std::size_t pos, std::list<Poco::UTF16String>& values);
@@ -462,12 +468,12 @@ private:
bool extractManualImpl(std::size_t pos, T& val, SQLSMALLINT cType)
{
SQLRETURN rc = 0;
T value = (T) 0;
T value{};
resizeLengths(pos);
rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
cType, //C data type
&value, //returned value
0, //buffer length (ignored)
@@ -475,10 +481,10 @@ private:
if (Utility::isError(rc))
throw StatementException(_rStmt, "SQLGetData()");
if (isNullLengthIndicator(_lengths[pos]))
if (isNullLengthIndicator(_lengths[pos]))
return false;
else
else
{
//for fixed-length data, buffer must be large enough
//otherwise, driver may write past the end
@@ -567,16 +573,53 @@ private:
case MetaColumn::FDT_TIMESTAMP:
{ return extAny<T, Poco::DateTime>(pos, val); }
default:
case MetaColumn::FDT_UUID:
{ return extAny<T, Poco::UUID>(pos, val); }
default:
throw DataFormatException("Unsupported data type.");
}
return false;
}
template <typename C>
bool stringContainerExtractConvert(std::size_t pos, C& val)
{
bool ret = false;
C res;
ret = extractBoundImplContainer(pos, res);
val.clear();
if (ret)
{
Poco::TextConverter conv(*_pDBEncoding, *_pToEncoding);
val.resize(res.size());
typename C::iterator vIt = val.begin();
typename C::iterator it = res.begin();
for (; it != res.end(); ++it, ++vIt) conv.convert(*it, *vIt);
}
return ret;
}
template <typename C>
bool stringContainerExtract(std::size_t pos, C& val)
{
bool ret = false;
if (Preparator::DE_BOUND == _dataExtraction)
{
if (!_transcode)
ret = extractBoundImplContainer(pos, val);
else
ret = stringContainerExtractConvert(pos, val);
}
else
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
return ret;
}
bool isNullLengthIndicator(SQLLEN val) const;
/// The reason for this utility wrapper are platforms where
/// SQLLEN macro (a.k.a. SQLINTEGER) yields 64-bit value,
/// The reason for this utility wrapper are platforms where
/// SQLLEN macro (a.k.a. SQLINTEGER) yields 64-bit value,
/// while SQL_NULL_DATA (#define'd as -1 literal) remains 32-bit.
SQLINTEGER columnSize(std::size_t pos) const;
@@ -585,6 +628,9 @@ private:
PreparatorPtr _pPreparator;
Preparator::DataExtraction _dataExtraction;
std::vector<SQLLEN> _lengths;
Poco::TextEncoding::Ptr _pDBEncoding;
bool _transcode;
Poco::TextEncoding::Ptr _pToEncoding;
};
@@ -640,42 +686,42 @@ inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<Poco
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
std::vector<Poco::Data::CLOB>& values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
std::deque<Poco::Data::CLOB>& values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
std::list<Poco::Data::CLOB>& values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
std::vector<Poco::Data::BLOB>& values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
std::deque<Poco::Data::BLOB>& values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
inline bool Extractor::extractBoundImplContainer(std::size_t pos,
std::list<Poco::Data::BLOB>& values)
{
return extractBoundImplContainerLOB(pos, values);
@@ -702,7 +748,7 @@ inline void Extractor::reset()
inline void Extractor::resizeLengths(std::size_t pos)
{
if (pos >= _lengths.size())
if (pos >= _lengths.size())
_lengths.resize(pos + 1, (SQLLEN) 0);
}

View File

@@ -136,8 +136,6 @@ private:
/// Called whenever SQLExecute returns SQL_NEED_DATA. This is expected
/// behavior for PB_AT_EXEC binding mode.
void getData();
void addPreparator();
void fillColumns();
void checkError(SQLRETURN rc, const std::string& msg="");

View File

@@ -18,12 +18,12 @@
#define Data_ODBC_Preparator_INCLUDED
#include "Poco/Data/Constants.h"
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/AbstractPreparator.h"
#include "Poco/Data/Constants.h"
#include "Poco/Data/LOB.h"
#include "Poco/Any.h"
#include "Poco/DynamicAny.h"
@@ -49,13 +49,13 @@ namespace ODBC {
class ODBC_API Preparator : public AbstractPreparator
/// Class used for database preparation where we first have to register all data types
/// with respective memory output locations before extracting data.
/// Class used for database preparation where we first have to register all data types
/// with respective memory output locations before extracting data.
/// Extraction works in two-phases: first prepare is called once, then extract n-times.
/// In ODBC, SQLBindCol/SQLFetch is the preferred method of data retrieval (SQLGetData is available,
/// however with numerous driver implementation dependent limitations and inferior performance).
/// In order to fit this functionality into Poco DataConnectors framework, every ODBC SQL statement
/// instantiates its own Preparator object.
/// In ODBC, SQLBindCol/SQLFetch is the preferred method of data retrieval (SQLGetData is available,
/// however with numerous driver implementation dependent limitations and inferior performance).
/// In order to fit this functionality into Poco DataConnectors framework, every ODBC SQL statement
/// instantiates its own Preparator object.
/// This is done once per statement execution (from StatementImpl::bindImpl()).
///
/// Preparator object is used to :
@@ -69,7 +69,7 @@ class ODBC_API Preparator : public AbstractPreparator
/// - Value datatypes in this interface prepare() calls serve only for the purpose of type distinction.
/// - Preparator keeps its own std::vector<Any> buffer for fetched data to be later retrieved by Extractor.
/// - prepare() methods should not be called when extraction mode is DE_MANUAL
///
///
{
public:
typedef std::vector<char*> CharArray;
@@ -96,8 +96,8 @@ public:
DT_DATETIME
};
Preparator(const StatementHandle& rStmt,
const std::string& statement,
Preparator(const StatementHandle& rStmt,
const std::string& statement,
std::size_t maxFieldSize,
DataExtraction dataExtraction = DE_BOUND);
/// Creates the Preparator.
@@ -353,6 +353,9 @@ public:
void prepare(std::size_t pos, const std::list<Poco::DateTime>& val);
/// 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);
/// Prepares an Any.
@@ -395,12 +398,12 @@ public:
std::size_t maxDataSize(std::size_t pos) const;
/// Returns max supported size for column at position pos.
/// Returned length for variable length fields is the one
/// Returned length for variable length fields is the one
/// supported by this implementation, not the underlying DB.
std::size_t actualDataSize(std::size_t col, std::size_t row = POCO_DATA_INVALID_ROW) const;
/// Returns the returned length for the column and row specified.
/// This is usually equal to the column size, except for
/// Returns the returned length for the column and row specified.
/// This is usually equal to the column size, except for
/// variable length fields (BLOB and variable length strings).
/// For null values, the return value is -1 (SQL_NO_DATA)
@@ -435,7 +438,7 @@ private:
if (pVal)
return prepareFixedSize<Poco::Int8>(pos, SQL_C_STINYINT, pVal->size());
else
return prepareFixedSize<Poco::Int8>(pos, SQL_C_STINYINT);
return prepareFixedSize<Poco::Int8>(pos, SQL_C_STINYINT);
case MetaColumn::FDT_UINT8:
if (pVal)
@@ -548,7 +551,13 @@ private:
else
return prepareFixedSize<DateTime>(pos, SQL_C_TYPE_TIMESTAMP);
default:
case MetaColumn::FDT_UUID:
if (pVal)
return prepareFixedSize<DateTime>(pos, SQL_C_BINARY, 16);
else
return prepareFixedSize<DateTime>(pos, SQL_C_BINARY);
default:
throw DataFormatException("Unsupported data type.");
}
}
@@ -567,11 +576,11 @@ private:
_values[pos] = Poco::Any(T());
T* pVal = AnyCast<T>(&_values[pos]);
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pVal,
(SQLINTEGER) dataSize,
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pVal,
(SQLINTEGER) dataSize,
&_lengths[pos])))
{
throw StatementException(_rStmt, "SQLBindCol()");
@@ -596,11 +605,11 @@ private:
std::vector<T>& cache = RefAnyCast<std::vector<T> >(_values[pos]);
cache.resize(length);
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) &cache[0],
(SQLINTEGER) dataSize,
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) &cache[0],
(SQLINTEGER) dataSize,
&_lenLengths[pos][0])))
{
throw StatementException(_rStmt, "SQLBindCol()");
@@ -614,18 +623,18 @@ private:
poco_assert (DE_BOUND == _dataExtraction);
poco_assert (pos < _values.size());
T* pCache = new T[size];
T* pCache = new T[size];
std::memset(pCache, 0, size);
_values[pos] = Any(pCache);
_lengths[pos] = (SQLLEN) size;
_varLengthArrays.insert(IndexMap::value_type(pos, dt));
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pCache,
(SQLINTEGER) size*sizeof(T),
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pCache,
(SQLINTEGER) size*sizeof(T),
&_lengths[pos])))
{
throw StatementException(_rStmt, "SQLBindCol()");
@@ -648,11 +657,11 @@ private:
_lenLengths[pos].resize(length);
_varLengthArrays.insert(IndexMap::value_type(pos, DT));
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pArray,
(SQLINTEGER) size,
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pArray,
(SQLINTEGER) size,
&_lenLengths[pos][0])))
{
throw StatementException(_rStmt, "SQLBindCol()");
@@ -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)
{
prepareImpl<std::vector<Poco::Any> >(pos);

View File

@@ -25,6 +25,7 @@
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/AbstractSessionImpl.h"
#include "Poco/TextEncoding.h"
#include "Poco/SharedPtr.h"
#include "Poco/Mutex.h"
#ifdef POCO_OS_FAMILY_WINDOWS
@@ -162,6 +163,16 @@ public:
/// Returns the timeout (in seconds) for queries,
/// or -1 if no timeout has been set.
void setDBEncoding(const std::string&, const Poco::Any& value);
/// Sets the database encoding.
/// Value must be of type std::string.
Poco::Any getDBEncoding(const std::string&) const;
/// Returns the database encoding.
const std::string& dbEncoding() const;
/// Returns the database encoding.
const ConnectionHandle& dbc() const;
/// Returns the connection handle.
@@ -193,6 +204,7 @@ private:
mutable char _canTransact;
bool _inTransaction;
int _queryTimeout;
std::string _dbEncoding;
Poco::FastMutex _mutex;
};
@@ -291,6 +303,18 @@ inline int SessionImpl::queryTimeout() const
}
inline Poco::Any SessionImpl::getDBEncoding(const std::string&) const
{
return _dbEncoding;
}
inline const std::string& SessionImpl::dbEncoding() const
{
return _dbEncoding;
}
} } } // namespace Poco::Data::ODBC

View File

@@ -47,7 +47,14 @@ inline void makeUTF8(Poco::Buffer<wchar_t>& buffer, SQLINTEGER length, SQLPOINTE
UnicodeConverter::toUTF8(buffer.begin(), length, result);
std::memset(pTarget, 0, targetLength);
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4996) // deprecation warnings
#endif
std::strncpy((char*) pTarget, result.c_str(), result.size() < targetLength ? result.size() : targetLength);
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}

View File

@@ -80,6 +80,10 @@ void Binder::freeMemory()
UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end();
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 endBool = _boolPtrs.end();
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);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_CHAR,
Connector::stringBoundToLongVarChar() ? SQL_LONGVARCHAR : SQL_VARCHAR,
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_CHAR,
Connector::stringBoundToLongVarChar() ? SQL_LONGVARCHAR : SQL_VARCHAR,
(SQLUINTEGER) colSize,
0,
pVal,
(SQLINTEGER) size,
pVal,
(SQLINTEGER) size,
_lengthIndicator.back())))
{
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;
Utility::dateSync(*pDS, val);
_dates.insert(DateMap::value_type(pDS, const_cast<Date*>(&val)));
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_TYPE_DATE, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_DATE,
SQL_TYPE_DATE,
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_DATE,
SQL_TYPE_DATE,
colSize,
decDigits,
(SQLPOINTER) pDS,
0,
(SQLPOINTER) pDS,
0,
_lengthIndicator.back())))
{
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;
Utility::timeSync(*pTS, val);
_times.insert(TimeMap::value_type(pTS, const_cast<Time*>(&val)));
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_TYPE_TIME, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_TIME,
SQL_TYPE_TIME,
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_TIME,
SQL_TYPE_TIME,
colSize,
decDigits,
(SQLPOINTER) pTS,
0,
(SQLPOINTER) pTS,
0,
_lengthIndicator.back())))
{
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;
getColSizeAndPrecision(pos, SQL_TYPE_TIMESTAMP, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_TIMESTAMP,
SQL_TYPE_TIMESTAMP,
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_TIMESTAMP,
SQL_TYPE_TIMESTAMP,
colSize,
decDigits,
(SQLPOINTER) pTS,
0,
(SQLPOINTER) pTS,
0,
_lengthIndicator.back())))
{
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)
{
if (isOutBound(dir) || !isInBound(dir))
@@ -311,15 +347,15 @@ void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
SQL_PARAM_INPUT,
SQL_C_STINYINT,
Utility::sqlDataType(SQL_C_STINYINT),
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
SQL_PARAM_INPUT,
SQL_C_STINYINT,
Utility::sqlDataType(SQL_C_STINYINT),
colSize,
decDigits,
0,
0,
0,
0,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter()");
@@ -334,7 +370,7 @@ std::size_t Binder::parameterSize(SQLPOINTER pAddr) const
it = _outParams.find(pAddr);
if (it != _outParams.end()) return it->second;
throw NotFoundException("Requested data size not found.");
}
@@ -350,7 +386,7 @@ SQLSMALLINT Binder::toODBCDirection(Direction dir) const
bool in = isInBound(dir);
bool out = isOutBound(dir);
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(out) ioType = SQL_PARAM_OUTPUT;
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 end = _dates.end();
for(; it != end; ++it)
for(; it != end; ++it)
Utility::dateSync(*it->second, *it->first);
}
@@ -373,7 +409,7 @@ void Binder::synchronize()
{
TimeMap::iterator it = _times.begin();
TimeMap::iterator end = _times.end();
for(; it != end; ++it)
for(; it != end; ++it)
Utility::timeSync(*it->second, *it->first);
}
@@ -381,7 +417,7 @@ void Binder::synchronize()
{
TimestampMap::iterator it = _timestamps.begin();
TimestampMap::iterator end = _timestamps.end();
for(; it != end; ++it)
for(; it != end; ++it)
Utility::dateTimeSync(*it->second, *it->first);
}
@@ -392,6 +428,14 @@ void Binder::synchronize()
for(; it != end; ++it)
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();
_timestamps.clear();
_strings.clear();
_uuids.clear();
_dateVecVec.clear();
_timeVecVec.clear();
_dateTimeVecVec.clear();
@@ -415,9 +460,9 @@ void Binder::reset()
}
void Binder::getColSizeAndPrecision(std::size_t pos,
SQLSMALLINT cDataType,
SQLINTEGER& colSize,
void Binder::getColSizeAndPrecision(std::size_t pos,
SQLSMALLINT cDataType,
SQLINTEGER& colSize,
SQLSMALLINT& decDigits,
std::size_t actualSize)
{
@@ -448,9 +493,9 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
colSize = (SQLINTEGER) p.columnSize();
decDigits = (SQLSMALLINT) p.decimalDigits();
return;
}
}
catch (StatementException&)
{
{
}
try
@@ -459,9 +504,9 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
colSize = (SQLINTEGER) c.length();
decDigits = (SQLSMALLINT) c.precision();
return;
}
catch (StatementException&)
{
}
catch (StatementException&)
{
}
// 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)))
{
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)
{
size = sz;
@@ -529,7 +574,7 @@ void Binder::setParamSetSize(std::size_t length)
{
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)))
throw StatementException(_rStmt, "SQLSetStmtAttr()");

View File

@@ -12,13 +12,13 @@
//
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/Extractor.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/LOB.h"
#include "Poco/Buffer.h"
#include "Poco/Exception.h"
#include <typeinfo>
@@ -33,11 +33,15 @@ const std::string Extractor::FLD_SIZE_EXCEEDED_FMT = "Specified data size (%z by
"to increase the maximum allowed data size\n";
Extractor::Extractor(const StatementHandle& rStmt,
Preparator::Ptr pPreparator):
_rStmt(rStmt),
Extractor::Extractor(const StatementHandle& rStmt,
Preparator::Ptr pPreparator,
TextEncoding::Ptr pDBEncoding):
_rStmt(rStmt),
_pPreparator(pPreparator),
_dataExtraction(pPreparator->getDataExtraction())
_dataExtraction(pPreparator->getDataExtraction()),
_pDBEncoding(pDBEncoding),
_transcode(_pDBEncoding && !_pDBEncoding->isA("UTF-8")),
_pToEncoding(_transcode ? Poco::TextEncoding::find("UTF-8") : nullptr)
{
}
@@ -106,7 +110,7 @@ bool Extractor::extractBoundImpl<Poco::Data::Date>(std::size_t pos, Poco::Data::
template<>
bool Extractor::extractBoundImplContainer<std::vector<Poco::Data::Date> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::vector<Poco::Data::Date> >(std::size_t pos,
std::vector<Poco::Data::Date>& val)
{
std::vector<SQL_DATE_STRUCT>& ds = RefAnyCast<std::vector<SQL_DATE_STRUCT> >(_pPreparator->at(pos));
@@ -116,7 +120,7 @@ bool Extractor::extractBoundImplContainer<std::vector<Poco::Data::Date> >(std::s
template<>
bool Extractor::extractBoundImplContainer<std::deque<Poco::Data::Date> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::deque<Poco::Data::Date> >(std::size_t pos,
std::deque<Poco::Data::Date>& val)
{
std::vector<SQL_DATE_STRUCT>& ds = RefAnyCast<std::vector<SQL_DATE_STRUCT> >(_pPreparator->at(pos));
@@ -126,7 +130,7 @@ bool Extractor::extractBoundImplContainer<std::deque<Poco::Data::Date> >(std::si
template<>
bool Extractor::extractBoundImplContainer<std::list<Poco::Data::Date> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::list<Poco::Data::Date> >(std::size_t pos,
std::list<Poco::Data::Date>& val)
{
std::vector<SQL_DATE_STRUCT>& ds = RefAnyCast<std::vector<SQL_DATE_STRUCT> >(_pPreparator->at(pos));
@@ -150,7 +154,7 @@ bool Extractor::extractBoundImpl<Poco::Data::Time>(std::size_t pos, Poco::Data::
template<>
bool Extractor::extractBoundImplContainer<std::vector<Poco::Data::Time> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::vector<Poco::Data::Time> >(std::size_t pos,
std::vector<Poco::Data::Time>& val)
{
std::vector<SQL_TIME_STRUCT>& ds = RefAnyCast<std::vector<SQL_TIME_STRUCT> >(_pPreparator->at(pos));
@@ -160,7 +164,7 @@ bool Extractor::extractBoundImplContainer<std::vector<Poco::Data::Time> >(std::s
template<>
bool Extractor::extractBoundImplContainer<std::deque<Poco::Data::Time> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::deque<Poco::Data::Time> >(std::size_t pos,
std::deque<Poco::Data::Time>& val)
{
std::vector<SQL_TIME_STRUCT>& ds = RefAnyCast<std::vector<SQL_TIME_STRUCT> >(_pPreparator->at(pos));
@@ -170,7 +174,7 @@ bool Extractor::extractBoundImplContainer<std::deque<Poco::Data::Time> >(std::si
template<>
bool Extractor::extractBoundImplContainer<std::list<Poco::Data::Time> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::list<Poco::Data::Time> >(std::size_t pos,
std::list<Poco::Data::Time>& val)
{
std::vector<SQL_TIME_STRUCT>& ds = RefAnyCast<std::vector<SQL_TIME_STRUCT> >(_pPreparator->at(pos));
@@ -194,7 +198,7 @@ bool Extractor::extractBoundImpl<Poco::DateTime>(std::size_t pos, Poco::DateTime
template<>
bool Extractor::extractBoundImplContainer<std::vector<Poco::DateTime> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::vector<Poco::DateTime> >(std::size_t pos,
std::vector<Poco::DateTime>& val)
{
std::vector<SQL_TIMESTAMP_STRUCT>& ds = RefAnyCast<std::vector<SQL_TIMESTAMP_STRUCT> >(_pPreparator->at(pos));
@@ -204,7 +208,7 @@ bool Extractor::extractBoundImplContainer<std::vector<Poco::DateTime> >(std::siz
template<>
bool Extractor::extractBoundImplContainer<std::deque<Poco::DateTime> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::deque<Poco::DateTime> >(std::size_t pos,
std::deque<Poco::DateTime>& val)
{
std::vector<SQL_TIMESTAMP_STRUCT>& ds = RefAnyCast<std::vector<SQL_TIMESTAMP_STRUCT> >(_pPreparator->at(pos));
@@ -214,7 +218,7 @@ bool Extractor::extractBoundImplContainer<std::deque<Poco::DateTime> >(std::size
template<>
bool Extractor::extractBoundImplContainer<std::list<Poco::DateTime> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::list<Poco::DateTime> >(std::size_t pos,
std::list<Poco::DateTime>& val)
{
std::vector<SQL_TIMESTAMP_STRUCT>& ds = RefAnyCast<std::vector<SQL_TIMESTAMP_STRUCT> >(_pPreparator->at(pos));
@@ -224,7 +228,21 @@ bool Extractor::extractBoundImplContainer<std::list<Poco::DateTime> >(std::size_
template<>
bool Extractor::extractBoundImplContainer<std::vector<bool> >(std::size_t pos,
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<>
bool Extractor::extractBoundImplContainer<std::vector<bool> >(std::size_t pos,
std::vector<bool>& val)
{
std::size_t length = _pPreparator->getLength();
@@ -235,7 +253,7 @@ bool Extractor::extractBoundImplContainer<std::vector<bool> >(std::size_t pos,
template<>
bool Extractor::extractBoundImplContainer<std::deque<bool> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::deque<bool> >(std::size_t pos,
std::deque<bool>& val)
{
std::size_t length = _pPreparator->getLength();
@@ -246,7 +264,7 @@ bool Extractor::extractBoundImplContainer<std::deque<bool> >(std::size_t pos,
template<>
bool Extractor::extractBoundImplContainer<std::list<bool> >(std::size_t pos,
bool Extractor::extractBoundImplContainer<std::list<bool> >(std::size_t pos,
std::list<bool>& val)
{
std::size_t length = _pPreparator->getLength();
@@ -262,13 +280,13 @@ bool Extractor::extractManualImpl<std::string>(std::size_t pos, std::string& val
std::size_t maxSize = _pPreparator->getMaxFieldSize();
std::size_t fetchedSize = 0;
std::size_t totalSize = 0;
SQLLEN len;
const int bufSize = CHUNK_SIZE;
Poco::Buffer<char> apChar(bufSize);
char* pChar = apChar.begin();
SQLRETURN rc = 0;
val.clear();
resizeLengths(pos);
@@ -276,8 +294,8 @@ bool Extractor::extractManualImpl<std::string>(std::size_t pos, std::string& val
{
std::memset(pChar, 0, bufSize);
len = 0;
rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
cType, //C data type
pChar, //returned value
bufSize, //buffer length
@@ -301,9 +319,9 @@ bool Extractor::extractManualImpl<std::string>(std::size_t pos, std::string& val
_lengths[pos] += len;
fetchedSize = _lengths[pos] > CHUNK_SIZE ? CHUNK_SIZE : _lengths[pos];
totalSize += fetchedSize;
if (totalSize <= maxSize)
if (totalSize <= maxSize)
val.append(pChar, fetchedSize);
else
else
throw DataException(format(FLD_SIZE_EXCEEDED_FMT, fetchedSize, maxSize));
}while (true);
@@ -367,8 +385,8 @@ bool Extractor::extractManualImpl<UTF16String>(std::size_t pos, UTF16String& val
template<>
bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos,
Poco::Data::CLOB& val,
bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos,
Poco::Data::CLOB& val,
SQLSMALLINT cType)
{
std::size_t maxSize = _pPreparator->getMaxFieldSize();
@@ -380,7 +398,7 @@ bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos,
Poco::Buffer<char> apChar(bufSize);
char* pChar = apChar.begin();
SQLRETURN rc = 0;
val.clear();
resizeLengths(pos);
@@ -388,13 +406,13 @@ bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos,
{
std::memset(pChar, 0, bufSize);
len = 0;
rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
cType, //C data type
pChar, //returned value
bufSize, //buffer length
&len); //length indicator
_lengths[pos] += len;
if (SQL_NO_DATA != rc && Utility::isError(rc))
@@ -411,9 +429,9 @@ bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos,
fetchedSize = len > CHUNK_SIZE ? CHUNK_SIZE : len;
totalSize += fetchedSize;
if (totalSize <= maxSize)
if (totalSize <= maxSize)
val.appendRaw(pChar, fetchedSize);
else
else
throw DataException(format(FLD_SIZE_EXCEEDED_FMT, fetchedSize, maxSize));
}while (true);
@@ -423,26 +441,26 @@ bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos,
template<>
bool Extractor::extractManualImpl<Poco::Data::Date>(std::size_t pos,
Poco::Data::Date& val,
bool Extractor::extractManualImpl<Poco::Data::Date>(std::size_t pos,
Poco::Data::Date& val,
SQLSMALLINT cType)
{
SQL_DATE_STRUCT ds;
resizeLengths(pos);
SQLRETURN rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
SQLRETURN rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
cType, //C data type
&ds, //returned value
sizeof(ds), //buffer length
&_lengths[pos]); //length indicator
if (Utility::isError(rc))
throw StatementException(_rStmt, "SQLGetData()");
if (isNullLengthIndicator(_lengths[pos]))
if (isNullLengthIndicator(_lengths[pos]))
return false;
else
else
Utility::dateSync(val, ds);
return true;
@@ -450,26 +468,26 @@ bool Extractor::extractManualImpl<Poco::Data::Date>(std::size_t pos,
template<>
bool Extractor::extractManualImpl<Poco::Data::Time>(std::size_t pos,
Poco::Data::Time& val,
bool Extractor::extractManualImpl<Poco::Data::Time>(std::size_t pos,
Poco::Data::Time& val,
SQLSMALLINT cType)
{
SQL_TIME_STRUCT ts;
resizeLengths(pos);
SQLRETURN rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
SQLRETURN rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
cType, //C data type
&ts, //returned value
sizeof(ts), //buffer length
&_lengths[pos]); //length indicator
if (Utility::isError(rc))
throw StatementException(_rStmt, "SQLGetData()");
if (isNullLengthIndicator(_lengths[pos]))
if (isNullLengthIndicator(_lengths[pos]))
return false;
else
else
Utility::timeSync(val, ts);
return true;
@@ -477,32 +495,59 @@ bool Extractor::extractManualImpl<Poco::Data::Time>(std::size_t pos,
template<>
bool Extractor::extractManualImpl<Poco::DateTime>(std::size_t pos,
Poco::DateTime& val,
bool Extractor::extractManualImpl<Poco::DateTime>(std::size_t pos,
Poco::DateTime& val,
SQLSMALLINT cType)
{
SQL_TIMESTAMP_STRUCT ts;
resizeLengths(pos);
SQLRETURN rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
SQLRETURN rc = SQLGetData(_rStmt,
(SQLUSMALLINT) pos + 1,
cType, //C data type
&ts, //returned value
sizeof(ts), //buffer length
&_lengths[pos]); //length indicator
if (Utility::isError(rc))
throw StatementException(_rStmt, "SQLGetData()");
if (isNullLengthIndicator(_lengths[pos]))
if (isNullLengthIndicator(_lengths[pos]))
return false;
else
else
Utility::dateTimeSync(val, ts);
return true;
}
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)
{
if (Preparator::DE_MANUAL == _dataExtraction)
@@ -660,37 +705,45 @@ bool Extractor::extract(std::size_t pos, std::list<double>& val)
bool Extractor::extract(std::size_t pos, std::string& val)
{
if (Preparator::DE_MANUAL == _dataExtraction)
return extractManualImpl(pos, val, SQL_C_CHAR);
bool ret = false;
if (!_transcode)
{
if (Preparator::DE_MANUAL == _dataExtraction)
ret = extractManualImpl(pos, val, SQL_C_CHAR);
else
ret = extractBoundImpl(pos, val);
}
else
return extractBoundImpl(pos, val);
{
std::string result;
if (Preparator::DE_MANUAL == _dataExtraction)
ret = extractManualImpl(pos, result, SQL_C_CHAR);
else
ret = extractBoundImpl(pos, result);
Poco::TextConverter converter(*_pDBEncoding, *_pToEncoding);
converter.convert(result, val);
}
return ret;
}
bool Extractor::extract(std::size_t pos, std::vector<std::string>& val)
{
if (Preparator::DE_BOUND == _dataExtraction)
return extractBoundImplContainer(pos, val);
else
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
return stringContainerExtract(pos, val);
}
bool Extractor::extract(std::size_t pos, std::deque<std::string>& val)
{
if (Preparator::DE_BOUND == _dataExtraction)
return extractBoundImplContainer(pos, val);
else
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
return stringContainerExtract(pos, val);
}
bool Extractor::extract(std::size_t pos, std::list<std::string>& val)
{
if (Preparator::DE_BOUND == _dataExtraction)
return extractBoundImplContainer(pos, val);
else
throw InvalidAccessException("Direct container extraction only allowed for bound mode.");
return stringContainerExtract(pos, val);
}
@@ -910,6 +963,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)
{
if (Preparator::DE_MANUAL == _dataExtraction)
@@ -1307,10 +1369,10 @@ bool Extractor::isNull(std::size_t col, std::size_t row)
try
{
return isNullLengthIndicator(_lengths.at(col));
}
}
catch (std::out_of_range& ex)
{
throw RangeException(ex.what());
throw RangeException(ex.what());
}
}
else

View File

@@ -102,9 +102,6 @@ void ODBCMetaColumn::init()
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
#ifdef SQL_GUID
case SQL_GUID:
#endif
setType(MetaColumn::FDT_STRING); break;
case SQL_WCHAR:
@@ -168,6 +165,9 @@ void ODBCMetaColumn::init()
case SQL_TYPE_TIMESTAMP:
setType(MetaColumn::FDT_TIMESTAMP); break;
case SQL_GUID:
setType(MetaColumn::FDT_UUID); break;
default:
throw DataFormatException("Unsupported data type.");
}

View File

@@ -145,7 +145,8 @@ void ODBCStatementImpl::addPreparator()
else
_preparations.push_back(new Preparator(*_preparations[0]));
_extractors.push_back(new Extractor(_stmt, _preparations.back()));
_extractors.push_back(new Extractor(_stmt, _preparations.back(),
TextEncoding::find(Poco::RefAnyCast<std::string>(session().getProperty("dbEncoding")))));
}

View File

@@ -25,10 +25,10 @@ namespace Data {
namespace ODBC {
Preparator::Preparator(const StatementHandle& rStmt,
const std::string& statement,
Preparator::Preparator(const StatementHandle& rStmt,
const std::string& statement,
std::size_t maxFieldSize,
DataExtraction dataExtraction):
DataExtraction dataExtraction):
_rStmt(rStmt),
_maxFieldSize(maxFieldSize),
_dataExtraction(dataExtraction)
@@ -39,7 +39,7 @@ Preparator::Preparator(const StatementHandle& rStmt,
}
Preparator::Preparator(const Preparator& other):
Preparator::Preparator(const Preparator& other):
_rStmt(other._rStmt),
_maxFieldSize(other._maxFieldSize),
_dataExtraction(other._dataExtraction)
@@ -151,14 +151,14 @@ std::size_t Preparator::maxDataSize(std::size_t pos) const
std::size_t sz = 0;
std::size_t maxsz = getMaxFieldSize();
try
try
{
ODBCMetaColumn mc(_rStmt, pos);
sz = mc.length();
// accomodate for terminating zero (non-bulk only!)
MetaColumn::ColumnDataType type = mc.type();
if (!isBulk() && ((ODBCMetaColumn::FDT_WSTRING == type) || (ODBCMetaColumn::FDT_STRING == type))) ++sz;
if (sz && !isBulk() && ((ODBCMetaColumn::FDT_WSTRING == type) || (ODBCMetaColumn::FDT_STRING == type))) ++sz;
}
catch (StatementException&) { }
@@ -194,11 +194,11 @@ void Preparator::prepareBoolArray(std::size_t pos, SQLSMALLINT valueType, std::s
_lenLengths[pos].resize(length);
_varLengthArrays.insert(IndexMap::value_type(pos, DT_BOOL_ARRAY));
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pArray,
(SQLINTEGER) sizeof(bool),
if (Utility::isError(SQLBindCol(_rStmt,
(SQLUSMALLINT) pos + 1,
valueType,
(SQLPOINTER) pArray,
(SQLINTEGER) sizeof(bool),
&_lenLengths[pos][0])))
{
throw StatementException(_rStmt, "SQLBindCol()");

View File

@@ -39,7 +39,8 @@ SessionImpl::SessionImpl(const std::string& connect,
_autoExtract(autoExtract),
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
_inTransaction(false),
_queryTimeout(-1)
_queryTimeout(-1),
_dbEncoding("UTF-8")
{
setFeature("bulk", true);
open();
@@ -58,7 +59,8 @@ SessionImpl::SessionImpl(const std::string& connect,
_autoExtract(autoExtract),
_canTransact(ODBC_TXN_CAPABILITY_UNKNOWN),
_inTransaction(false),
_queryTimeout(-1)
_queryTimeout(-1),
_dbEncoding("UTF-8")
{
setFeature("bulk", true);
open();
@@ -158,12 +160,24 @@ void SessionImpl::open(const std::string& connect)
&SessionImpl::setQueryTimeout,
&SessionImpl::getQueryTimeout);
addProperty("dbEncoding",
&SessionImpl::setDBEncoding,
&SessionImpl::getDBEncoding);
Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_ATTR_QUIET_MODE, 0, 0);
if (!canTransact()) autoCommit("", true);
}
void SessionImpl::setDBEncoding(const std::string&, const Poco::Any& value)
{
const std::string& enc = Poco::RefAnyCast<std::string>(value);
Poco::TextEncoding::byName(enc); // throws if not found
_dbEncoding = enc;
}
bool SessionImpl::isConnected() const
{
SQLULEN value = 0;

View File

@@ -612,6 +612,15 @@ void ODBCSQLServerTest::recreateFloatsTable()
}
void ODBCSQLServerTest::recreateUUIDsTable()
{
dropObject("TABLE", "Strings");
try { session() << "CREATE TABLE Strings (str UNIQUEIDENTIFIER)", now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateUUIDsTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateUUIDsTable()"); }
}
void ODBCSQLServerTest::recreateTuplesTable()
{
dropObject("TABLE", "Tuples");
@@ -787,6 +796,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDateTime);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testFloat);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDouble);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testUUID);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTuple);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTupleVector);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredProcedure);

View File

@@ -64,6 +64,7 @@ private:
void recreateStringsTable();
void recreateIntsTable();
void recreateFloatsTable();
void recreateUUIDsTable();
void recreateTuplesTable();
void recreateVectorTable();
void recreateVectorsTable();

View File

@@ -917,6 +917,21 @@ void ODBCTest::testDouble()
}
void ODBCTest::testUUID()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreateUUIDsTable();
_pSession->setFeature("autoBind", bindValue(i));
_pSession->setFeature("autoExtract", bindValue(i+1));
_pExecutor->uuids();
i += 2;
}
}
void ODBCTest::testTuple()
{
if (!_pSession) fail ("Test not available.");

View File

@@ -113,6 +113,8 @@ public:
virtual void testFloat();
virtual void testDouble();
virtual void testUUID();
virtual void testTuple();
virtual void testTupleVector();
@@ -166,6 +168,7 @@ protected:
virtual void recreateStringsTable();
virtual void recreateIntsTable();
virtual void recreateFloatsTable();
virtual void recreateUUIDsTable();
virtual void recreateTuplesTable();
virtual void recreateVectorsTable();
virtual void recreateAnysTable();
@@ -317,6 +320,12 @@ inline void ODBCTest::recreateFloatsTable()
}
inline void ODBCTest::recreateUUIDsTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateUUIDsTable()");
}
inline void ODBCTest::recreateTuplesTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateTuplesTable()");

View File

@@ -1540,6 +1540,29 @@ void SQLExecutor::doubles()
}
void SQLExecutor::uuids()
{
std::string funct = "uuids()";
Poco::UUID data("49cf6461-9b62-4163-9659-5472ef73153d");
Poco::UUID ret;
try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
int count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
assertTrue (count == 1);
try { session() << "SELECT str FROM Strings", into(ret), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
assertTrue (ret == data);
}
void SQLExecutor::insertSingleBulkVec()
{
std::string funct = "insertSingleBulkVec()";

View File

@@ -469,6 +469,7 @@ public:
void time();
void floats();
void doubles();
void uuids();
void tuples();
void tupleVector();

View File

@@ -37,6 +37,9 @@ endif
ifeq (0, $(shell test -e /opt/postgresql/lib$(LIB64SUFFIX); echo $$?))
SYSLIBS += -L/opt/postgresql/lib$(LIB64SUFFIX)
endif
ifeq (0, $(shell test -e /usr/local/opt/libpq/lib; echo $$?))
SYSLIBS += -L/usr/local/opt/libpq/lib$(LIB64SUFFIX)
endif
SYSLIBS += -lpq
objects = Extractor Binder SessionImpl Connector \

View File

@@ -108,6 +108,9 @@ public:
virtual void bind(std::size_t pos, const Time& val, Direction dir = PD_IN);
/// 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);
/// Binds a null.

View File

@@ -109,6 +109,9 @@ public:
virtual bool extract(std::size_t pos, Time& val);
/// 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);
/// Extracts an Any. Returns false if null was received.
@@ -326,15 +329,10 @@ private:
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
{
return false;
}
if (isColumnNull(outputParameter)) return false;
std::string tempString; // since the postgreSQL API in use is all about strings...
bool returnValue = extract(pos, tempString);
if (returnValue)
{
val = tempString;
@@ -343,9 +341,10 @@ private:
return returnValue;
}
bool extractToDynamic(std::size_t pos, Dynamic::Var& val);
// Prevent VC8 warning "operator= could not be generated"
Extractor& operator=(const Extractor&);
Extractor& operator = (const Extractor&);
private:
StatementExecutor& _statementExecutor;

View File

@@ -271,6 +271,7 @@ inline const void* InputParameter::pInternalRepresentation() const
case Poco::Data::MetaColumn::FDT_DATE:
case Poco::Data::MetaColumn::FDT_TIME:
case Poco::Data::MetaColumn::FDT_TIMESTAMP:
case Poco::Data::MetaColumn::FDT_UUID:
return _stringVersionRepresentation.c_str();
case Poco::Data::MetaColumn::FDT_BLOB:
@@ -278,7 +279,8 @@ inline const void* InputParameter::pInternalRepresentation() const
return _pNonStringVersionRepresentation;
case Poco::Data::MetaColumn::FDT_UNKNOWN:
default: return 0;
default:
return 0;
}
}

View File

@@ -89,8 +89,7 @@ public:
void connect(const char* aConnectionString);
void connect(const char* aHost, const char* aUser, const char* aPassword,
const char* aDatabase, unsigned short aPort, unsigned int aConnectionTimeout);
void connect(const char* aHost, const char* aUser, const char* aPassword, const char* aDatabase, unsigned short aPort, unsigned int aConnectionTimeout);
bool isConnected() const;
/// is a connection established?

View File

@@ -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)
{
poco_assert(dir == PD_IN);
@@ -198,8 +205,8 @@ Binder::bindVector() const
void Binder::updateBindVectorToCurrentValues()
{
InputParameterVector::iterator itr = _bindVector.begin();
InputParameterVector::iterator itrEnd = _bindVector.end();
InputParameterVector::iterator itr = _bindVector.begin();
InputParameterVector::iterator itrEnd = _bindVector.end();
for (; itr != itrEnd; ++itr)
{
@@ -293,6 +300,14 @@ void Binder::updateBindVectorToCurrentValues()
const Poco::Data::CLOB& clob = * static_cast<const Poco::Data::CLOB*>(itr->pData());
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:
default:

View File

@@ -17,6 +17,8 @@
#include "Poco/Data/Time.h"
#include "Poco/NumberParser.h"
#include "Poco/DateTimeParser.h"
#include "Poco/MemoryStream.h"
#include "Poco/HexBinaryDecoder.h"
#include <limits>
@@ -42,14 +44,10 @@ bool Extractor::extract(std::size_t pos, Poco::Int8& val)
OutputParameter outputParameter = extractPreamble(pos);
int tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParse(outputParameter.pData(), tempVal)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), tempVal))
{
return false;
}
val = static_cast<Int8>(tempVal);
return true;
@@ -61,15 +59,11 @@ bool Extractor::extract(std::size_t pos, Poco::UInt8& val)
OutputParameter outputParameter = extractPreamble(pos);
unsigned int tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal)
)
if (isColumnNull(outputParameter)|| !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal))
{
return false;
}
val = static_cast<Int8>(tempVal);
val = static_cast<UInt8>(tempVal);
return true;
}
@@ -80,15 +74,11 @@ bool Extractor::extract(std::size_t pos, Poco::Int16& val)
OutputParameter outputParameter = extractPreamble(pos);
int tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParse(outputParameter.pData(), tempVal)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), tempVal))
{
return false;
}
val = static_cast<Int8>(tempVal);
val = static_cast<Int16>(tempVal);
return true;
}
@@ -99,15 +89,11 @@ bool Extractor::extract(std::size_t pos, Poco::UInt16& val)
OutputParameter outputParameter = extractPreamble(pos);
unsigned int tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), tempVal))
{
return false;
}
val = static_cast<Int8>(tempVal);
val = static_cast<UInt16>(tempVal);
return true;
}
@@ -117,9 +103,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int32& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParse(outputParameter.pData(), val)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse(outputParameter.pData(), val))
{
return false;
}
@@ -132,9 +116,7 @@ bool Extractor::extract(std::size_t pos, Poco::UInt32& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), val)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned(outputParameter.pData(), val))
{
return false;
}
@@ -147,9 +129,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int64& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParse64(outputParameter.pData(), val)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse64(outputParameter.pData(), val))
{
return false;
}
@@ -162,9 +142,7 @@ bool Extractor::extract(std::size_t pos, Poco::UInt64& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), val)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), val))
{
return false;
}
@@ -179,13 +157,10 @@ bool Extractor::extract(std::size_t pos, long& val)
OutputParameter outputParameter = extractPreamble(pos);
Poco::Int64 tempVal = 0;
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse64(outputParameter.pData(), tempVal)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParse64(outputParameter.pData(), tempVal))
{
return false;
}
val = (long)tempVal;
return true;
@@ -197,14 +172,10 @@ bool Extractor::extract(std::size_t pos, unsigned long& val)
OutputParameter outputParameter = extractPreamble(pos);
Poco::UInt64 tempVal = 0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), tempVal)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseUnsigned64(outputParameter.pData(), tempVal))
{
return false;
}
val = (unsigned long)tempVal;
return true;
@@ -216,19 +187,12 @@ bool Extractor::extract(std::size_t pos, bool& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter))
if (isColumnNull(outputParameter))
{
return false;
}
if ('t' == *outputParameter.pData())
{
val = true;
}
else
{
val = false;
}
val = 't' == *outputParameter.pData();
return true;
}
@@ -239,15 +203,11 @@ bool Extractor::extract(std::size_t pos, float& val)
OutputParameter outputParameter = extractPreamble(pos);
double tempVal = 0.0;
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseFloat(outputParameter.pData(), tempVal)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseFloat(outputParameter.pData(), tempVal))
{
return false;
}
val = (float)tempVal;
val = static_cast<float>(tempVal);
return true;
}
@@ -257,9 +217,7 @@ bool Extractor::extract(std::size_t pos, double& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if ( isColumnNull(outputParameter)
|| ! Poco::NumberParser::tryParseFloat(outputParameter.pData(), val)
)
if (isColumnNull(outputParameter) || !Poco::NumberParser::tryParseFloat(outputParameter.pData(), val))
{
return false;
}
@@ -272,11 +230,10 @@ bool Extractor::extract(std::size_t pos, char& val)
{
OutputParameter outputParameter = extractPreamble(pos);
if (isColumnNull(outputParameter))
if (isColumnNull(outputParameter))
{
return false;
}
val = *outputParameter.pData();
return true;
@@ -291,7 +248,6 @@ bool Extractor::extract(std::size_t pos, std::string& val)
{
return false;
}
val.assign(outputParameter.pData(), outputParameter.size());
return true;
@@ -309,31 +265,24 @@ bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val)
// convert the PostgreSQL text format to binary and append to the BLOB
// Format: \x10843029479abcf ... two characters for every byte
//
// The code below can be made more efficient by converting more than one byte at a time
// also if BLOB had a resize method it would be useful to allocate memory in one
// attempt.
//
const char * pBLOB = reinterpret_cast<const char*>(outputParameter.pData());
std::size_t BLOBSize = outputParameter.size();
std::size_t blobSize = outputParameter.size();
val = Poco::Data::BLOB(); // don't share contents with _default
if ( '\\' == pBLOB[0]
&& 'x' == pBLOB[1] // preamble to BYTEA data format in text form is \x
)
if (blobSize > 2 && '\\' == pBLOB[0] && 'x' == pBLOB[1]) // preamble to BYTEA data format in text form is \x
{
BLOBSize -= 2; // lose the preamble
BLOBSize /= 2; // each byte is encoded as two text characters
blobSize -= 2; // lose the preamble
for (int i = 0; i < BLOBSize * 2; i += 2)
Poco::MemoryInputStream mistr(pBLOB + 2, blobSize);
Poco::HexBinaryDecoder decoder(mistr);
auto* pDecoderBuf = decoder.rdbuf();
blobSize /= 2;
val.resize(blobSize);
char* pData = reinterpret_cast<char*>(val.rawContent());
while (blobSize-- > 0)
{
std::string buffer(&pBLOB[i + 2], 2);
unsigned int binaryBuffer = 0;
if (Poco::NumberParser::tryParseHex(buffer, binaryBuffer))
{
UInt8 finalBinaryBuffer = static_cast<UInt8>(binaryBuffer); // downsize
val.appendRaw(&finalBinaryBuffer, 1);
}
*pData++ = pDecoderBuf->sbumpc();
}
}
return true;
@@ -348,7 +297,6 @@ bool Extractor::extract(std::size_t pos, Poco::Data::CLOB& val)
{
return false;
}
val.assignRaw(outputParameter.pData(), outputParameter.size());
return true;
@@ -366,14 +314,11 @@ bool Extractor::extract(std::size_t pos, DateTime& val)
int tzd = -1;
DateTime dateTime;
if (! DateTimeParser::tryParse(outputParameter.pData(), dateTime, tzd))
if (!DateTimeParser::tryParse(outputParameter.pData(), dateTime, tzd))
{
return false;
}
dateTime.makeUTC(tzd);
val = dateTime;
return true;
@@ -388,17 +333,13 @@ bool Extractor::extract(std::size_t pos, Date& val)
{
return false;
}
int tzd = -1;
DateTime dateTime;
if (! DateTimeParser::tryParse(outputParameter.pData(), dateTime, tzd))
if (!DateTimeParser::tryParse(outputParameter.pData(), dateTime, tzd))
{
return false;
}
dateTime.makeUTC(tzd);
val.assign(dateTime.year(), dateTime.month(), dateTime.day());
return true;
@@ -413,10 +354,8 @@ bool Extractor::extract(std::size_t pos, Time& val)
{
return false;
}
int tzd = -1;
DateTime dateTime;
if (! DateTimeParser::tryParse("%H:%M:%s%z", outputParameter.pData(), dateTime, tzd))
{
return false;
@@ -431,15 +370,28 @@ 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)
{
return extractStringImpl (pos, val);
return extractStringImpl(pos, val);
}
bool Extractor::extract(std::size_t pos, Dynamic::Var& val)
{
return extractStringImpl (pos, val);
return extractToDynamic(pos, val);
}
@@ -462,8 +414,7 @@ void Extractor::reset()
}
const OutputParameter&
Extractor::extractPreamble(std::size_t aPosition) const
const OutputParameter& Extractor::extractPreamble(std::size_t aPosition) const
{
if (_statementExecutor.columnsReturned() <= aPosition)
{
@@ -474,11 +425,125 @@ Extractor::extractPreamble(std::size_t aPosition) const
}
bool
Extractor::isColumnNull (const OutputParameter& anOutputParameter) const
bool Extractor::isColumnNull(const OutputParameter& anOutputParameter) const
{
return anOutputParameter.isNull()
|| 0 == anOutputParameter.pData();
return anOutputParameter.isNull() || 0 == anOutputParameter.pData();
}
bool Extractor::extractToDynamic(std::size_t pos, Dynamic::Var& val)
{
OutputParameter outputParameter = _statementExecutor.resultColumn(pos);
if (isColumnNull(outputParameter))
{
return false;
}
const std::string tempString{outputParameter.pData(), outputParameter.size()};
const Oid oid = outputParameter.internalFieldType();
bool success = false;
switch (oid)
{
case BOOLOID:
{
success = true;
if (tempString[0] == 't')
val = true;
else
val = false;
break;
}
case INT2OID:
case INT4OID:
case INT8OID:
{
Poco::Int64 tempValue = 0;
success = Poco::NumberParser::tryParse64(tempString, tempValue);
if (success)
val = tempValue;
break;
}
// floating point
case FLOAT8OID:
case FLOAT4OID:
case NUMERICOID:
{
double tempValue = 0;
success = Poco::NumberParser::tryParseFloat(tempString, tempValue);
if (success)
val = tempValue;
break;
}
// character strings
case CHAROID:
case BPCHAROID:
case VARCHAROID:
default:
{
success = true;
val = tempString;
break;
}
// BLOB, CLOB
case BYTEAOID:
{
Poco::Data::BLOB blob;
success = extract(pos, blob);
if (success)
val = blob;
break;
}
case TEXTOID:
{
Poco::Data::CLOB clob;
success = extract(pos, clob);
if (success)
val = clob;
break;
}
// date
case DATEOID:
{
Date d;
success = extract(pos, d);
if (success)
val = d;
break;
}
// time
case TIMEOID:
case TIMETZOID:
{
Time t;
success = extract(pos, t);
if (success)
val = t;
break;
}
//timestamp
case TIMESTAMPOID:
case TIMESTAMPZOID:
{
DateTime dt;
success = extract(pos, dt);
if (success)
val = dt;
break;
}
case UUIDOID:
{
UUID uuid;
success = extract(pos, uuid);
if (success)
val = uuid;
break;
}
}
return success;
}
@@ -487,381 +552,381 @@ Extractor::isColumnNull (const OutputParameter& anOutputParameter) const
//////////////
bool Extractor::extract(std::size_t , std::vector<Poco::Int8>&)
bool Extractor::extract(std::size_t, std::vector<Poco::Int8>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::Int8>&)
bool Extractor::extract(std::size_t, std::deque<Poco::Int8>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::Int8>&)
bool Extractor::extract(std::size_t, std::list<Poco::Int8>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::UInt8>&)
bool Extractor::extract(std::size_t, std::vector<Poco::UInt8>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::UInt8>&)
bool Extractor::extract(std::size_t, std::deque<Poco::UInt8>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::UInt8>&)
bool Extractor::extract(std::size_t, std::list<Poco::UInt8>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::Int16>&)
bool Extractor::extract(std::size_t, std::vector<Poco::Int16>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::Int16>&)
bool Extractor::extract(std::size_t, std::deque<Poco::Int16>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::Int16>&)
bool Extractor::extract(std::size_t, std::list<Poco::Int16>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::UInt16>&)
bool Extractor::extract(std::size_t, std::vector<Poco::UInt16>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::UInt16>&)
bool Extractor::extract(std::size_t, std::deque<Poco::UInt16>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::UInt16>&)
bool Extractor::extract(std::size_t, std::list<Poco::UInt16>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::Int32>&)
bool Extractor::extract(std::size_t, std::vector<Poco::Int32>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::Int32>&)
bool Extractor::extract(std::size_t, std::deque<Poco::Int32>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::Int32>&)
bool Extractor::extract(std::size_t, std::list<Poco::Int32>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::UInt32>&)
bool Extractor::extract(std::size_t, std::vector<Poco::UInt32>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::UInt32>&)
bool Extractor::extract(std::size_t, std::deque<Poco::UInt32>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::UInt32>&)
bool Extractor::extract(std::size_t, std::list<Poco::UInt32>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::Int64>&)
bool Extractor::extract(std::size_t, std::vector<Poco::Int64>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::Int64>&)
bool Extractor::extract(std::size_t, std::deque<Poco::Int64>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::Int64>&)
bool Extractor::extract(std::size_t, std::list<Poco::Int64>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Poco::UInt64>&)
bool Extractor::extract(std::size_t, std::vector<Poco::UInt64>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Poco::UInt64>&)
bool Extractor::extract(std::size_t, std::deque<Poco::UInt64>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Poco::UInt64>&)
bool Extractor::extract(std::size_t, std::list<Poco::UInt64>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
#ifndef POCO_INT64_IS_LONG
bool Extractor::extract(std::size_t , std::vector<long>&)
bool Extractor::extract(std::size_t, std::vector<long>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<long>&)
bool Extractor::extract(std::size_t, std::deque<long>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<long>&)
bool Extractor::extract(std::size_t, std::list<long>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
#endif
bool Extractor::extract(std::size_t , std::vector<bool>&)
bool Extractor::extract(std::size_t, std::vector<bool>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<bool>&)
bool Extractor::extract(std::size_t, std::deque<bool>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<bool>&)
bool Extractor::extract(std::size_t, std::list<bool>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<float>&)
bool Extractor::extract(std::size_t, std::vector<float>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<float>&)
bool Extractor::extract(std::size_t, std::deque<float>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<float>&)
bool Extractor::extract(std::size_t, std::list<float>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<double>&)
bool Extractor::extract(std::size_t, std::vector<double>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<double>&)
bool Extractor::extract(std::size_t, std::deque<double>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<double>&)
bool Extractor::extract(std::size_t, std::list<double>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<char>&)
bool Extractor::extract(std::size_t, std::vector<char>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<char>&)
bool Extractor::extract(std::size_t, std::deque<char>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<char>&)
bool Extractor::extract(std::size_t, std::list<char>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<std::string>&)
bool Extractor::extract(std::size_t, std::vector<std::string>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<std::string>&)
bool Extractor::extract(std::size_t, std::deque<std::string>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<std::string>&)
bool Extractor::extract(std::size_t, std::list<std::string>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<BLOB>&)
bool Extractor::extract(std::size_t, std::vector<BLOB>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<BLOB>&)
bool Extractor::extract(std::size_t, std::deque<BLOB>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<BLOB>&)
bool Extractor::extract(std::size_t, std::list<BLOB>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<CLOB>&)
bool Extractor::extract(std::size_t, std::vector<CLOB>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<CLOB>&)
bool Extractor::extract(std::size_t, std::deque<CLOB>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<CLOB>&)
bool Extractor::extract(std::size_t, std::list<CLOB>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<DateTime>&)
bool Extractor::extract(std::size_t, std::vector<DateTime>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<DateTime>&)
bool Extractor::extract(std::size_t, std::deque<DateTime>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<DateTime>&)
bool Extractor::extract(std::size_t, std::list<DateTime>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Date>&)
bool Extractor::extract(std::size_t, std::vector<Date>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Date>&)
bool Extractor::extract(std::size_t, std::deque<Date>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Date>&)
bool Extractor::extract(std::size_t, std::list<Date>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Time>&)
bool Extractor::extract(std::size_t, std::vector<Time>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Time>&)
bool Extractor::extract(std::size_t, std::deque<Time>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Time>&)
bool Extractor::extract(std::size_t, std::list<Time>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Any>&)
bool Extractor::extract(std::size_t, std::vector<Any>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Any>&)
bool Extractor::extract(std::size_t, std::deque<Any>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Any>&)
bool Extractor::extract(std::size_t, std::list<Any>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::vector<Dynamic::Var>&)
bool Extractor::extract(std::size_t, std::vector<Dynamic::Var>&)
{
throw NotImplementedException("std::vector extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::deque<Dynamic::Var>&)
bool Extractor::extract(std::size_t, std::deque<Dynamic::Var>&)
{
throw NotImplementedException("std::deque extractor must be implemented.");
}
bool Extractor::extract(std::size_t , std::list<Dynamic::Var>&)
bool Extractor::extract(std::size_t, std::list<Dynamic::Var>&)
{
throw NotImplementedException("std::list extractor must be implemented.");
}

View File

@@ -108,8 +108,7 @@ bool PostgreSQLStatementImpl::canBind() const
{
bool ret = false;
if ((_statementExecutor.state() >= StatementExecutor::STMT_COMPILED)
&& !bindings().empty())
if ((_statementExecutor.state() >= StatementExecutor::STMT_COMPILED) && !bindings().empty())
{
ret = (*bindings().begin())->canBind();
}

View File

@@ -94,6 +94,11 @@ Poco::Data::MetaColumn::ColumnDataType oidToColumnDataType(const Oid anOID)
cdt = Poco::Data::MetaColumn::FDT_TIMESTAMP;
break;
//uuid
case UUIDOID:
cdt = Poco::Data::MetaColumn::FDT_BLOB;
break;
// everything else is a string
default:
cdt = Poco::Data::MetaColumn::FDT_STRING;

View File

@@ -86,7 +86,7 @@ void SessionHandle::connect(const std::string& aConnectionString)
_pConnection = PQconnectdb(aConnectionString.c_str());
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw ConnectionFailedException(std::string("Connection Error: ") + lastErrorNoLock());
}
@@ -151,6 +151,7 @@ void SessionHandle::disconnect()
}
}
// TODO: Figure out what happens if a connection is reset with a pending transaction
bool SessionHandle::reset()
{
@@ -174,7 +175,7 @@ std::string SessionHandle::lastError() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
return std::string();
}
@@ -196,7 +197,7 @@ void SessionHandle::startTransaction()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -223,7 +224,7 @@ void SessionHandle::commit()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -247,7 +248,7 @@ void SessionHandle::rollback()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -291,7 +292,7 @@ void SessionHandle::setAsynchronousCommit(bool aShouldAsynchronousCommit)
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -318,7 +319,7 @@ void SessionHandle::cancel()
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -335,7 +336,7 @@ void SessionHandle::setTransactionIsolation(Poco::UInt32 aTI)
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -345,7 +346,7 @@ void SessionHandle::setTransactionIsolation(Poco::UInt32 aTI)
return;
}
if (! hasTransactionIsolation(aTI))
if (!hasTransactionIsolation(aTI))
{
throw Poco::InvalidArgumentException("setTransactionIsolation()");
}
@@ -354,12 +355,12 @@ void SessionHandle::setTransactionIsolation(Poco::UInt32 aTI)
switch (aTI)
{
case Session::TRANSACTION_READ_COMMITTED:
isolationLevel = POSTGRESQL_READ_COMMITTED; break;
case Session::TRANSACTION_REPEATABLE_READ:
isolationLevel = POSTGRESQL_REPEATABLE_READ; break;
case Session::TRANSACTION_SERIALIZABLE:
isolationLevel = POSTGRESQL_SERIALIZABLE; break;
case Session::TRANSACTION_READ_COMMITTED:
isolationLevel = POSTGRESQL_READ_COMMITTED; break;
case Session::TRANSACTION_REPEATABLE_READ:
isolationLevel = POSTGRESQL_REPEATABLE_READ; break;
case Session::TRANSACTION_SERIALIZABLE:
isolationLevel = POSTGRESQL_SERIALIZABLE; break;
}
PGresult* pPQResult = PQexec(_pConnection, Poco::format("SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL %s", isolationLevel).c_str());
@@ -393,12 +394,12 @@ void SessionHandle::deallocatePreparedStatement(const std::string& aPreparedStat
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
if (! _inTransaction)
if (!_inTransaction)
{
deallocatePreparedStatementNoLock(aPreparedStatementToDeAllocate);
}
@@ -431,7 +432,7 @@ void SessionHandle::deallocatePreparedStatementNoLock(const std::string& aPrepar
void SessionHandle::deallocateStoredPreparedStatements()
{
// DO NOT ACQUIRE THE MUTEX IN PRIVATE METHODS
while (! _preparedStatementsToBeDeallocated.empty())
while (!_preparedStatementsToBeDeallocated.empty())
{
deallocatePreparedStatementNoLock(_preparedStatementsToBeDeallocated.back());
@@ -444,7 +445,7 @@ int SessionHandle::serverVersion() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -457,7 +458,7 @@ int SessionHandle::serverProcessID() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -470,7 +471,7 @@ int SessionHandle::protocoVersion() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -483,7 +484,7 @@ std::string SessionHandle::clientEncoding() const
{
Poco::FastMutex::ScopedLock mutexLocker(_sessionMutex);
if (! isConnectedNoLock())
if (!isConnectedNoLock())
{
throw NotConnectedException();
}
@@ -502,7 +503,7 @@ SessionParametersMap SessionHandle::setConnectionInfoParameters(PQconninfoOption
{
SessionParametersMap sessionParametersMap;
while (0 != pConnInfOpt->keyword)
while (pConnInfOpt->keyword)
{
try
{
@@ -542,7 +543,7 @@ SessionParametersMap SessionHandle::connectionDefaultParameters()
SessionParametersMap SessionHandle::connectionParameters() const
{
if (! isConnected())
if (!isConnected())
{
throw NotConnectedException();
}

View File

@@ -38,7 +38,7 @@ namespace
{
std::string connectionString;
for (std::map<std::string, std::string>::const_iterator citr = anOptionsMap.begin(); citr != anOptionsMap.end(); ++citr)
for (auto citr = anOptionsMap.begin(); citr != anOptionsMap.end(); ++citr)
{
connectionString.append(citr->first);
connectionString.append("=");
@@ -57,7 +57,8 @@ namespace PostgreSQL {
SessionImpl::SessionImpl(const std::string& aConnectionString, std::size_t aLoginTimeout):
Poco::Data::AbstractSessionImpl<SessionImpl>(aConnectionString, aLoginTimeout)
Poco::Data::AbstractSessionImpl<SessionImpl>(aConnectionString, aLoginTimeout),
_connectorName("postgresql")
{
setProperty("handle", static_cast<SessionHandle*>(&_sessionHandle));
setConnectionTimeout(CONNECTION_TIMEOUT_DEFAULT);
@@ -92,7 +93,7 @@ void SessionImpl::open(const std::string& aConnectionString)
throw ConnectionException("Session already connected");
}
if (! aConnectionString.empty())
if (!aConnectionString.empty())
{
setConnectionString(aConnectionString);
}

View File

@@ -46,7 +46,6 @@ namespace
Poco::RegularExpression::Match match = { 0 , 0 }; // Match is a struct, not a class :-(
std::size_t startingPosition = 0;
while (match.offset != std::string::npos)
{
try
@@ -110,7 +109,7 @@ StatementExecutor::State StatementExecutor::state() const
void StatementExecutor::prepare(const std::string& aSQLStatement)
{
if (! _sessionHandle.isConnected()) throw NotConnectedException();
if (!_sessionHandle.isConnected()) throw NotConnectedException();
if (_state >= STMT_COMPILED) return;
// clear out the metadata. One way or another it is now obsolete.
@@ -160,7 +159,7 @@ void StatementExecutor::prepare(const std::string& aSQLStatement)
{
PQResultClear resultClearer(ptrPGResult);
if (! ptrPGResult || PQresultStatus(ptrPGResult) != PGRES_COMMAND_OK)
if (!ptrPGResult || PQresultStatus(ptrPGResult) != PGRES_COMMAND_OK)
{
throw StatementException(std::string("postgresql_stmt_describe error: ") +
PQresultErrorMessage (ptrPGResult) + " " + aSQLStatement);
@@ -186,7 +185,7 @@ void StatementExecutor::prepare(const std::string& aSQLStatement)
void StatementExecutor::bindParams(const InputParameterVector& anInputParameterVector)
{
if (! _sessionHandle.isConnected()) throw NotConnectedException();
if (!_sessionHandle.isConnected()) throw NotConnectedException();
if (_state < STMT_COMPILED) throw StatementException("Statement is not compiled yet");
@@ -203,7 +202,7 @@ void StatementExecutor::bindParams(const InputParameterVector& anInputParameterV
void StatementExecutor::execute()
{
if (! _sessionHandle.isConnected()) throw NotConnectedException();
if (!_sessionHandle.isConnected()) throw NotConnectedException();
if (_state < STMT_COMPILED) throw StatementException("Statement is not compiled yet");
@@ -225,8 +224,8 @@ void StatementExecutor::execute()
std::vector<int> parameterLengthVector;
std::vector<int> parameterFormatVector;
InputParameterVector::const_iterator cItr = _inputParameterVector.begin();
InputParameterVector::const_iterator cItrEnd = _inputParameterVector.end();
InputParameterVector::const_iterator cItr = _inputParameterVector.begin();
InputParameterVector::const_iterator cItrEnd = _inputParameterVector.end();
for (; cItr != cItrEnd; ++cItr)
{
@@ -315,7 +314,7 @@ void StatementExecutor::execute()
bool StatementExecutor::fetch()
{
if (! _sessionHandle.isConnected())
if (!_sessionHandle.isConnected())
{
throw NotConnectedException();
}

View File

@@ -27,13 +27,9 @@ namespace PostgreSQL {
std::string Utility::serverInfo(SessionHandle* aHandlePtr)
{
std::string srvrInfo = "Process ID: ";
srvrInfo.append(Poco::NumberFormatter::format(aHandlePtr->serverProcessID()));
srvrInfo.append(" Protocol Version: ");
srvrInfo.append(Poco::NumberFormatter::format(aHandlePtr->protocoVersion()));
return srvrInfo;
}
@@ -61,7 +57,6 @@ std::string Utility::hostInfo(SessionHandle* aHandlePtr)
SessionParametersMap parametersMap = aHandlePtr->connectionParameters();
SessionParametersMap::const_iterator cItr = parametersMap.find("host");
if (parametersMap.end() == cItr)
{
return std::string();

View File

@@ -37,6 +37,9 @@ endif
ifeq (0, $(shell test -e /opt/postgresql/lib$(LIB64SUFFIX); echo $$?))
SYSLIBS += -L/opt/postgresql/lib$(LIB64SUFFIX)
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.
SYSLIBS += -lpq -lz -lpthread -ldl

View File

@@ -690,6 +690,14 @@ void PostgreSQLTest::testDouble()
}
void PostgreSQLTest::testUUID()
{
if (!_pSession) fail ("Test not available.");
recreateUUIDsTable();
_pExecutor->uuids();
}
void PostgreSQLTest::testTuple()
{
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()
{
dropTable("Tuples");
@@ -1110,6 +1127,7 @@ CppUnit::Test* PostgreSQLTest::suite()
CppUnit_addTest(pSuite, PostgreSQLTest, testUnsignedInts);
CppUnit_addTest(pSuite, PostgreSQLTest, testFloat);
CppUnit_addTest(pSuite, PostgreSQLTest, testDouble);
CppUnit_addTest(pSuite, PostgreSQLTest, testUUID);
CppUnit_addTest(pSuite, PostgreSQLTest, testTuple);
CppUnit_addTest(pSuite, PostgreSQLTest, testTupleVector);
CppUnit_addTest(pSuite, PostgreSQLTest, testInternalExtraction);

View File

@@ -82,6 +82,7 @@ public:
void testUnsignedInts();
void testFloat();
void testDouble();
void testUUID();
void testTuple();
void testTupleVector();
@@ -118,6 +119,7 @@ private:
void recreateIntsTable();
void recreateUnsignedIntsTable();
void recreateFloatsTable();
void recreateUUIDsTable();
void recreateTuplesTable();
void recreateVectorsTable();
void recreateNullableIntTable();

View File

@@ -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()
{
std::string funct = "floats()";
@@ -1611,7 +1634,7 @@ void SQLExecutor::blobStmt()
std::string lastName("lastname");
std::string firstName("firstname");
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);
int count = 0;

View File

@@ -25,7 +25,7 @@ public:
PB_IMMEDIATE,
PB_AT_EXEC
};
enum DataExtraction
{
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[]);
/// 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);
/// This function uses "bare bone" API calls (i.e. calls are not
/// "wrapped" in PocoSQL framework structures).
@@ -89,6 +89,7 @@ public:
void unsignedInts();
void floats();
void doubles();
void uuids();
void tuples();
void tupleVector();

View File

@@ -60,10 +60,6 @@ else()
SQLITE_OMIT_COMPLETE
SQLITE_OMIT_TCL_VARIABLE
SQLITE_OMIT_DEPRECATED
SQLITE_ENABLE_RTREE
SQLITE_ENABLE_JSON1
SQLITE_ENABLE_SESSION
SQLITE_ENABLE_MATH_FUNCTIONS
)
endif()

View File

@@ -106,6 +106,9 @@ public:
void bind(std::size_t pos, const DateTime& val, Direction dir);
/// 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);
/// Binds a null.

View File

@@ -116,6 +116,9 @@ public:
bool extract(std::size_t pos, Poco::DateTime& val);
/// Extracts a DateTime.
bool extract(std::size_t pos, Poco::UUID& val);
/// Extracts a Time.
bool extract(std::size_t pos, Poco::Any& val);
/// Extracts an Any.
@@ -264,6 +267,13 @@ private:
val = dt;
break;
}
case MetaColumn::FDT_UUID:
{
UUID uuid;
ret = extract(pos, uuid);
val = uuid;
break;
}
default:
throw Poco::Data::UnknownTypeException("Unknown type during extraction");
}

View File

@@ -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)
{
sqlite3_bind_null(_pStmt, static_cast<int>(pos));

View File

@@ -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)
{
return extractImpl(pos, val);

View File

@@ -134,6 +134,8 @@ Utility::Utility()
_types.insert(TypeMap::value_type("TIME", MetaColumn::FDT_TIME));
_types.insert(TypeMap::value_type("DATETIME", 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));
}
}
@@ -248,7 +250,9 @@ bool Utility::fileToMemory(sqlite3* pInMemory, const std::string& fileName)
sqlite3* pFile;
sqlite3_backup* pBackup;
rc = sqlite3_open_v2(fileName.c_str(), &pFile, SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, NULL);
// Note: SQLITE_OPEN_READWRITE is required to correctly handle an existing hot journal.
// See #3135
rc = sqlite3_open_v2(fileName.c_str(), &pFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI, NULL);
if(rc == SQLITE_OK )
{
pBackup = sqlite3_backup_init(pInMemory, "main", pFile, "main");

File diff suppressed because it is too large Load Diff

View File

@@ -123,9 +123,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.35.3"
#define SQLITE_VERSION_NUMBER 3035003
#define SQLITE_SOURCE_ID "2021-03-26 12:12:52 4c5e6c200adc8afe0814936c67a971efc516d1bd739cb620235592f18f40be2a"
#define SQLITE_VERSION "3.36.0"
#define SQLITE_VERSION_NUMBER 3036000
#define SQLITE_SOURCE_ID "2021-06-18 18:36:39 5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -1128,6 +1128,23 @@ struct sqlite3_io_methods {
** file to the database file, but before the *-shm file is updated to
** record the fact that the pages have been checkpointed.
** </ul>
**
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
** whether or not there is a database client in another process with a wal-mode
** transaction open on the database or not. It is only available on unix.The
** (void*) argument passed with this file-control should be a pointer to a
** value of type (int). The integer value is set to 1 if the database is a wal
** mode database and there exists at least one client in another process that
** currently has an SQL transaction open on the database. It is set to 0 if
** the database is not a wal-mode db, or if there is no such connection in any
** other process. This opcode cannot be used to detect transactions opened
** by clients within the current process, only within other processes.
** </ul>
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
** Used by the cksmvfs VFS module only.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
@@ -1167,6 +1184,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_CKPT_DONE 37
#define SQLITE_FCNTL_RESERVE_BYTES 38
#define SQLITE_FCNTL_CKPT_START 39
#define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -4179,6 +4198,15 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
** sqlite3_stmt_readonly() returns false for those commands.
**
** ^This routine returns false if there is any possibility that the
** statement might change the database file. ^A false return does
** not guarantee that the statement will change the database file.
** ^For example, an UPDATE statement might have a WHERE clause that
** makes it a no-op, but the sqlite3_stmt_readonly() result would still
** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
** read-only no-op if the table already exists, but
** sqlite3_stmt_readonly() still returns false for such a statement.
*/
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
@@ -4348,18 +4376,22 @@ typedef struct sqlite3_context sqlite3_context;
** contain embedded NULs. The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it. ^The destructor is called
** to dispose of the BLOB or string even if the call to the bind API fails,
** except the destructor is not called if the third parameter is a NULL
** pointer or the fourth parameter is negative.
** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
** SQLite makes its own private copy of the data immediately, before
** the sqlite3_bind_*() routine returns.
** ^The fifth argument to the BLOB and string binding interfaces controls
** or indicates the lifetime of the object referenced by the third parameter.
** These three options exist:
** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
** bound to something else, whichever occurs sooner.
** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the
** object is to be copied prior to the return from sqlite3_bind_*(). ^The
** object and pointer to it must remain valid until then. ^SQLite will then
** manage the lifetime of its private copy.
**
** ^The sixth argument to sqlite3_bind_text64() must be one of
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
@@ -5101,7 +5133,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
** index expressions, or the WHERE clause of partial indexes.
**
** <span style="background-color:#ffff90;">
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
** all application-defined SQL functions that do not need to be
** used inside of triggers, view, CHECK constraints, or other elements of
@@ -5111,7 +5142,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** a database file to include invocations of the function with parameters
** chosen by the attacker, which the application will then execute when
** the database file is opened and read.
** </span>
**
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
@@ -7779,7 +7809,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
#define SQLITE_TESTCTRL_SEEK_COUNT 30
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_LAST 31 /* Largest TESTCTRL */
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -9531,6 +9562,15 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** triggers; or 2 for changes resulting from triggers called by top-level
** triggers; and so forth.
**
** When the [sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
** callback made with op==SQLITE_DELETE is actuall a write using the
** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
** regular DELETE, sqlite3_preupdate_blobwrite() returns -1.
**
** See also: [sqlite3_update_hook()]
*/
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
@@ -9551,6 +9591,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *);
#endif
/*
@@ -9789,8 +9830,8 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
**
** This interface is only available if SQLite is compiled with the
** [SQLITE_ENABLE_DESERIALIZE] option.
** This interface is omitted if SQLite is compiled with the
** [SQLITE_OMIT_DESERIALIZE] option.
*/
SQLITE_API unsigned char *sqlite3_serialize(
sqlite3 *db, /* The database connection */
@@ -9841,8 +9882,8 @@ SQLITE_API unsigned char *sqlite3_serialize(
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [sqlite3_free()] is invoked on argument P prior to returning.
**
** This interface is only available if SQLite is compiled with the
** [SQLITE_ENABLE_DESERIALIZE] option.
** This interface is omitted if SQLite is compiled with the
** [SQLITE_OMIT_DESERIALIZE] option.
*/
SQLITE_API int sqlite3_deserialize(
sqlite3 *db, /* The database connection */
@@ -10091,6 +10132,38 @@ SQLITE_API int sqlite3session_create(
*/
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
** CAPIREF: Conigure a Session Object
** METHOD: sqlite3_session
**
** This method is used to configure a session object after it has been
** created. At present the only valid value for the second parameter is
** [SQLITE_SESSION_OBJCONFIG_SIZE].
**
** Arguments for sqlite3session_object_config()
**
** The following values may passed as the the 4th parameter to
** sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
** This option is used to set, clear or query the flag that enables
** the [sqlite3session_changeset_size()] API. Because it imposes some
** computational overhead, this API is disabled by default. Argument
** pArg must point to a value of type (int). If the value is initially
** 0, then the sqlite3session_changeset_size() API is disabled. If it
** is greater than 0, then the same API is enabled. Or, if the initial
** value is less than zero, no change is made. In all cases the (int)
** variable is set to 1 if the sqlite3session_changeset_size() API is
** enabled following the current call, or 0 otherwise.
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
*/
SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
/*
*/
#define SQLITE_SESSION_OBJCONFIG_SIZE 1
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -10335,6 +10408,22 @@ SQLITE_API int sqlite3session_changeset(
void **ppChangeset /* OUT: Buffer containing changeset */
);
/*
** CAPI3REF: Return An Upper-limit For The Size Of The Changeset
** METHOD: sqlite3_session
**
** By default, this function always returns 0. For it to return
** a useful result, the sqlite3_session object must have been configured
** to enable this API using sqlite3session_object_config() with the
** SQLITE_SESSION_OBJCONFIG_SIZE verb.
**
** When enabled, this function returns an upper limit, in bytes, for the size
** of the changeset that might be produced if sqlite3session_changeset() were
** called. The final changeset size might be equal to or smaller than the
** size in bytes returned by this function.
*/
SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession);
/*
** CAPI3REF: Load The Difference Between Tables Into A Session
** METHOD: sqlite3_session

View File

@@ -30,6 +30,7 @@
#include "Poco/Data/SQLite/SQLiteException.h"
#include "Poco/Tuple.h"
#include "Poco/Any.h"
#include "Poco/UUIDGenerator.h"
#include "Poco/SharedPtr.h"
#include "Poco/DynamicAny.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()
{
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, testTupleVector1);
CppUnit_addTest(pSuite, SQLiteTest, testDateTime);
CppUnit_addTest(pSuite, SQLiteTest, testUUID);
CppUnit_addTest(pSuite, SQLiteTest, testInternalExtraction);
CppUnit_addTest(pSuite, SQLiteTest, testPrimaryKeyConstraint);
CppUnit_addTest(pSuite, SQLiteTest, testNullable);

View File

@@ -100,6 +100,8 @@ public:
void testDateTime();
void testUUID();
void testInternalExtraction();
void testPrimaryKeyConstraint();
void testNullable();

View File

@@ -5,8 +5,9 @@ POCO Data Library
POCO Data is POCO's database abstraction layer which allows users to
easily send/retrieve data to/from various databases. Currently supported
database connectors are SQLite, MySQL and ODBC. Framework is opened
for extension, so additional native connectors (Oracle, PostgreSQL, ...)
database connectors are SQLite, MySQL/MariaDB, PostgreSQL and ODBC (which
covers SQL Server and other databases).
Framework is opened for extension, so additional native connectors (Oracle, Db2, ...)
can be added. The intent behind the Poco::Data framework is to produce the
integration between C++ and relational databses in a simple and natural way.
@@ -16,54 +17,54 @@ The following complete example shows how to use POCO Data:
#include "Poco/Data/SQLite/Connector.h"
#include <vector>
#include <iostream>
using namespace Poco::Data::Keywords;
using Poco::Data::Session;
using Poco::Data::Statement;
struct Person
{
std::string name;
std::string address;
int age;
};
int main(int argc, char** argv)
{
// register SQLite connector
Poco::Data::SQLite::Connector::registerConnector();
// create a session
Session session("SQLite", "sample.db");
// drop sample table, if it exists
session << "DROP TABLE IF EXISTS Person", now;
// (re)create table
session << "CREATE TABLE Person (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;
// insert some rows
Person person =
Person person =
{
"Bart Simpson",
"Springfield",
12
};
Statement insert(session);
insert << "INSERT INTO Person VALUES(?, ?, ?)",
use(person.name),
use(person.address),
use(person.age);
insert.execute();
person.name = "Lisa Simpson";
person.address = "Springfield";
person.age = 10;
insert.execute();
// a simple query
Statement select(session);
select << "SELECT Name, Address, Age FROM Person",
@@ -71,24 +72,24 @@ The following complete example shows how to use POCO Data:
into(person.address),
into(person.age),
range(0, 1); // iterate over result set one row at a time
while (!select.done())
{
select.execute();
std::cout << person.name << " " << person.address << " " << person.age << std::endl;
}
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
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
for full namespace qualification; this document uses convention introduced in
for full namespace qualification; this document uses convention introduced in
the example above.
The remainder of this tutorial is split up into the following parts:
@@ -117,20 +118,23 @@ parameter contains the 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
a complete ODBC driver-specific connection string defining all the necessary connection parameters
(for details, consult your ODBC driver documentation).
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
(for details, consult your ODBC driver documentation).
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
automatic reconnect. Example: <["host=localhost;port=3306;db=mydb;user=alice;password=s3cr3t;compress=true;auto-reconnect=true"]>
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
automatic reconnect. Example:
"host=localhost;port=3306;db=mydb;user=alice;password=s3cr3t;compress=true;auto-reconnect=true"
----
!!!Inserting and Retrieving Data
!!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:
ForeName (Name VARCHAR(30))
@@ -139,17 +143,17 @@ Assume we have a table that stores only forenames:
If we want to insert one single forename we could simply write:
std::string aName("Peter");
session << "INSERT INTO FORENAME VALUES(" << aName << ")", now;
session << "INSERT INTO FORENAME VALUES('" << aName << "')", now;
----
However, a better solution is to use <*placeholders*> and connect each
placeholder via a <[use]> expression with a variable that will provide
placeholder via a `use` expression with a variable that will provide
the value during execution. Placeholders, depending on your database are
recognized by having either a colon(<[:]>) in front of the name or
simply by a question mark (<[?]>) as a placeholder. While having the
recognized by having either a colon (`:`) in front of the name or
simply by a question mark (`?`) as a placeholder. While having the
placeholders marked with a colon followed by a human-readable name is
very convenient due to readability, not all SQL dialects support this and
universally accepted standard placeholder is (<[?]>). Consult your database
universally accepted standard placeholder is `?`. Consult your database
SQL documentation to determine the valid placeholder syntax.
Rewriting the above code now simply gives:
@@ -159,8 +163,8 @@ Rewriting the above code now simply gives:
----
In this example the <[use]> expression matches the placeholder with the
<[Peter]> value. Note that apart from the nicer syntax, the real benefits of
placeholders -- which are performance and protection against SQL injection
<[Peter]> value. Note that apart from the nicer syntax, the real benefits of
placeholders -- which are performance and protection against SQL injection
attacks -- don't show here. Check the <[Statements]> section to find out more.
Retrieving data from the Database works similar. The <[into]>
@@ -172,14 +176,14 @@ database:
ses << "SELECT NAME FROM FORENAME", into(aName), 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
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.
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
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
output target.
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 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
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::Dynamic::Var, which will be set as empty for null values when used as query
output target.
----
It is also possible to combine into and use expressions:
@@ -224,18 +228,18 @@ To accomodate for NULL, use the Poco::Nullable template:
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.
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
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
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
tweak it to user's needs through folowing <[Session]> features:
*emptyStringIsNull
*forceEmptyString
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:
@@ -259,7 +263,7 @@ set it belongs to:
std::vector<Person> people;
Person pHomer, pLisa;
int aHomer(42), aLisa(10), aBart(0);
session << "SELECT * FROM Person WHERE Age = ?; "
"SELECT Age FROM Person WHERE FirstName = 'Bart'; "
"SELECT * FROM Person WHERE Age = ?",
@@ -293,7 +297,7 @@ More on statements and manipulators in the chapters that follow.
Most of the modern database systems support stored procedures and/or
functions. Does Poco::Data provide any support there? You bet.
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
best to provide reasonable access to such functionality through <[in]>,
<[out]> and <[io]> binding functions. As their names imply, these
@@ -306,7 +310,7 @@ here's an Oracle ODBC example:
" temp NUMBER := param1; "
" BEGIN param1 := param2; param2 := temp; RETURN(param1+param2); "
" END storedFunction;" , now;
int i = 1, j = 2, result = 0;
session << "{? = call storedFunction(?, ?)}", out(result), io(i), io(j), now; // i = 2, j = 1, result = 3
----
@@ -322,10 +326,10 @@ Stored procedures are allowed to return data sets (a.k.a. cursors):
" ret SYS_REFCURSOR; "
"BEGIN "
" OPEN ret FOR "
" SELECT * FROM Person WHERE Age < ageLimit; "
" SELECT * FROM Person WHERE Age < ageLimit; "
" RETURN ret; "
"END storedCursorFunction;" , now;
session << "{call storedCursorFunction(?)}", in(age), into(people), now;
----
@@ -387,8 +391,8 @@ Here's how we control when to actually execute the statement:
----
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
statement was fully completed.
the value was inserted. The check to <[stmt.done()]> simply guarantees that the
statement was fully completed.
@@ -479,7 +483,7 @@ return value is because, for asynchronous statements, <[execute()]>
always returns zero. This makes sense, because it does not know the
number of returned rows (remember, asynchronous <[execute()]> call
returns <[immediately]> and does not wait for the completion of the
execution).
execution).
!A Word of Warning
@@ -513,7 +517,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
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 for later retrieval through <[RecordSet]>. For details, see <[RecordSet]> chapter.
@@ -538,7 +542,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,
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 ("%%"):
Statement stmt = (ses << "SELECT * FROM %s WHERE Name LIKE 'Simp%%'", "Person");
@@ -609,8 +613,8 @@ not!> be used in conjunction with <[out]> and <[io]> under any
circumstances: <[std::vector<bool>]> . The details are beyond the scope
of this manual. For those interested to learn more about it, there is an
excellent explanation in S. Meyers book "Efective STL", Item 18 or Gotw
#50, [[http://www.gotw.ca/gotw/050.htm When Is a Container Not a
Container]] paragraph.
#50, [[http://www.gotw.ca/gotw/050.htm When Is a Container Not a Container]]
paragraph.
!!!Tuples
@@ -696,13 +700,13 @@ object until <[statement.done()]> returns true.
For the next example, we assume that our system knows about 101 forenames:
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
poco_assert (!stmt.done());
stmt.execute(); //names.size() == 100
poco_assert (!stmt.done());
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
@@ -750,14 +754,14 @@ off.
The <[bulk]> keyword allows to boost performance for the connectors that
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:
std::vector<int> ints(100, 1);
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:
@@ -771,8 +775,8 @@ size of data set we want to fetch, either explicitly as in the code
above or implicitly, through size of the supplied container as in
following example:
std::vector<int> ints(100, 1);
session << "SELECT * FROM Test", into(ints, bulk), now;
std::vector<int> ints(100, 1);
session << "SELECT * FROM Test", into(ints, bulk), now;
----
For statements that generate their ow internal extraction storage (see
@@ -827,7 +831,7 @@ feature.
!!! RecordSets, Iterators and Rows
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, something like this:
@@ -840,16 +844,16 @@ No worries -- that's what the RecordSet class does:
Statement select(session); // we need a Statement for later RecordSet creation
select << "SELECT * FROM Person", now;
// create a RecordSet
// create a RecordSet
RecordSet rs(select);
std::size_t cols = rs.columnCount();
// print all column names
for (std::size_t col = 0; col < cols; ++col)
std::cout << rs.columnName(col) << std::endl;
// 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 << " ";
----
@@ -889,7 +893,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
(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
----
@@ -914,7 +918,7 @@ Valid storage type manipulators are:
So, if neither data storage, nor storage type are explicitly specified,
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
@@ -930,19 +934,19 @@ Assume you have a class Person:
// default constructor+destr.
// getter and setter methods for all members
// ...
bool operator <(const Person&amp; p) const
/// we need this for set and multiset support
{
return _socialSecNr < p._socialSecNr;
}
Poco::UInt64 operator()() const
/// we need this operator to return the key for the map and multimap
{
return _socialSecNr;
}
private:
std::string _firstName;
std::string _lastName;
@@ -953,12 +957,12 @@ Assume you have a class Person:
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]>
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:
namespace Poco {
namespace Data {
template <>
class TypeHandler<class Person>
{
@@ -972,12 +976,12 @@ The template specialization must implement the following methods:
TypeHandler<std::string>::bind(pos++, obj.getLastName(), pBinder, dir);
TypeHandler<Poco::UInt64>::bind(pos++, obj.getSocialSecNr(), pBinder, dir);
}
static std::size_t size()
{
return 3; // we handle three columns of the Table!
}
static void prepare(std::size_t pos, const Person&amp; obj, AbstractPreparator::Ptr pPrepare)
{
poco_assert_dbg (!pPrepare.isNull());
@@ -987,7 +991,7 @@ The template specialization must implement the following methods:
TypeHandler<std::string>::prepare(pos++, obj.getLastName(), pPrepare);
TypeHandler<Poco::UInt64>::prepare(pos++, obj.getSocialSecNr(), pPrepare);
}
static void extract(std::size_t pos, Person&amp; obj, const Person&amp; defVal, AbstractExtractor::Ptr pExt)
/// obj will contain the result, defVal contains values we should use when one column is NULL
{
@@ -1002,14 +1006,14 @@ The template specialization must implement the following methods:
obj.setLastName(lastName);
obj.setSocialSecNr(socialSecNr);
}
private:
TypeHandler();
~TypeHandler();
TypeHandler(const TypeHandler&amp;);
TypeHandler&amp; operator=(const TypeHandler&amp;);
};
} } // namespace Poco::Data
----
@@ -1022,8 +1026,9 @@ working with a string:
!!!Session Pooling
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.
A Poco::Data::SessionPool manages a collection of sessions.
@@ -1046,7 +1051,7 @@ Pooled sessions are automatically returned to the pool when the
Session variable holding them is destroyed.
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 spc;
@@ -1060,15 +1065,15 @@ SessionPoolContainer:
This document provides an overview of the most important features
offered by the POCO Data framework. The framework also supports LOB
(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
(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
did not go into details here.
The great deal of <[RecordSet]> and <[Row]> runtime "magic" is achieved
through employment of Poco::Dynamic::Var, which is the POCO
equivalent of dynamic language data type. Obviously, due to its nature,
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,
with configurable efficiency/convenience ratio, providing a solid

View File

@@ -1,63 +0,0 @@
POCO Data Release Notes
POCO Data Library
!!!Release 1.5.0
The Data library has been available since the 1.2 release. For the 1.5.0 release, a few things have been changed in an incompatible way that requires changes
to existing code.
!!Summary of Changes
- Poco::Data::RowFormatter class for convenient output formatting.
- Stored procedures support (for databases and ODBC drivers that support it).
- Improved transaction support (for databases that support it).
- Bulk execution (for ODBC drivers that support it).
- Batch queries and multiple results (for databases and ODBC drivers that support it).
- Stored procedures/functions support (for databases that support it)
- New Poco::Data::SessionPoolContainer class.
!!Incompatible Changes and Possible Transition Issues
Keywords (use, into, limit, etc) now reside in Poco::Data::Keywords namespace.
!!!Release 1.5.2
!!Summary of Changes
- framework-wide refactoring to use SharedPtr-based garbage collection
!!Incompatible Changes and Possible Transition Issues
Internally, (Abstract)Binder, Extracion nas (where applicable) Preparator are garbage collected.
While old way of passing pointers to TypeHandler may still work, it is strongly recommended
to pass SharedPtr to handler functions, e.g. :
template <>
class TypeHandler<Person>
{
public:
static std::size_t size()
{
return 3;
}
static void bind(std::size_t pos, const Person& person, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir)
{
TypeHandler<std::string>::bind(pos++, person.name, pBinder, dir);
// ...
}
static void extract(std::size_t pos, Person& person, const Person& deflt, AbstractExtractor::Ptr pExtr)
{
TypeHandler<std::string>::extract(pos++, person.name, deflt.name, pExtr);
// ...
}
static void prepare(std::size_t pos, const Person& person, AbstractPreparator::Ptr pPrep)
{
TypeHandler<std::string>::prepare(pos++, person.name, pPrep);
// ...
}
};

View File

@@ -24,6 +24,7 @@
#include "Poco/Data/LOB.h"
#include "Poco/DateTime.h"
#include "Poco/Nullable.h"
#include "Poco/UUID.h"
#include "Poco/Any.h"
#include "Poco/Dynamic/Var.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);
/// 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;
/// Binds a null.

View File

@@ -21,6 +21,7 @@
#include "Poco/Data/Data.h"
#include "Poco/Data/Constants.h"
#include "Poco/Data/LOB.h"
#include "Poco/UUID.h"
#include "Poco/UTFString.h"
#include <vector>
#include <deque>
@@ -304,6 +305,18 @@ public:
virtual bool extract(std::size_t pos, std::list<Time>& val);
/// 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;
/// Extracts an Any. Returns false if null was received.

View File

@@ -21,6 +21,7 @@
#include "Poco/Data/Data.h"
#include "Poco/RefCountedObject.h"
#include "Poco/Data/LOB.h"
#include "Poco/UUID.h"
#include "Poco/UTFString.h"
#include <vector>
#include <deque>
@@ -310,6 +311,18 @@ public:
virtual void prepare(std::size_t pos, const std::list<Time>& val);
/// 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;
/// Prepares an Any.

View File

@@ -130,7 +130,18 @@ public:
if (_pContent->empty())
return 0;
else
return &(*_pContent)[0];
return _pContent->data();
}
T* rawContent()
/// Returns the raw content.
///
/// If the LOB is empty, returns NULL.
{
if (_pContent->empty())
return 0;
else
return _pContent->data();
}
void assignVal(std::size_t count, const T& val)
@@ -155,6 +166,18 @@ public:
_pContent->insert(_pContent->end(), pChar, pChar+count);
}
void reserve(std::size_t size)
/// Sets the capacity of the internal buffer.
{
_pContent->reserve(size);
}
void resize(std::size_t size)
/// Resizes the internal buffer.
{
_pContent->resize(size);
}
void clear(bool doCompact = false)
/// Clears the content of the blob.
/// If doCompact is true, trims the excess capacity.
@@ -185,6 +208,12 @@ public:
return static_cast<std::size_t>(_pContent->size());
}
std::size_t capacity() const
/// Returns the capacity of the underlying buffer.
{
return static_cast<std::size_t>(_pContent->capacity());
}
private:
ContentPtr _pContent;
};

View File

@@ -50,6 +50,7 @@ public:
FDT_DATE,
FDT_TIME,
FDT_TIMESTAMP,
FDT_UUID,
FDT_UNKNOWN
};

View File

@@ -55,7 +55,7 @@ class Data_API SQLChannel: public Poco::Channel
/// To provide as non-intrusive operation as possbile, the log entries are cached and
/// inserted into the target database asynchronously by default. The blocking, however, will occur
/// before the next entry insertion with default timeout of 1 second. The default settings can be
/// overriden (see async, timeout and throw properties for details).
/// overridden (see async, timeout and throw properties for details).
/// If throw property is false, insertion timeouts are ignored, otherwise a TimeoutException is thrown.
/// To force insertion of every entry, set timeout to 0. This setting, however, introduces
/// a risk of long blocking periods in case of remote server communication delays.

View File

@@ -70,19 +70,19 @@ public:
enum BulkType
{
BULK_UNDEFINED,
BULK_UNDEFINED,
/// Bulk mode not defined yet.
BULK_BINDING,
BULK_BINDING,
/// Binding in bulk mode.
/// If extraction is present in the same statement,
/// If extraction is present in the same statement,
/// it must also be bulk.
BULK_EXTRACTION,
BULK_EXTRACTION,
/// Extraction in bulk mode.
/// If binding is present in the same statement,
/// If binding is present in the same statement,
/// it must also be bulk.
BULK_FORBIDDEN
/// Bulk forbidden.
/// Happens when the statement has already been
BULK_FORBIDDEN
/// Bulk forbidden.
/// Happens when the statement has already been
/// configured as non-bulk.
};
@@ -99,7 +99,7 @@ public:
virtual ~StatementImpl();
/// Destroys the StatementImpl.
template <typename T>
template <typename T>
void add(const T& t)
/// Appends SQL statement (fragments).
{
@@ -117,15 +117,15 @@ public:
/// Registers objects used for extracting data with the StatementImpl.
void setExtractionLimit(const Limit& extrLimit);
/// Changes the extractionLimit to extrLimit.
/// Changes the extractionLimit to extrLimit.
/// Per default no limit (EXTRACT_UNLIMITED) is set.
std::string toString() const;
/// Create a string version of the SQL statement.
std::size_t execute(const bool& reset = true);
/// Executes a statement. Returns the number of rows
/// extracted for statements returning data or number of rows
/// Executes a statement. Returns the number of rows
/// extracted for statements returning data or number of rows
/// affected for all other statements (insert, update, delete).
/// If reset is true (default), the underlying bound storage is
/// reset and reused. In case of containers, this means they are
@@ -154,15 +154,15 @@ public:
std::size_t dataSetCount() const;
/// Returns the number of data sets associated with the statement.
protected:
virtual std::size_t columnsReturned() const = 0;
/// Returns number of columns returned by query.
/// Returns number of columns returned by query.
virtual int affectedRowCount() const = 0;
/// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert, delete or update.
///
///
/// Some back-ends may return a negative number in certain circumstances (e.g.
/// some ODBC drivers when this function is called after a select statement
/// execution).
@@ -174,10 +174,10 @@ protected:
/// Returns column meta data.
virtual bool hasNext() = 0;
/// Returns true if a call to next() will return data.
/// Returns true if a call to next() will return data.
///
/// Note that the implementation must support
/// several consecutive calls to hasNext without data getting lost,
/// several consecutive calls to hasNext without data getting lost,
/// ie. hasNext(); hasNext(); next() must be equal to hasNext(); next();
virtual std::size_t next() = 0;
@@ -232,8 +232,8 @@ protected:
/// Determines the type of the internal extraction container and
/// calls the extraction creation function (addInternalExtract)
/// with appropriate data type and container type arguments.
///
/// This function is only called in cases when there is data
///
/// This function is only called in cases when there is data
/// returned by query, but no data storage supplied by user.
///
/// The type of the internal container is determined in the
@@ -273,24 +273,24 @@ protected:
/// Used as a help to determine whether to automatically create the
/// internal extractions when no outside extraction is supplied.
/// The reason for this function is to prevent unnecessary internal
/// extraction creation in cases (behavior exhibited by some ODBC drivers)
/// when there is data available from the stored procedure call
/// statement execution but no external extraction is supplied (as is
/// extraction creation in cases (behavior exhibited by some ODBC drivers)
/// when there is data available from the stored procedure call
/// statement execution but no external extraction is supplied (as is
/// usually the case when stored procedures are called). In such cases
/// no storage is needed because output parameters serve as storage.
/// At the Data framework level, this function always returns false.
/// When connector-specific behavior is desired, it should be overriden
/// When connector-specific behavior is desired, it should be overridden
/// by the statement implementation.
std::size_t currentDataSet() const;
/// Returns the current data set.
std::size_t activateNextDataSet();
/// Returns the next data set index, or throws NoDataException if the last
/// Returns the next data set index, or throws NoDataException if the last
/// data set was reached.
std::size_t activatePreviousDataSet();
/// Returns the previous data set index, or throws NoDataException if the last
/// Returns the previous data set index, or throws NoDataException if the last
/// data set was reached.
bool hasMoreDataSets() const;
@@ -304,13 +304,13 @@ private:
/// Binds the statement, if not yet bound.
std::size_t executeWithLimit();
/// Executes with an upper limit set. Returns the number of rows
/// extracted for statements returning data or number of rows
/// Executes with an upper limit set. Returns the number of rows
/// extracted for statements returning data or number of rows
/// affected for all other statements (insert, update, delete).
std::size_t executeWithoutLimit();
/// Executes without an upper limit set. Returns the number of rows
/// extracted for statements returning data or number of rows
/// Executes without an upper limit set. Returns the number of rows
/// extracted for statements returning data or number of rows
/// affected for all other statements (insert, update, delete).
void resetExtraction();
@@ -339,7 +339,7 @@ private:
void addInternalExtract(const MetaColumn& mc)
/// Creates and adds the internal extraction.
///
/// The decision about internal extraction container is done
/// The decision about internal extraction container is done
/// in a following way:
///
/// If this statement has _storage member set, that setting
@@ -349,17 +349,17 @@ private:
/// type set, std::vector is the default container type used.
{
std::string storage;
switch (_storage)
{
case STORAGE_DEQUE_IMPL:
case STORAGE_DEQUE_IMPL:
storage = DEQUE; break;
case STORAGE_VECTOR_IMPL:
case STORAGE_VECTOR_IMPL:
storage = VECTOR; break;
case STORAGE_LIST_IMPL:
case STORAGE_LIST_IMPL:
storage = LIST; break;
case STORAGE_UNKNOWN_IMPL:
storage = AnyCast<std::string>(session().getProperty("storage"));
storage = AnyCast<std::string>(session().getProperty("storage"));
break;
}
@@ -390,7 +390,7 @@ private:
bool isNull(std::size_t col, std::size_t row) const;
/// Returns true if the value in [col, row] is null.
void forbidBulk();
/// Forbids bulk operations.
@@ -399,7 +399,7 @@ private:
void setBulkExtraction(const Bulk& l);
/// Sets the bulk extraction flag and extraction limit.
void resetBulk();
/// Resets the bulk extraction and binding flag.
@@ -446,7 +446,7 @@ private:
BulkType _bulkExtraction;
CountVec _subTotalRowCount;
friend class Statement;
friend class Statement;
};
@@ -538,13 +538,13 @@ inline bool StatementImpl::isStoredProcedure() const
inline bool StatementImpl::isNull(std::size_t col, std::size_t row) const
{
try
try
{
return extractions().at(col)->isNull(row);
}
catch (std::out_of_range& ex)
{
throw RangeException(ex.what());
{
throw RangeException(ex.what());
}
}
@@ -605,7 +605,7 @@ inline bool StatementImpl::isBulkExtraction() const
return BULK_EXTRACTION == _bulkExtraction;
}
inline void StatementImpl::resetBulk()
{
_bulkExtraction = BULK_UNDEFINED;

View File

@@ -34,7 +34,7 @@ namespace Data {
class AbstractTypeHandler
/// Parent class for type handlers.
/// Parent class for type handlers.
/// The reason for this class is to prevent instantiations of type handlers.
/// For documentation on type handlers, see TypeHandler class.
{
@@ -59,12 +59,12 @@ class TypeHandler: public AbstractTypeHandler
/// int _age;
/// public:
/// const std::string& getLastName();
/// [...] // other set/get methods (returning const reference), a default constructor,
/// [...] // other set/get methods (returning const reference), a default constructor,
/// [...] // optional < operator (for set, multiset) or function operator (for map, multimap)
/// };
///
/// The TypeHandler must provide a custom bind, size, prepare and extract method:
///
///
/// template <>
/// class TypeHandler<struct Person>
/// {
@@ -73,7 +73,7 @@ class TypeHandler: public AbstractTypeHandler
/// {
/// return 3; // lastName + firstname + age occupy three columns
/// }
///
///
/// static void bind(std::size_t pos, const Person& obj, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir)
/// {
/// // the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Age INTEGER(3))
@@ -83,7 +83,7 @@ class TypeHandler: public AbstractTypeHandler
/// TypeHandler<std::string>::bind(pos++, obj.getFirstName(), pBinder, dir);
/// TypeHandler<int>::bind(pos++, obj.getAge(), pBinder, dir);
/// }
///
///
/// static void prepare(std::size_t pos, const Person& obj, AbstractPreparator::Ptr pPreparator)
/// {
/// // the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Age INTEGER(3))
@@ -92,7 +92,7 @@ class TypeHandler: public AbstractTypeHandler
/// TypeHandler<std::string>::prepare(pos++, obj.getFirstName(), pPreparator);
/// TypeHandler<int>::prepare(pos++, obj.getAge(), pPreparator);
/// }
///
///
/// static void extract(std::size_t pos, Person& obj, const Person& defVal, AbstractExtractor::Ptr pExt)
/// {
/// // defVal is the default person we should use if we encunter NULL entries, so we take the individual fields
@@ -249,52 +249,52 @@ private:
};
template <typename T>
class TypeHandler<Nullable<T>>
class TypeHandler<Nullable<T>>
/// Specialization of type handler for Nullable.
{
public:
static void bind(std::size_t pos, const Nullable<T>& obj, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir)
static void bind(std::size_t pos, const Nullable<T>& obj, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir)
{
poco_assert_dbg (!pBinder.isNull());
if (obj.isNull())
if (obj.isNull())
{
pBinder->bind(pos++, Poco::Data::Keywords::null, dir);
}
else
else
{
pBinder->bind(pos++, obj.value(), dir);
}
}
static void prepare(std::size_t pos, const Nullable<T>& obj, AbstractPreparator::Ptr pPreparator)
static void prepare(std::size_t pos, const Nullable<T>& obj, AbstractPreparator::Ptr pPreparator)
{
poco_assert_dbg (!pPreparator.isNull());
if (obj.isNull())
if (obj.isNull())
{
pPreparator->prepare(pos++, Poco::Data::Keywords::null);
pPreparator->prepare(pos++, T());
}
else
else
{
pPreparator->prepare(pos++, obj.value());
}
}
static std::size_t size()
static std::size_t size()
{
return 1u;
}
static void extract(std::size_t pos, Nullable<T>& obj, const Nullable<T>& , AbstractExtractor::Ptr pExt)
static void extract(std::size_t pos, Nullable<T>& obj, const Nullable<T>& , AbstractExtractor::Ptr pExt)
{
poco_assert_dbg (!pExt.isNull());
T val;
if (pExt->extract(pos++, val))
if (pExt->extract(pos++, val))
{
obj = val;
obj = std::move(val);
}
else
else
{
obj.clear();
}
@@ -343,25 +343,25 @@ void tupleExtract(std::size_t& pos, TupleType tuple, DefValType defVal, Abstract
}
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15,
class T16,
class T17,
class T18,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15,
class T16,
class T17,
class T18,
class T19>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19>>
{
@@ -474,24 +474,24 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15,
class T16,
class T17,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15,
class T16,
class T17,
class T18>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18>>
{
@@ -600,23 +600,23 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15,
class T16,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15,
class T16,
class T17>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17>>
{
@@ -721,22 +721,22 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15,
class T16>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>>
{
@@ -837,21 +837,21 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14,
class T15>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15>>
{
@@ -948,20 +948,20 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13,
class T14>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>>
{
@@ -1054,19 +1054,19 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12,
class T13>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13>>
{
@@ -1155,18 +1155,18 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11,
class T12>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12>>
{
@@ -1251,17 +1251,17 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10,
class T11>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11>>
{
@@ -1342,16 +1342,16 @@ private:
};
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
template <class T0,
class T1,
class T2,
class T3,
class T4,
class T5,
class T6,
class T7,
class T8,
class T9,
class T10>
class TypeHandler<Poco::Tuple<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10>>
{
@@ -1956,7 +1956,7 @@ public:
return TypeHandler<T0>::size();
}
static void extract(std::size_t pos, TupleRef tuple, TupleConstRef defVal,
static void extract(std::size_t pos, TupleRef tuple, TupleConstRef defVal,
AbstractExtractor::Ptr pExt)
{
poco_assert_dbg (!pExt.isNull());
@@ -2013,7 +2013,7 @@ public:
static void bind(std::size_t pos, const Poco::AutoPtr<T>& obj, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir)
{
// *obj will trigger a nullpointer exception if empty: this is on purpose
TypeHandler<T>::bind(pos, *obj, pBinder, dir);
TypeHandler<T>::bind(pos, *obj, pBinder, dir);
}
static std::size_t size()
@@ -2024,7 +2024,7 @@ public:
static void extract(std::size_t pos, Poco::AutoPtr<T>& obj, const Poco::AutoPtr<T>& defVal, AbstractExtractor::Ptr pExt)
{
poco_assert_dbg (!pExt.isNull());
obj = Poco::AutoPtr<T>(new T());
if (defVal)
TypeHandler<T>::extract(pos, *obj, *defVal, pExt);
@@ -2053,7 +2053,7 @@ public:
static void bind(std::size_t pos, const Poco::SharedPtr<T>& obj, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir)
{
// *obj will trigger a nullpointer exception if empty
TypeHandler<T>::bind(pos, *obj, pBinder, dir);
TypeHandler<T>::bind(pos, *obj, pBinder, dir);
}
static std::size_t size()
@@ -2064,7 +2064,7 @@ public:
static void extract(std::size_t pos, Poco::SharedPtr<T>& obj, const Poco::SharedPtr<T>& defVal, AbstractExtractor::Ptr pExt)
{
poco_assert_dbg (!pExt.isNull());
obj = Poco::SharedPtr<T>(new T());
if (defVal)
TypeHandler<T>::extract(pos, *obj, *defVal, pExt);

View File

@@ -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)
{
throw NotImplementedException("std::vector binder must be implemented.");

View File

@@ -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)
{
throw NotImplementedException("std::vector extractor must be implemented.");

View File

@@ -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)
{
throw NotImplementedException("std::vector preparator must be implemented.");

View File

@@ -34,7 +34,7 @@ const std::size_t RecordSet::UNKNOWN_TOTAL_ROW_COUNT = std::numeric_limits<std::
RecordSet::RecordSet(const Statement& rStatement,
RowFormatter::Ptr pRowFormatter):
RowFormatter::Ptr pRowFormatter):
Statement(rStatement),
_currentRow(0),
_pBegin(new RowIterator(this, 0 == rowsExtracted())),
@@ -45,9 +45,9 @@ RecordSet::RecordSet(const Statement& rStatement,
}
RecordSet::RecordSet(Session& rSession,
const std::string& query,
RowFormatter::Ptr pRowFormatter):
RecordSet::RecordSet(Session& rSession,
const std::string& query,
RowFormatter::Ptr pRowFormatter):
Statement((rSession << query, now)),
_currentRow(0),
_pBegin(new RowIterator(this, 0 == rowsExtracted())),
@@ -119,7 +119,7 @@ void RecordSet::reset(const Statement& stmt)
_pEnd = 0;
_currentRow = 0;
_totalRowCount = UNKNOWN_TOTAL_ROW_COUNT;
RowMap::iterator it = _rowMap.begin();
RowMap::iterator end = _rowMap.end();
for (; it != end; ++it) delete it->second;
@@ -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_TIME: return value<Time>(col, row, useFilter);
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, row);
case MetaColumn::FDT_UUID: return value<UUID>(col, row);
default:
throw UnknownTypeException("Data type not supported.");
}
@@ -188,9 +189,11 @@ Poco::Dynamic::Var RecordSet::value(const std::string& name, std::size_t row, bo
case MetaColumn::FDT_STRING: return value<std::string>(name, row, useFilter);
case MetaColumn::FDT_WSTRING: return value<UTF16String>(name, row, useFilter);
case MetaColumn::FDT_BLOB: return value<BLOB>(name, row, useFilter);
case MetaColumn::FDT_CLOB: return value<CLOB>(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_TIMESTAMP: return value<DateTime>(name, row, useFilter);
case MetaColumn::FDT_UUID: return value<UUID>(name, row, useFilter);
default:
throw UnknownTypeException("Data type not supported.");
}
@@ -210,7 +213,7 @@ Row& RecordSet::row(std::size_t pos)
{
if (_rowMap.size())
{
//reuse first row column names and sorting fields to save some memory
//reuse first row column names and sorting fields to save some memory
pRow = new Row(_rowMap.begin()->second->names(),
_rowMap.begin()->second->getSortMap(),
getRowFormatter());
@@ -218,7 +221,7 @@ Row& RecordSet::row(std::size_t pos)
for (std::size_t col = 0; col < columns; ++col)
pRow->set(col, value(col, pos));
}
else
else
{
pRow = new Row;
pRow->setFormatter(getRowFormatter());
@@ -228,7 +231,7 @@ Row& RecordSet::row(std::size_t pos)
_rowMap.insert(RowMap::value_type(pos, pRow));
}
else
else
{
pRow = it->second;
poco_check_ptr (pRow);

View File

@@ -65,7 +65,7 @@ Session SessionPool::get()
{
Poco::Mutex::ScopedLock lock(_mutex);
if (_shutdown) throw InvalidAccessException("Session pool has been shut down.");
purgeDeadSessions();
if (_idleSessions.empty())
@@ -85,7 +85,7 @@ Session SessionPool::get()
PooledSessionHolderPtr pHolder(_idleSessions.front());
PooledSessionImplPtr pPSI(new PooledSessionImpl(pHolder));
_activeSessions.push_front(pHolder);
_idleSessions.pop_front();
return Session(pPSI);
@@ -115,14 +115,14 @@ int SessionPool::capacity() const
return _maxSessions;
}
int SessionPool::used() const
{
Poco::Mutex::ScopedLock lock(_mutex);
return (int) _activeSessions.size();
}
int SessionPool::idle() const
{
Poco::Mutex::ScopedLock lock(_mutex);
@@ -153,7 +153,7 @@ int SessionPool::allocated() const
return _nSessions;
}
int SessionPool::available() const
{
if (_shutdown) return 0;
@@ -233,28 +233,43 @@ void SessionPool::putBack(PooledSessionHolderPtr pHolder)
SessionList::iterator it = std::find(_activeSessions.begin(), _activeSessions.end(), pHolder);
if (it != _activeSessions.end())
{
if (pHolder->session()->isGood())
try
{
pHolder->session()->reset();
if (pHolder->session()->isGood())
{
pHolder->session()->reset();
// reverse settings applied at acquisition time, if any
AddPropertyMap::iterator pIt = _addPropertyMap.find(pHolder->session());
if (pIt != _addPropertyMap.end())
pHolder->session()->setProperty(pIt->second.first, pIt->second.second);
// reverse settings applied at acquisition time, if any
AddPropertyMap::iterator pIt = _addPropertyMap.find(pHolder->session());
if (pIt != _addPropertyMap.end())
pHolder->session()->setProperty(pIt->second.first, pIt->second.second);
AddFeatureMap::iterator fIt = _addFeatureMap.find(pHolder->session());
if (fIt != _addFeatureMap.end())
pHolder->session()->setFeature(fIt->second.first, fIt->second.second);
AddFeatureMap::iterator fIt = _addFeatureMap.find(pHolder->session());
if (fIt != _addFeatureMap.end())
pHolder->session()->setFeature(fIt->second.first, fIt->second.second);
// re-apply the default pool settings
applySettings(pHolder->session());
// re-apply the default pool settings
applySettings(pHolder->session());
pHolder->access();
_idleSessions.push_front(pHolder);
pHolder->access();
_idleSessions.push_front(pHolder);
}
else --_nSessions;
_activeSessions.erase(it);
}
catch (const Poco::Exception& e)
{
--_nSessions;
_activeSessions.erase(it);
poco_bugcheck_msg(format("Exception in SessionPool::putBack(): %s", e.displayText()).c_str());
}
catch (...)
{
--_nSessions;
_activeSessions.erase(it);
poco_bugcheck_msg("Unknown exception in SessionPool::putBack()");
}
else --_nSessions;
_activeSessions.erase(it);
}
else
{
@@ -268,13 +283,18 @@ void SessionPool::onJanitorTimer(Poco::Timer&)
Poco::Mutex::ScopedLock lock(_mutex);
if (_shutdown) return;
SessionList::iterator it = _idleSessions.begin();
SessionList::iterator it = _idleSessions.begin();
while (_nSessions > _minSessions && it != _idleSessions.end())
{
if ((*it)->idle() > _idleTime || !(*it)->session()->isGood())
{
try { (*it)->session()->close(); }
catch (...) { }
{
try
{
(*it)->session()->close();
}
catch (...)
{
}
it = _idleSessions.erase(it);
--_nSessions;
}
@@ -296,15 +316,20 @@ void SessionPool::shutdown()
void SessionPool::closeAll(SessionList& sessionList)
{
SessionList::iterator it = sessionList.begin();
SessionList::iterator it = sessionList.begin();
for (; it != sessionList.end();)
{
try { (*it)->session()->close(); }
catch (...) { }
try
{
(*it)->session()->close();
}
catch (...)
{
}
it = sessionList.erase(it);
if (_nSessions > 0) --_nSessions;
}
}
} } // namespace Poco::Data
} } // namespace Poco::Data

View File

@@ -131,15 +131,15 @@ std::size_t StatementImpl::executeWithLimit()
do
{
bind();
while (count < limit && hasNext())
while (count < limit && hasNext())
count += next();
} while (count < limit && canBind());
if (!canBind() && (!hasNext() || limit == 0))
if (!canBind() && (!hasNext() || limit == 0))
_state = ST_DONE;
else if (hasNext() && limit == count && _extrLimit.isHardLimit())
throw LimitException("HardLimit reached (retrieved more data than requested).");
else
else
_state = ST_PAUSED;
int affectedRows = affectedRowCount();
@@ -177,8 +177,8 @@ std::size_t StatementImpl::executeWithoutLimit()
void StatementImpl::compile()
{
if (_state == ST_INITIALIZED ||
_state == ST_RESET ||
if (_state == ST_INITIALIZED ||
_state == ST_RESET ||
_state == ST_BOUND)
{
compileImpl();
@@ -298,7 +298,7 @@ void StatementImpl::setStorage(const std::string& storage)
if (0 == icompare(DEQUE, storage))
_storage = STORAGE_DEQUE_IMPL;
else if (0 == icompare(VECTOR, storage))
_storage = STORAGE_VECTOR_IMPL;
_storage = STORAGE_VECTOR_IMPL;
else if (0 == icompare(LIST, storage))
_storage = STORAGE_LIST_IMPL;
else if (0 == icompare(UNKNOWN, storage))
@@ -317,38 +317,42 @@ void StatementImpl::makeExtractors(std::size_t count)
{
case MetaColumn::FDT_BOOL:
addInternalExtract<bool>(mc); break;
case MetaColumn::FDT_INT8:
case MetaColumn::FDT_INT8:
addInternalExtract<Int8>(mc); break;
case MetaColumn::FDT_UINT8:
case MetaColumn::FDT_UINT8:
addInternalExtract<UInt8>(mc); break;
case MetaColumn::FDT_INT16:
case MetaColumn::FDT_INT16:
addInternalExtract<Int16>(mc); break;
case MetaColumn::FDT_UINT16:
case MetaColumn::FDT_UINT16:
addInternalExtract<UInt16>(mc); break;
case MetaColumn::FDT_INT32:
case MetaColumn::FDT_INT32:
addInternalExtract<Int32>(mc); break;
case MetaColumn::FDT_UINT32:
case MetaColumn::FDT_UINT32:
addInternalExtract<UInt32>(mc); break;
case MetaColumn::FDT_INT64:
case MetaColumn::FDT_INT64:
addInternalExtract<Int64>(mc); break;
case MetaColumn::FDT_UINT64:
case MetaColumn::FDT_UINT64:
addInternalExtract<UInt64>(mc); break;
case MetaColumn::FDT_FLOAT:
case MetaColumn::FDT_FLOAT:
addInternalExtract<float>(mc); break;
case MetaColumn::FDT_DOUBLE:
case MetaColumn::FDT_DOUBLE:
addInternalExtract<double>(mc); break;
case MetaColumn::FDT_STRING:
case MetaColumn::FDT_STRING:
addInternalExtract<std::string>(mc); break;
case MetaColumn::FDT_WSTRING:
addInternalExtract<Poco::UTF16String>(mc); break;
case MetaColumn::FDT_BLOB:
case MetaColumn::FDT_BLOB:
addInternalExtract<BLOB>(mc); break;
case MetaColumn::FDT_CLOB:
addInternalExtract<CLOB>(mc); break;
case MetaColumn::FDT_DATE:
addInternalExtract<Date>(mc); break;
case MetaColumn::FDT_TIME:
addInternalExtract<Time>(mc); break;
case MetaColumn::FDT_TIMESTAMP:
addInternalExtract<DateTime>(mc); break;
case MetaColumn::FDT_UUID:
addInternalExtract<UUID>(mc); break;
default:
throw Poco::InvalidArgumentException("Data type not supported.");
}
@@ -391,7 +395,7 @@ void StatementImpl::addExtract(AbstractExtraction::Ptr pExtraction)
{
poco_check_ptr (pExtraction);
std::size_t pos = pExtraction->position();
if (pos >= _extractors.size())
if (pos >= _extractors.size())
_extractors.resize(pos + 1);
pExtraction->setEmptyStringIsNull(
@@ -411,7 +415,7 @@ void StatementImpl::removeBind(const std::string& name)
AbstractBindingVec::iterator it = _bindings.begin();
for (; it != _bindings.end();)
{
if ((*it)->name() == name)
if ((*it)->name() == name)
{
it = _bindings.erase(it);
found = true;
@@ -446,7 +450,7 @@ std::size_t StatementImpl::rowsExtracted(int dataSet) const
if (_extractors[dataSet].size() > 0)
return _extractors[dataSet][0]->numOfRowsHandled();
}
return 0;
}
@@ -459,7 +463,7 @@ std::size_t StatementImpl::subTotalRowCount(int dataSet) const
poco_assert (dataSet >= 0 && dataSet < _subTotalRowCount.size());
return _subTotalRowCount[dataSet];
}
return 0;
}

View File

@@ -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)
{
}

View File

@@ -100,8 +100,11 @@ public:
void bind(std::size_t pos, const DateTime& val, Direction dir);
/// 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);
/// Binds a DateTime.
/// Binds a NullData.
void reset();
};

View File

@@ -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)
{
return true;
}
bool Extractor::extract(std::size_t pos, Poco::UUID& val)
{
return true;
}
bool Extractor::extract(std::size_t pos, Poco::Any& val)
{
return true;

View File

@@ -100,9 +100,12 @@ public:
bool extract(std::size_t pos, Time& val);
/// Extracts a Time.
bool extract(std::size_t pos, Poco::DateTime& val);
bool extract(std::size_t pos, DateTime& val);
/// 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);
/// Returns true if the current row value at pos column is null.

View File

@@ -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&)
{
}

View File

@@ -98,6 +98,9 @@ public:
void prepare(std::size_t pos, const Poco::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&);
/// Prepares an Any.