// // 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. // // SPDX-License-Identifier: BSL-1.0 // #include "Poco/Data/RowFilter.h" #include "Poco/Data/RecordSet.h" #include "Poco/String.h" #include "Poco/Exception.h" #include namespace Poco { namespace Data { RowFilter::RowFilter(RecordSet* pRecordSet): _pRecordSet(pRecordSet), _not(false) { poco_check_ptr(pRecordSet); init(); duplicate(); _pRecordSet->filter(this); } RowFilter::RowFilter(Ptr pParent, LogicOperator op): _pRecordSet(0), _pParent(pParent), _not(false) { poco_check_ptr(_pParent.get()); init(); duplicate(); _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)); } RowFilter::~RowFilter() { try { if (_pRecordSet) _pRecordSet->filter(0); if (_pParent && _pParent->has(this)) _pParent->removeFilter(this); release(); } catch (...) { poco_unexpected(); } } bool RowFilter::isAllowed(std::size_t row) const { Poco::Dynamic::Var 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(col)).name()); if (_comparisonMap.find(name) == _comparisonMap.end()) continue; Poco::Dynamic::Var ret; CompT compOp = 0; Poco::Dynamic::Var 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(); } int RowFilter::remove(const std::string& name) { poco_check_ptr (_pRecordSet); _pRecordSet->moveFirst(); return static_cast(_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(Ptr pFilter, LogicOperator comparison) { poco_check_ptr (_pRecordSet); pFilter->_pRecordSet = _pRecordSet; _pRecordSet->moveFirst(); _filterMap.insert(FilterMap::value_type(pFilter, comparison)); } void RowFilter::removeFilter(Ptr pFilter) { poco_check_ptr (_pRecordSet); _pRecordSet->moveFirst(); _filterMap.erase(pFilter); pFilter->_pRecordSet = 0; pFilter->_pParent = 0; } void RowFilter::doCompare(Poco::Dynamic::Var& ret, Poco::Dynamic::Var& 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; } void RowFilter::rewindRecordSet() { if (_pRecordSet) _pRecordSet->moveFirst(); } } } // namespace Poco::Data