1 // +------------------------------------------------------------------+
2 // |             ____ _               _        __  __ _  __           |
3 // |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
4 // |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
5 // |           | |___| | | |  __/ (__|   <    | |  | | . \            |
6 // |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
7 // |                                                                  |
8 // | Copyright Mathias Kettner 2014             mk@mathias-kettner.de |
9 // +------------------------------------------------------------------+
10 //
11 // This file is part of Check_MK.
12 // The official homepage is at http://mathias-kettner.de/check_mk.
13 //
14 // check_mk is free software;  you can redistribute it and/or modify it
15 // under the  terms of the  GNU General Public License  as published by
16 // the Free Software Foundation in version 2.  check_mk is  distributed
17 // in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
18 // out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
19 // PARTICULAR PURPOSE. See the  GNU General Public License for more de-
20 // ails.  You should have  received  a copy of the  GNU  General Public
21 // License along with GNU Make; see the file  COPYING.  If  not,  write
22 // to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
23 // Boston, MA 02110-1301 USA.
24 
25 #include "IntColumnFilter.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include "IntColumn.h"
29 #include "logger.h"
30 #include "opids.h"
31 
IntColumnFilter(IntColumn * column,int opid,char * value)32 IntColumnFilter::IntColumnFilter(IntColumn *column, int opid, char *value)
33     : _column(column)
34     , _opid(abs(opid))
35     , _negate(opid < 0)
36     , _ref_string(value) {}
37 
38 // overridden by TimeColumnFilter in order to apply timezone
39 // offset from Localtime: header
convertRefValue()40 int32_t IntColumnFilter::convertRefValue() { return atoi(_ref_string.c_str()); }
41 
accepts(void * data)42 bool IntColumnFilter::accepts(void *data) {
43     bool pass = true;
44     int32_t act_value = _column->getValue(data, _query);
45     int32_t ref_value = convertRefValue();
46     switch (_opid) {
47         case OP_EQUAL:
48             pass = act_value == ref_value;
49             break;
50         case OP_GREATER:
51             pass = act_value > ref_value;
52             break;
53         case OP_LESS:
54             pass = act_value < ref_value;
55             break;
56         default:
57             logger(LG_INFO, "Sorry. Operator %s for integers not implemented.",
58                    op_names_plus_8[_opid]);
59             break;
60     }
61     return pass != _negate;
62 }
63 
findIntLimits(const char * columnname,int * lower,int * upper)64 void IntColumnFilter::findIntLimits(const char *columnname, int *lower,
65                                     int *upper) {
66     if (strcmp(columnname, _column->name()) != 0) {
67         return;  // wrong column
68     }
69     if (*lower >= *upper) {
70         return;  // already empty interval
71     }
72 
73     int32_t ref_value =
74         convertRefValue();  // TimeColumnFilter applies timezone offset here
75 
76     /* [lower, upper[ is some interval. This filter might restrict
77        that interval to a smaller interval.
78      */
79     int opref = _opid * (_negate ? -1 : 1);
80     switch (opref) {
81         case OP_EQUAL:
82             if (ref_value >= *lower && ref_value < *upper) {
83                 *lower = ref_value;
84                 *upper = ref_value + 1;
85             } else {
86                 *lower = *upper;
87             }
88             return;
89 
90         case -OP_EQUAL:
91             if (ref_value == *lower) {
92                 *lower = *lower + 1;
93             } else if (ref_value == *upper - 1) {
94                 *upper = *upper - 1;
95             }
96             return;
97 
98         case OP_GREATER:
99             if (ref_value >= *lower) {
100                 *lower = ref_value + 1;
101             }
102 
103             return;
104 
105         case OP_LESS:
106             if (ref_value < *upper) {
107                 *upper = ref_value;
108             }
109             return;
110 
111         case -OP_GREATER:  // LESS OR EQUAL
112             if (ref_value < *upper - 1) {
113                 *upper = ref_value + 1;
114             }
115             return;
116 
117         case -OP_LESS:  // GREATER OR EQUAL
118             if (ref_value > *lower) {
119                 *lower = ref_value;
120             }
121             return;
122     }
123 }
124 
optimizeBitmask(const char * columnname,uint32_t * mask)125 bool IntColumnFilter::optimizeBitmask(const char *columnname, uint32_t *mask) {
126     int32_t ref_value = convertRefValue();
127 
128     if (strcmp(columnname, _column->name()) != 0) {
129         return false;  // wrong column
130     }
131 
132     if (ref_value < 0 || ref_value > 31) {
133         return true;  // not optimizable by 32bit bit mask
134     }
135 
136     // Our task is to remove those bits from mask that are deselected
137     // by the filter.
138     uint32_t bit = 1 << ref_value;
139 
140     int opref = _opid * (_negate ? -1 : 1);
141     switch (opref) {
142         case OP_EQUAL:
143             *mask &= bit;  // bit must be set
144             return true;
145 
146         case -OP_EQUAL:
147             *mask &= ~bit;  // bit must not be set
148             return true;
149 
150         case -OP_LESS:  // >=
151             bit >>= 1;
152         case OP_GREATER:
153             while (bit != 0u) {
154                 *mask &= ~bit;
155                 bit >>= 1;
156             }
157             return true;
158 
159         case -OP_GREATER:  // <=
160             if (ref_value == 31) {
161                 return true;
162             }
163             bit <<= 1;
164         case OP_LESS:
165             while (true) {
166                 *mask &= ~bit;
167                 if (bit == 0x80000000) {
168                     return true;
169                 }
170                 bit <<= 1;
171             }
172             return true;
173     }
174     return false;  // should not be reached
175 }
176