2012-08-26 06:48:39 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
2015-10-12 07:05:54 +00:00
|
|
|
|
#include <DB/Core/FieldVisitors.h>
|
|
|
|
|
|
2012-08-26 06:48:39 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeArray.h>
|
2017-03-12 10:13:45 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypesNumber.h>
|
2014-10-28 13:43:22 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeDate.h>
|
|
|
|
|
#include <DB/DataTypes/DataTypeDateTime.h>
|
|
|
|
|
#include <DB/DataTypes/DataTypeString.h>
|
2017-01-22 08:33:16 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeNullable.h>
|
2014-10-28 13:43:22 +00:00
|
|
|
|
|
2012-08-26 06:48:39 +00:00
|
|
|
|
#include <DB/Columns/ColumnArray.h>
|
2012-11-02 19:10:43 +00:00
|
|
|
|
#include <DB/Columns/ColumnString.h>
|
2017-01-22 08:33:16 +00:00
|
|
|
|
#include <DB/Columns/ColumnNullable.h>
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
2012-08-26 06:48:39 +00:00
|
|
|
|
#include <DB/Functions/IFunction.h>
|
2017-01-22 08:33:16 +00:00
|
|
|
|
#include <DB/Functions/DataTypeTraits.h>
|
2017-02-01 14:00:12 +00:00
|
|
|
|
#include <DB/Functions/ObjectPool.h>
|
2016-07-14 05:22:09 +00:00
|
|
|
|
#include <DB/Common/StringUtils.h>
|
2012-08-26 06:48:39 +00:00
|
|
|
|
|
2015-10-05 00:33:43 +00:00
|
|
|
|
#include <ext/range.hpp>
|
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
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-08-26 06:48:39 +00:00
|
|
|
|
/** Функции по работе с массивами:
|
|
|
|
|
*
|
|
|
|
|
* array(с1, с2, ...) - создать массив из констант.
|
2014-01-29 01:59:01 +00:00
|
|
|
|
* arrayElement(arr, i) - получить элемент массива по индексу.
|
|
|
|
|
* Индекс начинается с 1. Также индекс может быть отрицательным - тогда он считается с конца массива.
|
2012-11-02 19:10:43 +00:00
|
|
|
|
* has(arr, x) - есть ли в массиве элемент x.
|
2012-12-15 20:01:46 +00:00
|
|
|
|
* indexOf(arr, x) - возвращает индекс элемента x (начиная с 1), если он есть в массиве, или 0, если его нет.
|
2013-10-21 11:36:44 +00:00
|
|
|
|
* arrayEnumerate(arr) - возаращает массив [1,2,3,..., length(arr)]
|
2015-07-23 11:11:10 +00:00
|
|
|
|
*
|
|
|
|
|
* arrayUniq(arr) - считает количество разных элементов в массиве,
|
|
|
|
|
* arrayUniq(arr1, arr2, ...) - считает количество разных кортежей из элементов на соответствующих позициях в нескольких массивах.
|
|
|
|
|
*
|
|
|
|
|
* arrayEnumerateUniq(arr)
|
|
|
|
|
* - возаращает массив, параллельный данному, где для каждого элемента указано,
|
|
|
|
|
* какой он по счету среди элементов с таким значением.
|
|
|
|
|
* Например: arrayEnumerateUniq([10, 20, 10, 30]) = [1, 1, 2, 1]
|
|
|
|
|
* arrayEnumerateUniq(arr1, arr2...)
|
|
|
|
|
* - для кортежей из элементов на соответствующих позициях в нескольких массивах.
|
2015-07-26 10:40:32 +00:00
|
|
|
|
*
|
|
|
|
|
* emptyArrayToSingle(arr) - заменить пустые массивы на массивы из одного элемента со значением "по-умолчанию".
|
2015-12-13 10:43:49 +00:00
|
|
|
|
*
|
|
|
|
|
* arrayReduce('agg', arr1, ...) - применить агрегатную функцию agg к массивам arr1...
|
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:
|
|
|
|
|
static constexpr auto name = "array";
|
2016-08-11 16:47:28 +00:00
|
|
|
|
static FunctionPtr create(const Context & context);
|
2016-07-09 06:33:44 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
FunctionArray(const Context & context);
|
2014-11-12 17:23:26 +00:00
|
|
|
|
|
2016-09-11 07:40:47 +00:00
|
|
|
|
bool hasSpecialSupportForNulls() const override { return true; }
|
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
bool isVariadic() const override { return true; }
|
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override;
|
2014-04-17 14:37:59 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +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:
|
|
|
|
|
String getName() const override;
|
2014-04-17 14:37:59 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +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:
|
|
|
|
|
const Context & context;
|
|
|
|
|
};
|
2014-04-17 14:37:59 +00:00
|
|
|
|
|
2016-09-11 07:40:47 +00:00
|
|
|
|
namespace ArrayImpl
|
|
|
|
|
{
|
2016-12-10 04:51:36 +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:
|
|
|
|
|
static constexpr auto name = "arrayElement";
|
|
|
|
|
static FunctionPtr create(const Context & context);
|
2015-02-01 08:19:11 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
String getName() const override;
|
2015-02-01 08:19:11 +00:00
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
size_t getNumberOfArguments() const override { return 2; }
|
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override;
|
2015-02-01 08:19:11 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +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:
|
2016-09-11 07:40:47 +00:00
|
|
|
|
void perform(Block & block, const ColumnNumbers & arguments, size_t result, ArrayImpl::NullMapBuilder & builder);
|
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
template <typename DataType>
|
2016-09-11 07:40:47 +00:00
|
|
|
|
bool executeNumberConst(Block & block, const ColumnNumbers & arguments, size_t result, const Field & index,
|
|
|
|
|
ArrayImpl::NullMapBuilder & builder);
|
2015-02-01 08:19:11 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
template <typename IndexType, typename DataType>
|
2016-09-11 07:40:47 +00:00
|
|
|
|
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
|
|
|
|
|
2016-09-11 07:40:47 +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
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
template <typename IndexType>
|
2016-09-11 07:40:47 +00:00
|
|
|
|
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
|
|
|
|
|
2016-09-11 07:40:47 +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
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
template <typename IndexType>
|
2016-09-11 07:40:47 +00:00
|
|
|
|
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
|
|
|
|
|
2016-09-11 07:40:47 +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
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
template <typename IndexType>
|
2016-09-11 07:40:47 +00:00
|
|
|
|
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
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
template <typename IndexType>
|
2016-09-11 07:40:47 +00:00
|
|
|
|
bool executeArgument(Block & block, const ColumnNumbers & arguments, size_t result, ArrayImpl::NullMapBuilder & builder);
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +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
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using ResultType = UInt8;
|
2015-09-18 12:40:42 +00:00
|
|
|
|
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
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using ResultType = UInt64;
|
2012-12-15 20:01:46 +00:00
|
|
|
|
/// Индекс возвращается начиная с единицы.
|
2015-09-18 12:40:42 +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
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using ResultType = UInt32;
|
2015-09-18 12:40:42 +00:00
|
|
|
|
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"
|
|
|
|
|
|
2015-09-18 12:40:42 +00:00
|
|
|
|
/// compares `lhs` against `i`-th element of `rhs`
|
2016-04-15 00:33:21 +00:00
|
|
|
|
static bool compare(const T & lhs, const PaddedPODArray<U> & rhs, const std::size_t i ) { return lhs == rhs[i]; }
|
2015-09-18 12:40:42 +00:00
|
|
|
|
/// compares `lhs against `rhs`, third argument unused
|
2015-10-12 07:05:54 +00:00
|
|
|
|
static bool compare(const T & lhs, const U & rhs, std::size_t) { return lhs == rhs; }
|
|
|
|
|
|
|
|
|
|
#pragma GCC diagnostic pop
|
2015-09-18 12:40:42 +00:00
|
|
|
|
|
2016-09-12 14:16:21 +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)
|
|
|
|
|
{
|
|
|
|
|
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR};
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Both function arguments are ordinary.
|
2015-09-18 12:40:42 +00:00
|
|
|
|
template <typename ScalarOrVector>
|
2016-09-12 14:16:21 +00:00
|
|
|
|
static void vectorCase1(
|
2016-04-15 00:33:21 +00:00
|
|
|
|
const PaddedPODArray<T> & data, const ColumnArray::Offsets_t & offsets,
|
2015-09-18 12:40:42 +00:00
|
|
|
|
const ScalarOrVector & value,
|
2016-04-15 00:33:21 +00:00
|
|
|
|
PaddedPODArray<typename IndexConv::ResultType> & result)
|
2012-12-15 20:01:46 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
2012-12-26 15:40:37 +00:00
|
|
|
|
typename IndexConv::ResultType current = 0;
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2012-12-15 20:01:46 +00:00
|
|
|
|
for (size_t j = 0; j < array_size; ++j)
|
2016-09-12 14:16:21 +00:00
|
|
|
|
{
|
2015-09-18 12:40:42 +00:00
|
|
|
|
if (compare(data[current_offset + j], value, i))
|
2016-09-12 14:16:21 +00:00
|
|
|
|
{
|
|
|
|
|
if (!IndexConv::apply(j, current))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result[i] = current;
|
|
|
|
|
current_offset = offsets[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// The 2nd function argument is nullable.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// The 1st function argument is a non-constant array of nullable values.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// The 1st function argument is a non-constant array of nullable values.
|
|
|
|
|
/// The 2nd function argument is nullable.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
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-20 15:59:47 +00:00
|
|
|
|
public:
|
2016-09-12 14:16:21 +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)
|
|
|
|
|
{
|
2016-09-15 21:27:34 +00:00
|
|
|
|
/// Processing is split into 4 cases.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
if ((null_map_data == nullptr) && (null_map_item == nullptr))
|
|
|
|
|
vectorCase1(data, offsets, value, result);
|
|
|
|
|
else if ((null_map_data == nullptr) && (null_map_item != nullptr))
|
|
|
|
|
vectorCase2(data, offsets, value, result, *null_map_item);
|
|
|
|
|
else if ((null_map_data != nullptr) && (null_map_item == nullptr))
|
|
|
|
|
vectorCase3(data, offsets, value, result, *null_map_data);
|
|
|
|
|
else
|
|
|
|
|
vectorCase4(data, offsets, value, result, *null_map_data, *null_map_item);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
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>
|
|
|
|
|
{
|
|
|
|
|
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-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
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (null_map_data == nullptr)
|
|
|
|
|
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)
|
|
|
|
|
{
|
2012-12-26 15:40:37 +00:00
|
|
|
|
if (!IndexConv::apply(j, current))
|
|
|
|
|
break;
|
2016-09-12 14:16:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2012-12-26 15:40:37 +00:00
|
|
|
|
result[i] = current;
|
2012-12-15 20:01:46 +00:00
|
|
|
|
current_offset = offsets[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
2016-09-15 21:27:34 +00:00
|
|
|
|
if (null_map_data == nullptr)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const auto & null_map_ref = *null_map_data;
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
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;
|
2016-09-15 21:27:34 +00:00
|
|
|
|
if (null_map_ref[k] == 1)
|
2016-09-15 12:14:25 +00:00
|
|
|
|
{
|
|
|
|
|
if (!IndexConv::apply(j, current))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result[i] = current;
|
|
|
|
|
current_offset = offsets[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2012-12-15 20:01:46 +00:00
|
|
|
|
template <typename IndexConv>
|
|
|
|
|
struct ArrayIndexStringImpl
|
|
|
|
|
{
|
2015-09-18 12:40:42 +00:00
|
|
|
|
static void vector_const(
|
2013-09-15 05:51:43 +00:00
|
|
|
|
const ColumnString::Chars_t & data, const ColumnArray::Offsets_t & offsets, const ColumnString::Offsets_t & string_offsets,
|
2012-12-15 20:01:46 +00:00
|
|
|
|
const String & value,
|
2016-09-15 12:14:25 +00:00
|
|
|
|
PaddedPODArray<typename IndexConv::ResultType> & result,
|
|
|
|
|
const PaddedPODArray<UInt8> * null_map_data)
|
2012-12-15 20:01:46 +00:00
|
|
|
|
{
|
2015-09-18 12:40:42 +00:00
|
|
|
|
const auto size = offsets.size();
|
|
|
|
|
const auto value_size = value.size();
|
2012-12-15 20:01:46 +00:00
|
|
|
|
result.resize(size);
|
|
|
|
|
|
|
|
|
|
ColumnArray::Offset_t current_offset = 0;
|
|
|
|
|
for (size_t i = 0; i < size; ++i)
|
|
|
|
|
{
|
2015-09-18 12:40:42 +00:00
|
|
|
|
const auto array_size = offsets[i] - current_offset;
|
2012-12-26 15:40:37 +00:00
|
|
|
|
typename IndexConv::ResultType current = 0;
|
2012-12-15 20:01:46 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
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))
|
2012-12-15 20:01:46 +00:00
|
|
|
|
{
|
2012-12-26 15:40:37 +00:00
|
|
|
|
if (!IndexConv::apply(j, current))
|
|
|
|
|
break;
|
2012-12-15 20:01:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-26 15:40:37 +00:00
|
|
|
|
result[i] = current;
|
2012-12-15 20:01:46 +00:00
|
|
|
|
current_offset = offsets[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-18 12:40:42 +00:00
|
|
|
|
|
|
|
|
|
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,
|
2016-09-15 12:14:25 +00:00
|
|
|
|
PaddedPODArray<typename IndexConv::ResultType> & result,
|
|
|
|
|
const PaddedPODArray<UInt8> * null_map_data,
|
|
|
|
|
const PaddedPODArray<UInt8> * null_map_item)
|
2015-09-18 12:40:42 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
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)
|
2015-09-18 12:40:42 +00:00
|
|
|
|
{
|
|
|
|
|
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:
|
|
|
|
|
/// Both function arguments are ordinary.
|
|
|
|
|
static void vectorCase1(
|
2016-07-09 04:39:57 +00:00
|
|
|
|
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)
|
2016-09-20 15:59:47 +00:00
|
|
|
|
{
|
2016-07-09 04:39:57 +00:00
|
|
|
|
if (0 == data.compareAt(current_offset + j, is_value_has_single_element_to_compare ? 0 : i, value, 1))
|
2016-09-20 15:59:47 +00:00
|
|
|
|
{
|
|
|
|
|
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))
|
|
|
|
|
{
|
2016-07-09 04:39:57 +00:00
|
|
|
|
if (!IndexConv::apply(j, current))
|
|
|
|
|
break;
|
2016-09-20 15:59:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-09 04:39:57 +00:00
|
|
|
|
|
|
|
|
|
result[i] = current;
|
|
|
|
|
current_offset = offsets[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-20 15:59:47 +00:00
|
|
|
|
|
|
|
|
|
/// 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
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.
|
|
|
|
|
if ((null_map_data == nullptr) && (null_map_item == nullptr))
|
|
|
|
|
vectorCase1(data, offsets, value, result);
|
|
|
|
|
else if ((null_map_data == nullptr) && (null_map_item != nullptr))
|
|
|
|
|
vectorCase2(data, offsets, value, result, *null_map_item);
|
|
|
|
|
else if ((null_map_data != nullptr) && (null_map_item == nullptr))
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (null_map_data == nullptr)
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
static constexpr auto name = Name::name;
|
2016-05-28 15:42:22 +00:00
|
|
|
|
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:
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using ResultColumnType = ColumnVector<typename IndexConv::ResultType>;
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2012-11-02 19:10:43 +00:00
|
|
|
|
template <typename T>
|
2015-09-18 12:40:42 +00:00
|
|
|
|
bool executeNumber(Block & block, const ColumnNumbers & arguments, size_t result)
|
2015-10-12 07:05:54 +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)
|
2016-09-12 14:16:21 +00:00
|
|
|
|
|| executeNumberNumber<T, Float64>(block, arguments, result)
|
|
|
|
|
|| executeNumberNumber<T, Null>(block, arguments, result);
|
2015-10-12 07:05:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T, typename U>
|
|
|
|
|
bool executeNumberNumber(Block & block, const ColumnNumbers & arguments, size_t result)
|
2012-11-02 19:10:43 +00:00
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const ColumnArray * col_array = typeid_cast<const ColumnArray *>(block.safeGetByPosition(arguments[0]).column.get());
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
if (!col_array)
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-06-26 00:58:14 +00:00
|
|
|
|
const ColumnVector<T> * col_nested = typeid_cast<const ColumnVector<T> *>(&col_array->getData());
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
if (!col_nested)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-09-20 15:59:47 +00:00
|
|
|
|
const auto col_res = std::make_shared<ResultColumnType>();
|
2017-01-02 20:12:12 +00:00
|
|
|
|
block.safeGetByPosition(result).column = col_res;
|
2016-09-20 15:59:47 +00:00
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Null maps of the 1st and second function arguments,
|
|
|
|
|
/// if it applies.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
const PaddedPODArray<UInt8> * null_map_data = nullptr;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
const PaddedPODArray<UInt8> * null_map_item = nullptr;
|
2016-09-12 14:16:21 +00:00
|
|
|
|
|
|
|
|
|
if (arguments.size() > 2)
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto & null_map1 = block.safeGetByPosition(arguments[2]).column;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
if (null_map1)
|
|
|
|
|
null_map_data = &static_cast<const ColumnUInt8 &>(*null_map1).getData();
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto & null_map2 = block.safeGetByPosition(arguments[3]).column;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
if (null_map2)
|
|
|
|
|
null_map_item = &static_cast<const ColumnUInt8 &>(*null_map2).getData();
|
2016-09-12 14:16:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto item_arg = block.safeGetByPosition(arguments[1]).column.get();
|
2015-09-18 12:40:42 +00:00
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
if (item_arg->isNull())
|
|
|
|
|
ArrayIndexNumNullImpl<T, IndexConv>::vector(col_nested->getData(), col_array->getOffsets(),
|
|
|
|
|
col_res->getData(), null_map_data);
|
|
|
|
|
else if (const auto item_arg_const = typeid_cast<const ColumnConst<U> *>(item_arg))
|
2016-09-20 15:59:47 +00:00
|
|
|
|
ArrayIndexNumImpl<T, U, IndexConv>::vector(col_nested->getData(), col_array->getOffsets(),
|
|
|
|
|
item_arg_const->getData(), col_res->getData(), null_map_data, nullptr);
|
2015-10-12 07:05:54 +00:00
|
|
|
|
else if (const auto item_arg_vector = typeid_cast<const ColumnVector<U> *>(item_arg))
|
|
|
|
|
ArrayIndexNumImpl<T, U, IndexConv>::vector(col_nested->getData(), col_array->getOffsets(),
|
2016-09-12 14:16:21 +00:00
|
|
|
|
item_arg_vector->getData(), col_res->getData(), null_map_data, null_map_item);
|
2015-10-12 07:05:54 +00:00
|
|
|
|
else
|
|
|
|
|
return false;
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 12:40:42 +00:00
|
|
|
|
bool executeString(Block & block, const ColumnNumbers & arguments, size_t result)
|
2012-11-02 19:10:43 +00:00
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const ColumnArray * col_array = typeid_cast<const ColumnArray *>(block.safeGetByPosition(arguments[0]).column.get());
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
if (!col_array)
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-06-26 00:58:14 +00:00
|
|
|
|
const ColumnString * col_nested = typeid_cast<const ColumnString *>(&col_array->getData());
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
if (!col_nested)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-09-20 15:59:47 +00:00
|
|
|
|
const auto col_res = std::make_shared<ResultColumnType>();
|
2017-01-02 20:12:12 +00:00
|
|
|
|
block.safeGetByPosition(result).column = col_res;
|
2016-09-20 15:59:47 +00:00
|
|
|
|
|
2016-09-15 12:14:25 +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-01-02 20:12:12 +00:00
|
|
|
|
const auto & col1 = block.safeGetByPosition(arguments[2]).column;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
if (col1)
|
|
|
|
|
null_map_data = &static_cast<const ColumnUInt8 &>(*col1).getData();
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto & col2 = block.safeGetByPosition(arguments[3]).column;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
if (col2)
|
|
|
|
|
null_map_item = &static_cast<const ColumnUInt8 &>(*col2).getData();
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto item_arg = block.safeGetByPosition(arguments[1]).column.get();
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
2016-09-15 12:14:25 +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);
|
|
|
|
|
else if (const auto item_arg_const = typeid_cast<const ColumnConst<String> *>(item_arg))
|
2015-09-18 12:40:42 +00:00
|
|
|
|
ArrayIndexStringImpl<IndexConv>::vector_const(col_nested->getChars(), col_array->getOffsets(),
|
2016-09-15 12:14:25 +00:00
|
|
|
|
col_nested->getOffsets(), item_arg_const->getData(), col_res->getData(),
|
|
|
|
|
null_map_data);
|
2015-09-18 12:40:42 +00:00
|
|
|
|
else if (const auto item_arg_vector = typeid_cast<const ColumnString *>(item_arg))
|
|
|
|
|
ArrayIndexStringImpl<IndexConv>::vector_vector(col_nested->getChars(), col_array->getOffsets(),
|
|
|
|
|
col_nested->getOffsets(), item_arg_vector->getChars(), item_arg_vector->getOffsets(),
|
2016-09-15 12:14:25 +00:00
|
|
|
|
col_res->getData(), null_map_data, null_map_item);
|
2016-07-09 04:39:57 +00:00
|
|
|
|
else
|
|
|
|
|
return false;
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 12:40:42 +00:00
|
|
|
|
bool executeConst(Block & block, const ColumnNumbers & arguments, size_t result)
|
2012-11-02 19:10:43 +00:00
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const ColumnConstArray * col_array = typeid_cast<const ColumnConstArray *>(block.safeGetByPosition(arguments[0]).column.get());
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
if (!col_array)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const Array & arr = col_array->getData();
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto item_arg = block.safeGetByPosition(arguments[1]).column.get();
|
2015-09-18 12:40:42 +00:00
|
|
|
|
if (item_arg->isConst())
|
2012-12-26 15:40:37 +00:00
|
|
|
|
{
|
2016-05-30 23:42:07 +00:00
|
|
|
|
typename IndexConv::ResultType current = 0;
|
2015-09-18 12:40:42 +00:00
|
|
|
|
const auto & value = (*item_arg)[0];
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0, size = arr.size(); i < size; ++i)
|
2012-12-26 15:40:37 +00:00
|
|
|
|
{
|
2017-01-06 17:41:19 +00:00
|
|
|
|
if (applyVisitor(FieldVisitorAccurateEquals(), arr[i], value))
|
2015-09-18 12:40:42 +00:00
|
|
|
|
{
|
|
|
|
|
if (!IndexConv::apply(i, current))
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-12-26 15:40:37 +00:00
|
|
|
|
}
|
2015-09-18 12:40:42 +00:00
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
block.safeGetByPosition(result).column = block.safeGetByPosition(result).type->createConstColumn(
|
2015-09-18 12:40:42 +00:00
|
|
|
|
item_arg->size(),
|
|
|
|
|
static_cast<typename NearestFieldType<typename IndexConv::ResultType>::Type>(current));
|
2012-12-26 15:40:37 +00:00
|
|
|
|
}
|
2015-09-18 12:40:42 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Null map of the 2nd function argument, if it applies.
|
|
|
|
|
const PaddedPODArray<UInt8> * null_map = nullptr;
|
|
|
|
|
|
|
|
|
|
if (arguments.size() > 2)
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto & col = block.safeGetByPosition(arguments[3]).column;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
if (col)
|
|
|
|
|
null_map = &static_cast<const ColumnUInt8 &>(*col).getData();
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 12:40:42 +00:00
|
|
|
|
const auto size = item_arg->size();
|
2016-05-28 05:31:36 +00:00
|
|
|
|
const auto col_res = std::make_shared<ResultColumnType>(size);
|
2017-01-02 20:12:12 +00:00
|
|
|
|
block.safeGetByPosition(result).column = col_res;
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
2015-09-18 12:40:42 +00:00
|
|
|
|
auto & data = col_res->getData();
|
|
|
|
|
|
|
|
|
|
for (size_t row = 0; row < size; ++row)
|
|
|
|
|
{
|
|
|
|
|
const auto & value = (*item_arg)[row];
|
2016-05-30 23:42:07 +00:00
|
|
|
|
|
|
|
|
|
data[row] = 0;
|
2015-09-18 12:40:42 +00:00
|
|
|
|
for (size_t i = 0, size = arr.size(); i < size; ++i)
|
2016-09-15 12:14:25 +00:00
|
|
|
|
{
|
|
|
|
|
bool hit = false;
|
|
|
|
|
|
|
|
|
|
if (arr[i].isNull())
|
|
|
|
|
{
|
|
|
|
|
if (null_map && ((*null_map)[row] == 1))
|
2017-02-10 09:04:31 +00:00
|
|
|
|
hit = true;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
}
|
2017-01-06 17:41:19 +00:00
|
|
|
|
else if (applyVisitor(FieldVisitorAccurateEquals(), arr[i], value))
|
2016-09-15 12:14:25 +00:00
|
|
|
|
hit = true;
|
|
|
|
|
|
|
|
|
|
if (hit)
|
|
|
|
|
{
|
2015-09-18 12:40:42 +00:00
|
|
|
|
if (!IndexConv::apply(i, data[row]))
|
|
|
|
|
break;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-18 12:40:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-09 04:39:57 +00:00
|
|
|
|
bool executeGeneric(Block & block, const ColumnNumbers & arguments, size_t result)
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const ColumnArray * col_array = typeid_cast<const ColumnArray *>(block.safeGetByPosition(arguments[0]).column.get());
|
2016-07-09 04:39:57 +00:00
|
|
|
|
|
|
|
|
|
if (!col_array)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const IColumn & col_nested = col_array->getData();
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const IColumn & item_arg = *block.safeGetByPosition(arguments[1]).column;
|
2016-07-09 04:39:57 +00:00
|
|
|
|
|
|
|
|
|
const auto col_res = std::make_shared<ResultColumnType>();
|
2017-01-02 20:12:12 +00:00
|
|
|
|
block.safeGetByPosition(result).column = col_res;
|
2016-07-09 04:39:57 +00:00
|
|
|
|
|
2016-09-20 15:59:47 +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)
|
2016-07-09 04:39:57 +00:00
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto & null_map1 = block.safeGetByPosition(arguments[2]).column;
|
2016-09-20 15:59:47 +00:00
|
|
|
|
if (null_map1)
|
|
|
|
|
null_map_data = &static_cast<const ColumnUInt8 &>(*null_map1).getData();
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto & null_map2 = block.safeGetByPosition(arguments[3]).column;
|
2016-09-20 15:59:47 +00:00
|
|
|
|
if (null_map2)
|
|
|
|
|
null_map_item = &static_cast<const ColumnUInt8 &>(*null_map2).getData();
|
2016-07-09 04:39:57 +00:00
|
|
|
|
}
|
2016-09-20 15:59:47 +00:00
|
|
|
|
|
|
|
|
|
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(),
|
|
|
|
|
*item_arg.cut(0, 1)->convertToFullColumnIfConst(), col_res->getData(),
|
|
|
|
|
null_map_data, nullptr);
|
2016-07-09 04:39:57 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/// If item_arg is tuple and have constants.
|
|
|
|
|
if (auto materialized_tuple = item_arg.convertToFullColumnIfConst())
|
|
|
|
|
ArrayIndexGenericImpl<IndexConv, false>::vector(
|
2016-09-20 15:59:47 +00:00
|
|
|
|
col_nested, col_array->getOffsets(), *materialized_tuple, col_res->getData(),
|
|
|
|
|
null_map_data, null_map_item);
|
2016-07-09 04:39:57 +00:00
|
|
|
|
else
|
|
|
|
|
ArrayIndexGenericImpl<IndexConv, false>::vector(
|
2016-09-20 15:59:47 +00:00
|
|
|
|
col_nested, col_array->getOffsets(), item_arg, col_res->getData(),
|
|
|
|
|
null_map_data, null_map_item);
|
2016-07-09 04:39:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
|
|
|
|
public:
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Get function name.
|
2015-10-11 23:36:45 +00:00
|
|
|
|
String getName() const override
|
2012-11-02 19:10:43 +00:00
|
|
|
|
{
|
2014-11-12 17:23:26 +00:00
|
|
|
|
return name;
|
2012-11-02 19:10:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-11 22:03:26 +00:00
|
|
|
|
bool hasSpecialSupportForNulls() const override
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
size_t getNumberOfArguments() const override { return 2; }
|
|
|
|
|
|
2012-11-02 19:10:43 +00:00
|
|
|
|
/// Получить типы результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение.
|
2016-07-06 09:47:55 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
2012-11-02 19:10:43 +00:00
|
|
|
|
{
|
2016-07-08 04:16:30 +00:00
|
|
|
|
const DataTypeArray * array_type = typeid_cast<const DataTypeArray *>(arguments[0].get());
|
2012-11-02 19:10:43 +00:00
|
|
|
|
if (!array_type)
|
2016-09-15 12:14:25 +00:00
|
|
|
|
throw Exception("First argument for function " + getName() + " must be an array.",
|
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
2016-09-11 22:03:26 +00:00
|
|
|
|
if (!arguments[1]->isNull())
|
|
|
|
|
{
|
2016-09-12 14:16:21 +00:00
|
|
|
|
const IDataType * observed_type0 = DataTypeTraits::removeNullable(array_type->getNestedType()).get();
|
|
|
|
|
const IDataType * observed_type1 = DataTypeTraits::removeNullable(arguments[1]).get();
|
2016-09-11 22:03:26 +00:00
|
|
|
|
|
|
|
|
|
if (!(observed_type0->behavesAsNumber() && observed_type1->behavesAsNumber())
|
|
|
|
|
&& observed_type0->getName() != observed_type1->getName())
|
2016-09-15 12:14:25 +00:00
|
|
|
|
throw Exception("Types of array and 2nd argument of function "
|
|
|
|
|
+ getName() + " must be identical up to nullability. Passed: "
|
2016-09-11 22:03:26 +00:00
|
|
|
|
+ arguments[0]->getName() + " and " + arguments[1]->getName() + ".",
|
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
}
|
2012-11-02 19:10:43 +00:00
|
|
|
|
|
2017-03-12 10:13:45 +00:00
|
|
|
|
return std::make_shared<DataTypeNumber<typename IndexConv::ResultType>>();
|
2012-11-02 19:10:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Perform function on the given block.
|
2016-07-06 09:47:55 +00:00
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
|
2016-09-12 14:16:21 +00:00
|
|
|
|
{
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// If one or both arguments passed to this function are nullable,
|
|
|
|
|
/// we create a new block that contains non-nullable parameters:
|
|
|
|
|
/// - 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.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
bool is_nullable;
|
|
|
|
|
|
|
|
|
|
const ColumnArray * col_array = nullptr;
|
2017-01-02 20:12:12 +00:00
|
|
|
|
col_array = typeid_cast<const ColumnArray *>(block.safeGetByPosition(arguments[0]).column.get());
|
2016-09-12 14:16:21 +00:00
|
|
|
|
if (col_array)
|
|
|
|
|
is_nullable = col_array->getData().isNullable();
|
2016-09-15 12:14:25 +00:00
|
|
|
|
else
|
|
|
|
|
is_nullable = false;
|
2016-09-12 14:16:21 +00:00
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Check nullability of the 2nd function argument.
|
2017-01-02 20:12:12 +00:00
|
|
|
|
bool is_arg_nullable = block.safeGetByPosition(arguments[1]).column->isNullable();
|
2016-09-12 14:16:21 +00:00
|
|
|
|
|
|
|
|
|
if (!is_nullable && !is_arg_nullable)
|
2016-09-15 12:14:25 +00:00
|
|
|
|
{
|
|
|
|
|
/// Simple case: no nullable value is passed.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
perform(block, arguments, result);
|
2016-09-15 12:14:25 +00:00
|
|
|
|
}
|
2016-09-12 14:16:21 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Template of the block on which we will actually apply the function.
|
|
|
|
|
/// Its elements will be filled later.
|
|
|
|
|
Block source_block =
|
2016-09-12 14:16:21 +00:00
|
|
|
|
{
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// 1st function argument (data)
|
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/// 2nd function argument
|
2016-09-12 14:16:21 +00:00
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// 1st argument null map
|
|
|
|
|
{
|
|
|
|
|
},
|
2016-09-12 14:16:21 +00:00
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// 2nd argument null map
|
2016-09-12 14:16:21 +00:00
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Function result.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
{
|
|
|
|
|
nullptr,
|
2017-01-02 20:12:12 +00:00
|
|
|
|
block.safeGetByPosition(result).type,
|
2016-09-12 14:16:21 +00:00
|
|
|
|
""
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
if (is_nullable)
|
|
|
|
|
{
|
|
|
|
|
const auto & nullable_col = static_cast<const ColumnNullable &>(col_array->getData());
|
|
|
|
|
const auto & nested_col = nullable_col.getNestedColumn();
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
auto & data = source_block.getByPosition(0);
|
2016-09-15 12:14:25 +00:00
|
|
|
|
data.column = std::make_shared<ColumnArray>(nested_col, col_array->getOffsetsColumn());
|
2017-01-02 20:12:12 +00:00
|
|
|
|
data.type = static_cast<const DataTypeNullable &>(*block.safeGetByPosition(arguments[0]).type).getNestedType();
|
2016-09-15 12:14:25 +00:00
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
auto & null_map = source_block.getByPosition(2);
|
2016-12-30 05:13:14 +00:00
|
|
|
|
null_map.column = nullable_col.getNullMapColumn();
|
2016-09-15 12:14:25 +00:00
|
|
|
|
null_map.type = std::make_shared<DataTypeUInt8>();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
auto & data = source_block.getByPosition(0);
|
|
|
|
|
data = block.safeGetByPosition(arguments[0]);
|
2016-09-15 12:14:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_arg_nullable)
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const auto & col = block.safeGetByPosition(arguments[1]).column;
|
2016-09-15 12:14:25 +00:00
|
|
|
|
const auto & nullable_col = static_cast<const ColumnNullable &>(*col);
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
auto & arg = source_block.getByPosition(1);
|
2016-09-15 12:14:25 +00:00
|
|
|
|
arg.column = nullable_col.getNestedColumn();
|
2017-01-02 20:12:12 +00:00
|
|
|
|
arg.type = static_cast<const DataTypeNullable &>(*block.safeGetByPosition(arguments[1]).type).getNestedType();
|
2016-09-15 12:14:25 +00:00
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
auto & null_map = source_block.getByPosition(3);
|
2016-12-30 05:13:14 +00:00
|
|
|
|
null_map.column = nullable_col.getNullMapColumn();
|
2016-09-15 12:14:25 +00:00
|
|
|
|
null_map.type = std::make_shared<DataTypeUInt8>();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
auto & arg = source_block.getByPosition(1);
|
|
|
|
|
arg = block.safeGetByPosition(arguments[1]);
|
2016-09-15 12:14:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Now perform the function.
|
|
|
|
|
perform(source_block, {0, 1, 2, 3}, 4);
|
2016-09-12 14:16:21 +00:00
|
|
|
|
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Move the result to its final position.
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const ColumnWithTypeAndName & source_col = source_block.getByPosition(4);
|
|
|
|
|
ColumnWithTypeAndName & dest_col = block.getByPosition(result);
|
2016-09-15 12:14:25 +00:00
|
|
|
|
dest_col.column = std::move(source_col.column);
|
2016-09-12 14:16:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2016-09-15 12:14:25 +00:00
|
|
|
|
/// Perform function on the given block. Internal version.
|
2016-09-12 14:16:21 +00:00
|
|
|
|
void perform(Block & block, const ColumnNumbers & arguments, size_t result)
|
2012-11-02 19:10:43 +00:00
|
|
|
|
{
|
2015-09-18 12:40:42 +00:00
|
|
|
|
if (!(executeNumber<UInt8>(block, arguments, result)
|
2016-07-09 04:39:57 +00:00
|
|
|
|
|| 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)
|
|
|
|
|
|| executeConst(block, arguments, result)
|
|
|
|
|
|| executeString(block, arguments, result)
|
|
|
|
|
|| executeGeneric(block, arguments, result)))
|
2015-09-18 12:40:42 +00:00
|
|
|
|
throw Exception{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
"Illegal column " + block.safeGetByPosition(arguments[0]).column->getName()
|
2015-09-18 12:40:42 +00:00
|
|
|
|
+ " of first argument of function " + getName(),
|
2016-07-09 04:39:57 +00:00
|
|
|
|
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:
|
2014-11-12 17:23:26 +00:00
|
|
|
|
static constexpr auto name = "arrayEnumerate";
|
2016-08-11 16:47:28 +00:00
|
|
|
|
static FunctionPtr create(const Context & context);
|
2014-11-12 17:23:26 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
String getName() const override;
|
2013-10-21 11:36:44 +00:00
|
|
|
|
|
2017-01-12 01:29:32 +00:00
|
|
|
|
size_t getNumberOfArguments() const override { return 1; }
|
2016-12-29 19:38:10 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override;
|
2013-10-21 11:36:44 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +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
|
|
|
|
|
|
|
|
|
/// Считает количество разных элементов в массиве, или количество разных кортежей из элементов на соответствующих позициях в нескольких массивах.
|
|
|
|
|
/// NOTE Реализация частично совпадает с arrayEnumerateUniq.
|
|
|
|
|
class FunctionArrayUniq : public IFunction
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
static constexpr auto name = "arrayUniq";
|
2016-08-11 16:47:28 +00:00
|
|
|
|
static FunctionPtr create(const Context & context);
|
2015-07-23 11:11:10 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
String getName() const override;
|
2015-07-23 11:11:10 +00:00
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
bool isVariadic() const override { return true; }
|
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override;
|
2015-07-23 11:11:10 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override;
|
2015-07-23 11:11:10 +00:00
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/// Изначально выделить кусок памяти для 512 элементов.
|
|
|
|
|
static constexpr size_t INITIAL_SIZE_DEGREE = 9;
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2016-09-15 21:27:34 +00:00
|
|
|
|
bool executeNumber(const ColumnArray * array, const IColumn * null_map, ColumnUInt32::Container_t & res_values);
|
2015-07-23 11:11:10 +00:00
|
|
|
|
|
2016-09-15 21:27:34 +00:00
|
|
|
|
bool executeString(const ColumnArray * array, const IColumn * null_map, ColumnUInt32::Container_t & res_values);
|
2015-07-23 11:11:10 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
bool executeConst(Block & block, const ColumnNumbers & arguments, size_t result);
|
2015-07-23 11:11:10 +00:00
|
|
|
|
|
|
|
|
|
bool execute128bit(
|
|
|
|
|
const ColumnArray::Offsets_t & offsets,
|
|
|
|
|
const ConstColumnPlainPtrs & columns,
|
2016-09-15 21:27:34 +00:00
|
|
|
|
const ConstColumnPlainPtrs & null_maps,
|
2016-09-16 16:11:36 +00:00
|
|
|
|
ColumnUInt32::Container_t & res_values,
|
|
|
|
|
bool has_nullable_columns);
|
2015-07-23 11:11:10 +00:00
|
|
|
|
|
|
|
|
|
void executeHashed(
|
|
|
|
|
const ColumnArray::Offsets_t & offsets,
|
|
|
|
|
const ConstColumnPlainPtrs & columns,
|
2016-08-11 16:47:28 +00:00
|
|
|
|
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:
|
2014-11-12 17:23:26 +00:00
|
|
|
|
static constexpr auto name = "arrayEnumerateUniq";
|
2016-08-11 16:47:28 +00:00
|
|
|
|
static FunctionPtr create(const Context & context);
|
2014-11-12 17:23:26 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
String getName() const override;
|
2013-10-11 11:43:50 +00:00
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
bool isVariadic() const override { return true; }
|
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override;
|
2013-10-11 11:43:50 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override;
|
2013-10-24 12:53:24 +00:00
|
|
|
|
|
|
|
|
|
private:
|
2014-04-28 02:47:56 +00:00
|
|
|
|
/// Изначально выделить кусок памяти для 512 элементов.
|
2014-05-03 16:03:49 +00:00
|
|
|
|
static constexpr size_t INITIAL_SIZE_DEGREE = 9;
|
2013-10-24 12:53:24 +00:00
|
|
|
|
|
2013-10-11 11:43:50 +00:00
|
|
|
|
template <typename T>
|
2016-09-19 09:40:17 +00:00
|
|
|
|
bool executeNumber(const ColumnArray * array, const IColumn * null_map, ColumnUInt32::Container_t & res_values);
|
2013-10-11 11:43:50 +00:00
|
|
|
|
|
2016-09-19 09:40:17 +00:00
|
|
|
|
bool executeString(const ColumnArray * array, const IColumn * null_map, ColumnUInt32::Container_t & res_values);
|
2013-10-11 11:43:50 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
bool executeConst(Block & block, const ColumnNumbers & arguments, size_t result);
|
2013-12-24 11:56:38 +00:00
|
|
|
|
|
|
|
|
|
bool execute128bit(
|
|
|
|
|
const ColumnArray::Offsets_t & offsets,
|
|
|
|
|
const ConstColumnPlainPtrs & columns,
|
2016-09-19 09:40:17 +00:00
|
|
|
|
const ConstColumnPlainPtrs & null_maps,
|
|
|
|
|
ColumnUInt32::Container_t & res_values,
|
|
|
|
|
bool has_nullable_columns);
|
2013-12-24 11:56:38 +00:00
|
|
|
|
|
|
|
|
|
void executeHashed(
|
|
|
|
|
const ColumnArray::Offsets_t & offsets,
|
|
|
|
|
const ConstColumnPlainPtrs & columns,
|
2016-08-11 16:47:28 +00:00
|
|
|
|
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
|
|
|
|
{
|
2014-11-12 17:23:26 +00:00
|
|
|
|
static constexpr auto base_name = "emptyArray";
|
|
|
|
|
static const String name;
|
2016-05-28 15:42:22 +00:00
|
|
|
|
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:
|
2015-10-11 23:36:45 +00:00
|
|
|
|
String getName() const override
|
2014-10-28 13:43:22 +00:00
|
|
|
|
{
|
2014-11-12 17:23:26 +00:00
|
|
|
|
return name;
|
2014-10-28 13:43:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
|
|
2016-07-06 09:47:55 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
2014-10-28 13:43:22 +00:00
|
|
|
|
{
|
2016-05-28 07:48:40 +00:00
|
|
|
|
return std::make_shared<DataTypeArray>(std::make_shared<DataType>());
|
2014-10-28 13:43:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-06 09:47:55 +00:00
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
|
2014-10-28 13:43:22 +00:00
|
|
|
|
{
|
|
|
|
|
using UnderlyingColumnType = typename TypeToColumnType<typename DataType::FieldType>::ColumnType;
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
block.safeGetByPosition(result).column = std::make_shared<ColumnArray>(
|
2016-05-28 05:31:36 +00:00
|
|
|
|
std::make_shared<UnderlyingColumnType>(),
|
2017-01-02 20:42:49 +00:00
|
|
|
|
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>
|
|
|
|
|
const String FunctionEmptyArray<DataType>::name = FunctionEmptyArray::base_name + DataTypeToName<DataType>::get();
|
|
|
|
|
|
2014-12-02 12:42:20 +00:00
|
|
|
|
class FunctionRange : public IFunction
|
|
|
|
|
{
|
|
|
|
|
public:
|
2016-09-19 16:04:53 +00:00
|
|
|
|
static constexpr auto max_elements = 100'000'000;
|
2014-12-02 12:42:20 +00:00
|
|
|
|
static constexpr auto name = "range";
|
2016-05-28 15:42:22 +00:00
|
|
|
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionRange>(); }
|
2014-12-02 12:42:20 +00:00
|
|
|
|
|
|
|
|
|
private:
|
2016-12-02 07:15:35 +00:00
|
|
|
|
String getName() const override;
|
2014-12-02 12:42:20 +00:00
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
size_t getNumberOfArguments() const override { return 1; }
|
|
|
|
|
|
2016-09-19 16:04:53 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override;
|
2014-12-02 12:42:20 +00:00
|
|
|
|
|
|
|
|
|
template <typename T>
|
2016-09-19 16:04:53 +00:00
|
|
|
|
bool executeInternal(Block & block, const IColumn * const arg, const size_t result);
|
2014-12-02 12:42:20 +00:00
|
|
|
|
|
2016-09-19 16:04:53 +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:
|
|
|
|
|
static constexpr auto name = "emptyArrayToSingle";
|
2016-08-11 16:47:28 +00:00
|
|
|
|
static FunctionPtr create(const Context & context);
|
2015-07-26 10:40:32 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
String getName() const override;
|
2015-07-26 10:40:32 +00:00
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
size_t getNumberOfArguments() const override { return 1; }
|
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override;
|
2015-07-26 10:40:32 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override;
|
2015-07-26 10:40:32 +00:00
|
|
|
|
|
|
|
|
|
private:
|
2016-08-11 16:47:28 +00:00
|
|
|
|
bool executeConst(Block & block, const ColumnNumbers & arguments, size_t result);
|
2015-07-26 10:40:32 +00:00
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
bool executeNumber(
|
|
|
|
|
const IColumn & src_data, const ColumnArray::Offsets_t & src_offsets,
|
2016-09-19 16:04:53 +00:00
|
|
|
|
IColumn & res_data_col, ColumnArray::Offsets_t & res_offsets,
|
|
|
|
|
const ColumnNullable * nullable_col,
|
|
|
|
|
ColumnNullable * nullable_res_col);
|
2015-07-26 10:40:32 +00:00
|
|
|
|
|
|
|
|
|
bool executeFixedString(
|
|
|
|
|
const IColumn & src_data, const ColumnArray::Offsets_t & src_offsets,
|
2016-09-19 16:04:53 +00:00
|
|
|
|
IColumn & res_data_col, ColumnArray::Offsets_t & res_offsets,
|
|
|
|
|
const ColumnNullable * nullable_col,
|
|
|
|
|
ColumnNullable * nullable_res_col);
|
2015-07-26 10:40:32 +00:00
|
|
|
|
|
|
|
|
|
bool executeString(
|
|
|
|
|
const IColumn & src_data, const ColumnArray::Offsets_t & src_array_offsets,
|
2016-09-19 16:04:53 +00:00
|
|
|
|
IColumn & res_data_col, ColumnArray::Offsets_t & res_array_offsets,
|
|
|
|
|
const ColumnNullable * nullable_col,
|
|
|
|
|
ColumnNullable * nullable_res_col);
|
2015-07-26 10:40:32 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-10-19 21:07:24 +00:00
|
|
|
|
class FunctionArrayReverse : public IFunction
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
static constexpr auto name = "reverse";
|
2016-08-11 16:47:28 +00:00
|
|
|
|
static FunctionPtr create(const Context & context);
|
2015-10-19 21:07:24 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
String getName() const override;
|
2015-10-19 21:07:24 +00:00
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
size_t getNumberOfArguments() const override { return 1; }
|
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override;
|
2015-10-19 21:07:24 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override;
|
2015-10-19 21:07:24 +00:00
|
|
|
|
|
|
|
|
|
private:
|
2016-08-11 16:47:28 +00:00
|
|
|
|
bool executeConst(Block & block, const ColumnNumbers & arguments, size_t result);
|
2015-10-19 21:07:24 +00:00
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
bool executeNumber(
|
|
|
|
|
const IColumn & src_data, const ColumnArray::Offsets_t & src_offsets,
|
2016-09-19 16:57:52 +00:00
|
|
|
|
IColumn & res_data_col,
|
|
|
|
|
const ColumnNullable * nullable_col,
|
|
|
|
|
ColumnNullable * nullable_res_col);
|
2015-10-19 21:07:24 +00:00
|
|
|
|
|
|
|
|
|
bool executeFixedString(
|
|
|
|
|
const IColumn & src_data, const ColumnArray::Offsets_t & src_offsets,
|
2016-09-19 16:57:52 +00:00
|
|
|
|
IColumn & res_data_col,
|
|
|
|
|
const ColumnNullable * nullable_col,
|
|
|
|
|
ColumnNullable * nullable_res_col);
|
2015-10-19 21:07:24 +00:00
|
|
|
|
|
|
|
|
|
bool executeString(
|
|
|
|
|
const IColumn & src_data, const ColumnArray::Offsets_t & src_array_offsets,
|
2016-09-19 16:57:52 +00:00
|
|
|
|
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.
|
|
|
|
|
* If aggregate function has multiple arguments, then this function can be applied to multiple arrays with the same size.
|
2015-12-13 10:43:49 +00:00
|
|
|
|
*/
|
|
|
|
|
class FunctionArrayReduce : public IFunction
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
static constexpr auto name = "arrayReduce";
|
2016-08-11 16:47:28 +00:00
|
|
|
|
static FunctionPtr create(const Context & context);
|
2015-12-13 10:43:49 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
String getName() const override;
|
2015-12-13 10:43:49 +00:00
|
|
|
|
|
2016-12-29 19:38:10 +00:00
|
|
|
|
bool isVariadic() const override { return true; }
|
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
|
|
2016-07-06 09:47:55 +00:00
|
|
|
|
void getReturnTypeAndPrerequisitesImpl(
|
2015-12-13 10:43:49 +00:00
|
|
|
|
const ColumnsWithTypeAndName & arguments,
|
|
|
|
|
DataTypePtr & out_return_type,
|
2016-08-11 16:47:28 +00:00
|
|
|
|
std::vector<ExpressionAction> & out_prerequisites) override;
|
2015-12-13 10:43:49 +00:00
|
|
|
|
|
2016-08-11 16:47:28 +00:00
|
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override;
|
2015-12-13 10:43:49 +00:00
|
|
|
|
private:
|
|
|
|
|
AggregateFunctionPtr aggregate_function;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2014-11-12 17:23:26 +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
|
|
|
|
}
|