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