ClickHouse/src/Functions/FunctionsComparison.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1394 lines
57 KiB
C++
Raw Normal View History

#pragma once
2019-03-03 20:08:39 +00:00
#include <Common/memcmpSmall.h>
#include <Common/assert_cast.h>
#include <Common/TargetSpecific.h>
2019-03-03 20:08:39 +00:00
#include <Columns/ColumnsNumber.h>
#include <Columns/ColumnConst.h>
#include <Columns/ColumnDecimal.h>
#include <Columns/ColumnString.h>
#include <Columns/ColumnFixedString.h>
#include <Columns/ColumnTuple.h>
#include <Columns/ColumnArray.h>
2021-12-24 05:08:54 +00:00
#include <DataTypes/DataTypeDate.h>
#include <DataTypes/DataTypeDateTime.h>
#include <DataTypes/DataTypeDateTime64.h>
2021-12-24 05:08:54 +00:00
#include <DataTypes/DataTypeEnum.h>
#include <DataTypes/DataTypeFixedString.h>
2021-12-24 05:08:54 +00:00
#include <DataTypes/DataTypeNothing.h>
#include <DataTypes/DataTypeNullable.h>
#include <DataTypes/DataTypeString.h>
#include <DataTypes/DataTypeTuple.h>
2021-12-24 05:08:54 +00:00
#include <DataTypes/DataTypeUUID.h>
#include <DataTypes/DataTypesNumber.h>
#include <DataTypes/getLeastSupertype.h>
#include <Interpreters/convertFieldToType.h>
#include <Interpreters/castColumn.h>
#include <Functions/IFunctionAdaptors.h>
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
#include <Functions/FunctionHelpers.h>
2020-09-08 00:59:13 +00:00
#include <Functions/IsOperation.h>
#include <Core/AccurateComparison.h>
#include <Core/DecimalComparison.h>
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
#include <IO/ReadBufferFromMemory.h>
#include <IO/ReadHelpers.h>
#include <limits>
#include <type_traits>
#if USE_EMBEDDED_COMPILER
2023-04-11 18:04:30 +00:00
# include <DataTypes/Native.h>
# include <llvm/IR/IRBuilder.h>
#endif
namespace DB
{
namespace ErrorCodes
{
extern const int ILLEGAL_COLUMN;
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
extern const int LOGICAL_ERROR;
extern const int NOT_IMPLEMENTED;
2020-06-21 14:25:41 +00:00
extern const int BAD_ARGUMENTS;
}
2018-08-08 13:57:16 +00:00
2017-05-27 15:45:25 +00:00
/** Comparison functions: ==, !=, <, >, <=, >=.
* The comparison functions always return 0 or 1 (UInt8).
*
2017-05-27 15:45:25 +00:00
* You can compare the following types:
2018-07-25 19:38:21 +00:00
* - numbers and decimals;
2017-05-27 15:45:25 +00:00
* - strings and fixed strings;
* - dates;
* - datetimes;
* within each group, but not from different groups;
* - tuples (lexicographic comparison).
*
2017-05-27 15:45:25 +00:00
* Exception: You can compare the date and datetime with a constant string. Example: EventDate = '2015-01-01'.
*/
2011-08-21 06:52:21 +00:00
2017-09-15 12:16:12 +00:00
template <typename A, typename B, typename Op>
struct NumComparisonImpl
2011-08-21 06:52:21 +00:00
{
2021-01-26 18:22:40 +00:00
using ContainerA = PaddedPODArray<A>;
using ContainerB = PaddedPODArray<B>;
MULTITARGET_FUNCTION_AVX512BW_AVX512F_AVX2_SSE42(
MULTITARGET_FUNCTION_HEADER(static void), vectorVectorImpl, MULTITARGET_FUNCTION_BODY(( /// NOLINT
const ContainerA & a, const ContainerB & b, PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
2017-05-27 15:45:25 +00:00
/** GCC 4.8.2 vectorizes a loop only if it is written in this form.
* In this case, if you loop through the array index (the code will look simpler),
* the loop will not be vectorized.
*/
2011-08-21 06:52:21 +00:00
size_t size = a.size();
const A * __restrict a_pos = a.data();
const B * __restrict b_pos = b.data();
UInt8 * __restrict c_pos = c.data();
const A * a_end = a_pos + size;
while (a_pos < a_end)
{
*c_pos = Op::apply(*a_pos, *b_pos);
++a_pos;
++b_pos;
++c_pos;
}
}))
static void NO_INLINE vectorVector(const ContainerA & a, const ContainerB & b, PaddedPODArray<UInt8> & c)
{
#if USE_MULTITARGET_CODE
if (isArchSupported(TargetArch::AVX512BW))
{
vectorVectorImplAVX512BW(a, b, c);
return;
}
2022-06-06 02:02:21 +00:00
if (isArchSupported(TargetArch::AVX512F))
{
vectorVectorImplAVX512F(a, b, c);
return;
}
if (isArchSupported(TargetArch::AVX2))
{
vectorVectorImplAVX2(a, b, c);
return;
}
2022-06-06 02:07:45 +00:00
if (isArchSupported(TargetArch::SSE42))
{
vectorVectorImplSSE42(a, b, c);
return;
}
#endif
vectorVectorImpl(a, b, c);
2011-08-21 06:52:21 +00:00
}
MULTITARGET_FUNCTION_AVX512BW_AVX512F_AVX2_SSE42(
MULTITARGET_FUNCTION_HEADER(static void), vectorConstantImpl, MULTITARGET_FUNCTION_BODY(( /// NOLINT
const ContainerA & a, B b, PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
size_t size = a.size();
const A * __restrict a_pos = a.data();
UInt8 * __restrict c_pos = c.data();
const A * a_end = a_pos + size;
while (a_pos < a_end)
{
*c_pos = Op::apply(*a_pos, b);
++a_pos;
++c_pos;
}
}))
2022-05-21 12:54:45 +00:00
static void NO_INLINE vectorConstant(const ContainerA & a, B b, PaddedPODArray<UInt8> & c)
{
#if USE_MULTITARGET_CODE
if (isArchSupported(TargetArch::AVX512BW))
{
vectorConstantImplAVX512BW(a, b, c);
return;
}
if (isArchSupported(TargetArch::AVX512F))
{
vectorConstantImplAVX512F(a, b, c);
return;
}
if (isArchSupported(TargetArch::AVX2))
{
vectorConstantImplAVX2(a, b, c);
return;
}
if (isArchSupported(TargetArch::SSE42))
{
vectorConstantImplSSE42(a, b, c);
return;
}
#endif
vectorConstantImpl(a, b, c);
2011-08-21 06:52:21 +00:00
}
static void constantVector(A a, const ContainerB & b, PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
NumComparisonImpl<B, A, typename Op::SymmetricOp>::vectorConstant(b, a, c);
2011-08-21 06:52:21 +00:00
}
static void constantConstant(A a, B b, UInt8 & c)
{
c = Op::apply(a, b);
}
2011-08-21 06:52:21 +00:00
};
template <typename Op>
struct StringComparisonImpl
2011-08-21 06:52:21 +00:00
{
static void NO_INLINE string_vector_string_vector( /// NOLINT
const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
size_t size = a_offsets.size();
2019-03-03 20:08:39 +00:00
ColumnString::Offset prev_a_offset = 0;
ColumnString::Offset prev_b_offset = 0;
2011-08-21 06:52:21 +00:00
for (size_t i = 0; i < size; ++i)
{
2019-03-03 20:08:39 +00:00
c[i] = Op::apply(memcmpSmallAllowOverflow15(
a_data.data() + prev_a_offset, a_offsets[i] - prev_a_offset - 1,
b_data.data() + prev_b_offset, b_offsets[i] - prev_b_offset - 1), 0);
2019-03-03 20:08:39 +00:00
prev_a_offset = a_offsets[i];
prev_b_offset = b_offsets[i];
2011-08-21 06:52:21 +00:00
}
}
static void NO_INLINE string_vector_fixed_string_vector( /// NOLINT
const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
const ColumnString::Chars & b_data, ColumnString::Offset b_n,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
size_t size = a_offsets.size();
2019-03-03 20:08:39 +00:00
ColumnString::Offset prev_a_offset = 0;
2011-08-21 06:52:21 +00:00
for (size_t i = 0; i < size; ++i)
{
c[i] = Op::apply(memcmpSmallLikeZeroPaddedAllowOverflow15(
2019-03-03 20:08:39 +00:00
a_data.data() + prev_a_offset, a_offsets[i] - prev_a_offset - 1,
b_data.data() + i * b_n, b_n), 0);
prev_a_offset = a_offsets[i];
2011-08-21 06:52:21 +00:00
}
}
static void NO_INLINE string_vector_constant( /// NOLINT
const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & b_data, ColumnString::Offset b_size,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
size_t size = a_offsets.size();
2019-03-03 20:08:39 +00:00
ColumnString::Offset prev_a_offset = 0;
2011-08-21 06:52:21 +00:00
for (size_t i = 0; i < size; ++i)
{
2019-03-03 20:08:39 +00:00
c[i] = Op::apply(memcmpSmallAllowOverflow15(
a_data.data() + prev_a_offset, a_offsets[i] - prev_a_offset - 1,
b_data.data(), b_size), 0);
prev_a_offset = a_offsets[i];
2011-08-21 06:52:21 +00:00
}
}
static void fixed_string_vector_string_vector( /// NOLINT
const ColumnString::Chars & a_data, ColumnString::Offset a_n,
const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
StringComparisonImpl<typename Op::SymmetricOp>::string_vector_fixed_string_vector(b_data, b_offsets, a_data, a_n, c);
}
static void NO_INLINE fixed_string_vector_fixed_string_vector_16( /// NOLINT
const ColumnString::Chars & a_data,
const ColumnString::Chars & b_data,
PaddedPODArray<UInt8> & c)
{
size_t size = a_data.size();
for (size_t i = 0, j = 0; i < size; i += 16, ++j)
c[j] = Op::apply(memcmp16(&a_data[i], &b_data[i]), 0);
2011-08-21 06:52:21 +00:00
}
static void NO_INLINE fixed_string_vector_constant_16( /// NOLINT
const ColumnString::Chars & a_data,
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & b_data,
PaddedPODArray<UInt8> & c)
{
size_t size = a_data.size();
for (size_t i = 0, j = 0; i < size; i += 16, ++j)
2019-03-03 20:08:39 +00:00
c[j] = Op::apply(memcmp16(&a_data[i], &b_data[0]), 0);
}
static void NO_INLINE fixed_string_vector_fixed_string_vector( /// NOLINT
const ColumnString::Chars & a_data, ColumnString::Offset a_n,
const ColumnString::Chars & b_data, ColumnString::Offset b_n,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
if (a_n == 16 && b_n == 16)
2011-08-21 06:52:21 +00:00
{
2019-03-03 20:08:39 +00:00
/** Specialization if both sizes are 16.
* To more efficient comparison of IPv6 addresses stored in FixedString(16).
*/
fixed_string_vector_fixed_string_vector_16(a_data, b_data, c);
}
2019-03-03 20:08:39 +00:00
else if (a_n == b_n)
{
size_t size = a_data.size();
for (size_t i = 0, j = 0; i < size; i += a_n, ++j)
2019-03-03 20:08:39 +00:00
c[j] = Op::apply(memcmpSmallAllowOverflow15(a_data.data() + i, b_data.data() + i, a_n), 0);
}
else
{
size_t size = a_data.size() / a_n;
for (size_t i = 0; i < size; ++i)
c[i] = Op::apply(memcmpSmallLikeZeroPaddedAllowOverflow15(a_data.data() + i * a_n, a_n, b_data.data() + i * b_n, b_n), 0);
2011-08-21 06:52:21 +00:00
}
}
static void NO_INLINE fixed_string_vector_constant( /// NOLINT
const ColumnString::Chars & a_data, ColumnString::Offset a_n,
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & b_data, ColumnString::Offset b_size,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
2019-03-03 20:08:39 +00:00
if (a_n == 16 && b_size == 16)
2011-08-21 06:52:21 +00:00
{
2019-03-03 20:08:39 +00:00
fixed_string_vector_constant_16(a_data, b_data, c);
}
else if (a_n == b_size)
{
size_t size = a_data.size();
for (size_t i = 0, j = 0; i < size; i += a_n, ++j)
c[j] = Op::apply(memcmpSmallAllowOverflow15(a_data.data() + i, b_data.data(), a_n), 0);
}
else
{
size_t size = a_data.size();
for (size_t i = 0, j = 0; i < size; i += a_n, ++j)
2020-06-20 13:13:51 +00:00
c[j] = Op::apply(memcmpSmallLikeZeroPaddedAllowOverflow15(a_data.data() + i, a_n, b_data.data(), b_size), 0);
2011-08-21 06:52:21 +00:00
}
}
static void constant_string_vector( /// NOLINT
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & a_data, ColumnString::Offset a_size,
const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
StringComparisonImpl<typename Op::SymmetricOp>::string_vector_constant(b_data, b_offsets, a_data, a_size, c);
2011-08-21 06:52:21 +00:00
}
static void constant_fixed_string_vector( /// NOLINT
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & a_data, ColumnString::Offset a_size,
const ColumnString::Chars & b_data, ColumnString::Offset b_n,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
StringComparisonImpl<typename Op::SymmetricOp>::fixed_string_vector_constant(b_data, b_n, a_data, a_size, c);
2011-08-21 06:52:21 +00:00
}
};
/// Comparisons for equality/inequality are implemented slightly more efficient.
template <bool positive>
struct StringEqualsImpl
2011-08-21 06:52:21 +00:00
{
static void NO_INLINE string_vector_string_vector( /// NOLINT
const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
size_t size = a_offsets.size();
2019-03-03 20:08:39 +00:00
ColumnString::Offset prev_a_offset = 0;
ColumnString::Offset prev_b_offset = 0;
2011-08-21 06:52:21 +00:00
for (size_t i = 0; i < size; ++i)
2019-03-03 20:08:39 +00:00
{
auto a_size = a_offsets[i] - prev_a_offset - 1;
auto b_size = b_offsets[i] - prev_b_offset - 1;
c[i] = positive == memequalSmallAllowOverflow15(
a_data.data() + prev_a_offset, a_size,
b_data.data() + prev_b_offset, b_size);
prev_a_offset = a_offsets[i];
prev_b_offset = b_offsets[i];
}
2011-08-21 06:52:21 +00:00
}
static void NO_INLINE string_vector_fixed_string_vector( /// NOLINT
const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
const ColumnString::Chars & b_data, ColumnString::Offset b_n,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
size_t size = a_offsets.size();
2019-03-03 20:08:39 +00:00
ColumnString::Offset prev_a_offset = 0;
2011-08-21 06:52:21 +00:00
for (size_t i = 0; i < size; ++i)
2019-03-03 20:08:39 +00:00
{
auto a_size = a_offsets[i] - prev_a_offset - 1;
c[i] = positive == memequalSmallLikeZeroPaddedAllowOverflow15(
2019-03-03 20:08:39 +00:00
a_data.data() + prev_a_offset, a_size,
b_data.data() + b_n * i, b_n);
prev_a_offset = a_offsets[i];
}
2011-08-21 06:52:21 +00:00
}
static void NO_INLINE string_vector_constant( /// NOLINT
const ColumnString::Chars & a_data, const ColumnString::Offsets & a_offsets,
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & b_data, ColumnString::Offset b_size,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
size_t size = a_offsets.size();
2019-03-03 20:08:39 +00:00
ColumnString::Offset prev_a_offset = 0;
if (b_size == 0)
2019-03-03 20:08:39 +00:00
{
/*
* Add the fast path of string comparison if the string constant is empty
* and b_size is 0. If a_size is also 0, both of string a and b are empty
* string. There is no need to call memequalSmallAllowOverflow15() for
* string comparison.
*/
for (size_t i = 0; i < size; ++i)
{
auto a_size = a_offsets[i] - prev_a_offset - 1;
2019-03-03 20:08:39 +00:00
if (a_size == 0)
c[i] = positive;
else
c[i] = !positive;
2019-03-03 20:08:39 +00:00
prev_a_offset = a_offsets[i];
}
}
else
{
for (size_t i = 0; i < size; ++i)
{
auto a_size = a_offsets[i] - prev_a_offset - 1;
c[i] = positive == memequalSmallAllowOverflow15(
a_data.data() + prev_a_offset, a_size,
b_data.data(), b_size);
prev_a_offset = a_offsets[i];
}
2019-03-03 20:08:39 +00:00
}
2011-08-21 06:52:21 +00:00
}
static void NO_INLINE fixed_string_vector_fixed_string_vector_16( /// NOLINT
const ColumnString::Chars & a_data,
const ColumnString::Chars & b_data,
PaddedPODArray<UInt8> & c)
{
2019-03-03 20:08:39 +00:00
size_t size = a_data.size() / 16;
2019-03-03 20:08:39 +00:00
for (size_t i = 0; i < size; ++i)
c[i] = positive == memequal16(
a_data.data() + i * 16,
b_data.data() + i * 16);
}
static void NO_INLINE fixed_string_vector_constant_16( /// NOLINT
const ColumnString::Chars & a_data,
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & b_data,
PaddedPODArray<UInt8> & c)
{
2019-03-03 20:08:39 +00:00
size_t size = a_data.size() / 16;
2019-03-03 20:08:39 +00:00
for (size_t i = 0; i < size; ++i)
c[i] = positive == memequal16(
a_data.data() + i * 16,
b_data.data());
}
static void NO_INLINE fixed_string_vector_fixed_string_vector( /// NOLINT
const ColumnString::Chars & a_data, ColumnString::Offset a_n,
const ColumnString::Chars & b_data, ColumnString::Offset b_n,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
/** Specialization if both sizes are 16.
* To more efficient comparison of IPv6 addresses stored in FixedString(16).
*/
if (a_n == 16 && b_n == 16)
{
fixed_string_vector_fixed_string_vector_16(a_data, b_data, c);
}
else if (a_n == b_n)
{
size_t size = a_data.size() / a_n;
for (size_t i = 0; i < size; ++i)
c[i] = positive == memequalSmallAllowOverflow15(a_data.data() + i * a_n, a_n, b_data.data() + i * a_n, a_n);
}
else
{
2019-03-03 20:08:39 +00:00
size_t size = a_data.size() / a_n;
for (size_t i = 0; i < size; ++i)
c[i] = positive == memequalSmallLikeZeroPaddedAllowOverflow15(a_data.data() + i * a_n, a_n, b_data.data() + i * b_n, b_n);
}
2011-08-21 06:52:21 +00:00
}
static void NO_INLINE fixed_string_vector_constant( /// NOLINT
const ColumnString::Chars & a_data, ColumnString::Offset a_n,
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & b_data, ColumnString::Offset b_size,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
2019-03-03 20:08:39 +00:00
if (a_n == 16 && b_size == 16)
{
2019-03-03 20:08:39 +00:00
fixed_string_vector_constant_16(a_data, b_data, c);
}
else
{
2019-03-03 20:08:39 +00:00
size_t size = a_data.size() / a_n;
for (size_t i = 0; i < size; ++i)
c[i] = positive == memequalSmallLikeZeroPaddedAllowOverflow15(a_data.data() + i * a_n, a_n, b_data.data(), b_size);
}
2011-08-21 06:52:21 +00:00
}
static void fixed_string_vector_string_vector( /// NOLINT
const ColumnString::Chars & a_data, ColumnString::Offset a_n,
const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
string_vector_fixed_string_vector(b_data, b_offsets, a_data, a_n, c);
2011-08-21 06:52:21 +00:00
}
static void constant_string_vector( /// NOLINT
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & a_data, ColumnString::Offset a_size,
const ColumnString::Chars & b_data, const ColumnString::Offsets & b_offsets,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
string_vector_constant(b_data, b_offsets, a_data, a_size, c);
2011-08-21 06:52:21 +00:00
}
static void constant_fixed_string_vector( /// NOLINT
2019-03-03 20:08:39 +00:00
const ColumnString::Chars & a_data, ColumnString::Offset a_size,
const ColumnString::Chars & b_data, ColumnString::Offset b_n,
PaddedPODArray<UInt8> & c)
2011-08-21 06:52:21 +00:00
{
fixed_string_vector_constant(b_data, b_n, a_data, a_size, c);
2011-08-21 06:52:21 +00:00
}
};
template <typename A, typename B>
struct StringComparisonImpl<EqualsOp<A, B>> : StringEqualsImpl<true> {};
template <typename A, typename B>
struct StringComparisonImpl<NotEqualsOp<A, B>> : StringEqualsImpl<false> {};
2011-08-19 20:35:21 +00:00
/// Generic version, implemented for columns of same type.
template <typename Op>
struct GenericComparisonImpl
{
static void NO_INLINE vectorVector(const IColumn & a, const IColumn & b, PaddedPODArray<UInt8> & c)
{
for (size_t i = 0, size = a.size(); i < size; ++i)
c[i] = Op::apply(a.compareAt(i, i, b, 1), 0);
}
static void NO_INLINE vectorConstant(const IColumn & a, const IColumn & b, PaddedPODArray<UInt8> & c)
{
auto b_materialized = b.cloneResized(1)->convertToFullColumnIfConst();
for (size_t i = 0, size = a.size(); i < size; ++i)
c[i] = Op::apply(a.compareAt(i, 0, *b_materialized, 1), 0);
}
static void constantVector(const IColumn & a, const IColumn & b, PaddedPODArray<UInt8> & c)
{
GenericComparisonImpl<typename Op::SymmetricOp>::vectorConstant(b, a, c);
}
static void constantConstant(const IColumn & a, const IColumn & b, UInt8 & c)
{
c = Op::apply(a.compareAt(0, 0, b, 1), 0);
}
};
#if USE_EMBEDDED_COMPILER
template <template <typename, typename> typename Op> struct CompileOp;
template <> struct CompileOp<EqualsOp>
{
static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool /*is_signed*/)
{
return x->getType()->isIntegerTy() ? b.CreateICmpEQ(x, y) : b.CreateFCmpOEQ(x, y); /// qNaNs always compare false
}
};
template <> struct CompileOp<NotEqualsOp>
{
static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool /*is_signed*/)
{
2023-05-21 17:38:26 +00:00
return x->getType()->isIntegerTy() ? b.CreateICmpNE(x, y) : b.CreateFCmpUNE(x, y);
}
};
template <> struct CompileOp<LessOp>
{
static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool is_signed)
{
return x->getType()->isIntegerTy() ? (is_signed ? b.CreateICmpSLT(x, y) : b.CreateICmpULT(x, y)) : b.CreateFCmpOLT(x, y);
}
};
template <> struct CompileOp<GreaterOp>
{
static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool is_signed)
{
return x->getType()->isIntegerTy() ? (is_signed ? b.CreateICmpSGT(x, y) : b.CreateICmpUGT(x, y)) : b.CreateFCmpOGT(x, y);
}
};
template <> struct CompileOp<LessOrEqualsOp>
{
static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool is_signed)
{
return x->getType()->isIntegerTy() ? (is_signed ? b.CreateICmpSLE(x, y) : b.CreateICmpULE(x, y)) : b.CreateFCmpOLE(x, y);
}
};
template <> struct CompileOp<GreaterOrEqualsOp>
{
static llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * x, llvm::Value * y, bool is_signed)
{
return x->getType()->isIntegerTy() ? (is_signed ? b.CreateICmpSGE(x, y) : b.CreateICmpUGE(x, y)) : b.CreateFCmpOGE(x, y);
}
};
#endif
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
struct NameEquals { static constexpr auto name = "equals"; };
struct NameNotEquals { static constexpr auto name = "notEquals"; };
struct NameLess { static constexpr auto name = "less"; };
struct NameGreater { static constexpr auto name = "greater"; };
struct NameLessOrEquals { static constexpr auto name = "lessOrEquals"; };
struct NameGreaterOrEquals { static constexpr auto name = "greaterOrEquals"; };
template <template <typename, typename> class Op, typename Name>
class FunctionComparison : public IFunction
{
public:
static constexpr auto name = Name::name;
2021-06-01 12:20:52 +00:00
static FunctionPtr create(ContextPtr context) { return std::make_shared<FunctionComparison>(context); }
2021-06-01 12:20:52 +00:00
explicit FunctionComparison(ContextPtr context_)
: context(context_), check_decimal_overflow(decimalCheckComparisonOverflow(context)) {}
private:
2021-06-01 12:20:52 +00:00
ContextPtr context;
bool check_decimal_overflow = true;
template <typename T0, typename T1>
2020-10-17 14:23:37 +00:00
ColumnPtr executeNumRightType(const ColumnVector<T0> * col_left, const IColumn * col_right_untyped) const
{
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
if (const ColumnVector<T1> * col_right = checkAndGetColumn<ColumnVector<T1>>(col_right_untyped))
{
auto col_res = ColumnUInt8::create();
ColumnUInt8::Container & vec_res = col_res->getData();
vec_res.resize(col_left->getData().size());
NumComparisonImpl<T0, T1, Op<T0, T1>>::vectorVector(col_left->getData(), col_right->getData(), vec_res);
2020-10-17 14:23:37 +00:00
return col_res;
}
2018-08-27 16:31:45 +00:00
else if (auto col_right_const = checkAndGetColumnConst<ColumnVector<T1>>(col_right_untyped))
{
auto col_res = ColumnUInt8::create();
ColumnUInt8::Container & vec_res = col_res->getData();
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
vec_res.resize(col_left->size());
NumComparisonImpl<T0, T1, Op<T0, T1>>::vectorConstant(col_left->getData(), col_right_const->template getValue<T1>(), vec_res);
2020-10-17 14:23:37 +00:00
return col_res;
}
2020-10-17 14:23:37 +00:00
return nullptr;
}
template <typename T0, typename T1>
2020-10-17 14:23:37 +00:00
ColumnPtr executeNumConstRightType(const ColumnConst * col_left, const IColumn * col_right_untyped) const
{
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
if (const ColumnVector<T1> * col_right = checkAndGetColumn<ColumnVector<T1>>(col_right_untyped))
{
auto col_res = ColumnUInt8::create();
ColumnUInt8::Container & vec_res = col_res->getData();
vec_res.resize(col_left->size());
NumComparisonImpl<T0, T1, Op<T0, T1>>::constantVector(col_left->template getValue<T0>(), col_right->getData(), vec_res);
2020-10-17 14:23:37 +00:00
return col_res;
}
2018-08-27 16:31:45 +00:00
else if (auto col_right_const = checkAndGetColumnConst<ColumnVector<T1>>(col_right_untyped))
{
UInt8 res = 0;
NumComparisonImpl<T0, T1, Op<T0, T1>>::constantConstant(col_left->template getValue<T0>(), col_right_const->template getValue<T1>(), res);
2020-10-17 14:23:37 +00:00
return DataTypeUInt8().createColumnConst(col_left->size(), toField(res));
}
2020-10-17 14:23:37 +00:00
return nullptr;
}
template <typename T0>
2020-10-17 14:23:37 +00:00
ColumnPtr executeNumLeftType(const IColumn * col_left_untyped, const IColumn * col_right_untyped) const
{
2020-10-17 14:23:37 +00:00
ColumnPtr res = nullptr;
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
if (const ColumnVector<T0> * col_left = checkAndGetColumn<ColumnVector<T0>>(col_left_untyped))
{
2020-10-17 14:23:37 +00:00
if ( (res = executeNumRightType<T0, UInt8>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, UInt16>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, UInt32>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, UInt64>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, UInt128>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, UInt256>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, Int8>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, Int16>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, Int32>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, Int64>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, Int128>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, Int256>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, Float32>(col_left, col_right_untyped))
|| (res = executeNumRightType<T0, Float64>(col_left, col_right_untyped)))
return res;
else
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of second argument of function {}",
col_right_untyped->getName(), getName());
}
2018-08-27 16:31:45 +00:00
else if (auto col_left_const = checkAndGetColumnConst<ColumnVector<T0>>(col_left_untyped))
{
2020-10-17 14:23:37 +00:00
if ( (res = executeNumConstRightType<T0, UInt8>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, UInt16>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, UInt32>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, UInt64>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, UInt128>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, UInt256>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, Int8>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, Int16>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, Int32>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, Int64>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, Int128>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, Int256>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, Float32>(col_left_const, col_right_untyped))
|| (res = executeNumConstRightType<T0, Float64>(col_left_const, col_right_untyped)))
return res;
else
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of second argument of function {}",
col_right_untyped->getName(), getName());
}
2020-10-17 14:23:37 +00:00
return nullptr;
}
2020-10-17 14:23:37 +00:00
ColumnPtr executeDecimal(const ColumnWithTypeAndName & col_left, const ColumnWithTypeAndName & col_right) const
2018-07-25 19:38:21 +00:00
{
TypeIndex left_number = col_left.type->getTypeId();
TypeIndex right_number = col_right.type->getTypeId();
2020-10-20 13:11:57 +00:00
ColumnPtr res;
2018-07-25 19:38:21 +00:00
auto call = [&](const auto & types) -> bool
2018-08-14 19:16:56 +00:00
{
using Types = std::decay_t<decltype(types)>;
using LeftDataType = typename Types::LeftType;
using RightDataType = typename Types::RightType;
2018-08-14 19:16:56 +00:00
if (check_decimal_overflow)
2020-10-20 13:11:57 +00:00
return (res = DecimalComparison<LeftDataType, RightDataType, Op, true>::apply(col_left, col_right)) != nullptr;
else
2020-10-20 13:11:57 +00:00
return (res = DecimalComparison<LeftDataType, RightDataType, Op, false>::apply(col_left, col_right)) != nullptr;
2018-08-14 19:16:56 +00:00
};
if (!callOnBasicTypes<true, false, true, true>(left_number, right_number, call))
throw Exception(ErrorCodes::LOGICAL_ERROR, "Wrong call for {} with {} and {}",
getName(), col_left.type->getName(), col_right.type->getName());
2020-10-20 13:11:57 +00:00
return res;
2018-07-25 19:38:21 +00:00
}
2020-10-17 14:23:37 +00:00
ColumnPtr executeString(const IColumn * c0, const IColumn * c1) const
2011-08-21 03:41:37 +00:00
{
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
const ColumnString * c0_string = checkAndGetColumn<ColumnString>(c0);
const ColumnString * c1_string = checkAndGetColumn<ColumnString>(c1);
const ColumnFixedString * c0_fixed_string = checkAndGetColumn<ColumnFixedString>(c0);
const ColumnFixedString * c1_fixed_string = checkAndGetColumn<ColumnFixedString>(c1);
2019-03-03 20:08:39 +00:00
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
const ColumnConst * c0_const = checkAndGetColumnConstStringOrFixedString(c0);
const ColumnConst * c1_const = checkAndGetColumnConstStringOrFixedString(c1);
if (!((c0_string || c0_fixed_string || c0_const) && (c1_string || c1_fixed_string || c1_const)))
2020-10-17 14:23:37 +00:00
return nullptr;
2019-03-03 20:08:39 +00:00
const ColumnString::Chars * c0_const_chars = nullptr;
const ColumnString::Chars * c1_const_chars = nullptr;
ColumnString::Offset c0_const_size = 0;
ColumnString::Offset c1_const_size = 0;
if (c0_const)
{
const ColumnString * c0_const_string = checkAndGetColumn<ColumnString>(&c0_const->getDataColumn());
const ColumnFixedString * c0_const_fixed_string = checkAndGetColumn<ColumnFixedString>(&c0_const->getDataColumn());
if (c0_const_string)
{
c0_const_chars = &c0_const_string->getChars();
c0_const_size = c0_const_string->getDataAt(0).size;
}
else if (c0_const_fixed_string)
{
c0_const_chars = &c0_const_fixed_string->getChars();
c0_const_size = c0_const_fixed_string->getN();
}
else
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Logical error: ColumnConst contains not String nor FixedString column");
2019-03-03 20:08:39 +00:00
}
if (c1_const)
{
const ColumnString * c1_const_string = checkAndGetColumn<ColumnString>(&c1_const->getDataColumn());
const ColumnFixedString * c1_const_fixed_string = checkAndGetColumn<ColumnFixedString>(&c1_const->getDataColumn());
if (c1_const_string)
{
c1_const_chars = &c1_const_string->getChars();
c1_const_size = c1_const_string->getDataAt(0).size;
}
else if (c1_const_fixed_string)
{
c1_const_chars = &c1_const_fixed_string->getChars();
c1_const_size = c1_const_fixed_string->getN();
}
else
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Logical error: ColumnConst contains not String nor FixedString column");
2019-03-03 20:08:39 +00:00
}
using StringImpl = StringComparisonImpl<Op<int, int>>;
if (c0_const && c1_const)
{
2020-10-17 14:23:37 +00:00
auto res = executeString(&c0_const->getDataColumn(), &c1_const->getDataColumn());
2020-04-20 04:02:52 +00:00
if (!res)
2020-10-17 14:23:37 +00:00
return nullptr;
2020-04-20 04:02:52 +00:00
2020-10-17 14:23:37 +00:00
return ColumnConst::create(res, c0_const->size());
}
2011-08-21 03:41:37 +00:00
else
{
auto c_res = ColumnUInt8::create();
ColumnUInt8::Container & vec_res = c_res->getData();
vec_res.resize(c0->size());
if (c0_string && c1_string)
StringImpl::string_vector_string_vector(
c0_string->getChars(), c0_string->getOffsets(),
c1_string->getChars(), c1_string->getOffsets(),
c_res->getData());
else if (c0_string && c1_fixed_string)
StringImpl::string_vector_fixed_string_vector(
c0_string->getChars(), c0_string->getOffsets(),
c1_fixed_string->getChars(), c1_fixed_string->getN(),
c_res->getData());
else if (c0_string && c1_const)
StringImpl::string_vector_constant(
c0_string->getChars(), c0_string->getOffsets(),
2019-03-03 20:08:39 +00:00
*c1_const_chars, c1_const_size,
c_res->getData());
else if (c0_fixed_string && c1_string)
StringImpl::fixed_string_vector_string_vector(
c0_fixed_string->getChars(), c0_fixed_string->getN(),
c1_string->getChars(), c1_string->getOffsets(),
c_res->getData());
else if (c0_fixed_string && c1_fixed_string)
StringImpl::fixed_string_vector_fixed_string_vector(
c0_fixed_string->getChars(), c0_fixed_string->getN(),
c1_fixed_string->getChars(), c1_fixed_string->getN(),
c_res->getData());
else if (c0_fixed_string && c1_const)
StringImpl::fixed_string_vector_constant(
c0_fixed_string->getChars(), c0_fixed_string->getN(),
2019-03-03 20:08:39 +00:00
*c1_const_chars, c1_const_size,
c_res->getData());
else if (c0_const && c1_string)
StringImpl::constant_string_vector(
2019-03-03 20:08:39 +00:00
*c0_const_chars, c0_const_size,
c1_string->getChars(), c1_string->getOffsets(),
c_res->getData());
else if (c0_const && c1_fixed_string)
StringImpl::constant_fixed_string_vector(
2019-03-03 20:08:39 +00:00
*c0_const_chars, c0_const_size,
c1_fixed_string->getChars(), c1_fixed_string->getN(),
c_res->getData());
else
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal columns {} and {} of arguments of function {}",
c0->getName(), c1->getName(), getName());
2020-10-17 14:23:37 +00:00
return c_res;
}
2011-08-21 03:41:37 +00:00
}
2020-10-17 14:23:37 +00:00
ColumnPtr executeWithConstString(
const DataTypePtr & result_type, const IColumn * col_left_untyped, const IColumn * col_right_untyped,
const DataTypePtr & left_type, const DataTypePtr & right_type, size_t input_rows_count) const
{
/// To compare something with const string, we cast constant to appropriate type and compare as usual.
/// It is ok to throw exception if value is not convertible.
/// We should deal with possible overflows, e.g. toUInt8(1) = '257' should return false.
const ColumnConst * left_const = checkAndGetColumnConstStringOrFixedString(col_left_untyped);
const ColumnConst * right_const = checkAndGetColumnConstStringOrFixedString(col_right_untyped);
if (!left_const && !right_const)
2020-10-17 14:23:37 +00:00
return nullptr;
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
const IDataType * type_string = left_const ? left_type.get() : right_type.get();
const DataTypePtr & type_to_compare = !left_const ? left_type : right_type;
Field string_value = left_const ? left_const->getField() : right_const->getField();
Field converted = convertFieldToType(string_value, *type_to_compare, type_string);
/// If not possible to convert, comparison with =, <, >, <=, >= yields to false and comparison with != yields to true.
if (converted.isNull())
{
2020-10-17 14:23:37 +00:00
return DataTypeUInt8().createColumnConst(input_rows_count, IsOperation<Op>::not_equals);
}
else
{
auto column_converted = type_to_compare->createColumnConst(input_rows_count, converted);
2020-10-17 14:23:37 +00:00
ColumnsWithTypeAndName tmp_columns
{
{ left_const ? column_converted : col_left_untyped->getPtr(), type_to_compare, "" },
{ !left_const ? column_converted : col_right_untyped->getPtr(), type_to_compare, "" },
};
2020-10-20 13:11:57 +00:00
return executeImpl(tmp_columns, result_type, input_rows_count);
}
}
2020-10-17 14:23:37 +00:00
ColumnPtr executeTuple(
const DataTypePtr & result_type, const ColumnWithTypeAndName & c0, const ColumnWithTypeAndName & c1,
size_t input_rows_count) const
{
2017-05-27 15:45:25 +00:00
/** We will lexicographically compare the tuples. This is done as follows:
* x == y : x1 == y1 && x2 == y2 ...
* x != y : x1 != y1 || x2 != y2 ...
*
* x < y: x1 < y1 || (x1 == y1 && (x2 < y2 || (x2 == y2 ... && xn < yn))
* x > y: x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 == y2 ... && xn > yn))
* x <= y: x1 < y1 || (x1 == y1 && (x2 < y2 || (x2 == y2 ... && xn <= yn))
*
* Recursive form:
* x <= y: x1 < y1 || (x1 == y1 && x_tail <= y_tail)
*
* x >= y: x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 == y2 ... && xn >= yn))
*/
const size_t tuple_size = typeid_cast<const DataTypeTuple &>(*c0.type).getElements().size();
if (0 == tuple_size)
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Comparison of zero-sized tuples is not implemented.");
if (tuple_size != typeid_cast<const DataTypeTuple &>(*c1.type).getElements().size())
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Cannot compare tuples of different sizes.");
2020-10-17 14:23:37 +00:00
if (result_type->onlyNull())
return result_type->createColumnConstWithDefaultValue(input_rows_count);
2020-08-06 13:47:08 +00:00
ColumnsWithTypeAndName x(tuple_size);
ColumnsWithTypeAndName y(tuple_size);
2020-08-07 08:29:41 +00:00
const auto * x_const = checkAndGetColumnConst<ColumnTuple>(c0.column.get());
const auto * y_const = checkAndGetColumnConst<ColumnTuple>(c1.column.get());
Columns x_columns;
Columns y_columns;
2016-07-10 07:24:24 +00:00
if (x_const)
x_columns = convertConstTupleToConstantElements(*x_const);
else
x_columns = assert_cast<const ColumnTuple &>(*c0.column).getColumnsCopy();
2016-07-10 07:24:24 +00:00
if (y_const)
y_columns = convertConstTupleToConstantElements(*y_const);
else
y_columns = assert_cast<const ColumnTuple &>(*c1.column).getColumnsCopy();
for (size_t i = 0; i < tuple_size; ++i)
{
x[i].type = static_cast<const DataTypeTuple &>(*c0.type).getElements()[i];
y[i].type = static_cast<const DataTypeTuple &>(*c1.type).getElements()[i];
x[i].column = x_columns[i];
y[i].column = y_columns[i];
}
2020-10-20 13:11:57 +00:00
return executeTupleImpl(x, y, tuple_size, input_rows_count);
}
2020-10-17 14:23:37 +00:00
ColumnPtr executeTupleImpl(const ColumnsWithTypeAndName & x,
const ColumnsWithTypeAndName & y, size_t tuple_size,
size_t input_rows_count) const;
2020-10-17 14:23:37 +00:00
ColumnPtr executeTupleEqualityImpl(
std::shared_ptr<IFunctionOverloadResolver> func_compare,
std::shared_ptr<IFunctionOverloadResolver> func_convolution,
const ColumnsWithTypeAndName & x,
const ColumnsWithTypeAndName & y,
size_t tuple_size,
size_t input_rows_count) const
{
2019-12-10 11:19:11 +00:00
if (0 == tuple_size)
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Comparison of zero-sized tuples is not implemented.");
2019-12-10 11:19:11 +00:00
2020-10-17 14:23:37 +00:00
ColumnsWithTypeAndName convolution_columns(tuple_size);
ColumnsWithTypeAndName tmp_columns(2);
2020-06-29 13:25:28 +00:00
for (size_t i = 0; i < tuple_size; ++i)
{
2020-10-17 14:23:37 +00:00
tmp_columns[0] = x[i];
tmp_columns[1] = y[i];
2020-10-17 14:23:37 +00:00
auto impl = func_compare->build(tmp_columns);
convolution_columns[i].type = impl->getResultType();
2019-12-09 14:41:55 +00:00
2017-05-27 15:45:25 +00:00
/// Comparison of the elements.
2020-10-17 14:23:37 +00:00
convolution_columns[i].column = impl->execute(tmp_columns, impl->getResultType(), input_rows_count);
}
2019-12-10 11:19:11 +00:00
if (tuple_size == 1)
{
/// Do not call AND for single-element tuple.
2020-10-20 13:11:57 +00:00
return convolution_columns[0].column;
2019-12-10 11:19:11 +00:00
}
2017-05-27 15:45:25 +00:00
/// Logical convolution.
2020-10-17 14:23:37 +00:00
auto impl = func_convolution->build(convolution_columns);
return impl->execute(convolution_columns, impl->getResultType(), input_rows_count);
}
2020-10-17 14:23:37 +00:00
ColumnPtr executeTupleLessGreaterImpl(
std::shared_ptr<IFunctionOverloadResolver> func_compare_head,
std::shared_ptr<IFunctionOverloadResolver> func_compare_tail,
std::shared_ptr<IFunctionOverloadResolver> func_and,
std::shared_ptr<IFunctionOverloadResolver> func_or,
std::shared_ptr<IFunctionOverloadResolver> func_equals,
const ColumnsWithTypeAndName & x,
const ColumnsWithTypeAndName & y,
size_t tuple_size,
size_t input_rows_count) const
{
2020-10-17 14:23:37 +00:00
ColumnsWithTypeAndName less_columns(tuple_size);
ColumnsWithTypeAndName equal_columns(tuple_size - 1);
ColumnsWithTypeAndName tmp_columns(2);
2017-05-27 15:45:25 +00:00
/// Pairwise comparison of the inequality of all elements; on the equality of all elements except the last.
2020-06-29 13:25:28 +00:00
/// (x[i], y[i], x[i] < y[i], x[i] == y[i])
for (size_t i = 0; i < tuple_size; ++i)
{
2020-10-17 14:23:37 +00:00
tmp_columns[0] = x[i];
tmp_columns[1] = y[i];
if (i + 1 != tuple_size)
{
2020-10-17 14:23:37 +00:00
auto impl_head = func_compare_head->build(tmp_columns);
less_columns[i].type = impl_head->getResultType();
less_columns[i].column = impl_head->execute(tmp_columns, less_columns[i].type, input_rows_count);
2019-12-09 14:41:55 +00:00
2020-10-17 14:23:37 +00:00
auto impl_equals = func_equals->build(tmp_columns);
equal_columns[i].type = impl_equals->getResultType();
equal_columns[i].column = impl_equals->execute(tmp_columns, equal_columns[i].type, input_rows_count);
}
else
2019-12-09 14:41:55 +00:00
{
2020-10-17 14:23:37 +00:00
auto impl_tail = func_compare_tail->build(tmp_columns);
less_columns[i].type = impl_tail->getResultType();
less_columns[i].column = impl_tail->execute(tmp_columns, less_columns[i].type, input_rows_count);
2019-12-09 14:41:55 +00:00
}
}
2017-05-27 15:45:25 +00:00
/// Combination. Complex code - make a drawing. It can be replaced by a recursive comparison of tuples.
2020-06-29 13:25:28 +00:00
/// Last column contains intermediate result.
/// Code is generally equivalent to:
/// res = `x < y`[tuple_size - 1];
/// for (int i = tuple_size - 2; i >= 0; --i)
/// res = (res && `x == y`[i]) || `x < y`[i];
size_t i = tuple_size - 1;
2020-10-17 14:23:37 +00:00
tmp_columns[0] = less_columns[i];
while (i > 0)
{
--i;
2020-06-29 13:25:28 +00:00
2020-10-17 14:23:37 +00:00
tmp_columns[1] = equal_columns[i];
auto func_and_adaptor = func_and->build(tmp_columns);
2020-06-29 13:25:28 +00:00
2020-10-17 14:23:37 +00:00
tmp_columns[0].column = func_and_adaptor->execute(tmp_columns, func_and_adaptor->getResultType(), input_rows_count);
tmp_columns[0].type = func_and_adaptor->getResultType();
2020-06-29 13:25:28 +00:00
2020-10-17 14:23:37 +00:00
tmp_columns[1] = less_columns[i];
auto func_or_adaptor = func_or->build(tmp_columns);
2020-06-29 13:25:28 +00:00
2020-10-17 14:23:37 +00:00
tmp_columns[0].column = func_or_adaptor->execute(tmp_columns, func_or_adaptor->getResultType(), input_rows_count);
tmp_columns[tmp_columns.size() - 1].type = func_or_adaptor->getResultType();
}
2020-10-17 14:23:37 +00:00
return tmp_columns[0].column;
}
2020-10-17 14:23:37 +00:00
ColumnPtr executeGenericIdenticalTypes(const IColumn * c0, const IColumn * c1) const
{
bool c0_const = isColumnConst(*c0);
bool c1_const = isColumnConst(*c1);
/// This is a paranoid check to protect from a broken query analysis.
if (c0->isNullable() != c1->isNullable())
throw Exception(ErrorCodes::LOGICAL_ERROR,
"Logical error: columns are assumed to be of identical types, but they are different in Nullable");
if (c0_const && c1_const)
{
UInt8 res = 0;
GenericComparisonImpl<Op<int, int>>::constantConstant(*c0, *c1, res);
2020-10-17 14:23:37 +00:00
return DataTypeUInt8().createColumnConst(c0->size(), toField(res));
}
else
{
auto c_res = ColumnUInt8::create();
ColumnUInt8::Container & vec_res = c_res->getData();
vec_res.resize(c0->size());
if (c0_const)
GenericComparisonImpl<Op<int, int>>::constantVector(*c0, *c1, vec_res);
else if (c1_const)
GenericComparisonImpl<Op<int, int>>::vectorConstant(*c0, *c1, vec_res);
else
GenericComparisonImpl<Op<int, int>>::vectorVector(*c0, *c1, vec_res);
2020-10-20 21:27:01 +00:00
return c_res;
}
}
2020-10-17 14:23:37 +00:00
ColumnPtr executeGeneric(const ColumnWithTypeAndName & c0, const ColumnWithTypeAndName & c1) const
{
DataTypePtr common_type = getLeastSupertype(DataTypes{c0.type, c1.type});
2020-04-14 21:05:45 +00:00
ColumnPtr c0_converted = castColumn(c0, common_type);
ColumnPtr c1_converted = castColumn(c1, common_type);
2020-10-17 14:23:37 +00:00
return executeGenericIdenticalTypes(c0_converted.get(), c1_converted.get());
}
public:
String getName() const override
{
return name;
}
2016-12-29 19:38:10 +00:00
size_t getNumberOfArguments() const override { return 2; }
2021-06-22 16:21:23 +00:00
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
2017-05-27 15:45:25 +00:00
/// Get result types by argument types. If the function does not apply to these arguments, throw an exception.
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
WhichDataType left(arguments[0].get());
WhichDataType right(arguments[1].get());
const DataTypeTuple * left_tuple = checkAndGetDataType<DataTypeTuple>(arguments[0].get());
const DataTypeTuple * right_tuple = checkAndGetDataType<DataTypeTuple>(arguments[1].get());
bool both_represented_by_number = arguments[0]->isValueRepresentedByNumber() && arguments[1]->isValueRepresentedByNumber();
bool has_date = left.isDateOrDate32() || right.isDateOrDate32();
2020-06-27 19:05:00 +00:00
if (!((both_represented_by_number && !has_date) /// Do not allow to compare date and number.
|| (left.isStringOrFixedString() || right.isStringOrFixedString()) /// Everything can be compared with string by conversion.
/// You can compare the date, datetime, or datatime64 and an enumeration with a constant string.
|| ((left.isDate() || left.isDate32() || left.isDateTime() || left.isDateTime64()) && (right.isDate() || right.isDate32() || right.isDateTime() || right.isDateTime64()) && left.idx == right.idx) /// only date vs date, or datetime vs datetime
|| (left.isUUID() && right.isUUID())
|| (left.isIPv4() && right.isIPv4())
|| (left.isIPv6() && right.isIPv6())
|| (left.isEnum() && right.isEnum() && arguments[0]->getName() == arguments[1]->getName()) /// only equivalent enum type values can be compared against
2017-06-01 13:41:58 +00:00
|| (left_tuple && right_tuple && left_tuple->getElements().size() == right_tuple->getElements().size())
|| (arguments[0]->equals(*arguments[1]))))
{
2023-06-25 00:37:10 +00:00
if (!tryGetLeastSupertype(arguments))
2023-01-17 16:39:07 +00:00
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal types of arguments ({}, {})"
" of function {}", arguments[0]->getName(), arguments[1]->getName(), getName());
}
if (left_tuple && right_tuple)
{
2021-05-15 17:33:15 +00:00
auto func = FunctionToOverloadResolverAdaptor(FunctionComparison<Op, Name>::create(context));
2019-12-09 14:41:55 +00:00
2020-06-29 13:25:28 +00:00
bool has_nullable = false;
bool has_null = false;
2020-06-29 13:25:28 +00:00
size_t size = left_tuple->getElements().size();
for (size_t i = 0; i < size; ++i)
{
ColumnsWithTypeAndName args = {{nullptr, left_tuple->getElements()[i], ""},
{nullptr, right_tuple->getElements()[i], ""}};
2021-05-15 17:33:15 +00:00
auto element_type = func.build(args)->getResultType();
has_nullable = has_nullable || element_type->isNullable();
has_null = has_null || element_type->onlyNull();
}
2020-06-29 13:25:28 +00:00
/// If any element comparison is nullable, return type will also be nullable.
/// We useDefaultImplementationForNulls, but it doesn't work for tuples.
if (has_null)
return std::make_shared<DataTypeNullable>(std::make_shared<DataTypeNothing>());
2020-06-29 13:25:28 +00:00
if (has_nullable)
return std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt8>());
}
return std::make_shared<DataTypeUInt8>();
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
{
2020-10-17 14:23:37 +00:00
const auto & col_with_type_and_name_left = arguments[0];
const auto & col_with_type_and_name_right = arguments[1];
const IColumn * col_left_untyped = col_with_type_and_name_left.column.get();
const IColumn * col_right_untyped = col_with_type_and_name_right.column.get();
const DataTypePtr & left_type = col_with_type_and_name_left.type;
const DataTypePtr & right_type = col_with_type_and_name_right.type;
/// The case when arguments are the same (tautological comparison). Return constant.
2020-06-20 06:41:09 +00:00
/// NOTE: Nullable types are special case.
/// (BTW, this function use default implementation for Nullable, so Nullable types cannot be here. Check just in case.)
2023-05-28 14:02:46 +00:00
if (left_type->equals(*right_type) &&
!left_type->isNullable() &&
!isTuple(left_type) &&
!WhichDataType(left_type).isFloat() &&
col_left_untyped == col_right_untyped)
{
ColumnPtr result_column;
/// Always true: =, <=, >=
2020-09-08 00:59:13 +00:00
if constexpr (IsOperation<Op>::equals
|| IsOperation<Op>::less_or_equals
|| IsOperation<Op>::greater_or_equals)
{
result_column = DataTypeUInt8().createColumnConst(input_rows_count, 1u);
}
else
{
result_column = DataTypeUInt8().createColumnConst(input_rows_count, 0u);
}
if (!isColumnConst(*col_left_untyped))
result_column = result_column->convertToFullColumnIfConst();
return result_column;
}
2019-02-02 17:57:36 +00:00
WhichDataType which_left{left_type};
2019-02-02 15:02:57 +00:00
WhichDataType which_right{right_type};
const bool left_is_num = col_left_untyped->isNumeric();
const bool right_is_num = col_right_untyped->isNumeric();
2021-12-07 15:51:47 +00:00
const bool left_is_string = which_left.isStringOrFixedString();
const bool right_is_string = which_right.isStringOrFixedString();
2021-12-24 05:08:54 +00:00
const bool left_is_float = which_left.isFloat();
const bool right_is_float = which_right.isFloat();
const bool left_is_ipv6 = which_left.isIPv6();
const bool right_is_ipv6 = which_right.isIPv6();
const bool left_is_fixed_string = which_left.isFixedString();
const bool right_is_fixed_string = which_right.isFixedString();
size_t fixed_string_size =
left_is_fixed_string ?
assert_cast<const DataTypeFixedString &>(*left_type).getN() :
(right_is_fixed_string ? assert_cast<const DataTypeFixedString &>(*right_type).getN() : 0);
bool date_and_datetime = (which_left.idx != which_right.idx) && (which_left.isDate() || which_left.isDate32() || which_left.isDateTime() || which_left.isDateTime64())
&& (which_right.isDate() || which_right.isDate32() || which_right.isDateTime() || which_right.isDateTime64());
/// Interval data types can be compared only when having equal units.
bool left_is_interval = which_left.isInterval();
bool right_is_interval = which_right.isInterval();
bool types_equal = left_type->equals(*right_type);
2020-10-17 14:23:37 +00:00
ColumnPtr res;
if (left_is_num && right_is_num && !date_and_datetime
&& (!left_is_interval || !right_is_interval || types_equal))
2011-08-21 03:41:37 +00:00
{
2020-10-20 13:11:57 +00:00
if (!((res = executeNumLeftType<UInt8>(col_left_untyped, col_right_untyped))
2020-10-17 14:23:37 +00:00
|| (res = executeNumLeftType<UInt16>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<UInt32>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<UInt64>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<UInt128>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<UInt256>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<Int8>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<Int16>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<Int32>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<Int64>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<Int128>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<Int256>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<Float32>(col_left_untyped, col_right_untyped))
|| (res = executeNumLeftType<Float64>(col_left_untyped, col_right_untyped))))
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of first argument of function {}",
col_left_untyped->getName(), getName());
2020-10-17 14:23:37 +00:00
return res;
2011-08-21 03:41:37 +00:00
}
else if (checkAndGetDataType<DataTypeTuple>(left_type.get())
&& checkAndGetDataType<DataTypeTuple>(right_type.get()))
{
2020-10-17 14:23:37 +00:00
return executeTuple(result_type, col_with_type_and_name_left, col_with_type_and_name_right, input_rows_count);
}
2020-10-17 14:23:37 +00:00
else if (left_is_string && right_is_string && (res = executeString(col_left_untyped, col_right_untyped)))
{
2020-10-17 14:23:37 +00:00
return res;
}
2020-10-17 14:23:37 +00:00
else if ((res = executeWithConstString(
result_type, col_left_untyped, col_right_untyped,
left_type, right_type,
2020-10-17 14:23:37 +00:00
input_rows_count)))
{
2020-10-17 14:23:37 +00:00
return res;
}
else if (((left_is_ipv6 && right_is_fixed_string) || (right_is_ipv6 && left_is_fixed_string)) && fixed_string_size == IPV6_BINARY_LENGTH)
{
/// Special treatment for FixedString(16) as a binary representation of IPv6 -
/// CAST is customized for this case
ColumnPtr left_column = left_is_ipv6 ?
col_with_type_and_name_left.column : castColumn(col_with_type_and_name_left, right_type);
ColumnPtr right_column = right_is_ipv6 ?
col_with_type_and_name_right.column : castColumn(col_with_type_and_name_right, left_type);
return executeGenericIdenticalTypes(left_column.get(), right_column.get());
}
2021-08-03 06:23:46 +00:00
else if ((isColumnedAsDecimal(left_type) || isColumnedAsDecimal(right_type)))
2018-07-25 19:38:21 +00:00
{
// Comparing Date/Date32 and DateTime64 requires implicit conversion,
if (date_and_datetime && (isDateOrDate32(left_type) || isDateOrDate32(right_type)))
2021-08-03 06:23:46 +00:00
{
DataTypePtr common_type = getLeastSupertype(DataTypes{left_type, right_type});
2021-08-03 06:23:46 +00:00
ColumnPtr c0_converted = castColumn(col_with_type_and_name_left, common_type);
ColumnPtr c1_converted = castColumn(col_with_type_and_name_right, common_type);
return executeDecimal({c0_converted, common_type, "left"}, {c1_converted, common_type, "right"});
}
else
{
2021-12-24 05:19:51 +00:00
/// Check does another data type is comparable to Decimal, includes Int and Float.
2021-08-03 06:23:46 +00:00
if (!allowDecimalComparison(left_type, right_type) && !date_and_datetime)
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "No operation {} between {} and {}",
getName(), left_type->getName(), right_type->getName());
2021-12-24 05:19:51 +00:00
/// When Decimal comparing to Float32/64, we convert both of them into Float64.
/// Other systems like MySQL and Spark also do as this.
2021-12-24 05:08:54 +00:00
if (left_is_float || right_is_float)
{
2021-12-26 09:23:42 +00:00
const auto converted_type = std::make_shared<DataTypeFloat64>();
2021-12-24 05:08:54 +00:00
ColumnPtr c0_converted = castColumn(col_with_type_and_name_left, converted_type);
ColumnPtr c1_converted = castColumn(col_with_type_and_name_right, converted_type);
2022-01-13 03:25:01 +00:00
auto new_arguments
= ColumnsWithTypeAndName{{c0_converted, converted_type, "left"}, {c1_converted, converted_type, "right"}};
return executeImpl(new_arguments, result_type, input_rows_count);
2021-12-24 05:08:54 +00:00
}
2021-08-03 06:23:46 +00:00
return executeDecimal(col_with_type_and_name_left, col_with_type_and_name_right);
}
2018-07-25 19:38:21 +00:00
2021-08-03 06:23:46 +00:00
}
else if (date_and_datetime)
{
DataTypePtr common_type = getLeastSupertype(DataTypes{left_type, right_type});
2021-08-03 06:23:46 +00:00
ColumnPtr c0_converted = castColumn(col_with_type_and_name_left, common_type);
ColumnPtr c1_converted = castColumn(col_with_type_and_name_right, common_type);
if (!((res = executeNumLeftType<UInt32>(c0_converted.get(), c1_converted.get()))
|| (res = executeNumLeftType<UInt64>(c0_converted.get(), c1_converted.get()))
|| (res = executeNumLeftType<Int32>(c0_converted.get(), c1_converted.get()))
|| (res = executeDecimal({c0_converted, common_type, "left"}, {c1_converted, common_type, "right"}))))
throw Exception(ErrorCodes::LOGICAL_ERROR, "Date related common types can only be UInt32/UInt64/Int32/Decimal");
2021-08-03 06:23:46 +00:00
return res;
2018-07-25 19:38:21 +00:00
}
else if (types_equal)
{
2020-10-17 14:23:37 +00:00
return executeGenericIdenticalTypes(col_left_untyped, col_right_untyped);
}
else
{
2020-10-17 14:23:37 +00:00
return executeGeneric(col_with_type_and_name_left, col_with_type_and_name_right);
}
2017-06-01 13:41:58 +00:00
}
};
}