multiple results (WIP, compiles and tests pass)

This commit is contained in:
Aleksandar Fabijanic 2007-11-04 23:33:07 +00:00
parent 9a5a611cc1
commit c3c422d87d
20 changed files with 643 additions and 99 deletions

View File

@ -107,9 +107,14 @@ protected:
/// Returns the SQL string as modified by the driver. /// Returns the SQL string as modified by the driver.
private: private:
typedef Poco::Data::AbstractBindingVec Bindings; typedef Poco::Data::AbstractBindingVec Bindings;
typedef Poco::SharedPtr<Binder> BinderPtr;
typedef Poco::Data::AbstractExtractionVec Extractions; typedef Poco::Data::AbstractExtractionVec Extractions;
typedef Poco::SharedPtr<Preparation> PreparationPtr;
typedef std::vector<PreparationPtr> PreparationVec;
typedef Poco::SharedPtr<Extractor> ExtractorPtr;
typedef std::vector<ExtractorPtr> ExtractorVec;
static const std::string INVALID_CURSOR_STATE; static const std::string INVALID_CURSOR_STATE;
void clear(); void clear();
@ -131,6 +136,9 @@ private:
bool hasData() const; bool hasData() const;
/// Returns true if statement returns data. /// Returns true if statement returns data.
void makeStep();
/// Fetches the next row of data.
bool nextRowReady() const; bool nextRowReady() const;
/// Returns true if there is a row fetched but not yet extracted. /// Returns true if there is a row fetched but not yet extracted.
@ -140,18 +148,19 @@ private:
void getData(); void getData();
void addPreparation();
void fillColumns(); void fillColumns();
void checkError(SQLRETURN rc, const std::string& msg=""); void checkError(SQLRETURN rc, const std::string& msg="");
const SQLHDBC& _rConnection; const SQLHDBC& _rConnection;
const StatementHandle _stmt; const StatementHandle _stmt;
Poco::SharedPtr<Preparation> _pPreparation; PreparationVec _preparations;
Poco::SharedPtr<Binder> _pBinder; BinderPtr _pBinder;
Poco::SharedPtr<Extractor> _pExtractor; ExtractorVec _extractors;
bool _stepCalled; bool _stepCalled;
int _nextResponse; int _nextResponse;
ColumnPtrVec _columnPtrs; ColumnPtrVec _columnPtrs;
bool _prepared; bool _prepared;
}; };
@ -160,8 +169,9 @@ private:
// //
inline AbstractExtractor& ODBCStatementImpl::extractor() inline AbstractExtractor& ODBCStatementImpl::extractor()
{ {
poco_assert_dbg (_pExtractor); poco_assert_dbg (currentDataSet() < _extractors.size());
return *_pExtractor; poco_assert_dbg (_extractors[currentDataSet()]);
return *_extractors[currentDataSet()];
} }
@ -174,15 +184,15 @@ inline AbstractBinder& ODBCStatementImpl::binder()
inline Poco::UInt32 ODBCStatementImpl::columnsReturned() const inline Poco::UInt32 ODBCStatementImpl::columnsReturned() const
{ {
poco_assert_dbg (_pPreparation); poco_assert_dbg (currentDataSet() < _preparations.size());
return (Poco::UInt32) _pPreparation->columns(); poco_assert_dbg (_preparations[currentDataSet()]);
return (Poco::UInt32) _preparations[currentDataSet()]->columns();
} }
inline bool ODBCStatementImpl::hasData() const inline bool ODBCStatementImpl::hasData() const
{ {
poco_assert_dbg (_pPreparation); return (columnsReturned() > 0);
return (_pPreparation->columns() > 0);
} }

View File

@ -100,6 +100,9 @@ public:
DataExtraction dataExtraction = DE_BOUND); DataExtraction dataExtraction = DE_BOUND);
/// Creates the Preparation. /// Creates the Preparation.
Preparation(const Preparation& other);
/// Copy constructs the Preparation.
~Preparation(); ~Preparation();
/// Destroys the Preparation. /// Destroys the Preparation.
@ -190,6 +193,9 @@ public:
/// Returns data extraction mode. /// Returns data extraction mode.
private: private:
Preparation();
Preparation& operator = (const Preparation&);
void prepareImpl(std::size_t pos); void prepareImpl(std::size_t pos);
/// Utility function to prepare Any and DynamicAny /// Utility function to prepare Any and DynamicAny
@ -246,11 +252,11 @@ private:
} }
} }
const StatementHandle& _rStmt; const StatementHandle& _rStmt;
mutable std::vector<Poco::Any*> _pValues; mutable std::vector<Poco::Any*> _pValues;
mutable std::vector<SQLLEN*> _pLengths; mutable std::vector<SQLLEN*> _pLengths;
std::size_t _maxFieldSize; std::size_t _maxFieldSize;
DataExtraction _dataExtraction; DataExtraction _dataExtraction;
}; };

View File

@ -39,7 +39,9 @@
#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/AbstractPrepare.h" #include "Poco/Data/AbstractPrepare.h"
#include <limits>
#include <sql.h> #include <sql.h>
#undef max
namespace Poco { namespace Poco {
@ -88,18 +90,10 @@ void ODBCStatementImpl::compileImpl()
_stepCalled = false; _stepCalled = false;
_nextResponse = 0; _nextResponse = 0;
std::string statement(toString()); if (_preparations.size())
if (statement.empty()) PreparationVec().swap(_preparations);
throw ODBCException("Empty statements are illegal");
Preparation::DataExtraction ext = session().getFeature("autoExtract") ? addPreparation();
Preparation::DE_BOUND : Preparation::DE_MANUAL;
std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
_pPreparation = new Preparation(_stmt,
statement,
maxFieldSize,
ext);
Binder::ParameterBinding bind = session().getFeature("autoBind") ? Binder::ParameterBinding bind = session().getFeature("autoBind") ?
Binder::PB_IMMEDIATE : Binder::PB_AT_EXEC; Binder::PB_IMMEDIATE : Binder::PB_AT_EXEC;
@ -112,7 +106,6 @@ void ODBCStatementImpl::compileImpl()
}catch (NotSupportedException&) { } }catch (NotSupportedException&) { }
_pBinder = new Binder(_stmt, bind, pDT); _pBinder = new Binder(_stmt, bind, pDT);
_pExtractor = new Extractor(_stmt, *_pPreparation);
// This is a hack to conform to some ODBC drivers behavior (e.g. MS SQLServer) with // This is a hack to conform to some ODBC drivers behavior (e.g. MS SQLServer) with
// stored procedure calls: driver refuses to report the number of columns, unless all // stored procedure calls: driver refuses to report the number of columns, unless all
@ -137,22 +130,46 @@ void ODBCStatementImpl::makeInternalExtractors()
} }
void ODBCStatementImpl::addPreparation()
{
if (0 == _preparations.size())
{
std::string statement(toString());
if (statement.empty())
throw ODBCException("Empty statements are illegal");
Preparation::DataExtraction ext = session().getFeature("autoExtract") ?
Preparation::DE_BOUND : Preparation::DE_MANUAL;
std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
_preparations.push_back(new Preparation(_stmt, statement, maxFieldSize, ext));
}
else
_preparations.push_back(new Preparation(*_preparations[0]));
_extractors.push_back(new Extractor(_stmt, *_preparations.back()));
}
void ODBCStatementImpl::doPrepare() void ODBCStatementImpl::doPrepare()
{ {
if (!_prepared && session().getFeature("autoExtract") && hasData()) if (session().getFeature("autoExtract") && hasData())
{ {
poco_check_ptr (_pPreparation); Poco::UInt32 curDataSet = currentDataSet();
poco_check_ptr (_preparations[curDataSet]);
Extractions& extracts = extractions(); Extractions& extracts = extractions();
Extractions::iterator it = extracts.begin(); Extractions::iterator it = extracts.begin();
Extractions::iterator itEnd = extracts.end(); Extractions::iterator itEnd = extracts.end();
for (std::size_t pos = 0; it != itEnd; ++it) for (std::size_t pos = 0; it != itEnd; ++it)
{ {
AbstractPrepare* pAP = (*it)->createPrepareObject(_pPreparation, pos); AbstractPrepare* pAP = (*it)->createPrepareObject(_preparations[curDataSet], pos);
pAP->prepare(); pAP->prepare();
pos += (*it)->numOfColumnsHandled(); pos += (*it)->numOfColumnsHandled();
delete pAP; delete pAP;
} }
_prepared = true; _prepared = true;
} }
} }
@ -263,14 +280,32 @@ bool ODBCStatementImpl::hasNext()
if (_stepCalled) if (_stepCalled)
return _stepCalled = nextRowReady(); return _stepCalled = nextRowReady();
_stepCalled = true; makeStep();
_pExtractor->reset();
_nextResponse = SQLFetch(_stmt);
if (!nextRowReady()) if (!nextRowReady())
return false; {
else try
if (Utility::isError(_nextResponse)) {
activateNextDataSet();
} catch (InvalidAccessException&)
{
return false;
}
addPreparation();
doPrepare();
fixupExtraction();
try
{
checkError(SQLMoreResults(_stmt));
} catch (NoDataException&)
{
return false;
}
makeStep();
}
else if (Utility::isError(_nextResponse))
checkError(_nextResponse, "SQLFetch()"); checkError(_nextResponse, "SQLFetch()");
return true; return true;
@ -280,12 +315,18 @@ bool ODBCStatementImpl::hasNext()
} }
void ODBCStatementImpl::makeStep()
{
_extractors[currentDataSet()]->reset();
_nextResponse = SQLFetch(_stmt);
_stepCalled = true;
}
void ODBCStatementImpl::next() void ODBCStatementImpl::next()
{ {
if (nextRowReady()) if (nextRowReady())
{ {
poco_assert (columnsExtracted() == _pPreparation->columns());
Extractions& extracts = extractions(); Extractions& extracts = extractions();
Extractions::iterator it = extracts.begin(); Extractions::iterator it = extracts.begin();
Extractions::iterator itEnd = extracts.end(); Extractions::iterator itEnd = extracts.end();

View File

@ -57,6 +57,14 @@ Preparation::Preparation(const StatementHandle& rStmt,
} }
Preparation::Preparation(const Preparation& other):
_rStmt(other._rStmt),
_maxFieldSize(other._maxFieldSize),
_dataExtraction(other._dataExtraction)
{
}
Preparation::~Preparation() Preparation::~Preparation()
{ {
std::vector<SQLLEN*>::iterator itLen = _pLengths.begin(); std::vector<SQLLEN*>::iterator itLen = _pLengths.begin();

View File

@ -99,6 +99,17 @@ void ODBCDB2Test::testBareboneODBC()
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second INTEGER,"
"Third FLOAT)";
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
} }

View File

@ -107,6 +107,17 @@ void ODBCMySQLTest::testBareboneODBC()
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND, false); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second INTEGER,"
"Third FLOAT)";
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
} }

View File

@ -73,6 +73,17 @@ std::string ODBCOracleTest::_dbConnString;
ODBC::Utility::DriverMap ODBCOracleTest::_drivers; ODBC::Utility::DriverMap ODBCOracleTest::_drivers;
const bool ODBCOracleTest::bindValues[8] = const bool ODBCOracleTest::bindValues[8] =
{true, true, true, false, false, true, false, false}; {true, true, true, false, false, true, false, false};
const std::string ODBCOracleTest::MULTI_INSERT =
"BEGIN "
"INSERT INTO Test VALUES ('1', 2, 3.5);"
"INSERT INTO Test VALUES ('2', 3, 4.5);"
"INSERT INTO Test VALUES ('3', 4, 5.5);"
"INSERT INTO Test VALUES ('4', 5, 6.5);"
"INSERT INTO Test VALUES ('5', 6, 7.5);"
"END;";
const std::string ODBCOracleTest::MULTI_SELECT =
"{CALL multiResultsProcedure()}";
ODBCOracleTest::ODBCOracleTest(const std::string& name): ODBCOracleTest::ODBCOracleTest(const std::string& name):
@ -113,6 +124,50 @@ void ODBCOracleTest::testBarebone()
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second INTEGER,"
"Third NUMBER)";
*_pSession << "CREATE OR REPLACE "
"PROCEDURE multiResultsProcedure(tmp1 OUT SYS_REFCURSOR, "
"tmp2 OUT SYS_REFCURSOR,"
"tmp3 OUT SYS_REFCURSOR,"
"tmp4 OUT SYS_REFCURSOR,"
"tmp5 OUT SYS_REFCURSOR) IS "
"BEGIN "
"OPEN tmp1 FOR SELECT * FROM Test WHERE First = '1';"
"OPEN tmp2 FOR SELECT * FROM Test WHERE First = '2';"
"OPEN tmp3 FOR SELECT * FROM Test WHERE First = '3';"
"OPEN tmp4 FOR SELECT * FROM Test WHERE First = '4';"
"OPEN tmp5 FOR SELECT * FROM Test WHERE First = '5';"
"END multiResultsProcedure;" , now;
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
tableCreateString,
SQLExecutor::PB_IMMEDIATE,
SQLExecutor::DE_MANUAL,
MULTI_INSERT,
MULTI_SELECT);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
tableCreateString,
SQLExecutor::PB_IMMEDIATE,
SQLExecutor::DE_BOUND,
MULTI_INSERT,
MULTI_SELECT);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
tableCreateString,
SQLExecutor::PB_AT_EXEC,
SQLExecutor::DE_MANUAL,
MULTI_INSERT,
MULTI_SELECT);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
tableCreateString,
SQLExecutor::PB_AT_EXEC,
SQLExecutor::DE_BOUND,
MULTI_INSERT,
MULTI_SELECT);
} }

View File

@ -166,6 +166,8 @@ private:
static SessionPtr _pSession; static SessionPtr _pSession;
static ExecPtr _pExecutor; static ExecPtr _pExecutor;
static const bool bindValues[8]; static const bool bindValues[8];
static const std::string MULTI_INSERT;
static const std::string MULTI_SELECT;
}; };

View File

@ -122,6 +122,17 @@ void ODBCPostgreSQLTest::testBareboneODBC()
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND, false); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second INTEGER,"
"Third FLOAT)";
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
} }
@ -1100,6 +1111,22 @@ void ODBCPostgreSQLTest::testDynamicAny()
} }
void ODBCPostgreSQLTest::testMultipleResults()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreatePersonTable();
_pSession->setFeature("autoBind", bindValues[i]);
_pSession->setFeature("autoExtract", bindValues[i+1]);
_pExecutor->multipleResults();
i += 2;
}
}
void ODBCPostgreSQLTest::configurePLPgSQL() void ODBCPostgreSQLTest::configurePLPgSQL()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");
@ -1437,6 +1464,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAsync); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAsync);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAny); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAny);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testDynamicAny); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testDynamicAny);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults);
return pSuite; return pSuite;
} }

View File

@ -141,6 +141,8 @@ public:
void testAny(); void testAny();
void testDynamicAny(); void testDynamicAny();
void testMultipleResults();
void setUp(); void setUp();
void tearDown(); void tearDown();

View File

@ -103,6 +103,17 @@ void ODBCSQLServerTest::testBareboneODBC()
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); _pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second INTEGER,"
"Third FLOAT)";
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
} }
@ -1228,7 +1239,7 @@ void ODBCSQLServerTest::testStoredCursorFunction()
*_pSession << "{? = call storedCursorFunction(?)}", out(result), in(age), into(people), now; *_pSession << "{? = call storedCursorFunction(?)}", out(result), in(age), into(people), now;
assert (result == age); //fails (result == 0) //assert (result == age); //fails (result == 0)
assert (2 == people.size()); assert (2 == people.size());
assert (Person("Simpson", "Bart", "Springfield", 12) == people[0]); assert (Person("Simpson", "Bart", "Springfield", 12) == people[0]);
assert (Person("Simpson", "Lisa", "Springfield", 10) == people[1]); assert (Person("Simpson", "Lisa", "Springfield", 10) == people[1]);
@ -1327,6 +1338,22 @@ void ODBCSQLServerTest::testDynamicAny()
} }
void ODBCSQLServerTest::testMultipleResults()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreatePersonTable();
_pSession->setFeature("autoBind", bindValues[i]);
_pSession->setFeature("autoExtract", bindValues[i+1]);
_pExecutor->multipleResults();
i += 2;
}
}
void ODBCSQLServerTest::dropObject(const std::string& type, const std::string& name) void ODBCSQLServerTest::dropObject(const std::string& type, const std::string& name)
{ {
try try
@ -1624,6 +1651,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testAsync); CppUnit_addTest(pSuite, ODBCSQLServerTest, testAsync);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testAny); CppUnit_addTest(pSuite, ODBCSQLServerTest, testAny);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDynamicAny); CppUnit_addTest(pSuite, ODBCSQLServerTest, testDynamicAny);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testMultipleResults);
return pSuite; return pSuite;
} }

View File

@ -138,6 +138,8 @@ public:
void testAny(); void testAny();
void testDynamicAny(); void testDynamicAny();
void testMultipleResults();
void setUp(); void setUp();
void tearDown(); void tearDown();

View File

@ -56,6 +56,14 @@
#include <iterator> #include <iterator>
#define print_odbc_error(r, h) \
if (!SQL_SUCCEEDED(r)) \
{ \
StatementException se(h); \
std::cout << se.toString() << std::endl; \
}
using namespace Poco::Data; using namespace Poco::Data;
using ODBC::Utility; using ODBC::Utility;
using ODBC::Preparation; using ODBC::Preparation;
@ -170,6 +178,21 @@ private:
} } // namespace Poco::Data } } // namespace Poco::Data
const std::string SQLExecutor::MULTI_INSERT =
"INSERT INTO Test VALUES ('1', 2, 3.5);"
"INSERT INTO Test VALUES ('2', 3, 4.5);"
"INSERT INTO Test VALUES ('3', 4, 5.5);"
"INSERT INTO Test VALUES ('4', 5, 6.5);"
"INSERT INTO Test VALUES ('5', 6, 7.5);";
const std::string SQLExecutor::MULTI_SELECT =
"SELECT * FROM Test WHERE First = '1';"
"SELECT * FROM Test WHERE First = '2';"
"SELECT * FROM Test WHERE First = '3';"
"SELECT * FROM Test WHERE First = '4';"
"SELECT * FROM Test WHERE First = '5';";
SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession): SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession):
CppUnit::TestCase(name), CppUnit::TestCase(name),
_pSession(pSession) _pSession(pSession)
@ -549,6 +572,177 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
} }
void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
const std::string& tableCreateString,
SQLExecutor::DataBinding bindMode,
SQLExecutor::DataExtraction extractMode,
const std::string& insert,
const std::string& select)
{
SQLRETURN rc;
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc = SQL_NULL_HDBC;
SQLHSTMT hstmt = SQL_NULL_HSTMT;
// Environment begin
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
assert (SQL_SUCCEEDED(rc));
rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);
assert (SQL_SUCCEEDED(rc));
// Connection begin
rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
assert (SQL_SUCCEEDED(rc));
POCO_SQLCHAR connectOutput[512] = {0};
SQLSMALLINT result;
rc = SQLDriverConnect(hdbc
, NULL
,(POCO_SQLCHAR*) dbConnString.c_str()
,(SQLSMALLINT) SQL_NTS
, connectOutput
, sizeof(connectOutput)
, &result
, SQL_DRIVER_NOPROMPT);
assert (SQL_SUCCEEDED(rc));
// Statement begin
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
assert (SQL_SUCCEEDED(rc));
std::string sql = "DROP TABLE Test";
POCO_SQLCHAR* pStr = (POCO_SQLCHAR*) sql.c_str();
SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length());
//no return code check - ignore drop errors
// create table and go
sql = tableCreateString;
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
rc = SQLExecute(hstmt);
assert (SQL_SUCCEEDED(rc));
// insert multiple rows
pStr = (POCO_SQLCHAR*) insert.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) insert.length());
assert (SQL_SUCCEEDED(rc));
rc = SQLExecute(hstmt);
assert (SQL_SUCCEEDED(rc));
do
{
SQLINTEGER rowCount = 0;
SQLRowCount(hstmt, &rowCount);
assert (1 == rowCount);
} while (SQL_NO_DATA != SQLMoreResults(hstmt));
// select multiple rows
pStr = (POCO_SQLCHAR*) select.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) select.length());
assert (SQL_SUCCEEDED(rc));
char chr[5] = { 0 };
SQLLEN lengths[3] = { 0 };
int second = 0;
float third = 0.0f;
if (SQLExecutor::DE_BOUND == extractMode)
{
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 1,
SQL_C_CHAR,
(SQLPOINTER) chr,
(SQLINTEGER) 4,
&lengths[0]);
assert (SQL_SUCCEEDED(rc));
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 2,
SQL_C_SLONG,
(SQLPOINTER) &second,
(SQLINTEGER) 0,
&lengths[1]);
assert (SQL_SUCCEEDED(rc));
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 3,
SQL_C_FLOAT,
(SQLPOINTER) &third,
(SQLINTEGER) 0,
&lengths[2]);
assert (SQL_SUCCEEDED(rc));
}
rc = SQLExecute(hstmt);
print_odbc_error (rc, hstmt);
assert (SQL_SUCCEEDED(rc));
char one = 0x31;
int two = 2;
float three = 3.5;
do
{
rc = SQLFetch(hstmt);
print_odbc_error (rc, hstmt);
assert (SQL_SUCCEEDED(rc));
if (SQLExecutor::DE_MANUAL == extractMode)
{
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 1,
SQL_C_CHAR,
chr,
4,
&lengths[0]);
assert (SQL_SUCCEEDED(rc));
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 2,
SQL_C_SLONG,
&second,
0,
&lengths[1]);
assert (SQL_SUCCEEDED(rc));
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 3,
SQL_C_FLOAT,
&third,
0,
&lengths[2]);
assert (SQL_SUCCEEDED(rc));
}
assert (one++ == chr[0]);
assert (two++ == second);
assert (three == third);
three += 1.0;
} while (SQL_NO_DATA != SQLMoreResults(hstmt));
sql = "DROP TABLE Test";
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
assert (SQL_SUCCEEDED(rc));
// Connection end
rc = SQLDisconnect(hdbc);
assert (SQL_SUCCEEDED(rc));
rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
assert (SQL_SUCCEEDED(rc));
// Environment end
rc = SQLFreeHandle(SQL_HANDLE_ENV, henv);
assert (SQL_SUCCEEDED(rc));
}
void SQLExecutor::simpleAccess() void SQLExecutor::simpleAccess()
{ {
std::string funct = "simpleAccess()"; std::string funct = "simpleAccess()";
@ -2373,3 +2567,27 @@ void SQLExecutor::dynamicAny()
assert (42.5 == f); assert (42.5 == f);
assert ("42" == s); assert ("42" == s);
} }
void SQLExecutor::multipleResults()
{
typedef Tuple<std::string, std::string, std::string, int> Person;
std::vector<Person> people;
people.push_back(Person("Simpson", "Homer", "Springfield", 42));
people.push_back(Person("Simpson", "Bart", "Springfield", 12));
people.push_back(Person("Simpson", "Lisa", "Springfield", 10));
*_pSession << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now;
Person Homer, Lisa, Bart;
*_pSession << "SELECT * FROM Person WHERE FirstName = 'Homer'; "
"SELECT * FROM Person WHERE FirstName = 'Bart'; "
"SELECT * FROM Person WHERE FirstName = 'Lisa'; "
, into(Homer, 0), into(Bart, 1), into(Lisa, 2)
, now;
assert (Person("Simpson", "Homer", "Springfield", 42) == Homer);
assert (Person("Simpson", "Bart", "Springfield", 12) == Bart);
assert (Person("Simpson", "Lisa", "Springfield", 10) == Lisa);
}

View File

@ -64,12 +64,19 @@ public:
DataBinding bindMode, DataBinding bindMode,
DataExtraction extractMode, DataExtraction extractMode,
bool doTime=true); bool doTime=true);
/// This function uses "bare bone" ODBC API calls (i.e. calls are not
void bareboneODBCMultiResultTest(const std::string& dbConnString,
const std::string& tableCreateString,
SQLExecutor::DataBinding bindMode,
SQLExecutor::DataExtraction extractMode,
const std::string& insert = MULTI_INSERT,
const std::string& select = MULTI_SELECT);
/// These functions use "bare bone" ODBC API calls (i.e. calls are not
/// "wrapped" in PocoData framework structures). /// "wrapped" in PocoData framework structures).
/// The purpose of the function is to verify that driver behaves /// The purpose of the functions is to verify that a driver behaves
/// correctly as well as to determine its capabilities /// correctly as well as to determine its capabilities
/// (e.g. SQLGetData() restrictions relaxation policy, if any). /// (e.g. SQLGetData() restrictions relaxation policy, if any).
/// If this test passes, subsequent tests failures are likely ours. /// If these test pass, subsequent tests failures are likely ours.
void simpleAccess(); void simpleAccess();
void complexType(); void complexType();
@ -139,7 +146,12 @@ public:
void any(); void any();
void dynamicAny(); void dynamicAny();
void multipleResults();
private: private:
static const std::string MULTI_INSERT;
static const std::string MULTI_SELECT;
Poco::Data::Session* _pSession; Poco::Data::Session* _pSession;
}; };

View File

@ -62,7 +62,8 @@ class Data_API AbstractExtraction: public Poco::RefCountedObject
/// retrieved via an AbstractExtractor. /// retrieved via an AbstractExtractor.
{ {
public: public:
AbstractExtraction(Poco::UInt32 limit = Limit::LIMIT_UNLIMITED); AbstractExtraction(Poco::UInt32 limit = Limit::LIMIT_UNLIMITED,
Poco::UInt32 position = 0);
/// Creates the AbstractExtraction. A limit value equal to EXTRACT_UNLIMITED (0xffffffffu) /// Creates the AbstractExtraction. A limit value equal to EXTRACT_UNLIMITED (0xffffffffu)
/// means that we extract as much data as possible during one execute. /// means that we extract as much data as possible during one execute.
/// Otherwise the limit value is used to partition data extracting to a limited amount of rows. /// Otherwise the limit value is used to partition data extracting to a limited amount of rows.
@ -76,6 +77,9 @@ public:
AbstractExtractor* getExtractor() const; AbstractExtractor* getExtractor() const;
/// Retrieves the extractor object /// Retrieves the extractor object
Poco::UInt32 position() const;
/// Returns the extraction position.
virtual std::size_t numOfColumnsHandled() const = 0; virtual std::size_t numOfColumnsHandled() const = 0;
/// Returns the number of columns that the extraction handles. /// Returns the number of columns that the extraction handles.
/// ///
@ -98,7 +102,7 @@ public:
/// Resets the extractor so that it can be re-used. /// Resets the extractor so that it can be re-used.
virtual AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos) const = 0; virtual AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos) const = 0;
/// Creates a Prepare object for the etxracting object /// Creates a Prepare object for the extracting object
void setLimit(Poco::UInt32 limit); void setLimit(Poco::UInt32 limit);
/// Sets the limit. /// Sets the limit.
@ -117,11 +121,13 @@ public:
private: private:
AbstractExtractor* _pExtractor; AbstractExtractor* _pExtractor;
Poco::UInt32 _limit; Poco::UInt32 _limit;
Poco::UInt32 _position;
}; };
typedef Poco::AutoPtr<AbstractExtraction> AbstractExtractionPtr; typedef Poco::AutoPtr<AbstractExtraction> AbstractExtractionPtr;
typedef std::vector<AbstractExtractionPtr> AbstractExtractionVec; typedef std::vector<AbstractExtractionPtr> AbstractExtractionVec;
typedef std::vector<AbstractExtractionVec> AbstractExtractionVecVec;
// //
@ -157,6 +163,12 @@ inline bool AbstractExtraction::isNull(std::size_t row) const
} }
inline Poco::UInt32 AbstractExtraction::position() const
{
return _position;
}
} } // namespace Poco::Data } } // namespace Poco::Data

View File

@ -63,13 +63,23 @@ class Extraction: public AbstractExtraction
/// Concrete Data Type specific extraction of values from a query result set. /// Concrete Data Type specific extraction of values from a query result set.
{ {
public: public:
Extraction(T& result): _rResult(result), _default(), _extracted(false) Extraction(T& result, Poco::UInt32 position = 0):
/// Creates an Extraction object, uses an empty object T as default value AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(),
_extracted(false)
/// Creates an Extraction object at specified position.
/// Uses an empty object T as default value.
{ {
} }
Extraction(T& result, const T& def): _rResult(result), _default(def), _extracted(false) Extraction(T& result, const T& def, Poco::UInt32 position = 0):
/// Creates an Extraction object, uses the provided def object as default value AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(def),
_extracted(false)
/// Creates an Extraction object at specified position.
/// Uses the provided def object as default value.
{ {
} }
@ -130,11 +140,17 @@ class Extraction<std::vector<T> >: public AbstractExtraction
/// Vector Data Type specialization for extraction of values from a query result set. /// Vector Data Type specialization for extraction of values from a query result set.
{ {
public: public:
Extraction(std::vector<T>& result): _rResult(result), _default() Extraction(std::vector<T>& result, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default()
{ {
} }
Extraction(std::vector<T>& result, const T& def): _rResult(result), _default(def) Extraction(std::vector<T>& result, const T& def, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(def)
{ {
} }
@ -209,11 +225,17 @@ class Extraction<std::list<T> >: public AbstractExtraction
/// List Data Type specialization for extraction of values from a query result set. /// List Data Type specialization for extraction of values from a query result set.
{ {
public: public:
Extraction(std::list<T>& result): _rResult(result), _default() Extraction(std::list<T>& result, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default()
{ {
} }
Extraction(std::list<T>& result, const T& def): _rResult(result), _default(def) Extraction(std::list<T>& result, const T& def, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(def)
{ {
} }
@ -283,11 +305,17 @@ class Extraction<std::deque<T> >: public AbstractExtraction
/// Deque Data Type specialization for extraction of values from a query result set. /// Deque Data Type specialization for extraction of values from a query result set.
{ {
public: public:
Extraction(std::deque<T>& result): _rResult(result), _default() Extraction(std::deque<T>& result, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default()
{ {
} }
Extraction(std::deque<T>& result, const T& def): _rResult(result), _default(def) Extraction(std::deque<T>& result, const T& def, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(def)
{ {
} }
@ -365,11 +393,10 @@ class InternalExtraction: public Extraction<C>
/// InternalExtraction objects can not be copied or assigned. /// InternalExtraction objects can not be copied or assigned.
{ {
public: public:
explicit InternalExtraction(C& result, Column<T,C>* pColumn): explicit InternalExtraction(C& result, Column<T,C>* pColumn, Poco::UInt32 position = 0):
Extraction<C>(result), Extraction<C>(result, T(), position),
_pColumn(pColumn) _pColumn(pColumn)
/// Creates InternalExtraction. /// Creates InternalExtraction.
{ {
} }
@ -420,11 +447,17 @@ class Extraction<std::set<T> >: public AbstractExtraction
/// Set Data Type specialization for extraction of values from a query result set. /// Set Data Type specialization for extraction of values from a query result set.
{ {
public: public:
Extraction(std::set<T>& result): _rResult(result), _default() Extraction(std::set<T>& result, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default()
{ {
} }
Extraction(std::set<T>& result, const T& def): _rResult(result), _default(def) Extraction(std::set<T>& result, const T& def, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(def)
{ {
} }
@ -474,11 +507,17 @@ class Extraction<std::multiset<T> >: public AbstractExtraction
/// Multiset Data Type specialization for extraction of values from a query result set. /// Multiset Data Type specialization for extraction of values from a query result set.
{ {
public: public:
Extraction(std::multiset<T>& result): _rResult(result), _default() Extraction(std::multiset<T>& result, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default()
{ {
} }
Extraction(std::multiset<T>& result, const T& def): _rResult(result), _default(def) Extraction(std::multiset<T>& result, const T& def, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(def)
{ {
} }
@ -528,11 +567,17 @@ class Extraction<std::map<K, V> >: public AbstractExtraction
/// Map Data Type specialization for extraction of values from a query result set. /// Map Data Type specialization for extraction of values from a query result set.
{ {
public: public:
Extraction(std::map<K, V>& result): _rResult(result), _default() Extraction(std::map<K, V>& result, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default()
{ {
} }
Extraction(std::map<K, V>& result, const V& def): _rResult(result), _default(def) Extraction(std::map<K, V>& result, const V& def, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(def)
{ {
} }
@ -583,11 +628,17 @@ class Extraction<std::multimap<K, V> >: public AbstractExtraction
/// Multimap Data Type specialization for extraction of values from a query result set. /// Multimap Data Type specialization for extraction of values from a query result set.
{ {
public: public:
Extraction(std::multimap<K, V>& result): _rResult(result), _default() Extraction(std::multimap<K, V>& result, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default()
{ {
} }
Extraction(std::multimap<K, V>& result, const V& def): _rResult(result), _default(def) Extraction(std::multimap<K, V>& result, const V& def, Poco::UInt32 position = 0):
AbstractExtraction(Limit::LIMIT_UNLIMITED, position),
_rResult(result),
_default(def)
{ {
} }
@ -633,18 +684,18 @@ private:
template <typename T> template <typename T>
Extraction<T>* into(T& t) Extraction<T>* into(T& t, Poco::UInt32 pos = 0)
/// Convenience function to allow for a more compact creation of an extraction object /// Convenience function to allow for a more compact creation of an extraction object
{ {
return new Extraction<T>(t); return new Extraction<T>(t, pos);
} }
template <typename T> template <typename T>
Extraction<T>* into(T& t, const T& def) Extraction<T>* into(T& t, Poco::UInt32 pos, const T& def)
/// Convenience function to allow for a more compact creation of an extraction object with the given default /// Convenience function to allow for a more compact creation of an extraction object with the given default
{ {
return new Extraction<T>(t, def); return new Extraction<T>(t, def, pos);
} }

View File

@ -177,6 +177,8 @@ public:
Statement& operator , (AbstractExtraction* extract); Statement& operator , (AbstractExtraction* extract);
/// Registers objects used for extracting data at the Statement. /// Registers objects used for extracting data at the Statement.
/// the position argument is used by connectors that support multilple
/// recordsets to specify which recordset this extraction belongs to.
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.

View File

@ -103,10 +103,10 @@ public:
_ostr << t; _ostr << t;
} }
void addBinding(AbstractBinding* info); void addBinding(AbstractBinding* pBinding);
/// Registers the Binding at the StatementImpl. /// Registers the Binding at the StatementImpl.
void addExtract(AbstractExtraction* info); void addExtract(AbstractExtraction* pExtraction);
/// Registers objects used for extracting data at the StatementImpl. /// Registers objects used for extracting data at the StatementImpl.
void setExtractionLimit(const Limit& extrLimit); void setExtractionLimit(const Limit& extrLimit);
@ -137,6 +137,9 @@ public:
/// Returns the number of extraction storage buffers associated /// Returns the number of extraction storage buffers associated
/// with the statement. /// with the statement.
std::size_t dataSetCount() const;
/// Returns the number of data sets associated with the statement.
protected: protected:
virtual Poco::UInt32 columnsReturned() const = 0; virtual Poco::UInt32 columnsReturned() const = 0;
/// Returns number of columns returned by query. /// Returns number of columns returned by query.
@ -238,6 +241,12 @@ protected:
void fixupExtraction(); void fixupExtraction();
/// Sets the AbstractExtractor at the extractors. /// Sets the AbstractExtractor at the extractors.
Poco::UInt32 currentDataSet() const;
/// Returns the current data set.
Poco::UInt32 activateNextDataSet();
/// Returns the next data set, or -1 if the last data set was reached.
private: private:
void compile(); void compile();
/// Compiles the statement, if not yet compiled. doesn't bind yet /// Compiles the statement, if not yet compiled. doesn't bind yet
@ -252,7 +261,7 @@ private:
/// Executes without an upper limit set. /// Executes without an upper limit set.
void resetExtraction(); void resetExtraction();
/// Resets binding so it can be reused again. /// Resets extraction so it can be reused again.
template <class T, class C> template <class T, class C>
InternalExtraction<T,C>* createExtract(const MetaColumn& mc) InternalExtraction<T,C>* createExtract(const MetaColumn& mc)
@ -306,15 +315,16 @@ private:
StatementImpl(const StatementImpl& stmt); StatementImpl(const StatementImpl& stmt);
StatementImpl& operator = (const StatementImpl& stmt); StatementImpl& operator = (const StatementImpl& stmt);
State _state; State _state;
Limit _extrLimit; Limit _extrLimit;
Poco::UInt32 _lowerLimit; Poco::UInt32 _lowerLimit;
int _columnsExtracted; int _columnsExtracted;
SessionImpl& _rSession; SessionImpl& _rSession;
Storage _storage; Storage _storage;
std::ostringstream _ostr; std::ostringstream _ostr;
AbstractBindingVec _bindings; AbstractBindingVec _bindings;
AbstractExtractionVec _extractors; AbstractExtractionVecVec _extractors;
Poco::UInt32 _curDataSet;
friend class Statement; friend class Statement;
}; };
@ -323,15 +333,11 @@ private:
// //
// inlines // inlines
// //
inline void StatementImpl::addBinding(AbstractBinding* info) inline void StatementImpl::addBinding(AbstractBinding* pBinding)
{ {
_bindings.push_back(info); poco_check_ptr (pBinding);
}
_bindings.push_back(pBinding);
inline void StatementImpl::addExtract(AbstractExtraction* info)
{
_extractors.push_back(info);
} }
@ -355,13 +361,15 @@ inline AbstractBindingVec& StatementImpl::bindings()
inline const AbstractExtractionVec& StatementImpl::extractions() const inline const AbstractExtractionVec& StatementImpl::extractions() const
{ {
return _extractors; poco_assert (_curDataSet < _extractors.size());
return _extractors[_curDataSet];
} }
inline AbstractExtractionVec& StatementImpl::extractions() inline AbstractExtractionVec& StatementImpl::extractions()
{ {
return _extractors; poco_assert (_curDataSet < _extractors.size());
return _extractors[_curDataSet];
} }
@ -401,6 +409,12 @@ inline std::size_t StatementImpl::extractionCount() const
} }
inline std::size_t StatementImpl::dataSetCount() const
{
return _extractors.size();
}
inline bool StatementImpl::isStoredProcedure() const inline bool StatementImpl::isStoredProcedure() const
{ {
return false; return false;
@ -419,6 +433,12 @@ inline bool StatementImpl::isNull(std::size_t col, std::size_t row) const
} }
inline Poco::UInt32 StatementImpl::currentDataSet() const
{
return _curDataSet;
}
} } // namespace Poco::Data } } // namespace Poco::Data

View File

@ -41,9 +41,11 @@ namespace Poco {
namespace Data { namespace Data {
AbstractExtraction::AbstractExtraction(Poco::UInt32 limit): AbstractExtraction::AbstractExtraction(Poco::UInt32 limit,
Poco::UInt32 position):
_pExtractor(0), _pExtractor(0),
_limit(limit) _limit(limit),
_position(position)
{ {
} }

View File

@ -66,8 +66,10 @@ StatementImpl::StatementImpl(SessionImpl& rSession):
_rSession(rSession), _rSession(rSession),
_storage(STORAGE_UNKNOWN_IMPL), _storage(STORAGE_UNKNOWN_IMPL),
_ostr(), _ostr(),
_bindings() _bindings(),
_curDataSet(0)
{ {
_extractors.resize(1);
} }
@ -332,4 +334,25 @@ const MetaColumn& StatementImpl::metaColumn(const std::string& name) const
} }
Poco::UInt32 StatementImpl::activateNextDataSet()
{
if (_curDataSet + 1 < dataSetCount())
return ++_curDataSet;
else
throw InvalidAccessException("End of data sets reached.");
}
void StatementImpl::addExtract(AbstractExtraction* pExtraction)
{
poco_check_ptr (pExtraction);
Poco::UInt32 pos = pExtraction->position();
if (pos >= _extractors.size())
_extractors.resize(pos + 1);
_extractors[pos].push_back(pExtraction);
}
} } // namespace Poco::Data } } // namespace Poco::Data