2011-08-15 21:50:08 +00:00
# pragma once
2019-03-03 20:08:39 +00:00
# include <Common/memcmpSmall.h>
2019-08-21 02:28:04 +00:00
# include <Common/assert_cast.h>
2022-05-20 20:42:48 +00:00
# include <Common/TargetSpecific.h>
2019-03-03 20:08:39 +00:00
2017-04-01 09:19:00 +00:00
# include <Columns/ColumnsNumber.h>
# include <Columns/ColumnConst.h>
2018-08-27 16:16:16 +00:00
# include <Columns/ColumnDecimal.h>
2017-04-01 09:19:00 +00:00
# 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>
2017-04-01 09:19:00 +00:00
# include <DataTypes/DataTypeDateTime.h>
2019-11-04 14:06:22 +00:00
# include <DataTypes/DataTypeDateTime64.h>
2021-12-24 05:08:54 +00:00
# include <DataTypes/DataTypeEnum.h>
2017-04-01 09:19:00 +00:00
# include <DataTypes/DataTypeFixedString.h>
2021-12-24 05:08:54 +00:00
# include <DataTypes/DataTypeNothing.h>
# include <DataTypes/DataTypeNullable.h>
# include <DataTypes/DataTypeString.h>
2017-04-01 09:19:00 +00:00
# include <DataTypes/DataTypeTuple.h>
2021-12-24 05:08:54 +00:00
# include <DataTypes/DataTypeUUID.h>
# include <DataTypes/DataTypesNumber.h>
2018-07-16 05:04:57 +00:00
# include <DataTypes/getLeastSupertype.h>
2020-06-13 22:18:48 +00:00
# include <Interpreters/convertFieldToType.h>
2018-07-16 05:04:57 +00:00
# include <Interpreters/castColumn.h>
2017-04-01 09:19:00 +00:00
2019-12-12 14:16:59 +00:00
# include <Functions/IFunctionAdaptors.h>
2017-07-21 06:35:58 +00:00
# include <Functions/FunctionHelpers.h>
2020-09-08 00:59:13 +00:00
# include <Functions/IsOperation.h>
2017-04-01 09:19:00 +00:00
2017-05-24 20:25:36 +00:00
# include <Core/AccurateComparison.h>
2018-09-02 01:12:32 +00:00
# include <Core/DecimalComparison.h>
2017-07-21 06:35:58 +00:00
# include <IO/ReadBufferFromMemory.h>
2017-04-01 09:19:00 +00:00
# include <IO/ReadHelpers.h>
2011-08-15 21:50:08 +00:00
2016-11-21 13:21:35 +00:00
# include <limits>
# include <type_traits>
2020-02-23 22:46:52 +00:00
# if USE_EMBEDDED_COMPILER
2023-04-11 18:04:30 +00:00
# include <DataTypes / Native.h>
# include <llvm / IR / IRBuilder.h>
2020-02-23 22:46:52 +00:00
# endif
2011-08-15 21:50:08 +00:00
namespace DB
{
2018-11-22 21:19:58 +00:00
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-11-22 21:19:58 +00:00
}
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 ) .
2011-08-15 21:50:08 +00:00
*
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 ) .
2015-06-12 07:46:58 +00:00
*
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-15 21:50:08 +00:00
*/
2011-08-21 06:52:21 +00:00
2017-09-15 12:16:12 +00:00
template < typename A , typename B , typename Op >
2014-08-17 03:29:56 +00:00
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 > ;
2020-08-19 11:52:17 +00:00
2022-06-06 01:29:47 +00:00
MULTITARGET_FUNCTION_AVX512BW_AVX512F_AVX2_SSE42 (
2022-05-24 12:25:29 +00:00
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 .
2014-08-17 05:41:28 +00:00
*/
2017-04-01 07:20:54 +00:00
2011-08-21 06:52:21 +00:00
size_t size = a . size ( ) ;
2020-02-24 00:12:47 +00:00
const A * __restrict a_pos = a . data ( ) ;
const B * __restrict b_pos = b . data ( ) ;
UInt8 * __restrict c_pos = c . data ( ) ;
2014-08-17 05:41:28 +00:00
const A * a_end = a_pos + size ;
2017-04-01 07:20:54 +00:00
2014-08-17 05:41:28 +00:00
while ( a_pos < a_end )
{
* c_pos = Op : : apply ( * a_pos , * b_pos ) ;
+ + a_pos ;
+ + b_pos ;
+ + c_pos ;
}
2022-05-20 20:42:48 +00:00
} ) )
static void NO_INLINE vectorVector ( const ContainerA & a , const ContainerB & b , PaddedPODArray < UInt8 > & c )
{
# if USE_MULTITARGET_CODE
2022-06-06 01:29:47 +00:00
if ( isArchSupported ( TargetArch : : AVX512BW ) )
{
vectorVectorImplAVX512BW ( a , b , c ) ;
return ;
}
2022-06-06 02:02:21 +00:00
if ( isArchSupported ( TargetArch : : AVX512F ) )
2022-06-06 01:29:47 +00:00
{
vectorVectorImplAVX512F ( a , b , c ) ;
return ;
}
2022-05-20 20:42:48 +00:00
if ( isArchSupported ( TargetArch : : AVX2 ) )
{
vectorVectorImplAVX2 ( a , b , c ) ;
return ;
}
2022-06-06 01:29:47 +00:00
2022-06-06 02:07:45 +00:00
if ( isArchSupported ( TargetArch : : SSE42 ) )
2022-05-20 20:42:48 +00:00
{
vectorVectorImplSSE42 ( a , b , c ) ;
return ;
}
# endif
vectorVectorImpl ( a , b , c ) ;
2011-08-21 06:52:21 +00:00
}
2017-04-01 07:20:54 +00:00
2022-05-20 20:42:48 +00:00
2022-06-06 01:29:47 +00:00
MULTITARGET_FUNCTION_AVX512BW_AVX512F_AVX2_SSE42 (
2022-05-24 12:25:29 +00:00
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 ( ) ;
2020-02-24 00:12:47 +00:00
const A * __restrict a_pos = a . data ( ) ;
UInt8 * __restrict c_pos = c . data ( ) ;
2014-08-17 05:41:28 +00:00
const A * a_end = a_pos + size ;
2017-04-01 07:20:54 +00:00
2014-08-17 05:41:28 +00:00
while ( a_pos < a_end )
{
* c_pos = Op : : apply ( * a_pos , b ) ;
+ + a_pos ;
+ + c_pos ;
}
2022-05-20 20:42:48 +00:00
} ) )
2022-05-21 12:54:45 +00:00
static void NO_INLINE vectorConstant ( const ContainerA & a , B b , PaddedPODArray < UInt8 > & c )
{
2022-05-20 20:42:48 +00:00
# if USE_MULTITARGET_CODE
2022-06-06 01:29:47 +00:00
if ( isArchSupported ( TargetArch : : AVX512BW ) )
{
vectorConstantImplAVX512BW ( a , b , c ) ;
return ;
}
if ( isArchSupported ( TargetArch : : AVX512F ) )
{
vectorConstantImplAVX512F ( a , b , c ) ;
return ;
}
2022-05-20 20:42:48 +00:00
if ( isArchSupported ( TargetArch : : AVX2 ) )
{
vectorConstantImplAVX2 ( a , b , c ) ;
return ;
}
2022-06-06 01:29:47 +00:00
if ( isArchSupported ( TargetArch : : SSE42 ) )
2022-05-20 20:42:48 +00:00
{
vectorConstantImplSSE42 ( a , b , c ) ;
return ;
}
# endif
vectorConstantImpl ( a , b , c ) ;
2011-08-21 06:52:21 +00:00
}
2017-04-01 07:20:54 +00:00
2020-08-19 11:52:17 +00:00
static void constantVector ( A a , const ContainerB & b , PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2020-03-23 02:12:31 +00:00
NumComparisonImpl < B , A , typename Op : : SymmetricOp > : : vectorConstant ( b , a , c ) ;
2011-08-21 06:52:21 +00:00
}
2018-03-17 18:29:50 +00:00
2020-03-23 02:12:31 +00:00
static void constantConstant ( A a , B b , UInt8 & c )
2018-03-17 18:29:50 +00:00
{
c = Op : : apply ( a , b ) ;
}
2011-08-21 06:52:21 +00:00
} ;
2014-08-17 03:29:56 +00:00
template < typename Op >
struct StringComparisonImpl
2011-08-21 06:52:21 +00:00
{
2022-03-12 18:05:50 +00:00
static void NO_INLINE string_vector_string_vector ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data , const ColumnString : : Offsets & a_offsets ,
const ColumnString : : Chars & b_data , const ColumnString : : Offsets & b_offsets ,
2016-04-15 00:33:21 +00:00
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 ;
2017-06-09 15:52:46 +00:00
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 ) ;
2017-06-09 15:52:46 +00:00
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
}
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE string_vector_fixed_string_vector ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data , const ColumnString : : Offsets & a_offsets ,
const ColumnString : : Chars & b_data , ColumnString : : Offset b_n ,
2016-04-15 00:33:21 +00:00
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 )
{
2020-04-20 01:01:31 +00:00
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
}
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE string_vector_constant ( /// NOLINT
2018-11-25 00:08:50 +00:00
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 ,
2016-04-15 00:33:21 +00:00
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
}
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void fixed_string_vector_string_vector ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data , ColumnString : : Offset a_n ,
const ColumnString : : Chars & b_data , const ColumnString : : Offsets & b_offsets ,
2016-04-15 00:33:21 +00:00
PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2017-03-10 20:15:34 +00:00
StringComparisonImpl < typename Op : : SymmetricOp > : : string_vector_fixed_string_vector ( b_data , b_offsets , a_data , a_n , c ) ;
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE fixed_string_vector_fixed_string_vector_16 ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data ,
const ColumnString : : Chars & b_data ,
2017-03-10 20:15:34 +00:00
PaddedPODArray < UInt8 > & c )
{
size_t size = a_data . size ( ) ;
2017-04-01 07:20:54 +00:00
2017-03-10 20:15:34 +00:00
for ( size_t i = 0 , j = 0 ; i < size ; i + = 16 , + + j )
2017-03-10 21:41:44 +00:00
c [ j ] = Op : : apply ( memcmp16 ( & a_data [ i ] , & b_data [ i ] ) , 0 ) ;
2011-08-21 06:52:21 +00:00
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE fixed_string_vector_constant_16 ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data ,
2019-03-03 20:08:39 +00:00
const ColumnString : : Chars & b_data ,
2017-03-10 20:15:34 +00:00
PaddedPODArray < UInt8 > & c )
{
size_t size = a_data . size ( ) ;
2017-04-01 07:20:54 +00:00
2017-03-10 20:15:34 +00:00
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 ) ;
2017-03-10 20:15:34 +00:00
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE fixed_string_vector_fixed_string_vector ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data , ColumnString : : Offset a_n ,
const ColumnString : : Chars & b_data , ColumnString : : Offset b_n ,
2016-04-15 00:33:21 +00:00
PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2017-03-10 20:15:34 +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 ) .
*/
2017-03-10 20:15:34 +00:00
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 )
2017-03-10 20:15:34 +00:00
{
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 )
2020-04-20 01:01:31 +00:00
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
}
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE fixed_string_vector_constant ( /// NOLINT
2018-11-25 00:08:50 +00:00
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 ,
2016-04-15 00:33:21 +00:00
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 ) ;
2017-03-10 20:15:34 +00:00
}
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
}
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +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 ,
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & b_data , const ColumnString : : Offsets & b_offsets ,
2016-04-15 00:33:21 +00:00
PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2020-04-20 01:01:31 +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
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +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 ,
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & b_data , ColumnString : : Offset b_n ,
2016-04-15 00:33:21 +00:00
PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2020-04-20 01:01:31 +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
}
} ;
2017-03-10 20:15:34 +00:00
/// Comparisons for equality/inequality are implemented slightly more efficient.
2014-08-17 03:29:56 +00:00
template < bool positive >
struct StringEqualsImpl
2011-08-21 06:52:21 +00:00
{
2022-03-12 18:05:50 +00:00
static void NO_INLINE string_vector_string_vector ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data , const ColumnString : : Offsets & a_offsets ,
const ColumnString : : Chars & b_data , const ColumnString : : Offsets & b_offsets ,
2016-04-15 00:33:21 +00:00
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
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE string_vector_fixed_string_vector ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data , const ColumnString : : Offsets & a_offsets ,
const ColumnString : : Chars & b_data , ColumnString : : Offset b_n ,
2016-04-15 00:33:21 +00:00
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 ;
2020-04-20 01:01:31 +00:00
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
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE string_vector_constant ( /// NOLINT
2018-11-25 00:08:50 +00:00
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 ,
2016-04-15 00:33:21 +00:00
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 ;
FunctionsComparison: optimize the comparison with empty string
Add the fast path in string_vector_constant if the string constant
is empty string. If the string size a_size and the string constant
size b_size are both 0, they are equal and both empty string. And
there is no need to call memequalSmallAllowOverflow15() for string
comparison.
We have tested the patch on ICX 8380 x 2 server with ClickBench.
Query 5, 10, 12, 13, 14, 15, 18, 20, 21, 22, 24, 25, 26, 27, 29, 34
of Clickbench have gained 2%-6% improvement. The overall geomean has
gained 1% improvement.
2022-09-28 15:47:46 +00:00
if ( b_size = = 0 )
2019-03-03 20:08:39 +00:00
{
FunctionsComparison: optimize the comparison with empty string
Add the fast path in string_vector_constant if the string constant
is empty string. If the string size a_size and the string constant
size b_size are both 0, they are equal and both empty string. And
there is no need to call memequalSmallAllowOverflow15() for string
comparison.
We have tested the patch on ICX 8380 x 2 server with ClickBench.
Query 5, 10, 12, 13, 14, 15, 18, 20, 21, 22, 24, 25, 26, 27, 29, 34
of Clickbench have gained 2%-6% improvement. The overall geomean has
gained 1% improvement.
2022-09-28 15:47:46 +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
FunctionsComparison: optimize the comparison with empty string
Add the fast path in string_vector_constant if the string constant
is empty string. If the string size a_size and the string constant
size b_size are both 0, they are equal and both empty string. And
there is no need to call memequalSmallAllowOverflow15() for string
comparison.
We have tested the patch on ICX 8380 x 2 server with ClickBench.
Query 5, 10, 12, 13, 14, 15, 18, 20, 21, 22, 24, 25, 26, 27, 29, 34
of Clickbench have gained 2%-6% improvement. The overall geomean has
gained 1% improvement.
2022-09-28 15:47:46 +00:00
if ( a_size = = 0 )
c [ i ] = positive ;
else
c [ i ] = ! positive ;
2019-03-03 20:08:39 +00:00
FunctionsComparison: optimize the comparison with empty string
Add the fast path in string_vector_constant if the string constant
is empty string. If the string size a_size and the string constant
size b_size are both 0, they are equal and both empty string. And
there is no need to call memequalSmallAllowOverflow15() for string
comparison.
We have tested the patch on ICX 8380 x 2 server with ClickBench.
Query 5, 10, 12, 13, 14, 15, 18, 20, 21, 22, 24, 25, 26, 27, 29, 34
of Clickbench have gained 2%-6% improvement. The overall geomean has
gained 1% improvement.
2022-09-28 15:47:46 +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
}
2022-03-12 18:05:50 +00:00
static void NO_INLINE fixed_string_vector_fixed_string_vector_16 ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data ,
const ColumnString : : Chars & b_data ,
2017-03-10 20:15:34 +00:00
PaddedPODArray < UInt8 > & c )
{
2019-03-03 20:08:39 +00:00
size_t size = a_data . size ( ) / 16 ;
2017-04-01 07:20:54 +00:00
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 ) ;
2017-03-10 20:15:34 +00:00
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE fixed_string_vector_constant_16 ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data ,
2019-03-03 20:08:39 +00:00
const ColumnString : : Chars & b_data ,
2017-03-10 20:15:34 +00:00
PaddedPODArray < UInt8 > & c )
{
2019-03-03 20:08:39 +00:00
size_t size = a_data . size ( ) / 16 ;
2017-04-01 07:20:54 +00:00
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 ( ) ) ;
2017-03-10 20:15:34 +00:00
}
2022-03-12 18:05:50 +00:00
static void NO_INLINE fixed_string_vector_fixed_string_vector ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data , ColumnString : : Offset a_n ,
const ColumnString : : Chars & b_data , ColumnString : : Offset b_n ,
2016-04-15 00:33:21 +00:00
PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2017-03-10 20:15:34 +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 ) ;
}
2020-04-20 01:01:31 +00:00
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 ) ;
}
2017-03-10 20:15:34 +00:00
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 )
2020-04-20 01:01:31 +00:00
c [ i ] = positive = = memequalSmallLikeZeroPaddedAllowOverflow15 ( a_data . data ( ) + i * a_n , a_n , b_data . data ( ) + i * b_n , b_n ) ;
2017-03-10 20:15:34 +00:00
}
2011-08-21 06:52:21 +00:00
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void NO_INLINE fixed_string_vector_constant ( /// NOLINT
2018-11-25 00:08:50 +00:00
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 ,
2016-04-15 00:33:21 +00:00
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 )
2017-03-10 20:15:34 +00:00
{
2019-03-03 20:08:39 +00:00
fixed_string_vector_constant_16 ( a_data , b_data , c ) ;
2017-03-10 20:15:34 +00:00
}
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 )
2020-04-20 01:01:31 +00:00
c [ i ] = positive = = memequalSmallLikeZeroPaddedAllowOverflow15 ( a_data . data ( ) + i * a_n , a_n , b_data . data ( ) , b_size ) ;
2017-03-10 20:15:34 +00:00
}
2011-08-21 06:52:21 +00:00
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +00:00
static void fixed_string_vector_string_vector ( /// NOLINT
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data , ColumnString : : Offset a_n ,
const ColumnString : : Chars & b_data , const ColumnString : : Offsets & b_offsets ,
2016-04-15 00:33:21 +00:00
PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2014-08-17 03:29:56 +00:00
string_vector_fixed_string_vector ( b_data , b_offsets , a_data , a_n , c ) ;
2011-08-21 06:52:21 +00:00
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +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 ,
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & b_data , const ColumnString : : Offsets & b_offsets ,
2016-04-15 00:33:21 +00:00
PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2020-04-20 01:01:31 +00:00
string_vector_constant ( b_data , b_offsets , a_data , a_size , c ) ;
2011-08-21 06:52:21 +00:00
}
2017-04-01 07:20:54 +00:00
2022-03-12 18:05:50 +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 ,
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & b_data , ColumnString : : Offset b_n ,
2016-04-15 00:33:21 +00:00
PaddedPODArray < UInt8 > & c )
2011-08-21 06:52:21 +00:00
{
2020-04-20 01:01:31 +00:00
fixed_string_vector_constant ( b_data , b_n , a_data , a_size , c ) ;
2011-08-21 06:52:21 +00:00
}
} ;
2014-08-17 03:29:56 +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-15 21:50:08 +00:00
2011-08-19 20:35:21 +00:00
2017-03-12 04:22:52 +00:00
/// Generic version, implemented for columns of same type.
template < typename Op >
struct GenericComparisonImpl
{
2020-03-23 02:12:31 +00:00
static void NO_INLINE vectorVector ( const IColumn & a , const IColumn & b , PaddedPODArray < UInt8 > & c )
2017-03-12 04:22:52 +00:00
{
for ( size_t i = 0 , size = a . size ( ) ; i < size ; + + i )
c [ i ] = Op : : apply ( a . compareAt ( i , i , b , 1 ) , 0 ) ;
}
2017-04-01 07:20:54 +00:00
2020-03-23 02:12:31 +00:00
static void NO_INLINE vectorConstant ( const IColumn & a , const IColumn & b , PaddedPODArray < UInt8 > & c )
2017-03-12 04:22:52 +00:00
{
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 ) ;
}
2017-04-01 07:20:54 +00:00
2020-03-23 02:12:31 +00:00
static void constantVector ( const IColumn & a , const IColumn & b , PaddedPODArray < UInt8 > & c )
2017-03-12 04:22:52 +00:00
{
2020-03-23 02:12:31 +00:00
GenericComparisonImpl < typename Op : : SymmetricOp > : : vectorConstant ( b , a , c ) ;
2017-03-12 04:22:52 +00:00
}
2018-03-17 18:29:50 +00:00
2020-03-23 02:12:31 +00:00
static void constantConstant ( const IColumn & a , const IColumn & b , UInt8 & c )
2018-03-17 18:29:50 +00:00
{
c = Op : : apply ( a . compareAt ( 0 , 0 , b , 1 ) , 0 ) ;
}
2017-03-12 04:22:52 +00:00
} ;
2018-09-02 01:12:32 +00:00
# if USE_EMBEDDED_COMPILER
2018-09-02 02:09:15 +00:00
template < template < typename , typename > typename Op > struct CompileOp ;
2018-09-02 01:12:32 +00:00
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 ) ;
2018-09-02 01:12:32 +00:00
}
} ;
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
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 " ; } ;
2015-10-12 01:42:47 +00:00
2021-04-10 23:33:54 +00:00
template < template < typename , typename > class Op , typename Name >
2011-08-15 21:50:08 +00:00
class FunctionComparison : public IFunction
{
2014-11-12 17:23:26 +00:00
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 ) ; }
2018-08-28 13:59:52 +00:00
2021-06-01 12:20:52 +00:00
explicit FunctionComparison ( ContextPtr context_ )
2021-04-10 23:33:54 +00:00
: context ( context_ ) , check_decimal_overflow ( decimalCheckComparisonOverflow ( context ) ) { }
2011-08-15 21:50:08 +00:00
2014-11-12 17:23:26 +00:00
private :
2021-06-01 12:20:52 +00:00
ContextPtr context ;
2018-08-28 13:59:52 +00:00
bool check_decimal_overflow = true ;
2018-07-16 05:04:57 +00:00
2011-08-15 21:50:08 +00:00
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
2011-08-15 21:50:08 +00:00
{
2017-07-21 06:35:58 +00:00
if ( const ColumnVector < T1 > * col_right = checkAndGetColumn < ColumnVector < T1 > > ( col_right_untyped ) )
2011-08-15 21:50:08 +00:00
{
2017-12-14 03:56:56 +00:00
auto col_res = ColumnUInt8 : : create ( ) ;
2017-04-01 07:20:54 +00:00
2017-12-15 21:32:25 +00:00
ColumnUInt8 : : Container & vec_res = col_res - > getData ( ) ;
2011-08-15 21:50:08 +00:00
vec_res . resize ( col_left - > getData ( ) . size ( ) ) ;
2020-03-23 02:12:31 +00:00
NumComparisonImpl < T0 , T1 , Op < T0 , T1 > > : : vectorVector ( col_left - > getData ( ) , col_right - > getData ( ) , vec_res ) ;
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
return col_res ;
2011-08-15 21:50:08 +00:00
}
2018-08-27 16:31:45 +00:00
else if ( auto col_right_const = checkAndGetColumnConst < ColumnVector < T1 > > ( col_right_untyped ) )
2011-08-15 21:50:08 +00:00
{
2017-12-14 03:56:56 +00:00
auto col_res = ColumnUInt8 : : create ( ) ;
2017-04-01 07:20:54 +00:00
2017-12-15 21:32:25 +00:00
ColumnUInt8 : : Container & vec_res = col_res - > getData ( ) ;
2017-07-21 06:35:58 +00:00
vec_res . resize ( col_left - > size ( ) ) ;
2020-03-23 02:12:31 +00:00
NumComparisonImpl < T0 , T1 , Op < T0 , T1 > > : : vectorConstant ( col_left - > getData ( ) , col_right_const - > template getValue < T1 > ( ) , vec_res ) ;
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
return col_res ;
2011-08-15 21:50:08 +00:00
}
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
return nullptr ;
2011-08-15 21:50:08 +00:00
}
2017-04-01 07:20:54 +00:00
2011-08-15 21:50:08 +00:00
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
2011-08-15 21:50:08 +00:00
{
2017-07-21 06:35:58 +00:00
if ( const ColumnVector < T1 > * col_right = checkAndGetColumn < ColumnVector < T1 > > ( col_right_untyped ) )
2011-08-15 21:50:08 +00:00
{
2017-12-14 03:56:56 +00:00
auto col_res = ColumnUInt8 : : create ( ) ;
2017-04-01 07:20:54 +00:00
2017-12-15 21:32:25 +00:00
ColumnUInt8 : : Container & vec_res = col_res - > getData ( ) ;
2011-08-15 21:50:08 +00:00
vec_res . resize ( col_left - > size ( ) ) ;
2020-03-23 02:12:31 +00:00
NumComparisonImpl < T0 , T1 , Op < T0 , T1 > > : : constantVector ( col_left - > template getValue < T0 > ( ) , col_right - > getData ( ) , vec_res ) ;
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
return col_res ;
2011-08-15 21:50:08 +00:00
}
2018-08-27 16:31:45 +00:00
else if ( auto col_right_const = checkAndGetColumnConst < ColumnVector < T1 > > ( col_right_untyped ) )
2018-03-17 18:29:50 +00:00
{
UInt8 res = 0 ;
2020-03-23 02:12:31 +00:00
NumComparisonImpl < T0 , T1 , Op < T0 , T1 > > : : constantConstant ( col_left - > template getValue < T0 > ( ) , col_right_const - > template getValue < T1 > ( ) , res ) ;
2018-03-17 18:29:50 +00:00
2020-10-17 14:23:37 +00:00
return DataTypeUInt8 ( ) . createColumnConst ( col_left - > size ( ) , toField ( res ) ) ;
2018-03-17 18:29:50 +00:00
}
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
return nullptr ;
2011-08-15 21:50:08 +00:00
}
2017-04-01 07:20:54 +00:00
2011-08-15 21:50:08 +00:00
template < typename T0 >
2020-10-17 14:23:37 +00:00
ColumnPtr executeNumLeftType ( const IColumn * col_left_untyped , const IColumn * col_right_untyped ) const
2011-08-15 21:50:08 +00:00
{
2020-10-17 14:23:37 +00:00
ColumnPtr res = nullptr ;
2017-07-21 06:35:58 +00:00
if ( const ColumnVector < T0 > * col_left = checkAndGetColumn < ColumnVector < T0 > > ( col_left_untyped ) )
2011-08-15 21:50:08 +00:00
{
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 ;
2011-08-15 21:50:08 +00:00
else
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Illegal column {} of second argument of function {} " ,
col_right_untyped - > getName ( ) , getName ( ) ) ;
2011-08-15 21:50:08 +00:00
}
2018-08-27 16:31:45 +00:00
else if ( auto col_left_const = checkAndGetColumnConst < ColumnVector < T0 > > ( col_left_untyped ) )
2011-08-15 21:50:08 +00:00
{
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 ;
2011-08-15 21:50:08 +00:00
else
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Illegal column {} of second argument of function {} " ,
col_right_untyped - > getName ( ) , getName ( ) ) ;
2011-08-15 21:50:08 +00:00
}
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
return nullptr ;
2011-08-15 21:50:08 +00:00
}
2017-04-01 07:20:54 +00:00
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
{
2018-08-20 15:17:55 +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
2018-08-20 15:17:55 +00:00
auto call = [ & ] ( const auto & types ) - > bool
2018-08-14 19:16:56 +00:00
{
2018-08-20 15:17:55 +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
2018-08-28 13:59:52 +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 ;
2018-08-22 13:22:56 +00:00
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
} ;
2019-10-07 15:19:18 +00:00
if ( ! callOnBasicTypes < true , false , true , true > ( left_number , right_number , call ) )
2023-01-23 21:13:58 +00:00
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
{
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
2017-07-21 06:35:58 +00:00
const ColumnConst * c0_const = checkAndGetColumnConstStringOrFixedString ( c0 ) ;
const ColumnConst * c1_const = checkAndGetColumnConstStringOrFixedString ( c1 ) ;
2017-04-01 07:20:54 +00:00
2017-03-12 04:22:52 +00:00
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 ;
2017-04-01 07:20:54 +00:00
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
2023-01-23 21:13:58 +00:00
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
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Logical error: ColumnConst contains not String nor FixedString column " ) ;
2019-03-03 20:08:39 +00:00
}
2014-08-17 03:29:56 +00:00
using StringImpl = StringComparisonImpl < Op < int , int > > ;
2017-04-01 07:20:54 +00:00
2018-03-17 18:29:50 +00:00
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 ( ) ) ;
2018-03-17 18:29:50 +00:00
}
2011-08-21 03:41:37 +00:00
else
2018-03-17 18:29:50 +00:00
{
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 )
2020-04-20 01:01:31 +00:00
StringImpl : : string_vector_constant (
2018-03-17 18:29:50 +00:00
c0_string - > getChars ( ) , c0_string - > getOffsets ( ) ,
2019-03-03 20:08:39 +00:00
* c1_const_chars , c1_const_size ,
2018-03-17 18:29:50 +00:00
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 )
2020-04-20 01:01:31 +00:00
StringImpl : : fixed_string_vector_constant (
2018-03-17 18:29:50 +00:00
c0_fixed_string - > getChars ( ) , c0_fixed_string - > getN ( ) ,
2019-03-03 20:08:39 +00:00
* c1_const_chars , c1_const_size ,
2018-03-17 18:29:50 +00:00
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 ,
2018-03-17 18:29:50 +00:00
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 ,
2018-03-17 18:29:50 +00:00
c1_fixed_string - > getChars ( ) , c1_fixed_string - > getN ( ) ,
c_res - > getData ( ) ) ;
else
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Illegal columns {} and {} of arguments of function {} " ,
c0 - > getName ( ) , c1 - > getName ( ) , getName ( ) ) ;
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
return c_res ;
2018-03-17 18:29:50 +00:00
}
2011-08-21 03:41:37 +00:00
}
2017-04-01 07:20:54 +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 ,
2020-10-14 13:09:11 +00:00
const DataTypePtr & left_type , const DataTypePtr & right_type , size_t input_rows_count ) const
2015-06-12 07:46:58 +00:00
{
2020-06-13 22:18:48 +00:00
/// To compare something with const string, we cast constant to appropriate type and compare as usual.
2020-06-13 23:27:10 +00:00
/// It is ok to throw exception if value is not convertible.
2020-06-13 22:18:48 +00:00
/// We should deal with possible overflows, e.g. toUInt8(1) = '257' should return false.
2017-04-01 07:20:54 +00:00
2020-06-13 22:18:48 +00:00
const ColumnConst * left_const = checkAndGetColumnConstStringOrFixedString ( col_left_untyped ) ;
const ColumnConst * right_const = checkAndGetColumnConstStringOrFixedString ( col_right_untyped ) ;
2018-09-06 08:56:46 +00:00
2020-06-13 22:18:48 +00:00
if ( ! left_const & & ! right_const )
2020-10-17 14:23:37 +00:00
return nullptr ;
2017-07-21 06:35:58 +00:00
2020-06-13 22:18:48 +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 ;
2017-04-01 07:20:54 +00:00
2020-06-13 22:18:48 +00:00
Field string_value = left_const ? left_const - > getField ( ) : right_const - > getField ( ) ;
Field converted = convertFieldToType ( string_value , * type_to_compare , type_string ) ;
2020-06-13 23:27:10 +00:00
/// If not possible to convert, comparison with =, <, >, <=, >= yields to false and comparison with != yields to true.
2020-06-13 22:18:48 +00:00
if ( converted . isNull ( ) )
2015-06-12 07:46:58 +00:00
{
2020-10-17 14:23:37 +00:00
return DataTypeUInt8 ( ) . createColumnConst ( input_rows_count , IsOperation < Op > : : not_equals ) ;
2015-06-12 07:46:58 +00:00
}
2020-06-13 22:18:48 +00:00
else
2017-06-15 09:12:32 +00:00
{
2020-06-13 22:18:48 +00:00
auto column_converted = type_to_compare - > createColumnConst ( input_rows_count , converted ) ;
2018-07-16 05:04:57 +00:00
2020-10-17 14:23:37 +00:00
ColumnsWithTypeAndName tmp_columns
2020-06-13 22:18:48 +00:00
{
{ left_const ? column_converted : col_left_untyped - > getPtr ( ) , type_to_compare , " " } ,
{ ! left_const ? column_converted : col_right_untyped - > getPtr ( ) , type_to_compare , " " } ,
} ;
2017-04-01 07:20:54 +00:00
2020-10-20 13:11:57 +00:00
return executeImpl ( tmp_columns , result_type , input_rows_count ) ;
2020-06-13 22:18:48 +00:00
}
2015-06-12 07:46:58 +00:00
}
2017-04-01 07:20:54 +00:00
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
2015-10-12 01:42:47 +00:00
{
2017-05-27 15:45:25 +00:00
/** We will lexicographically compare the tuples. This is done as follows:
2015-10-12 01:42:47 +00:00
* 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 ) )
*
2017-12-08 00:50:25 +00:00
* Recursive form :
2015-10-12 01:42:47 +00:00
* x < = y : x1 < y1 | | ( x1 = = y1 & & x_tail < = y_tail )
*
* x > = y : x1 > y1 | | ( x1 = = y1 & & ( x2 > y2 | | ( x2 = = y2 . . . & & xn > = yn ) )
*/
2017-04-01 07:20:54 +00:00
2017-12-09 12:23:09 +00:00
const size_t tuple_size = typeid_cast < const DataTypeTuple & > ( * c0 . type ) . getElements ( ) . size ( ) ;
2017-04-01 07:20:54 +00:00
2017-12-09 12:23:09 +00:00
if ( 0 = = tuple_size )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : NOT_IMPLEMENTED , " Comparison of zero-sized tuples is not implemented. " ) ;
2017-12-09 12:23:09 +00:00
2020-06-21 13:23:32 +00:00
if ( tuple_size ! = typeid_cast < const DataTypeTuple & > ( * c1 . type ) . getElements ( ) . size ( ) )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot compare tuples of different sizes. " ) ;
2020-06-21 13:23:32 +00:00
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
2017-12-09 12:23:09 +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 ( ) ) ;
2017-12-09 12:23:09 +00:00
Columns x_columns ;
Columns y_columns ;
2017-04-01 07:20:54 +00:00
2016-07-10 07:24:24 +00:00
if ( x_const )
2017-12-09 12:23:09 +00:00
x_columns = convertConstTupleToConstantElements ( * x_const ) ;
else
2019-08-21 02:28:04 +00:00
x_columns = assert_cast < const ColumnTuple & > ( * c0 . column ) . getColumnsCopy ( ) ;
2017-04-01 07:20:54 +00:00
2016-07-10 07:24:24 +00:00
if ( y_const )
2017-12-09 12:23:09 +00:00
y_columns = convertConstTupleToConstantElements ( * y_const ) ;
else
2019-08-21 02:28:04 +00:00
y_columns = assert_cast < const ColumnTuple & > ( * c1 . column ) . getColumnsCopy ( ) ;
2017-04-01 07:20:54 +00:00
2017-12-09 12:23:09 +00:00
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 ] ;
2017-04-01 07:20:54 +00:00
2017-12-09 12:23:09 +00:00
x [ i ] . column = x_columns [ i ] ;
y [ i ] . column = y_columns [ i ] ;
}
2017-04-01 07:20:54 +00:00
2020-10-20 13:11:57 +00:00
return executeTupleImpl ( x , y , tuple_size , input_rows_count ) ;
2015-10-12 01:42:47 +00:00
}
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
ColumnPtr executeTupleImpl ( const ColumnsWithTypeAndName & x ,
2020-10-14 13:09:11 +00:00
const ColumnsWithTypeAndName & y , size_t tuple_size ,
size_t input_rows_count ) const ;
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
ColumnPtr executeTupleEqualityImpl (
2020-10-14 13:09:11 +00:00
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
2015-10-12 01:42:47 +00:00
{
2019-12-10 11:19:11 +00:00
if ( 0 = = tuple_size )
2023-01-23 21:13:58 +00:00
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
2015-10-12 01:42:47 +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 ] ;
2017-04-01 07:20:54 +00:00
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 ) ;
2015-10-12 01:42:47 +00:00
}
2017-04-01 07:20:54 +00:00
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 ) ;
2015-10-12 01:42:47 +00:00
}
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
ColumnPtr executeTupleLessGreaterImpl (
2020-10-14 13:09:11 +00:00
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
2015-10-12 01:42:47 +00:00
{
2020-10-17 14:23:37 +00:00
ColumnsWithTypeAndName less_columns ( tuple_size ) ;
ColumnsWithTypeAndName equal_columns ( tuple_size - 1 ) ;
ColumnsWithTypeAndName tmp_columns ( 2 ) ;
2017-04-01 07:20:54 +00:00
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])
2015-10-12 01:42:47 +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 ] ;
2017-04-01 07:20:54 +00:00
2015-10-12 01:42:47 +00:00
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 ) ;
2017-04-01 07:20:54 +00:00
2015-10-12 01:42:47 +00:00
}
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
}
2015-10-12 01:42:47 +00:00
}
2017-04-01 07:20:54 +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];
2015-10-12 01:42:47 +00:00
size_t i = tuple_size - 1 ;
2020-10-17 14:23:37 +00:00
tmp_columns [ 0 ] = less_columns [ i ] ;
2015-10-12 01:42:47 +00:00
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 ( ) ;
2015-10-12 01:42:47 +00:00
}
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
return tmp_columns [ 0 ] . column ;
2015-10-12 01:42:47 +00:00
}
2017-04-01 07:20:54 +00:00
2020-10-17 14:23:37 +00:00
ColumnPtr executeGenericIdenticalTypes ( const IColumn * c0 , const IColumn * c1 ) const
2017-03-12 04:22:52 +00:00
{
2019-06-27 19:28:52 +00:00
bool c0_const = isColumnConst ( * c0 ) ;
bool c1_const = isColumnConst ( * c1 ) ;
2017-04-01 07:20:54 +00:00
2023-07-16 23:40:02 +00:00
/// 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 " ) ;
2018-03-17 18:29:50 +00:00
if ( c0_const & & c1_const )
{
UInt8 res = 0 ;
2020-03-23 02:12:31 +00:00
GenericComparisonImpl < Op < int , int > > : : constantConstant ( * c0 , * c1 , res ) ;
2020-10-17 14:23:37 +00:00
return DataTypeUInt8 ( ) . createColumnConst ( c0 - > size ( ) , toField ( res ) ) ;
2018-03-17 18:29:50 +00:00
}
2017-03-12 04:22:52 +00:00
else
2018-03-17 18:29:50 +00:00
{
auto c_res = ColumnUInt8 : : create ( ) ;
ColumnUInt8 : : Container & vec_res = c_res - > getData ( ) ;
vec_res . resize ( c0 - > size ( ) ) ;
if ( c0_const )
2020-03-23 02:12:31 +00:00
GenericComparisonImpl < Op < int , int > > : : constantVector ( * c0 , * c1 , vec_res ) ;
2018-03-17 18:29:50 +00:00
else if ( c1_const )
2020-03-23 02:12:31 +00:00
GenericComparisonImpl < Op < int , int > > : : vectorConstant ( * c0 , * c1 , vec_res ) ;
2018-03-17 18:29:50 +00:00
else
2020-03-23 02:12:31 +00:00
GenericComparisonImpl < Op < int , int > > : : vectorVector ( * c0 , * c1 , vec_res ) ;
2017-12-16 04:29:34 +00:00
2020-10-20 21:27:01 +00:00
return c_res ;
2018-03-17 18:29:50 +00:00
}
2017-03-12 04:22:52 +00:00
}
2015-10-12 01:42:47 +00:00
2020-10-17 14:23:37 +00:00
ColumnPtr executeGeneric ( const ColumnWithTypeAndName & c0 , const ColumnWithTypeAndName & c1 ) const
2018-07-16 05:04:57 +00:00
{
2021-06-12 15:10:25 +00:00
DataTypePtr common_type = getLeastSupertype ( DataTypes { c0 . type , c1 . type } ) ;
2018-07-16 05:04:57 +00:00
2020-04-14 21:05:45 +00:00
ColumnPtr c0_converted = castColumn ( c0 , common_type ) ;
ColumnPtr c1_converted = castColumn ( c1 , common_type ) ;
2018-07-16 05:04:57 +00:00
2020-10-17 14:23:37 +00:00
return executeGenericIdenticalTypes ( c0_converted . get ( ) , c1_converted . get ( ) ) ;
2018-07-16 05:04:57 +00:00
}
2011-08-15 21:50:08 +00:00
public :
2015-10-11 23:36:45 +00:00
String getName ( ) const override
2011-08-15 21:50:08 +00:00
{
2014-11-12 17:23:26 +00:00
return name ;
2011-08-15 21:50:08 +00:00
}
2017-04-01 07:20:54 +00:00
2016-12-29 19:38:10 +00:00
size_t getNumberOfArguments ( ) const override { return 2 ; }
2017-04-01 07:20:54 +00:00
2021-06-22 16:21:23 +00:00
bool isSuitableForShortCircuitArgumentsExecution ( const DataTypesWithConstInfo & /*arguments*/ ) const override { return false ; }
2021-04-27 12:49:58 +00:00
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.
2016-07-06 09:47:55 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override
2011-08-15 21:50:08 +00:00
{
2018-09-07 14:37:26 +00:00
WhichDataType left ( arguments [ 0 ] . get ( ) ) ;
WhichDataType right ( arguments [ 1 ] . get ( ) ) ;
2018-09-06 08:56:46 +00:00
const DataTypeTuple * left_tuple = checkAndGetDataType < DataTypeTuple > ( arguments [ 0 ] . get ( ) ) ;
const DataTypeTuple * right_tuple = checkAndGetDataType < DataTypeTuple > ( arguments [ 1 ] . get ( ) ) ;
2017-04-01 07:20:54 +00:00
2018-11-28 11:11:10 +00:00
bool both_represented_by_number = arguments [ 0 ] - > isValueRepresentedByNumber ( ) & & arguments [ 1 ] - > isValueRepresentedByNumber ( ) ;
2021-07-15 11:41:52 +00:00
bool has_date = left . isDateOrDate32 ( ) | | right . isDateOrDate32 ( ) ;
2018-11-28 11:11:10 +00:00
2020-06-27 19:05:00 +00:00
if ( ! ( ( both_represented_by_number & & ! has_date ) /// Do not allow to compare date and number.
2020-06-13 22:18:48 +00:00
| | ( left . isStringOrFixedString ( ) | | right . isStringOrFixedString ( ) ) /// Everything can be compared with string by conversion.
2020-04-28 15:29:09 +00:00
/// You can compare the date, datetime, or datatime64 and an enumeration with a constant string.
2021-10-15 08:09:37 +00:00
| | ( ( 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
2018-09-06 08:56:46 +00:00
| | ( left . isUUID ( ) & & right . isUUID ( ) )
2022-11-14 14:17:17 +00:00
| | ( left . isIPv4 ( ) & & right . isIPv4 ( ) )
| | ( left . isIPv6 ( ) & & right . isIPv6 ( ) )
2018-09-06 08:56:46 +00:00
| | ( 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 ] ) ) ) )
2018-07-16 05:04:57 +00:00
{
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 ( ) ) ;
2018-07-16 05:04:57 +00:00
}
2017-04-01 07:20:54 +00:00
2015-10-12 01:42:47 +00:00
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 ;
2020-08-06 12:54:14 +00:00
bool has_null = false ;
2020-06-29 13:25:28 +00:00
2015-10-12 01:42:47 +00:00
size_t size = left_tuple - > getElements ( ) . size ( ) ;
for ( size_t i = 0 ; i < size ; + + i )
2018-02-06 19:34:53 +00:00
{
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 ( ) ;
2020-08-06 12:54:14 +00:00
has_nullable = has_nullable | | element_type - > isNullable ( ) ;
has_null = has_null | | element_type - > onlyNull ( ) ;
2018-02-06 19:34:53 +00:00
}
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.
2020-08-06 12:54:14 +00:00
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 > ( ) ) ;
2015-10-12 01:42:47 +00:00
}
2017-04-01 07:20:54 +00:00
2016-05-28 07:48:40 +00:00
return std : : make_shared < DataTypeUInt8 > ( ) ;
2011-08-15 21:50:08 +00:00
}
2017-04-01 07:20:54 +00:00
2020-11-17 13:24:45 +00:00
ColumnPtr executeImpl ( const ColumnsWithTypeAndName & arguments , const DataTypePtr & result_type , size_t input_rows_count ) const override
2011-08-15 21:50:08 +00:00
{
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 ] ;
2016-07-30 04:39:51 +00:00
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 ( ) ;
2019-03-02 23:51:21 +00:00
2019-03-03 01:17:33 +00:00
const DataTypePtr & left_type = col_with_type_and_name_left . type ;
const DataTypePtr & right_type = col_with_type_and_name_right . type ;
2019-03-02 23:51:21 +00:00
/// 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 )
2019-03-02 23:51:21 +00:00
{
2021-05-12 14:43:37 +00:00
ColumnPtr result_column ;
2019-03-02 23:51:21 +00:00
/// 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 )
2019-03-02 23:51:21 +00:00
{
2021-05-12 14:43:37 +00:00
result_column = DataTypeUInt8 ( ) . createColumnConst ( input_rows_count , 1u ) ;
2019-03-02 23:51:21 +00:00
}
else
{
2021-05-12 14:43:37 +00:00
result_column = DataTypeUInt8 ( ) . createColumnConst ( input_rows_count , 0u ) ;
2019-03-02 23:51:21 +00:00
}
2021-05-12 14:43:37 +00:00
if ( ! isColumnConst ( * col_left_untyped ) )
result_column = result_column - > convertToFullColumnIfConst ( ) ;
return result_column ;
2019-03-02 23:51:21 +00:00
}
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 } ;
2019-02-02 14:23:44 +00:00
2015-12-22 12:03:21 +00:00
const bool left_is_num = col_left_untyped - > isNumeric ( ) ;
const bool right_is_num = col_right_untyped - > isNumeric ( ) ;
2017-04-01 07:20:54 +00:00
2021-12-07 15:51:47 +00:00
const bool left_is_string = which_left . isStringOrFixedString ( ) ;
const bool right_is_string = which_right . isStringOrFixedString ( ) ;
2020-06-13 22:18:48 +00:00
2021-12-24 05:08:54 +00:00
const bool left_is_float = which_left . isFloat ( ) ;
const bool right_is_float = which_right . isFloat ( ) ;
2020-06-13 22:18:48 +00:00
2022-11-24 05:00:28 +00:00
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 ) ;
2021-10-15 08:09:37 +00:00
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 ( ) ) ;
2019-02-02 14:23:44 +00:00
2020-10-17 14:23:37 +00:00
ColumnPtr res ;
2019-02-02 14:23:44 +00:00
if ( left_is_num & & right_is_num & & ! date_and_datetime )
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 ) ) ) )
2023-01-23 21:13:58 +00:00
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
}
2020-06-21 13:23:32 +00:00
else if ( checkAndGetDataType < DataTypeTuple > ( left_type . get ( ) )
& & checkAndGetDataType < DataTypeTuple > ( right_type . get ( ) ) )
2018-07-16 05:04:57 +00:00
{
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 ) ;
2018-07-16 05:04:57 +00:00
}
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-06-13 22:18:48 +00:00
{
2020-10-17 14:23:37 +00:00
return res ;
2020-06-13 22:18:48 +00:00
}
2020-10-17 14:23:37 +00:00
else if ( ( res = executeWithConstString (
result_type , col_left_untyped , col_right_untyped ,
2020-06-13 22:18:48 +00:00
left_type , right_type ,
2020-10-17 14:23:37 +00:00
input_rows_count ) ) )
2020-04-28 15:29:09 +00:00
{
2020-10-17 14:23:37 +00:00
return res ;
2020-04-28 15:29:09 +00:00
}
2022-11-24 05:00:28 +00:00
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
{
2021-10-18 08:53:25 +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
{
2021-08-20 13:33:30 +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 )
2023-01-23 21:13:58 +00:00
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 )
{
2021-08-20 13:33:30 +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 ) ;
if ( ! ( ( res = executeNumLeftType < UInt32 > ( c0_converted . get ( ) , c1_converted . get ( ) ) )
2021-10-18 08:53:25 +00:00
| | ( res = executeNumLeftType < UInt64 > ( c0_converted . get ( ) , c1_converted . get ( ) ) )
2021-10-15 08:09:37 +00:00
| | ( res = executeNumLeftType < Int32 > ( c0_converted . get ( ) , c1_converted . get ( ) ) )
2021-10-18 08:53:25 +00:00
| | ( res = executeDecimal ( { c0_converted , common_type , " left " } , { c1_converted , common_type , " right " } ) ) ) )
2023-01-23 21:13:58 +00:00
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 ( left_type - > equals ( * right_type ) )
2018-07-16 05:04:57 +00:00
{
2020-10-17 14:23:37 +00:00
return executeGenericIdenticalTypes ( col_left_untyped , col_right_untyped ) ;
2018-07-16 05:04:57 +00:00
}
else
{
2020-10-17 14:23:37 +00:00
return executeGeneric ( col_with_type_and_name_left , col_with_type_and_name_right ) ;
2018-07-16 05:04:57 +00:00
}
2017-06-01 13:41:58 +00:00
}
2011-08-15 21:50:08 +00:00
} ;
}