| 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 |  | 
|---|