diff --git a/Data/Data_VS71.vcproj b/Data/Data_VS71.vcproj
index d57f868ec..39a1ac68e 100644
--- a/Data/Data_VS71.vcproj
+++ b/Data/Data_VS71.vcproj
@@ -211,6 +211,12 @@
+
+
+
+
@@ -278,6 +284,12 @@
+
+
+
+
diff --git a/Data/Makefile b/Data/Makefile
index 192ec134b..3c54670f0 100644
--- a/Data/Makefile
+++ b/Data/Makefile
@@ -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
diff --git a/Data/ODBC/testsuite/src/ODBCDB2Test.cpp b/Data/ODBC/testsuite/src/ODBCDB2Test.cpp
index d070dbc02..6e6ad07a5 100644
--- a/Data/ODBC/testsuite/src/ODBCDB2Test.cpp
+++ b/Data/ODBC/testsuite/src/ODBCDB2Test.cpp
@@ -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;
}
diff --git a/Data/ODBC/testsuite/src/ODBCDB2Test.h b/Data/ODBC/testsuite/src/ODBCDB2Test.h
index d7ce913cb..9579152aa 100644
--- a/Data/ODBC/testsuite/src/ODBCDB2Test.h
+++ b/Data/ODBC/testsuite/src/ODBCDB2Test.h
@@ -123,6 +123,7 @@ public:
void testStoredFunction();
void testNull();
+ void testRowIterator();
void setUp();
void tearDown();
diff --git a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp
index cc874b038..b499e6719 100644
--- a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp
+++ b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp
@@ -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;
}
diff --git a/Data/ODBC/testsuite/src/ODBCMySQLTest.h b/Data/ODBC/testsuite/src/ODBCMySQLTest.h
index dec6dde6f..1dacdb9a0 100644
--- a/Data/ODBC/testsuite/src/ODBCMySQLTest.h
+++ b/Data/ODBC/testsuite/src/ODBCMySQLTest.h
@@ -125,6 +125,7 @@ public:
void testStoredFunction();
void testNull();
+ void testRowIterator();
void setUp();
void tearDown();
diff --git a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp
index d15a31210..bd3d98267 100644
--- a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp
+++ b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp
@@ -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;
}
diff --git a/Data/ODBC/testsuite/src/ODBCOracleTest.h b/Data/ODBC/testsuite/src/ODBCOracleTest.h
index aac7ac712..69a8ac50e 100644
--- a/Data/ODBC/testsuite/src/ODBCOracleTest.h
+++ b/Data/ODBC/testsuite/src/ODBCOracleTest.h
@@ -123,6 +123,7 @@ public:
void testStoredFunction();
void testNull();
+ void testRowIterator();
void setUp();
void tearDown();
diff --git a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp
index 65526bcce..03d74cf2c 100644
--- a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp
+++ b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp
@@ -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;
}
diff --git a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.h b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.h
index 53a9466d8..4f0d59062 100644
--- a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.h
+++ b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.h
@@ -124,6 +124,7 @@ public:
void testStoredFunction();
void testNull();
+ void testRowIterator();
void setUp();
void tearDown();
diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp
index f4b85d1ad..20722fa6b 100644
--- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp
+++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp
@@ -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;
}
diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.h b/Data/ODBC/testsuite/src/ODBCSQLServerTest.h
index f82778c58..c05c2cce1 100644
--- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.h
+++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.h
@@ -126,6 +126,7 @@ public:
void testInternalStorageType();
void testNull();
+ void testRowIterator();
void setUp();
void tearDown();
diff --git a/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp
index 6fa161cc7..c66bf9aa5 100644
--- a/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp
+++ b/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp
@@ -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;
}
diff --git a/Data/ODBC/testsuite/src/ODBCSQLiteTest.h b/Data/ODBC/testsuite/src/ODBCSQLiteTest.h
index b3ed875dd..14756718b 100644
--- a/Data/ODBC/testsuite/src/ODBCSQLiteTest.h
+++ b/Data/ODBC/testsuite/src/ODBCSQLiteTest.h
@@ -120,6 +120,7 @@ public:
void testInternalStorageType();
void testNull();
+ void testRowIterator();
void setUp();
void tearDown();
diff --git a/Data/ODBC/testsuite/src/SQLExecutor.cpp b/Data/ODBC/testsuite/src/SQLExecutor.cpp
index 0118dc475..ddba66d23 100644
--- a/Data/ODBC/testsuite/src/SQLExecutor.cpp
+++ b/Data/ODBC/testsuite/src/SQLExecutor.cpp
@@ -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
#include
+#include
+#include
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 > v;
+ v.push_back(Tuple(1, 1.5f, "3"));
+ v.push_back(Tuple(2, 2.5f, "4"));
+ v.push_back(Tuple(3, 3.5f, "5"));
+ v.push_back(Tuple(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(osCopy));
+ assert (osLoop.str() == osCopy.str());
+}
diff --git a/Data/ODBC/testsuite/src/SQLExecutor.h b/Data/ODBC/testsuite/src/SQLExecutor.h
index ff9df3635..55e70479a 100644
--- a/Data/ODBC/testsuite/src/SQLExecutor.h
+++ b/Data/ODBC/testsuite/src/SQLExecutor.h
@@ -131,6 +131,7 @@ public:
void internalStorageType();
void nulls();
void notNulls(const std::string& sqlState = "23502");
+ void rowIterator();
private:
Poco::Data::Session* _pSession;
diff --git a/Data/SQLite/testsuite/src/SQLiteTest.cpp b/Data/SQLite/testsuite/src/SQLiteTest.cpp
index 6b16d9b7d..6fad5382c 100644
--- a/Data/SQLite/testsuite/src/SQLiteTest.cpp
+++ b/Data/SQLite/testsuite/src/SQLiteTest.cpp
@@ -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 > v;
+ v.push_back(Tuple(1, 1.5f, "3"));
+ v.push_back(Tuple(2, 2.5f, "4"));
+ v.push_back(Tuple(3, 3.5f, "5"));
+ v.push_back(Tuple(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(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;
}
diff --git a/Data/SQLite/testsuite/src/SQLiteTest.h b/Data/SQLite/testsuite/src/SQLiteTest.h
index 4b61e5f45..c24189b03 100644
--- a/Data/SQLite/testsuite/src/SQLiteTest.h
+++ b/Data/SQLite/testsuite/src/SQLiteTest.h
@@ -111,6 +111,7 @@ public:
void testInternalExtraction();
void testPrimaryKeyConstraint();
void testNull();
+ void testRowIterator();
void setUp();
void tearDown();
diff --git a/Data/include/Poco/Data/RecordSet.h b/Data/include/Poco/Data/RecordSet.h
index 6e6dc63c8..4bcaf7cf8 100644
--- a/Data/include/Poco/Data/RecordSet.h
+++ b/Data/include/Poco/Data/RecordSet.h
@@ -78,6 +78,7 @@ class Data_API RecordSet: private Statement
{
public:
typedef std::map 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
@@ -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;
}
diff --git a/Data/include/Poco/Data/Row.h b/Data/include/Poco/Data/Row.h
index 57a3f0ed9..ac8b93da2 100644
--- a/Data/include/Poco/Data/Row.h
+++ b/Data/include/Poco/Data/Row.h
@@ -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
#include
-#include
+#include
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 NameVec;
+ typedef SharedPtr > 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
+ 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
+ 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 ValueVec;
+ typedef Tuple SortTuple;
+ typedef std::vector 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 _names;
- std::vector _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
diff --git a/Data/include/Poco/Data/RowIterator.h b/Data/include/Poco/Data/RowIterator.h
index c405f64c9..0d628bd6b 100644
--- a/Data/include/Poco/Data/RowIterator.h
+++ b/Data/include/Poco/Data/RowIterator.h
@@ -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
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;
};
diff --git a/Data/src/RecordSet.cpp b/Data/src/RecordSet.cpp
index 6d42d2023..7a85abd27 100644
--- a/Data/src/RecordSet.cpp
+++ b/Data/src/RecordSet.cpp
@@ -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(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(pos)).name(), value(i, pos));
+ }
_rowMap.insert(RowMap::value_type(pos, pRow));
}
+ else
+ pRow = it->second;
poco_check_ptr (pRow);
return *pRow;
diff --git a/Data/src/Row.cpp b/Data/src/Row.cpp
index 3773ac702..8c3f83589 100644
--- a/Data/src/Row.cpp
+++ b/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::const_iterator it = _names.begin();
- std::vector::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() <
- other._values[other._sortField].convert());
+ switch (it->get<1>())
+ {
+ case COMPARE_AS_INTEGER:
+ if (_values[it->get<0>()].convert() <
+ other._values[it->get<0>()].convert())
+ return true;
+ else if (_values[it->get<0>()].convert() !=
+ other._values[it->get<0>()].convert())
+ return false;
+ break;
- case COMPARE_AS_FLOAT:
- return (_values[_sortField].convert() <
- other._values[other._sortField].convert());
+ case COMPARE_AS_FLOAT:
+ if (_values[it->get<0>()].convert() <
+ other._values[it->get<0>()].convert())
+ return true;
+ else if (_values[it->get<0>()].convert() <
+ other._values[it->get<0>()].convert())
+ return false;
+ break;
- case COMPARE_AS_STRING:
- return (_values[_sortField].convert() <
- other._values[other._sortField].convert());
+ case COMPARE_AS_STRING:
+ if (_values[it->get<0>()].convert() <
+ other._values[it->get<0>()].convert())
+ return true;
+ else if (_values[it->get<0>()].convert() <
+ other._values[it->get<0>()].convert())
+ 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::const_iterator it = _values.begin();
- std::vector::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());
- _strValues.append(_separator);
+ strValues.append(it->convert());
+ 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::const_iterator it = _names.begin();
- std::vector::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;
}
diff --git a/Data/src/RowIterator.cpp b/Data/src/RowIterator.cpp
index e5881b546..00331aedd 100644
--- a/Data/src/RowIterator.cpp
+++ b/Data/src/RowIterator.cpp
@@ -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::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;
}
diff --git a/Data/testsuite/src/DataTest.cpp b/Data/testsuite/src/DataTest.cpp
index 29fbbe1d3..7375446cd 100644
--- a/Data/testsuite/src/DataTest.cpp
+++ b/Data/testsuite/src/DataTest.cpp
@@ -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
#include
-#include