1//
2// RowFilter.cpp
3//
4// Library: Data
5// Package: DataCore
6// Module: RowFilter
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Data/RowFilter.h"
16#include "Poco/Data/RecordSet.h"
17#include "Poco/String.h"
18#include "Poco/Exception.h"
19#include <functional>
20
21
22namespace Poco {
23namespace Data {
24
25
26RowFilter::RowFilter(RecordSet* pRecordSet): _pRecordSet(pRecordSet), _not(false)
27{
28 poco_check_ptr(pRecordSet);
29 init();
30 Ptr pThis(this, true);
31 _pRecordSet->filter(pThis);
32}
33
34
35RowFilter::RowFilter(Ptr pParent, LogicOperator op): _pRecordSet(0),
36 _pParent(pParent),
37 _not(false)
38{
39 poco_check_ptr(_pParent.get());
40 init();
41 Ptr pThis(this, true);
42 _pParent->addFilter(pThis, op);
43}
44
45
46void RowFilter::init()
47{
48 _comparisons.insert(Comparisons::value_type("<", VALUE_LESS_THAN));
49 _comparisons.insert(Comparisons::value_type("<=", VALUE_LESS_THAN_OR_EQUAL));
50 _comparisons.insert(Comparisons::value_type("=", VALUE_EQUAL));
51 _comparisons.insert(Comparisons::value_type("==", VALUE_EQUAL));
52 _comparisons.insert(Comparisons::value_type(">", VALUE_GREATER_THAN));
53 _comparisons.insert(Comparisons::value_type(">=", VALUE_GREATER_THAN_OR_EQUAL));
54 _comparisons.insert(Comparisons::value_type("<>", VALUE_NOT_EQUAL));
55 _comparisons.insert(Comparisons::value_type("!=", VALUE_NOT_EQUAL));
56 _comparisons.insert(Comparisons::value_type("IS NULL", VALUE_IS_NULL));
57}
58
59
60RowFilter::~RowFilter()
61{
62 try
63 {
64 if (_pRecordSet) _pRecordSet->filter(0);
65 if (_pParent)
66 {
67 Ptr pThis(this, true);
68 if(_pParent->has(pThis))
69 _pParent->removeFilter(pThis);
70 }
71 }
72 catch (...)
73 {
74 poco_unexpected();
75 }
76}
77
78
79bool RowFilter::isAllowed(std::size_t row) const
80{
81 Poco::Dynamic::Var retVal;
82 const RecordSet& rs = recordSet();
83
84 std::size_t columns = rs.columnCount();
85 ComparisonMap::const_iterator it = _comparisonMap.begin();
86 ComparisonMap::const_iterator end = _comparisonMap.end();
87 for (; it != end; ++it)
88 {
89 for (std::size_t col = 0; col < columns; ++col)
90 {
91 const std::string name = toUpper(rs.metaColumn(static_cast<UInt32>(col)).name());
92 if (_comparisonMap.find(name) == _comparisonMap.end()) continue;
93
94 Poco::Dynamic::Var ret;
95 CompT compOp = 0;
96 Poco::Dynamic::Var val = rs.value(col, row, false);
97
98 switch (it->second.get<1>())
99 {
100 case VALUE_LESS_THAN:
101 compOp = less; break;
102 case VALUE_LESS_THAN_OR_EQUAL:
103 compOp = lessOrEqual; break;
104 case VALUE_EQUAL:
105 compOp = equal; break;
106 case VALUE_GREATER_THAN:
107 compOp = greater; break;
108 case VALUE_GREATER_THAN_OR_EQUAL:
109 compOp = greaterOrEqual; break;
110 case VALUE_NOT_EQUAL:
111 compOp = notEqual; break;
112 case VALUE_IS_NULL:
113 compOp = isNull; break;
114 default:
115 throw IllegalStateException("Unsupported comparison criteria.");
116 }
117
118 doCompare(ret, val, compOp, it->second);
119 if (retVal.isEmpty()) retVal = ret;
120 else retVal = retVal || ret;
121 }
122 }
123
124 // iterate through children
125 FilterMap::const_iterator fIt = _filterMap.begin();
126 FilterMap::const_iterator fEnd = _filterMap.end();
127 for (; fIt != fEnd; ++fIt)
128 {
129 if (OP_OR == fIt->second)
130 {
131 if (retVal.isEmpty())
132 retVal = fIt->first->isAllowed(row);
133 else
134 retVal = retVal || fIt->first->isAllowed(row);
135 }
136 else if (OP_AND == fIt->second)
137 {
138 if (retVal.isEmpty())
139 retVal = fIt->first->isAllowed(row);
140 else
141 retVal = retVal && fIt->first->isAllowed(row);
142 }
143 else
144 throw IllegalStateException("Unknown logical operation.");
145 }
146
147 if (retVal.isEmpty()) retVal = true; // no filtering found
148 return (!_not) && retVal.extract<bool>();
149}
150
151
152int RowFilter::remove(const std::string& name)
153{
154 poco_check_ptr (_pRecordSet);
155 _pRecordSet->moveFirst();
156 return static_cast<int>(_comparisonMap.erase(toUpper(name)));
157}
158
159
160RowFilter::Comparison RowFilter::getComparison(const std::string& comp) const
161{
162 Comparisons::const_iterator it = _comparisons.find(toUpper(comp));
163 if (it == _comparisons.end())
164 throw NotFoundException("Comparison not found", comp);
165
166 return it->second;
167}
168
169
170void RowFilter::addFilter(Ptr pFilter, LogicOperator comparison)
171{
172 poco_check_ptr (_pRecordSet);
173
174 pFilter->_pRecordSet = _pRecordSet;
175 _pRecordSet->moveFirst();
176 _filterMap.insert(FilterMap::value_type(pFilter, comparison));
177}
178
179
180void RowFilter::removeFilter(Ptr pFilter)
181{
182 poco_check_ptr (_pRecordSet);
183
184 _pRecordSet->moveFirst();
185 _filterMap.erase(pFilter);
186 pFilter->_pRecordSet = 0;
187 pFilter->_pParent = 0;
188}
189
190
191void RowFilter::doCompare(Poco::Dynamic::Var& ret,
192 Poco::Dynamic::Var& val,
193 CompT comp,
194 const ComparisonEntry& ce)
195{
196 if (ret.isEmpty()) ret = comp(val, ce.get<0>());
197 else
198 {
199 if (ce.get<2>() == OP_OR)
200 ret = ret || comp(val, ce.get<0>());
201 else if (ce.get<2>() == OP_AND)
202 ret = ret && comp(val, ce.get<0>());
203 else
204 throw IllegalStateException("Unknown logical operation.");
205 }
206}
207
208
209RecordSet& RowFilter::recordSet() const
210{
211 if (!_pRecordSet)
212 {
213 Ptr pParent = _pParent;
214 while (pParent && !_pRecordSet)
215 _pRecordSet = pParent->_pRecordSet;
216 }
217 poco_check_ptr (_pRecordSet);
218 return *_pRecordSet;
219}
220
221
222void RowFilter::rewindRecordSet()
223{
224 if (_pRecordSet) _pRecordSet->moveFirst();
225}
226
227
228} } // namespace Poco::Data
229