bulk internal extraction fixes and tests; some renaming/refactoring

This commit is contained in:
Aleksandar Fabijanic
2007-12-21 02:33:26 +00:00
parent 7a6904b383
commit ad61968449
33 changed files with 342 additions and 179 deletions

View File

@@ -17,7 +17,7 @@ $(error No ODBC library found. Please install unixODBC or iODBC and try again)
endif
objects = Binder ConnectionHandle Connector EnvironmentHandle \
Extractor ODBCColumn ODBCException ODBCStatementImpl \
Extractor ODBCMetaColumn ODBCException ODBCStatementImpl \
Parameter Preparation SessionImpl TypeInfo Unicode Utility
target = PocoODBC

View File

@@ -176,7 +176,7 @@
RelativePath=".\include\Poco\Data\Odbc\ODBC.h">
</File>
<File
RelativePath=".\include\Poco\Data\ODBC\ODBCColumn.h">
RelativePath=".\include\Poco\Data\ODBC\ODBCMetaColumn.h">
</File>
<File
RelativePath=".\include\Poco\Data\Odbc\ODBCException.h">
@@ -228,7 +228,7 @@
RelativePath=".\src\Extractor.cpp">
</File>
<File
RelativePath=".\src\ODBCColumn.cpp">
RelativePath=".\src\ODBCMetaColumn.cpp">
</File>
<File
RelativePath=".\src\ODBCException.cpp">

View File

@@ -246,11 +246,11 @@
>
</File>
<File
RelativePath=".\include\Poco\Data\ODBC\ODBCColumn.h"
RelativePath=".\include\Poco\Data\ODBC\ODBCException.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\ODBC\ODBCException.h"
RelativePath=".\include\Poco\Data\ODBC\ODBCMetaColumn.h"
>
</File>
<File
@@ -314,11 +314,11 @@
>
</File>
<File
RelativePath=".\src\ODBCColumn.cpp"
RelativePath=".\src\ODBCException.cpp"
>
</File>
<File
RelativePath=".\src\ODBCException.cpp"
RelativePath=".\src\ODBCMetaColumn.cpp"
>
</File>
<File

View File

@@ -44,7 +44,7 @@
#include "Poco/Data/AbstractBinder.h"
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/Parameter.h"
#include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/TypeInfo.h"
#include "Poco/Exception.h"

View File

@@ -43,7 +43,7 @@
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/AbstractExtractor.h"
#include "Poco/Data/ODBC/Preparation.h"
#include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Error.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/DateTime.h"
@@ -401,7 +401,7 @@ private:
bool extractImpl(std::size_t pos, T& val)
/// Utility function for extraction of Any and DynamicAny.
{
ODBCColumn column(_rStmt, pos);
ODBCMetaColumn column(_rStmt, pos);
switch (column.type())
{
@@ -504,7 +504,7 @@ inline bool Extractor::isNullLengthIndicator(SQLLEN val) const
inline SQLINTEGER Extractor::columnSize(std::size_t pos) const
{
std::size_t size = ODBCColumn(_rStmt, pos).length();
std::size_t size = ODBCMetaColumn(_rStmt, pos).length();
std::size_t maxSize = _rPreparation.maxDataSize(pos);
if (size > maxSize) size = maxSize;
return (SQLINTEGER) size;

View File

@@ -77,8 +77,13 @@ public:
~Handle()
/// Destroys the Handle.
{
SQLRETURN rc = SQLFreeHandle(handleType, _handle);
poco_assert (!Utility::isError(rc));
#if defined(_DEBUG)
SQLRETURN rc =
#endif
SQLFreeHandle(handleType, _handle);
// N.B. Destructors should not throw, but neither do we want to
// leak resources. So, we throw here in debug mode if things go bad.
poco_assert_dbg (!Utility::isError(rc));
}
operator const H& () const

View File

@@ -1,13 +1,13 @@
//
// ODBCColumn.h
// ODBCMetaColumn.h
//
// $Id: //poco/Main/Data/ODBC/include/Poco/Data/ODBC/ODBCColumn.h#3 $
// $Id: //poco/Main/Data/ODBC/include/Poco/Data/ODBC/ODBCMetaColumn.h#3 $
//
// Library: ODBC
// Package: ODBC
// Module: ODBCColumn
// Module: ODBCMetaColumn
//
// Definition of ODBCColumn.
// Definition of ODBCMetaColumn.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
@@ -56,14 +56,14 @@ namespace Data {
namespace ODBC {
class ODBC_API ODBCColumn: public MetaColumn
class ODBC_API ODBCMetaColumn: public MetaColumn
{
public:
explicit ODBCColumn(const StatementHandle& rStmt, std::size_t position);
/// Creates the ODBCColumn.
explicit ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position);
/// Creates the ODBCMetaColumn.
~ODBCColumn();
/// Destroys the ODBCColumn.
~ODBCMetaColumn();
/// Destroys the ODBCMetaColumn.
std::size_t dataLength() const;
/// A numeric value that is either the maximum or actual character length of a character
@@ -73,7 +73,7 @@ public:
/// This information is returned from the SQL_DESC_LENGTH record field of the IRD.
private:
ODBCColumn();
ODBCMetaColumn();
static const int NAME_BUFFER_LENGTH = 2048;
@@ -99,7 +99,7 @@ private:
///
/// inlines
///
inline std::size_t ODBCColumn::dataLength() const
inline std::size_t ODBCMetaColumn::dataLength() const
{
return _dataLength;
}

View File

@@ -45,7 +45,7 @@
#include "Poco/Data/ODBC/Binder.h"
#include "Poco/Data/ODBC/Extractor.h"
#include "Poco/Data/ODBC/Preparation.h"
#include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/StatementImpl.h"
#include "Poco/Data/Column.h"
#include "Poco/SharedPtr.h"
@@ -66,7 +66,7 @@ class ODBC_API ODBCStatementImpl: public Poco::Data::StatementImpl
/// Implements statement functionality needed for ODBC
{
public:
typedef std::vector<ODBCColumn*> ColumnPtrVec;
typedef std::vector<ODBCMetaColumn*> ColumnPtrVec;
ODBCStatementImpl(SessionImpl& rSession);
/// Creates the ODBCStatementImpl.

View File

@@ -42,7 +42,7 @@
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/AbstractPreparation.h"
#include "Poco/Data/BLOB.h"
@@ -415,7 +415,7 @@ private:
void prepareImpl(std::size_t pos, const C* pVal = 0)
/// Utility function to prepare Any and DynamicAny.
{
ODBCColumn col(_rStmt, pos);
ODBCMetaColumn col(_rStmt, pos);
switch (col.type())
{

View File

@@ -444,7 +444,7 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
try
{
ODBCColumn c(_rStmt, pos);
ODBCMetaColumn c(_rStmt, pos);
colSize = (SQLINTEGER) c.length();
decDigits = (SQLSMALLINT) c.precision();
return;
@@ -465,7 +465,7 @@ void Binder::getColumnOrParameterSize(std::size_t pos, SQLINTEGER& size)
try
{
ODBCColumn col(_rStmt, pos);
ODBCMetaColumn col(_rStmt, pos);
colSize = col.length();
}
catch (StatementException&) { }

View File

@@ -35,7 +35,7 @@
#include "Poco/Data/ODBC/Extractor.h"
#include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/BLOB.h"

View File

@@ -1,11 +1,11 @@
//
// ODBCColumn.cpp
// ODBCMetaColumn.cpp
//
// $Id: //poco/Main/Data/ODBC/src/ODBCColumn.cpp#5 $
// $Id: //poco/Main/Data/ODBC/src/ODBCMetaColumn.cpp#5 $
//
// Library: ODBC
// Package: ODBC
// Module: ODBCColumn
// Module: ODBCMetaColumn
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
@@ -34,7 +34,7 @@
//
#include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Utility.h"
@@ -43,7 +43,7 @@ namespace Data {
namespace ODBC {
ODBCColumn::ODBCColumn(const StatementHandle& rStmt, std::size_t position) :
ODBCMetaColumn::ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position) :
MetaColumn(position),
_rStmt(rStmt)
{
@@ -51,12 +51,12 @@ ODBCColumn::ODBCColumn(const StatementHandle& rStmt, std::size_t position) :
}
ODBCColumn::~ODBCColumn()
ODBCMetaColumn::~ODBCMetaColumn()
{
}
void ODBCColumn::getDescription()
void ODBCMetaColumn::getDescription()
{
memset(_columnDesc.name, 0, NAME_BUFFER_LENGTH);
_columnDesc.nameBufferLength = 0;
@@ -80,7 +80,7 @@ void ODBCColumn::getDescription()
}
void ODBCColumn::init()
void ODBCMetaColumn::init()
{
getDescription();

View File

@@ -414,7 +414,7 @@ void ODBCStatementImpl::fillColumns()
Poco::UInt32 colCount = columnsReturned();
for (int i = 0; i < colCount; ++i)
_columnPtrs.push_back(new ODBCColumn(_stmt, i));
_columnPtrs.push_back(new ODBCMetaColumn(_stmt, i));
}

View File

@@ -35,7 +35,7 @@
#include "Poco/Data/ODBC/Preparation.h"
#include "Poco/Data/ODBC/ODBCColumn.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
namespace Poco {
@@ -154,7 +154,7 @@ std::size_t Preparation::maxDataSize(std::size_t pos) const
try
{
sz = ODBCColumn(_rStmt, pos).length();
sz = ODBCMetaColumn(_rStmt, pos).length();
}
catch (StatementException&) { }

View File

@@ -588,6 +588,7 @@ CppUnit::Test* ODBCDB2Test::suite()
CppUnit_addTest(pSuite, ODBCDB2Test, testLimitZero);
CppUnit_addTest(pSuite, ODBCDB2Test, testPrepare);
CppUnit_addTest(pSuite, ODBCDB2Test, testBulk);
CppUnit_addTest(pSuite, ODBCDB2Test, testBulkPerformance);
CppUnit_addTest(pSuite, ODBCDB2Test, testSetSimple);
CppUnit_addTest(pSuite, ODBCDB2Test, testSetComplex);
CppUnit_addTest(pSuite, ODBCDB2Test, testSetComplexUnique);
@@ -618,6 +619,7 @@ CppUnit::Test* ODBCDB2Test::suite()
CppUnit_addTest(pSuite, ODBCDB2Test, testTuple);
CppUnit_addTest(pSuite, ODBCDB2Test, testTupleVector);
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalExtraction);
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalBulkExtraction);
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCDB2Test, testStoredProcedure);
CppUnit_addTest(pSuite, ODBCDB2Test, testStoredProcedureAny);

View File

@@ -406,6 +406,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit_addTest(pSuite, ODBCMySQLTest, testLimitZero);
CppUnit_addTest(pSuite, ODBCMySQLTest, testPrepare);
//CppUnit_addTest(pSuite, ODBCMySQLTest, testBulk);
//CppUnit_addTest(pSuite, ODBCMySQLTest, testBulkPerformance);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSetSimple);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSetComplex);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSetComplexUnique);
@@ -438,6 +439,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit_addTest(pSuite, ODBCMySQLTest, testStoredProcedure);
CppUnit_addTest(pSuite, ODBCMySQLTest, testStoredFunction);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalExtraction);
//CppUnit_addTest(pSuite, ODBCOracleTest, testInternalBulkExtraction);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCMySQLTest, testNull);
CppUnit_addTest(pSuite, ODBCMySQLTest, testRowIterator);

View File

@@ -788,6 +788,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testLimitZero);
CppUnit_addTest(pSuite, ODBCOracleTest, testPrepare);
CppUnit_addTest(pSuite, ODBCOracleTest, testBulk);
CppUnit_addTest(pSuite, ODBCOracleTest, testBulkPerformance);
CppUnit_addTest(pSuite, ODBCOracleTest, testSetSimple);
CppUnit_addTest(pSuite, ODBCOracleTest, testSetComplex);
CppUnit_addTest(pSuite, ODBCOracleTest, testSetComplexUnique);
@@ -823,6 +824,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredFunction);
CppUnit_addTest(pSuite, ODBCOracleTest, testCursorStoredFunction);
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalExtraction);
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalBulkExtraction);
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCOracleTest, testNull);
CppUnit_addTest(pSuite, ODBCOracleTest, testRowIterator);

View File

@@ -522,7 +522,6 @@ void ODBCPostgreSQLTest::recreateMiscTable()
dropObject("TABLE", "MiscTest");
try
{
// pgSQL fails with BLOB bulk operations
// Mammoth does not bind columns properly
session() << "CREATE TABLE MiscTest "
"(First VARCHAR(30),"
@@ -567,7 +566,12 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testLimitPrepare);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testLimitZero);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testPrepare);
//On Linux, PostgreSQL driver returns SQL_NEED_DATA on SQLExecute (see ODBCStatementImpl::bindImpl() )
//this behavior is not expected and not handled for automatic binding
#ifdef POCO_OS_FAMILY_WINDOWS
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBulk);
#endif
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBulkPerformance);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetSimple);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetComplex);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetComplexUnique);
@@ -598,6 +602,11 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTuple);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTupleVector);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalExtraction);
//On Linux, PostgreSQL driver returns SQL_NEED_DATA on SQLExecute (see ODBCStatementImpl::bindImpl() )
//this behavior is not expected and not handled for automatic binding
#ifdef POCO_OS_FAMILY_WINDOWS
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalBulkExtraction);
#endif
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunction);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunctionAny);

View File

@@ -218,9 +218,6 @@ void ODBCSQLServerTest::testBulk()
std::list<double>,
std::list<DateTime>,
std::list<bool> >(100);
recreateMiscTable();
_pExecutor->doBulkPerformance(1000);
}
@@ -696,6 +693,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testLimitZero);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testPrepare);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBulk);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBulkPerformance);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSetSimple);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSetComplex);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSetComplexUnique);
@@ -729,6 +727,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredProcedureDynamicAny);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredFunction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalExtraction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalBulkExtraction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testRowIterator);

View File

@@ -435,6 +435,15 @@ void ODBCTest::testBulk()
std::list<BLOB>,
std::list<double>,
std::list<DateTime> >(100);
}
void ODBCTest::testBulkPerformance()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("autoBind", true);
_pSession->setFeature("autoExtract", true);
recreateMiscTable();
_pExecutor->doBulkPerformance(1000);
@@ -894,6 +903,17 @@ void ODBCTest::testInternalExtraction()
}
void ODBCTest::testInternalBulkExtraction()
{
if (!_pSession) fail ("Test not available.");
recreatePersonTable();
_pSession->setFeature("autoBind", true);
_pSession->setFeature("autoExtract", true);
_pExecutor->internalBulkExtraction();
}
void ODBCTest::testInternalStorageType()
{
if (!_pSession) fail ("Test not available.");

View File

@@ -92,6 +92,7 @@ public:
virtual void testLimitZero();
virtual void testPrepare();
virtual void testBulk();
virtual void testBulkPerformance();
virtual void testSetSimple();
virtual void testSetComplex();
@@ -128,6 +129,7 @@ public:
virtual void testTupleVector();
virtual void testInternalExtraction();
virtual void testInternalBulkExtraction();
virtual void testInternalStorageType();
virtual void testStoredProcedure() { /* no-op */ };

View File

@@ -2422,9 +2422,9 @@ void SQLExecutor::internalExtraction()
i = rset.value("str0", 2);
assert (5 == i);
const Column<int>& col = rset.column<int, std::deque<int> >(0);
Column<int>::Iterator it = col.begin();
Column<int>::Iterator end = col.end();
const Column<std::deque<int> >& col = rset.column<std::deque<int>, InternalExtraction<std::deque<int> > >(0);
Column<std::deque<int> >::Iterator it = col.begin();
Column<std::deque<int> >::Iterator end = col.end();
for (int i = 1; it != end; ++it, ++i)
assert (*it == i);
@@ -2456,7 +2456,7 @@ void SQLExecutor::internalExtraction()
s = rset.value("cnt", 0).convert<std::string>();
assert ("4" == s);
try { rset.column<int, std::vector<int> >(100); fail ("must fail"); }
try { rset.column<std::deque<int>, InternalExtraction<std::deque<int> > >(100); fail ("must fail"); }
catch (RangeException&) { }
try { rset.value<std::string>(0,0); fail ("must fail"); }
@@ -2465,7 +2465,7 @@ void SQLExecutor::internalExtraction()
stmt = (session() << "DELETE FROM Vectors", now);
rset = stmt;
try { rset.column<int, std::vector<int> >(0); fail ("must fail"); }
try { rset.column<std::deque<int>, InternalExtraction<std::deque<int> > >(0); fail ("must fail"); }
catch (RangeException&) { }
}
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
@@ -2473,6 +2473,65 @@ void SQLExecutor::internalExtraction()
}
void SQLExecutor::internalBulkExtraction()
{
std::string funct = "internalBulkExtraction()";
int size = 100;
std::vector<std::string> lastName(size);
std::vector<std::string> firstName(size);
std::vector<std::string> address(size);
std::vector<int> age(size);
for (int i = 0; i < size; ++i)
{
lastName[i] = "LN" + NumberFormatter::format(i);
firstName[i] = "FN" + NumberFormatter::format(i);
address[i] = "Addr" + NumberFormatter::format(i);
age[i] = i;
}
try
{
session() << "INSERT INTO Person VALUES (?,?,?,?)",
use(lastName, bulk),
use(firstName, bulk),
use(address, bulk),
use(age, bulk),
now;
}
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
try
{
Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now);
RecordSet rset(stmt);
assert (size == rset.rowCount());
assert ("LN0" == rset["LastName"]);
assert (0 == rset["Age"]);
rset.moveLast();
assert (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assert (size - 1 == rset["Age"]);
}
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
try
{
Statement stmt = (session() << "SELECT * FROM Person", limit(size), bulk, now);
RecordSet rset(stmt);
assert (size == rset.rowCount());
assert ("LN0" == rset["LastName"]);
assert (0 == rset["Age"]);
rset.moveLast();
assert (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assert (size - 1 == rset["Age"]);
}
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
}
void SQLExecutor::internalStorageType()
{
std::string funct = "internalStorageType()";

View File

@@ -38,6 +38,7 @@
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/BulkExtraction.h"
#include "Poco/Data/BulkBinding.h"
@@ -51,7 +52,7 @@
Poco::Data::ODBC::EnvironmentException ee(h); \
std::cout << ee.toString() << std::endl; \
} \
assert (SQL_SUCCEEDED(r));
assert (SQL_SUCCEEDED(r))
#define poco_odbc_check_dbc(r, h) \
@@ -60,7 +61,7 @@
Poco::Data::ODBC::ConnectionException ce(h); \
std::cout << ce.toString() << std::endl; \
} \
assert (SQL_SUCCEEDED(r));
assert (SQL_SUCCEEDED(r))
#define poco_odbc_check_stmt(r, h) \
@@ -69,7 +70,7 @@
Poco::Data::ODBC::StatementException se(h); \
std::cout << se.toString() << std::endl; \
} \
assert (SQL_SUCCEEDED(r));
assert (SQL_SUCCEEDED(r))
#define poco_odbc_check_desc(r, h) \
@@ -78,7 +79,17 @@
Poco::Data::ODBC::DescriptorException de(h); \
std::cout << de.toString() << std::endl; \
} \
assert (SQL_SUCCEEDED(r));
assert (SQL_SUCCEEDED(r))
#define poco_data_using_statements using Poco::Data::now; \
using Poco::Data::into; \
using Poco::Data::use; \
using Poco::Data::bulk; \
using Poco::Data::limit; \
using Poco::Data::BLOB; \
using Poco::Data::ODBC::ConnectionException; \
using Poco::Data::ODBC::StatementException
class SQLExecutor: public CppUnit::TestCase
@@ -148,6 +159,8 @@ public:
template <typename C1, typename C2, typename C3, typename C4, typename C5, typename C6>
void doBulkWithBool(Poco::UInt32 size)
{
poco_data_using_statements;
std::string funct = "doBulkWithBool()";
C1 ints;
C2 strings;
@@ -287,6 +300,8 @@ public:
template <typename C1, typename C2, typename C3, typename C4, typename C5>
void doBulk(Poco::UInt32 size)
{
poco_data_using_statements;
std::string funct = "doBulk()";
C1 ints;
C2 strings;
@@ -431,6 +446,8 @@ public:
template <typename C1, typename C2>
void blobContainer(int size)
{
poco_data_using_statements;
std::string funct = "blobContainer()";
C1 lastName(size, "lastname");
C1 firstName(size, "firstname");
@@ -464,6 +481,7 @@ public:
void tupleVector();
void internalExtraction();
void internalBulkExtraction();
void internalStorageType();
void nulls();
void notNulls(const std::string& sqlState = "23502");

View File

@@ -96,14 +96,14 @@ inline Bulk bulk(const T& limit)
}
inline void bulk()
inline void bulk(char)
/// Dummy bulk function. Used for bulk binding creation
/// (see BulkBinding.h).
/// (see BulkBinding) and bulk extraction signalling to Statement.
{
}
typedef void (*BulkFnType)();
typedef void (*BulkFnType)(char);
} } // namespace Poco::Data

View File

@@ -59,16 +59,18 @@ class BulkExtraction: public AbstractExtraction
/// - std::list
{
public:
typedef typename C::value_type T;
BulkExtraction(C& result, Poco::UInt32 limit):
AbstractExtraction(limit, 0, true),
_rResult(result),
_default(1)
_default()
{
if (static_cast<Poco::UInt32>(result.size()) != limit)
result.resize(limit);
}
BulkExtraction(C& result, const C& def, Poco::UInt32 limit):
BulkExtraction(C& result, const T& def, Poco::UInt32 limit):
AbstractExtraction(limit, 0, true),
_rResult(result),
_default(def)
@@ -139,7 +141,7 @@ protected:
private:
C& _rResult;
C _default;
T _default;
std::deque<bool> _nulls;
};
@@ -152,15 +154,15 @@ class InternalBulkExtraction: public BulkExtraction<C>
/// to automaticaly create internal BulkExtraction in cases when statement returns data and no external storage
/// was supplied. It is later used by RecordSet to retrieve the fetched data after statement execution.
/// It takes ownership of the Column pointer supplied as constructor argument. Column object, in turn
/// owns the data vector pointer.
/// owns the data container pointer.
///
/// InternalBulkExtraction objects can not be copied or assigned.
{
public:
typedef typename C::value_type T;
explicit InternalBulkExtraction(C& result, Column<T,C>* pColumn, Poco::UInt32 limit):
BulkExtraction<C>(result, _default, limit),
explicit InternalBulkExtraction(C& result, Column<C>* pColumn, Poco::UInt32 limit):
BulkExtraction<C>(result, T(), limit),
_pColumn(pColumn)
/// Creates InternalBulkExtraction.
{
@@ -194,7 +196,7 @@ public:
return BulkExtraction<C>::isNull(row);
}
const Column<T,C>& column() const
const Column<C>& column() const
{
return *_pColumn;
}
@@ -204,8 +206,7 @@ private:
InternalBulkExtraction(const InternalBulkExtraction&);
InternalBulkExtraction& operator = (const InternalBulkExtraction&);
Column<T,C>* _pColumn;
C _default;
Column<C>* _pColumn;
};

View File

@@ -52,7 +52,7 @@ namespace Poco {
namespace Data {
template <class T, class C = std::deque<T> >
template <class C>
class Column
/// Column class is column data container.
/// Data (a pointer to container) is assigned to the class
@@ -65,8 +65,9 @@ public:
typedef typename Container::const_iterator Iterator;
typedef typename Container::const_reverse_iterator RIterator;
typedef typename Container::size_type Size;
typedef typename Container::value_type Type;
Column(const MetaColumn& metaColumn, C* pData): _metaColumn(metaColumn), _pData(pData)
Column(const MetaColumn& metaColumn, Container* pData): _metaColumn(metaColumn), _pData(pData)
/// Creates the Column.
{
poco_check_ptr (_pData);
@@ -104,7 +105,7 @@ public:
return *_pData;
}
const T& value(std::size_t row) const
const Type& value(std::size_t row) const
/// Returns the field value in specified row.
{
try
@@ -117,7 +118,7 @@ public:
}
}
const T& operator [] (std::size_t row) const
const Type& operator [] (std::size_t row) const
/// Returns the field value in specified row.
{
return value(row);
@@ -132,7 +133,7 @@ public:
void reset()
/// Clears and shrinks the storage.
{
C().swap(*_pData);
Container().swap(*_pData);
}
const std::string& name() const
@@ -187,7 +188,7 @@ private:
template <>
class Column<bool, std::vector<bool> >
class Column<std::vector<bool> >
/// The std::vector<bool> specialization for the Column class.
///
/// This specialization is necessary due to the nature of std::vector<bool>.
@@ -339,7 +340,7 @@ private:
template <class T>
class Column<T, std::list<T> >
class Column<std::list<T> >
/// Column specialization for std::list
{
public:
@@ -485,8 +486,8 @@ private:
};
template <typename T, typename C>
inline void swap(Column<T,C>& c1, Column<T,C>& c2)
template <typename C>
inline void swap(Column<C>& c1, Column<C>& c2)
{
c1.swap(c2);
}

View File

@@ -480,14 +480,14 @@ class InternalExtraction: public Extraction<C>
/// to automaticaly create internal Extraction in cases when statement returns data and no external storage
/// was supplied. It is later used by RecordSet to retrieve the fetched data after statement execution.
/// It takes ownership of the Column pointer supplied as constructor argument. Column object, in turn
/// owns the data vector pointer.
/// owns the data container pointer.
///
/// InternalExtraction objects can not be copied or assigned.
{
public:
typedef typename C::value_type T;
explicit InternalExtraction(C& result, Column<T,C>* pColumn, const Position& pos = Position(0)):
explicit InternalExtraction(C& result, Column<C>* pColumn, const Position& pos = Position(0)):
Extraction<C>(result, T(), pos),
_pColumn(pColumn)
/// Creates InternalExtraction.
@@ -522,7 +522,7 @@ public:
return Extraction<C>::isNull(row);
}
const Column<T,C>& column() const
const Column<C>& column() const
{
return *_pColumn;
}
@@ -532,7 +532,7 @@ private:
InternalExtraction(const InternalExtraction&);
InternalExtraction& operator = (const InternalExtraction&);
Column<T,C>* _pColumn;
Column<C>* _pColumn;
};

View File

@@ -42,6 +42,7 @@
#include "Poco/Data/Data.h"
#include "Poco/Data/Extraction.h"
#include "Poco/Data/BulkExtraction.h"
#include "Poco/Data/Statement.h"
#include "Poco/Data/RowIterator.h"
#include "Poco/Data/BLOB.h"
@@ -100,18 +101,19 @@ public:
std::size_t columnCount() const;
/// Returns the number of rows in the recordset.
template <class T, class C>
const Column<T,C>& column(const std::string& name) const
template <class C, class E>
const Column<C>& column(const std::string& name) const
/// Returns the reference to the first Column with the specified name.
{
return column<T,C>(columnPosition<T,C>(name));
return column<C,E>(columnPosition<C,E>(name));
}
template <class T, class C>
const Column<T,C>& column(std::size_t pos) const
template <class C, class E>
const Column<C>& column(std::size_t pos) const
/// Returns the reference to column at specified location.
{
typedef const InternalExtraction<C>* ExtractionVecPtr;
typedef typename C::value_type T;
typedef const E* ExtractionVecPtr;
const AbstractExtractionVec& rExtractions = extractions();
@@ -144,12 +146,30 @@ public:
switch (storage())
{
case STORAGE_VECTOR:
return column<T, std::vector<T> >(col).value(row);
{
typedef std::vector<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(col).value(row);
else
return column<C, InternalExtraction<C> >(col).value(row);
}
case STORAGE_LIST:
return column<T, std::list<T> >(col).value(row);
{
typedef std::list<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(col).value(row);
else
return column<C, InternalExtraction<C> >(col).value(row);
}
case STORAGE_DEQUE:
case STORAGE_UNKNOWN:
return column<T, std::deque<T> >(col).value(row);
{
typedef std::deque<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(col).value(row);
else
return column<C, InternalExtraction<C> >(col).value(row);
}
default:
throw IllegalStateException("Invalid storage setting.");
}
@@ -162,12 +182,30 @@ public:
switch (storage())
{
case STORAGE_VECTOR:
return column<T, std::vector<T> >(name).value(row);
{
typedef std::vector<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(name).value(row);
else
return column<C, InternalExtraction<C> >(name).value(row);
}
case STORAGE_LIST:
return column<T, std::list<T> >(name).value(row);
{
typedef std::list<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(name).value(row);
else
return column<C, InternalExtraction<C> >(name).value(row);
}
case STORAGE_DEQUE:
case STORAGE_UNKNOWN:
return column<T, std::deque<T> >(name).value(row);
{
typedef std::deque<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(name).value(row);
else
return column<C, InternalExtraction<C> >(name).value(row);
}
default:
throw IllegalStateException("Invalid storage setting.");
}
@@ -259,11 +297,12 @@ public:
private:
RecordSet();
template<class T, class C>
template<class C, class E>
std::size_t columnPosition(const std::string& name) const
/// Returns the position of the column with specified name.
{
typedef const InternalExtraction<C>* ExtractionVecPtr;
typedef typename C::value_type T;
typedef const E* ExtractionVecPtr;
bool typeFound = false;
@@ -278,7 +317,7 @@ private:
if (pExtraction)
{
typeFound = true;
const Column<T,C>& col = pExtraction->column();
const Column<C>& col = pExtraction->column();
if (0 == Poco::icompare(name, col.name()))
return col.position();
}

View File

@@ -181,14 +181,19 @@ public:
Statement& operator , (const Bulk& bulk);
/// Sets the bulk execution mode (both binding and extraction) for this
/// statement.Statement must not have any extracors or binders set at the
/// statement.Statement must not have any extractors or binders set at the
/// time when this operator is applied.
/// Failure to adhere to the above constraint shall result in
/// InvalidAccessException.
/// Additionally, any binding buffers passed to the statement later
/// through use() or in() must be of the same size (determined by size
/// of the bulk passed to this function). Since they are resized automatically
/// by the framework, the extraction buffers do not have to adhere to this.
Statement& operator , (BulkFnType);
/// Sets the bulk execution mode (both binding and extraction) for this
/// statement.Statement must not have any extractors or binders set at the
/// time when this operator is applied.
/// Additionally, this function requires limit to be set in order to
/// determine the bulk size.
/// Failure to adhere to the above constraints shall result in
/// InvalidAccessException.
Statement& operator , (const Limit& extrLimit);
/// Sets a limit on the maximum number of rows a select is allowed to return.
@@ -277,6 +282,9 @@ protected:
bool isNull(std::size_t col, std::size_t row) const;
/// Returns true if the current row value at column pos is null.
bool isBulkExtraction() const;
/// Returns true if this statement extracts data in bulk.
private:
typedef Poco::SharedPtr<StatementImpl> StatementImplPtr;
@@ -443,6 +451,12 @@ inline bool Statement::isNull(std::size_t col, std::size_t row) const
}
inline bool Statement::isBulkExtraction() const
{
return _pImpl->isBulkExtraction();
}
inline bool Statement::isAsync() const
{
return _async;

View File

@@ -295,18 +295,16 @@ private:
template <class C>
InternalExtraction<C>* createExtract(const MetaColumn& mc)
{
typedef typename C::value_type T;
C* pData = new C;
Column<T,C>* pCol = new Column<T,C>(mc, pData);
Column<C>* pCol = new Column<C>(mc, pData);
return new InternalExtraction<C>(*pData, pCol);
}
template <class C>
InternalBulkExtraction<C>* createBulkExtract(const MetaColumn& mc)
{
typedef typename C::value_type T;
C* pData = new C;
Column<T,C>* pCol = new Column<T,C>(mc, pData);
Column<C>* pCol = new Column<C>(mc, pData);
return new InternalBulkExtraction<C>(*pData, pCol, getExtractionLimit());
}

View File

@@ -160,13 +160,12 @@ private:
};
template <class C>
class TypeHandler<std::deque<C> >: public AbstractTypeHandler
template <class T>
class TypeHandler<std::deque<T> >: public AbstractTypeHandler
/// Specialization of type handler for std::deque.
/// Used by bulk extraction.
{
public:
static void bind(std::size_t pos, const std::deque<C>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
static void bind(std::size_t pos, const std::deque<T>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
{
poco_assert_dbg (pBinder != 0);
pBinder->bind(pos, obj, dir);
@@ -177,21 +176,14 @@ public:
return 1;
}
static void extract(std::size_t pos, std::deque<C>& obj, const std::deque<C>& defVal, AbstractExtractor* pExt)
static void extract(std::size_t pos, std::deque<T>& obj, const T& defVal, AbstractExtractor* pExt)
{
poco_assert_dbg (pExt != 0);
if (!pExt->extract(pos, obj))
{
if (defVal.size() == 1)
obj.assign(obj.size(), defVal.front());
else if (defVal.size() > 1)
obj.assign(defVal.begin(), defVal.end());
else
throw InvalidArgumentException("Size of default value container must not be zero.");
}
obj.assign(obj.size(), defVal);
}
static void prepare(std::size_t pos, std::deque<C>& obj, AbstractPreparation* pPrepare)
static void prepare(std::size_t pos, std::deque<T>& obj, AbstractPreparation* pPrepare)
{
poco_assert_dbg (pPrepare != 0);
pPrepare->prepare(pos, obj);
@@ -203,15 +195,12 @@ private:
};
template <class C>
class TypeHandler<std::vector<C> >: public AbstractTypeHandler
template <class T>
class TypeHandler<std::vector<T> >: public AbstractTypeHandler
/// Specialization of type handler for std::vector.
/// Used by bulk extraction.
{
public:
typedef typename std::vector<C>::value_type T;
static void bind(std::size_t pos, const std::vector<C>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
static void bind(std::size_t pos, const std::vector<T>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
{
poco_assert_dbg (pBinder != 0);
pBinder->bind(pos, obj, dir);
@@ -222,21 +211,14 @@ public:
return 1;
}
static void extract(std::size_t pos, std::vector<C>& obj, const std::vector<C>& defVal, AbstractExtractor* pExt)
static void extract(std::size_t pos, std::vector<T>& obj, const T& defVal, AbstractExtractor* pExt)
{
poco_assert_dbg (pExt != 0);
if (!pExt->extract(pos, obj))
{
if (defVal.size() == 1)
obj.assign(obj.size(), defVal.front());
else if (defVal.size() > 1)
obj.assign(defVal.begin(), defVal.end());
else
throw InvalidArgumentException("Size of default value container must not be zero.");
}
obj.assign(obj.size(), defVal);
}
static void prepare(std::size_t pos, std::vector<C>& obj, AbstractPreparation* pPrepare)
static void prepare(std::size_t pos, std::vector<T>& obj, AbstractPreparation* pPrepare)
{
poco_assert_dbg (pPrepare != 0);
pPrepare->prepare(pos, obj);
@@ -248,13 +230,12 @@ private:
};
template <class C>
class TypeHandler<std::list<C> >: public AbstractTypeHandler
template <class T>
class TypeHandler<std::list<T> >: public AbstractTypeHandler
/// Specialization of type handler for std::list.
/// Used by bulk extraction.
{
public:
static void bind(std::size_t pos, const std::list<C>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
static void bind(std::size_t pos, const std::list<T>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
{
poco_assert_dbg (pBinder != 0);
pBinder->bind(pos, obj, dir);
@@ -265,21 +246,14 @@ public:
return 1;
}
static void extract(std::size_t pos, std::list<C>& obj, const std::list<C>& defVal, AbstractExtractor* pExt)
static void extract(std::size_t pos, std::list<T>& obj, const T& defVal, AbstractExtractor* pExt)
{
poco_assert_dbg (pExt != 0);
if (!pExt->extract(pos, obj))
{
if (defVal.size() == 1)
obj.assign(obj.size(), defVal.front());
else if (defVal.size() > 1)
obj.assign(defVal.begin(), defVal.end());
else
throw InvalidArgumentException("Size of default value container must not be zero.");
}
obj.assign(obj.size(), defVal);
}
static void prepare(std::size_t pos, std::list<C>& obj, AbstractPreparation* pPrepare)
static void prepare(std::size_t pos, std::list<T>& obj, AbstractPreparation* pPrepare)
{
poco_assert_dbg (pPrepare != 0);
pPrepare->prepare(pos, obj);

View File

@@ -269,7 +269,6 @@ Statement& Statement::operator , (const Bulk& bulk)
_pImpl->bulkExtractionAllowed() &&
_pImpl->bulkBindingAllowed())
{
Limit l(_pImpl->getExtractionLimit(), false, false);
_pImpl->setBulkExtraction(bulk);
_pImpl->setBulkBinding();
}
@@ -280,4 +279,23 @@ Statement& Statement::operator , (const Bulk& bulk)
}
Statement& Statement::operator , (BulkFnType)
{
const Limit& limit(_pImpl->extractionLimit());
if (limit.isHardLimit() ||
limit.isLowerLimit() ||
Limit::LIMIT_UNLIMITED == limit.value())
{
throw InvalidAccessException("Bulk is only allowed with limited extraction,"
"non-hard and zero-based limits.");
}
Bulk bulk(limit);
_pImpl->setBulkExtraction(bulk);
_pImpl->setBulkBinding();
return *this;
}
} } // namespace Poco::Data

View File

@@ -380,7 +380,7 @@ void DataTest::testColumnVector()
pData->push_back(4);
pData->push_back(5);
Column<int, std::vector<int> > c(mc, pData);
Column<std::vector<int> > c(mc, pData);
assert (c.rowCount() == 5);
assert (c[0] == 1);
@@ -401,7 +401,7 @@ void DataTest::testColumnVector()
}
catch (RangeException&) { }
Column<int, std::vector<int> > c1 = c;
Column<std::vector<int> > c1 = c;
assert (c1.rowCount() == 5);
assert (c1[0] == 1);
@@ -410,7 +410,7 @@ void DataTest::testColumnVector()
assert (c1[3] == 4);
assert (c1[4] == 5);
Column<int, std::vector<int> > c2(c1);
Column<std::vector<int> > c2(c1);
assert (c2.rowCount() == 5);
assert (c2[0] == 1);
@@ -445,8 +445,8 @@ void DataTest::testColumnVector()
pV2->push_back(3);
pV2->push_back(2);
pV2->push_back(1);
Column<int, std::vector<int> > c3(mc, pV1);
Column<int, std::vector<int> > c4(mc, pV2);
Column<std::vector<int> > c3(mc, pV1);
Column<std::vector<int> > c4(mc, pV2);
Poco::Data::swap(c3, c4);
assert (c3[0] == 5);
@@ -487,7 +487,7 @@ void DataTest::testColumnVectorBool()
pData->push_back(false);
pData->push_back(true);
Column<bool, std::vector<bool> > c(mc, pData);
Column<std::vector<bool> > c(mc, pData);
assert (c.rowCount() == 5);
assert (c[0] == true);
@@ -504,7 +504,7 @@ void DataTest::testColumnVectorBool()
}
catch (RangeException&) { }
Column<bool, std::vector<bool> > c1 = c;
Column<std::vector<bool> > c1 = c;
assert (c1.rowCount() == 5);
assert (c1[0] == true);
@@ -513,7 +513,7 @@ void DataTest::testColumnVectorBool()
assert (c1[3] == false);
assert (c1[4] == true);
Column<bool, std::vector<bool> > c2(c1);
Column<std::vector<bool> > c2(c1);
assert (c2.rowCount() == 5);
assert (c2[0] == true);
@@ -541,7 +541,7 @@ void DataTest::testColumnVectorBool()
void DataTest::testColumnDeque()
{
typedef std::deque<int> ContainerType;
typedef Column<int> ColumnType;
typedef Column<ContainerType> ColumnType;
MetaColumn mc(0, "mc", MetaColumn::FDT_DOUBLE, 2, 3, true);
@@ -624,8 +624,8 @@ void DataTest::testColumnDeque()
pV2->push_back(3);
pV2->push_back(2);
pV2->push_back(1);
Column<int> c3(mc, pV1);
Column<int> c4(mc, pV2);
Column<ContainerType> c3(mc, pV1);
Column<ContainerType> c4(mc, pV2);
Poco::Data::swap(c3, c4);
assert (c3[0] == 5);
@@ -658,7 +658,7 @@ void DataTest::testColumnDeque()
void DataTest::testColumnList()
{
typedef std::list<int> ContainerType;
typedef Column<int, ContainerType> ColumnType;
typedef Column<ContainerType> ColumnType;
MetaColumn mc(0, "mc", MetaColumn::FDT_DOUBLE, 2, 3, true);
@@ -739,8 +739,8 @@ void DataTest::testColumnList()
pV2->push_back(3);
pV2->push_back(2);
pV2->push_back(1);
Column<int, ContainerType> c3(mc, pV1);
Column<int, ContainerType> c4(mc, pV2);
Column<ContainerType> c3(mc, pV1);
Column<ContainerType> c4(mc, pV2);
Poco::Data::swap(c3, c4);
assert (c3[0] == 5);