SF [2047672] RecordSet Filtering

This commit is contained in:
Aleksandar Fabijanic
2008-08-12 10:12:56 +00:00
parent d6b81dca0f
commit e409026fba
23 changed files with 986 additions and 86 deletions

View File

@@ -56,7 +56,7 @@ namespace Poco {
namespace Data {
class Session;
class RowFilter;
class Data_API RecordSet: private Statement
@@ -112,7 +112,16 @@ public:
/// Assignment operator.
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;
/// Returns the number of rows in the recordset.
@@ -154,9 +163,12 @@ public:
/// Rows are lazy-created and cached.
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.
{
if (useFilter && isFiltered() && !isAllowed(row))
throw InvalidAccessException("Row not allowed");
switch (storage())
{
case STORAGE_VECTOR:
@@ -181,9 +193,12 @@ public:
}
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.
{
if (useFilter && isFiltered() && !isAllowed(row))
throw InvalidAccessException("Row not allowed");
switch (storage())
{
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.
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.
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
/// 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
/// if the value is not NULL, or deflt otherwise.
{
if (isNull(index, _currentRow))
return DynamicAny(deflt);
else
return value(index, _currentRow);
}
ConstIterator& begin() const;
/// Returns the const row iterator.
@@ -315,6 +344,9 @@ public:
/// Copies the column names and values to the target output stream.
/// Copied strings are formatted by the current RowFormatter.
bool isFiltered() const;
/// Returns true if recordset is filtered.
private:
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;
RowIterator* _pBegin;
RowIterator* _pEnd;
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)
{
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());
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

View 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

View File

@@ -792,7 +792,6 @@ inline void swap(Statement& s1, Statement& s2)
}
} } // namespace Poco::Data