1#pragma once
2
3#include <Common/memcmpSmall.h>
4#include <Common/assert_cast.h>
5
6#include <Columns/ColumnsNumber.h>
7#include <Columns/ColumnConst.h>
8#include <Columns/ColumnDecimal.h>
9#include <Columns/ColumnString.h>
10#include <Columns/ColumnFixedString.h>
11#include <Columns/ColumnTuple.h>
12#include <Columns/ColumnArray.h>
13
14#include <DataTypes/DataTypesNumber.h>
15#include <DataTypes/DataTypeDateTime.h>
16#include <DataTypes/DataTypeDateTime64.h>
17#include <DataTypes/DataTypeDate.h>
18#include <DataTypes/DataTypeString.h>
19#include <DataTypes/DataTypeUUID.h>
20#include <DataTypes/DataTypeFixedString.h>
21#include <DataTypes/DataTypeTuple.h>
22#include <DataTypes/DataTypeEnum.h>
23#include <DataTypes/getLeastSupertype.h>
24
25#include <Interpreters/castColumn.h>
26
27#include <Functions/FunctionsLogical.h>
28#include <Functions/IFunctionAdaptors.h>
29#include <Functions/FunctionHelpers.h>
30
31#include <Core/AccurateComparison.h>
32#include <Core/DecimalComparison.h>
33
34#include <IO/ReadBufferFromMemory.h>
35#include <IO/ReadHelpers.h>
36
37#include <limits>
38#include <type_traits>
39
40
41namespace DB
42{
43
44namespace ErrorCodes
45{
46 extern const int TOO_LARGE_STRING_SIZE;
47 extern const int ILLEGAL_COLUMN;
48 extern const int ILLEGAL_TYPE_OF_ARGUMENT;
49 extern const int LOGICAL_ERROR;
50 extern const int NOT_IMPLEMENTED;
51}
52
53
54/** Comparison functions: ==, !=, <, >, <=, >=.
55 * The comparison functions always return 0 or 1 (UInt8).
56 *
57 * You can compare the following types:
58 * - numbers and decimals;
59 * - strings and fixed strings;
60 * - dates;
61 * - datetimes;
62 * within each group, but not from different groups;
63 * - tuples (lexicographic comparison).
64 *
65 * Exception: You can compare the date and datetime with a constant string. Example: EventDate = '2015-01-01'.
66 */
67
68
69template <typename A, typename B, typename Op>
70struct NumComparisonImpl
71{
72 /// If you don't specify NO_INLINE, the compiler will inline this function, but we don't need this as this function contains tight loop inside.
73 static void NO_INLINE vector_vector(const PaddedPODArray<A> & a, const PaddedPODArray<B> & b, PaddedPODArray<UInt8> & c)
74 {
75 /** GCC 4.8.2 vectorizes a loop only if it is written in this form.
76 * In this case, if you loop through the array index (the code will look simpler),
77 * the loop will not be vectorized.
78 */
79
80 size_t size = a.size();
81 const A * a_pos = a.data();
82 const B * b_pos = b.data();
83 UInt8 * c_pos = c.data();
84 const A * a_end = a_pos + size;
85
86 while (a_pos < a_end)
87 {
88 *c_pos = Op::apply(*a_pos, *b_pos);
89 ++a_pos;
90 ++b_pos;
91 ++c_pos;
92 }
93 }
94
95 static void NO_INLINE vector_constant(const PaddedPODArray<A> & a, B b, PaddedPODArray<UInt8> & c)
96 {
97 size_t size = a.size();
98 const A * a_pos = a.data();
99 UInt8 * c_pos = c.data();
100 const A * a_end = a_pos + size;
101
102 while (a_pos < a_end)
103 {
104 *c_pos = Op::apply(*a_pos, b);
105 ++a_pos;
106 ++c_pos;
107 }
108 }
109
110 static void constant_vector(A a, const PaddedPODArray<B> & b, PaddedPODArray<UInt8> & c)
111 {
112 NumComparisonImpl<B, A, typename Op::SymmetricOp>::vector_constant(b, a, c);
113 }
114
115 static void constant_constant(A a, B b, UInt8 & c)
116 {
117 c = Op::apply(a, b);
118 }
119};
120
121
122template <typename Op>
123struct StringComparisonImpl
124{
125 static void NO_INLINE string_vector_string_vector(
126 const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
127 const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
128 PaddedPODArray<UInt8> & c)
129 {
130 size_t size = a_offsets.size();
131 ColumnString::Offset prev_a_offset = 0;
132 ColumnString::Offset prev_b_offset = 0;
133
134 for (size_t i = 0; i < size; ++i)
135 {
136 c[i] = Op::apply(memcmpSmallAllowOverflow15(
137 a_data.data() + prev_a_offset, a_offsets[i] - prev_a_offset - 1,
138 b_data.data() + prev_b_offset, b_offsets[i] - prev_b_offset - 1), 0);
139
140 prev_a_offset = a_offsets[i];
141 prev_b_offset = b_offsets[i];
142 }
143 }
144
145 static void NO_INLINE string_vector_fixed_string_vector(
146 const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
147 const ColumnString::Chars & b_data, ColumnString::Offset b_n,
148 PaddedPODArray<UInt8> & c)
149 {
150 size_t size = a_offsets.size();
151 ColumnString::Offset prev_a_offset = 0;
152
153 for (size_t i = 0; i < size; ++i)
154 {
155 c[i] = Op::apply(memcmpSmallAllowOverflow15(
156 a_data.data() + prev_a_offset, a_offsets[i] - prev_a_offset - 1,
157 b_data.data() + i * b_n, b_n), 0);
158
159 prev_a_offset = a_offsets[i];
160 }
161 }
162
163 static void NO_INLINE string_vector_constant(
164 const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
165 const ColumnString::Chars & b_data, ColumnString::Offset b_size,
166 PaddedPODArray<UInt8> & c)
167 {
168 size_t size = a_offsets.size();
169 ColumnString::Offset prev_a_offset = 0;
170
171 for (size_t i = 0; i < size; ++i)
172 {
173 c[i] = Op::apply(memcmpSmallAllowOverflow15(
174 a_data.data() + prev_a_offset, a_offsets[i] - prev_a_offset - 1,
175 b_data.data(), b_size), 0);
176
177 prev_a_offset = a_offsets[i];
178 }
179 }
180
181 static void fixed_string_vector_string_vector(
182 const ColumnString::Chars & a_data, ColumnString::Offset a_n,
183 const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
184 PaddedPODArray<UInt8> & c)
185 {
186 StringComparisonImpl<typename Op::SymmetricOp>::string_vector_fixed_string_vector(b_data, b_offsets, a_data, a_n, c);
187 }
188
189 static void NO_INLINE fixed_string_vector_fixed_string_vector_16(
190 const ColumnString::Chars & a_data,
191 const ColumnString::Chars & b_data,
192 PaddedPODArray<UInt8> & c)
193 {
194 size_t size = a_data.size();
195
196 for (size_t i = 0, j = 0; i < size; i += 16, ++j)
197 c[j] = Op::apply(memcmp16(&a_data[i], &b_data[i]), 0);
198 }
199
200 static void NO_INLINE fixed_string_vector_constant_16(
201 const ColumnString::Chars & a_data,
202 const ColumnString::Chars & b_data,
203 PaddedPODArray<UInt8> & c)
204 {
205 size_t size = a_data.size();
206
207 for (size_t i = 0, j = 0; i < size; i += 16, ++j)
208 c[j] = Op::apply(memcmp16(&a_data[i], &b_data[0]), 0);
209 }
210
211 static void NO_INLINE fixed_string_vector_fixed_string_vector(
212 const ColumnString::Chars & a_data, ColumnString::Offset a_n,
213 const ColumnString::Chars & b_data, ColumnString::Offset b_n,
214 PaddedPODArray<UInt8> & c)
215 {
216 if (a_n == 16 && b_n == 16)
217 {
218 /** Specialization if both sizes are 16.
219 * To more efficient comparison of IPv6 addresses stored in FixedString(16).
220 */
221 fixed_string_vector_fixed_string_vector_16(a_data, b_data, c);
222 }
223 else if (a_n == b_n)
224 {
225 size_t size = a_data.size();
226 for (size_t i = 0, j = 0; i < size; i += a_n, ++j)
227 c[j] = Op::apply(memcmpSmallAllowOverflow15(a_data.data() + i, b_data.data() + i, a_n), 0);
228 }
229 else
230 {
231 size_t size = a_data.size() / a_n;
232
233 for (size_t i = 0; i < size; ++i)
234 c[i] = Op::apply(memcmpSmallAllowOverflow15(a_data.data() + i * a_n, a_n, b_data.data() + i * b_n, b_n), 0);
235 }
236 }
237
238 static void NO_INLINE fixed_string_vector_constant(
239 const ColumnString::Chars & a_data, ColumnString::Offset a_n,
240 const ColumnString::Chars & b_data, ColumnString::Offset b_size,
241 PaddedPODArray<UInt8> & c)
242 {
243 if (a_n == 16 && b_size == 16)
244 {
245 fixed_string_vector_constant_16(a_data, b_data, c);
246 }
247 else if (a_n == b_size)
248 {
249 size_t size = a_data.size();
250 for (size_t i = 0, j = 0; i < size; i += a_n, ++j)
251 c[j] = Op::apply(memcmpSmallAllowOverflow15(a_data.data() + i, b_data.data(), a_n), 0);
252 }
253 else
254 {
255 size_t size = a_data.size();
256 for (size_t i = 0, j = 0; i < size; i += a_n, ++j)
257 c[j] = Op::apply(memcmpSmallAllowOverflow15(a_data.data() + i, a_n, b_data.data(), b_size), 0);
258 }
259 }
260
261 static void constant_string_vector(
262 const ColumnString::Chars & a_data, ColumnString::Offset a_size,
263 const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
264 PaddedPODArray<UInt8> & c)
265 {
266 StringComparisonImpl<typename Op::SymmetricOp>::string_vector_constant(b_data, b_offsets, a_data, a_size, c);
267 }
268
269 static void constant_fixed_string_vector(
270 const ColumnString::Chars & a_data, ColumnString::Offset a_size,
271 const ColumnString::Chars & b_data, ColumnString::Offset b_n,
272 PaddedPODArray<UInt8> & c)
273 {
274 StringComparisonImpl<typename Op::SymmetricOp>::fixed_string_vector_constant(b_data, b_n, a_data, a_size, c);
275 }
276
277 static void constant_constant(
278 const ColumnString::Chars & a_data, ColumnString::Offset a_size,
279 const ColumnString::Chars & b_data, ColumnString::Offset b_size,
280 UInt8 & c)
281 {
282 c = Op::apply(memcmpSmallAllowOverflow15(a_data.data(), a_size, b_data.data(), b_size), 0);
283 }
284};
285
286
287/// Comparisons for equality/inequality are implemented slightly more efficient.
288template <bool positive>
289struct StringEqualsImpl
290{
291 static void NO_INLINE string_vector_string_vector(
292 const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
293 const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
294 PaddedPODArray<UInt8> & c)
295 {
296 size_t size = a_offsets.size();
297 ColumnString::Offset prev_a_offset = 0;
298 ColumnString::Offset prev_b_offset = 0;
299
300 for (size_t i = 0; i < size; ++i)
301 {
302 auto a_size = a_offsets[i] - prev_a_offset - 1;
303 auto b_size = b_offsets[i] - prev_b_offset - 1;
304
305 c[i] = positive == memequalSmallAllowOverflow15(
306 a_data.data() + prev_a_offset, a_size,
307 b_data.data() + prev_b_offset, b_size);
308
309 prev_a_offset = a_offsets[i];
310 prev_b_offset = b_offsets[i];
311 }
312 }
313
314 static void NO_INLINE string_vector_fixed_string_vector(
315 const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
316 const ColumnString::Chars & b_data, ColumnString::Offset b_n,
317 PaddedPODArray<UInt8> & c)
318 {
319 size_t size = a_offsets.size();
320 ColumnString::Offset prev_a_offset = 0;
321
322 for (size_t i = 0; i < size; ++i)
323 {
324 auto a_size = a_offsets[i] - prev_a_offset - 1;
325
326 c[i] = positive == memequalSmallAllowOverflow15(
327 a_data.data() + prev_a_offset, a_size,
328 b_data.data() + b_n * i, b_n);
329
330 prev_a_offset = a_offsets[i];
331 }
332 }
333
334 static void NO_INLINE string_vector_constant(
335 const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
336 const ColumnString::Chars & b_data, ColumnString::Offset b_size,
337 PaddedPODArray<UInt8> & c)
338 {
339 size_t size = a_offsets.size();
340 ColumnString::Offset prev_a_offset = 0;
341
342 for (size_t i = 0; i < size; ++i)
343 {
344 auto a_size = a_offsets[i] - prev_a_offset - 1;
345
346 c[i] = positive == memequalSmallAllowOverflow15(
347 a_data.data() + prev_a_offset, a_size,
348 b_data.data(), b_size);
349
350 prev_a_offset = a_offsets[i];
351 }
352 }
353
354 static void NO_INLINE fixed_string_vector_fixed_string_vector_16(
355 const ColumnString::Chars & a_data,
356 const ColumnString::Chars & b_data,
357 PaddedPODArray<UInt8> & c)
358 {
359 size_t size = a_data.size() / 16;
360
361 for (size_t i = 0; i < size; ++i)
362 c[i] = positive == memequal16(
363 a_data.data() + i * 16,
364 b_data.data() + i * 16);
365 }
366
367 static void NO_INLINE fixed_string_vector_constant_16(
368 const ColumnString::Chars & a_data,
369 const ColumnString::Chars & b_data,
370 PaddedPODArray<UInt8> & c)
371 {
372 size_t size = a_data.size() / 16;
373
374 for (size_t i = 0; i < size; ++i)
375 c[i] = positive == memequal16(
376 a_data.data() + i * 16,
377 b_data.data());
378 }
379
380 static void NO_INLINE fixed_string_vector_fixed_string_vector(
381 const ColumnString::Chars & a_data, ColumnString::Offset a_n,
382 const ColumnString::Chars & b_data, ColumnString::Offset b_n,
383 PaddedPODArray<UInt8> & c)
384 {
385 /** Specialization if both sizes are 16.
386 * To more efficient comparison of IPv6 addresses stored in FixedString(16).
387 */
388 if (a_n == 16 && b_n == 16)
389 {
390 fixed_string_vector_fixed_string_vector_16(a_data, b_data, c);
391 }
392 else
393 {
394 size_t size = a_data.size() / a_n;
395 for (size_t i = 0; i < size; ++i)
396 c[i] = positive == memequalSmallAllowOverflow15(a_data.data() + i * a_n, a_n, b_data.data() + i * b_n, b_n);
397 }
398 }
399
400 static void NO_INLINE fixed_string_vector_constant(
401 const ColumnString::Chars & a_data, ColumnString::Offset a_n,
402 const ColumnString::Chars & b_data, ColumnString::Offset b_size,
403 PaddedPODArray<UInt8> & c)
404 {
405 if (a_n == 16 && b_size == 16)
406 {
407 fixed_string_vector_constant_16(a_data, b_data, c);
408 }
409 else
410 {
411 size_t size = a_data.size() / a_n;
412 for (size_t i = 0; i < size; ++i)
413 c[i] = positive == memequalSmallAllowOverflow15(a_data.data() + i * a_n, a_n, b_data.data(), b_size);
414 }
415 }
416
417 static void fixed_string_vector_string_vector(
418 const ColumnString::Chars & a_data, ColumnString::Offset a_n,
419 const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
420 PaddedPODArray<UInt8> & c)
421 {
422 string_vector_fixed_string_vector(b_data, b_offsets, a_data, a_n, c);
423 }
424
425 static void constant_string_vector(
426 const ColumnString::Chars & a_data, ColumnString::Offset a_size,
427 const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
428 PaddedPODArray<UInt8> & c)
429 {
430 string_vector_constant(b_data, b_offsets, a_data, a_size, c);
431 }
432
433 static void constant_fixed_string_vector(
434 const ColumnString::Chars & a_data, ColumnString::Offset a_size,
435 const ColumnString::Chars & b_data, ColumnString::Offset b_n,
436 PaddedPODArray<UInt8> & c)
437 {
438 fixed_string_vector_constant(b_data, b_n, a_data, a_size, c);
439 }
440
441 static void constant_constant(
442 const ColumnString::Chars & a_data, ColumnString::Offset a_size,
443 const ColumnString::Chars & b_data, ColumnString::Offset b_size,
444 UInt8 & c)
445 {
446 c = positive == memequalSmallAllowOverflow15(a_data.data(), a_size, b_data.data(), b_size);
447 }
448};
449
450
451template <typename A, typename B>
452struct StringComparisonImpl<EqualsOp<A, B>> : StringEqualsImpl<true> {};
453
454template <typename A, typename B>
455struct StringComparisonImpl<NotEqualsOp<A, B>> : StringEqualsImpl<false> {};
456
457
458/// Generic version, implemented for columns of same type.
459template <typename Op>
460struct GenericComparisonImpl
461{
462 static void NO_INLINE vector_vector(const IColumn & a, const IColumn & b, PaddedPODArray<UInt8> & c)
463 {
464 for (size_t i = 0, size = a.size(); i < size; ++i)
465 c[i] = Op::apply(a.compareAt(i, i, b, 1), 0);
466 }
467
468 static void NO_INLINE vector_constant(const IColumn & a, const IColumn & b, PaddedPODArray<UInt8> & c)
469 {
470 auto b_materialized = b.cloneResized(1)->convertToFullColumnIfConst();
471 for (size_t i = 0, size = a.size(); i < size; ++i)
472 c[i] = Op::apply(a.compareAt(i, 0, *b_materialized, 1), 0);
473 }
474
475 static void constant_vector(const IColumn & a, const IColumn & b, PaddedPODArray<UInt8> & c)
476 {
477 GenericComparisonImpl<typename Op::SymmetricOp>::vector_constant(b, a, c);
478 }
479
480 static void constant_constant(const IColumn & a, const IColumn & b, UInt8 & c)
481 {
482 c = Op::apply(a.compareAt(0, 0, b, 1), 0);
483 }
484};
485
486
487#if USE_EMBEDDED_COMPILER
488
489template <template <typename, typename> typename Op> struct CompileOp;
490
491template <> struct CompileOp<EqualsOp>
492{
493 static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool /*is_signed*/)
494 {
495 return x->getType()->isIntegerTy() ? b.CreateICmpEQ(x, y) : b.CreateFCmpOEQ(x, y); /// qNaNs always compare false
496 }
497};
498
499template <> struct CompileOp<NotEqualsOp>
500{
501 static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool /*is_signed*/)
502 {
503 return x->getType()->isIntegerTy() ? b.CreateICmpNE(x, y) : b.CreateFCmpONE(x, y);
504 }
505};
506
507template <> struct CompileOp<LessOp>
508{
509 static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool is_signed)
510 {
511 return x->getType()->isIntegerTy() ? (is_signed ? b.CreateICmpSLT(x, y) : b.CreateICmpULT(x, y)) : b.CreateFCmpOLT(x, y);
512 }
513};
514
515template <> struct CompileOp<GreaterOp>
516{
517 static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool is_signed)
518 {
519 return x->getType()->isIntegerTy() ? (is_signed ? b.CreateICmpSGT(x, y) : b.CreateICmpUGT(x, y)) : b.CreateFCmpOGT(x, y);
520 }
521};
522
523template <> struct CompileOp<LessOrEqualsOp>
524{
525 static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool is_signed)
526 {
527 return x->getType()->isIntegerTy() ? (is_signed ? b.CreateICmpSLE(x, y) : b.CreateICmpULE(x, y)) : b.CreateFCmpOLE(x, y);
528 }
529};
530
531template <> struct CompileOp<GreaterOrEqualsOp>
532{
533 static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool is_signed)
534 {
535 return x->getType()->isIntegerTy() ? (is_signed ? b.CreateICmpSGE(x, y) : b.CreateICmpUGE(x, y)) : b.CreateFCmpOGE(x, y);
536 }
537};
538
539#endif
540
541
542struct NameEquals { static constexpr auto name = "equals"; };
543struct NameNotEquals { static constexpr auto name = "notEquals"; };
544struct NameLess { static constexpr auto name = "less"; };
545struct NameGreater { static constexpr auto name = "greater"; };
546struct NameLessOrEquals { static constexpr auto name = "lessOrEquals"; };
547struct NameGreaterOrEquals { static constexpr auto name = "greaterOrEquals"; };
548
549
550template <
551 template <typename, typename> class Op,
552 typename Name>
553class FunctionComparison : public IFunction
554{
555public:
556 static constexpr auto name = Name::name;
557 static FunctionPtr create(const Context & context) { return std::make_shared<FunctionComparison>(context); }
558
559 FunctionComparison(const Context & context_)
560 : context(context_),
561 check_decimal_overflow(decimalCheckComparisonOverflow(context))
562 {}
563
564private:
565 const Context & context;
566 bool check_decimal_overflow = true;
567
568 template <typename T0, typename T1>
569 bool executeNumRightType(Block & block, size_t result, const ColumnVector<T0> * col_left, const IColumn * col_right_untyped)
570 {
571 if (const ColumnVector<T1> * col_right = checkAndGetColumn<ColumnVector<T1>>(col_right_untyped))
572 {
573 auto col_res = ColumnUInt8::create();
574
575 ColumnUInt8::Container & vec_res = col_res->getData();
576 vec_res.resize(col_left->getData().size());
577 NumComparisonImpl<T0, T1, Op<T0, T1>>::vector_vector(col_left->getData(), col_right->getData(), vec_res);
578
579 block.getByPosition(result).column = std::move(col_res);
580 return true;
581 }
582 else if (auto col_right_const = checkAndGetColumnConst<ColumnVector<T1>>(col_right_untyped))
583 {
584 auto col_res = ColumnUInt8::create();
585
586 ColumnUInt8::Container & vec_res = col_res->getData();
587 vec_res.resize(col_left->size());
588 NumComparisonImpl<T0, T1, Op<T0, T1>>::vector_constant(col_left->getData(), col_right_const->template getValue<T1>(), vec_res);
589
590 block.getByPosition(result).column = std::move(col_res);
591 return true;
592 }
593
594 return false;
595 }
596
597 template <typename T0, typename T1>
598 bool executeNumConstRightType(Block & block, size_t result, const ColumnConst * col_left, const IColumn * col_right_untyped)
599 {
600 if (const ColumnVector<T1> * col_right = checkAndGetColumn<ColumnVector<T1>>(col_right_untyped))
601 {
602 auto col_res = ColumnUInt8::create();
603
604 ColumnUInt8::Container & vec_res = col_res->getData();
605 vec_res.resize(col_left->size());
606 NumComparisonImpl<T0, T1, Op<T0, T1>>::constant_vector(col_left->template getValue<T0>(), col_right->getData(), vec_res);
607
608 block.getByPosition(result).column = std::move(col_res);
609 return true;
610 }
611 else if (auto col_right_const = checkAndGetColumnConst<ColumnVector<T1>>(col_right_untyped))
612 {
613 UInt8 res = 0;
614 NumComparisonImpl<T0, T1, Op<T0, T1>>::constant_constant(col_left->template getValue<T0>(), col_right_const->template getValue<T1>(), res);
615
616 block.getByPosition(result).column = DataTypeUInt8().createColumnConst(col_left->size(), toField(res));
617 return true;
618 }
619
620 return false;
621 }
622
623 template <typename T0>
624 bool executeNumLeftType(Block & block, size_t result, const IColumn * col_left_untyped, const IColumn * col_right_untyped)
625 {
626 if (const ColumnVector<T0> * col_left = checkAndGetColumn<ColumnVector<T0>>(col_left_untyped))
627 {
628 if ( executeNumRightType<T0, UInt8>(block, result, col_left, col_right_untyped)
629 || executeNumRightType<T0, UInt16>(block, result, col_left, col_right_untyped)
630 || executeNumRightType<T0, UInt32>(block, result, col_left, col_right_untyped)
631 || executeNumRightType<T0, UInt64>(block, result, col_left, col_right_untyped)
632 || executeNumRightType<T0, UInt128>(block, result, col_left, col_right_untyped)
633 || executeNumRightType<T0, Int8>(block, result, col_left, col_right_untyped)
634 || executeNumRightType<T0, Int16>(block, result, col_left, col_right_untyped)
635 || executeNumRightType<T0, Int32>(block, result, col_left, col_right_untyped)
636 || executeNumRightType<T0, Int64>(block, result, col_left, col_right_untyped)
637 || executeNumRightType<T0, Int128>(block, result, col_left, col_right_untyped)
638 || executeNumRightType<T0, Float32>(block, result, col_left, col_right_untyped)
639 || executeNumRightType<T0, Float64>(block, result, col_left, col_right_untyped))
640 return true;
641 else
642 throw Exception("Illegal column " + col_right_untyped->getName()
643 + " of second argument of function " + getName(),
644 ErrorCodes::ILLEGAL_COLUMN);
645 }
646 else if (auto col_left_const = checkAndGetColumnConst<ColumnVector<T0>>(col_left_untyped))
647 {
648 if ( executeNumConstRightType<T0, UInt8>(block, result, col_left_const, col_right_untyped)
649 || executeNumConstRightType<T0, UInt16>(block, result, col_left_const, col_right_untyped)
650 || executeNumConstRightType<T0, UInt32>(block, result, col_left_const, col_right_untyped)
651 || executeNumConstRightType<T0, UInt64>(block, result, col_left_const, col_right_untyped)
652 || executeNumConstRightType<T0, UInt128>(block, result, col_left_const, col_right_untyped)
653 || executeNumConstRightType<T0, Int8>(block, result, col_left_const, col_right_untyped)
654 || executeNumConstRightType<T0, Int16>(block, result, col_left_const, col_right_untyped)
655 || executeNumConstRightType<T0, Int32>(block, result, col_left_const, col_right_untyped)
656 || executeNumConstRightType<T0, Int64>(block, result, col_left_const, col_right_untyped)
657 || executeNumConstRightType<T0, Int128>(block, result, col_left_const, col_right_untyped)
658 || executeNumConstRightType<T0, Float32>(block, result, col_left_const, col_right_untyped)
659 || executeNumConstRightType<T0, Float64>(block, result, col_left_const, col_right_untyped))
660 return true;
661 else
662 throw Exception("Illegal column " + col_right_untyped->getName()
663 + " of second argument of function " + getName(),
664 ErrorCodes::ILLEGAL_COLUMN);
665 }
666
667 return false;
668 }
669
670 void executeDecimal(Block & block, size_t result, const ColumnWithTypeAndName & col_left, const ColumnWithTypeAndName & col_right)
671 {
672 TypeIndex left_number = col_left.type->getTypeId();
673 TypeIndex right_number = col_right.type->getTypeId();
674
675 auto call = [&](const auto & types) -> bool
676 {
677 using Types = std::decay_t<decltype(types)>;
678 using LeftDataType = typename Types::LeftType;
679 using RightDataType = typename Types::RightType;
680
681 if (check_decimal_overflow)
682 DecimalComparison<LeftDataType, RightDataType, Op, true>(block, result, col_left, col_right);
683 else
684 DecimalComparison<LeftDataType, RightDataType, Op, false>(block, result, col_left, col_right);
685 return true;
686 };
687
688 if (!callOnBasicTypes<true, false, true, true>(left_number, right_number, call))
689 throw Exception("Wrong call for " + getName() + " with " + col_left.type->getName() + " and " + col_right.type->getName(),
690 ErrorCodes::LOGICAL_ERROR);
691 }
692
693 bool executeString(Block & block, size_t result, const IColumn * c0, const IColumn * c1)
694 {
695 const ColumnString * c0_string = checkAndGetColumn<ColumnString>(c0);
696 const ColumnString * c1_string = checkAndGetColumn<ColumnString>(c1);
697 const ColumnFixedString * c0_fixed_string = checkAndGetColumn<ColumnFixedString>(c0);
698 const ColumnFixedString * c1_fixed_string = checkAndGetColumn<ColumnFixedString>(c1);
699
700 const ColumnConst * c0_const = checkAndGetColumnConstStringOrFixedString(c0);
701 const ColumnConst * c1_const = checkAndGetColumnConstStringOrFixedString(c1);
702
703 if (!((c0_string || c0_fixed_string || c0_const) && (c1_string || c1_fixed_string || c1_const)))
704 return false;
705
706 const ColumnString::Chars * c0_const_chars = nullptr;
707 const ColumnString::Chars * c1_const_chars = nullptr;
708 ColumnString::Offset c0_const_size = 0;
709 ColumnString::Offset c1_const_size = 0;
710
711 if (c0_const)
712 {
713 const ColumnString * c0_const_string = checkAndGetColumn<ColumnString>(&c0_const->getDataColumn());
714 const ColumnFixedString * c0_const_fixed_string = checkAndGetColumn<ColumnFixedString>(&c0_const->getDataColumn());
715
716 if (c0_const_string)
717 {
718 c0_const_chars = &c0_const_string->getChars();
719 c0_const_size = c0_const_string->getDataAt(0).size;
720 }
721 else if (c0_const_fixed_string)
722 {
723 c0_const_chars = &c0_const_fixed_string->getChars();
724 c0_const_size = c0_const_fixed_string->getN();
725 }
726 else
727 throw Exception("Logical error: ColumnConst contains not String nor FixedString column", ErrorCodes::ILLEGAL_COLUMN);
728 }
729
730 if (c1_const)
731 {
732 const ColumnString * c1_const_string = checkAndGetColumn<ColumnString>(&c1_const->getDataColumn());
733 const ColumnFixedString * c1_const_fixed_string = checkAndGetColumn<ColumnFixedString>(&c1_const->getDataColumn());
734
735 if (c1_const_string)
736 {
737 c1_const_chars = &c1_const_string->getChars();
738 c1_const_size = c1_const_string->getDataAt(0).size;
739 }
740 else if (c1_const_fixed_string)
741 {
742 c1_const_chars = &c1_const_fixed_string->getChars();
743 c1_const_size = c1_const_fixed_string->getN();
744 }
745 else
746 throw Exception("Logical error: ColumnConst contains not String nor FixedString column", ErrorCodes::ILLEGAL_COLUMN);
747 }
748
749 using StringImpl = StringComparisonImpl<Op<int, int>>;
750
751 if (c0_const && c1_const)
752 {
753 UInt8 res = 0;
754 StringImpl::constant_constant(*c0_const_chars, c0_const_size, *c1_const_chars, c1_const_size, res);
755 block.getByPosition(result).column = block.getByPosition(result).type->createColumnConst(c0_const->size(), toField(res));
756 return true;
757 }
758 else
759 {
760 auto c_res = ColumnUInt8::create();
761 ColumnUInt8::Container & vec_res = c_res->getData();
762 vec_res.resize(c0->size());
763
764 if (c0_string && c1_string)
765 StringImpl::string_vector_string_vector(
766 c0_string->getChars(), c0_string->getOffsets(),
767 c1_string->getChars(), c1_string->getOffsets(),
768 c_res->getData());
769 else if (c0_string && c1_fixed_string)
770 StringImpl::string_vector_fixed_string_vector(
771 c0_string->getChars(), c0_string->getOffsets(),
772 c1_fixed_string->getChars(), c1_fixed_string->getN(),
773 c_res->getData());
774 else if (c0_string && c1_const)
775 StringImpl::string_vector_constant(
776 c0_string->getChars(), c0_string->getOffsets(),
777 *c1_const_chars, c1_const_size,
778 c_res->getData());
779 else if (c0_fixed_string && c1_string)
780 StringImpl::fixed_string_vector_string_vector(
781 c0_fixed_string->getChars(), c0_fixed_string->getN(),
782 c1_string->getChars(), c1_string->getOffsets(),
783 c_res->getData());
784 else if (c0_fixed_string && c1_fixed_string)
785 StringImpl::fixed_string_vector_fixed_string_vector(
786 c0_fixed_string->getChars(), c0_fixed_string->getN(),
787 c1_fixed_string->getChars(), c1_fixed_string->getN(),
788 c_res->getData());
789 else if (c0_fixed_string && c1_const)
790 StringImpl::fixed_string_vector_constant(
791 c0_fixed_string->getChars(), c0_fixed_string->getN(),
792 *c1_const_chars, c1_const_size,
793 c_res->getData());
794 else if (c0_const && c1_string)
795 StringImpl::constant_string_vector(
796 *c0_const_chars, c0_const_size,
797 c1_string->getChars(), c1_string->getOffsets(),
798 c_res->getData());
799 else if (c0_const && c1_fixed_string)
800 StringImpl::constant_fixed_string_vector(
801 *c0_const_chars, c0_const_size,
802 c1_fixed_string->getChars(), c1_fixed_string->getN(),
803 c_res->getData());
804 else
805 throw Exception("Illegal columns "
806 + c0->getName() + " and " + c1->getName()
807 + " of arguments of function " + getName(),
808 ErrorCodes::ILLEGAL_COLUMN);
809
810 block.getByPosition(result).column = std::move(c_res);
811 return true;
812 }
813 }
814
815 bool executeDateOrDateTimeOrEnumOrUUIDWithConstString(
816 Block & block, size_t result, const IColumn * col_left_untyped, const IColumn * col_right_untyped,
817 const DataTypePtr & left_type, const DataTypePtr & right_type, bool left_is_num, size_t input_rows_count)
818 {
819 /// This is no longer very special case - comparing dates, datetimes, and enumerations with a string constant.
820 const IColumn * column_string_untyped = !left_is_num ? col_left_untyped : col_right_untyped;
821 const IColumn * column_number = left_is_num ? col_left_untyped : col_right_untyped;
822 const IDataType * number_type = left_is_num ? left_type.get() : right_type.get();
823
824 WhichDataType which(number_type);
825
826 const bool legal_types = which.isDateOrDateTime() || which.isEnum() || which.isUUID();
827
828 const auto column_string = checkAndGetColumnConst<ColumnString>(column_string_untyped);
829 if (!column_string || !legal_types)
830 return false;
831
832 StringRef string_value = column_string->getDataAt(0);
833
834 if (which.isDate())
835 {
836 DayNum date;
837 ReadBufferFromMemory in(string_value.data, string_value.size);
838 readDateText(date, in);
839 if (!in.eof())
840 throw Exception("String is too long for Date: " + string_value.toString(), ErrorCodes::TOO_LARGE_STRING_SIZE);
841
842 ColumnPtr parsed_const_date_holder = DataTypeDate().createColumnConst(input_rows_count, date);
843 const ColumnConst * parsed_const_date = assert_cast<const ColumnConst *>(parsed_const_date_holder.get());
844 executeNumLeftType<DataTypeDate::FieldType>(block, result,
845 left_is_num ? col_left_untyped : parsed_const_date,
846 left_is_num ? parsed_const_date : col_right_untyped);
847 }
848 else if (which.isDateTime())
849 {
850 time_t date_time;
851 ReadBufferFromMemory in(string_value.data, string_value.size);
852 readDateTimeText(date_time, in);
853 if (!in.eof())
854 throw Exception("String is too long for DateTime: " + string_value.toString(), ErrorCodes::TOO_LARGE_STRING_SIZE);
855
856 ColumnPtr parsed_const_date_time_holder = DataTypeDateTime().createColumnConst(input_rows_count, UInt64(date_time));
857 const ColumnConst * parsed_const_date_time = assert_cast<const ColumnConst *>(parsed_const_date_time_holder.get());
858 executeNumLeftType<DataTypeDateTime::FieldType>(block, result,
859 left_is_num ? col_left_untyped : parsed_const_date_time,
860 left_is_num ? parsed_const_date_time : col_right_untyped);
861 }
862 else if (which.isUUID())
863 {
864 UUID uuid;
865 ReadBufferFromMemory in(string_value.data, string_value.size);
866 readText(uuid, in);
867 if (!in.eof())
868 throw Exception("String is too long for UUID: " + string_value.toString(), ErrorCodes::TOO_LARGE_STRING_SIZE);
869
870 ColumnPtr parsed_const_uuid_holder = DataTypeUUID().createColumnConst(input_rows_count, uuid);
871 const ColumnConst * parsed_const_uuid = assert_cast<const ColumnConst *>(parsed_const_uuid_holder.get());
872 executeNumLeftType<DataTypeUUID::FieldType>(block, result,
873 left_is_num ? col_left_untyped : parsed_const_uuid,
874 left_is_num ? parsed_const_uuid : col_right_untyped);
875 }
876
877 else if (which.isEnum8())
878 executeEnumWithConstString<DataTypeEnum8>(block, result, column_number, column_string,
879 number_type, left_is_num, input_rows_count);
880 else if (which.isEnum16())
881 executeEnumWithConstString<DataTypeEnum16>(block, result, column_number, column_string,
882 number_type, left_is_num, input_rows_count);
883
884 return true;
885 }
886
887 /// Comparison between DataTypeEnum<T> and string constant containing the name of an enum element
888 template <typename EnumType>
889 void executeEnumWithConstString(
890 Block & block, const size_t result, const IColumn * column_number, const ColumnConst * column_string,
891 const IDataType * type_untyped, const bool left_is_num, size_t input_rows_count)
892 {
893 const auto type = static_cast<const EnumType *>(type_untyped);
894
895 const Field x = castToNearestFieldType(type->getValue(column_string->getValue<String>()));
896 const auto enum_col = type->createColumnConst(input_rows_count, x);
897
898 executeNumLeftType<typename EnumType::FieldType>(block, result,
899 left_is_num ? column_number : enum_col.get(),
900 left_is_num ? enum_col.get() : column_number);
901 }
902
903 void executeTuple(Block & block, size_t result, const ColumnWithTypeAndName & c0, const ColumnWithTypeAndName & c1,
904 size_t input_rows_count)
905 {
906 /** We will lexicographically compare the tuples. This is done as follows:
907 * x == y : x1 == y1 && x2 == y2 ...
908 * x != y : x1 != y1 || x2 != y2 ...
909 *
910 * x < y: x1 < y1 || (x1 == y1 && (x2 < y2 || (x2 == y2 ... && xn < yn))
911 * x > y: x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 == y2 ... && xn > yn))
912 * x <= y: x1 < y1 || (x1 == y1 && (x2 < y2 || (x2 == y2 ... && xn <= yn))
913 *
914 * Recursive form:
915 * x <= y: x1 < y1 || (x1 == y1 && x_tail <= y_tail)
916 *
917 * x >= y: x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 == y2 ... && xn >= yn))
918 */
919
920 const size_t tuple_size = typeid_cast<const DataTypeTuple &>(*c0.type).getElements().size();
921
922 if (0 == tuple_size)
923 throw Exception("Comparison of zero-sized tuples is not implemented.", ErrorCodes::NOT_IMPLEMENTED);
924
925 ColumnsWithTypeAndName x(tuple_size);
926 ColumnsWithTypeAndName y(tuple_size);
927
928 auto x_const = checkAndGetColumnConst<ColumnTuple>(c0.column.get());
929 auto y_const = checkAndGetColumnConst<ColumnTuple>(c1.column.get());
930
931 Columns x_columns;
932 Columns y_columns;
933
934 if (x_const)
935 x_columns = convertConstTupleToConstantElements(*x_const);
936 else
937 x_columns = assert_cast<const ColumnTuple &>(*c0.column).getColumnsCopy();
938
939 if (y_const)
940 y_columns = convertConstTupleToConstantElements(*y_const);
941 else
942 y_columns = assert_cast<const ColumnTuple &>(*c1.column).getColumnsCopy();
943
944 for (size_t i = 0; i < tuple_size; ++i)
945 {
946 x[i].type = static_cast<const DataTypeTuple &>(*c0.type).getElements()[i];
947 y[i].type = static_cast<const DataTypeTuple &>(*c1.type).getElements()[i];
948
949 x[i].column = x_columns[i];
950 y[i].column = y_columns[i];
951 }
952
953 executeTupleImpl(block, result, x, y, tuple_size, input_rows_count);
954 }
955
956 void executeTupleImpl(Block & block, size_t result, const ColumnsWithTypeAndName & x,
957 const ColumnsWithTypeAndName & y, size_t tuple_size,
958 size_t input_rows_count);
959
960 template <typename ComparisonFunction, typename ConvolutionFunction>
961 void executeTupleEqualityImpl(Block & block, size_t result, const ColumnsWithTypeAndName & x, const ColumnsWithTypeAndName & y,
962 size_t tuple_size, size_t input_rows_count)
963 {
964 if (0 == tuple_size)
965 throw Exception("Comparison of zero-sized tuples is not implemented.", ErrorCodes::NOT_IMPLEMENTED);
966
967 auto func_compare = ComparisonFunction::create(context);
968 auto func_convolution = ConvolutionFunction::create(context);
969
970 auto func_compare_adaptor = FunctionOverloadResolverAdaptor(std::make_unique<DefaultOverloadResolver>(func_compare));
971 auto func_convolution_adaptor = FunctionOverloadResolverAdaptor(std::make_unique<DefaultOverloadResolver>(func_convolution));
972
973 Block tmp_block;
974 for (size_t i = 0; i < tuple_size; ++i)
975 {
976 tmp_block.insert(x[i]);
977 tmp_block.insert(y[i]);
978
979 auto impl = func_compare_adaptor.build({x[i], y[i]});
980
981 /// Comparison of the elements.
982 tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" });
983 impl->execute(tmp_block, {i * 3, i * 3 + 1}, i * 3 + 2, input_rows_count);
984 }
985
986 if (tuple_size == 1)
987 {
988 /// Do not call AND for single-element tuple.
989 block.getByPosition(result).column = tmp_block.getByPosition(2).column;
990 return;
991 }
992
993 /// Logical convolution.
994 tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" });
995
996 ColumnNumbers convolution_args(tuple_size);
997 for (size_t i = 0; i < tuple_size; ++i)
998 convolution_args[i] = i * 3 + 2;
999
1000 ColumnsWithTypeAndName convolution_types(convolution_args.size(), { nullptr, std::make_shared<DataTypeUInt8>(), "" });
1001 auto impl = func_convolution_adaptor.build(convolution_types);
1002
1003 impl->execute(tmp_block, convolution_args, tuple_size * 3, input_rows_count);
1004 block.getByPosition(result).column = tmp_block.getByPosition(tuple_size * 3).column;
1005 }
1006
1007 template <typename HeadComparisonFunction, typename TailComparisonFunction>
1008 void executeTupleLessGreaterImpl(Block & block, size_t result, const ColumnsWithTypeAndName & x,
1009 const ColumnsWithTypeAndName & y, size_t tuple_size, size_t input_rows_count)
1010 {
1011 auto func_compare_head = HeadComparisonFunction::create(context);
1012 auto func_compare_tail = TailComparisonFunction::create(context);
1013 auto func_and = FunctionAnd::create(context);
1014 auto func_or = FunctionOr::create(context);
1015 auto func_equals = FunctionComparison<EqualsOp, NameEquals>::create(context);
1016
1017 auto func_compare_head_adaptor = FunctionOverloadResolverAdaptor(std::make_unique<DefaultOverloadResolver>(func_compare_head));
1018 auto func_compare_tail_adaptor = FunctionOverloadResolverAdaptor(std::make_unique<DefaultOverloadResolver>(func_compare_tail));
1019 auto func_equals_adaptor = FunctionOverloadResolverAdaptor(std::make_unique<DefaultOverloadResolver>(func_equals));
1020
1021 ColumnsWithTypeAndName bin_args = {{ nullptr, std::make_shared<DataTypeUInt8>(), "" },
1022 { nullptr, std::make_shared<DataTypeUInt8>(), "" }};
1023
1024 auto func_and_adaptor = FunctionOverloadResolverAdaptor(std::make_unique<DefaultOverloadResolver>(func_and))
1025 .build(bin_args);
1026
1027 auto func_or_adaptor = FunctionOverloadResolverAdaptor(std::make_unique<DefaultOverloadResolver>(func_or))
1028 .build(bin_args);
1029
1030 Block tmp_block;
1031
1032 /// Pairwise comparison of the inequality of all elements; on the equality of all elements except the last.
1033 for (size_t i = 0; i < tuple_size; ++i)
1034 {
1035 tmp_block.insert(x[i]);
1036 tmp_block.insert(y[i]);
1037
1038 tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" });
1039
1040 if (i + 1 != tuple_size)
1041 {
1042 auto impl_head = func_compare_head_adaptor.build({x[i], y[i]});
1043 impl_head->execute(tmp_block, {i * 4, i * 4 + 1}, i * 4 + 2, input_rows_count);
1044
1045 tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" });
1046
1047 auto impl_equals = func_equals_adaptor.build({x[i], y[i]});
1048 impl_equals->execute(tmp_block, {i * 4, i * 4 + 1}, i * 4 + 3, input_rows_count);
1049
1050 }
1051 else
1052 {
1053 auto impl_tail = func_compare_tail_adaptor.build({x[i], y[i]});
1054 impl_tail->execute(tmp_block, {i * 4, i * 4 + 1}, i * 4 + 2, input_rows_count);
1055 }
1056 }
1057
1058 /// Combination. Complex code - make a drawing. It can be replaced by a recursive comparison of tuples.
1059 size_t i = tuple_size - 1;
1060 while (i > 0)
1061 {
1062 tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" });
1063 func_and_adaptor->execute(tmp_block, {tmp_block.columns() - 2, (i - 1) * 4 + 3}, tmp_block.columns() - 1, input_rows_count);
1064 tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" });
1065 func_or_adaptor->execute(tmp_block, {tmp_block.columns() - 2, (i - 1) * 4 + 2}, tmp_block.columns() - 1, input_rows_count);
1066 --i;
1067 }
1068
1069 block.getByPosition(result).column = tmp_block.getByPosition(tmp_block.columns() - 1).column;
1070 }
1071
1072 void executeGenericIdenticalTypes(Block & block, size_t result, const IColumn * c0, const IColumn * c1)
1073 {
1074 bool c0_const = isColumnConst(*c0);
1075 bool c1_const = isColumnConst(*c1);
1076
1077 if (c0_const && c1_const)
1078 {
1079 UInt8 res = 0;
1080 GenericComparisonImpl<Op<int, int>>::constant_constant(*c0, *c1, res);
1081 block.getByPosition(result).column = DataTypeUInt8().createColumnConst(c0->size(), toField(res));
1082 }
1083 else
1084 {
1085 auto c_res = ColumnUInt8::create();
1086 ColumnUInt8::Container & vec_res = c_res->getData();
1087 vec_res.resize(c0->size());
1088
1089 if (c0_const)
1090 GenericComparisonImpl<Op<int, int>>::constant_vector(*c0, *c1, vec_res);
1091 else if (c1_const)
1092 GenericComparisonImpl<Op<int, int>>::vector_constant(*c0, *c1, vec_res);
1093 else
1094 GenericComparisonImpl<Op<int, int>>::vector_vector(*c0, *c1, vec_res);
1095
1096 block.getByPosition(result).column = std::move(c_res);
1097 }
1098 }
1099
1100 void executeGeneric(Block & block, size_t result, const ColumnWithTypeAndName & c0, const ColumnWithTypeAndName & c1)
1101 {
1102 DataTypePtr common_type = getLeastSupertype({c0.type, c1.type});
1103
1104 ColumnPtr c0_converted = castColumn(c0, common_type, context);
1105 ColumnPtr c1_converted = castColumn(c1, common_type, context);
1106
1107 executeGenericIdenticalTypes(block, result, c0_converted.get(), c1_converted.get());
1108 }
1109
1110public:
1111 String getName() const override
1112 {
1113 return name;
1114 }
1115
1116 size_t getNumberOfArguments() const override { return 2; }
1117
1118 /// Get result types by argument types. If the function does not apply to these arguments, throw an exception.
1119 DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
1120 {
1121 WhichDataType left(arguments[0].get());
1122 WhichDataType right(arguments[1].get());
1123
1124 const DataTypeTuple * left_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].get());
1125 const DataTypeTuple * right_tuple = checkAndGetDataType<DataTypeTuple>(arguments[1].get());
1126
1127 bool both_represented_by_number = arguments[0]->isValueRepresentedByNumber() && arguments[1]->isValueRepresentedByNumber();
1128 bool has_date = left.isDate() || right.isDate();
1129
1130 if (!((both_represented_by_number && !has_date) /// Do not allow compare date and number.
1131 || (left.isStringOrFixedString() && right.isStringOrFixedString())
1132 || (left.isDate() && right.isDate())
1133 || (left.isDate() && right.isString()) /// You can compare the date, datetime and an enumeration with a constant string.
1134 || (left.isString() && right.isDate())
1135 || (left.isDateTime() && right.isDateTime())
1136 || (left.isDateTime() && right.isString())
1137 || (left.isString() && right.isDateTime())
1138 || (left.isUUID() && right.isUUID())
1139 || (left.isUUID() && right.isString())
1140 || (left.isString() && right.isUUID())
1141 || (left.isEnum() && right.isEnum() && arguments[0]->getName() == arguments[1]->getName()) /// only equivalent enum type values can be compared against
1142 || (left.isEnum() && right.isString())
1143 || (left.isString() && right.isEnum())
1144 || (left_tuple && right_tuple && left_tuple->getElements().size() == right_tuple->getElements().size())
1145 || (arguments[0]->equals(*arguments[1]))))
1146 {
1147 try
1148 {
1149 getLeastSupertype(arguments);
1150 }
1151 catch (const Exception &)
1152 {
1153 throw Exception("Illegal types of arguments (" + arguments[0]->getName() + ", " + arguments[1]->getName() + ")"
1154 " of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
1155 }
1156 }
1157
1158 if (left_tuple && right_tuple)
1159 {
1160 auto adaptor = FunctionOverloadResolverAdaptor(
1161 std::make_unique<DefaultOverloadResolver>(FunctionComparison<Op, Name>::create(context)));
1162
1163 size_t size = left_tuple->getElements().size();
1164 for (size_t i = 0; i < size; ++i)
1165 {
1166 ColumnsWithTypeAndName args = {{nullptr, left_tuple->getElements()[i], ""},
1167 {nullptr, right_tuple->getElements()[i], ""}};
1168 adaptor.build(args);
1169 }
1170 }
1171
1172 return std::make_shared<DataTypeUInt8>();
1173 }
1174
1175 void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
1176 {
1177 const auto & col_with_type_and_name_left = block.getByPosition(arguments[0]);
1178 const auto & col_with_type_and_name_right = block.getByPosition(arguments[1]);
1179 const IColumn * col_left_untyped = col_with_type_and_name_left.column.get();
1180 const IColumn * col_right_untyped = col_with_type_and_name_right.column.get();
1181
1182 const DataTypePtr & left_type = col_with_type_and_name_left.type;
1183 const DataTypePtr & right_type = col_with_type_and_name_right.type;
1184
1185 /// The case when arguments are the same (tautological comparison). Return constant.
1186 /// NOTE: Nullable types are special case. (BTW, this function use default implementation for Nullable, so Nullable types cannot be here. Check just in case.)
1187 /// NOTE: We consider NaN comparison to be implementation specific (and in our implementation NaNs are sometimes equal sometimes not).
1188 if (left_type->equals(*right_type) && !left_type->isNullable() && col_left_untyped == col_right_untyped)
1189 {
1190 /// Always true: =, <=, >=
1191 if constexpr (std::is_same_v<Op<int, int>, EqualsOp<int, int>>
1192 || std::is_same_v<Op<int, int>, LessOrEqualsOp<int, int>>
1193 || std::is_same_v<Op<int, int>, GreaterOrEqualsOp<int, int>>)
1194 {
1195 block.getByPosition(result).column = DataTypeUInt8().createColumnConst(input_rows_count, 1u);
1196 return;
1197 }
1198 else
1199 {
1200 block.getByPosition(result).column = DataTypeUInt8().createColumnConst(input_rows_count, 0u);
1201 return;
1202 }
1203 }
1204
1205 WhichDataType which_left{left_type};
1206 WhichDataType which_right{right_type};
1207
1208 const bool left_is_num = col_left_untyped->isNumeric();
1209 const bool right_is_num = col_right_untyped->isNumeric();
1210
1211 bool date_and_datetime = (left_type != right_type) &&
1212 which_left.isDateOrDateTime() && which_right.isDateOrDateTime();
1213
1214 if (left_is_num && right_is_num && !date_and_datetime)
1215 {
1216 if (!(executeNumLeftType<UInt8>(block, result, col_left_untyped, col_right_untyped)
1217 || executeNumLeftType<UInt16>(block, result, col_left_untyped, col_right_untyped)
1218 || executeNumLeftType<UInt32>(block, result, col_left_untyped, col_right_untyped)
1219 || executeNumLeftType<UInt64>(block, result, col_left_untyped, col_right_untyped)
1220 || executeNumLeftType<UInt128>(block, result, col_left_untyped, col_right_untyped)
1221 || executeNumLeftType<Int8>(block, result, col_left_untyped, col_right_untyped)
1222 || executeNumLeftType<Int16>(block, result, col_left_untyped, col_right_untyped)
1223 || executeNumLeftType<Int32>(block, result, col_left_untyped, col_right_untyped)
1224 || executeNumLeftType<Int64>(block, result, col_left_untyped, col_right_untyped)
1225 || executeNumLeftType<Int128>(block, result, col_left_untyped, col_right_untyped)
1226 || executeNumLeftType<Float32>(block, result, col_left_untyped, col_right_untyped)
1227 || executeNumLeftType<Float64>(block, result, col_left_untyped, col_right_untyped)))
1228 throw Exception("Illegal column " + col_left_untyped->getName()
1229 + " of first argument of function " + getName(),
1230 ErrorCodes::ILLEGAL_COLUMN);
1231 }
1232 else if (checkAndGetDataType<DataTypeTuple>(left_type.get()))
1233 {
1234 executeTuple(block, result, col_with_type_and_name_left, col_with_type_and_name_right, input_rows_count);
1235 }
1236 else if (isColumnedAsDecimal(left_type) || isColumnedAsDecimal(right_type))
1237 {
1238 // compare
1239 if (!allowDecimalComparison(left_type, right_type) && !date_and_datetime)
1240 throw Exception("No operation " + getName() + " between " + left_type->getName() + " and " + right_type->getName(),
1241 ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
1242
1243 executeDecimal(block, result, col_with_type_and_name_left, col_with_type_and_name_right);
1244 }
1245 else if (!left_is_num && !right_is_num && executeString(block, result, col_left_untyped, col_right_untyped))
1246 {
1247 }
1248 else if (left_type->equals(*right_type))
1249 {
1250 executeGenericIdenticalTypes(block, result, col_left_untyped, col_right_untyped);
1251 }
1252 else if (executeDateOrDateTimeOrEnumOrUUIDWithConstString(
1253 block, result, col_left_untyped, col_right_untyped,
1254 left_type, right_type,
1255 left_is_num, input_rows_count))
1256 {
1257 }
1258 else
1259 {
1260 executeGeneric(block, result, col_with_type_and_name_left, col_with_type_and_name_right);
1261 }
1262 }
1263
1264#if USE_EMBEDDED_COMPILER
1265 bool isCompilableImpl(const DataTypes & types) const override
1266 {
1267 auto isBigInteger = &typeIsEither<DataTypeInt64, DataTypeUInt64, DataTypeUUID>;
1268 auto isFloatingPoint = &typeIsEither<DataTypeFloat32, DataTypeFloat64>;
1269 if ((isBigInteger(*types[0]) && isFloatingPoint(*types[1]))
1270 || (isBigInteger(*types[1]) && isFloatingPoint(*types[0]))
1271 || (WhichDataType(types[0]).isDate() && WhichDataType(types[1]).isDateTime())
1272 || (WhichDataType(types[1]).isDate() && WhichDataType(types[0]).isDateTime()))
1273 return false; /// TODO: implement (double, int_N where N > double's mantissa width)
1274 return isCompilableType(types[0]) && isCompilableType(types[1]);
1275 }
1276
1277 llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
1278 {
1279 auto & b = static_cast<llvm::IRBuilder<> &>(builder);
1280 auto * x = values[0]();
1281 auto * y = values[1]();
1282 if (!types[0]->equals(*types[1]))
1283 {
1284 llvm::Type * common;
1285 if (x->getType()->isIntegerTy() && y->getType()->isIntegerTy())
1286 common = b.getIntNTy(std::max(
1287 /// if one integer has a sign bit, make sure the other does as well. llvm generates optimal code
1288 /// (e.g. uses overflow flag on x86) for (word size + 1)-bit integer operations.
1289 x->getType()->getIntegerBitWidth() + (!typeIsSigned(*types[0]) && typeIsSigned(*types[1])),
1290 y->getType()->getIntegerBitWidth() + (!typeIsSigned(*types[1]) && typeIsSigned(*types[0]))));
1291 else
1292 /// (double, float) or (double, int_N where N <= double's mantissa width) -> double
1293 common = b.getDoubleTy();
1294 x = nativeCast(b, types[0], x, common);
1295 y = nativeCast(b, types[1], y, common);
1296 }
1297 auto * result = CompileOp<Op>::compile(b, x, y, typeIsSigned(*types[0]) || typeIsSigned(*types[1]));
1298 return b.CreateSelect(result, b.getInt8(1), b.getInt8(0));
1299 }
1300#endif
1301};
1302
1303}
1304