Skip to content

Commit c3c422d

Browse files
committed
multiple results (WIP, compiles and tests pass)
1 parent 9a5a611 commit c3c422d

20 files changed

Lines changed: 643 additions & 99 deletions

‎Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h‎

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,14 @@ class ODBC_API ODBCStatementImpl: public Poco::Data::StatementImpl
107107
/// Returns the SQL string as modified by the driver.
108108

109109
private:
110-
typedef Poco::Data::AbstractBindingVec Bindings;
110+
typedef Poco::Data::AbstractBindingVec Bindings;
111+
typedef Poco::SharedPtr<Binder> BinderPtr;
111112
typedef Poco::Data::AbstractExtractionVec Extractions;
112-
113+
typedef Poco::SharedPtr<Preparation> PreparationPtr;
114+
typedef std::vector<PreparationPtr> PreparationVec;
115+
typedef Poco::SharedPtr<Extractor> ExtractorPtr;
116+
typedef std::vector<ExtractorPtr> ExtractorVec;
117+
113118
static const std::string INVALID_CURSOR_STATE;
114119

115120
void clear();
@@ -131,6 +136,9 @@ class ODBC_API ODBCStatementImpl: public Poco::Data::StatementImpl
131136
bool hasData() const;
132137
/// Returns true if statement returns data.
133138

139+
void makeStep();
140+
/// Fetches the next row of data.
141+
134142
bool nextRowReady() const;
135143
/// Returns true if there is a row fetched but not yet extracted.
136144

@@ -140,18 +148,19 @@ class ODBC_API ODBCStatementImpl: public Poco::Data::StatementImpl
140148

141149
void getData();
142150

151+
void addPreparation();
143152
void fillColumns();
144153
void checkError(SQLRETURN rc, const std::string& msg="");
145154

146-
const SQLHDBC& _rConnection;
147-
const StatementHandle _stmt;
148-
Poco::SharedPtr<Preparation> _pPreparation;
149-
Poco::SharedPtr<Binder> _pBinder;
150-
Poco::SharedPtr<Extractor> _pExtractor;
151-
bool _stepCalled;
152-
int _nextResponse;
153-
ColumnPtrVec _columnPtrs;
154-
bool _prepared;
155+
const SQLHDBC& _rConnection;
156+
const StatementHandle _stmt;
157+
PreparationVec _preparations;
158+
BinderPtr _pBinder;
159+
ExtractorVec _extractors;
160+
bool _stepCalled;
161+
int _nextResponse;
162+
ColumnPtrVec _columnPtrs;
163+
bool _prepared;
155164
};
156165

157166

@@ -160,8 +169,9 @@ class ODBC_API ODBCStatementImpl: public Poco::Data::StatementImpl
160169
//
161170
inline AbstractExtractor& ODBCStatementImpl::extractor()
162171
{
163-
poco_assert_dbg (_pExtractor);
164-
return *_pExtractor;
172+
poco_assert_dbg (currentDataSet() < _extractors.size());
173+
poco_assert_dbg (_extractors[currentDataSet()]);
174+
return *_extractors[currentDataSet()];
165175
}
166176

167177

@@ -174,15 +184,15 @@ inline AbstractBinder& ODBCStatementImpl::binder()
174184

175185
inline Poco::UInt32 ODBCStatementImpl::columnsReturned() const
176186
{
177-
poco_assert_dbg (_pPreparation);
178-
return (Poco::UInt32) _pPreparation->columns();
187+
poco_assert_dbg (currentDataSet() < _preparations.size());
188+
poco_assert_dbg (_preparations[currentDataSet()]);
189+
return (Poco::UInt32) _preparations[currentDataSet()]->columns();
179190
}
180191

181192

182193
inline bool ODBCStatementImpl::hasData() const
183194
{
184-
poco_assert_dbg (_pPreparation);
185-
return (_pPreparation->columns() > 0);
195+
return (columnsReturned() > 0);
186196
}
187197

188198

‎Data/ODBC/include/Poco/Data/ODBC/Preparation.h‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ODBC_API Preparation : public AbstractPreparation
100100
DataExtraction dataExtraction = DE_BOUND);
101101
/// Creates the Preparation.
102102

103+
Preparation(const Preparation& other);
104+
/// Copy constructs the Preparation.
105+
103106
~Preparation();
104107
/// Destroys the Preparation.
105108

@@ -190,6 +193,9 @@ class ODBC_API Preparation : public AbstractPreparation
190193
/// Returns data extraction mode.
191194

192195
private:
196+
Preparation();
197+
Preparation& operator = (const Preparation&);
198+
193199
void prepareImpl(std::size_t pos);
194200
/// Utility function to prepare Any and DynamicAny
195201

@@ -246,11 +252,11 @@ class ODBC_API Preparation : public AbstractPreparation
246252
}
247253
}
248254

249-
const StatementHandle& _rStmt;
255+
const StatementHandle& _rStmt;
250256
mutable std::vector<Poco::Any*> _pValues;
251-
mutable std::vector<SQLLEN*> _pLengths;
252-
std::size_t _maxFieldSize;
253-
DataExtraction _dataExtraction;
257+
mutable std::vector<SQLLEN*> _pLengths;
258+
std::size_t _maxFieldSize;
259+
DataExtraction _dataExtraction;
254260
};
255261

256262

‎Data/ODBC/src/ODBCStatementImpl.cpp‎

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@
3939
#include "Poco/Data/ODBC/Utility.h"
4040
#include "Poco/Data/ODBC/ODBCException.h"
4141
#include "Poco/Data/AbstractPrepare.h"
42+
#include <limits>
4243
#include <sql.h>
44+
#undef max
4345

4446

4547
namespace Poco {
@@ -88,18 +90,10 @@ void ODBCStatementImpl::compileImpl()
8890
_stepCalled = false;
8991
_nextResponse = 0;
9092

91-
std::string statement(toString());
92-
if (statement.empty())
93-
throw ODBCException("Empty statements are illegal");
93+
if (_preparations.size())
94+
PreparationVec().swap(_preparations);
9495

95-
Preparation::DataExtraction ext = session().getFeature("autoExtract") ?
96-
Preparation::DE_BOUND : Preparation::DE_MANUAL;
97-
98-
std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
99-
_pPreparation = new Preparation(_stmt,
100-
statement,
101-
maxFieldSize,
102-
ext);
96+
addPreparation();
10397

10498
Binder::ParameterBinding bind = session().getFeature("autoBind") ?
10599
Binder::PB_IMMEDIATE : Binder::PB_AT_EXEC;
@@ -112,7 +106,6 @@ void ODBCStatementImpl::compileImpl()
112106
}catch (NotSupportedException&) { }
113107

114108
_pBinder = new Binder(_stmt, bind, pDT);
115-
_pExtractor = new Extractor(_stmt, *_pPreparation);
116109

117110
// This is a hack to conform to some ODBC drivers behavior (e.g. MS SQLServer) with
118111
// stored procedure calls: driver refuses to report the number of columns, unless all
@@ -137,22 +130,46 @@ void ODBCStatementImpl::makeInternalExtractors()
137130
}
138131

139132

133+
void ODBCStatementImpl::addPreparation()
134+
{
135+
if (0 == _preparations.size())
136+
{
137+
std::string statement(toString());
138+
if (statement.empty())
139+
throw ODBCException("Empty statements are illegal");
140+
141+
Preparation::DataExtraction ext = session().getFeature("autoExtract") ?
142+
Preparation::DE_BOUND : Preparation::DE_MANUAL;
143+
144+
std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
145+
146+
_preparations.push_back(new Preparation(_stmt, statement, maxFieldSize, ext));
147+
}
148+
else
149+
_preparations.push_back(new Preparation(*_preparations[0]));
150+
151+
_extractors.push_back(new Extractor(_stmt, *_preparations.back()));
152+
}
153+
154+
140155
void ODBCStatementImpl::doPrepare()
141156
{
142-
if (!_prepared && session().getFeature("autoExtract") && hasData())
157+
if (session().getFeature("autoExtract") && hasData())
143158
{
144-
poco_check_ptr (_pPreparation);
159+
Poco::UInt32 curDataSet = currentDataSet();
160+
poco_check_ptr (_preparations[curDataSet]);
145161

146162
Extractions& extracts = extractions();
147163
Extractions::iterator it = extracts.begin();
148164
Extractions::iterator itEnd = extracts.end();
149165
for (std::size_t pos = 0; it != itEnd; ++it)
150166
{
151-
AbstractPrepare* pAP = (*it)->createPrepareObject(_pPreparation, pos);
167+
AbstractPrepare* pAP = (*it)->createPrepareObject(_preparations[curDataSet], pos);
152168
pAP->prepare();
153169
pos += (*it)->numOfColumnsHandled();
154170
delete pAP;
155171
}
172+
156173
_prepared = true;
157174
}
158175
}
@@ -263,14 +280,32 @@ bool ODBCStatementImpl::hasNext()
263280
if (_stepCalled)
264281
return _stepCalled = nextRowReady();
265282

266-
_stepCalled = true;
267-
_pExtractor->reset();
268-
_nextResponse = SQLFetch(_stmt);
283+
makeStep();
269284

270285
if (!nextRowReady())
271-
return false;
272-
else
273-
if (Utility::isError(_nextResponse))
286+
{
287+
try
288+
{
289+
activateNextDataSet();
290+
} catch (InvalidAccessException&)
291+
{
292+
return false;
293+
}
294+
295+
addPreparation();
296+
doPrepare();
297+
fixupExtraction();
298+
299+
try
300+
{
301+
checkError(SQLMoreResults(_stmt));
302+
} catch (NoDataException&)
303+
{
304+
return false;
305+
}
306+
makeStep();
307+
}
308+
else if (Utility::isError(_nextResponse))
274309
checkError(_nextResponse, "SQLFetch()");
275310

276311
return true;
@@ -280,12 +315,18 @@ bool ODBCStatementImpl::hasNext()
280315
}
281316

282317

318+
void ODBCStatementImpl::makeStep()
319+
{
320+
_extractors[currentDataSet()]->reset();
321+
_nextResponse = SQLFetch(_stmt);
322+
_stepCalled = true;
323+
}
324+
325+
283326
void ODBCStatementImpl::next()
284327
{
285328
if (nextRowReady())
286329
{
287-
poco_assert (columnsExtracted() == _pPreparation->columns());
288-
289330
Extractions& extracts = extractions();
290331
Extractions::iterator it = extracts.begin();
291332
Extractions::iterator itEnd = extracts.end();

‎Data/ODBC/src/Preparation.cpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ Preparation::Preparation(const StatementHandle& rStmt,
5757
}
5858

5959

60+
Preparation::Preparation(const Preparation& other):
61+
_rStmt(other._rStmt),
62+
_maxFieldSize(other._maxFieldSize),
63+
_dataExtraction(other._dataExtraction)
64+
{
65+
}
66+
67+
6068
Preparation::~Preparation()
6169
{
6270
std::vector<SQLLEN*>::iterator itLen = _pLengths.begin();

‎Data/ODBC/testsuite/src/ODBCDB2Test.cpp‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ void ODBCDB2Test::testBareboneODBC()
9999
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
100100
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
101101
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
102+
103+
104+
tableCreateString = "CREATE TABLE Test "
105+
"(First VARCHAR(30),"
106+
"Second INTEGER,"
107+
"Third FLOAT)";
108+
109+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
110+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
111+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
112+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
102113
}
103114

104115

‎Data/ODBC/testsuite/src/ODBCMySQLTest.cpp‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ void ODBCMySQLTest::testBareboneODBC()
107107
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND, false);
108108
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false);
109109
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false);
110+
111+
112+
tableCreateString = "CREATE TABLE Test "
113+
"(First VARCHAR(30),"
114+
"Second INTEGER,"
115+
"Third FLOAT)";
116+
117+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL);
118+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
119+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
120+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
110121
}
111122

112123

‎Data/ODBC/testsuite/src/ODBCOracleTest.cpp‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,17 @@ std::string ODBCOracleTest::_dbConnString;
7373
ODBC::Utility::DriverMap ODBCOracleTest::_drivers;
7474
const bool ODBCOracleTest::bindValues[8] =
7575
{true, true, true, false, false, true, false, false};
76+
const std::string ODBCOracleTest::MULTI_INSERT =
77+
"BEGIN "
78+
"INSERT INTO Test VALUES ('1', 2, 3.5);"
79+
"INSERT INTO Test VALUES ('2', 3, 4.5);"
80+
"INSERT INTO Test VALUES ('3', 4, 5.5);"
81+
"INSERT INTO Test VALUES ('4', 5, 6.5);"
82+
"INSERT INTO Test VALUES ('5', 6, 7.5);"
83+
"END;";
84+
85+
const std::string ODBCOracleTest::MULTI_SELECT =
86+
"{CALL multiResultsProcedure()}";
7687

7788

7889
ODBCOracleTest::ODBCOracleTest(const std::string& name):
@@ -113,6 +124,50 @@ void ODBCOracleTest::testBarebone()
113124
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
114125
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
115126
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
127+
128+
tableCreateString = "CREATE TABLE Test "
129+
"(First VARCHAR(30),"
130+
"Second INTEGER,"
131+
"Third NUMBER)";
132+
133+
*_pSession << "CREATE OR REPLACE "
134+
"PROCEDURE multiResultsProcedure(tmp1 OUT SYS_REFCURSOR, "
135+
"tmp2 OUT SYS_REFCURSOR,"
136+
"tmp3 OUT SYS_REFCURSOR,"
137+
"tmp4 OUT SYS_REFCURSOR,"
138+
"tmp5 OUT SYS_REFCURSOR) IS "
139+
"BEGIN "
140+
"OPEN tmp1 FOR SELECT * FROM Test WHERE First = '1';"
141+
"OPEN tmp2 FOR SELECT * FROM Test WHERE First = '2';"
142+
"OPEN tmp3 FOR SELECT * FROM Test WHERE First = '3';"
143+
"OPEN tmp4 FOR SELECT * FROM Test WHERE First = '4';"
144+
"OPEN tmp5 FOR SELECT * FROM Test WHERE First = '5';"
145+
"END multiResultsProcedure;" , now;
146+
147+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
148+
tableCreateString,
149+
SQLExecutor::PB_IMMEDIATE,
150+
SQLExecutor::DE_MANUAL,
151+
MULTI_INSERT,
152+
MULTI_SELECT);
153+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
154+
tableCreateString,
155+
SQLExecutor::PB_IMMEDIATE,
156+
SQLExecutor::DE_BOUND,
157+
MULTI_INSERT,
158+
MULTI_SELECT);
159+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
160+
tableCreateString,
161+
SQLExecutor::PB_AT_EXEC,
162+
SQLExecutor::DE_MANUAL,
163+
MULTI_INSERT,
164+
MULTI_SELECT);
165+
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
166+
tableCreateString,
167+
SQLExecutor::PB_AT_EXEC,
168+
SQLExecutor::DE_BOUND,
169+
MULTI_INSERT,
170+
MULTI_SELECT);
116171
}
117172

118173

0 commit comments

Comments
 (0)