2012-08-26 06:48:39 +00:00
# pragma once
2017-04-01 09:19:00 +00:00
# include <Core/FieldVisitors.h>
# include <DataTypes/DataTypeArray.h>
# include <DataTypes/DataTypesNumber.h>
# include <DataTypes/DataTypeDate.h>
# include <DataTypes/DataTypeDateTime.h>
# include <DataTypes/DataTypeString.h>
# include <DataTypes/DataTypeNullable.h>
# include <Columns/ColumnArray.h>
# include <Columns/ColumnString.h>
2017-07-21 06:35:58 +00:00
# include <Columns/ColumnConst.h>
2017-04-01 09:19:00 +00:00
# include <Columns/ColumnNullable.h>
# include <Functions/IFunction.h>
2017-06-13 04:45:30 +00:00
# include <DataTypes/DataTypeTraits.h>
2017-04-01 09:19:00 +00:00
# include <Functions/ObjectPool.h>
2017-07-21 06:35:58 +00:00
# include <Functions/FunctionHelpers.h>
2017-04-01 09:19:00 +00:00
# include <Common/StringUtils.h>
2012-08-26 06:48:39 +00:00
2017-06-06 17:18:32 +00:00
# include <ext/range.h>
2014-12-02 12:42:20 +00:00
2014-01-08 16:33:28 +00:00
# include <unordered_map>
2016-05-23 00:40:28 +00:00
# include <numeric>
2013-10-11 11:43:50 +00:00
2012-08-26 06:48:39 +00:00
namespace DB
{
2016-01-11 21:46:36 +00:00
namespace ErrorCodes
{
2017-04-01 07:20:54 +00:00
extern const int ZERO_ARRAY_OR_TUPLE_INDEX ;
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH ;
extern const int PARAMETERS_TO_AGGREGATE_FUNCTIONS_MUST_BE_LITERALS ;
2017-07-27 23:23:13 +00:00
extern const int LOGICAL_ERROR ;
2016-01-11 21:46:36 +00:00
}
2017-05-27 15:45:25 +00:00
/** Array functions:
2012-08-26 06:48:39 +00:00
*
2017-06-01 13:41:58 +00:00
* array ( c1 , c2 , . . . ) - create an array .
* arrayElement ( arr , i ) - get the array element by index . If index is not constant and out of range - return default value of data type .
2017-05-27 15:45:25 +00:00
* The index begins with 1. Also , the index can be negative - then it is counted from the end of the array .
* has ( arr , x ) - whether there is an element x in the array .
* indexOf ( arr , x ) - returns the index of the element x ( starting with 1 ) , if it exists in the array , or 0 if it is not .
* arrayEnumerate ( arr ) - Returns the array [ 1 , 2 , 3 , . . . , length ( arr ) ]
2015-07-23 11:11:10 +00:00
*
2017-05-27 15:45:25 +00:00
* arrayUniq ( arr ) - counts the number of different elements in the array ,
* arrayUniq ( arr1 , arr2 , . . . ) - counts the number of different tuples from the elements in the corresponding positions in several arrays .
2015-07-23 11:11:10 +00:00
*
* arrayEnumerateUniq ( arr )
2017-06-01 13:41:58 +00:00
* - outputs an array parallel ( having same size ) to this , where for each element specified
* how much times this element was encountered before ( including this element ) among elements with the same value .
2017-05-27 15:45:25 +00:00
* For example : arrayEnumerateUniq ( [ 10 , 20 , 10 , 30 ] ) = [ 1 , 1 , 2 , 1 ]
2015-07-23 11:11:10 +00:00
* arrayEnumerateUniq ( arr1 , arr2 . . . )
2017-05-27 15:45:25 +00:00
* - for tuples from elements in the corresponding positions in several arrays .
2015-07-26 10:40:32 +00:00
*
2017-05-27 15:45:25 +00:00
* emptyArrayToSingle ( arr ) - replace empty arrays with arrays of one element with a default value .
2015-12-13 10:43:49 +00:00
*
2017-05-27 15:45:25 +00:00
* arrayReduce ( ' agg ' , arr1 , . . . ) - apply the aggregate function ` agg ` to arrays ` arr1 . . . `
2017-06-01 13:41:58 +00:00
* If multiple arrays passed , then elements on corresponding positions are passed as multiple arguments to the aggregate function .
2012-08-26 06:48:39 +00:00
*/
2014-04-10 17:28:06 +00:00
2012-08-26 06:48:39 +00:00
class FunctionArray : public IFunction
{
2014-11-12 17:23:26 +00:00
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = " array " ;
static FunctionPtr create ( const Context & context ) ;
2016-07-09 06:33:44 +00:00
2017-04-01 07:20:54 +00:00
FunctionArray ( const Context & context ) ;
2014-11-12 17:23:26 +00:00
2017-07-24 01:00:31 +00:00
bool useDefaultImplementationForNulls ( ) const override { return false ; }
2016-09-11 07:40:47 +00:00
2017-04-01 07:20:54 +00:00
bool isVariadic ( ) const override { return true ; }
size_t getNumberOfArguments ( ) const override { return 0 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
2014-04-17 14:37:59 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
2014-04-17 14:37:59 +00:00
2016-08-11 16:47:28 +00:00
private :
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2014-04-17 14:37:59 +00:00
2017-04-01 07:20:54 +00:00
bool addField ( DataTypePtr type_res , const Field & f , Array & arr ) const ;
static const DataTypePtr & getScalarType ( const DataTypePtr & type ) ;
DataTypeTraits : : EnrichedDataTypePtr getLeastCommonType ( const DataTypes & arguments ) const ;
2014-04-17 14:37:59 +00:00
2016-08-11 16:47:28 +00:00
private :
2017-04-01 07:20:54 +00:00
const Context & context ;
2016-08-11 16:47:28 +00:00
} ;
2014-04-17 14:37:59 +00:00
2016-09-11 07:40:47 +00:00
namespace ArrayImpl
{
2017-04-01 07:20:54 +00:00
class NullMapBuilder ;
2016-09-11 07:40:47 +00:00
}
2015-02-01 08:19:11 +00:00
2016-08-11 16:47:28 +00:00
class FunctionArrayElement : public IFunction
{
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = " arrayElement " ;
static FunctionPtr create ( const Context & context ) ;
2015-02-01 08:19:11 +00:00
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2015-02-01 08:19:11 +00:00
2017-04-01 07:20:54 +00:00
size_t getNumberOfArguments ( ) const override { return 2 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
2015-02-01 08:19:11 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
2015-02-01 08:19:11 +00:00
2016-08-11 16:47:28 +00:00
private :
2017-04-01 07:20:54 +00:00
void perform ( Block & block , const ColumnNumbers & arguments , size_t result , ArrayImpl : : NullMapBuilder & builder ) ;
2016-09-11 07:40:47 +00:00
2017-04-01 07:20:54 +00:00
template < typename DataType >
bool executeNumberConst ( Block & block , const ColumnNumbers & arguments , size_t result , const Field & index ,
ArrayImpl : : NullMapBuilder & builder ) ;
2015-02-01 08:19:11 +00:00
2017-04-01 07:20:54 +00:00
template < typename IndexType , typename DataType >
bool executeNumber ( Block & block , const ColumnNumbers & arguments , size_t result , const PaddedPODArray < IndexType > & indices ,
ArrayImpl : : NullMapBuilder & builder ) ;
2015-02-01 08:19:11 +00:00
2017-04-01 07:20:54 +00:00
bool executeStringConst ( Block & block , const ColumnNumbers & arguments , size_t result , const Field & index ,
ArrayImpl : : NullMapBuilder & builder ) ;
2015-02-01 08:19:11 +00:00
2017-04-01 07:20:54 +00:00
template < typename IndexType >
bool executeString ( Block & block , const ColumnNumbers & arguments , size_t result , const PaddedPODArray < IndexType > & indices ,
ArrayImpl : : NullMapBuilder & builder ) ;
2015-02-01 08:19:11 +00:00
2017-04-01 07:20:54 +00:00
bool executeGenericConst ( Block & block , const ColumnNumbers & arguments , size_t result , const Field & index ,
ArrayImpl : : NullMapBuilder & builder ) ;
2012-11-02 19:10:43 +00:00
2017-04-01 07:20:54 +00:00
template < typename IndexType >
bool executeGeneric ( Block & block , const ColumnNumbers & arguments , size_t result , const PaddedPODArray < IndexType > & indices ,
ArrayImpl : : NullMapBuilder & builder ) ;
2012-11-02 19:10:43 +00:00
2017-04-01 07:20:54 +00:00
bool executeConstConst ( Block & block , const ColumnNumbers & arguments , size_t result , const Field & index ,
ArrayImpl : : NullMapBuilder & builder ) ;
2012-11-02 19:10:43 +00:00
2017-04-01 07:20:54 +00:00
template < typename IndexType >
bool executeConst ( Block & block , const ColumnNumbers & arguments , size_t result , const PaddedPODArray < IndexType > & indices ,
ArrayImpl : : NullMapBuilder & builder ) ;
2012-11-02 19:10:43 +00:00
2017-04-01 07:20:54 +00:00
template < typename IndexType >
bool executeArgument ( Block & block , const ColumnNumbers & arguments , size_t result , ArrayImpl : : NullMapBuilder & builder ) ;
2012-11-02 19:10:43 +00:00
2017-05-27 15:45:25 +00:00
/** For a tuple array, the function is evaluated component-wise for each element of the tuple.
2017-04-01 07:20:54 +00:00
*/
bool executeTuple ( Block & block , const ColumnNumbers & arguments , size_t result ) ;
2012-11-02 19:10:43 +00:00
} ;
2016-07-09 04:39:57 +00:00
/// For has.
2012-12-15 20:01:46 +00:00
struct IndexToOne
{
2017-04-01 07:20:54 +00:00
using ResultType = UInt8 ;
static bool apply ( size_t j , ResultType & current ) { current = 1 ; return false ; }
2012-12-15 20:01:46 +00:00
} ;
2016-07-09 04:39:57 +00:00
/// For indexOf.
2012-12-15 20:01:46 +00:00
struct IndexIdentity
{
2017-04-01 07:20:54 +00:00
using ResultType = UInt64 ;
2017-05-27 15:45:25 +00:00
/// The index is returned starting from 1.
2017-04-01 07:20:54 +00:00
static bool apply ( size_t j , ResultType & current ) { current = j + 1 ; return false ; }
2012-12-26 15:40:37 +00:00
} ;
2016-07-09 04:39:57 +00:00
/// For countEqual.
2012-12-26 15:40:37 +00:00
struct IndexCount
{
2017-04-01 07:20:54 +00:00
using ResultType = UInt32 ;
static bool apply ( size_t j , ResultType & current ) { + + current ; return true ; }
2012-12-15 20:01:46 +00:00
} ;
2015-10-12 07:05:54 +00:00
template < typename T , typename U , typename IndexConv >
2012-12-15 20:01:46 +00:00
struct ArrayIndexNumImpl
{
2016-09-20 15:59:47 +00:00
private :
2015-10-12 07:05:54 +00:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-compare"
2017-04-01 07:20:54 +00:00
/// compares `lhs` against `i`-th element of `rhs`
2017-07-21 06:35:58 +00:00
static bool compare ( const T & lhs , const PaddedPODArray < U > & rhs , const size_t i ) { return lhs = = rhs [ i ] ; }
2017-04-01 07:20:54 +00:00
/// compares `lhs against `rhs`, third argument unused
2017-07-21 06:35:58 +00:00
static bool compare ( const T & lhs , const U & rhs , size_t ) { return lhs = = rhs ; }
2015-10-12 07:05:54 +00:00
# pragma GCC diagnostic pop
2015-09-18 12:40:42 +00:00
2017-04-01 07:20:54 +00:00
static bool hasNull ( const PaddedPODArray < U > & value , const PaddedPODArray < UInt8 > & null_map , size_t i )
{
return null_map [ i ] = = 1 ;
}
static bool hasNull ( const U & value , const PaddedPODArray < UInt8 > & null_map , size_t i )
{
2017-06-01 13:41:58 +00:00
throw Exception { " Logical error: constant column cannot have null map. " , ErrorCodes : : LOGICAL_ERROR } ;
2017-04-01 07:20:54 +00:00
}
/// Both function arguments are ordinary.
template < typename ScalarOrVector >
static void vectorCase1 (
const PaddedPODArray < T > & data , const ColumnArray : : Offsets_t & offsets ,
const ScalarOrVector & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
if ( compare ( data [ current_offset + j ] , value , i ) )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
/// The 2nd function argument is nullable.
template < typename ScalarOrVector >
static void vectorCase2 (
const PaddedPODArray < T > & data , const ColumnArray : : Offsets_t & offsets ,
const ScalarOrVector & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > & null_map_item )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
if ( ! hasNull ( value , null_map_item , i ) & & compare ( data [ current_offset + j ] , value , i ) )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
/// The 1st function argument is a non-constant array of nullable values.
template < typename ScalarOrVector >
static void vectorCase3 (
const PaddedPODArray < T > & data , const ColumnArray : : Offsets_t & offsets ,
const ScalarOrVector & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > & null_map_data )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
if ( null_map_data [ current_offset + j ] = = 1 )
{
}
else if ( compare ( data [ current_offset + j ] , value , i ) )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
/// The 1st function argument is a non-constant array of nullable values.
/// The 2nd function argument is nullable.
template < typename ScalarOrVector >
static void vectorCase4 (
const PaddedPODArray < T > & data , const ColumnArray : : Offsets_t & offsets ,
const ScalarOrVector & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > & null_map_data ,
const PaddedPODArray < UInt8 > & null_map_item )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
bool hit = false ;
if ( null_map_data [ current_offset + j ] = = 1 )
{
if ( hasNull ( value , null_map_item , i ) )
hit = true ;
}
else if ( compare ( data [ current_offset + j ] , value , i ) )
hit = true ;
if ( hit )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
2016-09-12 14:16:21 +00:00
2016-09-20 15:59:47 +00:00
public :
2017-04-01 07:20:54 +00:00
template < typename ScalarOrVector >
static void vector (
const PaddedPODArray < T > & data , const ColumnArray : : Offsets_t & offsets ,
const ScalarOrVector & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > * null_map_data ,
const PaddedPODArray < UInt8 > * null_map_item )
{
/// Processing is split into 4 cases.
2017-07-21 06:35:58 +00:00
if ( ! null_map_data & & ! null_map_item )
2017-04-01 07:20:54 +00:00
vectorCase1 ( data , offsets , value , result ) ;
2017-07-21 06:35:58 +00:00
else if ( ! null_map_data & & null_map_item )
2017-04-01 07:20:54 +00:00
vectorCase2 ( data , offsets , value , result , * null_map_item ) ;
2017-07-21 06:35:58 +00:00
else if ( null_map_data & & ! null_map_item )
2017-04-01 07:20:54 +00:00
vectorCase3 ( data , offsets , value , result , * null_map_data ) ;
else
vectorCase4 ( data , offsets , value , result , * null_map_data , * null_map_item ) ;
}
2016-09-12 14:16:21 +00:00
} ;
2016-09-15 21:27:34 +00:00
/// Specialization that catches internal errors.
2016-09-12 14:16:21 +00:00
template < typename T , typename IndexConv >
struct ArrayIndexNumImpl < T , Null , IndexConv >
{
2017-04-01 07:20:54 +00:00
template < typename ScalarOrVector >
static void vector (
const PaddedPODArray < T > & data , const ColumnArray : : Offsets_t & offsets ,
const ScalarOrVector & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > * null_map_data ,
const PaddedPODArray < UInt8 > * null_map_item )
{
throw Exception { " Internal error " , ErrorCodes : : LOGICAL_ERROR } ;
}
2016-09-12 14:16:21 +00:00
} ;
2016-09-15 12:14:25 +00:00
/// Implementation for arrays of numbers when the 2nd function argument
/// is a NULL value.
2016-09-12 14:16:21 +00:00
template < typename T , typename IndexConv >
struct ArrayIndexNumNullImpl
{
2017-04-01 07:20:54 +00:00
static void vector (
const PaddedPODArray < T > & data , const ColumnArray : : Offsets_t & offsets ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > * null_map_data )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
2017-07-21 06:35:58 +00:00
if ( ! null_map_data )
2017-04-01 07:20:54 +00:00
return ;
const auto & null_map_ref = * null_map_data ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
if ( null_map_ref [ current_offset + j ] = = 1 )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
2012-12-15 20:01:46 +00:00
} ;
2016-09-15 12:14:25 +00:00
/// Implementation for arrays of strings when the 2nd function argument
/// is a NULL value.
template < typename IndexConv >
struct ArrayIndexStringNullImpl
{
2017-04-01 07:20:54 +00:00
static void vector_const (
const ColumnString : : Chars_t & data , const ColumnArray : : Offsets_t & offsets , const ColumnString : : Offsets_t & string_offsets ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > * null_map_data )
{
const auto size = offsets . size ( ) ;
result . resize ( size ) ;
2017-07-21 06:35:58 +00:00
if ( ! null_map_data )
2017-04-01 07:20:54 +00:00
return ;
const auto & null_map_ref = * null_map_data ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
const auto array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
size_t k = ( current_offset = = 0 & & j = = 0 ) ? 0 : current_offset + j - 1 ;
if ( null_map_ref [ k ] = = 1 )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
2016-09-15 12:14:25 +00:00
} ;
2012-12-15 20:01:46 +00:00
template < typename IndexConv >
struct ArrayIndexStringImpl
{
2017-04-01 07:20:54 +00:00
static void vector_const (
const ColumnString : : Chars_t & data , const ColumnArray : : Offsets_t & offsets , const ColumnString : : Offsets_t & string_offsets ,
const String & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > * null_map_data )
{
const auto size = offsets . size ( ) ;
const auto value_size = value . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
const auto array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
ColumnArray : : Offset_t string_pos = current_offset = = 0 & & j = = 0
? 0
: string_offsets [ current_offset + j - 1 ] ;
ColumnArray : : Offset_t string_size = string_offsets [ current_offset + j ] - string_pos ;
size_t k = ( current_offset = = 0 & & j = = 0 ) ? 0 : current_offset + j - 1 ;
if ( null_map_data & & ( ( * null_map_data ) [ k ] = = 1 ) )
{
}
else if ( string_size = = value_size + 1 & & 0 = = memcmp ( value . data ( ) , & data [ string_pos ] , value_size ) )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
static void vector_vector (
const ColumnString : : Chars_t & data , const ColumnArray : : Offsets_t & offsets , const ColumnString : : Offsets_t & string_offsets ,
const ColumnString : : Chars_t & item_values , const ColumnString : : Offsets_t & item_offsets ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > * null_map_data ,
const PaddedPODArray < UInt8 > * null_map_item )
{
const auto size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
const auto array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
const auto value_pos = 0 = = i ? 0 : item_offsets [ i - 1 ] ;
const auto value_size = item_offsets [ i ] - value_pos ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
ColumnArray : : Offset_t string_pos = current_offset = = 0 & & j = = 0
? 0
: string_offsets [ current_offset + j - 1 ] ;
ColumnArray : : Offset_t string_size = string_offsets [ current_offset + j ] - string_pos ;
bool hit = false ;
size_t k = ( current_offset = = 0 & & j = = 0 ) ? 0 : current_offset + j - 1 ;
if ( null_map_data & & ( ( * null_map_data ) [ k ] = = 1 ) )
{
if ( null_map_item & & ( ( * null_map_item ) [ i ] = = 1 ) )
hit = true ;
}
else if ( string_size = = value_size & & 0 = = memcmp ( & item_values [ value_pos ] , & data [ string_pos ] , value_size ) )
hit = true ;
if ( hit )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
2012-12-15 20:01:46 +00:00
} ;
2016-09-20 15:59:47 +00:00
/// Catch-all implementation for arrays of arbitary type.
/// To compare with constant value, create non-constant column with single element,
/// and pass is_value_has_single_element_to_compare = true.
2016-07-09 04:39:57 +00:00
template < typename IndexConv , bool is_value_has_single_element_to_compare >
struct ArrayIndexGenericImpl
{
2016-09-20 15:59:47 +00:00
private :
2017-04-01 07:20:54 +00:00
/// Both function arguments are ordinary.
static void vectorCase1 (
const IColumn & data , const ColumnArray : : Offsets_t & offsets ,
const IColumn & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
if ( 0 = = data . compareAt ( current_offset + j , is_value_has_single_element_to_compare ? 0 : i , value , 1 ) )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
/// The 2nd function argument is nullable.
static void vectorCase2 (
const IColumn & data , const ColumnArray : : Offsets_t & offsets ,
const IColumn & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > & null_map_item )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
if ( ( null_map_item [ i ] = = 0 ) & &
( 0 = = data . compareAt ( current_offset + j , is_value_has_single_element_to_compare ? 0 : i , value , 1 ) ) )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
/// The 1st function argument is a non-constant array of nullable values.
static void vectorCase3 (
const IColumn & data , const ColumnArray : : Offsets_t & offsets ,
const IColumn & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > & null_map_data )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
if ( null_map_data [ current_offset + j ] = = 1 )
{
}
else if ( 0 = = data . compareAt ( current_offset + j , is_value_has_single_element_to_compare ? 0 : i , value , 1 ) )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
/// The 1st function argument is a non-constant array of nullable values.
/// The 2nd function argument is nullable.
static void vectorCase4 (
const IColumn & data , const ColumnArray : : Offsets_t & offsets ,
const IColumn & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > & null_map_data ,
const PaddedPODArray < UInt8 > & null_map_item )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
bool hit = false ;
if ( null_map_data [ current_offset + j ] = = 1 )
{
if ( null_map_item [ i ] = = 1 )
hit = true ;
}
else if ( 0 = = data . compareAt ( current_offset + j , is_value_has_single_element_to_compare ? 0 : i , value , 1 ) )
hit = true ;
if ( hit )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
}
}
2016-09-20 15:59:47 +00:00
public :
2017-04-01 07:20:54 +00:00
static void vector (
const IColumn & data , const ColumnArray : : Offsets_t & offsets ,
const IColumn & value ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > * null_map_data ,
const PaddedPODArray < UInt8 > * null_map_item )
{
/// Processing is split into 4 cases.
2017-07-21 06:35:58 +00:00
if ( ! null_map_data & & ! null_map_item )
2017-04-01 07:20:54 +00:00
vectorCase1 ( data , offsets , value , result ) ;
2017-07-21 06:35:58 +00:00
else if ( ! null_map_data & & null_map_item )
2017-04-01 07:20:54 +00:00
vectorCase2 ( data , offsets , value , result , * null_map_item ) ;
2017-07-21 06:35:58 +00:00
else if ( null_map_data & & ! null_map_item )
2017-04-01 07:20:54 +00:00
vectorCase3 ( data , offsets , value , result , * null_map_data ) ;
else
vectorCase4 ( data , offsets , value , result , * null_map_data , * null_map_item ) ;
}
2016-07-09 04:39:57 +00:00
} ;
2016-09-20 15:59:47 +00:00
/// Catch-all implementation for arrays of arbitary type
/// when the 2nd function argument is a NULL value.
template < typename IndexConv >
struct ArrayIndexGenericNullImpl
{
2017-04-01 07:20:54 +00:00
static void vector (
const IColumn & data , const ColumnArray : : Offsets_t & offsets ,
PaddedPODArray < typename IndexConv : : ResultType > & result ,
const PaddedPODArray < UInt8 > * null_map_data )
{
size_t size = offsets . size ( ) ;
result . resize ( size ) ;
2017-07-21 06:35:58 +00:00
if ( ! null_map_data )
2017-04-01 07:20:54 +00:00
return ;
const auto & null_map_ref = * null_map_data ;
ColumnArray : : Offset_t current_offset = 0 ;
for ( size_t i = 0 ; i < size ; + + i )
{
size_t array_size = offsets [ i ] - current_offset ;
typename IndexConv : : ResultType current = 0 ;
for ( size_t j = 0 ; j < array_size ; + + j )
{
if ( null_map_ref [ current_offset + j ] = = 1 )
{
if ( ! IndexConv : : apply ( j , current ) )
break ;
}
}
result [ i ] = current ;
current_offset = offsets [ i ] ;
}
}
2016-09-20 15:59:47 +00:00
} ;
2012-12-15 20:01:46 +00:00
template < typename IndexConv , typename Name >
class FunctionArrayIndex : public IFunction
2012-11-02 19:10:43 +00:00
{
2014-11-12 17:23:26 +00:00
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = Name : : name ;
static FunctionPtr create ( const Context & context ) { return std : : make_shared < FunctionArrayIndex > ( ) ; }
2014-11-12 17:23:26 +00:00
2012-11-02 19:10:43 +00:00
private :
2017-04-01 07:20:54 +00:00
using ResultColumnType = ColumnVector < typename IndexConv : : ResultType > ;
template < typename T >
bool executeNumber ( Block & block , const ColumnNumbers & arguments , size_t result )
{
2017-07-24 04:14:35 +00:00
return executeNumberNumber < T , UInt8 > ( block , arguments , result )
| | executeNumberNumber < T , UInt16 > ( block , arguments , result )
| | executeNumberNumber < T , UInt32 > ( block , arguments , result )
| | executeNumberNumber < T , UInt64 > ( block , arguments , result )
| | executeNumberNumber < T , Int8 > ( block , arguments , result )
| | executeNumberNumber < T , Int16 > ( block , arguments , result )
| | executeNumberNumber < T , Int32 > ( block , arguments , result )
| | executeNumberNumber < T , Int64 > ( block , arguments , result )
| | executeNumberNumber < T , Float32 > ( block , arguments , result )
| | executeNumberNumber < T , Float64 > ( block , arguments , result )
2017-04-01 07:20:54 +00:00
| | executeNumberNumber < T , Null > ( block , arguments , result ) ;
}
template < typename T , typename U >
bool executeNumberNumber ( Block & block , const ColumnNumbers & arguments , size_t result )
{
2017-07-21 06:35:58 +00:00
const ColumnArray * col_array = checkAndGetColumn < ColumnArray > ( block . getByPosition ( arguments [ 0 ] ) . column . get ( ) ) ;
2017-04-01 07:20:54 +00:00
if ( ! col_array )
return false ;
2017-07-21 06:35:58 +00:00
const ColumnVector < T > * col_nested = checkAndGetColumn < ColumnVector < T > > ( & col_array - > getData ( ) ) ;
2017-04-01 07:20:54 +00:00
if ( ! col_nested )
return false ;
const auto col_res = std : : make_shared < ResultColumnType > ( ) ;
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . column = col_res ;
2017-04-01 07:20:54 +00:00
/// Null maps of the 1st and second function arguments,
/// if it applies.
const PaddedPODArray < UInt8 > * null_map_data = nullptr ;
const PaddedPODArray < UInt8 > * null_map_item = nullptr ;
if ( arguments . size ( ) > 2 )
{
2017-07-21 06:35:58 +00:00
const auto & null_map1 = block . getByPosition ( arguments [ 2 ] ) . column ;
2017-04-01 07:20:54 +00:00
if ( null_map1 )
null_map_data = & static_cast < const ColumnUInt8 & > ( * null_map1 ) . getData ( ) ;
2017-07-21 06:35:58 +00:00
const auto & null_map2 = block . getByPosition ( arguments [ 3 ] ) . column ;
2017-04-01 07:20:54 +00:00
if ( null_map2 )
null_map_item = & static_cast < const ColumnUInt8 & > ( * null_map2 ) . getData ( ) ;
}
2017-07-21 06:35:58 +00:00
const auto item_arg = block . getByPosition ( arguments [ 1 ] ) . column . get ( ) ;
2017-04-01 07:20:54 +00:00
if ( item_arg - > isNull ( ) )
ArrayIndexNumNullImpl < T , IndexConv > : : vector ( col_nested - > getData ( ) , col_array - > getOffsets ( ) ,
col_res - > getData ( ) , null_map_data ) ;
2017-07-21 06:35:58 +00:00
else if ( const auto item_arg_const = checkAndGetColumnConst < ColumnVector < U > > ( item_arg ) )
2017-04-01 07:20:54 +00:00
ArrayIndexNumImpl < T , U , IndexConv > : : vector ( col_nested - > getData ( ) , col_array - > getOffsets ( ) ,
2017-07-21 06:35:58 +00:00
item_arg_const - > template getValue < U > ( ) , col_res - > getData ( ) , null_map_data , nullptr ) ;
else if ( const auto item_arg_vector = checkAndGetColumn < ColumnVector < U > > ( item_arg ) )
2017-04-01 07:20:54 +00:00
ArrayIndexNumImpl < T , U , IndexConv > : : vector ( col_nested - > getData ( ) , col_array - > getOffsets ( ) ,
item_arg_vector - > getData ( ) , col_res - > getData ( ) , null_map_data , null_map_item ) ;
else
return false ;
return true ;
}
bool executeString ( Block & block , const ColumnNumbers & arguments , size_t result )
{
2017-07-21 06:35:58 +00:00
const ColumnArray * col_array = checkAndGetColumn < ColumnArray > ( block . getByPosition ( arguments [ 0 ] ) . column . get ( ) ) ;
2017-04-01 07:20:54 +00:00
if ( ! col_array )
return false ;
2017-07-21 06:35:58 +00:00
const ColumnString * col_nested = checkAndGetColumn < ColumnString > ( & col_array - > getData ( ) ) ;
2017-04-01 07:20:54 +00:00
if ( ! col_nested )
return false ;
const auto col_res = std : : make_shared < ResultColumnType > ( ) ;
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . column = col_res ;
2017-04-01 07:20:54 +00:00
/// Null maps of the 1st and second function arguments,
/// if it applies.
const PaddedPODArray < UInt8 > * null_map_data = nullptr ;
const PaddedPODArray < UInt8 > * null_map_item = nullptr ;
if ( arguments . size ( ) > 2 )
{
2017-07-21 06:35:58 +00:00
const auto & col1 = block . getByPosition ( arguments [ 2 ] ) . column ;
2017-04-01 07:20:54 +00:00
if ( col1 )
null_map_data = & static_cast < const ColumnUInt8 & > ( * col1 ) . getData ( ) ;
2017-07-21 06:35:58 +00:00
const auto & col2 = block . getByPosition ( arguments [ 3 ] ) . column ;
2017-04-01 07:20:54 +00:00
if ( col2 )
null_map_item = & static_cast < const ColumnUInt8 & > ( * col2 ) . getData ( ) ;
}
2017-07-21 06:35:58 +00:00
const auto item_arg = block . getByPosition ( arguments [ 1 ] ) . column . get ( ) ;
2017-04-01 07:20:54 +00:00
if ( item_arg - > isNull ( ) )
ArrayIndexStringNullImpl < IndexConv > : : vector_const ( col_nested - > getChars ( ) , col_array - > getOffsets ( ) ,
col_nested - > getOffsets ( ) , col_res - > getData ( ) , null_map_data ) ;
2017-07-21 06:35:58 +00:00
else if ( const auto item_arg_const = checkAndGetColumnConstStringOrFixedString ( item_arg ) )
2017-04-01 07:20:54 +00:00
ArrayIndexStringImpl < IndexConv > : : vector_const ( col_nested - > getChars ( ) , col_array - > getOffsets ( ) ,
2017-07-21 06:35:58 +00:00
col_nested - > getOffsets ( ) , item_arg_const - > getValue < String > ( ) , col_res - > getData ( ) ,
2017-04-01 07:20:54 +00:00
null_map_data ) ;
2017-07-21 06:35:58 +00:00
else if ( const auto item_arg_vector = checkAndGetColumn < ColumnString > ( item_arg ) )
2017-04-01 07:20:54 +00:00
ArrayIndexStringImpl < IndexConv > : : vector_vector ( col_nested - > getChars ( ) , col_array - > getOffsets ( ) ,
col_nested - > getOffsets ( ) , item_arg_vector - > getChars ( ) , item_arg_vector - > getOffsets ( ) ,
col_res - > getData ( ) , null_map_data , null_map_item ) ;
else
return false ;
return true ;
}
bool executeConst ( Block & block , const ColumnNumbers & arguments , size_t result )
{
2017-07-21 06:35:58 +00:00
const ColumnConst * col_array = checkAndGetColumnConst < ColumnArray > ( block . getByPosition ( arguments [ 0 ] ) . column . get ( ) ) ;
2017-04-01 07:20:54 +00:00
if ( ! col_array )
return false ;
2017-07-21 06:35:58 +00:00
Array arr = col_array - > getValue < Array > ( ) ;
2017-04-01 07:20:54 +00:00
2017-07-21 06:35:58 +00:00
const auto item_arg = block . getByPosition ( arguments [ 1 ] ) . column . get ( ) ;
2017-04-01 07:20:54 +00:00
if ( item_arg - > isConst ( ) )
{
typename IndexConv : : ResultType current = 0 ;
const auto & value = ( * item_arg ) [ 0 ] ;
for ( size_t i = 0 , size = arr . size ( ) ; i < size ; + + i )
{
if ( applyVisitor ( FieldVisitorAccurateEquals ( ) , arr [ i ] , value ) )
{
if ( ! IndexConv : : apply ( i , current ) )
break ;
}
}
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . column = block . getByPosition ( result ) . type - > createConstColumn (
2017-04-01 07:20:54 +00:00
item_arg - > size ( ) ,
static_cast < typename NearestFieldType < typename IndexConv : : ResultType > : : Type > ( current ) ) ;
}
else
{
/// Null map of the 2nd function argument, if it applies.
const PaddedPODArray < UInt8 > * null_map = nullptr ;
if ( arguments . size ( ) > 2 )
{
2017-07-21 06:35:58 +00:00
const auto & col = block . getByPosition ( arguments [ 3 ] ) . column ;
2017-04-01 07:20:54 +00:00
if ( col )
null_map = & static_cast < const ColumnUInt8 & > ( * col ) . getData ( ) ;
}
const auto size = item_arg - > size ( ) ;
const auto col_res = std : : make_shared < ResultColumnType > ( size ) ;
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . column = col_res ;
2017-04-01 07:20:54 +00:00
auto & data = col_res - > getData ( ) ;
for ( size_t row = 0 ; row < size ; + + row )
{
const auto & value = ( * item_arg ) [ row ] ;
data [ row ] = 0 ;
for ( size_t i = 0 , size = arr . size ( ) ; i < size ; + + i )
{
bool hit = false ;
if ( arr [ i ] . isNull ( ) )
{
if ( null_map & & ( ( * null_map ) [ row ] = = 1 ) )
hit = true ;
}
else if ( applyVisitor ( FieldVisitorAccurateEquals ( ) , arr [ i ] , value ) )
hit = true ;
if ( hit )
{
if ( ! IndexConv : : apply ( i , data [ row ] ) )
break ;
}
}
}
}
return true ;
}
bool executeGeneric ( Block & block , const ColumnNumbers & arguments , size_t result )
{
2017-07-21 06:35:58 +00:00
const ColumnArray * col_array = checkAndGetColumn < ColumnArray > ( block . getByPosition ( arguments [ 0 ] ) . column . get ( ) ) ;
2017-04-01 07:20:54 +00:00
if ( ! col_array )
return false ;
const IColumn & col_nested = col_array - > getData ( ) ;
2017-07-21 06:35:58 +00:00
const IColumn & item_arg = * block . getByPosition ( arguments [ 1 ] ) . column ;
2017-04-01 07:20:54 +00:00
const auto col_res = std : : make_shared < ResultColumnType > ( ) ;
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . column = col_res ;
2017-04-01 07:20:54 +00:00
/// Null maps of the 1st and second function arguments,
/// if it applies.
const PaddedPODArray < UInt8 > * null_map_data = nullptr ;
const PaddedPODArray < UInt8 > * null_map_item = nullptr ;
if ( arguments . size ( ) > 2 )
{
2017-07-21 06:35:58 +00:00
const auto & null_map1 = block . getByPosition ( arguments [ 2 ] ) . column ;
2017-04-01 07:20:54 +00:00
if ( null_map1 )
null_map_data = & static_cast < const ColumnUInt8 & > ( * null_map1 ) . getData ( ) ;
2017-07-21 06:35:58 +00:00
const auto & null_map2 = block . getByPosition ( arguments [ 3 ] ) . column ;
2017-04-01 07:20:54 +00:00
if ( null_map2 )
null_map_item = & static_cast < const ColumnUInt8 & > ( * null_map2 ) . getData ( ) ;
}
if ( item_arg . isNull ( ) )
ArrayIndexGenericNullImpl < IndexConv > : : vector ( col_nested , col_array - > getOffsets ( ) ,
col_res - > getData ( ) , null_map_data ) ;
else if ( item_arg . isConst ( ) )
ArrayIndexGenericImpl < IndexConv , true > : : vector ( col_nested , col_array - > getOffsets ( ) ,
2017-07-21 06:35:58 +00:00
static_cast < const ColumnConst & > ( item_arg ) . getDataColumn ( ) , col_res - > getData ( ) , /// TODO This is wrong.
2017-04-01 07:20:54 +00:00
null_map_data , nullptr ) ;
else
{
/// If item_arg is tuple and have constants.
if ( auto materialized_tuple = item_arg . convertToFullColumnIfConst ( ) )
ArrayIndexGenericImpl < IndexConv , false > : : vector (
col_nested , col_array - > getOffsets ( ) , * materialized_tuple , col_res - > getData ( ) ,
null_map_data , null_map_item ) ;
else
ArrayIndexGenericImpl < IndexConv , false > : : vector (
col_nested , col_array - > getOffsets ( ) , item_arg , col_res - > getData ( ) ,
null_map_data , null_map_item ) ;
}
return true ;
}
2016-07-09 04:39:57 +00:00
2012-11-02 19:10:43 +00:00
public :
2017-04-01 07:20:54 +00:00
/// Get function name.
String getName ( ) const override
{
return name ;
}
2017-07-24 01:00:31 +00:00
bool useDefaultImplementationForNulls ( ) const override { return false ; }
2017-04-01 07:20:54 +00:00
size_t getNumberOfArguments ( ) const override { return 2 ; }
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override
{
2017-07-21 06:35:58 +00:00
const DataTypeArray * array_type = checkAndGetDataType < DataTypeArray > ( arguments [ 0 ] . get ( ) ) ;
2017-04-01 07:20:54 +00:00
if ( ! array_type )
throw Exception ( " First argument for function " + getName ( ) + " must be an array. " ,
ErrorCodes : : ILLEGAL_TYPE_OF_ARGUMENT ) ;
if ( ! arguments [ 1 ] - > isNull ( ) )
{
const IDataType * observed_type0 = DataTypeTraits : : removeNullable ( array_type - > getNestedType ( ) ) . get ( ) ;
const IDataType * observed_type1 = DataTypeTraits : : removeNullable ( arguments [ 1 ] ) . get ( ) ;
if ( ! ( observed_type0 - > behavesAsNumber ( ) & & observed_type1 - > behavesAsNumber ( ) )
& & ! observed_type0 - > equals ( * observed_type1 ) )
throw Exception ( " Types of array and 2nd argument of function "
+ getName ( ) + " must be identical up to nullability. Passed: "
+ arguments [ 0 ] - > getName ( ) + " and " + arguments [ 1 ] - > getName ( ) + " . " ,
ErrorCodes : : ILLEGAL_TYPE_OF_ARGUMENT ) ;
}
return std : : make_shared < DataTypeNumber < typename IndexConv : : ResultType > > ( ) ;
}
/// Perform function on the given block.
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override
{
/// If one or both arguments passed to this function are nullable,
2017-06-01 13:41:58 +00:00
/// we create a new block that contains non-nullable arguments:
2017-04-01 07:20:54 +00:00
/// - if the 1st argument is a non-constant array of nullable values,
/// it is turned into a non-constant array of ordinary values + a null
/// byte map;
/// - if the 2nd argument is a nullable value, it is turned into an
/// ordinary value + a null byte map.
/// Note that since constant arrays have quite a specific structure
/// (they are vectors of Fields, which may represent the NULL value),
/// they do not require any preprocessing
/// Check if the 1st function argument is a non-constant array of nullable
/// values.
bool is_nullable ;
const ColumnArray * col_array = nullptr ;
2017-07-21 06:35:58 +00:00
col_array = checkAndGetColumn < ColumnArray > ( block . getByPosition ( arguments [ 0 ] ) . column . get ( ) ) ;
2017-04-01 07:20:54 +00:00
if ( col_array )
is_nullable = col_array - > getData ( ) . isNullable ( ) ;
else
is_nullable = false ;
/// Check nullability of the 2nd function argument.
2017-07-21 06:35:58 +00:00
bool is_arg_nullable = block . getByPosition ( arguments [ 1 ] ) . column - > isNullable ( ) ;
2017-04-01 07:20:54 +00:00
if ( ! is_nullable & & ! is_arg_nullable )
{
/// Simple case: no nullable value is passed.
perform ( block , arguments , result ) ;
}
else
{
/// Template of the block on which we will actually apply the function.
/// Its elements will be filled later.
Block source_block =
{
/// 1st function argument (data)
{
} ,
/// 2nd function argument
{
} ,
/// 1st argument null map
{
} ,
/// 2nd argument null map
{
} ,
/// Function result.
{
nullptr ,
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . type ,
2017-04-01 07:20:54 +00:00
" "
}
} ;
if ( is_nullable )
{
const auto & nullable_col = static_cast < const ColumnNullable & > ( col_array - > getData ( ) ) ;
const auto & nested_col = nullable_col . getNestedColumn ( ) ;
auto & data = source_block . getByPosition ( 0 ) ;
data . column = std : : make_shared < ColumnArray > ( nested_col , col_array - > getOffsetsColumn ( ) ) ;
2017-07-21 06:35:58 +00:00
data . type = static_cast < const DataTypeNullable & > ( * block . getByPosition ( arguments [ 0 ] ) . type ) . getNestedType ( ) ;
2017-04-01 07:20:54 +00:00
auto & null_map = source_block . getByPosition ( 2 ) ;
null_map . column = nullable_col . getNullMapColumn ( ) ;
null_map . type = std : : make_shared < DataTypeUInt8 > ( ) ;
}
else
{
auto & data = source_block . getByPosition ( 0 ) ;
2017-07-21 06:35:58 +00:00
data = block . getByPosition ( arguments [ 0 ] ) ;
2017-04-01 07:20:54 +00:00
}
if ( is_arg_nullable )
{
2017-07-21 06:35:58 +00:00
const auto & col = block . getByPosition ( arguments [ 1 ] ) . column ;
2017-04-01 07:20:54 +00:00
const auto & nullable_col = static_cast < const ColumnNullable & > ( * col ) ;
auto & arg = source_block . getByPosition ( 1 ) ;
arg . column = nullable_col . getNestedColumn ( ) ;
2017-07-21 06:35:58 +00:00
arg . type = static_cast < const DataTypeNullable & > ( * block . getByPosition ( arguments [ 1 ] ) . type ) . getNestedType ( ) ;
2017-04-01 07:20:54 +00:00
auto & null_map = source_block . getByPosition ( 3 ) ;
null_map . column = nullable_col . getNullMapColumn ( ) ;
null_map . type = std : : make_shared < DataTypeUInt8 > ( ) ;
}
else
{
auto & arg = source_block . getByPosition ( 1 ) ;
2017-07-21 06:35:58 +00:00
arg = block . getByPosition ( arguments [ 1 ] ) ;
2017-04-01 07:20:54 +00:00
}
/// Now perform the function.
perform ( source_block , { 0 , 1 , 2 , 3 } , 4 ) ;
/// Move the result to its final position.
const ColumnWithTypeAndName & source_col = source_block . getByPosition ( 4 ) ;
ColumnWithTypeAndName & dest_col = block . getByPosition ( result ) ;
dest_col . column = std : : move ( source_col . column ) ;
}
}
2016-09-12 14:16:21 +00:00
private :
2017-04-01 07:20:54 +00:00
/// Perform function on the given block. Internal version.
void perform ( Block & block , const ColumnNumbers & arguments , size_t result )
{
2017-07-24 04:14:35 +00:00
if ( ! ( executeNumber < UInt8 > ( block , arguments , result )
| | executeNumber < UInt16 > ( block , arguments , result )
| | executeNumber < UInt32 > ( block , arguments , result )
| | executeNumber < UInt64 > ( block , arguments , result )
| | executeNumber < Int8 > ( block , arguments , result )
| | executeNumber < Int16 > ( block , arguments , result )
| | executeNumber < Int32 > ( block , arguments , result )
| | executeNumber < Int64 > ( block , arguments , result )
| | executeNumber < Float32 > ( block , arguments , result )
| | executeNumber < Float64 > ( block , arguments , result )
2017-04-01 07:20:54 +00:00
| | executeConst ( block , arguments , result )
| | executeString ( block , arguments , result )
| | executeGeneric ( block , arguments , result ) ) )
throw Exception {
2017-07-21 06:35:58 +00:00
" Illegal column " + block . getByPosition ( arguments [ 0 ] ) . column - > getName ( )
2017-04-01 07:20:54 +00:00
+ " of first argument of function " + getName ( ) ,
ErrorCodes : : ILLEGAL_COLUMN } ;
}
2012-11-02 19:10:43 +00:00
} ;
2016-08-11 16:47:28 +00:00
2013-10-21 11:36:44 +00:00
class FunctionArrayEnumerate : public IFunction
{
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = " arrayEnumerate " ;
static FunctionPtr create ( const Context & context ) ;
2014-11-12 17:23:26 +00:00
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2013-10-21 11:36:44 +00:00
2017-04-01 07:20:54 +00:00
size_t getNumberOfArguments ( ) const override { return 1 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
2013-10-21 11:36:44 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
2013-10-21 11:36:44 +00:00
} ;
2015-07-23 11:11:10 +00:00
2017-05-27 15:45:25 +00:00
/// Counts the number of different elements in the array, or the number of different tuples from the elements at the corresponding positions in several arrays.
/// NOTE The implementation partially matches arrayEnumerateUniq.
2015-07-23 11:11:10 +00:00
class FunctionArrayUniq : public IFunction
{
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = " arrayUniq " ;
static FunctionPtr create ( const Context & context ) ;
2015-07-23 11:11:10 +00:00
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2015-07-23 11:11:10 +00:00
2017-04-01 07:20:54 +00:00
bool isVariadic ( ) const override { return true ; }
size_t getNumberOfArguments ( ) const override { return 0 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
2015-07-23 11:11:10 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
2015-07-23 11:11:10 +00:00
private :
2017-06-01 13:41:58 +00:00
/// Initially allocate a piece of memory for 512 elements. NOTE: This is just a guess.
2017-04-01 07:20:54 +00:00
static constexpr size_t INITIAL_SIZE_DEGREE = 9 ;
2015-07-23 11:11:10 +00:00
2017-04-01 07:20:54 +00:00
template < typename T >
bool executeNumber ( const ColumnArray * array , const IColumn * null_map , ColumnUInt32 : : Container_t & res_values ) ;
2015-07-23 11:11:10 +00:00
2017-04-01 07:20:54 +00:00
bool executeString ( const ColumnArray * array , const IColumn * null_map , ColumnUInt32 : : Container_t & res_values ) ;
2015-07-23 11:11:10 +00:00
2017-04-01 07:20:54 +00:00
bool executeConst ( Block & block , const ColumnNumbers & arguments , size_t result ) ;
2015-07-23 11:11:10 +00:00
2017-04-01 07:20:54 +00:00
bool execute128bit (
const ColumnArray : : Offsets_t & offsets ,
const ConstColumnPlainPtrs & columns ,
const ConstColumnPlainPtrs & null_maps ,
ColumnUInt32 : : Container_t & res_values ,
bool has_nullable_columns ) ;
2015-07-23 11:11:10 +00:00
2017-04-01 07:20:54 +00:00
void executeHashed (
const ColumnArray : : Offsets_t & offsets ,
const ConstColumnPlainPtrs & columns ,
ColumnUInt32 : : Container_t & res_values ) ;
2015-07-23 11:11:10 +00:00
} ;
2013-10-11 11:43:50 +00:00
class FunctionArrayEnumerateUniq : public IFunction
{
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = " arrayEnumerateUniq " ;
static FunctionPtr create ( const Context & context ) ;
2014-11-12 17:23:26 +00:00
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2013-10-11 11:43:50 +00:00
2017-04-01 07:20:54 +00:00
bool isVariadic ( ) const override { return true ; }
size_t getNumberOfArguments ( ) const override { return 0 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
2013-10-11 11:43:50 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
2013-10-24 12:53:24 +00:00
private :
2017-06-01 13:41:58 +00:00
/// Initially allocate a piece of memory for 512 elements. NOTE: This is just a guess.
2017-04-01 07:20:54 +00:00
static constexpr size_t INITIAL_SIZE_DEGREE = 9 ;
2013-10-24 12:53:24 +00:00
2017-04-01 07:20:54 +00:00
template < typename T >
bool executeNumber ( const ColumnArray * array , const IColumn * null_map , ColumnUInt32 : : Container_t & res_values ) ;
2013-10-11 11:43:50 +00:00
2017-04-01 07:20:54 +00:00
bool executeString ( const ColumnArray * array , const IColumn * null_map , ColumnUInt32 : : Container_t & res_values ) ;
2013-10-11 11:43:50 +00:00
2017-04-01 07:20:54 +00:00
bool executeConst ( Block & block , const ColumnNumbers & arguments , size_t result ) ;
2013-12-24 11:56:38 +00:00
2017-04-01 07:20:54 +00:00
bool execute128bit (
const ColumnArray : : Offsets_t & offsets ,
const ConstColumnPlainPtrs & columns ,
const ConstColumnPlainPtrs & null_maps ,
ColumnUInt32 : : Container_t & res_values ,
bool has_nullable_columns ) ;
2013-12-24 11:56:38 +00:00
2017-04-01 07:20:54 +00:00
void executeHashed (
const ColumnArray : : Offsets_t & offsets ,
const ConstColumnPlainPtrs & columns ,
ColumnUInt32 : : Container_t & res_values ) ;
2013-10-11 11:43:50 +00:00
} ;
2012-11-02 19:10:43 +00:00
2014-10-28 13:43:22 +00:00
template < typename Type > struct TypeToColumnType { using ColumnType = ColumnVector < Type > ; } ;
template < > struct TypeToColumnType < String > { using ColumnType = ColumnString ; } ;
template < typename DataType > struct DataTypeToName : TypeName < typename DataType : : FieldType > { } ;
template < > struct DataTypeToName < DataTypeDate > { static std : : string get ( ) { return " Date " ; } } ;
template < > struct DataTypeToName < DataTypeDateTime > { static std : : string get ( ) { return " DateTime " ; } } ;
template < typename DataType >
2014-11-12 17:23:26 +00:00
struct FunctionEmptyArray : public IFunction
2014-10-28 13:43:22 +00:00
{
2017-04-01 07:20:54 +00:00
static constexpr auto base_name = " emptyArray " ;
static const String name ;
static FunctionPtr create ( const Context & context ) { return std : : make_shared < FunctionEmptyArray > ( ) ; }
2014-11-12 17:23:26 +00:00
2014-12-02 12:42:20 +00:00
private :
2017-04-01 07:20:54 +00:00
String getName ( ) const override
{
return name ;
}
size_t getNumberOfArguments ( ) const override { return 0 ; }
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override
{
return std : : make_shared < DataTypeArray > ( std : : make_shared < DataType > ( ) ) ;
}
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override
{
using UnderlyingColumnType = typename TypeToColumnType < typename DataType : : FieldType > : : ColumnType ;
2017-07-21 06:35:58 +00:00
block . getByPosition ( result ) . column = std : : make_shared < ColumnArray > (
2017-04-01 07:20:54 +00:00
std : : make_shared < UnderlyingColumnType > ( ) ,
std : : make_shared < ColumnArray : : ColumnOffsets_t > ( block . rows ( ) , 0 ) ) ;
}
2014-10-28 13:43:22 +00:00
} ;
2014-11-12 17:23:26 +00:00
template < typename DataType >
2017-07-16 03:05:40 +00:00
const String FunctionEmptyArray < DataType > : : name = FunctionEmptyArray : : base_name + String ( DataTypeToName < DataType > : : get ( ) ) ;
2014-11-12 17:23:26 +00:00
2014-12-02 12:42:20 +00:00
class FunctionRange : public IFunction
{
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = " range " ;
static FunctionPtr create ( const Context & ) { return std : : make_shared < FunctionRange > ( ) ; }
2014-12-02 12:42:20 +00:00
private :
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2014-12-02 12:42:20 +00:00
2017-04-01 07:20:54 +00:00
size_t getNumberOfArguments ( ) const override { return 1 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
2014-12-02 12:42:20 +00:00
2017-04-01 07:20:54 +00:00
template < typename T >
2017-07-21 06:35:58 +00:00
bool executeInternal ( Block & block , const IColumn * arg , const size_t result ) ;
2014-12-02 12:42:20 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , const size_t result ) override ;
2014-12-02 12:42:20 +00:00
} ;
2014-10-28 13:43:22 +00:00
2015-07-26 10:40:32 +00:00
class FunctionEmptyArrayToSingle : public IFunction
{
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = " emptyArrayToSingle " ;
static FunctionPtr create ( const Context & context ) ;
2015-07-26 10:40:32 +00:00
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2015-07-26 10:40:32 +00:00
2017-04-01 07:20:54 +00:00
size_t getNumberOfArguments ( ) const override { return 1 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
2015-07-26 10:40:32 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
2015-07-26 10:40:32 +00:00
} ;
2015-10-19 21:07:24 +00:00
class FunctionArrayReverse : public IFunction
{
public :
2017-06-10 09:04:31 +00:00
static constexpr auto name = " arrayReverse " ;
2017-04-01 07:20:54 +00:00
static FunctionPtr create ( const Context & context ) ;
2015-10-19 21:07:24 +00:00
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2015-10-19 21:07:24 +00:00
2017-04-01 07:20:54 +00:00
size_t getNumberOfArguments ( ) const override { return 1 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
2015-10-19 21:07:24 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
2015-10-19 21:07:24 +00:00
private :
2017-04-01 07:20:54 +00:00
bool executeConst ( Block & block , const ColumnNumbers & arguments , size_t result ) ;
template < typename T >
bool executeNumber (
const IColumn & src_data , const ColumnArray : : Offsets_t & src_offsets ,
IColumn & res_data_col ,
const ColumnNullable * nullable_col ,
ColumnNullable * nullable_res_col ) ;
bool executeFixedString (
const IColumn & src_data , const ColumnArray : : Offsets_t & src_offsets ,
IColumn & res_data_col ,
const ColumnNullable * nullable_col ,
ColumnNullable * nullable_res_col ) ;
bool executeString (
const IColumn & src_data , const ColumnArray : : Offsets_t & src_array_offsets ,
IColumn & res_data_col ,
const ColumnNullable * nullable_col ,
ColumnNullable * nullable_res_col ) ;
2015-10-19 21:07:24 +00:00
} ;
2017-01-21 04:24:28 +00:00
class IAggregateFunction ;
using AggregateFunctionPtr = std : : shared_ptr < IAggregateFunction > ;
2017-02-01 14:00:12 +00:00
/** Applies an aggregate function to array and returns its result.
2017-06-01 13:41:58 +00:00
* If aggregate function has multiple arguments , then this function can be applied to multiple arrays of the same size .
2015-12-13 10:43:49 +00:00
*/
class FunctionArrayReduce : public IFunction
{
public :
2017-04-01 07:20:54 +00:00
static constexpr auto name = " arrayReduce " ;
static FunctionPtr create ( const Context & context ) ;
2015-12-13 10:43:49 +00:00
2017-04-01 07:20:54 +00:00
String getName ( ) const override ;
2015-12-13 10:43:49 +00:00
2017-04-01 07:20:54 +00:00
bool isVariadic ( ) const override { return true ; }
size_t getNumberOfArguments ( ) const override { return 0 ; }
2016-12-29 19:38:10 +00:00
2017-04-01 07:20:54 +00:00
void getReturnTypeAndPrerequisitesImpl (
const ColumnsWithTypeAndName & arguments ,
DataTypePtr & out_return_type ,
std : : vector < ExpressionAction > & out_prerequisites ) override ;
2015-12-13 10:43:49 +00:00
2017-04-01 07:20:54 +00:00
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
2015-12-13 10:43:49 +00:00
private :
2017-04-01 07:20:54 +00:00
AggregateFunctionPtr aggregate_function ;
2015-12-13 10:43:49 +00:00
} ;
2017-08-16 17:50:12 +00:00
class FunctionArrayConcat : public IFunction
{
public :
static constexpr auto name = " arrayConcat " ;
static FunctionPtr create ( const Context & context ) ;
String getName ( ) const override ;
2017-08-17 19:33:02 +00:00
bool isVariadic ( ) const override { return true ; }
size_t getNumberOfArguments ( ) const override { return 0 ; }
2017-08-16 17:50:12 +00:00
DataTypePtr getReturnTypeImpl ( const DataTypes & arguments ) const override ;
void executeImpl ( Block & block , const ColumnNumbers & arguments , size_t result ) override ;
bool useDefaultImplementationForConstants ( ) const override { return true ; }
} ;
2017-06-01 13:41:58 +00:00
struct NameHas { static constexpr auto name = " has " ; } ;
struct NameIndexOf { static constexpr auto name = " indexOf " ; } ;
struct NameCountEqual { static constexpr auto name = " countEqual " ; } ;
2012-12-15 20:01:46 +00:00
2016-05-30 21:41:41 +00:00
using FunctionHas = FunctionArrayIndex < IndexToOne , NameHas > ;
using FunctionIndexOf = FunctionArrayIndex < IndexIdentity , NameIndexOf > ;
using FunctionCountEqual = FunctionArrayIndex < IndexCount , NameCountEqual > ;
2012-12-15 20:01:46 +00:00
2014-11-12 17:23:26 +00:00
using FunctionEmptyArrayUInt8 = FunctionEmptyArray < DataTypeUInt8 > ;
using FunctionEmptyArrayUInt16 = FunctionEmptyArray < DataTypeUInt16 > ;
using FunctionEmptyArrayUInt32 = FunctionEmptyArray < DataTypeUInt32 > ;
using FunctionEmptyArrayUInt64 = FunctionEmptyArray < DataTypeUInt64 > ;
using FunctionEmptyArrayInt8 = FunctionEmptyArray < DataTypeInt8 > ;
using FunctionEmptyArrayInt16 = FunctionEmptyArray < DataTypeInt16 > ;
using FunctionEmptyArrayInt32 = FunctionEmptyArray < DataTypeInt32 > ;
using FunctionEmptyArrayInt64 = FunctionEmptyArray < DataTypeInt64 > ;
using FunctionEmptyArrayFloat32 = FunctionEmptyArray < DataTypeFloat32 > ;
using FunctionEmptyArrayFloat64 = FunctionEmptyArray < DataTypeFloat64 > ;
using FunctionEmptyArrayDate = FunctionEmptyArray < DataTypeDate > ;
using FunctionEmptyArrayDateTime = FunctionEmptyArray < DataTypeDateTime > ;
using FunctionEmptyArrayString = FunctionEmptyArray < DataTypeString > ;
2014-10-28 13:43:22 +00:00
2012-12-15 20:01:46 +00:00
2012-08-26 06:48:39 +00:00
}