mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-13 18:45:10 +01:00
SF [2047672] RecordSet Filtering
This commit is contained in:
parent
d6b81dca0f
commit
e409026fba
@ -333,6 +333,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\Row.h">
|
RelativePath=".\include\Poco\Data\Row.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\include\Poco\Data\RowFilter.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\RowFormatter.h">
|
RelativePath=".\include\Poco\Data\RowFormatter.h">
|
||||||
</File>
|
</File>
|
||||||
@ -424,6 +427,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\src\Row.cpp">
|
RelativePath=".\src\Row.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\RowFilter.cpp">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\RowFormatter.cpp">
|
RelativePath=".\src\RowFormatter.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
@ -461,6 +461,10 @@
|
|||||||
RelativePath=".\include\Poco\Data\Row.h"
|
RelativePath=".\include\Poco\Data\Row.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\include\Poco\Data\RowFilter.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\RowFormatter.h"
|
RelativePath=".\include\Poco\Data\RowFormatter.h"
|
||||||
>
|
>
|
||||||
@ -585,6 +589,10 @@
|
|||||||
RelativePath=".\src\Row.cpp"
|
RelativePath=".\src\Row.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\RowFilter.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\RowFormatter.cpp"
|
RelativePath=".\src\RowFormatter.cpp"
|
||||||
>
|
>
|
||||||
|
@ -466,6 +466,10 @@
|
|||||||
RelativePath=".\include\Poco\Data\Row.h"
|
RelativePath=".\include\Poco\Data\Row.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\include\Poco\Data\RowFilter.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\Poco\Data\RowFormatter.h"
|
RelativePath=".\include\Poco\Data\RowFormatter.h"
|
||||||
>
|
>
|
||||||
@ -590,6 +594,10 @@
|
|||||||
RelativePath=".\src\Row.cpp"
|
RelativePath=".\src\Row.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\RowFilter.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\RowFormatter.cpp"
|
RelativePath=".\src\RowFormatter.cpp"
|
||||||
>
|
>
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
include $(POCO_BASE)/build/rules/global
|
include $(POCO_BASE)/build/rules/global
|
||||||
|
|
||||||
objects = AbstractBinder AbstractBinding AbstractExtraction \
|
objects = AbstractBinder AbstractBinding AbstractExtraction AbstractExtractor \
|
||||||
AbstractExtractor AbstractPreparation AbstractPrepare ArchiveStrategy \
|
AbstractPreparation AbstractPrepare ArchiveStrategy AutoTransaction \
|
||||||
Bulk Connector BLOB BLOBStream DataException Date Limit MetaColumn \
|
Bulk Connector BLOB BLOBStream DataException Date Limit MetaColumn \
|
||||||
PooledSessionHolder PooledSessionImpl Position \
|
PooledSessionHolder PooledSessionImpl Position \
|
||||||
Range RecordSet Row RowFormatter RowIterator \
|
Range RecordSet Row RowFilter RowFormatter RowIterator \
|
||||||
SimpleRowFormatter Session SessionFactory SessionImpl \
|
SimpleRowFormatter Session SessionFactory SessionImpl \
|
||||||
SessionPool SQLChannel Statement StatementCreator StatementImpl Time
|
SessionPool SQLChannel Statement StatementCreator StatementImpl Time
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "Poco/UnicodeConverter.h"
|
#include "Poco/UnicodeConverter.h"
|
||||||
#include "Poco/Buffer.h"
|
#include "Poco/Buffer.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
|
#include <cstring>
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -166,6 +166,21 @@ void ODBCDB2Test::testBLOB()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ODBCDB2Test::testFilter()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
for (int i = 0; i < 8;)
|
||||||
|
{
|
||||||
|
recreateVectorsTable();
|
||||||
|
_pSession->setFeature("autoBind", bindValue(i));
|
||||||
|
_pSession->setFeature("autoExtract", bindValue(i+1));
|
||||||
|
_pExecutor->filter("SELECT * FROM Vectors ORDER BY i0 ASC", "i0");
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ODBCDB2Test::testStoredProcedure()
|
void ODBCDB2Test::testStoredProcedure()
|
||||||
{
|
{
|
||||||
if (!_pSession) fail ("Test not available.");
|
if (!_pSession) fail ("Test not available.");
|
||||||
@ -646,6 +661,7 @@ CppUnit::Test* ODBCDB2Test::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testTuple);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testTuple);
|
||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testTupleVector);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testTupleVector);
|
||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalExtraction);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalExtraction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCDB2Test, testFilter);
|
||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalBulkExtraction);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalBulkExtraction);
|
||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalStorageType);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testInternalStorageType);
|
||||||
CppUnit_addTest(pSuite, ODBCDB2Test, testStoredProcedure);
|
CppUnit_addTest(pSuite, ODBCDB2Test, testStoredProcedure);
|
||||||
|
@ -55,6 +55,7 @@ public:
|
|||||||
void testBareboneODBC();
|
void testBareboneODBC();
|
||||||
|
|
||||||
void testBLOB();
|
void testBLOB();
|
||||||
|
void testFilter();
|
||||||
|
|
||||||
void testStoredProcedure();
|
void testStoredProcedure();
|
||||||
void testStoredProcedureAny();
|
void testStoredProcedureAny();
|
||||||
|
@ -240,6 +240,21 @@ http://bugs.mysql.com/bug.php?id=7445
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ODBCMySQLTest::testFilter()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
for (int i = 0; i < 8;)
|
||||||
|
{
|
||||||
|
recreateVectorsTable();
|
||||||
|
_pSession->setFeature("autoBind", bindValue(i));
|
||||||
|
_pSession->setFeature("autoExtract", bindValue(i+1));
|
||||||
|
_pExecutor->filter("SELECT * FROM Vectors ORDER BY i0 ASC", "i0");
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ODBCMySQLTest::dropObject(const std::string& type, const std::string& name)
|
void ODBCMySQLTest::dropObject(const std::string& type, const std::string& name)
|
||||||
{
|
{
|
||||||
*_pSession << format("DROP %s IF EXISTS %s", type, name), now;
|
*_pSession << format("DROP %s IF EXISTS %s", type, name), now;
|
||||||
@ -466,6 +481,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testStoredProcedure);
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testStoredProcedure);
|
||||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testStoredFunction);
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testStoredFunction);
|
||||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalExtraction);
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalExtraction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testFilter);
|
||||||
//CppUnit_addTest(pSuite, ODBCOracleTest, testInternalBulkExtraction);
|
//CppUnit_addTest(pSuite, ODBCOracleTest, testInternalBulkExtraction);
|
||||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalStorageType);
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalStorageType);
|
||||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testNull);
|
CppUnit_addTest(pSuite, ODBCMySQLTest, testNull);
|
||||||
|
@ -65,6 +65,7 @@ public:
|
|||||||
void testNull();
|
void testNull();
|
||||||
|
|
||||||
void testMultipleResults();
|
void testMultipleResults();
|
||||||
|
void testFilter();
|
||||||
|
|
||||||
static CppUnit::Test* suite();
|
static CppUnit::Test* suite();
|
||||||
|
|
||||||
|
@ -905,6 +905,7 @@ CppUnit::Test* ODBCOracleTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredFunction);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredFunction);
|
||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testCursorStoredFunction);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testCursorStoredFunction);
|
||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalExtraction);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalExtraction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCOracleTest, testFilter);
|
||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalBulkExtraction);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalBulkExtraction);
|
||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalStorageType);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalStorageType);
|
||||||
CppUnit_addTest(pSuite, ODBCOracleTest, testNull);
|
CppUnit_addTest(pSuite, ODBCOracleTest, testNull);
|
||||||
|
@ -629,6 +629,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTuple);
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTuple);
|
||||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTupleVector);
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTupleVector);
|
||||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalExtraction);
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalExtraction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testFilter);
|
||||||
//On Linux, PostgreSQL driver returns SQL_NEED_DATA on SQLExecute (see ODBCStatementImpl::bindImpl() )
|
//On Linux, PostgreSQL driver returns SQL_NEED_DATA on SQLExecute (see ODBCStatementImpl::bindImpl() )
|
||||||
//this behavior is not expected and not handled for automatic binding
|
//this behavior is not expected and not handled for automatic binding
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
#ifdef POCO_OS_FAMILY_WINDOWS
|
||||||
|
@ -757,6 +757,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredProcedureDynamicAny);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredProcedureDynamicAny);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredFunction);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredFunction);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalExtraction);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalExtraction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testFilter);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalBulkExtraction);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalBulkExtraction);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalStorageType);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalStorageType);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull);
|
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull);
|
||||||
|
@ -382,6 +382,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
|
|||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTuple);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTuple);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTupleVector);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testTupleVector);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalExtraction);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalExtraction);
|
||||||
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testFilter);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalStorageType);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalStorageType);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testNull);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testNull);
|
||||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testRowIterator);
|
CppUnit_addTest(pSuite, ODBCSQLiteTest, testRowIterator);
|
||||||
|
@ -919,6 +919,21 @@ void ODBCTest::testInternalExtraction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ODBCTest::testFilter()
|
||||||
|
{
|
||||||
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
|
||||||
|
for (int i = 0; i < 8;)
|
||||||
|
{
|
||||||
|
recreateVectorsTable();
|
||||||
|
_pSession->setFeature("autoBind", bindValue(i));
|
||||||
|
_pSession->setFeature("autoExtract", bindValue(i+1));
|
||||||
|
_pExecutor->filter();
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ODBCTest::testInternalBulkExtraction()
|
void ODBCTest::testInternalBulkExtraction()
|
||||||
{
|
{
|
||||||
if (!_pSession) fail ("Test not available.");
|
if (!_pSession) fail ("Test not available.");
|
||||||
|
@ -135,6 +135,7 @@ public:
|
|||||||
virtual void testTupleVector();
|
virtual void testTupleVector();
|
||||||
|
|
||||||
virtual void testInternalExtraction();
|
virtual void testInternalExtraction();
|
||||||
|
virtual void testFilter();
|
||||||
virtual void testInternalBulkExtraction();
|
virtual void testInternalBulkExtraction();
|
||||||
virtual void testInternalStorageType();
|
virtual void testInternalStorageType();
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "Poco/Data/StatementImpl.h"
|
#include "Poco/Data/StatementImpl.h"
|
||||||
#include "Poco/Data/RecordSet.h"
|
#include "Poco/Data/RecordSet.h"
|
||||||
#include "Poco/Data/RowIterator.h"
|
#include "Poco/Data/RowIterator.h"
|
||||||
|
#include "Poco/Data/RowFilter.h"
|
||||||
#include "Poco/Data/BulkExtraction.h"
|
#include "Poco/Data/BulkExtraction.h"
|
||||||
#include "Poco/Data/BulkBinding.h"
|
#include "Poco/Data/BulkBinding.h"
|
||||||
#include "Poco/Data/SQLChannel.h"
|
#include "Poco/Data/SQLChannel.h"
|
||||||
@ -72,6 +73,8 @@ using Poco::Data::Statement;
|
|||||||
using Poco::Data::RecordSet;
|
using Poco::Data::RecordSet;
|
||||||
using Poco::Data::Column;
|
using Poco::Data::Column;
|
||||||
using Poco::Data::Row;
|
using Poco::Data::Row;
|
||||||
|
using Poco::Data::RowFilter;
|
||||||
|
using Poco::Data::RowIterator;
|
||||||
using Poco::Data::SQLChannel;
|
using Poco::Data::SQLChannel;
|
||||||
using Poco::Data::LimitException;
|
using Poco::Data::LimitException;
|
||||||
using Poco::Data::BindingException;
|
using Poco::Data::BindingException;
|
||||||
@ -2526,6 +2529,86 @@ void SQLExecutor::internalExtraction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLExecutor::filter(const std::string& query, const std::string& intFldName)
|
||||||
|
{
|
||||||
|
std::string funct = "filter()";
|
||||||
|
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 { session() << "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); }
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Statement stmt = (session() << query, now);
|
||||||
|
RecordSet rset(stmt);
|
||||||
|
assert (rset.totalRowCount() == 4);
|
||||||
|
RowFilter::Ptr pRF = new RowFilter(&rset);
|
||||||
|
assert (pRF->isEmpty());
|
||||||
|
pRF->add(intFldName, RowFilter::VALUE_EQUAL, 1);
|
||||||
|
assert (!pRF->isEmpty());
|
||||||
|
|
||||||
|
DynamicAny da;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
da = rset.value(0, 1);
|
||||||
|
fail ("must fail");
|
||||||
|
} catch (InvalidAccessException&)
|
||||||
|
{
|
||||||
|
da = rset.value(0, 1, false);
|
||||||
|
assert (2 == da);
|
||||||
|
da = rset.value(0, 0);
|
||||||
|
assert (1 == da);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (rset.rowCount() == 1);
|
||||||
|
assert (rset.moveFirst());
|
||||||
|
assert (1 == rset[intFldName]);
|
||||||
|
assert (!rset.moveNext());
|
||||||
|
pRF->add("flt0", RowFilter::VALUE_LESS_THAN_OR_EQUAL, 3.5f);
|
||||||
|
assert (rset.rowCount() == 3);
|
||||||
|
assert (rset.moveNext());
|
||||||
|
assert (2.5 == rset["flt0"]);
|
||||||
|
assert (rset.moveNext());
|
||||||
|
assert (3.5 == rset["flt0"]);
|
||||||
|
assert (!rset.moveNext());
|
||||||
|
pRF->add("str0", RowFilter::VALUE_EQUAL, 6);
|
||||||
|
assert (rset.rowCount() == 4);
|
||||||
|
assert (rset.moveLast());
|
||||||
|
assert ("6" == rset["str0"]);
|
||||||
|
pRF->remove("flt0");
|
||||||
|
assert (rset.rowCount() == 2);
|
||||||
|
assert (rset.moveFirst());
|
||||||
|
assert ("3" == rset["str0"]);
|
||||||
|
assert (rset.moveNext());
|
||||||
|
assert ("6" == rset["str0"]);
|
||||||
|
pRF->remove(intFldName);
|
||||||
|
pRF->remove("str0");
|
||||||
|
assert (pRF->isEmpty());
|
||||||
|
pRF->add("str0", "!=", 3);
|
||||||
|
assert (rset.rowCount() == 3);
|
||||||
|
|
||||||
|
RowFilter::Ptr pRF1 = new RowFilter(pRF, RowFilter::OP_AND);
|
||||||
|
pRF1->add(intFldName, "==", 2);
|
||||||
|
assert (rset.rowCount() == 1);
|
||||||
|
pRF1->add(intFldName, "<", 2);
|
||||||
|
assert (rset.rowCount() == 1);
|
||||||
|
pRF1->add(intFldName, ">", 3);
|
||||||
|
assert (rset.rowCount() == 2);
|
||||||
|
pRF->removeFilter(pRF1);
|
||||||
|
pRF->remove("str0");
|
||||||
|
assert (pRF->isEmpty());
|
||||||
|
assert (rset.rowCount() == 4);
|
||||||
|
}
|
||||||
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||||
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SQLExecutor::internalBulkExtraction()
|
void SQLExecutor::internalBulkExtraction()
|
||||||
{
|
{
|
||||||
std::string funct = "internalBulkExtraction()";
|
std::string funct = "internalBulkExtraction()";
|
||||||
@ -2665,7 +2748,8 @@ void SQLExecutor::notNulls(const std::string& sqlState)
|
|||||||
{
|
{
|
||||||
//make sure we're failing for the right reason
|
//make sure we're failing for the right reason
|
||||||
//default sqlState value is "23502"; some drivers report "HY???" codes
|
//default sqlState value is "23502"; some drivers report "HY???" codes
|
||||||
assert (sqlState == se.diagnostics().sqlState(0));
|
if (se.diagnostics().fields().size())
|
||||||
|
assert (sqlState == se.diagnostics().sqlState(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2686,12 +2770,18 @@ void SQLExecutor::nulls()
|
|||||||
assert (rs.isNull("r"));
|
assert (rs.isNull("r"));
|
||||||
assert (rs.isNull("v"));
|
assert (rs.isNull("v"));
|
||||||
assert (rs["v"] != "");
|
assert (rs["v"] != "");
|
||||||
|
assert (rs.nvl<int>("i") == 0);
|
||||||
|
assert (rs.nvl("i", -1) == -1);
|
||||||
|
assert (rs.nvl<double>("r") == double());
|
||||||
|
assert (rs.nvl("r", -1.5) == -1.5);
|
||||||
|
assert (rs.nvl<std::string>("v") == "");
|
||||||
|
assert (rs.nvl("v", "123") == "123");
|
||||||
try { session() << "DELETE FROM NullTest", now; }
|
try { session() << "DELETE FROM NullTest", now; }
|
||||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||||
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
double f = 1.2;
|
double f = 1.5;
|
||||||
std::string s = "123";
|
std::string s = "123";
|
||||||
|
|
||||||
try { session() << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(f), use(s), now; }
|
try { session() << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(f), use(s), now; }
|
||||||
@ -2705,7 +2795,12 @@ void SQLExecutor::nulls()
|
|||||||
assert (!rs.isNull("v"));
|
assert (!rs.isNull("v"));
|
||||||
assert (!rs.isNull("r"));
|
assert (!rs.isNull("r"));
|
||||||
assert (rs["v"] == "123");
|
assert (rs["v"] == "123");
|
||||||
|
assert (rs.nvl<int>("i") == 1);
|
||||||
|
assert (rs.nvl("i", -1) == 1);
|
||||||
|
assert (rs.nvl<double>("r") == 1.5);
|
||||||
|
assert (rs.nvl("r", -1.5) == 1.5);
|
||||||
|
assert (rs.nvl<std::string>("v") == "123");
|
||||||
|
assert (rs.nvl("v", "456") == "123");
|
||||||
try { session() << "UPDATE NullTest SET v = ? WHERE i = ?", use(null), use(i), now; }
|
try { session() << "UPDATE NullTest SET v = ? WHERE i = ?", use(null), use(i), now; }
|
||||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||||
@ -2803,6 +2898,19 @@ void SQLExecutor::rowIterator()
|
|||||||
std::ostringstream osCopy;
|
std::ostringstream osCopy;
|
||||||
std::copy(rset.begin(), rset.end(), std::ostream_iterator<Row>(osCopy));
|
std::copy(rset.begin(), rset.end(), std::ostream_iterator<Row>(osCopy));
|
||||||
assert (osLoop.str() == osCopy.str());
|
assert (osLoop.str() == osCopy.str());
|
||||||
|
|
||||||
|
RowFilter::Ptr pRF = new RowFilter(&rset);
|
||||||
|
assert (pRF->isEmpty());
|
||||||
|
pRF->add("str0", RowFilter::VALUE_EQUAL, 1);
|
||||||
|
assert (!pRF->isEmpty());
|
||||||
|
it = rset.begin();
|
||||||
|
end = rset.end();
|
||||||
|
for (int i = 1; it != end; ++it, ++i)
|
||||||
|
{
|
||||||
|
assert (it->get(0) == i);
|
||||||
|
assert (1 == i);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -484,6 +484,10 @@ public:
|
|||||||
void tupleVector();
|
void tupleVector();
|
||||||
|
|
||||||
void internalExtraction();
|
void internalExtraction();
|
||||||
|
void filter(const std::string& query =
|
||||||
|
"SELECT * FROM Vectors ORDER BY int0 ASC",
|
||||||
|
const std::string& intFldName = "int0");
|
||||||
|
|
||||||
void internalBulkExtraction();
|
void internalBulkExtraction();
|
||||||
void internalStorageType();
|
void internalStorageType();
|
||||||
void nulls();
|
void nulls();
|
||||||
|
@ -56,7 +56,7 @@ namespace Poco {
|
|||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
|
|
||||||
class Session;
|
class RowFilter;
|
||||||
|
|
||||||
|
|
||||||
class Data_API RecordSet: private Statement
|
class Data_API RecordSet: private Statement
|
||||||
@ -112,7 +112,16 @@ public:
|
|||||||
/// Assignment operator.
|
/// Assignment operator.
|
||||||
|
|
||||||
std::size_t rowCount() const;
|
std::size_t rowCount() const;
|
||||||
/// Returns the number of rows in the recordset.
|
/// Returns the number of rows in the RecordSet.
|
||||||
|
/// The number of rows reported is dependent on filtering.
|
||||||
|
/// Due to the need for filter conditions checking,
|
||||||
|
/// this function may suffer significant performance penalty
|
||||||
|
/// for large recordsets, so it should be used judiciously.
|
||||||
|
/// Use totalRowCount() to obtain the total number of rows.
|
||||||
|
|
||||||
|
std::size_t totalRowCount() const;
|
||||||
|
/// Returns the total number of rows in the RecordSet.
|
||||||
|
/// The number of rows reported is independent of filtering.
|
||||||
|
|
||||||
std::size_t columnCount() const;
|
std::size_t columnCount() const;
|
||||||
/// Returns the number of rows in the recordset.
|
/// Returns the number of rows in the recordset.
|
||||||
@ -154,9 +163,12 @@ public:
|
|||||||
/// Rows are lazy-created and cached.
|
/// Rows are lazy-created and cached.
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
const T& value(std::size_t col, std::size_t row) const
|
const T& value(std::size_t col, std::size_t row, bool useFilter = true) const
|
||||||
/// Returns the reference to data value at [col, row] location.
|
/// Returns the reference to data value at [col, row] location.
|
||||||
{
|
{
|
||||||
|
if (useFilter && isFiltered() && !isAllowed(row))
|
||||||
|
throw InvalidAccessException("Row not allowed");
|
||||||
|
|
||||||
switch (storage())
|
switch (storage())
|
||||||
{
|
{
|
||||||
case STORAGE_VECTOR:
|
case STORAGE_VECTOR:
|
||||||
@ -181,9 +193,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
const T& value(const std::string& name, std::size_t row) const
|
const T& value(const std::string& name, std::size_t row, bool useFilter = true) const
|
||||||
/// Returns the reference to data value at named column, row location.
|
/// Returns the reference to data value at named column, row location.
|
||||||
{
|
{
|
||||||
|
if (useFilter && isFiltered() && !isAllowed(row))
|
||||||
|
throw InvalidAccessException("Row not allowed");
|
||||||
|
|
||||||
switch (storage())
|
switch (storage())
|
||||||
{
|
{
|
||||||
case STORAGE_VECTOR:
|
case STORAGE_VECTOR:
|
||||||
@ -207,19 +222,33 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicAny value(std::size_t col, std::size_t row) const;
|
DynamicAny value(std::size_t col, std::size_t row, bool checkFiltering = true) const;
|
||||||
/// Returns the 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;
|
DynamicAny value(const std::string& name, std::size_t row, bool checkFiltering = true) const;
|
||||||
/// Returns the data value at named column, row location.
|
/// Returns the data value at named column, row location.
|
||||||
|
|
||||||
DynamicAny nvl(const std::string& name, const DynamicAny& deflt) const;
|
template <typename T>
|
||||||
|
DynamicAny nvl(const std::string& name, const T& deflt = T()) const
|
||||||
/// Returns the value in the named column of the current row
|
/// Returns the value in the named column of the current row
|
||||||
/// if the value is not NULL, or deflt otherwise.
|
/// if the value is not NULL, or deflt otherwise.
|
||||||
|
{
|
||||||
DynamicAny nvl(std::size_t index, const DynamicAny& deflt) const;
|
if (isNull(name))
|
||||||
|
return DynamicAny(deflt);
|
||||||
|
else
|
||||||
|
return value(name, _currentRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DynamicAny nvl(std::size_t index, const T& deflt = T()) const
|
||||||
/// Returns the value in the given column of the current row
|
/// Returns the value in the given column of the current row
|
||||||
/// if the value is not NULL, or deflt otherwise.
|
/// if the value is not NULL, or deflt otherwise.
|
||||||
|
{
|
||||||
|
if (isNull(index, _currentRow))
|
||||||
|
return DynamicAny(deflt);
|
||||||
|
else
|
||||||
|
return value(index, _currentRow);
|
||||||
|
}
|
||||||
|
|
||||||
ConstIterator& begin() const;
|
ConstIterator& begin() const;
|
||||||
/// Returns the const row iterator.
|
/// Returns the const row iterator.
|
||||||
@ -315,6 +344,9 @@ public:
|
|||||||
/// Copies the column names and values to the target output stream.
|
/// Copies the column names and values to the target output stream.
|
||||||
/// Copied strings are formatted by the current RowFormatter.
|
/// Copied strings are formatted by the current RowFormatter.
|
||||||
|
|
||||||
|
bool isFiltered() const;
|
||||||
|
/// Returns true if recordset is filtered.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RecordSet();
|
RecordSet();
|
||||||
|
|
||||||
@ -384,10 +416,25 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isAllowed(std::size_t row) const;
|
||||||
|
/// Returns true if the specified row is allowed by the
|
||||||
|
/// currently active filter.
|
||||||
|
|
||||||
|
void filter(RowFilter* pFilter);
|
||||||
|
/// Sets the filter for the RecordSet.
|
||||||
|
|
||||||
|
|
||||||
|
RowFilter* getFilter();
|
||||||
|
/// Returns the filter associated with the RecordSet.
|
||||||
|
|
||||||
std::size_t _currentRow;
|
std::size_t _currentRow;
|
||||||
RowIterator* _pBegin;
|
RowIterator* _pBegin;
|
||||||
RowIterator* _pEnd;
|
RowIterator* _pEnd;
|
||||||
RowMap _rowMap;
|
RowMap _rowMap;
|
||||||
|
RowFilter* _pFilter;
|
||||||
|
|
||||||
|
friend class RowIterator;
|
||||||
|
friend class RowFilter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -397,11 +444,11 @@ private:
|
|||||||
|
|
||||||
inline Data_API std::ostream& operator << (std::ostream &os, const RecordSet& rs)
|
inline Data_API std::ostream& operator << (std::ostream &os, const RecordSet& rs)
|
||||||
{
|
{
|
||||||
return rs.copy(os);
|
return rs.copy(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::size_t RecordSet::rowCount() const
|
inline std::size_t RecordSet::totalRowCount() const
|
||||||
{
|
{
|
||||||
poco_assert (extractions().size());
|
poco_assert (extractions().size());
|
||||||
return extractions()[0].get()->numOfRowsHandled();
|
return extractions()[0].get()->numOfRowsHandled();
|
||||||
@ -524,6 +571,42 @@ inline std::ostream& RecordSet::copyNames(std::ostream& os) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline RowFilter* RecordSet::getFilter()
|
||||||
|
{
|
||||||
|
return _pFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
namespace Keywords {
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string& select(const std::string& str)
|
||||||
|
{
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const RecordSet& from(const RecordSet& rs)
|
||||||
|
{
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline RecordSet from(const Statement& stmt)
|
||||||
|
{
|
||||||
|
return RecordSet(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string& where(const std::string& str)
|
||||||
|
{
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Keywords
|
||||||
|
*/
|
||||||
|
|
||||||
} } // namespace Poco::Data
|
} } // namespace Poco::Data
|
||||||
|
|
||||||
|
|
||||||
|
285
Data/include/Poco/Data/RowFilter.h
Normal file
285
Data/include/Poco/Data/RowFilter.h
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
//
|
||||||
|
// RowFilter.h
|
||||||
|
//
|
||||||
|
// $Id: //poco/Main/Data/include/Poco/Data/RowFilter.h#1 $
|
||||||
|
//
|
||||||
|
// Library: Data
|
||||||
|
// Package: DataCore
|
||||||
|
// Module: RowFilter
|
||||||
|
//
|
||||||
|
// Definition of the RowFilter 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_RowFilter_INCLUDED
|
||||||
|
#define Data_RowFilter_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Data/Data.h"
|
||||||
|
#include "Poco/Data/RecordSet.h"
|
||||||
|
#include "Poco/DynamicAny.h"
|
||||||
|
#include "Poco/Tuple.h"
|
||||||
|
#include "Poco/String.h"
|
||||||
|
#include "Poco/RefCountedObject.h"
|
||||||
|
#include "Poco/AutoPtr.h"
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
|
||||||
|
class Data_API RowFilter: public RefCountedObject
|
||||||
|
/// RowFilter class provides row filtering functionality.
|
||||||
|
/// A filter contains a set of criteria (field name, value and
|
||||||
|
/// logical operation) for row filtering.
|
||||||
|
/// Additionally, a row filter contains a map of pointers to other
|
||||||
|
/// filters with related logical operations between filters.
|
||||||
|
/// RowFilter is typically added to recordset in order to filter
|
||||||
|
/// its content. Since the recordset own iteration is dependent upon
|
||||||
|
/// filtering, whenever the filtering criteria is changed,
|
||||||
|
/// the filter automatically notifies all associated recordsets
|
||||||
|
/// by rewinding them to the first position.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Comparison
|
||||||
|
{
|
||||||
|
VALUE_LESS_THAN,
|
||||||
|
VALUE_LESS_THAN_OR_EQUAL,
|
||||||
|
VALUE_EQUAL,
|
||||||
|
VALUE_GREATER_THAN,
|
||||||
|
VALUE_GREATER_THAN_OR_EQUAL,
|
||||||
|
VALUE_NOT_EQUAL,
|
||||||
|
VALUE_IS_NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LogicOperator
|
||||||
|
{
|
||||||
|
OP_AND,
|
||||||
|
OP_OR,
|
||||||
|
OP_NOT
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef bool (*CompT)(const DynamicAny&, const DynamicAny&);
|
||||||
|
typedef AutoPtr<RowFilter> Ptr;
|
||||||
|
typedef std::map<std::string, Comparison> Comparisons;
|
||||||
|
typedef Tuple<DynamicAny, Comparison, LogicOperator> ComparisonEntry;
|
||||||
|
typedef std::multimap<std::string, ComparisonEntry> ComparisonMap;
|
||||||
|
typedef std::map<AutoPtr<RowFilter>, LogicOperator> FilterMap;
|
||||||
|
|
||||||
|
RowFilter(RecordSet* pRecordSet);
|
||||||
|
/// Creates the top-level RowFilter and associates it with the recordset.
|
||||||
|
|
||||||
|
RowFilter(Ptr pParent, LogicOperator op = OP_OR);
|
||||||
|
/// Creates child RowFilter and associates it with the parent filter.
|
||||||
|
|
||||||
|
~RowFilter();
|
||||||
|
/// Destroys the RowFilter.
|
||||||
|
|
||||||
|
void addFilter(const Ptr& pFilter, LogicOperator comparison);
|
||||||
|
/// Appends another filter to this one.
|
||||||
|
|
||||||
|
void removeFilter(const Ptr& pFilter);
|
||||||
|
/// Removes filter from this filter.
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add(const std::string& name, Comparison comparison, const T& value, LogicOperator op = OP_OR)
|
||||||
|
/// Adds value to the filter.
|
||||||
|
{
|
||||||
|
if (_pRecordSet) _pRecordSet->moveFirst();
|
||||||
|
_comparisonMap.insert(ComparisonMap::value_type(toUpper(name),
|
||||||
|
ComparisonEntry(value, comparison, op)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add(const std::string& name, const std::string& comp, const T& value, LogicOperator op = OP_OR)
|
||||||
|
/// Adds value to the filter.
|
||||||
|
{
|
||||||
|
add(name, getComparison(comp), value, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void addAnd(const std::string& name, const std::string& comp, const T& value)
|
||||||
|
/// Adds logically AND-ed value to the filter.
|
||||||
|
{
|
||||||
|
add(name, getComparison(comp), value, OP_AND);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void addOr(const std::string& name, const std::string& comp, const T& value)
|
||||||
|
/// Adds logically OR-ed value to the filter.
|
||||||
|
{
|
||||||
|
add(name, getComparison(comp), value, OP_OR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove(const std::string& name);
|
||||||
|
/// Removes named comparisons from the filter.
|
||||||
|
/// All comparisons with specified name are removed.
|
||||||
|
/// Returns the number of comparisons removed.
|
||||||
|
|
||||||
|
void toggleNot();
|
||||||
|
/// Togless the NOT operator for this filter;
|
||||||
|
|
||||||
|
bool isNot() const;
|
||||||
|
/// Returns true if filter is NOT-ed, false otherwise.
|
||||||
|
|
||||||
|
bool isEmpty() const;
|
||||||
|
/// Returns true if there is not filtering criteria specified.
|
||||||
|
|
||||||
|
bool isAllowed(std::size_t row) const;//const std::string& name, const DynamicAny& val) const;
|
||||||
|
/// Returns true if name and value are allowed.
|
||||||
|
|
||||||
|
bool exists(const std::string& name) const;
|
||||||
|
/// Returns true if name is known to this row filter.
|
||||||
|
|
||||||
|
private:
|
||||||
|
RowFilter();
|
||||||
|
RowFilter(const RowFilter&);
|
||||||
|
RowFilter& operator=(const RowFilter&);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
static bool equal(const DynamicAny& p1, const DynamicAny& p2);
|
||||||
|
static bool notEqual(const DynamicAny& p1, const DynamicAny& p2);
|
||||||
|
static bool less(const DynamicAny& p1, const DynamicAny& p2);
|
||||||
|
static bool greater(const DynamicAny& p1, const DynamicAny& p2);
|
||||||
|
static bool lessOrEqual(const DynamicAny& p1, const DynamicAny& p2);
|
||||||
|
static bool greaterOrEqual(const DynamicAny& p1, const DynamicAny& p2);
|
||||||
|
static bool logicalAnd(const DynamicAny& p1, const DynamicAny& p2);
|
||||||
|
static bool logicalOr(const DynamicAny& p1, const DynamicAny& p2);
|
||||||
|
static bool isNull(const DynamicAny& p1, const DynamicAny&);
|
||||||
|
|
||||||
|
static void doCompare(DynamicAny& ret,
|
||||||
|
DynamicAny& val,
|
||||||
|
CompT comp,
|
||||||
|
const ComparisonEntry& ce);
|
||||||
|
|
||||||
|
RecordSet& recordSet() const;
|
||||||
|
|
||||||
|
Comparison getComparison(const std::string& comp) const;
|
||||||
|
|
||||||
|
Comparisons _comparisons;
|
||||||
|
ComparisonMap _comparisonMap;
|
||||||
|
mutable RecordSet* _pRecordSet;
|
||||||
|
Ptr _pParent;
|
||||||
|
FilterMap _filterMap;
|
||||||
|
bool _not;
|
||||||
|
|
||||||
|
friend class RecordSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// inlines
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::isEmpty() const
|
||||||
|
{
|
||||||
|
return _comparisonMap.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::exists(const std::string& name) const
|
||||||
|
{
|
||||||
|
return _comparisonMap.find(name) != _comparisonMap.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void RowFilter::toggleNot()
|
||||||
|
{
|
||||||
|
_not = !_not;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::isNot() const
|
||||||
|
{
|
||||||
|
return _not;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::equal(const DynamicAny& p1, const DynamicAny& p2)
|
||||||
|
{
|
||||||
|
return p1 == p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::notEqual(const DynamicAny& p1, const DynamicAny& p2)
|
||||||
|
{
|
||||||
|
return p1 != p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::less(const DynamicAny& p1, const DynamicAny& p2)
|
||||||
|
{
|
||||||
|
return p1 < p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::greater(const DynamicAny& p1, const DynamicAny& p2)
|
||||||
|
{
|
||||||
|
return p1 > p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::lessOrEqual(const DynamicAny& p1, const DynamicAny& p2)
|
||||||
|
{
|
||||||
|
return p1 <= p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::greaterOrEqual(const DynamicAny& p1, const DynamicAny& p2)
|
||||||
|
{
|
||||||
|
return p1 >= p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::logicalAnd(const DynamicAny& p1, const DynamicAny& p2)
|
||||||
|
{
|
||||||
|
return p1 && p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::logicalOr(const DynamicAny& p1, const DynamicAny& p2)
|
||||||
|
{
|
||||||
|
return p1 || p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool RowFilter::isNull(const DynamicAny& p1, const DynamicAny&)
|
||||||
|
{
|
||||||
|
return p1.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} } // namespace Poco::Data
|
||||||
|
|
||||||
|
|
||||||
|
#endif // Data_RowFilter_INCLUDED
|
@ -792,7 +792,6 @@ inline void swap(Statement& s1, Statement& s2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Data
|
} } // namespace Poco::Data
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "Poco/Data/RecordSet.h"
|
#include "Poco/Data/RecordSet.h"
|
||||||
#include "Poco/Data/Session.h"
|
#include "Poco/Data/Session.h"
|
||||||
|
#include "Poco/Data/RowFilter.h"
|
||||||
#include "Poco/Data/Date.h"
|
#include "Poco/Data/Date.h"
|
||||||
#include "Poco/Data/Time.h"
|
#include "Poco/Data/Time.h"
|
||||||
#include "Poco/Data/DataException.h"
|
#include "Poco/Data/DataException.h"
|
||||||
@ -54,7 +55,8 @@ RecordSet::RecordSet(const Statement& rStatement):
|
|||||||
Statement(rStatement),
|
Statement(rStatement),
|
||||||
_currentRow(0),
|
_currentRow(0),
|
||||||
_pBegin(new RowIterator(this)),
|
_pBegin(new RowIterator(this)),
|
||||||
_pEnd(new RowIterator(this, true))
|
_pEnd(new RowIterator(this, true)),
|
||||||
|
_pFilter(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +67,8 @@ RecordSet::RecordSet(Session& rSession,
|
|||||||
Statement((rSession << query, now)),
|
Statement((rSession << query, now)),
|
||||||
_currentRow(0),
|
_currentRow(0),
|
||||||
_pBegin(new RowIterator(this)),
|
_pBegin(new RowIterator(this)),
|
||||||
_pEnd(new RowIterator(this, true))
|
_pEnd(new RowIterator(this, true)),
|
||||||
|
_pFilter(0)
|
||||||
{
|
{
|
||||||
if (pRowFormatter) setRowFormatter(pRowFormatter);
|
if (pRowFormatter) setRowFormatter(pRowFormatter);
|
||||||
}
|
}
|
||||||
@ -75,7 +78,8 @@ RecordSet::RecordSet(const RecordSet& other):
|
|||||||
Statement(other.impl().duplicate()),
|
Statement(other.impl().duplicate()),
|
||||||
_currentRow(other._currentRow),
|
_currentRow(other._currentRow),
|
||||||
_pBegin(new RowIterator(this)),
|
_pBegin(new RowIterator(this)),
|
||||||
_pEnd(new RowIterator(this, true))
|
_pEnd(new RowIterator(this, true)),
|
||||||
|
_pFilter(other._pFilter)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,34 +88,38 @@ RecordSet::~RecordSet()
|
|||||||
{
|
{
|
||||||
delete _pBegin;
|
delete _pBegin;
|
||||||
delete _pEnd;
|
delete _pEnd;
|
||||||
|
if(_pFilter) _pFilter->release();
|
||||||
|
|
||||||
RowMap::iterator it = _rowMap.begin();
|
RowMap::iterator it = _rowMap.begin();
|
||||||
RowMap::iterator end = _rowMap.end();
|
RowMap::iterator end = _rowMap.end();
|
||||||
for (; it != end; ++it) delete it->second;
|
for (; it != end; ++it) delete it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DynamicAny RecordSet::value(std::size_t col, std::size_t row) const
|
DynamicAny RecordSet::value(std::size_t col, std::size_t row, bool useFilter) const
|
||||||
{
|
{
|
||||||
|
if (useFilter && isFiltered() && !isAllowed(row))
|
||||||
|
throw InvalidAccessException("Row not allowed");
|
||||||
|
|
||||||
if (isNull(col, row)) return DynamicAny();
|
if (isNull(col, row)) return DynamicAny();
|
||||||
|
|
||||||
switch (columnType(col))
|
switch (columnType(col))
|
||||||
{
|
{
|
||||||
case MetaColumn::FDT_BOOL: return value<bool>(col, row);
|
case MetaColumn::FDT_BOOL: return value<bool>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_INT8: return value<Int8>(col, row);
|
case MetaColumn::FDT_INT8: return value<Int8>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_UINT8: return value<UInt8>(col, row);
|
case MetaColumn::FDT_UINT8: return value<UInt8>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_INT16: return value<Int16>(col, row);
|
case MetaColumn::FDT_INT16: return value<Int16>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_UINT16: return value<UInt16>(col, row);
|
case MetaColumn::FDT_UINT16: return value<UInt16>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_INT32: return value<Int32>(col, row);
|
case MetaColumn::FDT_INT32: return value<Int32>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_UINT32: return value<UInt32>(col, row);
|
case MetaColumn::FDT_UINT32: return value<UInt32>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_INT64: return value<Int64>(col, row);
|
case MetaColumn::FDT_INT64: return value<Int64>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_UINT64: return value<UInt64>(col, row);
|
case MetaColumn::FDT_UINT64: return value<UInt64>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_FLOAT: return value<float>(col, row);
|
case MetaColumn::FDT_FLOAT: return value<float>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_DOUBLE: return value<double>(col, row);
|
case MetaColumn::FDT_DOUBLE: return value<double>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_STRING: return value<std::string>(col, row);
|
case MetaColumn::FDT_STRING: return value<std::string>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_BLOB: return value<BLOB>(col, row);
|
case MetaColumn::FDT_BLOB: return value<BLOB>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_DATE: return value<Date>(col, row);
|
case MetaColumn::FDT_DATE: return value<Date>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_TIME: return value<Time>(col, row);
|
case MetaColumn::FDT_TIME: return value<Time>(col, row, useFilter);
|
||||||
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, row);
|
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, row);
|
||||||
default:
|
default:
|
||||||
throw UnknownTypeException("Data type not supported.");
|
throw UnknownTypeException("Data type not supported.");
|
||||||
@ -119,28 +127,31 @@ DynamicAny RecordSet::value(std::size_t col, std::size_t row) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DynamicAny RecordSet::value(const std::string& name, std::size_t row) const
|
DynamicAny RecordSet::value(const std::string& name, std::size_t row, bool useFilter) const
|
||||||
{
|
{
|
||||||
|
if (useFilter && isFiltered() && !isAllowed(row))
|
||||||
|
throw InvalidAccessException("Row not allowed");
|
||||||
|
|
||||||
if (isNull(metaColumn(name).position(), row)) return DynamicAny();
|
if (isNull(metaColumn(name).position(), row)) return DynamicAny();
|
||||||
|
|
||||||
switch (columnType(name))
|
switch (columnType(name))
|
||||||
{
|
{
|
||||||
case MetaColumn::FDT_BOOL: return value<bool>(name, row);
|
case MetaColumn::FDT_BOOL: return value<bool>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_INT8: return value<Int8>(name, row);
|
case MetaColumn::FDT_INT8: return value<Int8>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_UINT8: return value<UInt8>(name, row);
|
case MetaColumn::FDT_UINT8: return value<UInt8>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_INT16: return value<Int16>(name, row);
|
case MetaColumn::FDT_INT16: return value<Int16>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_UINT16: return value<UInt16>(name, row);
|
case MetaColumn::FDT_UINT16: return value<UInt16>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_INT32: return value<Int32>(name, row);
|
case MetaColumn::FDT_INT32: return value<Int32>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_UINT32: return value<UInt32>(name, row);
|
case MetaColumn::FDT_UINT32: return value<UInt32>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_INT64: return value<Int64>(name, row);
|
case MetaColumn::FDT_INT64: return value<Int64>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_UINT64: return value<UInt64>(name, row);
|
case MetaColumn::FDT_UINT64: return value<UInt64>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_FLOAT: return value<float>(name, row);
|
case MetaColumn::FDT_FLOAT: return value<float>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_DOUBLE: return value<double>(name, row);
|
case MetaColumn::FDT_DOUBLE: return value<double>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_STRING: return value<std::string>(name, row);
|
case MetaColumn::FDT_STRING: return value<std::string>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_BLOB: return value<BLOB>(name, row);
|
case MetaColumn::FDT_BLOB: return value<BLOB>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_DATE: return value<Date>(name, row);
|
case MetaColumn::FDT_DATE: return value<Date>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_TIME: return value<Time>(name, row);
|
case MetaColumn::FDT_TIME: return value<Time>(name, row, useFilter);
|
||||||
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(name, row);
|
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(name, row, useFilter);
|
||||||
default:
|
default:
|
||||||
throw UnknownTypeException("Data type not supported.");
|
throw UnknownTypeException("Data type not supported.");
|
||||||
}
|
}
|
||||||
@ -183,11 +194,48 @@ Row& RecordSet::row(std::size_t pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::size_t RecordSet::rowCount() const
|
||||||
|
{
|
||||||
|
poco_assert (extractions().size());
|
||||||
|
std::size_t rc = totalRowCount();
|
||||||
|
if (!isFiltered()) return rc;
|
||||||
|
|
||||||
|
std::size_t counter = 0;
|
||||||
|
for (int row = 0; row < rc; ++row)
|
||||||
|
{
|
||||||
|
if (isAllowed(row)) ++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RecordSet::isAllowed(std::size_t row) const
|
||||||
|
{
|
||||||
|
if (!isFiltered()) return true;
|
||||||
|
return _pFilter->isAllowed(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool RecordSet::moveFirst()
|
bool RecordSet::moveFirst()
|
||||||
{
|
{
|
||||||
if (rowCount() > 0)
|
if (totalRowCount() > 0)
|
||||||
{
|
{
|
||||||
_currentRow = 0;
|
if (!isFiltered())
|
||||||
|
{
|
||||||
|
_currentRow = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t currentRow = _currentRow;
|
||||||
|
currentRow = 0;
|
||||||
|
while (!isAllowed(currentRow))
|
||||||
|
{
|
||||||
|
if (currentRow >= totalRowCount() - 1) return false;
|
||||||
|
++currentRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentRow = currentRow;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
@ -196,49 +244,57 @@ bool RecordSet::moveFirst()
|
|||||||
|
|
||||||
bool RecordSet::moveNext()
|
bool RecordSet::moveNext()
|
||||||
{
|
{
|
||||||
if (_currentRow >= rowCount() - 1) return false;
|
std::size_t currentRow = _currentRow;
|
||||||
++_currentRow;
|
do
|
||||||
|
{
|
||||||
|
if (currentRow >= totalRowCount() - 1) return false;
|
||||||
|
++currentRow;
|
||||||
|
} while (isFiltered() && !isAllowed(currentRow));
|
||||||
|
|
||||||
|
_currentRow = currentRow;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool RecordSet::movePrevious()
|
bool RecordSet::movePrevious()
|
||||||
{
|
{
|
||||||
if (0 == _currentRow) return false;
|
std::size_t currentRow = _currentRow;
|
||||||
--_currentRow;
|
do
|
||||||
|
{
|
||||||
|
if (currentRow <= 0) return false;
|
||||||
|
--currentRow;
|
||||||
|
} while (isFiltered() && !isAllowed(currentRow));
|
||||||
|
|
||||||
|
_currentRow = currentRow;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool RecordSet::moveLast()
|
bool RecordSet::moveLast()
|
||||||
{
|
{
|
||||||
if (rowCount() > 0)
|
if (totalRowCount() > 0)
|
||||||
{
|
{
|
||||||
_currentRow = rowCount() - 1;
|
std::size_t currentRow = _currentRow;
|
||||||
|
currentRow = totalRowCount() - 1;
|
||||||
|
if (!isFiltered())
|
||||||
|
{
|
||||||
|
_currentRow = currentRow;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!isAllowed(currentRow))
|
||||||
|
{
|
||||||
|
if (currentRow <= 0) return false;
|
||||||
|
--currentRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentRow = currentRow;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DynamicAny RecordSet::nvl(const std::string& name, const DynamicAny& deflt) const
|
|
||||||
{
|
|
||||||
if (isNull(name))
|
|
||||||
return deflt;
|
|
||||||
else
|
|
||||||
return value(name, _currentRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DynamicAny RecordSet::nvl(std::size_t index, const DynamicAny& deflt) const
|
|
||||||
{
|
|
||||||
if (isNull(index, _currentRow))
|
|
||||||
return deflt;
|
|
||||||
else
|
|
||||||
return value(index, _currentRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::ostream& RecordSet::copyValues(std::ostream& os, std::size_t offset, std::size_t length) const
|
std::ostream& RecordSet::copyValues(std::ostream& os, std::size_t offset, std::size_t length) const
|
||||||
{
|
{
|
||||||
if (length == RowIterator::POSITION_END)
|
if (length == RowIterator::POSITION_END)
|
||||||
@ -265,4 +321,18 @@ std::ostream& RecordSet::copy(std::ostream& os) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RecordSet::filter(RowFilter* pFilter)
|
||||||
|
{
|
||||||
|
if (_pFilter) _pFilter->release();
|
||||||
|
_pFilter = pFilter;
|
||||||
|
if(_pFilter) _pFilter->duplicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RecordSet::isFiltered() const
|
||||||
|
{
|
||||||
|
return _pFilter && !_pFilter->isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Data
|
} } // namespace Poco::Data
|
||||||
|
230
Data/src/RowFilter.cpp
Normal file
230
Data/src/RowFilter.cpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
//
|
||||||
|
// RowFilter.cpp
|
||||||
|
//
|
||||||
|
// $Id: //poco/Main/Data/src/RowFilter.cpp#1 $
|
||||||
|
//
|
||||||
|
// Library: Data
|
||||||
|
// Package: DataCore
|
||||||
|
// Module: RowFilter
|
||||||
|
//
|
||||||
|
// 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/RowFilter.h"
|
||||||
|
#include "Poco/Data/RecordSet.h"
|
||||||
|
#include "Poco/String.h"
|
||||||
|
#include "Poco/Exception.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
|
||||||
|
RowFilter::RowFilter(RecordSet* pRecordSet): _pRecordSet(pRecordSet), _not(false)
|
||||||
|
{
|
||||||
|
poco_check_ptr(pRecordSet);
|
||||||
|
init();
|
||||||
|
_pRecordSet->filter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RowFilter::RowFilter(Ptr pParent, LogicOperator op): _pRecordSet(0),
|
||||||
|
_pParent(pParent),
|
||||||
|
_not(false)
|
||||||
|
{
|
||||||
|
poco_check_ptr(_pParent.get());
|
||||||
|
init();
|
||||||
|
_pParent->addFilter(this, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowFilter::init()
|
||||||
|
{
|
||||||
|
_comparisons.insert(Comparisons::value_type("<", VALUE_LESS_THAN));
|
||||||
|
_comparisons.insert(Comparisons::value_type("<=", VALUE_LESS_THAN_OR_EQUAL));
|
||||||
|
_comparisons.insert(Comparisons::value_type("=", VALUE_EQUAL));
|
||||||
|
_comparisons.insert(Comparisons::value_type("==", VALUE_EQUAL));
|
||||||
|
_comparisons.insert(Comparisons::value_type(">", VALUE_GREATER_THAN));
|
||||||
|
_comparisons.insert(Comparisons::value_type(">=", VALUE_GREATER_THAN_OR_EQUAL));
|
||||||
|
_comparisons.insert(Comparisons::value_type("<>", VALUE_NOT_EQUAL));
|
||||||
|
_comparisons.insert(Comparisons::value_type("!=", VALUE_NOT_EQUAL));
|
||||||
|
_comparisons.insert(Comparisons::value_type("IS NULL", VALUE_IS_NULL));
|
||||||
|
|
||||||
|
duplicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RowFilter::~RowFilter()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
if (_pRecordSet) _pRecordSet->filter(0);
|
||||||
|
if (_pParent.get()) _pParent->removeFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RowFilter::isAllowed(std::size_t row) const
|
||||||
|
{
|
||||||
|
DynamicAny retVal;
|
||||||
|
const RecordSet& rs = recordSet();
|
||||||
|
|
||||||
|
std::size_t columns = rs.columnCount();
|
||||||
|
ComparisonMap::const_iterator it = _comparisonMap.begin();
|
||||||
|
ComparisonMap::const_iterator end = _comparisonMap.end();
|
||||||
|
for (; it != end; ++it)
|
||||||
|
{
|
||||||
|
for (std::size_t col = 0; col < columns; ++col)
|
||||||
|
{
|
||||||
|
const std::string name = toUpper(rs.metaColumn(static_cast<UInt32>(col)).name());
|
||||||
|
if (_comparisonMap.find(name) == _comparisonMap.end()) continue;
|
||||||
|
|
||||||
|
DynamicAny ret;
|
||||||
|
CompT compOp = 0;
|
||||||
|
DynamicAny val = rs.value(col, row, false);
|
||||||
|
|
||||||
|
switch (it->second.get<1>())
|
||||||
|
{
|
||||||
|
case VALUE_LESS_THAN:
|
||||||
|
compOp = less; break;
|
||||||
|
case VALUE_LESS_THAN_OR_EQUAL:
|
||||||
|
compOp = lessOrEqual; break;
|
||||||
|
case VALUE_EQUAL:
|
||||||
|
compOp = equal; break;
|
||||||
|
case VALUE_GREATER_THAN:
|
||||||
|
compOp = greater; break;
|
||||||
|
case VALUE_GREATER_THAN_OR_EQUAL:
|
||||||
|
compOp = greaterOrEqual; break;
|
||||||
|
case VALUE_NOT_EQUAL:
|
||||||
|
compOp = notEqual; break;
|
||||||
|
case VALUE_IS_NULL:
|
||||||
|
compOp = isNull; break;
|
||||||
|
default:
|
||||||
|
throw IllegalStateException("Unsupported comparison criteria.");
|
||||||
|
}
|
||||||
|
|
||||||
|
doCompare(ret, val, compOp, it->second);
|
||||||
|
if (retVal.isEmpty()) retVal = ret;
|
||||||
|
else retVal = retVal || ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate through children
|
||||||
|
FilterMap::const_iterator fIt = _filterMap.begin();
|
||||||
|
FilterMap::const_iterator fEnd = _filterMap.end();
|
||||||
|
for (; fIt != fEnd; ++fIt)
|
||||||
|
{
|
||||||
|
if (OP_OR == fIt->second)
|
||||||
|
{
|
||||||
|
if (retVal.isEmpty())
|
||||||
|
retVal = fIt->first->isAllowed(row);
|
||||||
|
else
|
||||||
|
retVal = retVal || fIt->first->isAllowed(row);
|
||||||
|
}
|
||||||
|
else if (OP_AND == fIt->second)
|
||||||
|
{
|
||||||
|
if (retVal.isEmpty())
|
||||||
|
retVal = fIt->first->isAllowed(row);
|
||||||
|
else
|
||||||
|
retVal = retVal && fIt->first->isAllowed(row);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw IllegalStateException("Unknown logical operation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retVal.isEmpty()) retVal = true; // no filtering found
|
||||||
|
return (!_not) && retVal.extract<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int RowFilter::remove(const std::string& name)
|
||||||
|
{
|
||||||
|
poco_check_ptr (_pRecordSet);
|
||||||
|
_pRecordSet->moveFirst();
|
||||||
|
return static_cast<int>(_comparisonMap.erase(toUpper(name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RowFilter::Comparison RowFilter::getComparison(const std::string& comp) const
|
||||||
|
{
|
||||||
|
Comparisons::const_iterator it = _comparisons.find(toUpper(comp));
|
||||||
|
if (it == _comparisons.end())
|
||||||
|
throw NotFoundException("Comparison not found", comp);
|
||||||
|
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowFilter::addFilter(const Ptr& pFilter, LogicOperator comparison)
|
||||||
|
{
|
||||||
|
poco_check_ptr (_pRecordSet);
|
||||||
|
|
||||||
|
pFilter->_pRecordSet = _pRecordSet;
|
||||||
|
_pRecordSet->moveFirst();
|
||||||
|
_filterMap.insert(FilterMap::value_type(pFilter, comparison));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowFilter::removeFilter(const Ptr& pFilter)
|
||||||
|
{
|
||||||
|
poco_check_ptr (_pRecordSet);
|
||||||
|
|
||||||
|
pFilter->_pRecordSet = 0;
|
||||||
|
_pRecordSet->moveFirst();
|
||||||
|
_filterMap.erase(pFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowFilter::doCompare(DynamicAny& ret,
|
||||||
|
DynamicAny& val,
|
||||||
|
CompT comp,
|
||||||
|
const ComparisonEntry& ce)
|
||||||
|
{
|
||||||
|
if (ret.isEmpty()) ret = comp(val, ce.get<0>());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ce.get<2>() == OP_OR)
|
||||||
|
ret = ret || comp(val, ce.get<0>());
|
||||||
|
else if (ce.get<2>() == OP_AND)
|
||||||
|
ret = ret && comp(val, ce.get<0>());
|
||||||
|
else
|
||||||
|
throw IllegalStateException("Unknown logical operation.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordSet& RowFilter::recordSet() const
|
||||||
|
{
|
||||||
|
if (!_pRecordSet)
|
||||||
|
{
|
||||||
|
Ptr pParent = _pParent;
|
||||||
|
while (pParent && !_pRecordSet)
|
||||||
|
_pRecordSet = pParent->_pRecordSet;
|
||||||
|
}
|
||||||
|
poco_check_ptr (_pRecordSet);
|
||||||
|
return *_pRecordSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} } // namespace Poco::Data
|
@ -50,7 +50,7 @@ const int RowIterator::POSITION_END = std::numeric_limits<std::size_t>::max();
|
|||||||
|
|
||||||
RowIterator::RowIterator(RecordSet* pRecordSet, bool positionEnd):
|
RowIterator::RowIterator(RecordSet* pRecordSet, bool positionEnd):
|
||||||
_pRecordSet(pRecordSet),
|
_pRecordSet(pRecordSet),
|
||||||
_position((0 == pRecordSet->rowCount()) || positionEnd ? POSITION_END : 0)
|
_position((0 == pRecordSet->totalRowCount()) || positionEnd ? POSITION_END : 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,10 +89,19 @@ void RowIterator::increment() const
|
|||||||
if (POSITION_END == _position)
|
if (POSITION_END == _position)
|
||||||
throw RangeException("End of iterator reached.");
|
throw RangeException("End of iterator reached.");
|
||||||
|
|
||||||
if (_position < _pRecordSet->rowCount() - 1)
|
if (_position < _pRecordSet->totalRowCount() - 1)
|
||||||
++_position;
|
++_position;
|
||||||
else
|
else
|
||||||
_position = POSITION_END;
|
_position = POSITION_END;
|
||||||
|
|
||||||
|
if (_pRecordSet->getFilter() && POSITION_END != _position)
|
||||||
|
{
|
||||||
|
while (!_pRecordSet->isAllowed(_position))
|
||||||
|
{
|
||||||
|
increment();
|
||||||
|
if (POSITION_END == _position) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -101,17 +110,52 @@ void RowIterator::decrement() const
|
|||||||
if (0 == _position)
|
if (0 == _position)
|
||||||
throw RangeException("Beginning of iterator reached.");
|
throw RangeException("Beginning of iterator reached.");
|
||||||
else if (POSITION_END == _position)
|
else if (POSITION_END == _position)
|
||||||
_position = _pRecordSet->rowCount() - 1;
|
_position = _pRecordSet->totalRowCount() - 1;
|
||||||
else
|
else
|
||||||
--_position;
|
--_position;
|
||||||
|
|
||||||
|
if (_pRecordSet->getFilter() && 0 != _position)
|
||||||
|
{
|
||||||
|
while (!_pRecordSet->isAllowed(_position))
|
||||||
|
{
|
||||||
|
decrement();
|
||||||
|
if (0 == _position) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RowIterator::setPosition(std::size_t pos) const
|
void RowIterator::setPosition(std::size_t pos) const
|
||||||
{
|
{
|
||||||
if (pos < _pRecordSet->rowCount())
|
if (_position == pos) return;
|
||||||
|
|
||||||
|
if (_pRecordSet->getFilter())
|
||||||
|
{
|
||||||
|
std::size_t start = _position;
|
||||||
|
if (_position > pos)
|
||||||
|
{
|
||||||
|
std::size_t end = _position - pos;
|
||||||
|
for (; start > end; --start)
|
||||||
|
{
|
||||||
|
if (pos) --pos;
|
||||||
|
else throw RangeException("Invalid position argument.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::size_t end = pos - _position;
|
||||||
|
for (; start < end; ++start)
|
||||||
|
{
|
||||||
|
if (_pRecordSet->totalRowCount() != pos) ++pos;
|
||||||
|
else throw RangeException("Invalid position argument.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < _pRecordSet->totalRowCount())
|
||||||
_position = pos;
|
_position = pos;
|
||||||
else if (pos == _pRecordSet->rowCount())
|
else if (pos == _pRecordSet->totalRowCount())
|
||||||
_position = POSITION_END;
|
_position = POSITION_END;
|
||||||
else
|
else
|
||||||
throw RangeException("Invalid position argument.");
|
throw RangeException("Invalid position argument.");
|
||||||
|
Loading…
Reference in New Issue
Block a user