RowFormatter redesign, sample and some other minor changes

This commit is contained in:
Aleksandar Fabijanic
2008-01-05 21:19:33 +00:00
parent 76079f5baa
commit e1d27fecba
21 changed files with 1085 additions and 281 deletions

View File

@@ -1580,16 +1580,16 @@ void SQLiteTest::testInternalExtraction()
typedef std::deque<Int64> IntDeq;
const Column<Int64>& col = rset.column<Int64, IntDeq>(0);
const Column<IntDeq>& col = rset.column<IntDeq>(0);
assert (col[0] == 1);
try { rset.column<Int64, IntDeq>(100); fail ("must fail"); }
try { rset.column<IntDeq>(100); fail ("must fail"); }
catch (RangeException&) { }
const Column<Int64>& col1 = rset.column<Int64, IntDeq>(0);
const Column<IntDeq>& col1 = rset.column<IntDeq>(0);
assert ("int0" == col1.name());
Column<Int64>::Iterator it = col1.begin();
Column<Int64>::Iterator itEnd = col1.end();
Column<IntDeq>::Iterator it = col1.begin();
Column<IntDeq>::Iterator itEnd = col1.end();
int counter = 1;
for (; it != itEnd; ++it, ++counter)
assert (counter == *it);
@@ -1601,7 +1601,7 @@ void SQLiteTest::testInternalExtraction()
stmt = (tmp << "DELETE FROM Vectors", now);
rset = stmt;
try { rset.column<Int64, IntDeq>(0); fail ("must fail"); }
try { rset.column<IntDeq>(0); fail ("must fail"); }
catch (RangeException&) { }
}
@@ -1723,8 +1723,8 @@ void SQLiteTest::testRowIterator()
RecordSet rset(ses, "SELECT * FROM Vectors");
std::ostringstream osLoop;
RecordSet::Iterator it = rset.begin();
RecordSet::Iterator end = rset.end();
RecordSet::ConstIterator it = rset.begin();
RecordSet::ConstIterator end = rset.end();
for (int i = 1; it != end; ++it, ++i)
{
assert (it->get(0) == i);

View File

@@ -55,25 +55,30 @@ namespace Data {
template <class C>
class Column
/// Column class is column data container.
/// Data (a pointer to container) is assigned to the class
/// through either constructor or set() member function.
/// Construction with null pointer is not allowed.
/// Data (a pointer to underlying STL container) is assigned to the class
/// at construction time. Construction with null pointer is not allowed.
/// This class owns the data assigned to it and deletes the storage on destruction.
{
public:
typedef C Container;
typedef typename Container::const_iterator Iterator;
typedef typename Container::const_reverse_iterator RIterator;
typedef typename Container::size_type Size;
typedef typename Container::value_type Type;
typedef C Container;
typedef Poco::SharedPtr<C> ContainerPtr;
typedef typename C::const_iterator Iterator;
typedef typename C::const_reverse_iterator RIterator;
typedef typename C::size_type Size;
typedef typename C::value_type Type;
Column(const MetaColumn& metaColumn, Container* pData): _metaColumn(metaColumn), _pData(pData)
Column(const MetaColumn& metaColumn, Container* pData):
_metaColumn(metaColumn),
_pData(pData)
/// Creates the Column.
{
poco_check_ptr (_pData);
if (!_pData)
throw NullPointerException("Container pointer must point to valid storage.");
}
Column(const Column& col): _metaColumn(col._metaColumn), _pData(col._pData)
Column(const Column& col):
_metaColumn(col._metaColumn),
_pData(col._pData)
/// Creates the Column.
{
}
@@ -182,8 +187,8 @@ public:
private:
Column();
MetaColumn _metaColumn;
Poco::SharedPtr<Container> _pData;
MetaColumn _metaColumn;
ContainerPtr _pData;
};
@@ -202,10 +207,11 @@ class Column<std::vector<bool> >
/// column data.
{
public:
typedef std::vector<bool> Container;
typedef Container::const_iterator Iterator;
typedef std::vector<bool> Container;
typedef Poco::SharedPtr<Container> ContainerPtr;
typedef Container::const_iterator Iterator;
typedef Container::const_reverse_iterator RIterator;
typedef Container::size_type Size;
typedef Container::size_type Size;
Column(const MetaColumn& metaColumn, Container* pData):
_metaColumn(metaColumn),
@@ -333,8 +339,8 @@ public:
private:
Column();
MetaColumn _metaColumn;
Poco::SharedPtr<Container> _pData;
MetaColumn _metaColumn;
ContainerPtr _pData;
mutable std::deque<bool> _deque;
};
@@ -344,18 +350,23 @@ class Column<std::list<T> >
/// Column specialization for std::list
{
public:
typedef std::list<T> List;
typedef typename List::const_iterator Iterator;
typedef typename List::const_reverse_iterator RIterator;
typedef typename List::size_type Size;
typedef std::list<T> Container;
typedef Poco::SharedPtr<Container> ContainerPtr;
typedef typename Container::const_iterator Iterator;
typedef typename Container::const_reverse_iterator RIterator;
typedef typename Container::size_type Size;
Column(const MetaColumn& metaColumn, std::list<T>* pData): _metaColumn(metaColumn), _pData(pData)
Column(const MetaColumn& metaColumn, std::list<T>* pData):
_metaColumn(metaColumn),
_pData(pData)
/// Creates the Column.
{
poco_check_ptr (_pData);
}
Column(const Column& col): _metaColumn(col._metaColumn), _pData(col._pData)
Column(const Column& col):
_metaColumn(col._metaColumn),
_pData(col._pData)
/// Creates the Column.
{
}
@@ -381,7 +392,7 @@ public:
swap(_pData, other._pData);
}
List& data()
Container& data()
/// Returns reference to contained data.
{
return *_pData;
@@ -481,8 +492,8 @@ public:
private:
Column();
MetaColumn _metaColumn;
Poco::SharedPtr<List> _pData;
MetaColumn _metaColumn;
ContainerPtr _pData;
};

View File

@@ -45,10 +45,12 @@
#include "Poco/Data/BulkExtraction.h"
#include "Poco/Data/Statement.h"
#include "Poco/Data/RowIterator.h"
#include "Poco/Data/RowFormatter.h"
#include "Poco/Data/BLOB.h"
#include "Poco/String.h"
#include "Poco/DynamicAny.h"
#include "Poco/Exception.h"
#include <ostream>
namespace Poco {
@@ -79,16 +81,22 @@ class Data_API RecordSet: private Statement
{
public:
typedef std::map<std::size_t, Row*> RowMap;
typedef RowIterator Iterator;
typedef const RowIterator ConstIterator;
typedef RowIterator Iterator;
using Statement::isNull;
explicit RecordSet(const Statement& rStatement);
/// Creates the RecordSet.
explicit RecordSet(Session& rSession, const std::string& query);
explicit RecordSet(Session& rSession,
const std::string& query,
RowFormatter* pRowFormatter = 0);
/// Creates the RecordSet.
RecordSet(const RecordSet& other);
/// Copy-creates the recordset.
~RecordSet();
/// Destroys the RecordSet.
@@ -101,37 +109,35 @@ public:
std::size_t columnCount() const;
/// Returns the number of rows in the recordset.
template <class C, class E>
template <class C>
const Column<C>& column(const std::string& name) const
/// Returns the reference to the first Column with the specified name.
{
return column<C,E>(columnPosition<C,E>(name));
}
template <class C, class E>
const Column<C>& column(std::size_t pos) const
/// Returns the reference to column at specified location.
{
typedef typename C::value_type T;
typedef const E* ExtractionVecPtr;
const AbstractExtractionVec& rExtractions = extractions();
std::size_t s = rExtractions.size();
if (0 == s || pos >= s)
throw RangeException(format("Invalid column index: %z", pos));
ExtractionVecPtr pExtraction = dynamic_cast<ExtractionVecPtr>(rExtractions[pos].get());
if (pExtraction)
if (isBulkExtraction())
{
return pExtraction->column();
typedef InternalBulkExtraction<C> E;
return columnImpl<C,E>(name);
}
else
{
throw Poco::BadCastException(format("Type cast failed!\nColumn: %z\nTarget type:\t%s",
pos,
std::string(typeid(T).name())));
typedef InternalExtraction<C> E;
return columnImpl<C,E>(name);
}
}
template <class C>
const Column<C>& column(std::size_t pos) const
/// Returns the reference to column at specified position.
{
if (isBulkExtraction())
{
typedef InternalBulkExtraction<C> E;
return columnImpl<C,E>(pos);
}
else
{
typedef InternalExtraction<C> E;
return columnImpl<C,E>(pos);
}
}
@@ -148,27 +154,18 @@ public:
case STORAGE_VECTOR:
{
typedef std::vector<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(col).value(row);
else
return column<C, InternalExtraction<C> >(col).value(row);
return column<C>(col).value(row);
}
case STORAGE_LIST:
{
typedef std::list<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(col).value(row);
else
return column<C, InternalExtraction<C> >(col).value(row);
return column<C>(col).value(row);
}
case STORAGE_DEQUE:
case STORAGE_UNKNOWN:
{
typedef std::deque<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(col).value(row);
else
return column<C, InternalExtraction<C> >(col).value(row);
return column<C>(col).value(row);
}
default:
throw IllegalStateException("Invalid storage setting.");
@@ -184,27 +181,18 @@ public:
case STORAGE_VECTOR:
{
typedef std::vector<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(name).value(row);
else
return column<C, InternalExtraction<C> >(name).value(row);
return column<C>(name).value(row);
}
case STORAGE_LIST:
{
typedef std::list<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(name).value(row);
else
return column<C, InternalExtraction<C> >(name).value(row);
return column<C>(name).value(row);
}
case STORAGE_DEQUE:
case STORAGE_UNKNOWN:
{
typedef std::deque<T> C;
if (isBulkExtraction())
return column<C, InternalBulkExtraction<C> >(name).value(row);
else
return column<C, InternalExtraction<C> >(name).value(row);
return column<C>(name).value(row);
}
default:
throw IllegalStateException("Invalid storage setting.");
@@ -225,8 +213,17 @@ public:
/// Returns the value in the given column of the current row
/// if the value is not NULL, or deflt otherwise.
const RowIterator& begin();
/// Moves the row cursor to the first row and returns the pointer to row.
ConstIterator& begin() const;
/// Returns the const row iterator.
ConstIterator& end() const;
/// Returns the const row iterator.
Iterator begin();
/// Returns the row iterator.
Iterator end();
/// Returns the row iterator.
bool moveFirst();
/// Moves the row cursor to the first row.
@@ -247,9 +244,6 @@ public:
/// Returns true if the row is available, or false
/// if there are no more rows available.
const RowIterator& end();
/// Moves the row cursor to the last row and returns null pointer.
bool moveLast();
/// Moves the row cursor to the last row.
///
@@ -294,6 +288,34 @@ public:
bool isNull(const std::string& name) const;
/// Returns true if column value of the current row is null.
void setFormatter(Row::FormatterPtr pRowFormatter);
/// Sets the row formatter for this recordset.
/// Row formatter is null pointer by default, indicating
/// use of default formatter for output formatting.
/// This function allows for custom formatters to be
/// supplied by users. After setting a user supplied formatter,
/// to revert back to the default one, call this function with
/// zero argument.
std::ostream& copyNames(std::ostream& os) const;
/// Copies the column names to the target output stream.
/// Copied string is formatted by the current RowFormatter.
std::ostream& copyValues(std::ostream& os,
std::size_t offset = 0,
std::size_t length = RowIterator::POSITION_END) const;
/// Copies the data values to the supplied output stream.
/// The data set to be copied is starting at the specified offset
/// from the recordset beginning. The number of rows to be copied
/// is specified by length argument.
/// An invalid combination of offset/length arguments shall
/// cause RangeException to be thrown.
/// Copied string is formatted by the current RowFormatter.
std::ostream& copy(std::ostream& os) const;
/// Copies the column names and values to the target output stream.
/// Copied strings are formatted by the current RowFormatter.
private:
RecordSet();
@@ -329,16 +351,58 @@ private:
throw NotFoundException(format("Column type: %s, name: %s", std::string(typeid(T).name()), name));
}
std::size_t _currentRow;
RowIterator* _pBegin;
RowIterator* _pEnd;
RowMap _rowMap;
template <class C, class E>
const Column<C>& columnImpl(const std::string& name) const
/// Returns the reference to the first Column with the specified name.
{
return columnImpl<C,E>(columnPosition<C,E>(name));
}
template <class C, class E>
const Column<C>& columnImpl(std::size_t pos) const
/// Returns the reference to column at specified position.
{
typedef typename C::value_type T;
typedef const E* ExtractionVecPtr;
const AbstractExtractionVec& rExtractions = extractions();
std::size_t s = rExtractions.size();
if (0 == s || pos >= s)
throw RangeException(format("Invalid column index: %z", pos));
ExtractionVecPtr pExtraction = dynamic_cast<ExtractionVecPtr>(rExtractions[pos].get());
if (pExtraction)
{
return pExtraction->column();
}
else
{
throw Poco::BadCastException(format("Type cast failed!\nColumn: %z\nTarget type:\t%s",
pos,
std::string(typeid(T).name())));
}
}
std::size_t _currentRow;
RowIterator* _pBegin;
RowIterator* _pEnd;
RowMap _rowMap;
Row::FormatterPtr _pRowFormatter;
};
///
/// inlines
///
inline Data_API std::ostream& operator << (std::ostream &os, const RecordSet& rs)
{
return rs.copy(os);
}
inline std::size_t RecordSet::rowCount() const
{
poco_assert (extractions().size());
@@ -431,15 +495,43 @@ inline bool RecordSet::isNull(const std::string& name) const
}
inline const RowIterator& RecordSet::end()
inline RecordSet::ConstIterator& RecordSet::begin() const
{
if (!_pEnd)
_pEnd = new RowIterator(*this, true);
return *_pBegin;
}
inline RecordSet::ConstIterator& RecordSet::end() const
{
return *_pEnd;
}
inline RecordSet::Iterator RecordSet::begin()
{
return *_pBegin;
}
inline RecordSet::Iterator RecordSet::end()
{
return *_pEnd;
}
inline void RecordSet::setFormatter(Row::FormatterPtr pRowFormatter)
{
_pRowFormatter = pRowFormatter;
}
inline std::ostream& RecordSet::copyNames(std::ostream& os) const
{
os << (*_pBegin)->namesToString();
return os;
}
} } // namespace Poco::Data

View File

@@ -47,7 +47,7 @@
#include "Poco/SharedPtr.h"
#include <vector>
#include <string>
#include <sstream>
#include <ostream>
namespace Poco {
@@ -79,9 +79,10 @@ class Data_API Row
/// The stream operator is provided for Row data type as a free-standing function.
{
public:
typedef std::vector<std::string> NameVec;
typedef SharedPtr<std::vector<std::string> > NameVecPtr;
typedef std::vector<DynamicAny> ValueVec;
typedef RowFormatter::NameVec NameVec;
typedef RowFormatter::NameVecPtr NameVecPtr;
typedef RowFormatter::ValueVec ValueVec;
typedef SharedPtr<RowFormatter> FormatterPtr;
enum ComparisonType
{
@@ -90,12 +91,10 @@ public:
COMPARE_AS_STRING
};
static const std::string EOL;
Row();
/// Creates the Row.
explicit Row(NameVecPtr pNames, RowFormatter* pFormatter = 0);
explicit Row(NameVecPtr pNames, FormatterPtr* pFormatter = 0);
/// Creates the Row.
~Row();
@@ -181,13 +180,11 @@ public:
void resetSort();
/// Resets the sorting criteria to field 0 only.
const std::string namesToString() const;
/// Converts the row names to string, inserting separator
/// string between fields and end-of-line at the end.
const std::string& namesToString() const;
/// Converts the row names to string.
const std::string valuesToString() const;
/// Converts the row values to string, inserting separator
/// string between fields and end-of-line at the end.
const std::string& valuesToString() const;
/// Converts the row values to string.
bool operator == (const Row& other) const;
/// Equality operator.
@@ -198,12 +195,19 @@ public:
bool operator < (const Row& other) const;
/// Less-then operator.
NameVecPtr names();
const NameVecPtr names() const;
/// Returns the shared pointer to names vector.
const ValueVec& values();
const ValueVec& values() const;
/// Returns the const reference to values vector.
void setFormatter(FormatterPtr* pFormatter);
/// Sets the formatter for this row and takes the
/// shared ownership of it.
const RowFormatter& getFormatter() const;
/// Returns the reference to the formatter.
private:
typedef Tuple<std::size_t, ComparisonType> SortTuple;
typedef std::vector<SortTuple> SortMap;
@@ -212,14 +216,19 @@ private:
/// corresponds to adding order rather than field's position in the row.
/// That requirement rules out use of std::map due to its sorted nature.
ValueVec& values();
/// Returns the reference to values vector.
std::size_t getPosition(const std::string& name);
bool isEqualSize(const Row& other) const;
bool isEqualType(const Row& other) const;
NameVecPtr _pNames;
ValueVec _values;
SortMap _sortFields;
mutable SharedPtr<RowFormatter> _pFormatter;
NameVecPtr _pNames;
ValueVec _values;
SortMap _sortFields;
FormatterPtr _pFormatter;
mutable std::string _nameStr;
mutable std::string _valueStr;
};
@@ -242,13 +251,19 @@ inline void Row::reset()
}
inline Row::NameVecPtr Row::names()
inline const Row::NameVecPtr Row::names() const
{
return _pNames;
}
inline const Row::ValueVec& Row::values()
inline const Row::ValueVec& Row::values() const
{
return _values;
}
inline Row::ValueVec& Row::values()
{
return _values;
}
@@ -266,6 +281,18 @@ inline DynamicAny& Row::operator [] (const std::string& name)
}
inline const RowFormatter& Row::getFormatter() const
{
return *_pFormatter;
}
inline const std::string& Row::valuesToString() const
{
return _pFormatter->formatValues(values(), _valueStr);
}
} } // namespace Poco::Data

View File

@@ -41,47 +41,64 @@
#include "Poco/Data/Data.h"
#include "Poco/SharedPtr.h"
#include "Poco/DynamicAny.h"
#include <sstream>
#include <vector>
namespace Poco {
namespace Data {
class Row;
class Data_API RowFormatter
/// Row formatter is a rudimentary formatting class providing
/// basic row formatting. This class will separate field names and
/// filed values by a tab ('\t') and append the platform specific
/// end of line at the end of each row. For custom formatting
/// basic row formatting. For custom formatting
/// strategies, inherit from this class and override formatNames()
/// and formaValues() member functions.
/// and formatValues() member functions.
{
public:
static const std::string EOL;
typedef std::vector<std::string> NameVec;
typedef SharedPtr<std::vector<std::string> > NameVecPtr;
typedef std::vector<DynamicAny> ValueVec;
RowFormatter(Row* pRow = 0);
/// Creates the RowFormatter.
static const int DEFAULT_COLUMN_WIDTH = 16;
RowFormatter(std::streamsize width);
/// Creates the RowFormatter and sets the column width to specified value.
RowFormatter(const std::string& prefix = "", const std::string& postfix = "");
/// Creates the RowFormatter and sets the prefix and postfix to specified values.
virtual ~RowFormatter();
/// Destroys the RowFormatter.
void setRow(Row* pRow);
/// Assigns the row to this formatter.
const std::string& prefix() const;
/// Returns prefix string;
virtual std::string& formatNames(std::string& names);
virtual std::string& formatNames(const NameVecPtr pNames, std::string& formattedNames) const;
/// Formats the row field names.
virtual std::string& formatValues(std::string& values);
virtual std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const;
/// Formats the row values.
private:
RowFormatter(const RowFormatter&);
RowFormatter& operator = (const RowFormatter&);
const std::string& postfix() const;
/// Returns postfix string;
Row* _pRow;
std::string _separator;
void setWidth(std::streamsize width);
/// Sets the column width.
std::streamsize getWidth() const;
/// Returns the column width.
protected:
void setPrefix(const std::string& prefix);
void setPostfix(const std::string& postfix);
private:
std::streamsize _width;
std::string _prefix;
std::string _postfix;
};
@@ -89,11 +106,39 @@ private:
/// inlines
///
inline void RowFormatter::setRow(Row* pRow)
inline void RowFormatter::setWidth(std::streamsize width)
{
poco_check_ptr (pRow);
_pRow = pRow;
_width = width;
}
inline std::streamsize RowFormatter::getWidth() const
{
return _width;
}
inline void RowFormatter::setPrefix(const std::string& prefix)
{
_prefix = prefix;
}
inline void RowFormatter::setPostfix(const std::string& postfix)
{
_postfix = postfix;
}
inline const std::string& RowFormatter::prefix() const
{
return _prefix;
}
inline const std::string& RowFormatter::postfix() const
{
return _postfix;
}

View File

@@ -58,21 +58,30 @@ class Data_API RowIterator
{
public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef Row value_type;
typedef std::ptrdiff_t difference_type;
typedef Row* pointer;
typedef Row& reference;
typedef Row value_type;
typedef std::ptrdiff_t difference_type;
typedef Row* pointer;
typedef Row& reference;
RowIterator(RecordSet& recordSet, bool positionEnd = false);
static const int POSITION_END;
/// End position indicator.
RowIterator(RecordSet* pRecordSet, bool positionEnd = false);
/// Creates the RowIterator and positions it at the beginning.
RowIterator(const RowIterator& other);
/// Creates a copy of other RowIterator.
~RowIterator();
/// Destroys the RowIterator.
bool operator == (const RowIterator& other);
RowIterator& operator = (const RowIterator& other);
/// Assigns the other RowIterator.
bool operator == (const RowIterator& other) const;
/// Equality operator.
bool operator != (const RowIterator& other);
bool operator != (const RowIterator& other) const;
/// Inequality operator.
Row& operator * () const;
@@ -81,47 +90,80 @@ public:
Row* operator -> () const;
/// Returns pointer to the current row.
std::size_t operator ++ ();
const RowIterator& operator ++ () const;
/// Advances by one position and returns current position.
std::size_t operator ++ (int);
/// Advances by one position and returns previous current position.
RowIterator operator ++ (int) const;
/// Advances by one position and returns copy of the iterator with
/// previous current position.
std::size_t operator -- ();
/// Goes back by one position and returns current position.
const RowIterator& operator -- () const;
/// Goes back by one position and returns copy of the iterator with
/// previous current position.
std::size_t operator -- (int);
/// Goes back by one position and returns previouscurrent position.
RowIterator operator -- (int) const;
/// Goes back by one position and returns previous current position.
RowIterator operator + (std::size_t diff) const;
/// Returns a copy the RowIterator advanced by diff positions.
RowIterator operator - (std::size_t diff) const;
/// Returns a copy the RowIterator backed by diff positions.
/// Throws RangeException if diff is larger than current position.
void swap(RowIterator& other);
/// Swaps the RowIterator with another one.
private:
RowIterator();
void increment();
void decrement();
void increment() const;
/// Increments the iterator position by one.
/// Throws RangeException if position is out of range.
static const int POSITION_END;
void decrement() const;
/// Decrements the iterator position by one.
/// Throws RangeException if position is out of range.
RecordSet& _recordSet;
std::size_t _position;
void setPosition(std::size_t pos) const;
/// Sets the iterator position.
/// Throws RangeException if position is out of range.
RecordSet* _pRecordSet;
mutable std::size_t _position;
};
///
/// inlines
///
inline bool RowIterator::operator == (const RowIterator& other)
inline bool RowIterator::operator == (const RowIterator& other) const
{
return _position == other._position;
return _pRecordSet == other._pRecordSet && _position == other._position;
}
inline bool RowIterator::operator != (const RowIterator& other)
inline bool RowIterator::operator != (const RowIterator& other) const
{
return _position != other._position;
return _pRecordSet != other._pRecordSet || _position != other._position;
}
} } // namespace Poco::Data
namespace std
{
template<>
inline void swap<Poco::Data::RowIterator>(Poco::Data::RowIterator& s1,
Poco::Data::RowIterator& s2)
/// Full template specalization of std:::swap for RowIterator
{
s1.swap(s2);
}
}
#endif // Data_RowIterator_INCLUDED

View File

@@ -270,6 +270,8 @@ public:
/// with the statement.
protected:
typedef Poco::AutoPtr<StatementImpl> StatementImplPtr;
const AbstractExtractionVec& extractions() const;
/// Returns the extractions vector.
@@ -285,9 +287,10 @@ protected:
bool isBulkExtraction() const;
/// Returns true if this statement extracts data in bulk.
private:
typedef Poco::SharedPtr<StatementImpl> StatementImplPtr;
StatementImplPtr impl() const;
/// Returns pointer to statement implementation.
private:
static const int WAIT_FOREVER = -1;
const Result& doAsyncExec();
@@ -379,6 +382,12 @@ inline void Data_API reset(Statement& statement)
//
inline Statement::StatementImplPtr Statement::impl() const
{
return _pImpl;
}
inline std::string Statement::toString() const
{
return _pImpl->toString();

View File

@@ -12,4 +12,5 @@ projects:
$(MAKE) -C Binding $(MAKECMDGOALS)
$(MAKE) -C TypeHandler $(MAKECMDGOALS)
$(MAKE) -C RecordSet $(MAKECMDGOALS)
$(MAKE) -C RowFormatter $(MAKECMDGOALS)
$(MAKE) -C Tuple $(MAKECMDGOALS)

View File

@@ -20,7 +20,6 @@
#include "Poco/Data/SessionFactory.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/RecordSet.h"
#include "Poco/Data/Column.h"
#include "Poco/Data/SQLite/Connector.h"
#include <iostream>
@@ -28,14 +27,6 @@
using namespace Poco::Data;
struct Person
{
std::string name;
std::string address;
int age;
};
int main(int argc, char** argv)
{
// register SQLite connector
@@ -51,30 +42,20 @@ int main(int argc, char** argv)
session << "CREATE TABLE Person (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;
// insert some rows
session << "INSERT INTO Person VALUES('Homer Simpson', 'Springfield', 42)", now;
session << "INSERT INTO Person VALUES('Marge Simpson', 'Springfield', 38)", now;
session << "INSERT INTO Person VALUES('Bart Simpson', 'Springfield', 12)", now;
session << "INSERT INTO Person VALUES('Lisa Simpson', 'Springfield', 10)", now;
// a simple query
Statement select(session);
select << "SELECT * FROM Person";
select.execute();
// create a recordset and print the column names and data
RecordSet rs(session, "SELECT * FROM Person");
std::cout << rs;
// create a RecordSet
RecordSet rs(select);
std::size_t cols = rs.columnCount();
// print all column names
for (std::size_t col = 0; col < cols; ++col)
{
std::cout << rs.columnName(col) << "\t\t";
}
// print just two middle rows
std::cout << std::endl << "Middle rows :" << std::endl;
rs.copyValues(std::cout, 1, 2);
std::cout << std::endl;
std::cout << "-----------------------------------" << std::endl;
// iterate over all rows and print the data
RecordSet::Iterator it = rs.begin();
RecordSet::Iterator end = rs.end();
for (; it != end; ++it) std::cout << *it;
std::cout << "---" << std::endl << "Thats all, folks!" << std::endl;
return 0;
}

View File

@@ -0,0 +1,17 @@
#
# Makefile
#
# $Id: //poco/Main/Data/samples/RowFormatter/Makefile#1 $
#
# Makefile for Poco Data RowFormatter sample
#
include $(POCO_BASE)/build/rules/global
objects = RowFormatter
target = RowFormatter
target_version = 1
target_libs = PocoFoundation PocoData PocoSQLite
include $(POCO_BASE)/build/rules/exec

View File

@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="RowFormatter"
ProjectGUID="{56F66D36-F11E-4AA1-AD37-4518A253059D}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="debug_shared|Win32"
OutputDirectory="obj\debug_shared"
IntermediateDirectory="obj\debug_shared"
ConfigurationType="1"
UseOfMFC="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=".\include;..\..\..\Foundation\include;..\..\..\Data\include;..\..\..\Data\SQLite\include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;POCO_DLL;WINVER=0x0500"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
BufferSecurityCheck="TRUE"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="TRUE"
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="bin/RowFormatterd.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\..\lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="bin/RowFormatterd.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="release_shared|Win32"
OutputDirectory="obj\release_shared"
IntermediateDirectory="obj\release_shared"
ConfigurationType="1"
UseOfMFC="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="4"
InlineFunctionExpansion="1"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
OptimizeForWindowsApplication="TRUE"
AdditionalIncludeDirectories=".\include;..\..\..\Foundation\include;..\..\..\Data\include;..\..\..\Data\SQLite\include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;POCO_DLL;WINVER=0x0500"
StringPooling="TRUE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="TRUE"
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="bin/RowFormatter.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\..\lib"
GenerateDebugInformation="FALSE"
ProgramDatabaseFile=""
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Header Files"
Filter="">
</Filter>
<Filter
Name="Source Files"
Filter="">
<File
RelativePath=".\src\RowFormatter.cpp">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,209 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="RowFormatter"
ProjectGUID="{2613C7FF-A9A1-4376-9CD7-07F694501498}"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="debug_shared|Win32"
OutputDirectory="obj\debug_shared"
IntermediateDirectory="obj\debug_shared"
ConfigurationType="1"
UseOfMFC="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=".\include;..\..\..\Foundation\include;..\..\..\Data\include;..\..\..\Data\SQLite\include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;POCO_DLL;WINVER=0x0500"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
BufferSecurityCheck="true"
TreatWChar_tAsBuiltInType="true"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="bin/RowFormatterd.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\..\lib"
GenerateDebugInformation="true"
ProgramDatabaseFile="bin/RowFormatterd.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="release_shared|Win32"
OutputDirectory="obj\release_shared"
IntermediateDirectory="obj\release_shared"
ConfigurationType="1"
UseOfMFC="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="4"
InlineFunctionExpansion="1"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
AdditionalIncludeDirectories=".\include;..\..\..\Foundation\include;..\..\..\Data\include;..\..\..\Data\SQLite\include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;POCO_DLL;WINVER=0x0500"
StringPooling="true"
RuntimeLibrary="2"
BufferSecurityCheck="false"
TreatWChar_tAsBuiltInType="true"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="bin/Rowformatter.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\..\lib"
GenerateDebugInformation="false"
ProgramDatabaseFile=""
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Header Files"
>
</Filter>
<Filter
Name="Source Files"
>
<File
RelativePath=".\src\RowFormatter.cpp"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,106 @@
//
// RecordSet.cpp
//
// $Id: //poco/Main/Data/samples/RecordSet/src/RowFormatter.cpp#2 $
//
// This sample demonstrates the Data library recordset formatting
// capabilities.
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// All rights reserved.
//
// This is unpublished proprietary source code of Applied Informatics
// Software Engineering GmbH.
// The contents of this file may not be disclosed to third parties,
// copied or duplicated in any form, in whole or in part, without
// prior written permission from Applied Informatics.
//
#include "Poco/SharedPtr.h"
#include "Poco/Data/SessionFactory.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/RecordSet.h"
#include "Poco/Data/RowFormatter.h"
#include "Poco/Data/SQLite/Connector.h"
#include <iostream>
using namespace Poco::Data;
class HTMLTableFormatter : public RowFormatter
{
public:
HTMLTableFormatter()
{
std::ostringstream os;
os << "<TABLE border=\"1\" cellspacing=\"0\">" << std::endl;
setPrefix(os.str());
os.str("");
os << "</TABLE>" << std::endl;
setPostfix(os.str());
}
std::string& formatNames(const NameVecPtr pNames, std::string& formattedNames) const
{
std::ostringstream str;
str << "\t<TR>" << std::endl;
NameVec::const_iterator it = pNames->begin();
NameVec::const_iterator end = pNames->end();
for (; it != end; ++it) str << "\t\t<TH align=\"center\">" << *it << "</TH>" << std::endl;
str << "\t</TR>" << std::endl;
return formattedNames = str.str();
}
std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const
{
std::ostringstream str;
str << "\t<TR>" << std::endl;
ValueVec::const_iterator it = vals.begin();
ValueVec::const_iterator end = vals.end();
for (; it != end; ++it)
{
if (it->isNumeric())
str << "\t\t<TD align=\"right\">";
else
str << "\t\t<TD align=\"left\">";
str << it->convert<std::string>() << "</TD>" << std::endl;
}
str << "\t</TR>" << std::endl;
return formattedValues = str.str();
}
};
int main(int argc, char** argv)
{
// register SQLite connector
Poco::Data::SQLite::Connector::registerConnector();
// create a session
Session session("SQLite", "sample.db");
// drop sample table, if it exists
session << "DROP TABLE IF EXISTS Person", now;
// (re)create table
session << "CREATE TABLE Person (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;
// insert some rows
session << "INSERT INTO Person VALUES('Homer Simpson', 'Springfield', 42)", now;
session << "INSERT INTO Person VALUES('Marge Simpson', 'Springfield', 38)", now;
session << "INSERT INTO Person VALUES('Bart Simpson', 'Springfield', 12)", now;
session << "INSERT INTO Person VALUES('Lisa Simpson', 'Springfield', 10)", now;
// create a recordset and print the column names and data as HTML table
std::cout << RecordSet(session, "SELECT * FROM Person", new HTMLTableFormatter);
return 0;
}

View File

@@ -65,7 +65,7 @@ public:
TypeHandler<int>::extract(pos++, person.age, deflt.age, pExtr);
}
static void prepare(std::size_t pos, const Person& person, AbstractPreparation* pPrep)
static void prepare(std::size_t pos, Person& person, AbstractPreparation* pPrep)
{
TypeHandler<std::string>::prepare(pos++, person.name, pPrep);
TypeHandler<std::string>::prepare(pos++, person.address, pPrep);

View File

@@ -15,11 +15,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tuple", "Tuple\Tuple_vs71.v
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RowFormatter", "RowFormatter\RowFormatter_vs71.vcproj", "{56F66D36-F11E-4AA1-AD37-4518A253059D}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
debug_shared = debug_shared
release_shared = release_shared
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{54BCEDA8-C241-4DCF-AEAD-6177F115B0D0}.debug_shared.ActiveCfg = debug_shared|Win32
{54BCEDA8-C241-4DCF-AEAD-6177F115B0D0}.debug_shared.Build.0 = debug_shared|Win32
@@ -37,6 +43,10 @@ Global
{08C81227-3322-4DBD-A83F-55CCC933A5F7}.debug_shared.Build.0 = debug_shared|Win32
{08C81227-3322-4DBD-A83F-55CCC933A5F7}.release_shared.ActiveCfg = release_shared|Win32
{08C81227-3322-4DBD-A83F-55CCC933A5F7}.release_shared.Build.0 = release_shared|Win32
{56F66D36-F11E-4AA1-AD37-4518A253059D}.debug_shared.ActiveCfg = debug_shared|Win32
{56F66D36-F11E-4AA1-AD37-4518A253059D}.debug_shared.Build.0 = debug_shared|Win32
{56F66D36-F11E-4AA1-AD37-4518A253059D}.release_shared.ActiveCfg = release_shared|Win32
{56F66D36-F11E-4AA1-AD37-4518A253059D}.release_shared.Build.0 = release_shared|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection

View File

@@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RecordSet", "RecordSet\Reco
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tuple", "Tuple\Tuple_vs80.vcproj", "{08C81227-3322-4DBD-A83F-55CCC933A5F7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RowFormatter", "RowFormatter\RowFormatter_vs80.vcproj", "{2613C7FF-A9A1-4376-9CD7-07F694501498}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
debug_shared|Win32 = debug_shared|Win32
@@ -31,6 +33,10 @@ Global
{08C81227-3322-4DBD-A83F-55CCC933A5F7}.debug_shared|Win32.Build.0 = debug_shared|Win32
{08C81227-3322-4DBD-A83F-55CCC933A5F7}.release_shared|Win32.ActiveCfg = release_shared|Win32
{08C81227-3322-4DBD-A83F-55CCC933A5F7}.release_shared|Win32.Build.0 = release_shared|Win32
{2613C7FF-A9A1-4376-9CD7-07F694501498}.debug_shared|Win32.ActiveCfg = debug_shared|Win32
{2613C7FF-A9A1-4376-9CD7-07F694501498}.debug_shared|Win32.Build.0 = debug_shared|Win32
{2613C7FF-A9A1-4376-9CD7-07F694501498}.release_shared|Win32.ActiveCfg = release_shared|Win32
{2613C7FF-A9A1-4376-9CD7-07F694501498}.release_shared|Win32.Build.0 = release_shared|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -52,17 +52,30 @@ namespace Data {
RecordSet::RecordSet(const Statement& rStatement):
Statement(rStatement),
_currentRow(0),
_pBegin(0),
_pEnd(0)
_pBegin(new RowIterator(this)),
_pEnd(new RowIterator(this, true))
{
}
RecordSet::RecordSet(Session& rSession, const std::string& query):
RecordSet::RecordSet(Session& rSession,
const std::string& query,
RowFormatter* pRowFormatter):
Statement((rSession << query, now)),
_currentRow(0),
_pBegin(0),
_pEnd(0)
_pBegin(new RowIterator(this)),
_pEnd(new RowIterator(this, true)),
_pRowFormatter(pRowFormatter)
{
}
RecordSet::RecordSet(const RecordSet& other):
Statement(other.impl().duplicate()),
_currentRow(other._currentRow),
_pBegin(new RowIterator(this)),
_pEnd(new RowIterator(this, true)),
_pRowFormatter(other._pRowFormatter)
{
}
@@ -74,8 +87,7 @@ RecordSet::~RecordSet()
RowMap::iterator it = _rowMap.begin();
RowMap::iterator end = _rowMap.end();
for (; it != end; ++it)
delete it->second;
for (; it != end; ++it) delete it->second;
}
@@ -131,15 +143,6 @@ DynamicAny RecordSet::value(const std::string& name, std::size_t row) const
}
const RowIterator& RecordSet::begin()
{
if (!_pBegin)
_pBegin = new RowIterator(*this);
return *_pBegin;
}
Row& RecordSet::row(std::size_t pos)
{
if (pos > rowCount() - 1)
@@ -147,27 +150,31 @@ Row& RecordSet::row(std::size_t pos)
RowMap::iterator it = _rowMap.find(pos);
Row* pRow = 0;
std::size_t columns = columnCount();
if (it == _rowMap.end())
{
if (_rowMap.size())//reuse first row column names to save some memory
{
pRow = new Row(_rowMap.begin()->second->names());
for (std::size_t i = 0; i < columnCount(); ++i)
pRow->set(i, value(i, pos));
pRow = new Row(_rowMap.begin()->second->names(), &_pRowFormatter);
for (std::size_t col = 0; col < columns; ++col)
pRow->set(col, value(col, pos));
}
else
{
pRow = new Row;
for (std::size_t i = 0; i < columnCount(); ++i)
pRow->append(metaColumn(static_cast<UInt32>(pos)).name(), value(i, pos));
if (_pRowFormatter) pRow->setFormatter(&_pRowFormatter);
for (std::size_t col = 0; col < columns; ++col)
pRow->append(metaColumn(static_cast<UInt32>(col)).name(), value(col, pos));
}
_rowMap.insert(RowMap::value_type(pos, pRow));
}
else
{
pRow = it->second;
poco_check_ptr (pRow);
}
poco_check_ptr (pRow);
return *pRow;
}
@@ -228,4 +235,30 @@ DynamicAny RecordSet::nvl(std::size_t index, const DynamicAny& deflt) 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 itEnd = itBegin + length;
std::copy(itBegin, itEnd, std::ostream_iterator<Row>(os));
return os;
}
std::ostream& RecordSet::copy(std::ostream& os) const
{
const RowFormatter& ri = (*_pBegin)->getFormatter();
os << ri.prefix();
copyNames(os);
copyValues(os);
os << ri.postfix();
return os;
}
} } // namespace Poco::Data

View File

@@ -35,6 +35,7 @@
#include "Poco/Data/Row.h"
#include "Poco/Data/RowFormatter.h"
#include "Poco/Exception.h"
@@ -51,20 +52,18 @@ std::ostream& operator << (std::ostream &os, const Row& row)
Row::Row():
_pNames(0),
_pFormatter(new RowFormatter(this))
_pFormatter(new RowFormatter)
{
}
Row::Row(NameVecPtr pNames, RowFormatter* pFormatter):
_pNames(pNames),
_pFormatter(pFormatter)
Row::Row(NameVecPtr pNames, FormatterPtr* pFormatter):
_pNames(pNames)
{
if (!_pNames)
throw NullPointerException();
if (!_pNames) throw NullPointerException();
if (!_pFormatter) _pFormatter = new RowFormatter(this);
else _pFormatter->setRow(this);
if (pFormatter && *pFormatter) _pFormatter = *pFormatter;
else _pFormatter = new RowFormatter;
_values.resize(_pNames->size());
addSortField(0);
@@ -316,20 +315,21 @@ bool Row::operator < (const Row& other) const
}
const std::string Row::valuesToString() const
void Row::setFormatter(FormatterPtr* pFormatter)
{
std::string values;
return _pFormatter->formatValues(values);
if (pFormatter && *pFormatter)
_pFormatter = *pFormatter;
else
_pFormatter = new RowFormatter;
}
const std::string Row::namesToString() const
const std::string& Row::namesToString() const
{
if (!_pNames)
throw NullPointerException();
std::string names;
return _pFormatter->formatNames(names);
return _pFormatter->formatNames(names(), _nameStr);
}

View File

@@ -35,26 +35,24 @@
#include "Poco/Data/RowFormatter.h"
#include "Poco/Data/Row.h"
#include "Poco/Exception.h"
#include <iomanip>
namespace Poco {
namespace Data {
#if defined(POCO_OS_FAMILY_WINDOWS)
const std::string RowFormatter::EOL = "\r\n";
#elif (POCO_OS == POCO_OS_MAC_OS_X)
const std::string RowFormatter::EOL = "\r";
#else
const std::string RowFormatter::EOL = "\n";
#endif
RowFormatter::RowFormatter(std::streamsize width):
_width(width)
{
}
RowFormatter::RowFormatter(Row* pRow):
_pRow(pRow),
_separator("\t")
RowFormatter::RowFormatter(const std::string& prefix, const std::string& postfix):
_width(DEFAULT_COLUMN_WIDTH),
_prefix(prefix),
_postfix(postfix)
{
}
@@ -64,40 +62,44 @@ RowFormatter::~RowFormatter()
}
std::string& RowFormatter::formatNames(std::string& names)
std::string& RowFormatter::formatNames(const NameVecPtr pNames, std::string& formattedNames) const
{
if (!_pRow)
throw NullPointerException("Null row.");
std::ostringstream str;
std::string line(_width * pNames->size(), '-');
Row::NameVec::const_iterator it = _pRow->names()->begin();
Row::NameVec::const_iterator end = _pRow->names()->end();
NameVec::const_iterator it = pNames->begin();
NameVec::const_iterator end = pNames->end();
for (; it != end; ++it)
{
names.append(*it);
names.append(_separator);
str << std::left << std::setw(_width) << *it;
}
names.replace(names.find_last_of(_separator), _separator.length(), EOL);
str << std::endl << line << std::endl;
return names;
return formattedNames = str.str();
}
std::string& RowFormatter::formatValues(std::string& values)
std::string& RowFormatter::formatValues(const ValueVec& vals, std::string& formattedValues) const
{
if (!_pRow)
throw NullPointerException("Null row.");
std::ostringstream str;
Row::ValueVec::const_iterator it = _pRow->values().begin();
Row::ValueVec::const_iterator end = _pRow->values().end();
ValueVec::const_iterator it = vals.begin();
ValueVec::const_iterator end = vals.end();
for (; it != end; ++it)
{
values.append(it->convert<std::string>());
values.append(_separator);
if (it->isNumeric())
{
str << std::right
<< std::fixed
<< std::setprecision(2);
}
else str << std::left;
str << std::setw(_width) << it->convert<std::string>();
}
values.replace(values.find_last_of(_separator), _separator.length(), EOL);
str << std::endl;
return values;
return formattedValues = str.str();
}
} } // namespace Poco::Data

View File

@@ -48,9 +48,16 @@ namespace Data {
const int RowIterator::POSITION_END = std::numeric_limits<std::size_t>::max();
RowIterator::RowIterator(RecordSet& recordSet, bool positionEnd):
_recordSet(recordSet),
_position((0 == recordSet.rowCount()) || positionEnd ? POSITION_END : 0)
RowIterator::RowIterator(RecordSet* pRecordSet, bool positionEnd):
_pRecordSet(pRecordSet),
_position((0 == pRecordSet->rowCount()) || positionEnd ? POSITION_END : 0)
{
}
RowIterator::RowIterator(const RowIterator& other):
_pRecordSet(other._pRecordSet),
_position(other._position)
{
}
@@ -60,35 +67,63 @@ RowIterator::~RowIterator()
}
void RowIterator::increment()
RowIterator& RowIterator::operator = (const RowIterator& other)
{
RowIterator tmp(other);
swap(tmp);
return *this;
}
void RowIterator::swap(RowIterator& other)
{
using std::swap;
swap(_pRecordSet, other._pRecordSet);
swap(_position, other._position);
}
void RowIterator::increment() const
{
if (POSITION_END == _position)
throw RangeException("End of iterator reached.");
if (_position < _recordSet.rowCount() - 1)
if (_position < _pRecordSet->rowCount() - 1)
++_position;
else
_position = POSITION_END;
}
void RowIterator::decrement()
void RowIterator::decrement() const
{
if (0 == _position)
throw RangeException("Beginning of iterator reached.");
else if (POSITION_END == _position)
_position = _recordSet.rowCount() - 1;
_position = _pRecordSet->rowCount() - 1;
else
--_position;
}
void RowIterator::setPosition(std::size_t pos) const
{
if (pos < _pRecordSet->rowCount())
_position = pos;
else if (pos == _pRecordSet->rowCount())
_position = POSITION_END;
else
throw RangeException("Invalid position argument.");
}
Row& RowIterator::operator * () const
{
if (POSITION_END == _position)
throw InvalidAccessException("End of iterator reached.");
return _recordSet.row(_position);
return _pRecordSet->row(_position);
}
@@ -97,37 +132,54 @@ Row* RowIterator::operator -> () const
if (POSITION_END == _position)
throw InvalidAccessException("End of iterator reached.");
return &_recordSet.row(_position);
return &_pRecordSet->row(_position);
}
std::size_t RowIterator::operator ++ ()
const RowIterator& RowIterator::operator ++ () const
{
increment();
return _position;
return *this;
}
std::size_t RowIterator::operator ++ (int)
RowIterator RowIterator::operator ++ (int) const
{
std::size_t oldPos = _position;
RowIterator old(*this);
increment();
return oldPos;
return old;
}
std::size_t RowIterator::operator -- ()
const RowIterator& RowIterator::operator -- () const
{
decrement();
return _position;
return *this;
}
std::size_t RowIterator::operator -- (int)
RowIterator RowIterator::operator -- (int) const
{
std::size_t oldPos = _position;
RowIterator old(*this);
decrement();
return oldPos;
return old;
}
RowIterator RowIterator::operator + (std::size_t diff) const
{
RowIterator ri(*this);
ri.setPosition(_position + diff);
return ri;
}
RowIterator RowIterator::operator - (std::size_t diff) const
{
if (diff > _position) throw RangeException("Invalid position argument.");
RowIterator ri(*this);
ri.setPosition(_position - diff);
return ri;
}

View File

@@ -49,6 +49,7 @@
#include "Poco/Exception.h"
#include <cstring>
#include <sstream>
#include <iomanip>
#include <set>
@@ -1000,12 +1001,25 @@ void DataTest::testRowFormat()
row1.append("field3", 3);
row1.append("field4", 4);
RowFormatter rf;
std::streamsize sz = rf.getWidth();
std::string line(sz * 5, '-');
std::ostringstream os;
os << "field0\tfield1\tfield2\tfield3\tfield4" << RowFormatter::EOL;
os << std::left << std::setw(sz) << "field0"
<< std::setw(sz) << "field1"
<< std::setw(sz) << "field2"
<< std::setw(sz) << "field3"
<< std::setw(sz) << "field4" << std::endl
<< line << std::endl;
assert (row1.namesToString() == os.str());
os.str("");
os << "0\t1\t2\t3\t4" << RowFormatter::EOL;
os << std::right << std::setw(sz) << "0"
<< std::setw(sz) << "1"
<< std::setw(sz) << "2"
<< std::setw(sz) << "3"
<< std::setw(sz) << "4" << std::endl;
assert (row1.valuesToString() == os.str());
}