ODBC generic nulls, added Row and RowIterator

This commit is contained in:
Aleksandar Fabijanic
2007-06-22 02:07:48 +00:00
parent 366ac99f7d
commit c9b65928db
11 changed files with 844 additions and 25 deletions

View File

@@ -293,6 +293,14 @@
RelativePath=".\include\Poco\Data\RecordSet.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\Row.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\RowIterator.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\Session.h"
>
@@ -381,6 +389,14 @@
RelativePath=".\src\RecordSet.cpp"
>
</File>
<File
RelativePath=".\src\Row.cpp"
>
</File>
<File
RelativePath=".\src\RowIterator.cpp"
>
</File>
<File
RelativePath=".\src\Session.cpp"
>

View File

@@ -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.");
}
}

View File

@@ -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);

View File

@@ -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<std::size_t, Row*> 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 <class T>
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

View File

@@ -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 <vector>
#include <string>
#include <iostream>
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 <typename T>
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<std::string> _names;
std::vector<DynamicAny> _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

View File

@@ -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

View File

@@ -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<UInt32>(pos)).name(), value(i, pos));
_rowMap.insert(RowMap::value_type(pos, pRow));
}
poco_check_ptr (pRow);
return *pRow;
}
bool RecordSet::moveFirst()
{
if (rowCount() > 0)

245
Data/src/Row.cpp Normal file
View File

@@ -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<std::string>::const_iterator it = _names.begin();
std::vector<std::string>::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<DynamicAny>::const_iterator it = _values.begin();
std::vector<DynamicAny>::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<DynamicAny>::const_iterator it = _values.begin();
std::vector<DynamicAny>::const_iterator end = _values.end();
for (int i = 0; it != end; ++it, ++i)
{
if ((*it).convert<std::string>() != other._values[i].convert<std::string>())
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<Poco::Int64>() <
other._values[other._sortField].convert<Poco::Int64>());
case COMPARE_AS_FLOAT:
return (_values[_sortField].convert<double>() <
other._values[other._sortField].convert<double>());
case COMPARE_AS_STRING:
return (_values[_sortField].convert<std::string>() <
other._values[other._sortField].convert<std::string>());
}
throw IllegalStateException("Unknown comparison mode.");
}
const std::string& Row::toStringV() const
{
_strValues.clear();
std::vector<DynamicAny>::const_iterator it = _values.begin();
std::vector<DynamicAny>::const_iterator end = _values.end();
for (; it != end; ++it)
{
_strValues.append(it->convert<std::string>());
_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<std::string>::const_iterator it = _names.begin();
std::vector<std::string>::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

118
Data/src/RowIterator.cpp Normal file
View File

@@ -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 <limits>
namespace Poco {
namespace Data {
const int RowIterator::POSITION_END = std::numeric_limits<std::size_t>::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

View File

@@ -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 <cstring>
#include <sstream>
#include <map>
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<Row, int> rowMap;
rowMap.insert(std::map<Row, int>::value_type(row2, 0));
rowMap.insert(std::map<Row, int>::value_type(row, 1));
std::map<Row, int>::iterator it = rowMap.begin();
assert (row == it->first);
++it;
assert (row2 == it->first);
rowMap.clear();
row.sortField("field4");
rowMap.insert(std::map<Row, int>::value_type(row, 0));
try
{
rowMap.insert(std::map<Row, int>::value_type(row2, 1));
fail ("must fail");
}catch (InvalidAccessException&) {}
row2.sortField("field4");
rowMap.insert(std::map<Row, int>::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;
}

View File

@@ -56,6 +56,7 @@ public:
void testColumnVector();
void testColumnDeque();
void testColumnList();
void testRow();
void setUp();
void tearDown();