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