| 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 | |
| 41 | namespace DB |
| 42 | { |
| 43 | |
| 44 | namespace 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 | |
| 69 | template <typename A, typename B, typename Op> |
| 70 | struct 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 | |
| 122 | template <typename Op> |
| 123 | struct 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. |
| 288 | template <bool positive> |
| 289 | struct 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 | |
| 451 | template <typename A, typename B> |
| 452 | struct StringComparisonImpl<EqualsOp<A, B>> : StringEqualsImpl<true> {}; |
| 453 | |
| 454 | template <typename A, typename B> |
| 455 | struct StringComparisonImpl<NotEqualsOp<A, B>> : StringEqualsImpl<false> {}; |
| 456 | |
| 457 | |
| 458 | /// Generic version, implemented for columns of same type. |
| 459 | template <typename Op> |
| 460 | struct 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 | |
| 489 | template <template <typename, typename> typename Op> struct CompileOp; |
| 490 | |
| 491 | template <> 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 | |
| 499 | template <> 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 | |
| 507 | template <> 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 | |
| 515 | template <> 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 | |
| 523 | template <> 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 | |
| 531 | template <> 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 | |
| 542 | struct NameEquals { static constexpr auto name = "equals" ; }; |
| 543 | struct NameNotEquals { static constexpr auto name = "notEquals" ; }; |
| 544 | struct NameLess { static constexpr auto name = "less" ; }; |
| 545 | struct NameGreater { static constexpr auto name = "greater" ; }; |
| 546 | struct NameLessOrEquals { static constexpr auto name = "lessOrEquals" ; }; |
| 547 | struct NameGreaterOrEquals { static constexpr auto name = "greaterOrEquals" ; }; |
| 548 | |
| 549 | |
| 550 | template < |
| 551 | template <typename, typename> class Op, |
| 552 | typename Name> |
| 553 | class FunctionComparison : public IFunction |
| 554 | { |
| 555 | public: |
| 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 | |
| 564 | private: |
| 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 | |
| 1110 | public: |
| 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 | |