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 endif
objects = Binder ConnectionHandle Connector EnvironmentHandle \ objects = Binder ConnectionHandle Connector EnvironmentHandle \
Extractor ODBCColumn ODBCException ODBCStatementImpl \ Extractor ODBCMetaColumn ODBCException ODBCStatementImpl \
Parameter Preparation SessionImpl TypeInfo Unicode Utility Parameter Preparation SessionImpl TypeInfo Unicode Utility
target = PocoODBC target = PocoODBC

View File

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

View File

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

View File

@@ -44,7 +44,7 @@
#include "Poco/Data/AbstractBinder.h" #include "Poco/Data/AbstractBinder.h"
#include "Poco/Data/ODBC/Handle.h" #include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/Parameter.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/Utility.h"
#include "Poco/Data/ODBC/TypeInfo.h" #include "Poco/Data/ODBC/TypeInfo.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"

View File

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

View File

@@ -77,8 +77,13 @@ public:
~Handle() ~Handle()
/// Destroys the Handle. /// Destroys the Handle.
{ {
SQLRETURN rc = SQLFreeHandle(handleType, _handle); #if defined(_DEBUG)
poco_assert (!Utility::isError(rc)); 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 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 // Library: ODBC
// Package: ODBC // Package: ODBC
// Module: ODBCColumn // Module: ODBCMetaColumn
// //
// Definition of ODBCColumn. // Definition of ODBCMetaColumn.
// //
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH. // Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors. // and Contributors.
@@ -56,14 +56,14 @@ namespace Data {
namespace ODBC { namespace ODBC {
class ODBC_API ODBCColumn: public MetaColumn class ODBC_API ODBCMetaColumn: public MetaColumn
{ {
public: public:
explicit ODBCColumn(const StatementHandle& rStmt, std::size_t position); explicit ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position);
/// Creates the ODBCColumn. /// Creates the ODBCMetaColumn.
~ODBCColumn(); ~ODBCMetaColumn();
/// Destroys the ODBCColumn. /// Destroys the ODBCMetaColumn.
std::size_t dataLength() const; std::size_t dataLength() const;
/// A numeric value that is either the maximum or actual character length of a character /// 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. /// This information is returned from the SQL_DESC_LENGTH record field of the IRD.
private: private:
ODBCColumn(); ODBCMetaColumn();
static const int NAME_BUFFER_LENGTH = 2048; static const int NAME_BUFFER_LENGTH = 2048;
@@ -99,7 +99,7 @@ private:
/// ///
/// inlines /// inlines
/// ///
inline std::size_t ODBCColumn::dataLength() const inline std::size_t ODBCMetaColumn::dataLength() const
{ {
return _dataLength; return _dataLength;
} }

View File

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

View File

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

View File

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

View File

@@ -35,7 +35,7 @@
#include "Poco/Data/ODBC/Extractor.h" #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/Utility.h"
#include "Poco/Data/ODBC/ODBCException.h" #include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/BLOB.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 // Library: ODBC
// Package: ODBC // Package: ODBC
// Module: ODBCColumn // Module: ODBCMetaColumn
// //
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH. // Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors. // and Contributors.
@@ -34,7 +34,7 @@
// //
#include "Poco/Data/ODBC/ODBCColumn.h" #include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Utility.h" #include "Poco/Data/ODBC/Utility.h"
@@ -43,7 +43,7 @@ namespace Data {
namespace ODBC { namespace ODBC {
ODBCColumn::ODBCColumn(const StatementHandle& rStmt, std::size_t position) : ODBCMetaColumn::ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position) :
MetaColumn(position), MetaColumn(position),
_rStmt(rStmt) _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); memset(_columnDesc.name, 0, NAME_BUFFER_LENGTH);
_columnDesc.nameBufferLength = 0; _columnDesc.nameBufferLength = 0;
@@ -80,7 +80,7 @@ void ODBCColumn::getDescription()
} }
void ODBCColumn::init() void ODBCMetaColumn::init()
{ {
getDescription(); getDescription();

View File

@@ -414,7 +414,7 @@ void ODBCStatementImpl::fillColumns()
Poco::UInt32 colCount = columnsReturned(); Poco::UInt32 colCount = columnsReturned();
for (int i = 0; i < colCount; ++i) 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/Preparation.h"
#include "Poco/Data/ODBC/ODBCColumn.h" #include "Poco/Data/ODBC/ODBCMetaColumn.h"
namespace Poco { namespace Poco {
@@ -154,7 +154,7 @@ std::size_t Preparation::maxDataSize(std::size_t pos) const
try try
{ {
sz = ODBCColumn(_rStmt, pos).length(); sz = ODBCMetaColumn(_rStmt, pos).length();
} }
catch (StatementException&) { } catch (StatementException&) { }

View File

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

View File

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

View File

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

View File

@@ -522,7 +522,6 @@ void ODBCPostgreSQLTest::recreateMiscTable()
dropObject("TABLE", "MiscTest"); dropObject("TABLE", "MiscTest");
try try
{ {
// pgSQL fails with BLOB bulk operations
// Mammoth does not bind columns properly // Mammoth does not bind columns properly
session() << "CREATE TABLE MiscTest " session() << "CREATE TABLE MiscTest "
"(First VARCHAR(30)," "(First VARCHAR(30),"
@@ -567,7 +566,12 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testLimitPrepare); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testLimitPrepare);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testLimitZero); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testLimitZero);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testPrepare); 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); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBulk);
#endif
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBulkPerformance);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetSimple); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetSimple);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetComplex); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetComplex);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetComplexUnique); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSetComplexUnique);
@@ -598,6 +602,11 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTuple); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTuple);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTupleVector); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTupleVector);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalExtraction); 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, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunction); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunction);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunctionAny); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunctionAny);

View File

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

View File

@@ -435,6 +435,15 @@ void ODBCTest::testBulk()
std::list<BLOB>, std::list<BLOB>,
std::list<double>, std::list<double>,
std::list<DateTime> >(100); std::list<DateTime> >(100);
}
void ODBCTest::testBulkPerformance()
{
if (!_pSession) fail ("Test not available.");
_pSession->setFeature("autoBind", true);
_pSession->setFeature("autoExtract", true);
recreateMiscTable(); recreateMiscTable();
_pExecutor->doBulkPerformance(1000); _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() void ODBCTest::testInternalStorageType()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");

View File

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

View File

@@ -2422,9 +2422,9 @@ void SQLExecutor::internalExtraction()
i = rset.value("str0", 2); i = rset.value("str0", 2);
assert (5 == i); assert (5 == i);
const Column<int>& col = rset.column<int, std::deque<int> >(0); const Column<std::deque<int> >& col = rset.column<std::deque<int>, InternalExtraction<std::deque<int> > >(0);
Column<int>::Iterator it = col.begin(); Column<std::deque<int> >::Iterator it = col.begin();
Column<int>::Iterator end = col.end(); Column<std::deque<int> >::Iterator end = col.end();
for (int i = 1; it != end; ++it, ++i) for (int i = 1; it != end; ++it, ++i)
assert (*it == i); assert (*it == i);
@@ -2456,7 +2456,7 @@ void SQLExecutor::internalExtraction()
s = rset.value("cnt", 0).convert<std::string>(); s = rset.value("cnt", 0).convert<std::string>();
assert ("4" == s); 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&) { } catch (RangeException&) { }
try { rset.value<std::string>(0,0); fail ("must fail"); } try { rset.value<std::string>(0,0); fail ("must fail"); }
@@ -2465,7 +2465,7 @@ void SQLExecutor::internalExtraction()
stmt = (session() << "DELETE FROM Vectors", now); stmt = (session() << "DELETE FROM Vectors", now);
rset = stmt; 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 (RangeException&) { }
} }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } 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() void SQLExecutor::internalStorageType()
{ {
std::string funct = "internalStorageType()"; std::string funct = "internalStorageType()";

View File

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

View File

@@ -59,16 +59,18 @@ class BulkExtraction: public AbstractExtraction
/// - std::list /// - std::list
{ {
public: public:
typedef typename C::value_type T;
BulkExtraction(C& result, Poco::UInt32 limit): BulkExtraction(C& result, Poco::UInt32 limit):
AbstractExtraction(limit, 0, true), AbstractExtraction(limit, 0, true),
_rResult(result), _rResult(result),
_default(1) _default()
{ {
if (static_cast<Poco::UInt32>(result.size()) != limit) if (static_cast<Poco::UInt32>(result.size()) != limit)
result.resize(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), AbstractExtraction(limit, 0, true),
_rResult(result), _rResult(result),
_default(def) _default(def)
@@ -139,7 +141,7 @@ protected:
private: private:
C& _rResult; C& _rResult;
C _default; T _default;
std::deque<bool> _nulls; 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 /// 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. /// 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 /// 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. /// InternalBulkExtraction objects can not be copied or assigned.
{ {
public: public:
typedef typename C::value_type T; typedef typename C::value_type T;
explicit InternalBulkExtraction(C& result, Column<T,C>* pColumn, Poco::UInt32 limit): explicit InternalBulkExtraction(C& result, Column<C>* pColumn, Poco::UInt32 limit):
BulkExtraction<C>(result, _default, limit), BulkExtraction<C>(result, T(), limit),
_pColumn(pColumn) _pColumn(pColumn)
/// Creates InternalBulkExtraction. /// Creates InternalBulkExtraction.
{ {
@@ -194,7 +196,7 @@ public:
return BulkExtraction<C>::isNull(row); return BulkExtraction<C>::isNull(row);
} }
const Column<T,C>& column() const const Column<C>& column() const
{ {
return *_pColumn; return *_pColumn;
} }
@@ -204,8 +206,7 @@ private:
InternalBulkExtraction(const InternalBulkExtraction&); InternalBulkExtraction(const InternalBulkExtraction&);
InternalBulkExtraction& operator = (const InternalBulkExtraction&); InternalBulkExtraction& operator = (const InternalBulkExtraction&);
Column<T,C>* _pColumn; Column<C>* _pColumn;
C _default;
}; };

View File

@@ -52,7 +52,7 @@ namespace Poco {
namespace Data { namespace Data {
template <class T, class C = std::deque<T> > template <class C>
class Column class Column
/// Column class is column data container. /// Column class is column data container.
/// Data (a pointer to container) is assigned to the class /// 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_iterator Iterator;
typedef typename Container::const_reverse_iterator RIterator; typedef typename Container::const_reverse_iterator RIterator;
typedef typename Container::size_type Size; 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. /// Creates the Column.
{ {
poco_check_ptr (_pData); poco_check_ptr (_pData);
@@ -104,7 +105,7 @@ public:
return *_pData; 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. /// Returns the field value in specified row.
{ {
try 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. /// Returns the field value in specified row.
{ {
return value(row); return value(row);
@@ -132,7 +133,7 @@ public:
void reset() void reset()
/// Clears and shrinks the storage. /// Clears and shrinks the storage.
{ {
C().swap(*_pData); Container().swap(*_pData);
} }
const std::string& name() const const std::string& name() const
@@ -187,7 +188,7 @@ private:
template <> template <>
class Column<bool, std::vector<bool> > class Column<std::vector<bool> >
/// The std::vector<bool> specialization for the Column class. /// The std::vector<bool> specialization for the Column class.
/// ///
/// This specialization is necessary due to the nature of std::vector<bool>. /// This specialization is necessary due to the nature of std::vector<bool>.
@@ -339,7 +340,7 @@ private:
template <class T> template <class T>
class Column<T, std::list<T> > class Column<std::list<T> >
/// Column specialization for std::list /// Column specialization for std::list
{ {
public: public:
@@ -485,8 +486,8 @@ private:
}; };
template <typename T, typename C> template <typename C>
inline void swap(Column<T,C>& c1, Column<T,C>& c2) inline void swap(Column<C>& c1, Column<C>& c2)
{ {
c1.swap(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 /// 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. /// 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 /// 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. /// InternalExtraction objects can not be copied or assigned.
{ {
public: public:
typedef typename C::value_type T; 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), Extraction<C>(result, T(), pos),
_pColumn(pColumn) _pColumn(pColumn)
/// Creates InternalExtraction. /// Creates InternalExtraction.
@@ -522,7 +522,7 @@ public:
return Extraction<C>::isNull(row); return Extraction<C>::isNull(row);
} }
const Column<T,C>& column() const const Column<C>& column() const
{ {
return *_pColumn; return *_pColumn;
} }
@@ -532,7 +532,7 @@ private:
InternalExtraction(const InternalExtraction&); InternalExtraction(const InternalExtraction&);
InternalExtraction& operator = (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/Data.h"
#include "Poco/Data/Extraction.h" #include "Poco/Data/Extraction.h"
#include "Poco/Data/BulkExtraction.h"
#include "Poco/Data/Statement.h" #include "Poco/Data/Statement.h"
#include "Poco/Data/RowIterator.h" #include "Poco/Data/RowIterator.h"
#include "Poco/Data/BLOB.h" #include "Poco/Data/BLOB.h"
@@ -100,18 +101,19 @@ public:
std::size_t columnCount() const; std::size_t columnCount() const;
/// Returns the number of rows in the recordset. /// Returns the number of rows in the recordset.
template <class T, class C> template <class C, class E>
const Column<T,C>& column(const std::string& name) const const Column<C>& column(const std::string& name) const
/// Returns the reference to the first Column with the specified name. /// 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> template <class C, class E>
const Column<T,C>& column(std::size_t pos) const const Column<C>& column(std::size_t pos) const
/// Returns the reference to column at specified location. /// 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(); const AbstractExtractionVec& rExtractions = extractions();
@@ -144,12 +146,30 @@ public:
switch (storage()) switch (storage())
{ {
case STORAGE_VECTOR: 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: 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_DEQUE:
case STORAGE_UNKNOWN: 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: default:
throw IllegalStateException("Invalid storage setting."); throw IllegalStateException("Invalid storage setting.");
} }
@@ -162,12 +182,30 @@ public:
switch (storage()) switch (storage())
{ {
case STORAGE_VECTOR: 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: 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_DEQUE:
case STORAGE_UNKNOWN: 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: default:
throw IllegalStateException("Invalid storage setting."); throw IllegalStateException("Invalid storage setting.");
} }
@@ -259,11 +297,12 @@ public:
private: private:
RecordSet(); RecordSet();
template<class T, class C> template<class C, class E>
std::size_t columnPosition(const std::string& name) const std::size_t columnPosition(const std::string& name) const
/// Returns the position of the column with specified name. /// 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; bool typeFound = false;
@@ -278,7 +317,7 @@ private:
if (pExtraction) if (pExtraction)
{ {
typeFound = true; typeFound = true;
const Column<T,C>& col = pExtraction->column(); const Column<C>& col = pExtraction->column();
if (0 == Poco::icompare(name, col.name())) if (0 == Poco::icompare(name, col.name()))
return col.position(); return col.position();
} }

View File

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

View File

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

View File

@@ -160,13 +160,12 @@ private:
}; };
template <class C> template <class T>
class TypeHandler<std::deque<C> >: public AbstractTypeHandler class TypeHandler<std::deque<T> >: public AbstractTypeHandler
/// Specialization of type handler for std::deque. /// Specialization of type handler for std::deque.
/// Used by bulk extraction.
{ {
public: 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); poco_assert_dbg (pBinder != 0);
pBinder->bind(pos, obj, dir); pBinder->bind(pos, obj, dir);
@@ -177,21 +176,14 @@ public:
return 1; 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); poco_assert_dbg (pExt != 0);
if (!pExt->extract(pos, obj)) if (!pExt->extract(pos, obj))
{ obj.assign(obj.size(), defVal);
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.");
}
} }
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); poco_assert_dbg (pPrepare != 0);
pPrepare->prepare(pos, obj); pPrepare->prepare(pos, obj);
@@ -203,15 +195,12 @@ private:
}; };
template <class C> template <class T>
class TypeHandler<std::vector<C> >: public AbstractTypeHandler class TypeHandler<std::vector<T> >: public AbstractTypeHandler
/// Specialization of type handler for std::vector. /// Specialization of type handler for std::vector.
/// Used by bulk extraction.
{ {
public: public:
typedef typename std::vector<C>::value_type T; static void bind(std::size_t pos, const std::vector<T>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
static void bind(std::size_t pos, const std::vector<C>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
{ {
poco_assert_dbg (pBinder != 0); poco_assert_dbg (pBinder != 0);
pBinder->bind(pos, obj, dir); pBinder->bind(pos, obj, dir);
@@ -222,21 +211,14 @@ public:
return 1; 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); poco_assert_dbg (pExt != 0);
if (!pExt->extract(pos, obj)) if (!pExt->extract(pos, obj))
{ obj.assign(obj.size(), defVal);
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.");
}
} }
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); poco_assert_dbg (pPrepare != 0);
pPrepare->prepare(pos, obj); pPrepare->prepare(pos, obj);
@@ -248,13 +230,12 @@ private:
}; };
template <class C> template <class T>
class TypeHandler<std::list<C> >: public AbstractTypeHandler class TypeHandler<std::list<T> >: public AbstractTypeHandler
/// Specialization of type handler for std::list. /// Specialization of type handler for std::list.
/// Used by bulk extraction.
{ {
public: 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); poco_assert_dbg (pBinder != 0);
pBinder->bind(pos, obj, dir); pBinder->bind(pos, obj, dir);
@@ -265,21 +246,14 @@ public:
return 1; 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); poco_assert_dbg (pExt != 0);
if (!pExt->extract(pos, obj)) if (!pExt->extract(pos, obj))
{ obj.assign(obj.size(), defVal);
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.");
}
} }
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); poco_assert_dbg (pPrepare != 0);
pPrepare->prepare(pos, obj); pPrepare->prepare(pos, obj);

View File

@@ -269,7 +269,6 @@ Statement& Statement::operator , (const Bulk& bulk)
_pImpl->bulkExtractionAllowed() && _pImpl->bulkExtractionAllowed() &&
_pImpl->bulkBindingAllowed()) _pImpl->bulkBindingAllowed())
{ {
Limit l(_pImpl->getExtractionLimit(), false, false);
_pImpl->setBulkExtraction(bulk); _pImpl->setBulkExtraction(bulk);
_pImpl->setBulkBinding(); _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 } } // namespace Poco::Data

View File

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