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
14namespace duckdb {
15
16template <class T>
17bool 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
24template <>
25bool Equals::Operation(const float &left, const float &right) {
26 return EqualsFloat<float>(left, right);
27}
28
29template <>
30bool Equals::Operation(const double &left, const double &right) {
31 return EqualsFloat<double>(left, right);
32}
33
34template <class T>
35bool 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
51template <>
52bool GreaterThan::Operation(const float &left, const float &right) {
53 return GreaterThanFloat<float>(left, right);
54}
55
56template <>
57bool GreaterThan::Operation(const double &left, const double &right) {
58 return GreaterThanFloat<double>(left, right);
59}
60
61template <class T>
62bool 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
79template <>
80bool GreaterThanEquals::Operation(const float &left, const float &right) {
81 return GreaterThanEqualsFloat<float>(left, right);
82}
83
84template <>
85bool GreaterThanEquals::Operation(const double &left, const double &right) {
86 return GreaterThanEqualsFloat<double>(left, right);
87}
88
89struct 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
97template <>
98inline 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
104template <>
105inline 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
111template <>
112inline 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
118template <>
119inline 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
126template <>
127inline 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
133template <>
134inline 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
140static 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
151template <typename OP>
152static 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
199struct ComparisonExecutor {
200private:
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
206public:
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
262void VectorOperations::Equals(Vector &left, Vector &right, Vector &result, idx_t count) {
263 ComparisonExecutor::Execute<duckdb::Equals>(left, right, result, count);
264}
265
266void VectorOperations::NotEquals(Vector &left, Vector &right, Vector &result, idx_t count) {
267 ComparisonExecutor::Execute<duckdb::NotEquals>(left, right, result, count);
268}
269
270void VectorOperations::GreaterThanEquals(Vector &left, Vector &right, Vector &result, idx_t count) {
271 ComparisonExecutor::Execute<duckdb::GreaterThanEquals>(left, right, result, count);
272}
273
274void VectorOperations::LessThanEquals(Vector &left, Vector &right, Vector &result, idx_t count) {
275 ComparisonExecutor::Execute<duckdb::GreaterThanEquals>(left&: right, right&: left, result, count);
276}
277
278void VectorOperations::GreaterThan(Vector &left, Vector &right, Vector &result, idx_t count) {
279 ComparisonExecutor::Execute<duckdb::GreaterThan>(left, right, result, count);
280}
281
282void 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