mirror of
https://github.com/pocoproject/poco.git
synced 2025-11-24 22:29:47 +01:00
SQLite multiple statement handling
This commit is contained in:
@@ -66,8 +66,6 @@ class ODBC_API ODBCStatementImpl: public Poco::Data::StatementImpl
|
|||||||
/// Implements statement functionality needed for ODBC
|
/// Implements statement functionality needed for ODBC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::vector<ODBCMetaColumn*> ColumnPtrVec;
|
|
||||||
|
|
||||||
ODBCStatementImpl(SessionImpl& rSession);
|
ODBCStatementImpl(SessionImpl& rSession);
|
||||||
/// Creates the ODBCStatementImpl.
|
/// Creates the ODBCStatementImpl.
|
||||||
|
|
||||||
@@ -96,8 +94,12 @@ protected:
|
|||||||
bool canBind() const;
|
bool canBind() const;
|
||||||
/// Returns true if a valid statement is set and we can bind.
|
/// Returns true if a valid statement is set and we can bind.
|
||||||
|
|
||||||
void compileImpl();
|
bool compileImpl();
|
||||||
/// Compiles the statement, doesn't bind yet
|
/// Compiles the statement, doesn't bind yet.
|
||||||
|
/// Does nothing if the statement has already been compiled.
|
||||||
|
/// In this implementation, batch statements are compiled in a single step.
|
||||||
|
/// Therefore, this function always return false indicating no need for
|
||||||
|
/// subsequent compilation.
|
||||||
|
|
||||||
void bindImpl();
|
void bindImpl();
|
||||||
/// Binds all parameters and executes the statement.
|
/// Binds all parameters and executes the statement.
|
||||||
@@ -119,6 +121,8 @@ private:
|
|||||||
typedef std::vector<PreparationPtr> PreparationVec;
|
typedef std::vector<PreparationPtr> PreparationVec;
|
||||||
typedef Poco::SharedPtr<Extractor> ExtractorPtr;
|
typedef Poco::SharedPtr<Extractor> ExtractorPtr;
|
||||||
typedef std::vector<ExtractorPtr> ExtractorVec;
|
typedef std::vector<ExtractorPtr> ExtractorVec;
|
||||||
|
typedef std::vector<ODBCMetaColumn*> ColumnPtrVec;
|
||||||
|
typedef std::vector<ColumnPtrVec> ColumnPtrVecVec;
|
||||||
|
|
||||||
static const std::string INVALID_CURSOR_STATE;
|
static const std::string INVALID_CURSOR_STATE;
|
||||||
|
|
||||||
@@ -167,9 +171,10 @@ private:
|
|||||||
ExtractorVec _extractors;
|
ExtractorVec _extractors;
|
||||||
bool _stepCalled;
|
bool _stepCalled;
|
||||||
int _nextResponse;
|
int _nextResponse;
|
||||||
ColumnPtrVec _columnPtrs;
|
ColumnPtrVecVec _columnPtrs;
|
||||||
bool _prepared;
|
bool _prepared;
|
||||||
mutable Poco::UInt32 _affectedRowCount;
|
mutable Poco::UInt32 _affectedRowCount;
|
||||||
|
bool _compiled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -101,17 +101,11 @@ void Binder::freeMemory()
|
|||||||
|
|
||||||
StringMap::iterator itStr = _strings.begin();
|
StringMap::iterator itStr = _strings.begin();
|
||||||
StringMap::iterator itStrEnd = _strings.end();
|
StringMap::iterator itStrEnd = _strings.end();
|
||||||
for(; itStr != itStrEnd; ++itStr)
|
for(; itStr != itStrEnd; ++itStr) std::free(itStr->first);
|
||||||
{
|
|
||||||
if (itStr->first) std::free(itStr->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
CharPtrVec::iterator itChr = _charPtrs.begin();
|
CharPtrVec::iterator itChr = _charPtrs.begin();
|
||||||
CharPtrVec::iterator endChr = _charPtrs.end();
|
CharPtrVec::iterator endChr = _charPtrs.end();
|
||||||
for (; itChr != endChr; ++itChr)
|
for (; itChr != endChr; ++itChr) std::free(*itChr);
|
||||||
{
|
|
||||||
if (*itChr) std::free(*itChr);
|
|
||||||
}
|
|
||||||
|
|
||||||
BoolPtrVec::iterator itBool = _boolPtrs.begin();
|
BoolPtrVec::iterator itBool = _boolPtrs.begin();
|
||||||
BoolPtrVec::iterator endBool = _boolPtrs.end();
|
BoolPtrVec::iterator endBool = _boolPtrs.end();
|
||||||
|
|||||||
@@ -65,21 +65,30 @@ ODBCStatementImpl::ODBCStatementImpl(SessionImpl& rSession):
|
|||||||
_stepCalled(false),
|
_stepCalled(false),
|
||||||
_nextResponse(0),
|
_nextResponse(0),
|
||||||
_prepared(false),
|
_prepared(false),
|
||||||
_affectedRowCount(0)
|
_affectedRowCount(0),
|
||||||
|
_compiled(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ODBCStatementImpl::~ODBCStatementImpl()
|
ODBCStatementImpl::~ODBCStatementImpl()
|
||||||
{
|
{
|
||||||
ColumnPtrVec::iterator it = _columnPtrs.begin();
|
ColumnPtrVecVec::iterator it = _columnPtrs.begin();
|
||||||
ColumnPtrVec::iterator itEnd = _columnPtrs.end();
|
ColumnPtrVecVec::iterator end = _columnPtrs.end();
|
||||||
for(; it != itEnd; ++it) delete *it;
|
for(; it != end; ++it)
|
||||||
|
{
|
||||||
|
ColumnPtrVec::iterator itC = it->begin();
|
||||||
|
ColumnPtrVec::iterator endC = it->end();
|
||||||
|
for(; itC != endC; ++itC) delete *itC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ODBCStatementImpl::compileImpl()
|
bool ODBCStatementImpl::compileImpl()
|
||||||
{
|
{
|
||||||
|
if (_compiled) return false;
|
||||||
|
|
||||||
|
clear();
|
||||||
_stepCalled = false;
|
_stepCalled = false;
|
||||||
_nextResponse = 0;
|
_nextResponse = 0;
|
||||||
|
|
||||||
@@ -111,6 +120,9 @@ void ODBCStatementImpl::compileImpl()
|
|||||||
|
|
||||||
makeInternalExtractors();
|
makeInternalExtractors();
|
||||||
doPrepare();
|
doPrepare();
|
||||||
|
|
||||||
|
_compiled = true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -302,9 +314,8 @@ bool ODBCStatementImpl::hasNext()
|
|||||||
|
|
||||||
if (!nextRowReady())
|
if (!nextRowReady())
|
||||||
{
|
{
|
||||||
try { activateNextDataSet(); }
|
if (hasMoreDataSets()) activateNextDataSet();
|
||||||
catch (NoDataException&)
|
else return false;
|
||||||
{ return false; }
|
|
||||||
|
|
||||||
if (SQL_NO_DATA == SQLMoreResults(_stmt))
|
if (SQL_NO_DATA == SQLMoreResults(_stmt))
|
||||||
return false;
|
return false;
|
||||||
@@ -418,9 +429,12 @@ void ODBCStatementImpl::checkError(SQLRETURN rc, const std::string& msg)
|
|||||||
void ODBCStatementImpl::fillColumns()
|
void ODBCStatementImpl::fillColumns()
|
||||||
{
|
{
|
||||||
Poco::UInt32 colCount = columnsReturned();
|
Poco::UInt32 colCount = columnsReturned();
|
||||||
|
Poco::UInt32 curDataSet = currentDataSet();
|
||||||
|
if (curDataSet >= _columnPtrs.size())
|
||||||
|
_columnPtrs.resize(curDataSet + 1);
|
||||||
|
|
||||||
for (int i = 0; i < colCount; ++i)
|
for (int i = 0; i < colCount; ++i)
|
||||||
_columnPtrs.push_back(new ODBCMetaColumn(_stmt, i));
|
_columnPtrs[curDataSet].push_back(new ODBCMetaColumn(_stmt, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -435,12 +449,15 @@ bool ODBCStatementImpl::isStoredProcedure() const
|
|||||||
|
|
||||||
const MetaColumn& ODBCStatementImpl::metaColumn(Poco::UInt32 pos) const
|
const MetaColumn& ODBCStatementImpl::metaColumn(Poco::UInt32 pos) const
|
||||||
{
|
{
|
||||||
std::size_t sz = _columnPtrs.size();
|
Poco::UInt32 curDataSet = currentDataSet();
|
||||||
|
poco_assert_dbg (curDataSet < _columnPtrs.size());
|
||||||
|
|
||||||
|
std::size_t sz = _columnPtrs[curDataSet].size();
|
||||||
|
|
||||||
if (0 == sz || pos > sz - 1)
|
if (0 == sz || pos > sz - 1)
|
||||||
throw InvalidAccessException(format("Invalid column number: %u", pos));
|
throw InvalidAccessException(format("Invalid column number: %u", pos));
|
||||||
|
|
||||||
return *_columnPtrs[pos];
|
return *_columnPtrs[curDataSet][pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -94,14 +94,14 @@ void Preparation::freeMemory() const
|
|||||||
case DT_CHAR_ARRAY:
|
case DT_CHAR_ARRAY:
|
||||||
{
|
{
|
||||||
char* pc = AnyCast<char>(&_values[it->first]);
|
char* pc = AnyCast<char>(&_values[it->first]);
|
||||||
if (pc) std::free(pc);
|
std::free(pc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DT_BOOL_ARRAY:
|
case DT_BOOL_ARRAY:
|
||||||
{
|
{
|
||||||
bool* pb = AnyCast<bool>(&_values[it->first]);
|
bool* pb = AnyCast<bool>(&_values[it->first]);
|
||||||
if (pb) std::free(pb);
|
std::free(pb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -586,13 +586,14 @@ void ODBCOracleTest::testMultipleResults()
|
|||||||
std::string sql = "CREATE OR REPLACE "
|
std::string sql = "CREATE OR REPLACE "
|
||||||
"PROCEDURE multiResultsProcedure(paramAge1 IN NUMBER,"
|
"PROCEDURE multiResultsProcedure(paramAge1 IN NUMBER,"
|
||||||
" paramAge2 IN NUMBER,"
|
" paramAge2 IN NUMBER,"
|
||||||
|
" paramAge3 IN NUMBER,"
|
||||||
" ret1 OUT SYS_REFCURSOR, "
|
" ret1 OUT SYS_REFCURSOR, "
|
||||||
" ret2 OUT SYS_REFCURSOR,"
|
" ret2 OUT SYS_REFCURSOR,"
|
||||||
" ret3 OUT SYS_REFCURSOR) IS "
|
" ret3 OUT SYS_REFCURSOR) IS "
|
||||||
"BEGIN "
|
"BEGIN "
|
||||||
" OPEN ret1 FOR SELECT * FROM Person WHERE Age = paramAge1;"
|
" OPEN ret1 FOR SELECT * FROM Person WHERE Age = paramAge1;"
|
||||||
" OPEN ret2 FOR SELECT Age FROM Person WHERE FirstName = 'Bart';"
|
" OPEN ret2 FOR SELECT Age FROM Person WHERE FirstName = 'Bart';"
|
||||||
" OPEN ret3 FOR SELECT * FROM Person WHERE Age = paramAge2;"
|
" OPEN ret3 FOR SELECT * FROM Person WHERE Age = paramAge2 OR Age = paramAge3 ORDER BY Age;"
|
||||||
"END multiResultsProcedure;";
|
"END multiResultsProcedure;";
|
||||||
|
|
||||||
for (int i = 0; i < 8;)
|
for (int i = 0; i < 8;)
|
||||||
|
|||||||
@@ -2950,30 +2950,30 @@ void SQLExecutor::multipleResults(const std::string& sql)
|
|||||||
typedef Tuple<std::string, std::string, std::string, Poco::UInt32> Person;
|
typedef Tuple<std::string, std::string, std::string, Poco::UInt32> Person;
|
||||||
std::vector<Person> people;
|
std::vector<Person> people;
|
||||||
people.push_back(Person("Simpson", "Homer", "Springfield", 42));
|
people.push_back(Person("Simpson", "Homer", "Springfield", 42));
|
||||||
people.push_back(Person("Simpson", "Bart", "Springfield", 12));
|
people.push_back(Person("Simpson", "Marge", "Springfield", 38));
|
||||||
people.push_back(Person("Simpson", "Lisa", "Springfield", 10));
|
people.push_back(Person("Simpson", "Bart", "Springfield", 10));
|
||||||
|
people.push_back(Person("Simpson", "Lisa", "Springfield", 8));
|
||||||
|
people.push_back(Person("Simpson", "Maggie", "Springfield", 3));
|
||||||
session() << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now;
|
session() << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now;
|
||||||
|
|
||||||
Person pHomer, pLisa;
|
Person pHomer;
|
||||||
int aHomer = 42, aLisa = 10;
|
int aHomer = 42, aLisa = 8;
|
||||||
Poco::UInt32 aBart = 0;
|
Poco::UInt32 aBart = 0;
|
||||||
|
|
||||||
Poco::UInt32 pos1 = 1;
|
Poco::UInt32 pos1 = 1;
|
||||||
int pos2 = 2;
|
int pos2 = 2;
|
||||||
try {
|
std::vector<Person> people2;
|
||||||
session() << sql
|
Statement stmt(session());
|
||||||
, into(pHomer, from(0)), use(aHomer)
|
stmt << sql, into(pHomer, from(0)), use(aHomer)
|
||||||
, into(aBart, pos1)
|
, into(aBart, pos1)
|
||||||
, into(pLisa, pos2), use(aLisa)
|
, into(people2, from(pos2)), use(aLisa), use(aHomer);
|
||||||
, now;
|
|
||||||
} catch (StatementException& ex)
|
|
||||||
{
|
|
||||||
std::cout << ex.toString() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
assert (4 == stmt.execute());
|
||||||
assert (Person("Simpson", "Homer", "Springfield", 42) == pHomer);
|
assert (Person("Simpson", "Homer", "Springfield", 42) == pHomer);
|
||||||
assert (12 == aBart);
|
assert (10 == aBart);
|
||||||
assert (Person("Simpson", "Lisa", "Springfield", 10) == pLisa);
|
assert (2 == people2.size());
|
||||||
|
assert (Person("Simpson", "Lisa", "Springfield", 8) == people2[0]);
|
||||||
|
assert (Person("Simpson", "Homer", "Springfield", 42) == people2[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -499,7 +499,7 @@ public:
|
|||||||
void multipleResults(const std::string& sql =
|
void multipleResults(const std::string& sql =
|
||||||
"SELECT * FROM Person WHERE Age = ?; "
|
"SELECT * FROM Person WHERE Age = ?; "
|
||||||
"SELECT Age FROM Person WHERE FirstName = 'Bart'; "
|
"SELECT Age FROM Person WHERE FirstName = 'Bart'; "
|
||||||
"SELECT * FROM Person WHERE Age = ?; ");
|
"SELECT * FROM Person WHERE Age = ? OR Age = ? ORDER BY Age;");
|
||||||
|
|
||||||
void sqlChannel(const std::string& connect);
|
void sqlChannel(const std::string& connect);
|
||||||
void sqlLogger(const std::string& connect);
|
void sqlLogger(const std::string& connect);
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_stmt* _pStmt;
|
sqlite3_stmt* _pStmt;
|
||||||
NullIndVec _nulls;
|
NullIndVec _nulls;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -95,8 +95,15 @@ protected:
|
|||||||
bool canBind() const;
|
bool canBind() const;
|
||||||
/// Returns true if a valid statement is set and we can bind.
|
/// Returns true if a valid statement is set and we can bind.
|
||||||
|
|
||||||
void compileImpl();
|
bool compileImpl();
|
||||||
/// Compiles the statement, doesn't bind yet
|
/// Compiles the statement, doesn't bind yet.
|
||||||
|
/// Returns true if the statement was succesfully compiled.
|
||||||
|
/// The way SQLite handles batches of statmeents is by compiling
|
||||||
|
/// one at a time and returning a pointer to the next one.
|
||||||
|
/// The remainder of the statement is remebered in a string
|
||||||
|
/// buffer pointed to by _pLeftover member. Non-zero _pLeftover
|
||||||
|
/// pointing to an empty string means no more statements left
|
||||||
|
/// to compile.
|
||||||
|
|
||||||
void bindImpl();
|
void bindImpl();
|
||||||
/// Binds parameters
|
/// Binds parameters
|
||||||
@@ -116,15 +123,22 @@ private:
|
|||||||
typedef Poco::Data::AbstractBindingVec Bindings;
|
typedef Poco::Data::AbstractBindingVec Bindings;
|
||||||
typedef Poco::Data::AbstractExtractionVec Extractions;
|
typedef Poco::Data::AbstractExtractionVec Extractions;
|
||||||
typedef std::vector<Poco::Data::MetaColumn> MetaColumnVec;
|
typedef std::vector<Poco::Data::MetaColumn> MetaColumnVec;
|
||||||
|
typedef std::vector<MetaColumnVec> MetaColumnVecVec;
|
||||||
|
typedef Poco::SharedPtr<std::string> StrPtr;
|
||||||
|
typedef Bindings::iterator BindIt;
|
||||||
|
|
||||||
sqlite3* _pDB;
|
sqlite3* _pDB;
|
||||||
sqlite3_stmt* _pStmt;
|
sqlite3_stmt* _pStmt;
|
||||||
bool _stepCalled;
|
bool _stepCalled;
|
||||||
int _nextResponse;
|
int _nextResponse;
|
||||||
BinderPtr _pBinder;
|
BinderPtr _pBinder;
|
||||||
ExtractorPtr _pExtractor;
|
ExtractorPtr _pExtractor;
|
||||||
MetaColumnVec _columns;
|
MetaColumnVecVec _columns;
|
||||||
Poco::UInt32 _affectedRowCount;
|
Poco::UInt32 _affectedRowCount;
|
||||||
|
StrPtr _pLeftover;
|
||||||
|
BindIt _bindBegin;
|
||||||
|
bool _canBind;
|
||||||
|
bool _isExtracted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -143,6 +157,12 @@ inline AbstractBinder& SQLiteStatementImpl::binder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool SQLiteStatementImpl::canBind() const
|
||||||
|
{
|
||||||
|
return _canBind;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::SQLite
|
} } } // namespace Poco::Data::SQLite
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -54,8 +54,11 @@ SQLiteStatementImpl::SQLiteStatementImpl(Poco::Data::SessionImpl& rSession, sqli
|
|||||||
_pStmt(0),
|
_pStmt(0),
|
||||||
_stepCalled(false),
|
_stepCalled(false),
|
||||||
_nextResponse(0),
|
_nextResponse(0),
|
||||||
_affectedRowCount(0)
|
_affectedRowCount(0),
|
||||||
|
_canBind(false),
|
||||||
|
_isExtracted(false)
|
||||||
{
|
{
|
||||||
|
_columns.resize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -65,29 +68,33 @@ SQLiteStatementImpl::~SQLiteStatementImpl()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SQLiteStatementImpl::compileImpl()
|
bool SQLiteStatementImpl::compileImpl()
|
||||||
{
|
{
|
||||||
if (_pStmt) return;
|
if (_pLeftover && _pLeftover->empty())
|
||||||
|
{
|
||||||
|
_pLeftover = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!_pLeftover)
|
||||||
|
_bindBegin = bindings().begin();
|
||||||
|
|
||||||
std::string statement(toString());
|
std::string statement(toString());
|
||||||
if (statement.empty())
|
sqlite3_stmt* pStmt = 0;
|
||||||
|
const char* pSql = _pLeftover ? _pLeftover->c_str() : statement.c_str();
|
||||||
|
|
||||||
|
if (0 == std::strlen(pSql))
|
||||||
throw InvalidSQLStatementException("Empty statements are illegal");
|
throw InvalidSQLStatementException("Empty statements are illegal");
|
||||||
|
|
||||||
sqlite3_stmt* pStmt = 0;
|
|
||||||
const char* pSql = statement.c_str(); // The SQL to be executed
|
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
const char* pLeftover = 0;
|
const char* pLeftover = 0;
|
||||||
bool queryFound = false;
|
bool queryFound = false;
|
||||||
|
|
||||||
while (rc == SQLITE_OK && !pStmt && !queryFound)
|
do
|
||||||
{
|
{
|
||||||
rc = sqlite3_prepare_v2(_pDB, pSql, -1, &pStmt, &pLeftover);
|
rc = sqlite3_prepare_v2(_pDB, pSql, -1, &pStmt, &pLeftover);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (pStmt)
|
if (pStmt) sqlite3_finalize(pStmt);
|
||||||
{
|
|
||||||
sqlite3_finalize(pStmt);
|
|
||||||
}
|
|
||||||
pStmt = 0;
|
pStmt = 0;
|
||||||
std::string errMsg = sqlite3_errmsg(_pDB);
|
std::string errMsg = sqlite3_errmsg(_pDB);
|
||||||
Utility::throwException(rc, errMsg);
|
Utility::throwException(rc, errMsg);
|
||||||
@@ -106,32 +113,45 @@ void SQLiteStatementImpl::compileImpl()
|
|||||||
queryFound = true;
|
queryFound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while (rc == SQLITE_OK && !pStmt && !queryFound);
|
||||||
|
|
||||||
|
//Finalization call in clear() invalidates the pointer, so the value is remembered here.
|
||||||
|
//For last statement in a batch (or a single statement), pLeftover == "", so the next call
|
||||||
|
// to compileImpl() shall return false immediately when there are no more statements left.
|
||||||
|
std::string leftOver(pLeftover);
|
||||||
clear();
|
clear();
|
||||||
_pStmt = pStmt;
|
_pStmt = pStmt;
|
||||||
|
_pLeftover = new std::string(leftOver);
|
||||||
|
trimInPlace(*_pLeftover);
|
||||||
|
|
||||||
// prepare binding
|
|
||||||
_pBinder = new Binder(_pStmt);
|
_pBinder = new Binder(_pStmt);
|
||||||
_pExtractor = new Extractor(_pStmt);
|
_pExtractor = new Extractor(_pStmt);
|
||||||
|
|
||||||
|
if (SQLITE_DONE == _nextResponse && _isExtracted)
|
||||||
|
{
|
||||||
|
//if this is not the first compile and there has already been extraction
|
||||||
|
//during previous step, switch to the next set if there is one provided
|
||||||
|
if (hasMoreDataSets())
|
||||||
|
{
|
||||||
|
activateNextDataSet();
|
||||||
|
_isExtracted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int colCount = sqlite3_column_count(_pStmt);
|
int colCount = sqlite3_column_count(_pStmt);
|
||||||
|
|
||||||
for (int i = 0; i < colCount; ++i)
|
if (colCount)
|
||||||
{
|
{
|
||||||
MetaColumn mc(i, sqlite3_column_name(_pStmt, i), Utility::getColumnType(_pStmt, i));
|
Poco::UInt32 curDataSet = currentDataSet();
|
||||||
_columns.push_back(mc);
|
if (curDataSet >= _columns.size()) _columns.resize(curDataSet + 1);
|
||||||
|
for (int i = 0; i < colCount; ++i)
|
||||||
|
{
|
||||||
|
MetaColumn mc(i, sqlite3_column_name(_pStmt, i), Utility::getColumnType(_pStmt, i));
|
||||||
|
_columns[curDataSet].push_back(mc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
return true;
|
||||||
bool SQLiteStatementImpl::canBind() const
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
if (!bindings().empty() && _pStmt)
|
|
||||||
ret = (*bindings().begin())->canBind();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -143,32 +163,61 @@ void SQLiteStatementImpl::bindImpl()
|
|||||||
|
|
||||||
sqlite3_reset(_pStmt);
|
sqlite3_reset(_pStmt);
|
||||||
|
|
||||||
// bind
|
int paramCount = sqlite3_bind_parameter_count(_pStmt);
|
||||||
Bindings& binds = bindings();
|
BindIt bindEnd = bindings().end();
|
||||||
int pc = sqlite3_bind_parameter_count(_pStmt);
|
if (0 == paramCount || bindEnd == _bindBegin)
|
||||||
if (binds.empty() && 0 == pc) return;
|
|
||||||
else if (binds.empty() && pc > 0)
|
|
||||||
throw ParameterCountMismatchException();
|
|
||||||
else if (!binds.empty() && binds.size() * (*binds.begin())->numOfColumnsHandled() != pc)
|
|
||||||
throw ParameterCountMismatchException();
|
|
||||||
|
|
||||||
std::size_t pos = 1; // sqlite starts with 1 not 0!
|
|
||||||
|
|
||||||
Bindings::iterator it = binds.begin();
|
|
||||||
Bindings::iterator itEnd = binds.end();
|
|
||||||
if (it != itEnd)
|
|
||||||
_affectedRowCount = (*it)->numOfRowsHandled();
|
|
||||||
for (; it != itEnd && (*it)->canBind(); ++it)
|
|
||||||
{
|
{
|
||||||
(*it)->bind(pos);
|
_canBind = false;
|
||||||
pos += (*it)->numOfColumnsHandled();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableCount = 0;
|
||||||
|
Bindings::difference_type bindCount = 0;
|
||||||
|
Bindings::iterator it = _bindBegin;
|
||||||
|
for (; it != bindEnd; ++it)
|
||||||
|
{
|
||||||
|
availableCount += (*it)->numOfColumnsHandled();
|
||||||
|
if (availableCount <= paramCount) ++bindCount;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bindings::difference_type remainingBindCount = bindEnd - _bindBegin;
|
||||||
|
if (bindCount < remainingBindCount)
|
||||||
|
{
|
||||||
|
bindEnd = _bindBegin + bindCount;
|
||||||
|
_canBind = true;
|
||||||
|
}
|
||||||
|
else if (bindCount > remainingBindCount)
|
||||||
|
throw ParameterCountMismatchException();
|
||||||
|
|
||||||
|
if (_bindBegin != bindings().end())
|
||||||
|
{
|
||||||
|
_affectedRowCount = (*_bindBegin)->numOfRowsHandled();
|
||||||
|
|
||||||
|
Bindings::iterator oldBegin = _bindBegin;
|
||||||
|
for (std::size_t pos = 1; _bindBegin != bindEnd && (*_bindBegin)->canBind(); ++_bindBegin)
|
||||||
|
{
|
||||||
|
if (_affectedRowCount != (*_bindBegin)->numOfRowsHandled())
|
||||||
|
throw BindingException("Size mismatch in Bindings. All Bindings MUST have the same size");
|
||||||
|
|
||||||
|
(*_bindBegin)->bind(pos);
|
||||||
|
pos += (*_bindBegin)->numOfColumnsHandled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*oldBegin)->canBind())
|
||||||
|
{
|
||||||
|
//container binding will come back for more, so we must rewind
|
||||||
|
_bindBegin = oldBegin;
|
||||||
|
_canBind = true;
|
||||||
|
}
|
||||||
|
else _canBind = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SQLiteStatementImpl::clear()
|
void SQLiteStatementImpl::clear()
|
||||||
{
|
{
|
||||||
_columns.clear();
|
_columns[currentDataSet()].clear();
|
||||||
_affectedRowCount = 0;
|
_affectedRowCount = 0;
|
||||||
|
|
||||||
if (_pStmt)
|
if (_pStmt)
|
||||||
@@ -176,6 +225,8 @@ void SQLiteStatementImpl::clear()
|
|||||||
sqlite3_finalize(_pStmt);
|
sqlite3_finalize(_pStmt);
|
||||||
_pStmt=0;
|
_pStmt=0;
|
||||||
}
|
}
|
||||||
|
_pLeftover = 0;
|
||||||
|
_canBind = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -194,12 +245,11 @@ bool SQLiteStatementImpl::hasNext()
|
|||||||
|
|
||||||
_stepCalled = true;
|
_stepCalled = true;
|
||||||
_nextResponse = sqlite3_step(_pStmt);
|
_nextResponse = sqlite3_step(_pStmt);
|
||||||
_pExtractor->reset();//to clear the cached null indicators
|
|
||||||
|
|
||||||
if (_nextResponse != SQLITE_ROW && _nextResponse != SQLITE_OK && _nextResponse != SQLITE_DONE)
|
if (_nextResponse != SQLITE_ROW && _nextResponse != SQLITE_OK && _nextResponse != SQLITE_DONE)
|
||||||
{
|
|
||||||
Utility::throwException(_nextResponse);
|
Utility::throwException(_nextResponse);
|
||||||
}
|
|
||||||
|
_pExtractor->reset();//clear the cached null indicators
|
||||||
|
|
||||||
return (_nextResponse == SQLITE_ROW);
|
return (_nextResponse == SQLITE_ROW);
|
||||||
}
|
}
|
||||||
@@ -212,13 +262,14 @@ Poco::UInt32 SQLiteStatementImpl::next()
|
|||||||
poco_assert (columnsReturned() == sqlite3_column_count(_pStmt));
|
poco_assert (columnsReturned() == sqlite3_column_count(_pStmt));
|
||||||
|
|
||||||
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();
|
||||||
std::size_t pos = 0; // sqlite starts with pos 0 for results!
|
std::size_t pos = 0; // sqlite starts with pos 0 for results!
|
||||||
for (; it != itEnd; ++it)
|
for (; it != itEnd; ++it)
|
||||||
{
|
{
|
||||||
(*it)->extract(pos);
|
(*it)->extract(pos);
|
||||||
pos += (*it)->numOfColumnsHandled();
|
pos += (*it)->numOfColumnsHandled();
|
||||||
|
_isExtracted = true;
|
||||||
}
|
}
|
||||||
_stepCalled = false;
|
_stepCalled = false;
|
||||||
}
|
}
|
||||||
@@ -238,14 +289,15 @@ Poco::UInt32 SQLiteStatementImpl::next()
|
|||||||
|
|
||||||
Poco::UInt32 SQLiteStatementImpl::columnsReturned() const
|
Poco::UInt32 SQLiteStatementImpl::columnsReturned() const
|
||||||
{
|
{
|
||||||
return (Poco::UInt32) _columns.size();
|
return (Poco::UInt32) _columns[currentDataSet()].size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const MetaColumn& SQLiteStatementImpl::metaColumn(Poco::UInt32 pos) const
|
const MetaColumn& SQLiteStatementImpl::metaColumn(Poco::UInt32 pos) const
|
||||||
{
|
{
|
||||||
poco_assert (pos >= 0 && pos <= _columns.size());
|
Poco::UInt32 curDataSet = currentDataSet();
|
||||||
return _columns[pos];
|
poco_assert (pos >= 0 && pos <= _columns[curDataSet].size());
|
||||||
|
return _columns[curDataSet][pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -489,11 +489,12 @@ void SQLiteTest::testInsertSingleBulk()
|
|||||||
int x = 0;
|
int x = 0;
|
||||||
Statement stmt((tmp << "INSERT INTO Strings VALUES(:str)", use(x)));
|
Statement stmt((tmp << "INSERT INTO Strings VALUES(:str)", use(x)));
|
||||||
|
|
||||||
for (x = 0; x < 100; ++x)
|
for (int i = 0; x < 100; ++x)
|
||||||
{
|
{
|
||||||
int i = stmt.execute();
|
i = stmt.execute();
|
||||||
assert (1 == i);
|
assert (1 == i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
tmp << "SELECT COUNT(*) FROM Strings", into(count), now;
|
tmp << "SELECT COUNT(*) FROM Strings", into(count), now;
|
||||||
assert (count == 100);
|
assert (count == 100);
|
||||||
@@ -2140,16 +2141,61 @@ void SQLiteTest::testBindingCount()
|
|||||||
int i = 42;
|
int i = 42;
|
||||||
try { tmp << "INSERT INTO Ints VALUES (?)", now; }
|
try { tmp << "INSERT INTO Ints VALUES (?)", now; }
|
||||||
catch (ParameterCountMismatchException&) { }
|
catch (ParameterCountMismatchException&) { }
|
||||||
|
|
||||||
try { tmp << "INSERT INTO Ints VALUES (?)", bind(42), bind(42), now; }
|
|
||||||
catch (ParameterCountMismatchException&) { }
|
|
||||||
tmp << "INSERT INTO Ints VALUES (?)", use(i), now;
|
tmp << "INSERT INTO Ints VALUES (?)", use(i), now;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
try { tmp << "SELECT int0 from Ints where int0 = ?", into(i), now; }
|
try { tmp << "SELECT int0 from Ints where int0 = ?", into(i), now; }
|
||||||
catch (ParameterCountMismatchException&) { }
|
catch (ParameterCountMismatchException&) { }
|
||||||
tmp << "SELECT int0 from Ints where int0 = ?", bind(42), into(i), now;
|
tmp << "SELECT int0 from Ints where int0 = ?", bind(42), into(i), now;
|
||||||
assert (42 == i);
|
assert (42 == i);
|
||||||
|
|
||||||
|
tmp << "DROP TABLE IF EXISTS Ints", now;
|
||||||
|
tmp << "CREATE TABLE Ints (int0 INTEGER, int1 INTEGER, int2 INTEGER)", now;
|
||||||
|
|
||||||
|
try { tmp << "INSERT INTO Ints VALUES (?,?,?)", bind(42), bind(42), now; }
|
||||||
|
catch (ParameterCountMismatchException&) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLiteTest::testMultipleResults()
|
||||||
|
{
|
||||||
|
Session tmp (SQLite::Connector::KEY, "dummy.db");
|
||||||
|
|
||||||
|
tmp << "DROP TABLE IF EXISTS Person", now;
|
||||||
|
tmp << "CREATE TABLE Person (LastName VARCHAR(30),"
|
||||||
|
"FirstName VARCHAR(30),"
|
||||||
|
"Address VARCHAR(30),"
|
||||||
|
"Age INTEGER)", now;
|
||||||
|
|
||||||
|
typedef Tuple<std::string, std::string, std::string, Poco::UInt32> Person;
|
||||||
|
std::vector<Person> people, people2;
|
||||||
|
people.push_back(Person("Simpson", "Homer", "Springfield", 42));
|
||||||
|
people.push_back(Person("Simpson", "Bart", "Springfield", 12));
|
||||||
|
people.push_back(Person("Simpson", "Lisa", "Springfield", 10));
|
||||||
|
|
||||||
|
Person pHomer;
|
||||||
|
int aHomer = 42, aLisa = 10;
|
||||||
|
Poco::UInt32 aBart = 0;
|
||||||
|
|
||||||
|
Poco::UInt32 pos1 = 1;
|
||||||
|
int pos2 = 2;
|
||||||
|
|
||||||
|
Statement stmt(tmp);
|
||||||
|
stmt << "INSERT INTO Person VALUES (?, ?, ?, ?);"
|
||||||
|
"SELECT * FROM Person WHERE Age = ?; "
|
||||||
|
"SELECT Age FROM Person WHERE FirstName = 'Bart'; "
|
||||||
|
"SELECT * FROM Person WHERE Age = ? OR Age = ? ORDER BY Age;"
|
||||||
|
, use(people)
|
||||||
|
, into(pHomer, from(0)), use(aHomer)
|
||||||
|
, into(aBart, pos1)
|
||||||
|
, into(people2, from(pos2)), use(aLisa), use(aHomer);
|
||||||
|
|
||||||
|
assert (7 == stmt.execute());
|
||||||
|
assert (Person("Simpson", "Homer", "Springfield", 42) == pHomer);
|
||||||
|
assert (12 == aBart);
|
||||||
|
assert (2 == people2.size());
|
||||||
|
assert (Person("Simpson", "Lisa", "Springfield", 10) == people2[0]);
|
||||||
|
assert (Person("Simpson", "Homer", "Springfield", 42) == people2[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2236,6 +2282,7 @@ CppUnit::Test* SQLiteTest::suite()
|
|||||||
CppUnit_addTest(pSuite, SQLiteTest, testSQLLogger);
|
CppUnit_addTest(pSuite, SQLiteTest, testSQLLogger);
|
||||||
CppUnit_addTest(pSuite, SQLiteTest, testExternalBindingAndExtraction);
|
CppUnit_addTest(pSuite, SQLiteTest, testExternalBindingAndExtraction);
|
||||||
CppUnit_addTest(pSuite, SQLiteTest, testBindingCount);
|
CppUnit_addTest(pSuite, SQLiteTest, testBindingCount);
|
||||||
|
CppUnit_addTest(pSuite, SQLiteTest, testMultipleResults);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ public:
|
|||||||
|
|
||||||
void testExternalBindingAndExtraction();
|
void testExternalBindingAndExtraction();
|
||||||
void testBindingCount();
|
void testBindingCount();
|
||||||
|
void testMultipleResults();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
|
|||||||
@@ -101,8 +101,13 @@ public:
|
|||||||
/// Extracts a value from the param, starting at the given column position.
|
/// Extracts a value from the param, starting at the given column position.
|
||||||
/// Returns the number of rows extracted.
|
/// Returns the number of rows extracted.
|
||||||
|
|
||||||
virtual void reset() = 0;
|
virtual void reset();
|
||||||
/// Resets the extractor so that it can be re-used.
|
/// Resets the extractor so that it can be re-used.
|
||||||
|
/// Does nothing in this implementation.
|
||||||
|
/// Implementations should override it for different behavior.
|
||||||
|
|
||||||
|
virtual bool canExtract() const;
|
||||||
|
/// Returns true. Implementations should override it for different behavior.
|
||||||
|
|
||||||
virtual AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos) = 0;
|
virtual AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos) = 0;
|
||||||
/// Creates a Prepare object for the extracting object
|
/// Creates a Prepare object for the extracting object
|
||||||
@@ -186,6 +191,17 @@ inline bool AbstractExtraction::isBulk() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void AbstractExtraction::reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool AbstractExtraction::canExtract() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Data
|
} } // namespace Poco::Data
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ class BulkExtraction: public AbstractExtraction
|
|||||||
public:
|
public:
|
||||||
typedef typename C::value_type T;
|
typedef typename C::value_type T;
|
||||||
|
|
||||||
BulkExtraction(C& result, Poco::UInt32 limit):
|
BulkExtraction(C& result, Poco::UInt32 limit, const Position& pos = Position(0)):
|
||||||
AbstractExtraction(limit, 0, true),
|
AbstractExtraction(limit, pos.value(), true),
|
||||||
_rResult(result),
|
_rResult(result),
|
||||||
_default()
|
_default()
|
||||||
{
|
{
|
||||||
@@ -70,8 +70,8 @@ public:
|
|||||||
result.resize(limit);
|
result.resize(limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
BulkExtraction(C& result, const T& def, Poco::UInt32 limit):
|
BulkExtraction(C& result, const T& def, Poco::UInt32 limit, const Position& pos = Position(0)):
|
||||||
AbstractExtraction(limit, 0, true),
|
AbstractExtraction(limit, pos.value(), true),
|
||||||
_rResult(result),
|
_rResult(result),
|
||||||
_default(def)
|
_default(def)
|
||||||
{
|
{
|
||||||
@@ -161,8 +161,11 @@ class InternalBulkExtraction: public BulkExtraction<C>
|
|||||||
public:
|
public:
|
||||||
typedef typename C::value_type T;
|
typedef typename C::value_type T;
|
||||||
|
|
||||||
explicit InternalBulkExtraction(C& result, Column<C>* pColumn, Poco::UInt32 limit):
|
explicit InternalBulkExtraction(C& result,
|
||||||
BulkExtraction<C>(result, T(), limit),
|
Column<C>* pColumn,
|
||||||
|
Poco::UInt32 limit,
|
||||||
|
const Position& pos = Position(0)):
|
||||||
|
BulkExtraction<C>(result, T(), limit, pos),
|
||||||
_pColumn(pColumn)
|
_pColumn(pColumn)
|
||||||
/// Creates InternalBulkExtraction.
|
/// Creates InternalBulkExtraction.
|
||||||
{
|
{
|
||||||
@@ -211,62 +214,62 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
BulkExtraction<std::vector<T> >* into(std::vector<T>& t, const Bulk& bulk)
|
BulkExtraction<std::vector<T> >* into(std::vector<T>& t, const Bulk& bulk, const Position& pos = Position(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
|
||||||
/// with std::vector bulk extraction support.
|
/// with std::vector bulk extraction support.
|
||||||
{
|
{
|
||||||
return new BulkExtraction<std::vector<T> >(t, bulk.size());
|
return new BulkExtraction<std::vector<T> >(t, bulk.size(), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
BulkExtraction<std::vector<T> >* into(std::vector<T>& t, BulkFnType)
|
BulkExtraction<std::vector<T> >* into(std::vector<T>& t, BulkFnType, const Position& pos = Position(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
|
||||||
/// with std::vector bulk extraction support.
|
/// with std::vector bulk extraction support.
|
||||||
{
|
{
|
||||||
Poco::UInt32 size = static_cast<Poco::UInt32>(t.size());
|
Poco::UInt32 size = static_cast<Poco::UInt32>(t.size());
|
||||||
if (0 == size) throw InvalidArgumentException("Zero length not allowed.");
|
if (0 == size) throw InvalidArgumentException("Zero length not allowed.");
|
||||||
return new BulkExtraction<std::vector<T> >(t, size);
|
return new BulkExtraction<std::vector<T> >(t, size, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
BulkExtraction<std::deque<T> >* into(std::deque<T>& t, const Bulk& bulk)
|
BulkExtraction<std::deque<T> >* into(std::deque<T>& t, const Bulk& bulk, const Position& pos = Position(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
|
||||||
/// with std::deque bulk extraction support.
|
/// with std::deque bulk extraction support.
|
||||||
{
|
{
|
||||||
return new BulkExtraction<std::deque<T> >(t, bulk.size());
|
return new BulkExtraction<std::deque<T> >(t, bulk.size(), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
BulkExtraction<std::deque<T> >* into(std::deque<T>& t, BulkFnType)
|
BulkExtraction<std::deque<T> >* into(std::deque<T>& t, BulkFnType, const Position& pos = Position(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
|
||||||
/// with std::deque bulk extraction support.
|
/// with std::deque bulk extraction support.
|
||||||
{
|
{
|
||||||
Poco::UInt32 size = static_cast<Poco::UInt32>(t.size());
|
Poco::UInt32 size = static_cast<Poco::UInt32>(t.size());
|
||||||
if (0 == size) throw InvalidArgumentException("Zero length not allowed.");
|
if (0 == size) throw InvalidArgumentException("Zero length not allowed.");
|
||||||
return new BulkExtraction<std::deque<T> >(t, size);
|
return new BulkExtraction<std::deque<T> >(t, size, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
BulkExtraction<std::list<T> >* into(std::list<T>& t, const Bulk& bulk)
|
BulkExtraction<std::list<T> >* into(std::list<T>& t, const Bulk& bulk, const Position& pos = Position(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
|
||||||
/// with std::list bulk extraction support.
|
/// with std::list bulk extraction support.
|
||||||
{
|
{
|
||||||
return new BulkExtraction<std::list<T> >(t, bulk.size());
|
return new BulkExtraction<std::list<T> >(t, bulk.size(), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
BulkExtraction<std::list<T> >* into(std::list<T>& t, BulkFnType)
|
BulkExtraction<std::list<T> >* into(std::list<T>& t, BulkFnType, const Position& pos = Position(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
|
||||||
/// with std::list bulk extraction support.
|
/// with std::list bulk extraction support.
|
||||||
{
|
{
|
||||||
Poco::UInt32 size = static_cast<Poco::UInt32>(t.size());
|
Poco::UInt32 size = static_cast<Poco::UInt32>(t.size());
|
||||||
if (0 == size) throw InvalidArgumentException("Zero length not allowed.");
|
if (0 == size) throw InvalidArgumentException("Zero length not allowed.");
|
||||||
return new BulkExtraction<std::list<T> >(t, size);
|
return new BulkExtraction<std::list<T> >(t, size, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
#include "Poco/Data/Data.h"
|
#include "Poco/Data/Data.h"
|
||||||
#include "Poco/Data/MetaColumn.h"
|
#include "Poco/Data/MetaColumn.h"
|
||||||
#include "Poco/SharedPtr.h"
|
#include "Poco/SharedPtr.h"
|
||||||
|
#include "Poco/RefCountedObject.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|||||||
@@ -124,6 +124,11 @@ public:
|
|||||||
_extracted = false;
|
_extracted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool canExtract() const
|
||||||
|
{
|
||||||
|
return !_extracted;
|
||||||
|
}
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<T>(pPrep, pos, _rResult);
|
return new Prepare<T>(pPrep, pos, _rResult);
|
||||||
@@ -198,10 +203,6 @@ public:
|
|||||||
return 1u;
|
return 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<T>(pPrep, pos, _default);
|
return new Prepare<T>(pPrep, pos, _default);
|
||||||
@@ -283,10 +284,6 @@ public:
|
|||||||
return 1u;
|
return 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<bool>(pPrep, pos, _default);
|
return new Prepare<bool>(pPrep, pos, _default);
|
||||||
@@ -366,10 +363,6 @@ public:
|
|||||||
return 1u;
|
return 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<T>(pPrep, pos, _default);
|
return new Prepare<T>(pPrep, pos, _default);
|
||||||
@@ -449,10 +442,6 @@ public:
|
|||||||
return 1u;
|
return 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<T>(pPrep, pos, _default);
|
return new Prepare<T>(pPrep, pos, _default);
|
||||||
@@ -586,10 +575,6 @@ public:
|
|||||||
return 1u;
|
return 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<T>(pPrep, pos, _default);
|
return new Prepare<T>(pPrep, pos, _default);
|
||||||
@@ -649,10 +634,6 @@ public:
|
|||||||
return 1u;
|
return 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<T>(pPrep, pos, _default);
|
return new Prepare<T>(pPrep, pos, _default);
|
||||||
@@ -712,16 +693,11 @@ public:
|
|||||||
return 1u;
|
return 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<V>(pPrep, pos, _default);
|
return new Prepare<V>(pPrep, pos, _default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<K, V>& _rResult;
|
std::map<K, V>& _rResult;
|
||||||
V _default;
|
V _default;
|
||||||
@@ -776,10 +752,6 @@ public:
|
|||||||
return 1u;
|
return 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos)
|
||||||
{
|
{
|
||||||
return new Prepare<V>(pPrep, pos, _default);
|
return new Prepare<V>(pPrep, pos, _default);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class Data_API Limit
|
|||||||
/// Limit stores information how many rows a query should return.
|
/// Limit stores information how many rows a query should return.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum
|
enum Type
|
||||||
{
|
{
|
||||||
LIMIT_UNLIMITED = 0xffffffffu
|
LIMIT_UNLIMITED = 0xffffffffu
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -75,6 +75,14 @@ class Data_API RecordSet: private Statement
|
|||||||
/// select.execute();
|
/// select.execute();
|
||||||
/// RecordSet rs(select);
|
/// RecordSet rs(select);
|
||||||
///
|
///
|
||||||
|
/// The shorter way to do the above is following:
|
||||||
|
///
|
||||||
|
/// RecordSet rs(session, "SELECT * FROM Person"[, new SimpleRowFormatter]);
|
||||||
|
///
|
||||||
|
/// The third (optional) argument passed to the Recordset constructor is a RowFormatter
|
||||||
|
/// implementation. The formatter is used in conjunction with << operator for recordset
|
||||||
|
/// data formating.
|
||||||
|
///
|
||||||
/// The number of rows in the RecordSet can be limited by specifying
|
/// The number of rows in the RecordSet can be limited by specifying
|
||||||
/// a limit for the Statement.
|
/// a limit for the Statement.
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -285,7 +285,6 @@ public:
|
|||||||
|
|
||||||
Statement& operator , (unsigned long value);
|
Statement& operator , (unsigned long value);
|
||||||
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
|
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Statement& operator , (Poco::UInt64 value);
|
Statement& operator , (Poco::UInt64 value);
|
||||||
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
|
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
|
||||||
@@ -372,7 +371,20 @@ public:
|
|||||||
|
|
||||||
std::size_t extractionCount() const;
|
std::size_t extractionCount() const;
|
||||||
/// Returns the number of extraction storage buffers associated
|
/// Returns the number of extraction storage buffers associated
|
||||||
/// with the statement.
|
/// with the current data set.
|
||||||
|
|
||||||
|
std::size_t dataSetCount() const;
|
||||||
|
/// Returns the number of data sets associated with the statement.
|
||||||
|
|
||||||
|
std::size_t nextDataSet();
|
||||||
|
/// Returns the index of the next data set.
|
||||||
|
|
||||||
|
std::size_t previousDataSet();
|
||||||
|
/// Returns the index of the previous data set.
|
||||||
|
|
||||||
|
bool hasMoreDataSets() const;
|
||||||
|
/// Returns false if the current data set index points to the last
|
||||||
|
/// data set. Otherwise, it returns true.
|
||||||
|
|
||||||
void setRowFormatter(RowFormatter* pRowFormatter);
|
void setRowFormatter(RowFormatter* pRowFormatter);
|
||||||
/// Sets the row formatter for this statement.
|
/// Sets the row formatter for this statement.
|
||||||
@@ -683,6 +695,30 @@ inline std::size_t Statement::extractionCount() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::size_t Statement::dataSetCount() const
|
||||||
|
{
|
||||||
|
return _pImpl->dataSetCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::size_t Statement::nextDataSet()
|
||||||
|
{
|
||||||
|
return _pImpl->activateNextDataSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::size_t Statement::previousDataSet()
|
||||||
|
{
|
||||||
|
return _pImpl->activatePreviousDataSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Statement::hasMoreDataSets() const
|
||||||
|
{
|
||||||
|
return _pImpl->hasMoreDataSets();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline Statement::Storage Statement::storage() const
|
inline Statement::Storage Statement::storage() const
|
||||||
{
|
{
|
||||||
return static_cast<Storage>(_pImpl->getStorage());
|
return static_cast<Storage>(_pImpl->getStorage());
|
||||||
|
|||||||
@@ -136,14 +136,16 @@ public:
|
|||||||
/// Registers objects used for extracting data with the StatementImpl.
|
/// Registers objects used for extracting data with the StatementImpl.
|
||||||
|
|
||||||
void setExtractionLimit(const Limit& extrLimit);
|
void setExtractionLimit(const Limit& extrLimit);
|
||||||
/// Changes the extractionLimit to extrLimit. Per default no limit (EXTRACT_UNLIMITED) is set.
|
/// Changes the extractionLimit to extrLimit.
|
||||||
|
/// Per default no limit (EXTRACT_UNLIMITED) is set.
|
||||||
|
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
/// Create a string version of the SQL statement.
|
/// Create a string version of the SQL statement.
|
||||||
|
|
||||||
Poco::UInt32 execute();
|
Poco::UInt32 execute();
|
||||||
/// Executes a statement. Returns the number of rows extracted for statements
|
/// Executes a statement. Returns the number of rows
|
||||||
/// returning data or number of rows affected for all other statements (insert, update, delete).
|
/// extracted for statements returning data or number of rows
|
||||||
|
/// affected for all other statements (insert, update, delete).
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
/// Resets the statement, so that we can reuse all bindings and re-execute again.
|
/// Resets the statement, so that we can reuse all bindings and re-execute again.
|
||||||
@@ -198,8 +200,16 @@ protected:
|
|||||||
virtual bool canBind() const = 0;
|
virtual bool canBind() const = 0;
|
||||||
/// Returns if another bind is possible.
|
/// Returns if another bind is possible.
|
||||||
|
|
||||||
virtual void compileImpl() = 0;
|
virtual bool compileImpl() = 0;
|
||||||
/// Compiles the statement, doesn't bind yet.
|
/// Compiles the statement, doesn't bind yet.
|
||||||
|
/// Returns true if compilation was succesful.
|
||||||
|
/// This function will be called at least twice, so
|
||||||
|
/// for connectors requiring one call only, this function
|
||||||
|
/// should always return false and internall protect itself
|
||||||
|
/// against multiple calls.
|
||||||
|
/// This design is to conform to the connectors (e.g. SQLite)
|
||||||
|
/// that handle batches of statements as a sequence of independent
|
||||||
|
/// statements, each with its own prepare/bind/execute operations.
|
||||||
|
|
||||||
virtual void bindImpl() = 0;
|
virtual void bindImpl() = 0;
|
||||||
/// Binds parameters.
|
/// Binds parameters.
|
||||||
@@ -240,11 +250,11 @@ protected:
|
|||||||
/// session is queried for container type setting. If the
|
/// session is queried for container type setting. If the
|
||||||
/// session container type setting is found, it is used.
|
/// session container type setting is found, it is used.
|
||||||
/// 3. If neither session nor statement have the internal
|
/// 3. If neither session nor statement have the internal
|
||||||
/// container type set, std::vector is used.
|
/// container type set, std::deque is used.
|
||||||
///
|
///
|
||||||
/// Supported internal extraction container types are:
|
/// Supported internal extraction container types are:
|
||||||
/// - std::vector (default)
|
/// - std::deque (default)
|
||||||
/// - std::deque
|
/// - std::vector
|
||||||
/// - std::list
|
/// - std::list
|
||||||
|
|
||||||
SessionImpl& session();
|
SessionImpl& session();
|
||||||
@@ -277,7 +287,15 @@ protected:
|
|||||||
/// Returns the current data set.
|
/// Returns the current data set.
|
||||||
|
|
||||||
Poco::UInt32 activateNextDataSet();
|
Poco::UInt32 activateNextDataSet();
|
||||||
/// Returns the next data set, or -1 if the last data set was reached.
|
/// Returns the next data set index, or throws NoDataException if the last
|
||||||
|
/// data set was reached.
|
||||||
|
|
||||||
|
Poco::UInt32 activatePreviousDataSet();
|
||||||
|
/// Returns the previous data set index, or throws NoDataException if the last
|
||||||
|
/// data set was reached.
|
||||||
|
|
||||||
|
bool hasMoreDataSets() const;
|
||||||
|
/// Returns true if there are data sets not activated yet.
|
||||||
|
|
||||||
Poco::UInt32 getExtractionLimit();
|
Poco::UInt32 getExtractionLimit();
|
||||||
/// Returns the extraction limit value.
|
/// Returns the extraction limit value.
|
||||||
@@ -286,17 +304,22 @@ protected:
|
|||||||
/// Returns the extraction limit.
|
/// Returns the extraction limit.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void compile();
|
bool compile();
|
||||||
/// Compiles the statement, if not yet compiled.
|
/// Compiles the statement, if not yet compiled.
|
||||||
|
/// Returns true if more compile calls are needed.
|
||||||
|
|
||||||
void bind();
|
void bind();
|
||||||
/// Binds the statement, if not yet bound.
|
/// Binds the statement, if not yet bound.
|
||||||
|
|
||||||
Poco::UInt32 executeWithLimit();
|
Poco::UInt32 executeWithLimit();
|
||||||
/// Executes with an upper limit set.
|
/// Executes with an upper limit set. Returns the number of rows
|
||||||
|
/// extracted for statements returning data or number of rows
|
||||||
|
/// affected for all other statements (insert, update, delete).
|
||||||
|
|
||||||
Poco::UInt32 executeWithoutLimit();
|
Poco::UInt32 executeWithoutLimit();
|
||||||
/// Executes without an upper limit set.
|
/// Executes without an upper limit set. Returns the number of rows
|
||||||
|
/// extracted for statements returning data or number of rows
|
||||||
|
/// affected for all other statements (insert, update, delete).
|
||||||
|
|
||||||
void resetExtraction();
|
void resetExtraction();
|
||||||
/// Resets extraction so it can be reused again.
|
/// Resets extraction so it can be reused again.
|
||||||
@@ -306,7 +329,7 @@ private:
|
|||||||
{
|
{
|
||||||
C* pData = new C;
|
C* pData = new C;
|
||||||
Column<C>* pCol = new Column<C>(mc, pData);
|
Column<C>* pCol = new Column<C>(mc, pData);
|
||||||
return new InternalExtraction<C>(*pData, pCol);
|
return new InternalExtraction<C>(*pData, pCol, currentDataSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class C>
|
template <class C>
|
||||||
@@ -314,7 +337,7 @@ private:
|
|||||||
{
|
{
|
||||||
C* pData = new C;
|
C* pData = new C;
|
||||||
Column<C>* pCol = new Column<C>(mc, pData);
|
Column<C>* pCol = new Column<C>(mc, pData);
|
||||||
return new InternalBulkExtraction<C>(*pData, pCol, getExtractionLimit());
|
return new InternalBulkExtraction<C>(*pData, pCol, getExtractionLimit(), currentDataSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@@ -413,7 +436,7 @@ private:
|
|||||||
State _state;
|
State _state;
|
||||||
Limit _extrLimit;
|
Limit _extrLimit;
|
||||||
Poco::UInt32 _lowerLimit;
|
Poco::UInt32 _lowerLimit;
|
||||||
int _columnsExtracted;
|
std::vector<int> _columnsExtracted;
|
||||||
SessionImpl& _rSession;
|
SessionImpl& _rSession;
|
||||||
Storage _storage;
|
Storage _storage;
|
||||||
std::ostringstream _ostr;
|
std::ostringstream _ostr;
|
||||||
@@ -471,7 +494,8 @@ inline AbstractExtractionVec& StatementImpl::extractions()
|
|||||||
|
|
||||||
inline int StatementImpl::columnsExtracted() const
|
inline int StatementImpl::columnsExtracted() const
|
||||||
{
|
{
|
||||||
return _columnsExtracted;
|
poco_assert (_curDataSet < _columnsExtracted.size());
|
||||||
|
return _columnsExtracted[_curDataSet];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -600,6 +624,12 @@ inline bool StatementImpl::isBulkSupported() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool StatementImpl::hasMoreDataSets() const
|
||||||
|
{
|
||||||
|
return currentDataSet() + 1 < dataSetCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Data
|
} } // namespace Poco::Data
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ void SQLChannel::logAsync(const Message& msg)
|
|||||||
|
|
||||||
void SQLChannel::logSync(const Message& msg)
|
void SQLChannel::logSync(const Message& msg)
|
||||||
{
|
{
|
||||||
//if (isArchiving()) archive();
|
|
||||||
if (_pArchiveStrategy) _pArchiveStrategy->archive();
|
if (_pArchiveStrategy) _pArchiveStrategy->archive();
|
||||||
|
|
||||||
_source = msg.getSource();
|
_source = msg.getSource();
|
||||||
@@ -289,7 +288,8 @@ void SQLChannel::initLogStatement()
|
|||||||
|
|
||||||
void SQLChannel::registerChannel()
|
void SQLChannel::registerChannel()
|
||||||
{
|
{
|
||||||
Poco::LoggingFactory::defaultFactory().registerChannelClass("SQLChannel", new Poco::Instantiator<SQLChannel, Poco::Channel>);
|
Poco::LoggingFactory::defaultFactory().registerChannelClass("SQLChannel",
|
||||||
|
new Poco::Instantiator<SQLChannel, Poco::Channel>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -63,16 +63,15 @@ StatementImpl::StatementImpl(SessionImpl& rSession):
|
|||||||
_state(ST_INITIALIZED),
|
_state(ST_INITIALIZED),
|
||||||
_extrLimit(upperLimit((Poco::UInt32) Limit::LIMIT_UNLIMITED, false)),
|
_extrLimit(upperLimit((Poco::UInt32) Limit::LIMIT_UNLIMITED, false)),
|
||||||
_lowerLimit(0),
|
_lowerLimit(0),
|
||||||
_columnsExtracted(0),
|
|
||||||
_rSession(rSession),
|
_rSession(rSession),
|
||||||
_storage(STORAGE_UNKNOWN_IMPL),
|
_storage(STORAGE_UNKNOWN_IMPL),
|
||||||
_ostr(),
|
_ostr(),
|
||||||
_bindings(),
|
|
||||||
_curDataSet(0),
|
_curDataSet(0),
|
||||||
_bulkBinding(BULK_UNDEFINED),
|
_bulkBinding(BULK_UNDEFINED),
|
||||||
_bulkExtraction(BULK_UNDEFINED)
|
_bulkExtraction(BULK_UNDEFINED)
|
||||||
{
|
{
|
||||||
_extractors.resize(1);
|
_extractors.resize(1);
|
||||||
|
_columnsExtracted.resize(1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -88,16 +87,21 @@ Poco::UInt32 StatementImpl::execute()
|
|||||||
if (_lowerLimit > _extrLimit.value())
|
if (_lowerLimit > _extrLimit.value())
|
||||||
throw LimitException("Illegal Statement state. Upper limit must not be smaller than the lower limit.");
|
throw LimitException("Illegal Statement state. Upper limit must not be smaller than the lower limit.");
|
||||||
|
|
||||||
|
compile();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (_extrLimit.value() == Limit::LIMIT_UNLIMITED)
|
||||||
|
lim += executeWithoutLimit();
|
||||||
|
else
|
||||||
|
lim += executeWithLimit();
|
||||||
|
} while (compile());
|
||||||
|
|
||||||
if (_extrLimit.value() == Limit::LIMIT_UNLIMITED)
|
if (_extrLimit.value() == Limit::LIMIT_UNLIMITED)
|
||||||
lim = executeWithoutLimit();
|
_state = ST_DONE;
|
||||||
else
|
|
||||||
lim = executeWithLimit();
|
|
||||||
|
|
||||||
if (lim < _lowerLimit)
|
if (lim < _lowerLimit)
|
||||||
throw LimitException("Did not receive enough data.");
|
throw LimitException("Did not receive enough data.");
|
||||||
|
|
||||||
if (0 == lim) lim = affectedRowCount();
|
|
||||||
|
|
||||||
return lim;
|
return lim;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,48 +109,51 @@ Poco::UInt32 StatementImpl::execute()
|
|||||||
Poco::UInt32 StatementImpl::executeWithLimit()
|
Poco::UInt32 StatementImpl::executeWithLimit()
|
||||||
{
|
{
|
||||||
poco_assert (_state != ST_DONE);
|
poco_assert (_state != ST_DONE);
|
||||||
compile();
|
|
||||||
Poco::UInt32 count = 0;
|
Poco::UInt32 count = 0;
|
||||||
Poco::UInt32 limit = _extrLimit.value();
|
Poco::UInt32 limit = _extrLimit.value();
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
bind();
|
bind();
|
||||||
while (count < limit && hasNext())
|
while (count < limit && hasNext())
|
||||||
count += next();
|
count += next();
|
||||||
} while (count < limit && canBind());
|
} while (count < limit && canBind());
|
||||||
|
|
||||||
if (!canBind() && (!hasNext() || limit == 0))
|
if (!canBind() && (!hasNext() || limit == 0))
|
||||||
_state = ST_DONE;
|
_state = ST_DONE;
|
||||||
else if (hasNext() && limit == count && _extrLimit.isHardLimit())
|
else if (hasNext() && limit == count && _extrLimit.isHardLimit())
|
||||||
throw LimitException("HardLimit reached. We got more data than we asked for");
|
throw LimitException("HardLimit reached (retrieved more data than requested).");
|
||||||
else
|
else
|
||||||
_state = ST_PAUSED;
|
_state = ST_PAUSED;
|
||||||
|
|
||||||
return count;
|
return count ? count : affectedRowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Poco::UInt32 StatementImpl::executeWithoutLimit()
|
Poco::UInt32 StatementImpl::executeWithoutLimit()
|
||||||
{
|
{
|
||||||
poco_assert (_state != ST_DONE);
|
poco_assert (_state != ST_DONE);
|
||||||
compile();
|
|
||||||
Poco::UInt32 count = 0;
|
Poco::UInt32 count = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
bind();
|
bind();
|
||||||
while (hasNext()) count += next();
|
while (hasNext()) count += next();
|
||||||
} while (canBind());
|
} while (canBind());
|
||||||
|
|
||||||
_state = ST_DONE;
|
return count ? count : affectedRowCount();
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StatementImpl::compile()
|
bool StatementImpl::compile()
|
||||||
{
|
{
|
||||||
if (_state == ST_INITIALIZED)
|
bool retval = false;
|
||||||
|
|
||||||
|
if (_state == ST_INITIALIZED ||
|
||||||
|
_state == ST_RESET ||
|
||||||
|
_state == ST_BOUND)
|
||||||
{
|
{
|
||||||
compileImpl();
|
retval = compileImpl();
|
||||||
_state = ST_COMPILED;
|
_state = ST_COMPILED;
|
||||||
|
|
||||||
if (!extractions().size() && !isStoredProcedure())
|
if (!extractions().size() && !isStoredProcedure())
|
||||||
@@ -158,12 +165,8 @@ void StatementImpl::compile()
|
|||||||
fixupExtraction();
|
fixupExtraction();
|
||||||
fixupBinding();
|
fixupBinding();
|
||||||
}
|
}
|
||||||
else if (_state == ST_RESET)
|
|
||||||
{
|
return retval;
|
||||||
resetBinding();
|
|
||||||
resetExtraction();
|
|
||||||
_state = ST_COMPILED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -187,8 +190,9 @@ void StatementImpl::bind()
|
|||||||
|
|
||||||
void StatementImpl::reset()
|
void StatementImpl::reset()
|
||||||
{
|
{
|
||||||
|
resetBinding();
|
||||||
|
resetExtraction();
|
||||||
_state = ST_RESET;
|
_state = ST_RESET;
|
||||||
compile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -217,12 +221,15 @@ void StatementImpl::fixupExtraction()
|
|||||||
Poco::Data::AbstractExtractionVec::iterator it = extractions().begin();
|
Poco::Data::AbstractExtractionVec::iterator it = extractions().begin();
|
||||||
Poco::Data::AbstractExtractionVec::iterator itEnd = extractions().end();
|
Poco::Data::AbstractExtractionVec::iterator itEnd = extractions().end();
|
||||||
AbstractExtractor& ex = extractor();
|
AbstractExtractor& ex = extractor();
|
||||||
_columnsExtracted = 0;
|
|
||||||
|
if (_curDataSet >= _columnsExtracted.size())
|
||||||
|
_columnsExtracted.resize(_curDataSet + 1, 0);
|
||||||
|
|
||||||
for (; it != itEnd; ++it)
|
for (; it != itEnd; ++it)
|
||||||
{
|
{
|
||||||
(*it)->setExtractor(&ex);
|
(*it)->setExtractor(&ex);
|
||||||
(*it)->setLimit(_extrLimit.value()),
|
(*it)->setLimit(_extrLimit.value()),
|
||||||
_columnsExtracted += (int)(*it)->numOfColumnsHandled();
|
_columnsExtracted[_curDataSet] += (int)(*it)->numOfColumnsHandled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,16 +241,8 @@ void StatementImpl::fixupBinding()
|
|||||||
AbstractBindingVec::iterator itEnd = bindings().end();
|
AbstractBindingVec::iterator itEnd = bindings().end();
|
||||||
AbstractBinder& bin = binder();
|
AbstractBinder& bin = binder();
|
||||||
std::size_t numRows = 0;
|
std::size_t numRows = 0;
|
||||||
if (it != itEnd)
|
if (it != itEnd) numRows = (*it)->numOfRowsHandled();
|
||||||
numRows = (*it)->numOfRowsHandled();
|
for (; it != itEnd; ++it) (*it)->setBinder(&bin);
|
||||||
for (; it != itEnd; ++it)
|
|
||||||
{
|
|
||||||
if (numRows != (*it)->numOfRowsHandled())
|
|
||||||
{
|
|
||||||
throw BindingException("Size mismatch in Bindings. All Bindings MUST have the same size");
|
|
||||||
}
|
|
||||||
(*it)->setBinder(&bin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -251,10 +250,7 @@ void StatementImpl::resetBinding()
|
|||||||
{
|
{
|
||||||
AbstractBindingVec::iterator it = bindings().begin();
|
AbstractBindingVec::iterator it = bindings().begin();
|
||||||
AbstractBindingVec::iterator itEnd = bindings().end();
|
AbstractBindingVec::iterator itEnd = bindings().end();
|
||||||
for (; it != itEnd; ++it)
|
for (; it != itEnd; ++it) (*it)->reset();
|
||||||
{
|
|
||||||
(*it)->reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -262,10 +258,10 @@ void StatementImpl::resetExtraction()
|
|||||||
{
|
{
|
||||||
Poco::Data::AbstractExtractionVec::iterator it = extractions().begin();
|
Poco::Data::AbstractExtractionVec::iterator it = extractions().begin();
|
||||||
Poco::Data::AbstractExtractionVec::iterator itEnd = extractions().end();
|
Poco::Data::AbstractExtractionVec::iterator itEnd = extractions().end();
|
||||||
for (; it != itEnd; ++it)
|
for (; it != itEnd; ++it) (*it)->reset();
|
||||||
{
|
|
||||||
(*it)->reset();
|
poco_assert (_curDataSet < _columnsExtracted.size());
|
||||||
}
|
_columnsExtracted[_curDataSet] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -352,6 +348,15 @@ Poco::UInt32 StatementImpl::activateNextDataSet()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt32 StatementImpl::activatePreviousDataSet()
|
||||||
|
{
|
||||||
|
if (_curDataSet > 0)
|
||||||
|
return --_curDataSet;
|
||||||
|
else
|
||||||
|
throw NoDataException("Beginning of data sets reached.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void StatementImpl::addExtract(AbstractExtraction* pExtraction)
|
void StatementImpl::addExtract(AbstractExtraction* pExtraction)
|
||||||
{
|
{
|
||||||
poco_check_ptr (pExtraction);
|
poco_check_ptr (pExtraction);
|
||||||
|
|||||||
@@ -50,12 +50,13 @@ TestStatementImpl::~TestStatementImpl()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TestStatementImpl::compileImpl()
|
bool TestStatementImpl::compileImpl()
|
||||||
{
|
{
|
||||||
// prepare binding
|
// prepare binding
|
||||||
_ptrBinder = new Binder;
|
_ptrBinder = new Binder;
|
||||||
_ptrExtractor = new Extractor;
|
_ptrExtractor = new Extractor;
|
||||||
_ptrPrepare = new Preparation;
|
_ptrPrepare = new Preparation;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ protected:
|
|||||||
bool canBind() const;
|
bool canBind() const;
|
||||||
/// Returns true if a valid statement is set and we can bind.
|
/// Returns true if a valid statement is set and we can bind.
|
||||||
|
|
||||||
void compileImpl();
|
bool compileImpl();
|
||||||
/// Compiles the statement, doesn't bind yet
|
/// Compiles the statement, doesn't bind yet
|
||||||
|
|
||||||
void bindImpl();
|
void bindImpl();
|
||||||
|
|||||||
Reference in New Issue
Block a user