mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-12 18:20:26 +01:00
Row and RowIterator done and tested (windows and linux)
This commit is contained in:
parent
08f8448478
commit
b2977d3df2
@ -211,6 +211,12 @@
|
||||
<File
|
||||
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">
|
||||
</File>
|
||||
@ -278,6 +284,12 @@
|
||||
<File
|
||||
RelativePath=".\src\RecordSet.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\Row.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\RowIterator.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\Session.cpp">
|
||||
</File>
|
||||
|
@ -12,7 +12,7 @@ objects = AbstractBinder AbstractBinding AbstractExtraction \
|
||||
AbstractExtractor AbstractPreparation AbstractPrepare \
|
||||
BLOB BLOBStream DataException Limit MetaColumn \
|
||||
PooledSessionHolder PooledSessionImpl \
|
||||
Range RecordSet Session SessionFactory SessionImpl \
|
||||
Range RecordSet Row RowIterator Session SessionFactory SessionImpl \
|
||||
Connector SessionPool Statement StatementCreator StatementImpl
|
||||
|
||||
target = PocoData
|
||||
|
@ -1051,6 +1051,21 @@ void ODBCDB2Test::testStoredFunction()
|
||||
}
|
||||
|
||||
|
||||
void ODBCDB2Test::testRowIterator()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateVectorsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->rowIterator();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCDB2Test::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@ -1305,6 +1320,7 @@ CppUnit::Test* ODBCDB2Test::suite()
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testStoredProcedure);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testStoredFunction);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testRowIterator);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ public:
|
||||
void testStoredFunction();
|
||||
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -915,6 +915,21 @@ void ODBCMySQLTest::testStoredFunction()
|
||||
}
|
||||
|
||||
|
||||
void ODBCMySQLTest::testRowIterator()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateVectorsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->rowIterator();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCMySQLTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
*_pSession << format("DROP %s IF EXISTS %s", type, name), now;
|
||||
@ -1152,7 +1167,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalExtraction);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testNull);
|
||||
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testRowIterator);
|
||||
return pSuite;
|
||||
}
|
||||
|
||||
|
@ -125,6 +125,7 @@ public:
|
||||
void testStoredFunction();
|
||||
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -1068,6 +1068,21 @@ void ODBCOracleTest::testStoredFunction()
|
||||
}
|
||||
|
||||
|
||||
void ODBCOracleTest::testRowIterator()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateVectorsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->rowIterator();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCOracleTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@ -1345,6 +1360,7 @@ CppUnit::Test* ODBCOracleTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalExtraction);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testRowIterator);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ public:
|
||||
void testStoredFunction();
|
||||
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -954,6 +954,21 @@ void ODBCPostgreSQLTest::testStoredFunction()
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::testRowIterator()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateVectorsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->rowIterator();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::configurePLPgSQL()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@ -1263,6 +1278,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunction);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testRowIterator);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ public:
|
||||
|
||||
void testStoredFunction();
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -1054,6 +1054,21 @@ void ODBCSQLServerTest::testStoredFunction()
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::testRowIterator()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateVectorsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->rowIterator();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@ -1321,6 +1336,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalExtraction);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testRowIterator);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -126,6 +126,7 @@ public:
|
||||
void testInternalStorageType();
|
||||
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -890,6 +890,21 @@ void ODBCSQLiteTest::testNull()
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLiteTest::testRowIterator()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateVectorsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->rowIterator();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLiteTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@ -1136,6 +1151,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalExtraction);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testRowIterator);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ public:
|
||||
void testInternalStorageType();
|
||||
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "Poco/Data/BLOB.h"
|
||||
#include "Poco/Data/StatementImpl.h"
|
||||
#include "Poco/Data/RecordSet.h"
|
||||
#include "Poco/Data/RowIterator.h"
|
||||
#include "Poco/Data/ODBC/Connector.h"
|
||||
#include "Poco/Data/ODBC/Utility.h"
|
||||
#include "Poco/Data/ODBC/Diagnostics.h"
|
||||
@ -50,6 +51,8 @@
|
||||
#include "Poco/Data/ODBC/ODBCStatementImpl.h"
|
||||
#include <sqltypes.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
using namespace Poco::Data;
|
||||
@ -2139,3 +2142,34 @@ void SQLExecutor::nulls()
|
||||
assert (rs.isNull("v"));
|
||||
assert (rs["v"] == "");
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::rowIterator()
|
||||
{
|
||||
std::string funct = "internalExtraction()";
|
||||
std::vector<Tuple<int, double, std::string> > v;
|
||||
v.push_back(Tuple<int, double, std::string>(1, 1.5f, "3"));
|
||||
v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4"));
|
||||
v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5"));
|
||||
v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6"));
|
||||
|
||||
try { *_pSession << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
RecordSet rset(*_pSession, "SELECT * FROM Vectors");
|
||||
|
||||
std::ostringstream osLoop;
|
||||
RecordSet::Iterator it = rset.begin();
|
||||
RecordSet::Iterator end = rset.end();
|
||||
for (int i = 1; it != end; ++it, ++i)
|
||||
{
|
||||
assert (it->get(0) == i);
|
||||
osLoop << *it;
|
||||
}
|
||||
assert (!osLoop.str().empty());
|
||||
|
||||
std::ostringstream osCopy;
|
||||
std::copy(rset.begin(), rset.end(), std::ostream_iterator<Row>(osCopy));
|
||||
assert (osLoop.str() == osCopy.str());
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ public:
|
||||
void internalStorageType();
|
||||
void nulls();
|
||||
void notNulls(const std::string& sqlState = "23502");
|
||||
void rowIterator();
|
||||
|
||||
private:
|
||||
Poco::Data::Session* _pSession;
|
||||
|
@ -1669,6 +1669,38 @@ void SQLiteTest::testNull()
|
||||
}
|
||||
|
||||
|
||||
void SQLiteTest::testRowIterator()
|
||||
{
|
||||
Session ses (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
|
||||
ses << "DROP TABLE IF EXISTS Vectors", now;
|
||||
ses << "CREATE TABLE Vectors (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now;
|
||||
|
||||
std::vector<Tuple<int, double, std::string> > v;
|
||||
v.push_back(Tuple<int, double, std::string>(1, 1.5f, "3"));
|
||||
v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4"));
|
||||
v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5"));
|
||||
v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6"));
|
||||
|
||||
ses << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now;
|
||||
|
||||
RecordSet rset(ses, "SELECT * FROM Vectors");
|
||||
|
||||
std::ostringstream osLoop;
|
||||
RecordSet::Iterator it = rset.begin();
|
||||
RecordSet::Iterator end = rset.end();
|
||||
for (int i = 1; it != end; ++it, ++i)
|
||||
{
|
||||
assert (it->get(0) == i);
|
||||
osLoop << *it;
|
||||
}
|
||||
assert (!osLoop.str().empty());
|
||||
|
||||
std::ostringstream osCopy;
|
||||
std::copy(rset.begin(), rset.end(), std::ostream_iterator<Row>(osCopy));
|
||||
assert (osLoop.str() == osCopy.str());
|
||||
}
|
||||
|
||||
|
||||
void SQLiteTest::setUp()
|
||||
{
|
||||
}
|
||||
@ -1742,6 +1774,7 @@ CppUnit::Test* SQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testInternalExtraction);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testPrimaryKeyConstraint);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testNull);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testRowIterator);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -111,6 +111,7 @@ public:
|
||||
void testInternalExtraction();
|
||||
void testPrimaryKeyConstraint();
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -78,6 +78,7 @@ class Data_API RecordSet: private Statement
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::size_t, Row*> RowMap;
|
||||
typedef RowIterator Iterator;
|
||||
|
||||
using Statement::isNull;
|
||||
|
||||
@ -132,8 +133,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const Row& row(std::size_t pos) const;
|
||||
/// Returns row at position pos.
|
||||
Row& row(std::size_t pos);
|
||||
/// Returns reference to row at position pos.
|
||||
/// Rows are lazy-created and cached.
|
||||
|
||||
template <class T>
|
||||
@ -278,7 +279,7 @@ private:
|
||||
std::size_t _currentRow;
|
||||
RowIterator* _pBegin;
|
||||
RowIterator* _pEnd;
|
||||
mutable RowMap _rowMap;
|
||||
RowMap _rowMap;
|
||||
};
|
||||
|
||||
|
||||
@ -380,7 +381,7 @@ inline bool RecordSet::isNull(const std::string& name)
|
||||
inline const RowIterator& RecordSet::end()
|
||||
{
|
||||
if (!_pEnd)
|
||||
_pEnd = new RowIterator(*this);
|
||||
_pEnd = new RowIterator(*this, true);
|
||||
|
||||
return *_pEnd;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Row.h
|
||||
//
|
||||
// $Id: //poco/Main/Data/include/Poco/Data/Row.h#7 $
|
||||
// $Id: //poco/Main/Data/include/Poco/Data/Row.h#1 $
|
||||
//
|
||||
// Library: Data
|
||||
// Package: DataCore
|
||||
@ -42,9 +42,11 @@
|
||||
|
||||
#include "Poco/Data/Data.h"
|
||||
#include "Poco/DynamicAny.h"
|
||||
#include "Poco/Tuple.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -55,10 +57,31 @@ class RecordSet;
|
||||
|
||||
|
||||
class Data_API Row
|
||||
/// Row class.
|
||||
/// Row class provides a data type for RecordSet iteration purposes.
|
||||
/// Dereferencing a RowIterator returns Row.
|
||||
/// Rows are sortable. The sortability is maintained at all times (i.e. there
|
||||
/// is always at least one column specified as a sorting criteria) .
|
||||
/// The default and minimal sorting criteria is the first field (position 0).
|
||||
/// The default sorting criteria can be replaced with any other field by
|
||||
/// calling replaceSortField() member function.
|
||||
/// Additional fields can be added to sorting criteria, in which case the
|
||||
/// field precedence corresponds to addition order (i.e. later added fields
|
||||
/// have lower sorting precedence).
|
||||
/// These features make Row suitable for use with standard sorted
|
||||
/// containers and algorithms. The main constraint is that all the rows from
|
||||
/// a set that is being sorted must have the same sorting criteria (i.e., the same
|
||||
/// set of fields must be in sorting criteria in the same order). Since rows don't
|
||||
/// know about each other, it is the programmer's responsibility to ensure this
|
||||
/// constraint is satisfied.
|
||||
/// Field names are a shared pointer to a vector of strings. For efficiency sake,
|
||||
/// a constructor taking a shared pointer to names vector argument is provided.
|
||||
/// The stream operator is provided for Row data type as a free-standing function.
|
||||
{
|
||||
public:
|
||||
enum Comparison
|
||||
typedef std::vector<std::string> NameVec;
|
||||
typedef SharedPtr<std::vector<std::string> > NameVecPtr;
|
||||
|
||||
enum ComparisonType
|
||||
{
|
||||
COMPARE_AS_INTEGER,
|
||||
COMPARE_AS_FLOAT,
|
||||
@ -70,9 +93,15 @@ public:
|
||||
Row();
|
||||
/// Creates the Row.
|
||||
|
||||
explicit Row(NameVecPtr pNames);
|
||||
/// Creates the Row.
|
||||
|
||||
~Row();
|
||||
/// Destroys the Row.
|
||||
|
||||
DynamicAny& get(std::size_t col);
|
||||
/// Returns the reference to data value at column location.
|
||||
|
||||
DynamicAny& operator [] (std::size_t col);
|
||||
/// Returns the reference to data value at column location.
|
||||
|
||||
@ -83,31 +112,78 @@ public:
|
||||
void append(const std::string& name, const T& val)
|
||||
/// Appends the value to the row.
|
||||
{
|
||||
if (!_pNames) _pNames = new NameVec;
|
||||
DynamicAny da = val;
|
||||
_values.push_back(da);
|
||||
_names.push_back(name);
|
||||
_pNames->push_back(name);
|
||||
if (1 == _values.size()) addSortField(0);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void set(std::size_t pos, const T& val)
|
||||
/// Assigns the value to the row.
|
||||
{
|
||||
try
|
||||
{
|
||||
_values.at(pos) = val;
|
||||
}catch (std::out_of_range&)
|
||||
{
|
||||
throw RangeException("Invalid column number.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void set(const std::string& name, const T& val)
|
||||
/// Assigns the value to the row.
|
||||
{
|
||||
NameVec::iterator it = _pNames->begin();
|
||||
NameVec::iterator end = _pNames->end();
|
||||
for (int i = 0; it != end; ++it, ++i)
|
||||
{
|
||||
if (*it == name)
|
||||
return set(i, val);
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
os << "Column with name " << name << " not found.";
|
||||
throw NotFoundException(os.str());
|
||||
}
|
||||
|
||||
std::size_t fieldCount() const;
|
||||
/// Returns the number of fields in this row.
|
||||
|
||||
void reset();
|
||||
/// Resets the row.
|
||||
/// Resets the row by clearing all field names and values.
|
||||
|
||||
void separator(const std::string& sep);
|
||||
/// Sets the separator.
|
||||
|
||||
void sortField(std::size_t pos);
|
||||
/// Sets the field used for sorting.
|
||||
void addSortField(std::size_t pos);
|
||||
/// Adds the field used for sorting.
|
||||
|
||||
void sortField(const std::string& name);
|
||||
/// Sets the field used for sorting.
|
||||
void addSortField(const std::string& name);
|
||||
/// Adds the field used for sorting.
|
||||
|
||||
const std::string& toStringN() const;
|
||||
void removeSortField(std::size_t pos);
|
||||
/// Removes the field used for sorting.
|
||||
|
||||
void removeSortField(const std::string& name);
|
||||
/// Removes the field used for sorting.
|
||||
|
||||
void replaceSortField(std::size_t oldPos, std::size_t newPos);
|
||||
/// Replaces the field used for sorting.
|
||||
|
||||
void replaceSortField(const std::string& oldName, const std::string& newName);
|
||||
/// Replaces the field used for sorting.
|
||||
|
||||
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& toStringV() const;
|
||||
const std::string valuesToString() const;
|
||||
/// Converts the row values to string, inserting separator
|
||||
/// string between fields and end-of-line at the end.
|
||||
|
||||
@ -120,21 +196,26 @@ public:
|
||||
bool operator < (const Row& other) const;
|
||||
/// Less-then operator.
|
||||
|
||||
void comparison(Comparison comp);
|
||||
/// Sets the type of comparison.
|
||||
NameVecPtr names();
|
||||
/// Returns the shared pointer to names vector.
|
||||
|
||||
private:
|
||||
typedef std::vector<DynamicAny> ValueVec;
|
||||
typedef Tuple<std::size_t, ComparisonType> SortTuple;
|
||||
typedef std::vector<SortTuple> SortMap;
|
||||
/// The type for map holding fields used for sorting criteria.
|
||||
/// Fields are added sequentially and have precedence that
|
||||
/// 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.
|
||||
|
||||
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;
|
||||
std::string _separator;
|
||||
NameVecPtr _pNames;
|
||||
ValueVec _values;
|
||||
SortMap _sortFields;
|
||||
};
|
||||
|
||||
|
||||
@ -152,7 +233,7 @@ inline std::size_t Row::fieldCount() const
|
||||
|
||||
inline void Row::reset()
|
||||
{
|
||||
_names.clear();
|
||||
_pNames->clear();
|
||||
_values.clear();
|
||||
}
|
||||
|
||||
@ -163,6 +244,24 @@ inline void Row::separator(const std::string& sep)
|
||||
}
|
||||
|
||||
|
||||
inline Row::NameVecPtr Row::names()
|
||||
{
|
||||
return _pNames;
|
||||
}
|
||||
|
||||
|
||||
inline DynamicAny& Row::operator [] (std::size_t col)
|
||||
{
|
||||
return get(col);
|
||||
}
|
||||
|
||||
|
||||
inline DynamicAny& Row::operator [] (const std::string& name)
|
||||
{
|
||||
return get(getPosition(name));
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// RowIterator.h
|
||||
//
|
||||
// $Id: //poco/Main/Data/include/Poco/Data/RowIterator.h#7 $
|
||||
// $Id: //poco/Main/Data/include/Poco/Data/RowIterator.h#1 $
|
||||
//
|
||||
// Library: Data
|
||||
// Package: DataCore
|
||||
@ -43,6 +43,7 @@
|
||||
#include "Poco/Data/Data.h"
|
||||
#include "Poco/Data/Row.h"
|
||||
#include "Poco/DynamicAny.h"
|
||||
#include <iterator>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -53,10 +54,16 @@ class RecordSet;
|
||||
|
||||
|
||||
class Data_API RowIterator
|
||||
/// RowIterator class is an interface to a row of RecordSet data.
|
||||
/// RowIterator class.
|
||||
{
|
||||
public:
|
||||
RowIterator(const RecordSet& recordSet, bool isEmpty = true);
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
typedef Row value_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef Row* pointer;
|
||||
typedef Row& reference;
|
||||
|
||||
RowIterator(RecordSet& recordSet, bool positionEnd = false);
|
||||
/// Creates the RowIterator and positions it at the beginning.
|
||||
|
||||
~RowIterator();
|
||||
@ -68,24 +75,23 @@ public:
|
||||
bool operator != (const RowIterator& other);
|
||||
/// Inequality operator.
|
||||
|
||||
const Row& operator * () const;
|
||||
/// Returns const reference to the current row.
|
||||
Row& operator * () const;
|
||||
/// Returns reference to the current row.
|
||||
|
||||
const Row& operator ++ ();
|
||||
/// Advances by one position and returns const reference
|
||||
/// to the current row.
|
||||
Row* operator -> () const;
|
||||
/// Returns pointer to the current row.
|
||||
|
||||
const Row& operator ++ (int);
|
||||
/// Advances by one position and returns const reference
|
||||
/// to the previous current row.
|
||||
std::size_t operator ++ ();
|
||||
/// Advances by one position and returns current position.
|
||||
|
||||
const Row& operator -- ();
|
||||
/// Goes back by one position and returns const reference
|
||||
/// to the current row.
|
||||
std::size_t operator ++ (int);
|
||||
/// Advances by one position and returns previous current position.
|
||||
|
||||
const Row& operator -- (int);
|
||||
/// Goes back by one position and returns const reference
|
||||
/// to the previous current row.
|
||||
std::size_t operator -- ();
|
||||
/// Goes back by one position and returns current position.
|
||||
|
||||
std::size_t operator -- (int);
|
||||
/// Goes back by one position and returns previouscurrent position.
|
||||
|
||||
private:
|
||||
RowIterator();
|
||||
@ -95,8 +101,8 @@ private:
|
||||
|
||||
static const int POSITION_END;
|
||||
|
||||
RecordSet& _recordSet;
|
||||
std::size_t _position;
|
||||
const RecordSet& _recordSet;
|
||||
};
|
||||
|
||||
|
||||
|
@ -121,13 +121,13 @@ 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());
|
||||
_pBegin = new RowIterator(*this);
|
||||
|
||||
return *_pBegin;
|
||||
}
|
||||
|
||||
|
||||
const Row& RecordSet::row(std::size_t pos) const
|
||||
Row& RecordSet::row(std::size_t pos)
|
||||
{
|
||||
if (pos > rowCount() - 1)
|
||||
throw RangeException("Invalid recordset row requested.");
|
||||
@ -136,12 +136,23 @@ const Row& RecordSet::row(std::size_t pos) const
|
||||
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));
|
||||
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));
|
||||
}
|
||||
else
|
||||
{
|
||||
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));
|
||||
}
|
||||
else
|
||||
pRow = it->second;
|
||||
|
||||
poco_check_ptr (pRow);
|
||||
return *pRow;
|
||||
|
226
Data/src/Row.cpp
226
Data/src/Row.cpp
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Row.cpp
|
||||
//
|
||||
// $Id: //poco/Main/Data/src/Row.cpp#2 $
|
||||
// $Id: //poco/Main/Data/src/Row.cpp#1 $
|
||||
//
|
||||
// Library: Data
|
||||
// Package: DataCore
|
||||
@ -52,60 +52,74 @@ const std::string Row::EOL = "\n";
|
||||
|
||||
std::ostream& operator << (std::ostream &os, const Row& row)
|
||||
{
|
||||
os << row.toStringV();
|
||||
os << row.valuesToString();
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
Row::Row():
|
||||
_separator("\t"),
|
||||
_sortField(0),
|
||||
_comparison(COMPARE_AS_STRING)
|
||||
Row::Row(): _separator("\t"), _pNames(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Row::Row(NameVecPtr pNames): _separator("\t"), _pNames(pNames)
|
||||
{
|
||||
if (!_pNames)
|
||||
throw NullPointerException();
|
||||
|
||||
_values.resize(_pNames->size());
|
||||
addSortField(0);
|
||||
}
|
||||
|
||||
|
||||
Row::~Row()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DynamicAny& Row::operator [] (std::size_t col)
|
||||
DynamicAny& Row::get(std::size_t col)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _values.at(col);
|
||||
}catch (std::range_error& re)
|
||||
}catch (std::out_of_range& 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();
|
||||
if (!_pNames)
|
||||
throw NullPointerException();
|
||||
|
||||
NameVec::const_iterator it = _pNames->begin();
|
||||
NameVec::const_iterator end = _pNames->end();
|
||||
std::size_t col = 0;
|
||||
for (; it != end; ++it, ++col)
|
||||
if (name == *it) break;
|
||||
|
||||
if (it == end)
|
||||
throw NotFoundException(name);
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
|
||||
void Row::sortField(std::size_t pos)
|
||||
void Row::addSortField(std::size_t pos)
|
||||
{
|
||||
poco_assert (pos <= _values.size());
|
||||
_sortField = pos;
|
||||
|
||||
SortMap::iterator it = _sortFields.begin();
|
||||
SortMap::iterator end = _sortFields.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->get<0>() == pos)
|
||||
throw InvalidAccessException("Field already in comparison set.");
|
||||
}
|
||||
|
||||
ComparisonType ct;
|
||||
if ((_values[pos].type() == typeid(Poco::Int8)) ||
|
||||
(_values[pos].type() == typeid(Poco::UInt8)) ||
|
||||
(_values[pos].type() == typeid(Poco::Int16)) ||
|
||||
@ -116,24 +130,103 @@ void Row::sortField(std::size_t pos)
|
||||
(_values[pos].type() == typeid(Poco::UInt64)) ||
|
||||
(_values[pos].type() == typeid(bool)))
|
||||
{
|
||||
comparison(COMPARE_AS_INTEGER);
|
||||
ct = COMPARE_AS_INTEGER;
|
||||
}
|
||||
else if ((_values[pos].type() == typeid(float)) ||
|
||||
(_values[pos].type() == typeid(double)))
|
||||
{
|
||||
comparison(COMPARE_AS_FLOAT);
|
||||
ct = COMPARE_AS_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
comparison(COMPARE_AS_STRING);
|
||||
ct = COMPARE_AS_STRING;
|
||||
}
|
||||
|
||||
_sortFields.push_back(SortTuple(pos, ct));
|
||||
}
|
||||
|
||||
|
||||
void Row::sortField(const std::string& name)
|
||||
void Row::addSortField(const std::string& name)
|
||||
{
|
||||
sortField(getPosition(name));
|
||||
addSortField(getPosition(name));
|
||||
}
|
||||
|
||||
|
||||
void Row::removeSortField(std::size_t pos)
|
||||
{
|
||||
SortMap::iterator it = _sortFields.begin();
|
||||
SortMap::iterator end = _sortFields.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->get<0>() == pos)
|
||||
{
|
||||
_sortFields.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Row::removeSortField(const std::string& name)
|
||||
{
|
||||
removeSortField(getPosition(name));
|
||||
}
|
||||
|
||||
|
||||
void Row::replaceSortField(std::size_t oldPos, std::size_t newPos)
|
||||
{
|
||||
poco_assert (oldPos <= _values.size());
|
||||
poco_assert (newPos <= _values.size());
|
||||
|
||||
ComparisonType ct;
|
||||
|
||||
if ((_values[newPos].type() == typeid(Poco::Int8)) ||
|
||||
(_values[newPos].type() == typeid(Poco::UInt8)) ||
|
||||
(_values[newPos].type() == typeid(Poco::Int16)) ||
|
||||
(_values[newPos].type() == typeid(Poco::UInt16)) ||
|
||||
(_values[newPos].type() == typeid(Poco::Int32)) ||
|
||||
(_values[newPos].type() == typeid(Poco::UInt32)) ||
|
||||
(_values[newPos].type() == typeid(Poco::Int64)) ||
|
||||
(_values[newPos].type() == typeid(Poco::UInt64)) ||
|
||||
(_values[newPos].type() == typeid(bool)))
|
||||
{
|
||||
ct = COMPARE_AS_INTEGER;
|
||||
}
|
||||
else if ((_values[newPos].type() == typeid(float)) ||
|
||||
(_values[newPos].type() == typeid(double)))
|
||||
{
|
||||
ct = COMPARE_AS_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ct = COMPARE_AS_STRING;
|
||||
}
|
||||
|
||||
SortMap::iterator it = _sortFields.begin();
|
||||
SortMap::iterator end = _sortFields.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->get<0>() == oldPos)
|
||||
{
|
||||
*it = SortTuple(newPos, ct);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw NotFoundException("Field not found");
|
||||
}
|
||||
|
||||
|
||||
void Row::replaceSortField(const std::string& oldName, const std::string& newName)
|
||||
{
|
||||
replaceSortField(getPosition(oldName), getPosition(newName));
|
||||
}
|
||||
|
||||
|
||||
void Row::resetSort()
|
||||
{
|
||||
_sortFields.clear();
|
||||
if (_values.size()) addSortField(0);
|
||||
}
|
||||
|
||||
|
||||
@ -157,12 +250,6 @@ bool Row::isEqualType(const Row& other) const
|
||||
}
|
||||
|
||||
|
||||
void Row::comparison(Comparison comp)
|
||||
{
|
||||
_comparison = comp;
|
||||
}
|
||||
|
||||
|
||||
bool Row::operator == (const Row& other) const
|
||||
{
|
||||
if (!isEqualSize(other)) return false;
|
||||
@ -188,57 +275,80 @@ bool Row::operator != (const Row& other) const
|
||||
|
||||
bool Row::operator < (const Row& other) const
|
||||
{
|
||||
if (_sortField != other._sortField)
|
||||
if (_sortFields != other._sortFields)
|
||||
throw InvalidAccessException("Rows compared have different sorting criteria.");
|
||||
|
||||
switch (_comparison)
|
||||
SortMap::const_iterator it = _sortFields.begin();
|
||||
SortMap::const_iterator end = _sortFields.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
case COMPARE_AS_INTEGER:
|
||||
return (_values[_sortField].convert<Poco::Int64>() <
|
||||
other._values[other._sortField].convert<Poco::Int64>());
|
||||
switch (it->get<1>())
|
||||
{
|
||||
case COMPARE_AS_INTEGER:
|
||||
if (_values[it->get<0>()].convert<Poco::Int64>() <
|
||||
other._values[it->get<0>()].convert<Poco::Int64>())
|
||||
return true;
|
||||
else if (_values[it->get<0>()].convert<Poco::Int64>() !=
|
||||
other._values[it->get<0>()].convert<Poco::Int64>())
|
||||
return false;
|
||||
break;
|
||||
|
||||
case COMPARE_AS_FLOAT:
|
||||
return (_values[_sortField].convert<double>() <
|
||||
other._values[other._sortField].convert<double>());
|
||||
case COMPARE_AS_FLOAT:
|
||||
if (_values[it->get<0>()].convert<double>() <
|
||||
other._values[it->get<0>()].convert<double>())
|
||||
return true;
|
||||
else if (_values[it->get<0>()].convert<double>() <
|
||||
other._values[it->get<0>()].convert<double>())
|
||||
return false;
|
||||
break;
|
||||
|
||||
case COMPARE_AS_STRING:
|
||||
return (_values[_sortField].convert<std::string>() <
|
||||
other._values[other._sortField].convert<std::string>());
|
||||
case COMPARE_AS_STRING:
|
||||
if (_values[it->get<0>()].convert<std::string>() <
|
||||
other._values[it->get<0>()].convert<std::string>())
|
||||
return true;
|
||||
else if (_values[it->get<0>()].convert<std::string>() <
|
||||
other._values[it->get<0>()].convert<std::string>())
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
throw IllegalStateException("Unknown comparison mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const std::string& Row::toStringV() const
|
||||
const std::string Row::valuesToString() const
|
||||
{
|
||||
_strValues.clear();
|
||||
std::vector<DynamicAny>::const_iterator it = _values.begin();
|
||||
std::vector<DynamicAny>::const_iterator end = _values.end();
|
||||
std::string strValues;
|
||||
ValueVec::const_iterator it = _values.begin();
|
||||
ValueVec::const_iterator end = _values.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
_strValues.append(it->convert<std::string>());
|
||||
_strValues.append(_separator);
|
||||
strValues.append(it->convert<std::string>());
|
||||
strValues.append(_separator);
|
||||
}
|
||||
_strValues.replace(_strValues.find_last_of(_separator), _separator.length(), EOL);
|
||||
strValues.replace(strValues.find_last_of(_separator), _separator.length(), EOL);
|
||||
|
||||
return _strValues;
|
||||
return strValues;
|
||||
}
|
||||
|
||||
|
||||
const std::string& Row::toStringN() const
|
||||
const std::string Row::namesToString() const
|
||||
{
|
||||
_strNames.clear();
|
||||
std::vector<std::string>::const_iterator it = _names.begin();
|
||||
std::vector<std::string>::const_iterator end = _names.end();
|
||||
if (!_pNames)
|
||||
throw NullPointerException();
|
||||
|
||||
std::string strNames;
|
||||
NameVec::const_iterator it = _pNames->begin();
|
||||
NameVec::const_iterator end = _pNames->end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
_strNames.append(*it);
|
||||
_strNames.append(_separator);
|
||||
strNames.append(*it);
|
||||
strNames.append(_separator);
|
||||
}
|
||||
_strNames.replace(_strNames.find_last_of(_separator), _separator.length(), EOL);
|
||||
strNames.replace(strNames.find_last_of(_separator), _separator.length(), EOL);
|
||||
|
||||
return _strNames;
|
||||
return strNames;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// RowIterator.cpp
|
||||
//
|
||||
// $Id: //poco/Main/Data/src/RowIterator.cpp#2 $
|
||||
// $Id: //poco/Main/Data/src/RowIterator.cpp#1 $
|
||||
//
|
||||
// Library: Data
|
||||
// Package: DataCore
|
||||
@ -48,9 +48,9 @@ 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(RecordSet& recordSet, bool positionEnd):
|
||||
_recordSet(recordSet),
|
||||
_position((0 == recordSet.rowCount()) || positionEnd ? POSITION_END : 0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -75,43 +75,59 @@ void RowIterator::increment()
|
||||
void RowIterator::decrement()
|
||||
{
|
||||
if (0 == _position)
|
||||
throw RangeException("End of iterator reached.");
|
||||
|
||||
--_position;
|
||||
throw RangeException("Beginning of iterator reached.");
|
||||
else if (POSITION_END == _position)
|
||||
_position = _recordSet.rowCount() - 1;
|
||||
else
|
||||
--_position;
|
||||
}
|
||||
|
||||
|
||||
const Row& RowIterator::operator * () const
|
||||
Row& RowIterator::operator * () const
|
||||
{
|
||||
if (POSITION_END == _position)
|
||||
throw InvalidAccessException("End of iterator reached.");
|
||||
|
||||
return _recordSet.row(_position);
|
||||
}
|
||||
|
||||
|
||||
const Row& RowIterator::operator ++ ()
|
||||
Row* RowIterator::operator -> () const
|
||||
{
|
||||
if (POSITION_END == _position)
|
||||
throw InvalidAccessException("End of iterator reached.");
|
||||
|
||||
return &_recordSet.row(_position);
|
||||
}
|
||||
|
||||
|
||||
std::size_t RowIterator::operator ++ ()
|
||||
{
|
||||
increment();
|
||||
return _recordSet.row(_position);
|
||||
return _position;
|
||||
}
|
||||
|
||||
|
||||
const Row& RowIterator::operator ++ (int)
|
||||
std::size_t RowIterator::operator ++ (int)
|
||||
{
|
||||
std::size_t oldPos = _position;
|
||||
increment();
|
||||
return _recordSet.row(_position - 1);
|
||||
return oldPos;
|
||||
}
|
||||
|
||||
|
||||
const Row& RowIterator::operator -- ()
|
||||
std::size_t RowIterator::operator -- ()
|
||||
{
|
||||
decrement();
|
||||
return _recordSet.row(_position);
|
||||
return _position;
|
||||
}
|
||||
|
||||
|
||||
const Row& RowIterator::operator -- (int)
|
||||
std::size_t RowIterator::operator -- (int)
|
||||
{
|
||||
std::size_t oldPos = _position;
|
||||
decrement();
|
||||
return _recordSet.row(_position + 1);
|
||||
return oldPos;
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,7 +38,6 @@
|
||||
#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"
|
||||
@ -46,7 +45,7 @@
|
||||
#include "Poco/Exception.h"
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
|
||||
using namespace Poco::Data;
|
||||
@ -59,6 +58,7 @@ using Poco::Int64;
|
||||
using Poco::UInt64;
|
||||
using Poco::InvalidAccessException;
|
||||
using Poco::RangeException;
|
||||
using Poco::NotFoundException;
|
||||
|
||||
|
||||
DataTest::DataTest(const std::string& name): CppUnit::TestCase(name)
|
||||
@ -576,13 +576,36 @@ 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 (row["field0"] == 0);
|
||||
assert (row["field1"] == 1);
|
||||
assert (row["field2"] == 2);
|
||||
assert (row["field3"] == 3);
|
||||
assert (row["field4"] == 4);
|
||||
|
||||
assert (row[0] == 0);
|
||||
assert (row[1] == 1);
|
||||
assert (row[2] == 2);
|
||||
assert (row[3] == 3);
|
||||
assert (row[4] == 4);
|
||||
|
||||
try
|
||||
{
|
||||
int i = row[5];
|
||||
fail ("must fail");
|
||||
}catch (RangeException&) {}
|
||||
|
||||
try
|
||||
{
|
||||
int i = row["a bad name"];
|
||||
fail ("must fail");
|
||||
}catch (NotFoundException&) {}
|
||||
|
||||
assert (5 == row.fieldCount());
|
||||
assert (row[0] == 0);
|
||||
assert (row["field0"] == 0);
|
||||
@ -595,12 +618,12 @@ void DataTest::testRow()
|
||||
assert (row[4] == 4);
|
||||
assert (row["field4"] == 4);
|
||||
|
||||
assert (row.toStringN() == std::string("field0\tfield1\tfield2\tfield3\tfield4") + Row::EOL);
|
||||
assert (row.namesToString() == 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);
|
||||
assert (row.namesToString() == 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);
|
||||
@ -615,30 +638,6 @@ void DataTest::testRow()
|
||||
|
||||
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);
|
||||
@ -648,6 +647,160 @@ void DataTest::testRow()
|
||||
row3.append("field4", 4);
|
||||
|
||||
assert (row3 == row);
|
||||
assert (!(row < row3 | row3 < row));
|
||||
|
||||
Row row4(row3.names());
|
||||
try
|
||||
{
|
||||
row4.set("badfieldname", 0);
|
||||
fail ("must fail");
|
||||
}catch (NotFoundException&) {}
|
||||
|
||||
row4.set("field0", 0);
|
||||
row4.set("field1", 1);
|
||||
row4.set("field2", 2);
|
||||
row4.set("field3", 3);
|
||||
row4.set("field4", 4);
|
||||
assert (row3 == row4);
|
||||
try
|
||||
{
|
||||
row4.set(5, 0);
|
||||
fail ("must fail");
|
||||
}catch (RangeException&) {}
|
||||
row4.set("field0", 1);
|
||||
assert (row3 != row4);
|
||||
assert (row3 < row4);
|
||||
}
|
||||
|
||||
|
||||
void DataTest::testRowSort()
|
||||
{
|
||||
Row row1;
|
||||
row1.append("0", 0);
|
||||
row1.append("1", 1);
|
||||
row1.append("2", 2);
|
||||
row1.append("3", 3);
|
||||
row1.append("4", 4);
|
||||
|
||||
Row row2;
|
||||
row2.append("0", 0);
|
||||
row2.append("1", 1);
|
||||
row2.append("2", 2);
|
||||
row2.append("3", 3);
|
||||
row2.append("4", 4);
|
||||
|
||||
std::multiset<Row> rowSet1;
|
||||
rowSet1.insert(row1);
|
||||
rowSet1.insert(row2);
|
||||
std::multiset<Row>::iterator it1 = rowSet1.begin();
|
||||
assert (row1 == *it1);
|
||||
++it1;
|
||||
assert (row2 == *it1);
|
||||
|
||||
Row row3;
|
||||
row3.append("0", 1);
|
||||
row3.append("1", 1);
|
||||
row3.append("2", 2);
|
||||
row3.append("3", 3);
|
||||
row3.append("4", 4);
|
||||
|
||||
Row row4;
|
||||
row4.append("0", 0);
|
||||
row4.append("1", 1);
|
||||
row4.append("2", 2);
|
||||
row4.append("3", 3);
|
||||
row4.append("4", 4);
|
||||
|
||||
std::set<Row> rowSet2;
|
||||
rowSet2.insert(row4);
|
||||
rowSet2.insert(row3);
|
||||
std::set<Row>::iterator it2 = rowSet2.begin();
|
||||
assert (row4 == *it2);
|
||||
++it2;
|
||||
assert (row3 == *it2);
|
||||
|
||||
Row row5;
|
||||
row5.append("0", 2);
|
||||
row5.append("1", 2);
|
||||
row5.append("2", 0);
|
||||
row5.append("3", 3);
|
||||
row5.append("4", 4);
|
||||
row5.addSortField("1");
|
||||
|
||||
Row row6;
|
||||
row6.append("0", 1);
|
||||
row6.append("1", 0);
|
||||
row6.append("2", 1);
|
||||
row6.append("3", 3);
|
||||
row6.append("4", 4);
|
||||
row6.addSortField("1");
|
||||
|
||||
Row row7;
|
||||
row7.append("0", 0);
|
||||
row7.append("1", 1);
|
||||
row7.append("2", 2);
|
||||
row7.append("3", 3);
|
||||
row7.append("4", 4);
|
||||
|
||||
std::set<Row> rowSet3;
|
||||
rowSet3.insert(row5);
|
||||
rowSet3.insert(row6);
|
||||
try
|
||||
{
|
||||
rowSet3.insert(row7);//has no same sort criteria
|
||||
fail ("must fail");
|
||||
} catch (InvalidAccessException&) {}
|
||||
|
||||
row7.addSortField("1");
|
||||
testRowStrictWeak(row7, row6, row5);
|
||||
rowSet3.insert(row7);
|
||||
|
||||
std::set<Row>::iterator it3 = rowSet3.begin();
|
||||
assert (row7 == *it3);
|
||||
++it3;
|
||||
assert (row6 == *it3);
|
||||
++it3;
|
||||
assert (row5 == *it3);
|
||||
|
||||
row5.replaceSortField("0", "2");
|
||||
row6.replaceSortField("0", "2");
|
||||
row7.replaceSortField("0", "2");
|
||||
|
||||
rowSet3.clear();
|
||||
rowSet3.insert(row7);
|
||||
rowSet3.insert(row6);
|
||||
rowSet3.insert(row5);
|
||||
|
||||
it3 = rowSet3.begin();
|
||||
assert (row5 == *it3);
|
||||
++it3;
|
||||
assert (row6 == *it3);
|
||||
++it3;
|
||||
assert (row7 == *it3);
|
||||
|
||||
row5.resetSort();
|
||||
row6.resetSort();
|
||||
row7.resetSort();
|
||||
|
||||
rowSet3.clear();
|
||||
rowSet3.insert(row5);
|
||||
rowSet3.insert(row6);
|
||||
rowSet3.insert(row7);
|
||||
|
||||
it3 = rowSet3.begin();
|
||||
assert (row7 == *it3);
|
||||
++it3;
|
||||
assert (row6 == *it3);
|
||||
++it3;
|
||||
assert (row5 == *it3);
|
||||
}
|
||||
|
||||
|
||||
void DataTest::testRowStrictWeak(const Row& row1, const Row& row2, const Row& row3)
|
||||
{
|
||||
assert (row1 < row2 && !(row2 < row1)); // antisymmetric
|
||||
assert (row1 < row2 && row2 < row3 && row1 < row3); // transitive
|
||||
assert (!(row1 < row1)); // irreflexive
|
||||
}
|
||||
|
||||
|
||||
@ -674,6 +827,7 @@ CppUnit::Test* DataTest::suite()
|
||||
CppUnit_addTest(pSuite, DataTest, testColumnDeque);
|
||||
CppUnit_addTest(pSuite, DataTest, testColumnList);
|
||||
CppUnit_addTest(pSuite, DataTest, testRow);
|
||||
CppUnit_addTest(pSuite, DataTest, testRowSort);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "Poco/Data/Data.h"
|
||||
#include "Poco/BinaryReader.h"
|
||||
#include "Poco/BinaryWriter.h"
|
||||
#include "Poco/Data/Row.h"
|
||||
#include "CppUnit/TestCase.h"
|
||||
|
||||
|
||||
@ -57,6 +58,7 @@ public:
|
||||
void testColumnDeque();
|
||||
void testColumnList();
|
||||
void testRow();
|
||||
void testRowSort();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
@ -64,6 +66,15 @@ public:
|
||||
static CppUnit::Test* suite();
|
||||
|
||||
private:
|
||||
void testRowStrictWeak(const Poco::Data::Row& row1,
|
||||
const Poco::Data::Row& row2,
|
||||
const Poco::Data::Row& row3);
|
||||
/// Strict weak ordering requirement for sorted containers
|
||||
/// as described in Josuttis "The Standard C++ Library"
|
||||
/// chapter 6.5. pg. 176.
|
||||
/// For this to pass, the following condition must be satisifed:
|
||||
/// row1 < row2 < row3
|
||||
|
||||
void writeToBLOB(Poco::BinaryWriter& writer);
|
||||
void readFromBLOB(Poco::BinaryReader& reader);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user