improved support for multiple statement execution and recordset paging

This commit is contained in:
Aleksandar Fabijanic
2009-08-11 14:34:21 +00:00
parent c6ee567a71
commit 49101951a2
12 changed files with 267 additions and 61 deletions

View File

@@ -50,6 +50,7 @@
#include "Poco/Dynamic/Var.h" #include "Poco/Dynamic/Var.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include <ostream> #include <ostream>
#include <limits>
namespace Poco { namespace Poco {
@@ -93,8 +94,12 @@ public:
using Statement::isNull; using Statement::isNull;
using Statement::setRowFormatter; using Statement::setRowFormatter;
using Statement::subTotalRowCount;
explicit RecordSet(const Statement& rStatement); static const std::size_t UNKNOWN_TOTAL_ROW_COUNT;
explicit RecordSet(const Statement& rStatement,
RowFormatter* pRowFormatter = 0);
/// Creates the RecordSet. /// Creates the RecordSet.
explicit RecordSet(Session& rSession, explicit RecordSet(Session& rSession,
@@ -119,9 +124,31 @@ public:
/// for large recordsets, so it should be used judiciously. /// for large recordsets, so it should be used judiciously.
/// Use totalRowCount() to obtain the total number of rows. /// Use totalRowCount() to obtain the total number of rows.
std::size_t extractedRowCount() const;
/// Returns the number of rows extracted during the last statement
/// execution.
/// The number of rows reported is independent of filtering.
std::size_t totalRowCount() const; std::size_t totalRowCount() const;
//@ deprecated
/// Replaced with subTotalRowCount() and getTotalRowCount().
std::size_t getTotalRowCount() const;
/// Returns the total number of rows in the RecordSet. /// Returns the total number of rows in the RecordSet.
/// The number of rows reported is independent of filtering. /// The number of rows reported is independent of filtering.
/// If the total row count has not been set externally
/// (either explicitly or implicitly through SQL), the value
/// returned shall only be accurate if the statement limit
/// is less or equal to the total row count.
void setTotalRowCount(std::size_t totalRowCount);
/// Explicitly sets the total row count.
void setTotalRowCount(const std::string& sql);
/// Implicitly sets the total row count.
/// The supplied sql must return exactly one column
/// and one row. The returned value must be an unsigned
/// integer. The value is set as the total number of rows.
std::size_t columnCount() const; std::size_t columnCount() const;
/// Returns the number of columns in the recordset. /// Returns the number of columns in the recordset.
@@ -340,7 +367,9 @@ public:
/// cause RangeException to be thrown. /// cause RangeException to be thrown.
/// Copied string is formatted by the current RowFormatter. /// Copied string is formatted by the current RowFormatter.
std::ostream& copy(std::ostream& os) const; std::ostream& copy(std::ostream& os,
std::size_t offset = 0,
std::size_t length = RowIterator::POSITION_END) const;
/// Copies the column names and values to the target output stream. /// Copies the column names and values to the target output stream.
/// Copied strings are formatted by the current RowFormatter. /// Copied strings are formatted by the current RowFormatter.
@@ -432,6 +461,7 @@ private:
RowIterator* _pEnd; RowIterator* _pEnd;
RowMap _rowMap; RowMap _rowMap;
RowFilter* _pFilter; RowFilter* _pFilter;
std::size_t _totalRowCount;
friend class RowIterator; friend class RowIterator;
friend class RowFilter; friend class RowFilter;
@@ -448,7 +478,28 @@ inline Data_API std::ostream& operator << (std::ostream &os, const RecordSet& rs
} }
inline std::size_t RecordSet::getTotalRowCount() const
{
if (UNKNOWN_TOTAL_ROW_COUNT == _totalRowCount)
return subTotalRowCount();
else
return _totalRowCount;
}
inline std::size_t RecordSet::totalRowCount() const inline std::size_t RecordSet::totalRowCount() const
{
return getTotalRowCount();
}
inline void RecordSet::setTotalRowCount(std::size_t totalRowCount)
{
_totalRowCount = totalRowCount;
}
inline std::size_t RecordSet::extractedRowCount() const
{ {
return rowsExtracted(); return rowsExtracted();
} }

View File

@@ -153,7 +153,7 @@ public:
bool isEmpty() const; bool isEmpty() const;
/// Returns true if there is not filtering criteria specified. /// Returns true if there is not filtering criteria specified.
bool isAllowed(std::size_t row) const;//const std::string& name, const Poco::Dynamic::Var& val) const; bool isAllowed(std::size_t row) const;
/// Returns true if name and value are allowed. /// Returns true if name and value are allowed.
bool exists(const std::string& name) const; bool exists(const std::string& name) const;

View File

@@ -75,7 +75,9 @@ class Data_API RowFormatter
public: public:
typedef std::vector<std::string> NameVec; typedef std::vector<std::string> NameVec;
typedef SharedPtr<std::vector<std::string> > NameVecPtr; typedef SharedPtr<std::vector<std::string> > NameVecPtr;
typedef std::vector<Poco::Dynamic::Var> ValueVec; typedef std::vector<Poco::Dynamic::Var> ValueVec;
static const int INVALID_ROW_COUNT = -1;
RowFormatter(const std::string& prefix = "", const std::string& postfix = ""); RowFormatter(const std::string& prefix = "", const std::string& postfix = "");
/// Creates the RowFormatter and sets the prefix and postfix to specified values. /// Creates the RowFormatter and sets the prefix and postfix to specified values.
@@ -89,34 +91,72 @@ public:
virtual std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const = 0; virtual std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const = 0;
/// Formats the row values. /// Formats the row values.
virtual int rowCount() const;
/// Returns INVALID_ROW_COUNT. Must be implemented by inheriting classes
/// which maintain count of processed rows.
int getTotalRowCount() const;
/// Returns zero. Must be implemented by inheriting classes.
/// Typically, total row count shall be set up front through
/// setTotalRowCount() call.
void setTotalRowCount(int count);
/// Sets total row count.
const std::string& prefix() const; const std::string& prefix() const;
/// Returns prefix string; /// Returns prefix string;
const std::string& postfix() const; const std::string& postfix() const;
/// Returns postfix string; /// Returns postfix string;
void reset();
/// Resets the formatter by setting prefix and postfix
/// to empty strings and row count to INVALID_ROW_COUNT.
protected: protected:
void setPrefix(const std::string& prefix);
void setPostfix(const std::string& postfix); void setPrefix(const std::string& prefix) const;
/// Sets the p[refix for the formatter.
void setPostfix(const std::string& postfix) const;
/// Sets the postfix for the formatter
private: private:
std::string _prefix;
std::string _postfix; mutable std::string _prefix;
mutable std::string _postfix;
int _totalRowCount;
}; };
/// ///
/// inlines /// inlines
/// ///
inline int RowFormatter::rowCount() const
{
return INVALID_ROW_COUNT;
}
inline void RowFormatter::setPrefix(const std::string& prefix) inline int RowFormatter::getTotalRowCount() const
{
return _totalRowCount;
}
inline void RowFormatter::setTotalRowCount(int count)
{
_totalRowCount = count;
}
inline void RowFormatter::setPrefix(const std::string& prefix) const
{ {
_prefix = prefix; _prefix = prefix;
} }
inline void RowFormatter::setPostfix(const std::string& postfix) inline void RowFormatter::setPostfix(const std::string& postfix) const
{ {
_postfix = postfix; _postfix = postfix;
} }

View File

@@ -79,6 +79,9 @@ public:
std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const; std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const;
/// Formats the row values. /// Formats the row values.
int rowCount() const;
/// Returns row count.
void setColumnWidth(std::streamsize width); void setColumnWidth(std::streamsize width);
/// Sets the column width. /// Sets the column width.
@@ -87,12 +90,17 @@ public:
private: private:
std::streamsize _colWidth; std::streamsize _colWidth;
mutable int _rowCount;
}; };
/// ///
/// inlines /// inlines
/// ///
inline int SimpleRowFormatter::rowCount() const
{
return _rowCount;
}
inline void SimpleRowFormatter::setColumnWidth(std::streamsize columnWidth) inline void SimpleRowFormatter::setColumnWidth(std::streamsize columnWidth)

View File

@@ -95,9 +95,9 @@ public:
typedef void (*Manipulator)(Statement&); typedef void (*Manipulator)(Statement&);
typedef ActiveResult<std::size_t> Result; typedef ActiveResult<std::size_t> Result;
typedef SharedPtr<Result> ResultPtr; typedef SharedPtr<Result> ResultPtr;
typedef ActiveMethod<std::size_t, void, StatementImpl> AsyncExecMethod; typedef ActiveMethod<std::size_t, bool, StatementImpl> AsyncExecMethod;
typedef SharedPtr<AsyncExecMethod> AsyncExecMethodPtr; typedef SharedPtr<AsyncExecMethod> AsyncExecMethodPtr;
static const int WAIT_FOREVER = -1; static const int WAIT_FOREVER = -1;
@@ -309,17 +309,20 @@ public:
const std::string& toString() const; const std::string& toString() const;
/// Creates a string from the accumulated SQL statement. /// Creates a string from the accumulated SQL statement.
std::size_t execute(); std::size_t execute(bool reset = true);
/// Executes the statement synchronously or asynchronously. /// Executes the statement synchronously or asynchronously.
/// Stops when either a limit is hit or the whole statement was executed. /// Stops when either a limit is hit or the whole statement was executed.
/// Returns the number of rows extracted from the database (for statements /// Returns the number of rows extracted from the database (for statements
/// returning data) or number of rows affected (for all other statements). /// returning data) or number of rows affected (for all other statements).
/// If reset is true (default), associated storage is reset and reused.
/// Otherwise, the results from this execution step are appended.
/// Reset argument has no meaning for unlimited statements that return all rows.
/// If isAsync() returns true, the statement is executed asynchronously /// If isAsync() returns true, the statement is executed asynchronously
/// and the return value from this function is zero. /// and the return value from this function is zero.
/// The result of execution (i.e. number of returned or affected rows) can be /// The result of execution (i.e. number of returned or affected rows) can be
/// obtained by calling wait() on the statement at a later point in time. /// obtained by calling wait() on the statement at a later point in time.
const Result& executeAsync(); const Result& executeAsync(bool reset = true);
/// Executes the statement asynchronously. /// Executes the statement asynchronously.
/// Stops when either a limit is hit or the whole statement was executed. /// Stops when either a limit is hit or the whole statement was executed.
/// Returns immediately. Calling wait() (on either the result returned from this /// Returns immediately. Calling wait() (on either the result returned from this
@@ -373,7 +376,11 @@ public:
/// Default value indicates current data set (if any). /// Default value indicates current data set (if any).
std::size_t rowsExtracted(int dataSet = StatementImpl::USE_CURRENT_DATA_SET) const; std::size_t rowsExtracted(int dataSet = StatementImpl::USE_CURRENT_DATA_SET) const;
/// Returns the number of rows returned for current data set. /// Returns the number of rows returned for current data set during last statement
/// execution. Default value indicates current data set (if any).
std::size_t subTotalRowCount(int dataSet = StatementImpl::USE_CURRENT_DATA_SET) const;
/// Returns the number of rows extracted so far for the data set.
/// Default value indicates current data set (if any). /// Default value indicates current data set (if any).
std::size_t extractionCount() const; std::size_t extractionCount() const;
@@ -421,8 +428,11 @@ protected:
const RowFormatterPtr& getRowFormatter(); const RowFormatterPtr& getRowFormatter();
/// Returns the row formatter for this statement. /// Returns the row formatter for this statement.
Session session();
/// Returns the underlying session.
private: private:
const Result& doAsyncExec(); const Result& doAsyncExec(bool reset = true);
/// Asynchronously executes the statement. /// Asynchronously executes the statement.
template <typename T> template <typename T>
@@ -444,6 +454,14 @@ private:
mutable std::string _stmtString; mutable std::string _stmtString;
}; };
//
// inlines
inline std::size_t Statement::subTotalRowCount(int dataSet) const
{
return _pImpl->subTotalRowCount(dataSet);
}
namespace Keywords { namespace Keywords {

View File

@@ -144,10 +144,15 @@ public:
std::string toString() const; std::string toString() const;
/// Create a string version of the SQL statement. /// Create a string version of the SQL statement.
std::size_t execute(); std::size_t execute(const bool& reset = true);
/// Executes a statement. Returns the number of rows /// Executes a statement. Returns the number of rows
/// extracted for statements returning data or number of rows /// extracted for statements returning data or number of rows
/// affected for all other statements (insert, update, delete). /// affected for all other statements (insert, update, delete).
/// If reset is true (default), the underlying bound storage is
/// reset and reused. In case of containers, this means they are
/// cleared and resized to accomodate the number of rows returned by
/// this execution step. When reset is false, data is appended to the
/// bound containers during multiple execute calls.
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.
@@ -227,6 +232,10 @@ protected:
/// Returns the number of rows extracted for current data set. /// Returns the number of rows extracted for current data set.
/// Default value (USE_CURRENT_DATA_SET) indicates current data set (if any). /// Default value (USE_CURRENT_DATA_SET) indicates current data set (if any).
std::size_t subTotalRowCount(int dataSet = USE_CURRENT_DATA_SET) const;
/// Returns the number of rows extracted so far for the data set.
/// Default value indicates current data set (if any).
const AbstractBindingVec& bindings() const; const AbstractBindingVec& bindings() const;
/// Returns the bindings. /// Returns the bindings.
@@ -430,9 +439,13 @@ private:
void formatSQL(std::vector<Any>& arguments); void formatSQL(std::vector<Any>& arguments);
/// Formats the SQL string by filling in placeholders with values from supplied vector. /// Formats the SQL string by filling in placeholders with values from supplied vector.
void assignSubTotal(bool reset);
StatementImpl(const StatementImpl& stmt); StatementImpl(const StatementImpl& stmt);
StatementImpl& operator = (const StatementImpl& stmt); StatementImpl& operator = (const StatementImpl& stmt);
typedef std::vector<std::size_t> CountVec;
State _state; State _state;
Limit _extrLimit; Limit _extrLimit;
std::size_t _lowerLimit; std::size_t _lowerLimit;
@@ -445,6 +458,7 @@ private:
std::size_t _curDataSet; std::size_t _curDataSet;
BulkType _bulkBinding; BulkType _bulkBinding;
BulkType _bulkExtraction; BulkType _bulkExtraction;
CountVec _subTotalRowCount;
friend class Statement; friend class Statement;
}; };
@@ -453,6 +467,8 @@ private:
// //
// inlines // inlines
// //
inline void StatementImpl::addBind(AbstractBinding* pBinding) inline void StatementImpl::addBind(AbstractBinding* pBinding)
{ {
poco_check_ptr (pBinding); poco_check_ptr (pBinding);

View File

@@ -51,13 +51,19 @@ namespace Poco {
namespace Data { namespace Data {
RecordSet::RecordSet(const Statement& rStatement): const std::size_t RecordSet::UNKNOWN_TOTAL_ROW_COUNT = std::numeric_limits<std::size_t>::max();
RecordSet::RecordSet(const Statement& rStatement,
RowFormatter* pRowFormatter):
Statement(rStatement), Statement(rStatement),
_currentRow(0), _currentRow(0),
_pBegin(new RowIterator(this, 0 == rowsExtracted())), _pBegin(new RowIterator(this, 0 == rowsExtracted())),
_pEnd(new RowIterator(this, true)), _pEnd(new RowIterator(this, true)),
_pFilter(0) _pFilter(0),
_totalRowCount(UNKNOWN_TOTAL_ROW_COUNT)
{ {
if (pRowFormatter) setRowFormatter(pRowFormatter);
} }
@@ -68,7 +74,8 @@ RecordSet::RecordSet(Session& rSession,
_currentRow(0), _currentRow(0),
_pBegin(new RowIterator(this, 0 == rowsExtracted())), _pBegin(new RowIterator(this, 0 == rowsExtracted())),
_pEnd(new RowIterator(this, true)), _pEnd(new RowIterator(this, true)),
_pFilter(0) _pFilter(0),
_totalRowCount(UNKNOWN_TOTAL_ROW_COUNT)
{ {
if (pRowFormatter) setRowFormatter(pRowFormatter); if (pRowFormatter) setRowFormatter(pRowFormatter);
} }
@@ -79,7 +86,8 @@ RecordSet::RecordSet(const RecordSet& other):
_currentRow(other._currentRow), _currentRow(other._currentRow),
_pBegin(new RowIterator(this, 0 == rowsExtracted())), _pBegin(new RowIterator(this, 0 == rowsExtracted())),
_pEnd(new RowIterator(this, true)), _pEnd(new RowIterator(this, true)),
_pFilter(other._pFilter) _pFilter(other._pFilter),
_totalRowCount(other._totalRowCount)
{ {
} }
@@ -203,7 +211,7 @@ Row& RecordSet::row(std::size_t pos)
std::size_t RecordSet::rowCount() const std::size_t RecordSet::rowCount() const
{ {
poco_assert (extractions().size()); poco_assert (extractions().size());
std::size_t rc = totalRowCount(); std::size_t rc = subTotalRowCount();
if (!isFiltered()) return rc; if (!isFiltered()) return rc;
std::size_t counter = 0; std::size_t counter = 0;
@@ -225,7 +233,7 @@ bool RecordSet::isAllowed(std::size_t row) const
bool RecordSet::moveFirst() bool RecordSet::moveFirst()
{ {
if (totalRowCount() > 0) if (subTotalRowCount() > 0)
{ {
if (!isFiltered()) if (!isFiltered())
{ {
@@ -237,7 +245,7 @@ bool RecordSet::moveFirst()
currentRow = 0; currentRow = 0;
while (!isAllowed(currentRow)) while (!isAllowed(currentRow))
{ {
if (currentRow >= totalRowCount() - 1) return false; if (currentRow >= subTotalRowCount() - 1) return false;
++currentRow; ++currentRow;
} }
@@ -253,7 +261,7 @@ bool RecordSet::moveNext()
std::size_t currentRow = _currentRow; std::size_t currentRow = _currentRow;
do do
{ {
if (currentRow >= totalRowCount() - 1) return false; if (currentRow >= subTotalRowCount() - 1) return false;
++currentRow; ++currentRow;
} while (isFiltered() && !isAllowed(currentRow)); } while (isFiltered() && !isAllowed(currentRow));
@@ -278,10 +286,10 @@ bool RecordSet::movePrevious()
bool RecordSet::moveLast() bool RecordSet::moveLast()
{ {
if (totalRowCount() > 0) if (subTotalRowCount() > 0)
{ {
std::size_t currentRow = _currentRow; std::size_t currentRow = _currentRow;
currentRow = totalRowCount() - 1; currentRow = subTotalRowCount() - 1;
if (!isFiltered()) if (!isFiltered())
{ {
_currentRow = currentRow; _currentRow = currentRow;
@@ -303,26 +311,21 @@ bool RecordSet::moveLast()
std::ostream& RecordSet::copyValues(std::ostream& os, std::size_t offset, std::size_t length) const std::ostream& RecordSet::copyValues(std::ostream& os, std::size_t offset, std::size_t length) const
{ {
if (length == RowIterator::POSITION_END)
{
if (0 != offset) throw RangeException("Invalid range.");
length = rowCount();
}
RowIterator itBegin = *_pBegin + offset; RowIterator itBegin = *_pBegin + offset;
RowIterator itEnd = itBegin + length; RowIterator itEnd = (RowIterator::POSITION_END != length) ? itBegin + length : *_pEnd;
std::copy(itBegin, itEnd, std::ostream_iterator<Row>(os)); std::copy(itBegin, itEnd, std::ostream_iterator<Row>(os));
return os; return os;
} }
std::ostream& RecordSet::copy(std::ostream& os) const std::ostream& RecordSet::copy(std::ostream& os, std::size_t offset, std::size_t length) const
{ {
const RowFormatter& ri = (*_pBegin)->getFormatter(); RowFormatter& rf = const_cast<RowFormatter&>((*_pBegin)->getFormatter());
os << ri.prefix(); rf.setTotalRowCount(getTotalRowCount());
os << rf.prefix();
copyNames(os); copyNames(os);
copyValues(os); copyValues(os, offset, length);
os << ri.postfix(); os << rf.postfix();
return os; return os;
} }
@@ -341,4 +344,10 @@ bool RecordSet::isFiltered() const
} }
void RecordSet::setTotalRowCount(const std::string& sql)
{
session() << sql, into(_totalRowCount), now;
}
} } // namespace Poco::Data } } // namespace Poco::Data

View File

@@ -45,7 +45,8 @@ namespace Data {
RowFormatter::RowFormatter(const std::string& prefix, const std::string& postfix): RowFormatter::RowFormatter(const std::string& prefix, const std::string& postfix):
_prefix(prefix), _prefix(prefix),
_postfix(postfix) _postfix(postfix),
_totalRowCount(0)
{ {
} }
@@ -55,4 +56,12 @@ RowFormatter::~RowFormatter()
} }
void RowFormatter::reset()
{
_prefix = "";
_postfix = "";
_totalRowCount = INVALID_ROW_COUNT;
}
} } // namespace Poco::Data } } // namespace Poco::Data

View File

@@ -89,7 +89,7 @@ void RowIterator::increment() const
if (POSITION_END == _position) if (POSITION_END == _position)
throw RangeException("End of iterator reached."); throw RangeException("End of iterator reached.");
if (_position < _pRecordSet->totalRowCount() - 1) if (_position < _pRecordSet->subTotalRowCount() - 1)
++_position; ++_position;
else else
_position = POSITION_END; _position = POSITION_END;
@@ -110,7 +110,7 @@ void RowIterator::decrement() const
if (0 == _position) if (0 == _position)
throw RangeException("Beginning of iterator reached."); throw RangeException("Beginning of iterator reached.");
else if (POSITION_END == _position) else if (POSITION_END == _position)
_position = _pRecordSet->totalRowCount() - 1; _position = _pRecordSet->subTotalRowCount() - 1;
else else
--_position; --_position;
@@ -146,16 +146,15 @@ void RowIterator::setPosition(std::size_t pos) const
std::size_t end = pos - _position; std::size_t end = pos - _position;
for (; start < end; ++start) for (; start < end; ++start)
{ {
if (_pRecordSet->totalRowCount() != pos) ++pos; if (_pRecordSet->subTotalRowCount() != pos) ++pos;
else throw RangeException("Invalid position argument."); else throw RangeException("Invalid position argument.");
} }
} }
} }
if (pos < _pRecordSet->totalRowCount()) if (pos < _pRecordSet->subTotalRowCount())
_position = pos; _position = pos;
else if (pos == _pRecordSet->totalRowCount()) else if (pos == _pRecordSet->subTotalRowCount())
_position = POSITION_END; _position = POSITION_END;
else else
throw RangeException("Invalid position argument."); throw RangeException("Invalid position argument.");

View File

@@ -44,7 +44,7 @@ namespace Data {
SimpleRowFormatter::SimpleRowFormatter(std::streamsize columnWidth): SimpleRowFormatter::SimpleRowFormatter(std::streamsize columnWidth):
_colWidth(columnWidth) _colWidth(columnWidth), _rowCount(0)
{ {
} }
@@ -81,6 +81,8 @@ void SimpleRowFormatter::swap(SimpleRowFormatter& other)
std::string& SimpleRowFormatter::formatNames(const NameVecPtr pNames, std::string& formattedNames) const std::string& SimpleRowFormatter::formatNames(const NameVecPtr pNames, std::string& formattedNames) const
{ {
_rowCount = 0;
std::ostringstream str; std::ostringstream str;
std::string line(_colWidth * pNames->size(), '-'); std::string line(_colWidth * pNames->size(), '-');
@@ -112,10 +114,15 @@ std::string& SimpleRowFormatter::formatValues(const ValueVec& vals, std::string&
} }
else str << std::left; else str << std::left;
str << std::setw(_colWidth) << it->convert<std::string>(); if (!it->isEmpty())
str << std::setw(_colWidth) << it->convert<std::string>();
else
str << std::setw(_colWidth) << "null";
} }
str << std::endl; str << std::endl;
++_rowCount;
return formattedValues = str.str(); return formattedValues = str.str();
} }

View File

@@ -109,7 +109,7 @@ Statement& Statement::reset(Session& session)
} }
std::size_t Statement::execute() std::size_t Statement::execute(bool reset)
{ {
Mutex::ScopedLock lock(_mutex); Mutex::ScopedLock lock(_mutex);
bool isDone = done(); bool isDone = done();
@@ -124,7 +124,7 @@ std::size_t Statement::execute()
if (!isAsync()) if (!isAsync())
{ {
if (isDone) _pImpl->reset(); if (isDone) _pImpl->reset();
return _pImpl->execute(); return _pImpl->execute(reset);
} }
else else
{ {
@@ -136,22 +136,22 @@ std::size_t Statement::execute()
} }
const Statement::Result& Statement::executeAsync() const Statement::Result& Statement::executeAsync(bool reset)
{ {
Mutex::ScopedLock lock(_mutex); Mutex::ScopedLock lock(_mutex);
if (initialized() || paused() || done()) if (initialized() || paused() || done())
return doAsyncExec(); return doAsyncExec(reset);
else else
throw InvalidAccessException("Statement still executing."); throw InvalidAccessException("Statement still executing.");
} }
const Statement::Result& Statement::doAsyncExec() const Statement::Result& Statement::doAsyncExec(bool reset)
{ {
if (done()) _pImpl->reset(); if (done()) _pImpl->reset();
if (!_pAsyncExec) if (!_pAsyncExec)
_pAsyncExec = new AsyncExecMethod(_pImpl, &StatementImpl::execute); _pAsyncExec = new AsyncExecMethod(_pImpl, &StatementImpl::execute);
_pResult = new Result((*_pAsyncExec)()); _pResult = new Result((*_pAsyncExec)(reset));
return *_pResult; return *_pResult;
} }
@@ -308,4 +308,11 @@ Statement& Statement::operator , (BulkFnType)
} }
Session Statement::session()
{
Poco::AutoPtr<SessionImpl> ps(&impl()->session(), true);
return Session(ps);
}
} } // namespace Poco::Data } } // namespace Poco::Data

View File

@@ -80,6 +80,7 @@ StatementImpl::StatementImpl(SessionImpl& rSession):
_extractors.resize(1); _extractors.resize(1);
_columnsExtracted.resize(1, 0); _columnsExtracted.resize(1, 0);
_subTotalRowCount.resize(1, 0);
} }
@@ -88,9 +89,9 @@ StatementImpl::~StatementImpl()
} }
std::size_t StatementImpl::execute() std::size_t StatementImpl::execute(const bool& reset)
{ {
resetExtraction(); if (reset) resetExtraction();
if (!_rSession.isConnected()) if (!_rSession.isConnected())
{ {
@@ -117,10 +118,32 @@ std::size_t StatementImpl::execute()
if (lim < _lowerLimit) if (lim < _lowerLimit)
throw LimitException("Did not receive enough data."); throw LimitException("Did not receive enough data.");
assignSubTotal(reset);
return lim; return lim;
} }
void StatementImpl::assignSubTotal(bool reset)
{
if (_extractors.size() == _subTotalRowCount.size())
{
CountVec::iterator it = _subTotalRowCount.begin();
CountVec::iterator end = _subTotalRowCount.end();
for (int counter = 0; it != end; ++it, ++counter)
{
if (_extractors[counter].size())
{
if (reset)
*it += _extractors[counter][0]->numOfRowsHandled();
else
*it = _extractors[counter][0]->numOfRowsHandled();
}
}
}
}
std::size_t StatementImpl::executeWithLimit() std::size_t StatementImpl::executeWithLimit()
{ {
poco_assert (_state != ST_DONE); poco_assert (_state != ST_DONE);
@@ -229,13 +252,19 @@ void StatementImpl::setBulkExtraction(const Bulk& b)
void StatementImpl::fixupExtraction() void StatementImpl::fixupExtraction()
{ {
CountVec::iterator sIt = _subTotalRowCount.begin();
CountVec::iterator sEnd = _subTotalRowCount.end();
for (; sIt != sEnd; ++sIt) *sIt = 0;
if (_curDataSet >= _columnsExtracted.size())
{
_columnsExtracted.resize(_curDataSet + 1, 0);
_subTotalRowCount.resize(_curDataSet + 1, 0);
}
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();
if (_curDataSet >= _columnsExtracted.size())
_columnsExtracted.resize(_curDataSet + 1, 0);
for (; it != itEnd; ++it) for (; it != itEnd; ++it)
{ {
(*it)->setExtractor(&ex); (*it)->setExtractor(&ex);
@@ -432,6 +461,19 @@ std::size_t StatementImpl::rowsExtracted(int dataSet) const
} }
std::size_t StatementImpl::subTotalRowCount(int dataSet) const
{
if (USE_CURRENT_DATA_SET == dataSet) dataSet = _curDataSet;
if (_subTotalRowCount.size() > 0)
{
poco_assert (dataSet >= 0 && dataSet < _subTotalRowCount.size());
return _subTotalRowCount[dataSet];
}
return 0;
}
void StatementImpl::formatSQL(std::vector<Any>& arguments) void StatementImpl::formatSQL(std::vector<Any>& arguments)
{ {
std::string sql; std::string sql;