1 | //===--------------------------------------------------------------------===// |
2 | // comparison_operators.cpp |
3 | // Description: This file contains the implementation of the comparison |
4 | // operations == != >= <= > < |
5 | //===--------------------------------------------------------------------===// |
6 | |
7 | #include "duckdb/common/operator/comparison_operators.hpp" |
8 | |
9 | #include "duckdb/common/vector_operations/binary_executor.hpp" |
10 | #include "duckdb/common/vector_operations/vector_operations.hpp" |
11 | |
12 | #include "duckdb/common/likely.hpp" |
13 | |
14 | namespace duckdb { |
15 | |
16 | template <class T> |
17 | bool EqualsFloat(T left, T right) { |
18 | if (DUCKDB_UNLIKELY(Value::IsNan(left) && Value::IsNan(right))) { |
19 | return true; |
20 | } |
21 | return left == right; |
22 | } |
23 | |
24 | template <> |
25 | bool Equals::Operation(const float &left, const float &right) { |
26 | return EqualsFloat<float>(left, right); |
27 | } |
28 | |
29 | template <> |
30 | bool Equals::Operation(const double &left, const double &right) { |
31 | return EqualsFloat<double>(left, right); |
32 | } |
33 | |
34 | template <class T> |
35 | bool GreaterThanFloat(T left, T right) { |
36 | // handle nans |
37 | // nan is always bigger than everything else |
38 | bool left_is_nan = Value::IsNan(left); |
39 | bool right_is_nan = Value::IsNan(right); |
40 | // if right is nan, there is no number that is bigger than right |
41 | if (DUCKDB_UNLIKELY(right_is_nan)) { |
42 | return false; |
43 | } |
44 | // if left is nan, but right is not, left is always bigger |
45 | if (DUCKDB_UNLIKELY(left_is_nan)) { |
46 | return true; |
47 | } |
48 | return left > right; |
49 | } |
50 | |
51 | template <> |
52 | bool GreaterThan::Operation(const float &left, const float &right) { |
53 | return GreaterThanFloat<float>(left, right); |
54 | } |
55 | |
56 | template <> |
57 | bool GreaterThan::Operation(const double &left, const double &right) { |
58 | return GreaterThanFloat<double>(left, right); |
59 | } |
60 | |
61 | template <class T> |
62 | bool GreaterThanEqualsFloat(T left, T right) { |
63 | // handle nans |
64 | // nan is always bigger than everything else |
65 | bool left_is_nan = Value::IsNan(left); |
66 | bool right_is_nan = Value::IsNan(right); |
67 | // if right is nan, there is no bigger number |
68 | // we only return true if left is also nan (in which case the numbers are equal) |
69 | if (DUCKDB_UNLIKELY(right_is_nan)) { |
70 | return left_is_nan; |
71 | } |
72 | // if left is nan, but right is not, left is always bigger |
73 | if (DUCKDB_UNLIKELY(left_is_nan)) { |
74 | return true; |
75 | } |
76 | return left >= right; |
77 | } |
78 | |
79 | template <> |
80 | bool GreaterThanEquals::Operation(const float &left, const float &right) { |
81 | return GreaterThanEqualsFloat<float>(left, right); |
82 | } |
83 | |
84 | template <> |
85 | bool GreaterThanEquals::Operation(const double &left, const double &right) { |
86 | return GreaterThanEqualsFloat<double>(left, right); |
87 | } |
88 | |
89 | struct ComparisonSelector { |
90 | template <typename OP> |
91 | static idx_t Select(Vector &left, Vector &right, const SelectionVector *sel, idx_t count, SelectionVector *true_sel, |
92 | SelectionVector *false_sel) { |
93 | throw NotImplementedException("Unknown comparison operation!" ); |
94 | } |
95 | }; |
96 | |
97 | template <> |
98 | inline idx_t ComparisonSelector::Select<duckdb::Equals>(Vector &left, Vector &right, const SelectionVector *sel, |
99 | idx_t count, SelectionVector *true_sel, |
100 | SelectionVector *false_sel) { |
101 | return VectorOperations::Equals(left, right, sel, count, true_sel, false_sel); |
102 | } |
103 | |
104 | template <> |
105 | inline idx_t ComparisonSelector::Select<duckdb::NotEquals>(Vector &left, Vector &right, const SelectionVector *sel, |
106 | idx_t count, SelectionVector *true_sel, |
107 | SelectionVector *false_sel) { |
108 | return VectorOperations::NotEquals(left, right, sel, count, true_sel, false_sel); |
109 | } |
110 | |
111 | template <> |
112 | inline idx_t ComparisonSelector::Select<duckdb::GreaterThan>(Vector &left, Vector &right, const SelectionVector *sel, |
113 | idx_t count, SelectionVector *true_sel, |
114 | SelectionVector *false_sel) { |
115 | return VectorOperations::GreaterThan(left, right, sel, count, true_sel, false_sel); |
116 | } |
117 | |
118 | template <> |
119 | inline idx_t ComparisonSelector::Select<duckdb::GreaterThanEquals>(Vector &left, Vector &right, |
120 | const SelectionVector *sel, idx_t count, |
121 | SelectionVector *true_sel, |
122 | SelectionVector *false_sel) { |
123 | return VectorOperations::GreaterThanEquals(left, right, sel, count, true_sel, false_sel); |
124 | } |
125 | |
126 | template <> |
127 | inline idx_t ComparisonSelector::Select<duckdb::LessThan>(Vector &left, Vector &right, const SelectionVector *sel, |
128 | idx_t count, SelectionVector *true_sel, |
129 | SelectionVector *false_sel) { |
130 | return VectorOperations::GreaterThan(left&: right, right&: left, sel, count, true_sel, false_sel); |
131 | } |
132 | |
133 | template <> |
134 | inline idx_t ComparisonSelector::Select<duckdb::LessThanEquals>(Vector &left, Vector &right, const SelectionVector *sel, |
135 | idx_t count, SelectionVector *true_sel, |
136 | SelectionVector *false_sel) { |
137 | return VectorOperations::GreaterThanEquals(left&: right, right&: left, sel, count, true_sel, false_sel); |
138 | } |
139 | |
140 | static void ComparesNotNull(UnifiedVectorFormat &ldata, UnifiedVectorFormat &rdata, ValidityMask &vresult, |
141 | idx_t count) { |
142 | for (idx_t i = 0; i < count; ++i) { |
143 | auto lidx = ldata.sel->get_index(idx: i); |
144 | auto ridx = rdata.sel->get_index(idx: i); |
145 | if (!ldata.validity.RowIsValid(row_idx: lidx) || !rdata.validity.RowIsValid(row_idx: ridx)) { |
146 | vresult.SetInvalid(i); |
147 | } |
148 | } |
149 | } |
150 | |
151 | template <typename OP> |
152 | static void NestedComparisonExecutor(Vector &left, Vector &right, Vector &result, idx_t count) { |
153 | const auto left_constant = left.GetVectorType() == VectorType::CONSTANT_VECTOR; |
154 | const auto right_constant = right.GetVectorType() == VectorType::CONSTANT_VECTOR; |
155 | |
156 | if ((left_constant && ConstantVector::IsNull(vector: left)) || (right_constant && ConstantVector::IsNull(vector: right))) { |
157 | // either left or right is constant NULL: result is constant NULL |
158 | result.SetVectorType(VectorType::CONSTANT_VECTOR); |
159 | ConstantVector::SetNull(vector&: result, is_null: true); |
160 | return; |
161 | } |
162 | |
163 | if (left_constant && right_constant) { |
164 | // both sides are constant, and neither is NULL so just compare one element. |
165 | result.SetVectorType(VectorType::CONSTANT_VECTOR); |
166 | SelectionVector true_sel(1); |
167 | auto match_count = ComparisonSelector::Select<OP>(left, right, nullptr, 1, &true_sel, nullptr); |
168 | auto result_data = ConstantVector::GetData<bool>(vector&: result); |
169 | result_data[0] = match_count > 0; |
170 | return; |
171 | } |
172 | |
173 | result.SetVectorType(VectorType::FLAT_VECTOR); |
174 | auto result_data = FlatVector::GetData<bool>(vector&: result); |
175 | auto &result_validity = FlatVector::Validity(vector&: result); |
176 | |
177 | UnifiedVectorFormat leftv, rightv; |
178 | left.ToUnifiedFormat(count, data&: leftv); |
179 | right.ToUnifiedFormat(count, data&: rightv); |
180 | if (!leftv.validity.AllValid() || !rightv.validity.AllValid()) { |
181 | ComparesNotNull(ldata&: leftv, rdata&: rightv, vresult&: result_validity, count); |
182 | } |
183 | SelectionVector true_sel(count); |
184 | SelectionVector false_sel(count); |
185 | idx_t match_count = ComparisonSelector::Select<OP>(left, right, nullptr, count, &true_sel, &false_sel); |
186 | |
187 | for (idx_t i = 0; i < match_count; ++i) { |
188 | const auto idx = true_sel.get_index(idx: i); |
189 | result_data[idx] = true; |
190 | } |
191 | |
192 | const idx_t no_match_count = count - match_count; |
193 | for (idx_t i = 0; i < no_match_count; ++i) { |
194 | const auto idx = false_sel.get_index(idx: i); |
195 | result_data[idx] = false; |
196 | } |
197 | } |
198 | |
199 | struct ComparisonExecutor { |
200 | private: |
201 | template <class T, class OP> |
202 | static inline void TemplatedExecute(Vector &left, Vector &right, Vector &result, idx_t count) { |
203 | BinaryExecutor::Execute<T, T, bool, OP>(left, right, result, count); |
204 | } |
205 | |
206 | public: |
207 | template <class OP> |
208 | static inline void Execute(Vector &left, Vector &right, Vector &result, idx_t count) { |
209 | D_ASSERT(left.GetType() == right.GetType() && result.GetType() == LogicalType::BOOLEAN); |
210 | // the inplace loops take the result as the last parameter |
211 | switch (left.GetType().InternalType()) { |
212 | case PhysicalType::BOOL: |
213 | case PhysicalType::INT8: |
214 | TemplatedExecute<int8_t, OP>(left, right, result, count); |
215 | break; |
216 | case PhysicalType::INT16: |
217 | TemplatedExecute<int16_t, OP>(left, right, result, count); |
218 | break; |
219 | case PhysicalType::INT32: |
220 | TemplatedExecute<int32_t, OP>(left, right, result, count); |
221 | break; |
222 | case PhysicalType::INT64: |
223 | TemplatedExecute<int64_t, OP>(left, right, result, count); |
224 | break; |
225 | case PhysicalType::UINT8: |
226 | TemplatedExecute<uint8_t, OP>(left, right, result, count); |
227 | break; |
228 | case PhysicalType::UINT16: |
229 | TemplatedExecute<uint16_t, OP>(left, right, result, count); |
230 | break; |
231 | case PhysicalType::UINT32: |
232 | TemplatedExecute<uint32_t, OP>(left, right, result, count); |
233 | break; |
234 | case PhysicalType::UINT64: |
235 | TemplatedExecute<uint64_t, OP>(left, right, result, count); |
236 | break; |
237 | case PhysicalType::INT128: |
238 | TemplatedExecute<hugeint_t, OP>(left, right, result, count); |
239 | break; |
240 | case PhysicalType::FLOAT: |
241 | TemplatedExecute<float, OP>(left, right, result, count); |
242 | break; |
243 | case PhysicalType::DOUBLE: |
244 | TemplatedExecute<double, OP>(left, right, result, count); |
245 | break; |
246 | case PhysicalType::INTERVAL: |
247 | TemplatedExecute<interval_t, OP>(left, right, result, count); |
248 | break; |
249 | case PhysicalType::VARCHAR: |
250 | TemplatedExecute<string_t, OP>(left, right, result, count); |
251 | break; |
252 | case PhysicalType::LIST: |
253 | case PhysicalType::STRUCT: |
254 | NestedComparisonExecutor<OP>(left, right, result, count); |
255 | break; |
256 | default: |
257 | throw InternalException("Invalid type for comparison" ); |
258 | } |
259 | } |
260 | }; |
261 | |
262 | void VectorOperations::Equals(Vector &left, Vector &right, Vector &result, idx_t count) { |
263 | ComparisonExecutor::Execute<duckdb::Equals>(left, right, result, count); |
264 | } |
265 | |
266 | void VectorOperations::NotEquals(Vector &left, Vector &right, Vector &result, idx_t count) { |
267 | ComparisonExecutor::Execute<duckdb::NotEquals>(left, right, result, count); |
268 | } |
269 | |
270 | void VectorOperations::GreaterThanEquals(Vector &left, Vector &right, Vector &result, idx_t count) { |
271 | ComparisonExecutor::Execute<duckdb::GreaterThanEquals>(left, right, result, count); |
272 | } |
273 | |
274 | void VectorOperations::LessThanEquals(Vector &left, Vector &right, Vector &result, idx_t count) { |
275 | ComparisonExecutor::Execute<duckdb::GreaterThanEquals>(left&: right, right&: left, result, count); |
276 | } |
277 | |
278 | void VectorOperations::GreaterThan(Vector &left, Vector &right, Vector &result, idx_t count) { |
279 | ComparisonExecutor::Execute<duckdb::GreaterThan>(left, right, result, count); |
280 | } |
281 | |
282 | void VectorOperations::LessThan(Vector &left, Vector &right, Vector &result, idx_t count) { |
283 | ComparisonExecutor::Execute<duckdb::GreaterThan>(left&: right, right&: left, result, count); |
284 | } |
285 | |
286 | } // namespace duckdb |
287 | |