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 using namespace Poco::Data; @@ -570,6 +573,84 @@ void DataTest::testColumnList() } +void DataTest::testRow() +{ + Row row; + + row.append("field0", 0); + row.append("field1", 1); + row.append("field2", 2); + row.append("field3", 3); + row.append("field4", 4); + + assert (5 == row.fieldCount()); + assert (row[0] == 0); + assert (row["field0"] == 0); + assert (row[1] == 1); + assert (row["field1"] == 1); + assert (row[2] == 2); + assert (row["field2"] == 2); + assert (row[3] == 3); + assert (row["field3"] == 3); + assert (row[4] == 4); + assert (row["field4"] == 4); + + assert (row.toStringN() == std::string("field0\tfield1\tfield2\tfield3\tfield4") + Row::EOL); + std::ostringstream os; + os << row; + assert (os.str() == std::string("0\t1\t2\t3\t4") + Row::EOL); + row.separator(","); + assert (row.toStringN() == std::string("field0,field1,field2,field3,field4") + Row::EOL); + os.str(""); + os << row; + assert (os.str() == std::string("0,1,2,3,4") + Row::EOL); + + Row row2; + + row2.append("field0", 5); + row2.append("field1", 4); + row2.append("field2", 3); + row2.append("field3", 2); + row2.append("field4", 1); + + assert (row != row2); + + std::map rowMap; + rowMap.insert(std::map::value_type(row2, 0)); + rowMap.insert(std::map::value_type(row, 1)); + std::map::iterator it = rowMap.begin(); + assert (row == it->first); + ++it; + assert (row2 == it->first); + + rowMap.clear(); + row.sortField("field4"); + rowMap.insert(std::map::value_type(row, 0)); + try + { + rowMap.insert(std::map::value_type(row2, 1)); + fail ("must fail"); + }catch (InvalidAccessException&) {} + + row2.sortField("field4"); + rowMap.insert(std::map::value_type(row2, 1)); + it = rowMap.begin(); + assert (row2 == it->first); + ++it; + assert (row == it->first); + + Row row3; + + row3.append("field0", 0); + row3.append("field1", 1); + row3.append("field2", 2); + row3.append("field3", 3); + row3.append("field4", 4); + + assert (row3 == row); +} + + void DataTest::setUp() { } @@ -592,6 +673,7 @@ CppUnit::Test* DataTest::suite() CppUnit_addTest(pSuite, DataTest, testColumnVector); CppUnit_addTest(pSuite, DataTest, testColumnDeque); CppUnit_addTest(pSuite, DataTest, testColumnList); + CppUnit_addTest(pSuite, DataTest, testRow); return pSuite; } diff --git a/Data/testsuite/src/DataTest.h b/Data/testsuite/src/DataTest.h index 0e8bdf357..697e9c9da 100644 --- a/Data/testsuite/src/DataTest.h +++ b/Data/testsuite/src/DataTest.h @@ -56,6 +56,7 @@ public: void testColumnVector(); void testColumnDeque(); void testColumnList(); + void testRow(); void setUp(); void tearDown();