mirror of
https://github.com/pocoproject/poco.git
synced 2025-04-01 17:25:03 +02:00
multiple results (WIP, compiles and tests pass)
This commit is contained in:
parent
9a5a611cc1
commit
c3c422d87d
@ -107,9 +107,14 @@ protected:
|
||||
/// Returns the SQL string as modified by the driver.
|
||||
|
||||
private:
|
||||
typedef Poco::Data::AbstractBindingVec Bindings;
|
||||
typedef Poco::Data::AbstractBindingVec Bindings;
|
||||
typedef Poco::SharedPtr<Binder> BinderPtr;
|
||||
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;
|
||||
|
||||
void clear();
|
||||
@ -131,6 +136,9 @@ private:
|
||||
bool hasData() const;
|
||||
/// Returns true if statement returns data.
|
||||
|
||||
void makeStep();
|
||||
/// Fetches the next row of data.
|
||||
|
||||
bool nextRowReady() const;
|
||||
/// Returns true if there is a row fetched but not yet extracted.
|
||||
|
||||
@ -140,18 +148,19 @@ private:
|
||||
|
||||
void getData();
|
||||
|
||||
void addPreparation();
|
||||
void fillColumns();
|
||||
void checkError(SQLRETURN rc, const std::string& msg="");
|
||||
|
||||
const SQLHDBC& _rConnection;
|
||||
const StatementHandle _stmt;
|
||||
Poco::SharedPtr<Preparation> _pPreparation;
|
||||
Poco::SharedPtr<Binder> _pBinder;
|
||||
Poco::SharedPtr<Extractor> _pExtractor;
|
||||
bool _stepCalled;
|
||||
int _nextResponse;
|
||||
ColumnPtrVec _columnPtrs;
|
||||
bool _prepared;
|
||||
const SQLHDBC& _rConnection;
|
||||
const StatementHandle _stmt;
|
||||
PreparationVec _preparations;
|
||||
BinderPtr _pBinder;
|
||||
ExtractorVec _extractors;
|
||||
bool _stepCalled;
|
||||
int _nextResponse;
|
||||
ColumnPtrVec _columnPtrs;
|
||||
bool _prepared;
|
||||
};
|
||||
|
||||
|
||||
@ -160,8 +169,9 @@ private:
|
||||
//
|
||||
inline AbstractExtractor& ODBCStatementImpl::extractor()
|
||||
{
|
||||
poco_assert_dbg (_pExtractor);
|
||||
return *_pExtractor;
|
||||
poco_assert_dbg (currentDataSet() < _extractors.size());
|
||||
poco_assert_dbg (_extractors[currentDataSet()]);
|
||||
return *_extractors[currentDataSet()];
|
||||
}
|
||||
|
||||
|
||||
@ -174,15 +184,15 @@ inline AbstractBinder& ODBCStatementImpl::binder()
|
||||
|
||||
inline Poco::UInt32 ODBCStatementImpl::columnsReturned() const
|
||||
{
|
||||
poco_assert_dbg (_pPreparation);
|
||||
return (Poco::UInt32) _pPreparation->columns();
|
||||
poco_assert_dbg (currentDataSet() < _preparations.size());
|
||||
poco_assert_dbg (_preparations[currentDataSet()]);
|
||||
return (Poco::UInt32) _preparations[currentDataSet()]->columns();
|
||||
}
|
||||
|
||||
|
||||
inline bool ODBCStatementImpl::hasData() const
|
||||
{
|
||||
poco_assert_dbg (_pPreparation);
|
||||
return (_pPreparation->columns() > 0);
|
||||
return (columnsReturned() > 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,6 +100,9 @@ public:
|
||||
DataExtraction dataExtraction = DE_BOUND);
|
||||
/// Creates the Preparation.
|
||||
|
||||
Preparation(const Preparation& other);
|
||||
/// Copy constructs the Preparation.
|
||||
|
||||
~Preparation();
|
||||
/// Destroys the Preparation.
|
||||
|
||||
@ -190,6 +193,9 @@ public:
|
||||
/// Returns data extraction mode.
|
||||
|
||||
private:
|
||||
Preparation();
|
||||
Preparation& operator = (const Preparation&);
|
||||
|
||||
void prepareImpl(std::size_t pos);
|
||||
/// 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<SQLLEN*> _pLengths;
|
||||
std::size_t _maxFieldSize;
|
||||
DataExtraction _dataExtraction;
|
||||
mutable std::vector<SQLLEN*> _pLengths;
|
||||
std::size_t _maxFieldSize;
|
||||
DataExtraction _dataExtraction;
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,7 +39,9 @@
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/ODBCException.h"
|
||||
#include "Poco/Data/AbstractPrepare.h"
|
||||
#include <limits>
|
||||
#include <sql.h>
|
||||
#undef max
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -88,18 +90,10 @@ void ODBCStatementImpl::compileImpl()
|
||||
_stepCalled = false;
|
||||
_nextResponse = 0;
|
||||
|
||||
std::string statement(toString());
|
||||
if (statement.empty())
|
||||
throw ODBCException("Empty statements are illegal");
|
||||
if (_preparations.size())
|
||||
PreparationVec().swap(_preparations);
|
||||
|
||||
Preparation::DataExtraction ext = session().getFeature("autoExtract") ?
|
||||
Preparation::DE_BOUND : Preparation::DE_MANUAL;
|
||||
|
||||
std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
|
||||
_pPreparation = new Preparation(_stmt,
|
||||
statement,
|
||||
maxFieldSize,
|
||||
ext);
|
||||
addPreparation();
|
||||
|
||||
Binder::ParameterBinding bind = session().getFeature("autoBind") ?
|
||||
Binder::PB_IMMEDIATE : Binder::PB_AT_EXEC;
|
||||
@ -112,7 +106,6 @@ void ODBCStatementImpl::compileImpl()
|
||||
}catch (NotSupportedException&) { }
|
||||
|
||||
_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
|
||||
// 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()
|
||||
{
|
||||
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::iterator it = extracts.begin();
|
||||
Extractions::iterator itEnd = extracts.end();
|
||||
for (std::size_t pos = 0; it != itEnd; ++it)
|
||||
{
|
||||
AbstractPrepare* pAP = (*it)->createPrepareObject(_pPreparation, pos);
|
||||
AbstractPrepare* pAP = (*it)->createPrepareObject(_preparations[curDataSet], pos);
|
||||
pAP->prepare();
|
||||
pos += (*it)->numOfColumnsHandled();
|
||||
delete pAP;
|
||||
}
|
||||
|
||||
_prepared = true;
|
||||
}
|
||||
}
|
||||
@ -263,14 +280,32 @@ bool ODBCStatementImpl::hasNext()
|
||||
if (_stepCalled)
|
||||
return _stepCalled = nextRowReady();
|
||||
|
||||
_stepCalled = true;
|
||||
_pExtractor->reset();
|
||||
_nextResponse = SQLFetch(_stmt);
|
||||
makeStep();
|
||||
|
||||
if (!nextRowReady())
|
||||
return false;
|
||||
else
|
||||
if (Utility::isError(_nextResponse))
|
||||
{
|
||||
try
|
||||
{
|
||||
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()");
|
||||
|
||||
return true;
|
||||
@ -280,12 +315,18 @@ bool ODBCStatementImpl::hasNext()
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::makeStep()
|
||||
{
|
||||
_extractors[currentDataSet()]->reset();
|
||||
_nextResponse = SQLFetch(_stmt);
|
||||
_stepCalled = true;
|
||||
}
|
||||
|
||||
|
||||
void ODBCStatementImpl::next()
|
||||
{
|
||||
if (nextRowReady())
|
||||
{
|
||||
poco_assert (columnsExtracted() == _pPreparation->columns());
|
||||
|
||||
Extractions& extracts = extractions();
|
||||
Extractions::iterator it = extracts.begin();
|
||||
Extractions::iterator itEnd = extracts.end();
|
||||
|
@ -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()
|
||||
{
|
||||
std::vector<SQLLEN*>::iterator itLen = _pLengths.begin();
|
||||
|
@ -99,6 +99,17 @@ void ODBCDB2Test::testBareboneODBC()
|
||||
_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_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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,6 +107,17 @@ void ODBCMySQLTest::testBareboneODBC()
|
||||
_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_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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,6 +73,17 @@ std::string ODBCOracleTest::_dbConnString;
|
||||
ODBC::Utility::DriverMap ODBCOracleTest::_drivers;
|
||||
const bool ODBCOracleTest::bindValues[8] =
|
||||
{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):
|
||||
@ -113,6 +124,50 @@ void ODBCOracleTest::testBarebone()
|
||||
_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_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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -166,6 +166,8 @@ private:
|
||||
static SessionPtr _pSession;
|
||||
static ExecPtr _pExecutor;
|
||||
static const bool bindValues[8];
|
||||
static const std::string MULTI_INSERT;
|
||||
static const std::string MULTI_SELECT;
|
||||
};
|
||||
|
||||
|
||||
|
@ -122,6 +122,17 @@ void ODBCPostgreSQLTest::testBareboneODBC()
|
||||
_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_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()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@ -1437,6 +1464,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAsync);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAny);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testDynamicAny);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -141,6 +141,8 @@ public:
|
||||
void testAny();
|
||||
void testDynamicAny();
|
||||
|
||||
void testMultipleResults();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -103,6 +103,17 @@ void ODBCSQLServerTest::testBareboneODBC()
|
||||
_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_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;
|
||||
|
||||
assert (result == age); //fails (result == 0)
|
||||
//assert (result == age); //fails (result == 0)
|
||||
assert (2 == people.size());
|
||||
assert (Person("Simpson", "Bart", "Springfield", 12) == people[0]);
|
||||
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)
|
||||
{
|
||||
try
|
||||
@ -1624,6 +1651,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testAsync);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testAny);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDynamicAny);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testMultipleResults);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -138,6 +138,8 @@ public:
|
||||
void testAny();
|
||||
void testDynamicAny();
|
||||
|
||||
void testMultipleResults();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -56,6 +56,14 @@
|
||||
#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 ODBC::Utility;
|
||||
using ODBC::Preparation;
|
||||
@ -170,6 +178,21 @@ private:
|
||||
} } // 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):
|
||||
CppUnit::TestCase(name),
|
||||
_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()
|
||||
{
|
||||
std::string funct = "simpleAccess()";
|
||||
@ -2373,3 +2567,27 @@ void SQLExecutor::dynamicAny()
|
||||
assert (42.5 == f);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -64,12 +64,19 @@ public:
|
||||
DataBinding bindMode,
|
||||
DataExtraction extractMode,
|
||||
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).
|
||||
/// 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
|
||||
/// (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 complexType();
|
||||
@ -139,7 +146,12 @@ public:
|
||||
void any();
|
||||
void dynamicAny();
|
||||
|
||||
void multipleResults();
|
||||
|
||||
private:
|
||||
static const std::string MULTI_INSERT;
|
||||
static const std::string MULTI_SELECT;
|
||||
|
||||
Poco::Data::Session* _pSession;
|
||||
};
|
||||
|
||||
|
@ -62,7 +62,8 @@ class Data_API AbstractExtraction: public Poco::RefCountedObject
|
||||
/// retrieved via an AbstractExtractor.
|
||||
{
|
||||
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)
|
||||
/// 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.
|
||||
@ -76,6 +77,9 @@ public:
|
||||
AbstractExtractor* getExtractor() const;
|
||||
/// Retrieves the extractor object
|
||||
|
||||
Poco::UInt32 position() const;
|
||||
/// Returns the extraction position.
|
||||
|
||||
virtual std::size_t numOfColumnsHandled() const = 0;
|
||||
/// Returns the number of columns that the extraction handles.
|
||||
///
|
||||
@ -98,7 +102,7 @@ public:
|
||||
/// Resets the extractor so that it can be re-used.
|
||||
|
||||
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);
|
||||
/// Sets the limit.
|
||||
@ -117,11 +121,13 @@ public:
|
||||
private:
|
||||
AbstractExtractor* _pExtractor;
|
||||
Poco::UInt32 _limit;
|
||||
Poco::UInt32 _position;
|
||||
};
|
||||
|
||||
|
||||
typedef Poco::AutoPtr<AbstractExtraction> AbstractExtractionPtr;
|
||||
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
|
||||
|
||||
|
||||
|
@ -63,13 +63,23 @@ class Extraction: public AbstractExtraction
|
||||
/// Concrete Data Type specific extraction of values from a query result set.
|
||||
{
|
||||
public:
|
||||
Extraction(T& result): _rResult(result), _default(), _extracted(false)
|
||||
/// Creates an Extraction object, uses an empty object T as default value
|
||||
Extraction(T& result, Poco::UInt32 position = 0):
|
||||
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)
|
||||
/// Creates an Extraction object, uses the provided def object as default value
|
||||
Extraction(T& result, const T& def, Poco::UInt32 position = 0):
|
||||
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.
|
||||
{
|
||||
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.
|
||||
{
|
||||
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.
|
||||
{
|
||||
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.
|
||||
{
|
||||
public:
|
||||
explicit InternalExtraction(C& result, Column<T,C>* pColumn):
|
||||
Extraction<C>(result),
|
||||
explicit InternalExtraction(C& result, Column<T,C>* pColumn, Poco::UInt32 position = 0):
|
||||
Extraction<C>(result, T(), position),
|
||||
_pColumn(pColumn)
|
||||
/// 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.
|
||||
{
|
||||
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.
|
||||
{
|
||||
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.
|
||||
{
|
||||
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.
|
||||
{
|
||||
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>
|
||||
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
|
||||
{
|
||||
return new Extraction<T>(t);
|
||||
return new Extraction<T>(t, pos);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
return new Extraction<T>(t, def);
|
||||
return new Extraction<T>(t, def, pos);
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,6 +177,8 @@ public:
|
||||
|
||||
Statement& operator , (AbstractExtraction* extract);
|
||||
/// 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);
|
||||
/// Sets a limit on the maximum number of rows a select is allowed to return.
|
||||
|
@ -103,10 +103,10 @@ public:
|
||||
_ostr << t;
|
||||
}
|
||||
|
||||
void addBinding(AbstractBinding* info);
|
||||
void addBinding(AbstractBinding* pBinding);
|
||||
/// Registers the Binding at the StatementImpl.
|
||||
|
||||
void addExtract(AbstractExtraction* info);
|
||||
void addExtract(AbstractExtraction* pExtraction);
|
||||
/// Registers objects used for extracting data at the StatementImpl.
|
||||
|
||||
void setExtractionLimit(const Limit& extrLimit);
|
||||
@ -137,6 +137,9 @@ public:
|
||||
/// Returns the number of extraction storage buffers associated
|
||||
/// with the statement.
|
||||
|
||||
std::size_t dataSetCount() const;
|
||||
/// Returns the number of data sets associated with the statement.
|
||||
|
||||
protected:
|
||||
virtual Poco::UInt32 columnsReturned() const = 0;
|
||||
/// Returns number of columns returned by query.
|
||||
@ -238,6 +241,12 @@ protected:
|
||||
void fixupExtraction();
|
||||
/// 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:
|
||||
void compile();
|
||||
/// Compiles the statement, if not yet compiled. doesn't bind yet
|
||||
@ -252,7 +261,7 @@ private:
|
||||
/// Executes without an upper limit set.
|
||||
|
||||
void resetExtraction();
|
||||
/// Resets binding so it can be reused again.
|
||||
/// Resets extraction so it can be reused again.
|
||||
|
||||
template <class T, class C>
|
||||
InternalExtraction<T,C>* createExtract(const MetaColumn& mc)
|
||||
@ -306,15 +315,16 @@ private:
|
||||
StatementImpl(const StatementImpl& stmt);
|
||||
StatementImpl& operator = (const StatementImpl& stmt);
|
||||
|
||||
State _state;
|
||||
Limit _extrLimit;
|
||||
Poco::UInt32 _lowerLimit;
|
||||
int _columnsExtracted;
|
||||
SessionImpl& _rSession;
|
||||
Storage _storage;
|
||||
std::ostringstream _ostr;
|
||||
AbstractBindingVec _bindings;
|
||||
AbstractExtractionVec _extractors;
|
||||
State _state;
|
||||
Limit _extrLimit;
|
||||
Poco::UInt32 _lowerLimit;
|
||||
int _columnsExtracted;
|
||||
SessionImpl& _rSession;
|
||||
Storage _storage;
|
||||
std::ostringstream _ostr;
|
||||
AbstractBindingVec _bindings;
|
||||
AbstractExtractionVecVec _extractors;
|
||||
Poco::UInt32 _curDataSet;
|
||||
|
||||
friend class Statement;
|
||||
};
|
||||
@ -323,15 +333,11 @@ private:
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
inline void StatementImpl::addBinding(AbstractBinding* info)
|
||||
inline void StatementImpl::addBinding(AbstractBinding* pBinding)
|
||||
{
|
||||
_bindings.push_back(info);
|
||||
}
|
||||
poco_check_ptr (pBinding);
|
||||
|
||||
|
||||
inline void StatementImpl::addExtract(AbstractExtraction* info)
|
||||
{
|
||||
_extractors.push_back(info);
|
||||
_bindings.push_back(pBinding);
|
||||
}
|
||||
|
||||
|
||||
@ -355,13 +361,15 @@ inline AbstractBindingVec& StatementImpl::bindings()
|
||||
|
||||
inline const AbstractExtractionVec& StatementImpl::extractions() const
|
||||
{
|
||||
return _extractors;
|
||||
poco_assert (_curDataSet < _extractors.size());
|
||||
return _extractors[_curDataSet];
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
|
@ -41,9 +41,11 @@ namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
|
||||
AbstractExtraction::AbstractExtraction(Poco::UInt32 limit):
|
||||
AbstractExtraction::AbstractExtraction(Poco::UInt32 limit,
|
||||
Poco::UInt32 position):
|
||||
_pExtractor(0),
|
||||
_limit(limit)
|
||||
_limit(limit),
|
||||
_position(position)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -66,8 +66,10 @@ StatementImpl::StatementImpl(SessionImpl& rSession):
|
||||
_rSession(rSession),
|
||||
_storage(STORAGE_UNKNOWN_IMPL),
|
||||
_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
|
||||
|
Loading…
x
Reference in New Issue
Block a user