mirror of
https://github.com/pocoproject/poco.git
synced 2025-04-02 17:50:53 +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.
|
/// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,8 @@ public:
|
|||||||
void testAny();
|
void testAny();
|
||||||
void testDynamicAny();
|
void testDynamicAny();
|
||||||
|
|
||||||
|
void testMultipleResults();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
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_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;
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,8 @@ public:
|
|||||||
void testAny();
|
void testAny();
|
||||||
void testDynamicAny();
|
void testDynamicAny();
|
||||||
|
|
||||||
|
void testMultipleResults();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user