diff --git a/Data/Data_VS80.vcproj b/Data/Data_VS80.vcproj
index 9456d8055..8d34c37af 100644
--- a/Data/Data_VS80.vcproj
+++ b/Data/Data_VS80.vcproj
@@ -293,6 +293,14 @@
RelativePath=".\include\Poco\Data\RecordSet.h"
>
+
+
+
+
@@ -381,6 +389,14 @@
RelativePath=".\src\RecordSet.cpp"
>
+
+
+
+
diff --git a/Data/ODBC/src/Binder.cpp b/Data/ODBC/src/Binder.cpp
index c22a44630..ba31d4b51 100644
--- a/Data/ODBC/src/Binder.cpp
+++ b/Data/ODBC/src/Binder.cpp
@@ -215,22 +215,23 @@ void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
switch (val)
{
- case NULL_INT8: bindNull(pos, SQL_C_STINYINT); break;
- case NULL_UINT8: bindNull(pos, SQL_C_UTINYINT); break;
- case NULL_INT16: bindNull(pos, SQL_C_SSHORT); break;
- case NULL_UINT16: bindNull(pos, SQL_C_USHORT); break;
- case NULL_INT32: bindNull(pos, SQL_C_SLONG); break;
- case NULL_UINT32: bindNull(pos, SQL_C_ULONG); break;
- case NULL_INT64: bindNull(pos, SQL_C_SBIGINT); break;
- case NULL_UINT64: bindNull(pos, SQL_C_UBIGINT); break;
- case NULL_BOOL: bindNull(pos, Utility::boolDataType); break;
- case NULL_FLOAT: bindNull(pos, SQL_C_FLOAT); break;
- case NULL_DOUBLE: bindNull(pos, SQL_C_DOUBLE); break;
- case NULL_STRING: bindNull(pos, SQL_C_CHAR); break;
- case NULL_BLOB: bindNull(pos, SQL_C_BINARY); break;
- case NULL_TIMESTAMP: bindNull(pos, SQL_C_TIMESTAMP); break;
+ case NULL_GENERIC:
+ case NULL_INT8: bindNull(pos, SQL_C_STINYINT); break;
+ case NULL_UINT8: bindNull(pos, SQL_C_UTINYINT); break;
+ case NULL_INT16: bindNull(pos, SQL_C_SSHORT); break;
+ case NULL_UINT16: bindNull(pos, SQL_C_USHORT); break;
+ case NULL_INT32: bindNull(pos, SQL_C_SLONG); break;
+ case NULL_UINT32: bindNull(pos, SQL_C_ULONG); break;
+ case NULL_INT64: bindNull(pos, SQL_C_SBIGINT); break;
+ case NULL_UINT64: bindNull(pos, SQL_C_UBIGINT); break;
+ case NULL_BOOL: bindNull(pos, Utility::boolDataType); break;
+ case NULL_FLOAT: bindNull(pos, SQL_C_FLOAT); break;
+ case NULL_DOUBLE: bindNull(pos, SQL_C_DOUBLE); break;
+ case NULL_STRING: bindNull(pos, SQL_C_CHAR); break;
+ case NULL_BLOB: bindNull(pos, SQL_C_BINARY); break;
+ case NULL_TIMESTAMP: bindNull(pos, SQL_C_TIMESTAMP); break;
- default:
+ default:
throw DataFormatException("Unsupported data type.");
}
}
diff --git a/Data/ODBC/testsuite/src/SQLExecutor.cpp b/Data/ODBC/testsuite/src/SQLExecutor.cpp
index 63b07fe57..0118dc475 100644
--- a/Data/ODBC/testsuite/src/SQLExecutor.cpp
+++ b/Data/ODBC/testsuite/src/SQLExecutor.cpp
@@ -2068,7 +2068,7 @@ void SQLExecutor::notNulls(const std::string& sqlState)
{
try
{
- *_pSession << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(NULL_INT8), use(NULL_FLOAT), use(NULL_STRING), now;
+ *_pSession << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now;
fail ("must fail");
}catch (StatementException& se)
{
@@ -2083,7 +2083,7 @@ void SQLExecutor::nulls()
{
std::string funct = "nulls()";
- try { *_pSession << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(NULL_INT32), use(NULL_FLOAT), use(NULL_STRING), now; }
+ try { *_pSession << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
@@ -2115,12 +2115,12 @@ void SQLExecutor::nulls()
assert (!rs.isNull("r"));
assert (rs["v"] == "123");
- try { *_pSession << "UPDATE NullTest SET v = ? WHERE i = ?", use(NULL_STRING), use(i), now; }
+ try { *_pSession << "UPDATE NullTest SET v = ? WHERE i = ?", use(null), use(i), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
i = 2;
f = 3.4;
- try { *_pSession << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(NULL_FLOAT), use(NULL_STRING), now; }
+ try { *_pSession << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(null), use(null), now; }
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
rs = (*_pSession << "SELECT i, r, v FROM NullTest ORDER BY i ASC", now);
diff --git a/Data/include/Poco/Data/RecordSet.h b/Data/include/Poco/Data/RecordSet.h
index 8de745d90..6e6dc63c8 100644
--- a/Data/include/Poco/Data/RecordSet.h
+++ b/Data/include/Poco/Data/RecordSet.h
@@ -43,6 +43,7 @@
#include "Poco/Data/Data.h"
#include "Poco/Data/Extraction.h"
#include "Poco/Data/Statement.h"
+#include "Poco/Data/RowIterator.h"
#include "Poco/Data/BLOB.h"
#include "Poco/String.h"
#include "Poco/DynamicAny.h"
@@ -58,7 +59,7 @@ class Session;
class Data_API RecordSet: private Statement
/// RecordSet provides access to data returned from a query.
- /// Data access indexes (row and column) are 0-based, as usual in C++.
+ /// Data access indices (row and column) are 0-based, as usual in C++.
///
/// Recordset provides navigation methods to iterate through the
/// recordset, retrieval methods to extract data, and methods
@@ -76,6 +77,8 @@ class Data_API RecordSet: private Statement
/// a limit for the Statement.
{
public:
+ typedef std::map RowMap;
+
using Statement::isNull;
explicit RecordSet(const Statement& rStatement);
@@ -129,6 +132,10 @@ public:
}
}
+ const Row& row(std::size_t pos) const;
+ /// Returns row at position pos.
+ /// Rows are lazy-created and cached.
+
template
const T& value(std::size_t col, std::size_t row) const
/// Returns the reference to data value at [col, row] location.
@@ -166,10 +173,13 @@ public:
}
DynamicAny value(std::size_t col, std::size_t row) const;
- /// Returns the reference to data value at column, row location.
+ /// Returns the data value at column, row location.
DynamicAny value(const std::string& name, std::size_t row) const;
- /// Returns the reference to data value at named column, row location.
+ /// Returns the data value at named column, row location.
+
+ const RowIterator& begin();
+ /// Moves the row cursor to the first row and returns the pointer to row.
bool moveFirst();
/// Moves the row cursor to the first row.
@@ -190,6 +200,9 @@ 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.
///
@@ -262,7 +275,10 @@ private:
throw NotFoundException(format("Unknown column name: %s", name));
}
- std::size_t _currentRow;
+ std::size_t _currentRow;
+ RowIterator* _pBegin;
+ RowIterator* _pEnd;
+ mutable RowMap _rowMap;
};
@@ -361,6 +377,15 @@ inline bool RecordSet::isNull(const std::string& name)
}
+inline const RowIterator& RecordSet::end()
+{
+ if (!_pEnd)
+ _pEnd = new RowIterator(*this);
+
+ return *_pEnd;
+}
+
+
} } // namespace Poco::Data
diff --git a/Data/include/Poco/Data/Row.h b/Data/include/Poco/Data/Row.h
new file mode 100644
index 000000000..57a3f0ed9
--- /dev/null
+++ b/Data/include/Poco/Data/Row.h
@@ -0,0 +1,169 @@
+//
+// Row.h
+//
+// $Id: //poco/Main/Data/include/Poco/Data/Row.h#7 $
+//
+// Library: Data
+// Package: DataCore
+// Module: Row
+//
+// Definition of the Row class.
+//
+// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+
+#ifndef Data_Row_INCLUDED
+#define Data_Row_INCLUDED
+
+
+#include "Poco/Data/Data.h"
+#include "Poco/DynamicAny.h"
+#include
+#include
+#include
+
+
+namespace Poco {
+namespace Data {
+
+
+class RecordSet;
+
+
+class Data_API Row
+ /// Row class.
+{
+public:
+ enum Comparison
+ {
+ COMPARE_AS_INTEGER,
+ COMPARE_AS_FLOAT,
+ COMPARE_AS_STRING
+ };
+
+ static const std::string EOL;
+
+ Row();
+ /// Creates the Row.
+
+ ~Row();
+ /// Destroys the Row.
+
+ DynamicAny& operator [] (std::size_t col);
+ /// Returns the reference to data value at column location.
+
+ DynamicAny& operator [] (const std::string& name);
+ /// Returns the reference to data value at named column location.
+
+ template
+ void append(const std::string& name, const T& val)
+ /// Appends the value to the row.
+ {
+ DynamicAny da = val;
+ _values.push_back(da);
+ _names.push_back(name);
+ }
+
+ std::size_t fieldCount() const;
+ /// Returns the number of fields in this row.
+
+ void reset();
+ /// Resets the row.
+
+ void separator(const std::string& sep);
+ /// Sets the separator.
+
+ void sortField(std::size_t pos);
+ /// Sets the field used for sorting.
+
+ void sortField(const std::string& name);
+ /// Sets the field used for sorting.
+
+ const std::string& toStringN() const;
+ /// Converts the row names to string, inserting separator
+ /// string between fields and end-of-line at the end.
+
+ const std::string& toStringV() const;
+ /// Converts the row values to string, inserting separator
+ /// string between fields and end-of-line at the end.
+
+ bool operator == (const Row& other) const;
+ /// Equality operator.
+
+ bool operator != (const Row& other) const;
+ /// Inequality operator.
+
+ bool operator < (const Row& other) const;
+ /// Less-then operator.
+
+ void comparison(Comparison comp);
+ /// Sets the type of comparison.
+
+private:
+ std::size_t getPosition(const std::string& name);
+ bool isEqualSize(const Row& other) const;
+ bool isEqualType(const Row& other) const;
+
+ std::vector _names;
+ std::vector _values;
+ mutable std::string _strValues;
+ mutable std::string _strNames;
+ std::string _separator;
+ std::size_t _sortField;
+ Comparison _comparison;
+};
+
+
+Data_API std::ostream& operator << (std::ostream &os, const Row& row);
+
+
+///
+/// inlines
+///
+inline std::size_t Row::fieldCount() const
+{
+ return _values.size();
+}
+
+
+inline void Row::reset()
+{
+ _names.clear();
+ _values.clear();
+}
+
+
+inline void Row::separator(const std::string& sep)
+{
+ _separator = sep;
+}
+
+
+} } // namespace Poco::Data
+
+
+#endif // Data_Row_INCLUDED
diff --git a/Data/include/Poco/Data/RowIterator.h b/Data/include/Poco/Data/RowIterator.h
new file mode 100644
index 000000000..c405f64c9
--- /dev/null
+++ b/Data/include/Poco/Data/RowIterator.h
@@ -0,0 +1,121 @@
+//
+// RowIterator.h
+//
+// $Id: //poco/Main/Data/include/Poco/Data/RowIterator.h#7 $
+//
+// Library: Data
+// Package: DataCore
+// Module: RowIterator
+//
+// Definition of the RowIterator class.
+//
+// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+
+#ifndef Data_RowIterator_INCLUDED
+#define Data_RowIterator_INCLUDED
+
+
+#include "Poco/Data/Data.h"
+#include "Poco/Data/Row.h"
+#include "Poco/DynamicAny.h"
+
+
+namespace Poco {
+namespace Data {
+
+
+class RecordSet;
+
+
+class Data_API RowIterator
+ /// RowIterator class is an interface to a row of RecordSet data.
+{
+public:
+ RowIterator(const RecordSet& recordSet, bool isEmpty = true);
+ /// Creates the RowIterator and positions it at the beginning.
+
+ ~RowIterator();
+ /// Destroys the RowIterator.
+
+ bool operator == (const RowIterator& other);
+ /// Equality operator.
+
+ bool operator != (const RowIterator& other);
+ /// Inequality operator.
+
+ const Row& operator * () const;
+ /// Returns const reference to the current row.
+
+ const Row& operator ++ ();
+ /// Advances by one position and returns const reference
+ /// to the current row.
+
+ const Row& operator ++ (int);
+ /// Advances by one position and returns const reference
+ /// to the previous current row.
+
+ const Row& operator -- ();
+ /// Goes back by one position and returns const reference
+ /// to the current row.
+
+ const Row& operator -- (int);
+ /// Goes back by one position and returns const reference
+ /// to the previous current row.
+
+private:
+ RowIterator();
+
+ void increment();
+ void decrement();
+
+ static const int POSITION_END;
+
+ std::size_t _position;
+ const RecordSet& _recordSet;
+};
+
+
+///
+/// inlines
+///
+inline bool RowIterator::operator == (const RowIterator& other)
+{
+ return _position == other._position;
+}
+
+
+inline bool RowIterator::operator != (const RowIterator& other)
+{
+ return _position != other._position;
+}
+
+
+} } // namespace Poco::Data
+
+
+#endif // Data_RowIterator_INCLUDED
diff --git a/Data/src/RecordSet.cpp b/Data/src/RecordSet.cpp
index c87d8a19f..6d42d2023 100644
--- a/Data/src/RecordSet.cpp
+++ b/Data/src/RecordSet.cpp
@@ -44,20 +44,31 @@ namespace Data {
RecordSet::RecordSet(const Statement& rStatement):
Statement(rStatement),
- _currentRow(0)
+ _currentRow(0),
+ _pBegin(0),
+ _pEnd(0)
{
}
RecordSet::RecordSet(Session& rSession, const std::string& query):
Statement((rSession << query, now)),
- _currentRow(0)
+ _currentRow(0),
+ _pBegin(0),
+ _pEnd(0)
{
}
RecordSet::~RecordSet()
{
+ delete _pBegin;
+ delete _pEnd;
+
+ RowMap::iterator it = _rowMap.begin();
+ RowMap::iterator end = _rowMap.end();
+ for (; it != end; ++it)
+ delete it->second;
}
@@ -107,6 +118,36 @@ DynamicAny RecordSet::value(const std::string& name, std::size_t row) const
}
+const RowIterator& RecordSet::begin()
+{
+ if (!_pBegin)
+ _pBegin = new RowIterator(*this, 0 == extractions().size());
+
+ return *_pBegin;
+}
+
+
+const Row& RecordSet::row(std::size_t pos) const
+{
+ if (pos > rowCount() - 1)
+ throw RangeException("Invalid recordset row requested.");
+
+ RowMap::iterator it = _rowMap.find(pos);
+ Row* pRow = 0;
+ if (it == _rowMap.end())
+ {
+ pRow = new Row;
+ for (std::size_t i = 0; i < columnCount(); ++i)
+ pRow->append(metaColumn(static_cast(pos)).name(), value(i, pos));
+
+ _rowMap.insert(RowMap::value_type(pos, pRow));
+ }
+
+ poco_check_ptr (pRow);
+ return *pRow;
+}
+
+
bool RecordSet::moveFirst()
{
if (rowCount() > 0)
diff --git a/Data/src/Row.cpp b/Data/src/Row.cpp
new file mode 100644
index 000000000..3773ac702
--- /dev/null
+++ b/Data/src/Row.cpp
@@ -0,0 +1,245 @@
+//
+// Row.cpp
+//
+// $Id: //poco/Main/Data/src/Row.cpp#2 $
+//
+// Library: Data
+// Package: DataCore
+// Module: Row
+//
+// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+
+#include "Poco/Data/Row.h"
+#include "Poco/Exception.h"
+
+
+namespace Poco {
+namespace Data {
+
+
+#if defined(POCO_OS_FAMILY_WINDOWS)
+const std::string Row::EOL = "\r\n";
+#else
+const std::string Row::EOL = "\n";
+#endif
+
+
+
+std::ostream& operator << (std::ostream &os, const Row& row)
+{
+ os << row.toStringV();
+ return os;
+}
+
+
+Row::Row():
+ _separator("\t"),
+ _sortField(0),
+ _comparison(COMPARE_AS_STRING)
+{
+}
+
+
+Row::~Row()
+{
+}
+
+
+DynamicAny& Row::operator [] (std::size_t col)
+{
+ try
+ {
+ return _values.at(col);
+ }catch (std::range_error& re)
+ {
+ throw RangeException(re.what());
+ }
+}
+
+
+DynamicAny& Row::operator [] (const std::string& name)
+{
+ std::size_t col = getPosition(name);
+ return (*this)[col];
+}
+
+
+std::size_t Row::getPosition(const std::string& name)
+{
+ std::vector::const_iterator it = _names.begin();
+ std::vector::const_iterator end = _names.end();
+ std::size_t col = 0;
+ for (; it != end; ++it, ++col)
+ if (name == *it) break;
+
+ return col;
+}
+
+
+void Row::sortField(std::size_t pos)
+{
+ poco_assert (pos <= _values.size());
+ _sortField = pos;
+
+ if ((_values[pos].type() == typeid(Poco::Int8)) ||
+ (_values[pos].type() == typeid(Poco::UInt8)) ||
+ (_values[pos].type() == typeid(Poco::Int16)) ||
+ (_values[pos].type() == typeid(Poco::UInt16)) ||
+ (_values[pos].type() == typeid(Poco::Int32)) ||
+ (_values[pos].type() == typeid(Poco::UInt32)) ||
+ (_values[pos].type() == typeid(Poco::Int64)) ||
+ (_values[pos].type() == typeid(Poco::UInt64)) ||
+ (_values[pos].type() == typeid(bool)))
+ {
+ comparison(COMPARE_AS_INTEGER);
+ }
+ else if ((_values[pos].type() == typeid(float)) ||
+ (_values[pos].type() == typeid(double)))
+ {
+ comparison(COMPARE_AS_FLOAT);
+ }
+ else
+ {
+ comparison(COMPARE_AS_STRING);
+ }
+
+}
+
+
+void Row::sortField(const std::string& name)
+{
+ sortField(getPosition(name));
+}
+
+
+bool Row::isEqualSize(const Row& other) const
+{
+ return (other._values.size() == _values.size());
+}
+
+
+bool Row::isEqualType(const Row& other) const
+{
+ std::vector::const_iterator it = _values.begin();
+ std::vector::const_iterator end = _values.end();
+ for (int i = 0; it != end; ++it, ++i)
+ {
+ if (it->type() != other._values[i].type())
+ return false;
+ }
+
+ return true;
+}
+
+
+void Row::comparison(Comparison comp)
+{
+ _comparison = comp;
+}
+
+
+bool Row::operator == (const Row& other) const
+{
+ if (!isEqualSize(other)) return false;
+ if (!isEqualType(other)) return false;
+
+ std::vector::const_iterator it = _values.begin();
+ std::vector::const_iterator end = _values.end();
+ for (int i = 0; it != end; ++it, ++i)
+ {
+ if ((*it).convert() != other._values[i].convert())
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Row::operator != (const Row& other) const
+{
+ return !(*this == other);
+}
+
+
+bool Row::operator < (const Row& other) const
+{
+ if (_sortField != other._sortField)
+ throw InvalidAccessException("Rows compared have different sorting criteria.");
+
+ switch (_comparison)
+ {
+ case COMPARE_AS_INTEGER:
+ return (_values[_sortField].convert() <
+ other._values[other._sortField].convert());
+
+ case COMPARE_AS_FLOAT:
+ return (_values[_sortField].convert() <
+ other._values[other._sortField].convert());
+
+ case COMPARE_AS_STRING:
+ return (_values[_sortField].convert() <
+ other._values[other._sortField].convert());
+ }
+
+ throw IllegalStateException("Unknown comparison mode.");
+}
+
+
+const std::string& Row::toStringV() const
+{
+ _strValues.clear();
+ std::vector::const_iterator it = _values.begin();
+ std::vector::const_iterator end = _values.end();
+ for (; it != end; ++it)
+ {
+ _strValues.append(it->convert());
+ _strValues.append(_separator);
+ }
+ _strValues.replace(_strValues.find_last_of(_separator), _separator.length(), EOL);
+
+ return _strValues;
+}
+
+
+const std::string& Row::toStringN() const
+{
+ _strNames.clear();
+ std::vector::const_iterator it = _names.begin();
+ std::vector::const_iterator end = _names.end();
+ for (; it != end; ++it)
+ {
+ _strNames.append(*it);
+ _strNames.append(_separator);
+ }
+ _strNames.replace(_strNames.find_last_of(_separator), _separator.length(), EOL);
+
+ return _strNames;
+}
+
+
+} } // namespace Poco::Data
diff --git a/Data/src/RowIterator.cpp b/Data/src/RowIterator.cpp
new file mode 100644
index 000000000..e5881b546
--- /dev/null
+++ b/Data/src/RowIterator.cpp
@@ -0,0 +1,118 @@
+//
+// RowIterator.cpp
+//
+// $Id: //poco/Main/Data/src/RowIterator.cpp#2 $
+//
+// Library: Data
+// Package: DataCore
+// Module: RowIterator
+//
+// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+
+#include "Poco/Data/RowIterator.h"
+#include "Poco/Data/RecordSet.h"
+#undef min
+#undef max
+#include
+
+
+namespace Poco {
+namespace Data {
+
+
+const int RowIterator::POSITION_END = std::numeric_limits::max();
+
+
+RowIterator::RowIterator(const RecordSet& recordSet, bool isEmpty):
+ _position(isEmpty ? POSITION_END : 0),
+ _recordSet(recordSet)
+{
+}
+
+
+RowIterator::~RowIterator()
+{
+}
+
+
+void RowIterator::increment()
+{
+ if (POSITION_END == _position)
+ throw RangeException("End of iterator reached.");
+
+ if (_position < _recordSet.rowCount() - 1)
+ ++_position;
+ else
+ _position = POSITION_END;
+}
+
+
+void RowIterator::decrement()
+{
+ if (0 == _position)
+ throw RangeException("End of iterator reached.");
+
+ --_position;
+}
+
+
+const Row& RowIterator::operator * () const
+{
+ return _recordSet.row(_position);
+}
+
+
+const Row& RowIterator::operator ++ ()
+{
+ increment();
+ return _recordSet.row(_position);
+}
+
+
+const Row& RowIterator::operator ++ (int)
+{
+ increment();
+ return _recordSet.row(_position - 1);
+}
+
+
+const Row& RowIterator::operator -- ()
+{
+ decrement();
+ return _recordSet.row(_position);
+}
+
+
+const Row& RowIterator::operator -- (int)
+{
+ decrement();
+ return _recordSet.row(_position + 1);
+}
+
+
+} } // namespace Poco::Data
diff --git a/Data/testsuite/src/DataTest.cpp b/Data/testsuite/src/DataTest.cpp
index bc6965cf1..29fbbe1d3 100644
--- a/Data/testsuite/src/DataTest.cpp
+++ b/Data/testsuite/src/DataTest.cpp
@@ -38,12 +38,15 @@
#include "Poco/Data/BLOBStream.h"
#include "Poco/Data/MetaColumn.h"
#include "Poco/Data/Column.h"
+#include "Poco/Data/Row.h"
#include "Connector.h"
#include "Poco/BinaryReader.h"
#include "Poco/BinaryWriter.h"
#include "Poco/Types.h"
#include "Poco/Exception.h"
#include
+#include
+#include