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>
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>
# include <DataTypes/DataTypesNumber.h>
# include <DataTypes/DataTypeDateTime.h>
2019-11-04 14:06:22 +00:00
# include <DataTypes/DataTypeDateTime64.h>
2017-04-01 09:19:00 +00:00
# include <DataTypes/DataTypeDate.h>
# include <DataTypes/DataTypeString.h>
2017-07-04 10:42:53 +00:00
# include <DataTypes/DataTypeUUID.h>
2017-04-01 09:19:00 +00:00
# include <DataTypes/DataTypeFixedString.h>
# include <DataTypes/DataTypeTuple.h>
# include <DataTypes/DataTypeEnum.h>
2018-07-16 05:04:57 +00:00
# include <DataTypes/getLeastSupertype.h>
# 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>
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
# include <DataTypes/Native.h>
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
# include <llvm/IR/IRBuilder.h>
# pragma GCC diagnostic pop
# endif
2011-08-15 21:50:08 +00:00
namespace DB
{
2018-11-22 21:19:58 +00:00
namespace ErrorCodes
{
extern const int TOO_LARGE_STRING_SIZE ;
extern const int ILLEGAL_COLUMN ;
extern const int ILLEGAL_TYPE_OF_ARGUMENT ;
extern const int LOGICAL_ERROR ;
extern const int NOT_IMPLEMENTED ;
}
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
{
2017-04-01 07:20:54 +00:00
/// If you don't specify NO_INLINE, the compiler will inline this function, but we don't need this as this function contains tight loop inside.
static void NO_INLINE vector_vector ( const PaddedPODArray < A > & a , const PaddedPODArray < B > & b , PaddedPODArray < UInt8 > & c )
{
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 .
2017-04-01 07:20:54 +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 ( ) ;
2017-04-01 07:20:54 +00:00
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 vector_constant ( const PaddedPODArray < A > & a , B b , PaddedPODArray < UInt8 > & c )
{
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 ( ) ;
2017-04-01 07:20:54 +00:00
const A * a_end = a_pos + size ;
while ( a_pos < a_end )
{
* c_pos = Op : : apply ( * a_pos , b ) ;
+ + a_pos ;
+ + c_pos ;
}
}
static void constant_vector ( A a , const PaddedPODArray < B > & b , PaddedPODArray < UInt8 > & c )
{
NumComparisonImpl < B , A , typename Op : : SymmetricOp > : : vector_constant ( b , a , c ) ;
}
2018-03-17 18:29:50 +00:00
static void constant_constant ( A a , B b , UInt8 & c )
{
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
{
2017-04-01 07:20:54 +00:00
static void NO_INLINE string_vector_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
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
2017-04-01 07:20:54 +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 ] ;
2017-04-01 07:20:54 +00:00
}
}
static void NO_INLINE string_vector_fixed_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
size_t size = a_offsets . size ( ) ;
2019-03-03 20:08:39 +00:00
ColumnString : : Offset prev_a_offset = 0 ;
2017-04-01 07:20:54 +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 ( ) + i * b_n , b_n ) , 0 ) ;
prev_a_offset = a_offsets [ i ] ;
2017-04-01 07:20:54 +00:00
}
}
static void NO_INLINE string_vector_constant (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
size_t size = a_offsets . size ( ) ;
2019-03-03 20:08:39 +00:00
ColumnString : : Offset prev_a_offset = 0 ;
2017-04-01 07:20:54 +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 ] ;
2017-04-01 07:20:54 +00:00
}
}
static void fixed_string_vector_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
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 (
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data ,
const ColumnString : : Chars & b_data ,
2017-04-01 07:20:54 +00:00
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 ) ;
}
static void NO_INLINE fixed_string_vector_constant_16 (
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-04-01 07:20:54 +00:00
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 ) ;
2017-04-01 07:20:54 +00:00
}
static void NO_INLINE fixed_string_vector_fixed_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
if ( a_n = = 16 & & b_n = = 16 )
{
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-04-01 07:20:54 +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-04-01 07:20:54 +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 )
c [ i ] = Op : : apply ( memcmpSmallAllowOverflow15 ( a_data . data ( ) + i * a_n , a_n , b_data . data ( ) + i * b_n , b_n ) , 0 ) ;
2017-04-01 07:20:54 +00:00
}
}
static void NO_INLINE fixed_string_vector_constant (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
2019-03-03 20:08:39 +00:00
if ( a_n = = 16 & & b_size = = 16 )
2017-04-01 07:20:54 +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-04-01 07:20:54 +00:00
}
else
{
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 , a_n , b_data . data ( ) , b_size ) , 0 ) ;
2017-04-01 07:20:54 +00:00
}
}
static void constant_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
2019-03-03 20:08:39 +00:00
StringComparisonImpl < typename Op : : SymmetricOp > : : string_vector_constant ( b_data , b_offsets , a_data , a_size , c ) ;
2017-04-01 07:20:54 +00:00
}
static void constant_fixed_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
2019-03-03 20:08:39 +00:00
StringComparisonImpl < typename Op : : SymmetricOp > : : fixed_string_vector_constant ( b_data , b_n , a_data , a_size , c ) ;
2017-04-01 07:20:54 +00:00
}
2018-03-17 18:29:50 +00:00
static void constant_constant (
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_size ,
2018-03-17 18:29:50 +00:00
UInt8 & c )
{
2019-03-03 20:08:39 +00:00
c = Op : : apply ( memcmpSmallAllowOverflow15 ( a_data . data ( ) , a_size , b_data . data ( ) , b_size ) , 0 ) ;
2018-03-17 18:29:50 +00:00
}
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
{
2017-04-01 07:20:54 +00:00
static void NO_INLINE string_vector_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
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-04-01 07:20:54 +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 ] ;
}
2017-04-01 07:20:54 +00:00
}
static void NO_INLINE string_vector_fixed_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
size_t size = a_offsets . size ( ) ;
2019-03-03 20:08:39 +00:00
ColumnString : : Offset prev_a_offset = 0 ;
2017-04-01 07:20:54 +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 = = memequalSmallAllowOverflow15 (
a_data . data ( ) + prev_a_offset , a_size ,
b_data . data ( ) + b_n * i , b_n ) ;
prev_a_offset = a_offsets [ i ] ;
}
2017-04-01 07:20:54 +00:00
}
static void NO_INLINE string_vector_constant (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
size_t size = a_offsets . size ( ) ;
2019-03-03 20:08:39 +00:00
ColumnString : : Offset prev_a_offset = 0 ;
2017-04-01 07:20:54 +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 = = memequalSmallAllowOverflow15 (
a_data . data ( ) + prev_a_offset , a_size ,
b_data . data ( ) , b_size ) ;
prev_a_offset = a_offsets [ i ] ;
}
2017-04-01 07:20:54 +00:00
}
2011-08-21 06:52:21 +00:00
2017-04-01 07:20:54 +00:00
static void NO_INLINE fixed_string_vector_fixed_string_vector_16 (
2018-11-25 00:08:50 +00:00
const ColumnString : : Chars & a_data ,
const ColumnString : : Chars & b_data ,
2017-04-01 07:20:54 +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-04-01 07:20:54 +00:00
}
static void NO_INLINE fixed_string_vector_constant_16 (
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-04-01 07:20:54 +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-04-01 07:20:54 +00:00
}
2017-03-10 20:15:34 +00:00
2017-04-01 07:20:54 +00:00
static void NO_INLINE fixed_string_vector_fixed_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
/** 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
{
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 = = memequalSmallAllowOverflow15 ( a_data . data ( ) + i * a_n , a_n , b_data . data ( ) + i * b_n , b_n ) ;
2017-04-01 07:20:54 +00:00
}
}
static void NO_INLINE fixed_string_vector_constant (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
2019-03-03 20:08:39 +00:00
if ( a_n = = 16 & & b_size = = 16 )
2017-04-01 07:20:54 +00:00
{
2019-03-03 20:08:39 +00:00
fixed_string_vector_constant_16 ( a_data , b_data , c ) ;
2017-04-01 07:20:54 +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 )
c [ i ] = positive = = memequalSmallAllowOverflow15 ( a_data . data ( ) + i * a_n , a_n , b_data . data ( ) , b_size ) ;
2017-04-01 07:20:54 +00:00
}
}
static void fixed_string_vector_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
string_vector_fixed_string_vector ( b_data , b_offsets , a_data , a_n , c ) ;
}
static void constant_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
2019-03-03 20:08:39 +00:00
string_vector_constant ( b_data , b_offsets , a_data , a_size , c ) ;
2017-04-01 07:20:54 +00:00
}
static void constant_fixed_string_vector (
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 ,
2017-04-01 07:20:54 +00:00
PaddedPODArray < UInt8 > & c )
{
2019-03-03 20:08:39 +00:00
fixed_string_vector_constant ( b_data , b_n , a_data , a_size , c ) ;
2017-04-01 07:20:54 +00:00
}
2018-03-17 18:29:50 +00:00
static void constant_constant (
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_size ,
2018-03-17 18:29:50 +00:00
UInt8 & c )
{
2019-03-03 20:08:39 +00:00
c = positive = = memequalSmallAllowOverflow15 ( a_data . data ( ) , a_size , b_data . data ( ) , b_size ) ;
2018-03-17 18:29:50 +00:00
}
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
{
2017-04-01 07:20:54 +00:00
static void NO_INLINE vector_vector ( 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 vector_constant ( 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 constant_vector ( const IColumn & a , const IColumn & b , PaddedPODArray < UInt8 > & c )
{
GenericComparisonImpl < typename Op : : SymmetricOp > : : vector_constant ( b , a , c ) ;
}
2018-03-17 18:29:50 +00:00
static void constant_constant ( const IColumn & a , const IColumn & b , UInt8 & c )
{
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*/ )
{
return x - > getType ( ) - > isIntegerTy ( ) ? b . CreateICmpNE ( x , y ) : b . CreateFCmpONE ( 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
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
2011-08-21 03:41:37 +00:00
template <
2017-04-01 07:20:54 +00:00
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 :
2017-04-01 07:20:54 +00:00
static constexpr auto name = Name : : name ;
2018-07-16 05:04:57 +00:00
static FunctionPtr create ( const Context & context ) { return std : : make_shared < FunctionComparison > ( context ) ; }
2018-08-28 13:59:52 +00:00
2019-08-03 11:02:40 +00:00
FunctionComparison ( const Context & context_ )
: context ( context_ ) ,
2018-08-28 13:59:52 +00:00
check_decimal_overflow ( decimalCheckComparisonOverflow ( context ) )
{ }
2011-08-15 21:50:08 +00:00
2014-11-12 17:23:26 +00:00
private :
2018-07-16 05:04:57 +00:00
const Context & context ;
2018-08-28 13:59:52 +00:00
bool check_decimal_overflow = true ;
2018-07-16 05:04:57 +00:00
2017-04-01 07:20:54 +00:00
template < typename T0 , typename T1 >
bool executeNumRightType ( Block & block , size_t result , const ColumnVector < T0 > * col_left , const IColumn * col_right_untyped )
{
2017-07-21 06:35:58 +00:00
if ( const ColumnVector < T1 > * col_right = checkAndGetColumn < ColumnVector < T1 > > ( col_right_untyped ) )
2017-04-01 07:20:54 +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-04-01 07:20:54 +00:00
vec_res . resize ( col_left - > getData ( ) . size ( ) ) ;
NumComparisonImpl < T0 , T1 , Op < T0 , T1 > > : : vector_vector ( col_left - > getData ( ) , col_right - > getData ( ) , vec_res ) ;
2017-12-14 03:56:56 +00:00
block . getByPosition ( result ) . column = std : : move ( col_res ) ;
2017-04-01 07:20:54 +00:00
return true ;
}
2018-08-27 16:31:45 +00:00
else if ( auto col_right_const = checkAndGetColumnConst < ColumnVector < T1 > > ( col_right_untyped ) )
2017-04-01 07:20:54 +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 ( ) ) ;
2018-08-27 16:31:45 +00:00
NumComparisonImpl < T0 , T1 , Op < T0 , T1 > > : : vector_constant ( col_left - > getData ( ) , col_right_const - > template getValue < T1 > ( ) , vec_res ) ;
2017-04-01 07:20:54 +00:00
2017-12-14 03:56:56 +00:00
block . getByPosition ( result ) . column = std : : move ( col_res ) ;
2017-04-01 07:20:54 +00:00
return true ;
}
return false ;
}
template < typename T0 , typename T1 >
2017-07-21 06:35:58 +00:00
bool executeNumConstRightType ( Block & block , size_t result , const ColumnConst * col_left , const IColumn * col_right_untyped )
2017-04-01 07:20:54 +00:00
{
2017-07-21 06:35:58 +00:00
if ( const ColumnVector < T1 > * col_right = checkAndGetColumn < ColumnVector < T1 > > ( col_right_untyped ) )
2017-04-01 07:20:54 +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-04-01 07:20:54 +00:00
vec_res . resize ( col_left - > size ( ) ) ;
2017-07-21 06:35:58 +00:00
NumComparisonImpl < T0 , T1 , Op < T0 , T1 > > : : constant_vector ( col_left - > template getValue < T0 > ( ) , col_right - > getData ( ) , vec_res ) ;
2017-04-01 07:20:54 +00:00
2017-12-14 03:56:56 +00:00
block . getByPosition ( result ) . column = std : : move ( col_res ) ;
2017-04-01 07:20:54 +00:00
return true ;
}
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 ;
2018-08-27 16:31:45 +00:00
NumComparisonImpl < T0 , T1 , Op < T0 , T1 > > : : constant_constant ( col_left - > template getValue < T0 > ( ) , col_right_const - > template getValue < T1 > ( ) , res ) ;
2018-03-17 18:29:50 +00:00
block . getByPosition ( result ) . column = DataTypeUInt8 ( ) . createColumnConst ( col_left - > size ( ) , toField ( res ) ) ;
return true ;
}
2017-04-01 07:20:54 +00:00
return false ;
}
template < typename T0 >
bool executeNumLeftType ( Block & block , size_t result , const IColumn * col_left_untyped , const IColumn * col_right_untyped )
{
2017-07-21 06:35:58 +00:00
if ( const ColumnVector < T0 > * col_left = checkAndGetColumn < ColumnVector < T0 > > ( col_left_untyped ) )
2017-04-01 07:20:54 +00:00
{
2017-07-21 06:35:58 +00:00
if ( executeNumRightType < T0 , UInt8 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , UInt16 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , UInt32 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , UInt64 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , UInt128 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , Int8 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , Int16 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , Int32 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , Int64 > ( block , result , col_left , col_right_untyped )
2018-07-25 19:38:21 +00:00
| | executeNumRightType < T0 , Int128 > ( block , result , col_left , col_right_untyped )
2017-07-21 06:35:58 +00:00
| | executeNumRightType < T0 , Float32 > ( block , result , col_left , col_right_untyped )
| | executeNumRightType < T0 , Float64 > ( block , result , col_left , col_right_untyped ) )
2017-04-01 07:20:54 +00:00
return true ;
else
throw Exception ( " Illegal column " + col_right_untyped - > getName ( )
+ " of second argument of function " + getName ( ) ,
ErrorCodes : : ILLEGAL_COLUMN ) ;
}
2018-08-27 16:31:45 +00:00
else if ( auto col_left_const = checkAndGetColumnConst < ColumnVector < T0 > > ( col_left_untyped ) )
2017-04-01 07:20:54 +00:00
{
2018-08-27 16:31:45 +00:00
if ( executeNumConstRightType < T0 , UInt8 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , UInt16 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , UInt32 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , UInt64 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , UInt128 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , Int8 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , Int16 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , Int32 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , Int64 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , Int128 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , Float32 > ( block , result , col_left_const , col_right_untyped )
| | executeNumConstRightType < T0 , Float64 > ( block , result , col_left_const , col_right_untyped ) )
2017-04-01 07:20:54 +00:00
return true ;
else
throw Exception ( " Illegal column " + col_right_untyped - > getName ( )
+ " of second argument of function " + getName ( ) ,
ErrorCodes : : ILLEGAL_COLUMN ) ;
}
return false ;
}
2018-07-26 15:28:14 +00:00
void executeDecimal ( Block & block , size_t result , const ColumnWithTypeAndName & col_left , const ColumnWithTypeAndName & col_right )
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 ( ) ;
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 )
2018-08-22 13:22:56 +00:00
DecimalComparison < LeftDataType , RightDataType , Op , true > ( block , result , col_left , col_right ) ;
else
DecimalComparison < LeftDataType , RightDataType , Op , false > ( block , result , col_left , col_right ) ;
2018-08-20 15:17:55 +00:00
return true ;
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 ) )
2018-07-26 15:28:14 +00:00
throw Exception ( " Wrong call for " + getName ( ) + " with " + col_left . type - > getName ( ) + " and " + col_right . type - > getName ( ) ,
ErrorCodes : : LOGICAL_ERROR ) ;
2018-07-25 19:38:21 +00:00
}
2017-04-01 07:20:54 +00:00
bool executeString ( Block & block , size_t result , const IColumn * c0 , const IColumn * c1 )
{
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
if ( ! ( ( c0_string | | c0_fixed_string | | c0_const ) & & ( c1_string | | c1_fixed_string | | c1_const ) ) )
return false ;
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 ( " Logical error: ColumnConst contains not String nor FixedString column " , ErrorCodes : : ILLEGAL_COLUMN ) ;
}
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 ( " Logical error: ColumnConst contains not String nor FixedString column " , ErrorCodes : : ILLEGAL_COLUMN ) ;
}
2017-04-01 07:20:54 +00:00
using StringImpl = StringComparisonImpl < Op < int , int > > ;
2018-03-17 18:29:50 +00:00
if ( c0_const & & c1_const )
{
UInt8 res = 0 ;
2019-03-03 20:08:39 +00:00
StringImpl : : constant_constant ( * c0_const_chars , c0_const_size , * c1_const_chars , c1_const_size , res ) ;
2018-03-17 18:29:50 +00:00
block . getByPosition ( result ) . column = block . getByPosition ( result ) . type - > createColumnConst ( c0_const - > size ( ) , toField ( res ) ) ;
return true ;
}
2017-04-01 07:20:54 +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 )
StringImpl : : string_vector_constant (
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 )
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 ,
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
throw Exception ( " Illegal columns "
+ c0 - > getName ( ) + " and " + c1 - > getName ( )
+ " of arguments of function " + getName ( ) ,
ErrorCodes : : ILLEGAL_COLUMN ) ;
2017-04-01 07:20:54 +00:00
2018-03-17 18:29:50 +00:00
block . getByPosition ( result ) . column = std : : move ( c_res ) ;
return true ;
}
2017-04-01 07:20:54 +00:00
}
2018-07-16 05:04:57 +00:00
bool executeDateOrDateTimeOrEnumOrUUIDWithConstString (
2017-04-01 07:20:54 +00:00
Block & block , size_t result , const IColumn * col_left_untyped , const IColumn * col_right_untyped ,
2018-04-24 07:16:39 +00:00
const DataTypePtr & left_type , const DataTypePtr & right_type , bool left_is_num , size_t input_rows_count )
2017-04-01 07:20:54 +00:00
{
2017-05-27 15:45:25 +00:00
/// This is no longer very special case - comparing dates, datetimes, and enumerations with a string constant.
2017-04-01 07:20:54 +00:00
const IColumn * column_string_untyped = ! left_is_num ? col_left_untyped : col_right_untyped ;
const IColumn * column_number = left_is_num ? col_left_untyped : col_right_untyped ;
const IDataType * number_type = left_is_num ? left_type . get ( ) : right_type . get ( ) ;
2018-09-07 14:37:26 +00:00
WhichDataType which ( number_type ) ;
2018-09-06 08:56:46 +00:00
const bool legal_types = which . isDateOrDateTime ( ) | | which . isEnum ( ) | | which . isUUID ( ) ;
2017-04-01 07:20:54 +00:00
2017-07-21 06:35:58 +00:00
const auto column_string = checkAndGetColumnConst < ColumnString > ( column_string_untyped ) ;
2017-04-01 07:20:54 +00:00
if ( ! column_string | | ! legal_types )
2018-07-16 05:04:57 +00:00
return false ;
2017-07-21 06:35:58 +00:00
StringRef string_value = column_string - > getDataAt ( 0 ) ;
2017-04-01 07:20:54 +00:00
2018-09-06 08:56:46 +00:00
if ( which . isDate ( ) )
2017-04-01 07:20:54 +00:00
{
2018-05-25 13:29:15 +00:00
DayNum date ;
2017-07-21 06:35:58 +00:00
ReadBufferFromMemory in ( string_value . data , string_value . size ) ;
2017-04-01 07:20:54 +00:00
readDateText ( date , in ) ;
if ( ! in . eof ( ) )
2018-11-22 21:19:58 +00:00
throw Exception ( " String is too long for Date: " + string_value . toString ( ) , ErrorCodes : : TOO_LARGE_STRING_SIZE ) ;
2017-04-01 07:20:54 +00:00
2018-10-22 08:54:54 +00:00
ColumnPtr parsed_const_date_holder = DataTypeDate ( ) . createColumnConst ( input_rows_count , date ) ;
2019-08-21 02:28:04 +00:00
const ColumnConst * parsed_const_date = assert_cast < const ColumnConst * > ( parsed_const_date_holder . get ( ) ) ;
2017-04-01 07:20:54 +00:00
executeNumLeftType < DataTypeDate : : FieldType > ( block , result ,
2017-07-21 06:35:58 +00:00
left_is_num ? col_left_untyped : parsed_const_date ,
left_is_num ? parsed_const_date : col_right_untyped ) ;
2017-04-01 07:20:54 +00:00
}
2018-09-06 08:56:46 +00:00
else if ( which . isDateTime ( ) )
2017-04-01 07:20:54 +00:00
{
time_t date_time ;
2017-07-21 06:35:58 +00:00
ReadBufferFromMemory in ( string_value . data , string_value . size ) ;
2017-04-01 07:20:54 +00:00
readDateTimeText ( date_time , in ) ;
if ( ! in . eof ( ) )
2018-11-22 21:19:58 +00:00
throw Exception ( " String is too long for DateTime: " + string_value . toString ( ) , ErrorCodes : : TOO_LARGE_STRING_SIZE ) ;
2017-04-01 07:20:54 +00:00
2018-04-24 07:16:39 +00:00
ColumnPtr parsed_const_date_time_holder = DataTypeDateTime ( ) . createColumnConst ( input_rows_count , UInt64 ( date_time ) ) ;
2019-08-21 02:28:04 +00:00
const ColumnConst * parsed_const_date_time = assert_cast < const ColumnConst * > ( parsed_const_date_time_holder . get ( ) ) ;
2017-04-01 07:20:54 +00:00
executeNumLeftType < DataTypeDateTime : : FieldType > ( block , result ,
2017-07-21 06:35:58 +00:00
left_is_num ? col_left_untyped : parsed_const_date_time ,
left_is_num ? parsed_const_date_time : col_right_untyped ) ;
2017-04-01 07:20:54 +00:00
}
2018-09-06 08:56:46 +00:00
else if ( which . isUUID ( ) )
2017-06-15 09:12:32 +00:00
{
2017-07-04 10:42:53 +00:00
UUID uuid ;
2017-07-21 06:35:58 +00:00
ReadBufferFromMemory in ( string_value . data , string_value . size ) ;
2017-06-15 09:12:32 +00:00
readText ( uuid , in ) ;
if ( ! in . eof ( ) )
2018-11-22 21:19:58 +00:00
throw Exception ( " String is too long for UUID: " + string_value . toString ( ) , ErrorCodes : : TOO_LARGE_STRING_SIZE ) ;
2017-06-15 09:12:32 +00:00
2018-10-22 08:54:54 +00:00
ColumnPtr parsed_const_uuid_holder = DataTypeUUID ( ) . createColumnConst ( input_rows_count , uuid ) ;
2019-08-21 02:28:04 +00:00
const ColumnConst * parsed_const_uuid = assert_cast < const ColumnConst * > ( parsed_const_uuid_holder . get ( ) ) ;
2017-07-04 10:42:53 +00:00
executeNumLeftType < DataTypeUUID : : FieldType > ( block , result ,
2017-07-21 06:35:58 +00:00
left_is_num ? col_left_untyped : parsed_const_uuid ,
left_is_num ? parsed_const_uuid : col_right_untyped ) ;
2017-06-15 09:12:32 +00:00
}
2018-09-06 08:56:46 +00:00
else if ( which . isEnum8 ( ) )
2017-04-01 07:20:54 +00:00
executeEnumWithConstString < DataTypeEnum8 > ( block , result , column_number , column_string ,
2018-04-24 07:16:39 +00:00
number_type , left_is_num , input_rows_count ) ;
2018-09-06 08:56:46 +00:00
else if ( which . isEnum16 ( ) )
2017-04-01 07:20:54 +00:00
executeEnumWithConstString < DataTypeEnum16 > ( block , result , column_number , column_string ,
2018-04-24 07:16:39 +00:00
number_type , left_is_num , input_rows_count ) ;
2018-07-16 05:04:57 +00:00
return true ;
2017-04-01 07:20:54 +00:00
}
/// Comparison between DataTypeEnum<T> and string constant containing the name of an enum element
template < typename EnumType >
void executeEnumWithConstString (
2017-07-21 06:35:58 +00:00
Block & block , const size_t result , const IColumn * column_number , const ColumnConst * column_string ,
2018-04-24 07:16:39 +00:00
const IDataType * type_untyped , const bool left_is_num , size_t input_rows_count )
2017-04-01 07:20:54 +00:00
{
const auto type = static_cast < const EnumType * > ( type_untyped ) ;
2019-09-27 13:44:33 +00:00
const Field x = castToNearestFieldType ( type - > getValue ( column_string - > getValue < String > ( ) ) ) ;
2018-04-24 07:16:39 +00:00
const auto enum_col = type - > createColumnConst ( input_rows_count , x ) ;
2017-04-01 07:20:54 +00:00
executeNumLeftType < typename EnumType : : FieldType > ( block , result ,
left_is_num ? column_number : enum_col . get ( ) ,
left_is_num ? enum_col . get ( ) : column_number ) ;
}
2018-04-24 07:16:39 +00:00
void executeTuple ( Block & block , size_t result , const ColumnWithTypeAndName & c0 , const ColumnWithTypeAndName & c1 ,
size_t input_rows_count )
2017-04-01 07:20:54 +00:00
{
2017-05-27 15:45:25 +00:00
/** We will lexicographically compare the tuples. This is done as follows:
2017-04-01 07:20:54 +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 :
2017-04-01 07:20:54 +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-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 )
throw Exception ( " Comparison of zero-sized tuples is not implemented. " , ErrorCodes : : NOT_IMPLEMENTED ) ;
ColumnsWithTypeAndName x ( tuple_size ) ;
ColumnsWithTypeAndName y ( tuple_size ) ;
auto x_const = checkAndGetColumnConst < ColumnTuple > ( c0 . column . get ( ) ) ;
auto y_const = checkAndGetColumnConst < ColumnTuple > ( c1 . column . get ( ) ) ;
Columns x_columns ;
Columns y_columns ;
2017-04-01 07:20:54 +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
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
2018-04-24 07:16:39 +00:00
executeTupleImpl ( block , result , x , y , tuple_size , input_rows_count ) ;
2017-04-01 07:20:54 +00:00
}
2018-04-24 07:16:39 +00:00
void executeTupleImpl ( Block & block , size_t result , const ColumnsWithTypeAndName & x ,
const ColumnsWithTypeAndName & y , size_t tuple_size ,
size_t input_rows_count ) ;
2017-04-01 07:20:54 +00:00
2020-02-23 22:46:52 +00:00
void executeTupleEqualityImpl (
std : : shared_ptr < IFunctionOverloadResolver > func_compare ,
std : : shared_ptr < IFunctionOverloadResolver > func_convolution ,
Block & block ,
size_t result ,
const ColumnsWithTypeAndName & x ,
const ColumnsWithTypeAndName & y ,
size_t tuple_size ,
size_t input_rows_count )
2017-04-01 07:20:54 +00:00
{
2019-12-10 11:19:11 +00:00
if ( 0 = = tuple_size )
throw Exception ( " Comparison of zero-sized tuples is not implemented. " , ErrorCodes : : NOT_IMPLEMENTED ) ;
2017-04-01 07:20:54 +00:00
Block tmp_block ;
for ( size_t i = 0 ; i < tuple_size ; + + i )
{
2017-12-09 12:23:09 +00:00
tmp_block . insert ( x [ i ] ) ;
tmp_block . insert ( y [ i ] ) ;
2017-04-01 07:20:54 +00:00
2020-02-23 22:46:52 +00:00
auto impl = func_compare - > build ( { x [ i ] , y [ i ] } ) ;
2019-12-09 14:41:55 +00:00
2017-05-27 15:45:25 +00:00
/// Comparison of the elements.
2017-04-01 07:20:54 +00:00
tmp_block . insert ( { nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } ) ;
2019-12-09 14:41:55 +00:00
impl - > execute ( tmp_block , { i * 3 , i * 3 + 1 } , i * 3 + 2 , input_rows_count ) ;
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.
block . getByPosition ( result ) . column = tmp_block . getByPosition ( 2 ) . column ;
return ;
}
2017-05-27 15:45:25 +00:00
/// Logical convolution.
2017-04-01 07:20:54 +00:00
tmp_block . insert ( { nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } ) ;
ColumnNumbers convolution_args ( tuple_size ) ;
for ( size_t i = 0 ; i < tuple_size ; + + i )
convolution_args [ i ] = i * 3 + 2 ;
2019-12-09 14:41:55 +00:00
ColumnsWithTypeAndName convolution_types ( convolution_args . size ( ) , { nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } ) ;
2020-02-23 22:46:52 +00:00
auto impl = func_convolution - > build ( convolution_types ) ;
2019-12-09 14:41:55 +00:00
impl - > execute ( tmp_block , convolution_args , tuple_size * 3 , input_rows_count ) ;
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . column = tmp_block . getByPosition ( tuple_size * 3 ) . column ;
2017-04-01 07:20:54 +00:00
}
2020-02-23 22:46:52 +00:00
void 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 ,
Block & block ,
size_t result ,
const ColumnsWithTypeAndName & x ,
const ColumnsWithTypeAndName & y ,
size_t tuple_size ,
size_t input_rows_count )
2017-04-01 07:20:54 +00:00
{
2019-12-09 14:41:55 +00:00
ColumnsWithTypeAndName bin_args = { { nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } ,
{ nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } } ;
2020-02-23 22:46:52 +00:00
auto func_and_adaptor = func_and - > build ( bin_args ) ;
auto func_or_adaptor = func_or - > build ( bin_args ) ;
2017-04-01 07:20:54 +00:00
Block tmp_block ;
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.
2017-04-01 07:20:54 +00:00
for ( size_t i = 0 ; i < tuple_size ; + + i )
{
2017-12-09 12:23:09 +00:00
tmp_block . insert ( x [ i ] ) ;
tmp_block . insert ( y [ i ] ) ;
2017-04-01 07:20:54 +00:00
tmp_block . insert ( { nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } ) ;
if ( i + 1 ! = tuple_size )
{
2020-02-23 22:46:52 +00:00
auto impl_head = func_compare_head - > build ( { x [ i ] , y [ i ] } ) ;
2019-12-09 14:41:55 +00:00
impl_head - > execute ( tmp_block , { i * 4 , i * 4 + 1 } , i * 4 + 2 , input_rows_count ) ;
2017-04-01 07:20:54 +00:00
tmp_block . insert ( { nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } ) ;
2019-12-09 14:41:55 +00:00
2020-02-23 22:46:52 +00:00
auto impl_equals = func_equals - > build ( { x [ i ] , y [ i ] } ) ;
2019-12-09 14:41:55 +00:00
impl_equals - > execute ( tmp_block , { i * 4 , i * 4 + 1 } , i * 4 + 3 , input_rows_count ) ;
2017-04-01 07:20:54 +00:00
}
else
2019-12-09 14:41:55 +00:00
{
2020-02-23 22:46:52 +00:00
auto impl_tail = func_compare_tail - > build ( { x [ i ] , y [ i ] } ) ;
2019-12-09 14:41:55 +00:00
impl_tail - > execute ( tmp_block , { i * 4 , i * 4 + 1 } , i * 4 + 2 , input_rows_count ) ;
}
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.
2017-04-01 07:20:54 +00:00
size_t i = tuple_size - 1 ;
while ( i > 0 )
{
tmp_block . insert ( { nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } ) ;
2019-12-09 14:41:55 +00:00
func_and_adaptor - > execute ( tmp_block , { tmp_block . columns ( ) - 2 , ( i - 1 ) * 4 + 3 } , tmp_block . columns ( ) - 1 , input_rows_count ) ;
2017-04-01 07:20:54 +00:00
tmp_block . insert ( { nullptr , std : : make_shared < DataTypeUInt8 > ( ) , " " } ) ;
2019-12-09 14:41:55 +00:00
func_or_adaptor - > execute ( tmp_block , { tmp_block . columns ( ) - 2 , ( i - 1 ) * 4 + 2 } , tmp_block . columns ( ) - 1 , input_rows_count ) ;
2017-04-01 07:20:54 +00:00
- - i ;
}
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . column = tmp_block . getByPosition ( tmp_block . columns ( ) - 1 ) . column ;
2017-04-01 07:20:54 +00:00
}
2018-07-16 05:04:57 +00:00
void executeGenericIdenticalTypes ( Block & block , size_t result , const IColumn * c0 , const IColumn * c1 )
2017-04-01 07:20:54 +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
2018-03-17 18:29:50 +00:00
if ( c0_const & & c1_const )
{
UInt8 res = 0 ;
GenericComparisonImpl < Op < int , int > > : : constant_constant ( * c0 , * c1 , res ) ;
block . getByPosition ( result ) . column = DataTypeUInt8 ( ) . createColumnConst ( c0 - > size ( ) , toField ( res ) ) ;
}
2017-04-01 07:20:54 +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 )
GenericComparisonImpl < Op < int , int > > : : constant_vector ( * c0 , * c1 , vec_res ) ;
else if ( c1_const )
GenericComparisonImpl < Op < int , int > > : : vector_constant ( * c0 , * c1 , vec_res ) ;
else
GenericComparisonImpl < Op < int , int > > : : vector_vector ( * c0 , * c1 , vec_res ) ;
2017-12-16 04:29:34 +00:00
2018-03-17 18:29:50 +00:00
block . getByPosition ( result ) . column = std : : move ( c_res ) ;
}
2017-04-01 07:20:54 +00:00
}
2015-10-12 01:42:47 +00:00
2018-07-16 05:04:57 +00:00
void executeGeneric ( Block & block , size_t result , const ColumnWithTypeAndName & c0 , const ColumnWithTypeAndName & c1 )
{
DataTypePtr common_type = getLeastSupertype ( { c0 . type , c1 . type } ) ;
ColumnPtr c0_converted = castColumn ( c0 , common_type , context ) ;
ColumnPtr c1_converted = castColumn ( c1 , common_type , context ) ;
executeGenericIdenticalTypes ( block , result , c0_converted . get ( ) , c1_converted . get ( ) ) ;
}
2011-08-15 21:50:08 +00:00
public :
2017-04-01 07:20:54 +00:00
String getName ( ) const override
{
return name ;
}
size_t getNumberOfArguments ( ) const override { return 2 ; }
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.
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override
{
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 ( ) ;
2018-11-28 11:37:07 +00:00
bool has_date = left . isDate ( ) | | right . isDate ( ) ;
2018-11-28 11:11:10 +00:00
if ( ! ( ( both_represented_by_number & & ! has_date ) /// Do not allow compare date and number.
2018-09-06 08:56:46 +00:00
| | ( left . isStringOrFixedString ( ) & & right . isStringOrFixedString ( ) )
| | ( left . isDate ( ) & & right . isDate ( ) )
| | ( left . isDate ( ) & & right . isString ( ) ) /// You can compare the date, datetime and an enumeration with a constant string.
| | ( left . isString ( ) & & right . isDate ( ) )
| | ( left . isDateTime ( ) & & right . isDateTime ( ) )
| | ( left . isDateTime ( ) & & right . isString ( ) )
| | ( left . isString ( ) & & right . isDateTime ( ) )
| | ( left . isUUID ( ) & & right . isUUID ( ) )
| | ( left . isUUID ( ) & & right . isString ( ) )
| | ( left . isString ( ) & & right . isUUID ( ) )
| | ( left . isEnum ( ) & & right . isEnum ( ) & & arguments [ 0 ] - > getName ( ) = = arguments [ 1 ] - > getName ( ) ) /// only equivalent enum type values can be compared against
| | ( left . isEnum ( ) & & right . isString ( ) )
| | ( left . isString ( ) & & right . isEnum ( ) )
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
{
try
{
getLeastSupertype ( arguments ) ;
}
catch ( const Exception & )
{
throw Exception ( " Illegal types of arguments ( " + arguments [ 0 ] - > getName ( ) + " , " + arguments [ 1 ] - > getName ( ) + " ) "
" of function " + getName ( ) , ErrorCodes : : ILLEGAL_TYPE_OF_ARGUMENT ) ;
}
}
2017-04-01 07:20:54 +00:00
if ( left_tuple & & right_tuple )
{
2020-02-23 22:46:52 +00:00
auto adaptor = FunctionOverloadResolverAdaptor ( std : : make_unique < DefaultOverloadResolver > ( FunctionComparison < Op , Name > : : create ( context ) ) ) ;
2019-12-09 14:41:55 +00:00
2017-04-01 07:20:54 +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 ] , " " } } ;
2019-12-09 14:41:55 +00:00
adaptor . build ( args ) ;
2018-02-06 19:34:53 +00:00
}
2017-04-01 07:20:54 +00:00
}
return std : : make_shared < DataTypeUInt8 > ( ) ;
}
2018-04-24 07:16:39 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result , size_t input_rows_count ) override
2017-04-01 07:20:54 +00:00
{
2017-07-21 06:35:58 +00:00
const auto & col_with_type_and_name_left = block . getByPosition ( arguments [ 0 ] ) ;
const auto & col_with_type_and_name_right = block . getByPosition ( arguments [ 1 ] ) ;
2017-04-01 07:20:54 +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.
2019-03-03 01:17:33 +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.)
2019-03-03 01:18:35 +00:00
/// NOTE: We consider NaN comparison to be implementation specific (and in our implementation NaNs are sometimes equal sometimes not).
2019-03-03 13:53:06 +00:00
if ( left_type - > equals ( * right_type ) & & ! left_type - > isNullable ( ) & & col_left_untyped = = col_right_untyped )
2019-03-02 23:51:21 +00:00
{
/// Always true: =, <=, >=
if constexpr ( std : : is_same_v < Op < int , int > , EqualsOp < int , int > >
| | std : : is_same_v < Op < int , int > , LessOrEqualsOp < int , int > >
| | std : : is_same_v < Op < int , int > , GreaterOrEqualsOp < int , int > > )
{
block . getByPosition ( result ) . column = DataTypeUInt8 ( ) . createColumnConst ( input_rows_count , 1u ) ;
return ;
}
else
{
block . getByPosition ( result ) . column = DataTypeUInt8 ( ) . createColumnConst ( input_rows_count , 0u ) ;
return ;
}
}
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
2017-04-01 07:20:54 +00:00
const bool left_is_num = col_left_untyped - > isNumeric ( ) ;
const bool right_is_num = col_right_untyped - > isNumeric ( ) ;
2019-02-02 14:23:44 +00:00
bool date_and_datetime = ( left_type ! = right_type ) & &
2019-02-02 17:57:36 +00:00
which_left . isDateOrDateTime ( ) & & which_right . isDateOrDateTime ( ) ;
2019-02-02 14:23:44 +00:00
if ( left_is_num & & right_is_num & & ! date_and_datetime )
2017-04-01 07:20:54 +00:00
{
2018-11-24 01:48:06 +00:00
if ( ! ( executeNumLeftType < UInt8 > ( block , result , col_left_untyped , col_right_untyped )
2017-06-01 13:41:58 +00:00
| | executeNumLeftType < UInt16 > ( block , result , col_left_untyped , col_right_untyped )
| | executeNumLeftType < UInt32 > ( block , result , col_left_untyped , col_right_untyped )
| | executeNumLeftType < UInt64 > ( block , result , col_left_untyped , col_right_untyped )
2017-06-30 20:21:42 +00:00
| | executeNumLeftType < UInt128 > ( block , result , col_left_untyped , col_right_untyped )
2017-06-01 13:41:58 +00:00
| | executeNumLeftType < Int8 > ( block , result , col_left_untyped , col_right_untyped )
| | executeNumLeftType < Int16 > ( block , result , col_left_untyped , col_right_untyped )
| | executeNumLeftType < Int32 > ( block , result , col_left_untyped , col_right_untyped )
| | executeNumLeftType < Int64 > ( block , result , col_left_untyped , col_right_untyped )
2018-07-25 19:38:21 +00:00
| | executeNumLeftType < Int128 > ( block , result , col_left_untyped , col_right_untyped )
2017-06-01 13:41:58 +00:00
| | executeNumLeftType < Float32 > ( block , result , col_left_untyped , col_right_untyped )
| | executeNumLeftType < Float64 > ( block , result , col_left_untyped , col_right_untyped ) ) )
2017-04-01 07:20:54 +00:00
throw Exception ( " Illegal column " + col_left_untyped - > getName ( )
+ " of first argument of function " + getName ( ) ,
ErrorCodes : : ILLEGAL_COLUMN ) ;
}
2018-07-25 19:38:21 +00:00
else if ( checkAndGetDataType < DataTypeTuple > ( left_type . get ( ) ) )
2018-07-16 05:04:57 +00:00
{
2018-04-24 07:16:39 +00:00
executeTuple ( block , result , col_with_type_and_name_left , col_with_type_and_name_right , input_rows_count ) ;
2018-07-16 05:04:57 +00:00
}
2019-10-07 15:19:18 +00:00
else if ( isColumnedAsDecimal ( left_type ) | | isColumnedAsDecimal ( right_type ) )
2018-07-25 19:38:21 +00:00
{
2019-10-07 15:19:18 +00:00
// compare
if ( ! allowDecimalComparison ( left_type , right_type ) & & ! date_and_datetime )
2018-07-25 19:38:21 +00:00
throw Exception ( " No operation " + getName ( ) + " between " + left_type - > getName ( ) + " and " + right_type - > getName ( ) ,
ErrorCodes : : ILLEGAL_TYPE_OF_ARGUMENT ) ;
executeDecimal ( block , result , col_with_type_and_name_left , col_with_type_and_name_right ) ;
}
2017-04-01 07:20:54 +00:00
else if ( ! left_is_num & & ! right_is_num & & executeString ( block , result , col_left_untyped , col_right_untyped ) )
2018-07-16 05:04:57 +00:00
{
}
2018-07-25 19:38:21 +00:00
else if ( left_type - > equals ( * right_type ) )
2018-07-16 05:04:57 +00:00
{
executeGenericIdenticalTypes ( block , result , col_left_untyped , col_right_untyped ) ;
}
else if ( executeDateOrDateTimeOrEnumOrUUIDWithConstString (
2017-04-01 07:20:54 +00:00
block , result , col_left_untyped , col_right_untyped ,
2018-07-25 19:38:21 +00:00
left_type , right_type ,
2018-07-16 05:04:57 +00:00
left_is_num , input_rows_count ) )
{
}
else
{
executeGeneric ( block , result , col_with_type_and_name_left , col_with_type_and_name_right ) ;
}
2017-06-01 13:41:58 +00:00
}
2018-05-10 14:02:25 +00:00
# if USE_EMBEDDED_COMPILER
bool isCompilableImpl ( const DataTypes & types ) const override
{
auto isBigInteger = & typeIsEither < DataTypeInt64 , DataTypeUInt64 , DataTypeUUID > ;
auto isFloatingPoint = & typeIsEither < DataTypeFloat32 , DataTypeFloat64 > ;
2019-02-03 22:08:17 +00:00
if ( ( isBigInteger ( * types [ 0 ] ) & & isFloatingPoint ( * types [ 1 ] ) )
| | ( isBigInteger ( * types [ 1 ] ) & & isFloatingPoint ( * types [ 0 ] ) )
2019-02-03 22:08:40 +00:00
| | ( WhichDataType ( types [ 0 ] ) . isDate ( ) & & WhichDataType ( types [ 1 ] ) . isDateTime ( ) )
| | ( WhichDataType ( types [ 1 ] ) . isDate ( ) & & WhichDataType ( types [ 0 ] ) . isDateTime ( ) ) )
2018-05-10 14:02:25 +00:00
return false ; /// TODO: implement (double, int_N where N > double's mantissa width)
2018-09-07 14:37:26 +00:00
return isCompilableType ( types [ 0 ] ) & & isCompilableType ( types [ 1 ] ) ;
2018-05-10 14:02:25 +00:00
}
llvm : : Value * compileImpl ( llvm : : IRBuilderBase & builder , const DataTypes & types , ValuePlaceholders values ) const override
{
auto & b = static_cast < llvm : : IRBuilder < > & > ( builder ) ;
auto * x = values [ 0 ] ( ) ;
auto * y = values [ 1 ] ( ) ;
if ( ! types [ 0 ] - > equals ( * types [ 1 ] ) )
{
llvm : : Type * common ;
if ( x - > getType ( ) - > isIntegerTy ( ) & & y - > getType ( ) - > isIntegerTy ( ) )
common = b . getIntNTy ( std : : max (
/// if one integer has a sign bit, make sure the other does as well. llvm generates optimal code
/// (e.g. uses overflow flag on x86) for (word size + 1)-bit integer operations.
x - > getType ( ) - > getIntegerBitWidth ( ) + ( ! typeIsSigned ( * types [ 0 ] ) & & typeIsSigned ( * types [ 1 ] ) ) ,
y - > getType ( ) - > getIntegerBitWidth ( ) + ( ! typeIsSigned ( * types [ 1 ] ) & & typeIsSigned ( * types [ 0 ] ) ) ) ) ;
else
/// (double, float) or (double, int_N where N <= double's mantissa width) -> double
common = b . getDoubleTy ( ) ;
x = nativeCast ( b , types [ 0 ] , x , common ) ;
y = nativeCast ( b , types [ 1 ] , y , common ) ;
}
2018-09-02 01:12:32 +00:00
auto * result = CompileOp < Op > : : compile ( b , x , y , typeIsSigned ( * types [ 0 ] ) | | typeIsSigned ( * types [ 1 ] ) ) ;
2018-05-10 14:02:25 +00:00
return b . CreateSelect ( result , b . getInt8 ( 1 ) , b . getInt8 ( 0 ) ) ;
}
# endif
2011-08-15 21:50:08 +00:00
} ;
}