mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-30 05:29:41 +01:00
SF [2047672] RecordSet Filtering
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user