2011-08-22 01:01:01 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <DB/DataTypes/DataTypesNumberFixed.h>
|
|
|
|
|
#include <DB/Functions/IFunction.h>
|
2014-02-13 10:24:56 +00:00
|
|
|
|
#include <DB/Functions/FunctionsArithmetic.h>
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/** Функции - логические связки: and, or, not, xor.
|
|
|
|
|
* Принимают любые числовые типы, возвращают UInt8, содержащий 0 или 1.
|
|
|
|
|
*/
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
template<typename B>
|
2011-08-22 01:01:01 +00:00
|
|
|
|
struct AndImpl
|
|
|
|
|
{
|
2014-02-21 16:32:52 +00:00
|
|
|
|
static inline bool isSaturable()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-24 07:37:13 +00:00
|
|
|
|
static inline bool isSaturatedValue(UInt8 a)
|
2014-02-21 16:32:52 +00:00
|
|
|
|
{
|
|
|
|
|
return !a;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
static inline UInt8 apply(UInt8 a, B b)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
return a && b;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
template<typename B>
|
2011-08-22 01:01:01 +00:00
|
|
|
|
struct OrImpl
|
|
|
|
|
{
|
2014-02-21 16:32:52 +00:00
|
|
|
|
static inline bool isSaturable()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-24 07:37:13 +00:00
|
|
|
|
static inline bool isSaturatedValue(UInt8 a)
|
2014-02-21 16:32:52 +00:00
|
|
|
|
{
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
static inline UInt8 apply(UInt8 a, B b)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
return a || b;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
2014-02-13 10:24:56 +00:00
|
|
|
|
};
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
template<typename B>
|
|
|
|
|
struct XorImpl
|
|
|
|
|
{
|
2014-02-21 16:32:52 +00:00
|
|
|
|
static inline bool isSaturable()
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-24 07:37:13 +00:00
|
|
|
|
static inline bool isSaturatedValue(UInt8 a)
|
2014-02-21 16:32:52 +00:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
static inline UInt8 apply(UInt8 a, B b)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
return (!a) != (!b);
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
2014-02-13 10:24:56 +00:00
|
|
|
|
};
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
template<typename A>
|
|
|
|
|
struct NotImpl
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using ResultType = UInt8;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
static inline UInt8 apply(A a)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
return !a;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using UInt8Container = ColumnUInt8::Container_t;
|
|
|
|
|
using UInt8ColumnPtrs = std::vector<const ColumnUInt8 *>;
|
2014-02-13 10:24:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Op, size_t N>
|
|
|
|
|
struct AssociativeOperationImpl
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
/// Выбрасывает N последних столбцов из in (если их меньше, то все) и кладет в result их комбинацию.
|
|
|
|
|
static void execute(UInt8ColumnPtrs & in, UInt8Container & result)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-04-22 22:52:00 +00:00
|
|
|
|
if (N > in.size())
|
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
AssociativeOperationImpl<Op, N - 1>::execute(in, result);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
AssociativeOperationImpl<Op, N> operation(in);
|
|
|
|
|
in.erase(in.end() - N, in.end());
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
size_t n = result.size();
|
|
|
|
|
for (size_t i = 0; i < n; ++i)
|
|
|
|
|
{
|
|
|
|
|
result[i] = operation.apply(i);
|
|
|
|
|
}
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
const UInt8Container & vec;
|
|
|
|
|
AssociativeOperationImpl<Op, N - 1> continuation;
|
|
|
|
|
|
|
|
|
|
/// Запоминает последние N столбцов из in.
|
|
|
|
|
AssociativeOperationImpl(UInt8ColumnPtrs & in)
|
|
|
|
|
: vec(in[in.size() - N]->getData()), continuation(in) {}
|
|
|
|
|
|
|
|
|
|
/// Возвращает комбинацию значений в i-й строке всех столбцов, запомненных в конструкторе.
|
|
|
|
|
inline UInt8 apply(size_t i) const
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-21 16:32:52 +00:00
|
|
|
|
if (Op::isSaturable())
|
|
|
|
|
{
|
|
|
|
|
UInt8 a = vec[i];
|
|
|
|
|
return Op::isSaturatedValue(a) ? a : continuation.apply(i);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return Op::apply(vec[i], continuation.apply(i));
|
|
|
|
|
}
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
template <typename Op>
|
|
|
|
|
struct AssociativeOperationImpl<Op, 1>
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
static void execute(UInt8ColumnPtrs & in, UInt8Container & result)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
throw Exception("Logical error: AssociativeOperationImpl<Op, 1>::execute called", ErrorCodes::LOGICAL_ERROR);
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
const UInt8Container & vec;
|
|
|
|
|
|
|
|
|
|
AssociativeOperationImpl(UInt8ColumnPtrs & in)
|
|
|
|
|
: vec(in[in.size() - 1]->getData()) {}
|
|
|
|
|
|
|
|
|
|
inline UInt8 apply(size_t i) const
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
return vec[i];
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
template <template <typename> class Impl, typename Name>
|
|
|
|
|
class FunctionAnyArityLogical : public IFunction
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-11-12 17:23:26 +00:00
|
|
|
|
public:
|
|
|
|
|
static constexpr auto name = Name::name;
|
|
|
|
|
static IFunction * create(const Context & context) { return new FunctionAnyArityLogical; };
|
|
|
|
|
|
2011-08-22 01:01:01 +00:00
|
|
|
|
private:
|
2014-02-13 10:24:56 +00:00
|
|
|
|
bool extractConstColumns(ColumnPlainPtrs & in, UInt8 & res)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
bool has_res = false;
|
|
|
|
|
for (int i = static_cast<int>(in.size()) - 1; i >= 0; --i)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
if (in[i]->isConst())
|
|
|
|
|
{
|
|
|
|
|
Field val = (*in[i])[0];
|
|
|
|
|
UInt8 x = !!val.get<UInt64>();
|
|
|
|
|
if (has_res)
|
|
|
|
|
{
|
|
|
|
|
res = Impl<UInt8>::apply(res, x);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
res = x;
|
|
|
|
|
has_res = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
in.erase(in.begin() + i);
|
|
|
|
|
}
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
2014-02-13 10:24:56 +00:00
|
|
|
|
return has_res;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
bool convertTypeToUInt8(const IColumn * column, UInt8Container & res)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-06-26 00:58:14 +00:00
|
|
|
|
auto col = typeid_cast<const ColumnVector<T> *>(column);
|
2014-02-13 10:24:56 +00:00
|
|
|
|
if (!col)
|
|
|
|
|
return false;
|
|
|
|
|
const typename ColumnVector<T>::Container_t & vec = col->getData();
|
|
|
|
|
size_t n = res.size();
|
|
|
|
|
for (size_t i = 0; i < n; ++i)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 11:32:45 +00:00
|
|
|
|
res[i] = !!vec[i];
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
2014-02-13 10:24:56 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
void convertToUInt8(const IColumn * column, UInt8Container & res)
|
|
|
|
|
{
|
|
|
|
|
if (!convertTypeToUInt8< Int8 >(column, res) &&
|
|
|
|
|
!convertTypeToUInt8< Int16>(column, res) &&
|
|
|
|
|
!convertTypeToUInt8< Int32>(column, res) &&
|
|
|
|
|
!convertTypeToUInt8< Int64>(column, res) &&
|
|
|
|
|
!convertTypeToUInt8< UInt16>(column, res) &&
|
|
|
|
|
!convertTypeToUInt8< UInt32>(column, res) &&
|
|
|
|
|
!convertTypeToUInt8< UInt64>(column, res) &&
|
|
|
|
|
!convertTypeToUInt8<Float32>(column, res) &&
|
|
|
|
|
!convertTypeToUInt8<Float64>(column, res))
|
|
|
|
|
throw Exception("Unexpected type of column: " + column->getName(), ErrorCodes::ILLEGAL_COLUMN);
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
bool executeUInt8Type(const UInt8Container & uint8_vec, IColumn * column, UInt8Container & res)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-06-26 00:58:14 +00:00
|
|
|
|
auto col = typeid_cast<const ColumnVector<T> *>(column);
|
2014-02-13 10:24:56 +00:00
|
|
|
|
if (!col)
|
|
|
|
|
return false;
|
|
|
|
|
const typename ColumnVector<T>::Container_t & other_vec = col->getData();
|
|
|
|
|
size_t n = res.size();
|
|
|
|
|
for (size_t i = 0; i < n; ++i)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
res[i] = Impl<T>::apply(uint8_vec[i], other_vec[i]);
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
2014-02-13 10:24:56 +00:00
|
|
|
|
return true;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
2014-02-13 10:24:56 +00:00
|
|
|
|
|
2014-02-13 11:21:06 +00:00
|
|
|
|
void executeUInt8Other(const UInt8Container & uint8_vec, IColumn * column, UInt8Container & res)
|
2014-02-13 10:24:56 +00:00
|
|
|
|
{
|
|
|
|
|
if (!executeUInt8Type< Int8 >(uint8_vec, column, res) &&
|
|
|
|
|
!executeUInt8Type< Int16>(uint8_vec, column, res) &&
|
|
|
|
|
!executeUInt8Type< Int32>(uint8_vec, column, res) &&
|
|
|
|
|
!executeUInt8Type< Int64>(uint8_vec, column, res) &&
|
|
|
|
|
!executeUInt8Type< UInt16>(uint8_vec, column, res) &&
|
|
|
|
|
!executeUInt8Type< UInt32>(uint8_vec, column, res) &&
|
|
|
|
|
!executeUInt8Type< UInt64>(uint8_vec, column, res) &&
|
|
|
|
|
!executeUInt8Type<Float32>(uint8_vec, column, res) &&
|
|
|
|
|
!executeUInt8Type<Float64>(uint8_vec, column, res))
|
|
|
|
|
throw Exception("Unexpected type of column: " + column->getName(), ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-22 01:01:01 +00:00
|
|
|
|
public:
|
|
|
|
|
/// Получить имя функции.
|
2015-10-11 23:36:45 +00:00
|
|
|
|
String getName() const override
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-11-12 17:23:26 +00:00
|
|
|
|
return name;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Получить типы результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение.
|
2015-10-11 23:36:45 +00:00
|
|
|
|
DataTypePtr getReturnType(const DataTypes & arguments) const override
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
if (arguments.size() < 2)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
|
2014-02-13 10:24:56 +00:00
|
|
|
|
+ toString(arguments.size()) + ", should be at least 2.",
|
2011-08-22 01:01:01 +00:00
|
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
|
2014-02-13 10:24:56 +00:00
|
|
|
|
for (size_t i = 0; i < arguments.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (!arguments[i]->isNumeric())
|
|
|
|
|
throw Exception("Illegal type ("
|
|
|
|
|
+ arguments[i]->getName()
|
|
|
|
|
+ ") of " + toString(i + 1) + " argument of function " + getName(),
|
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
}
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2016-05-28 07:48:40 +00:00
|
|
|
|
return std::make_shared<DataTypeUInt8>();
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Выполнить функцию над блоком.
|
2015-10-11 23:36:45 +00:00
|
|
|
|
void execute(Block & block, const ColumnNumbers & arguments, size_t result) override
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-02-13 10:24:56 +00:00
|
|
|
|
ColumnPlainPtrs in(arguments.size());
|
|
|
|
|
for (size_t i = 0; i < arguments.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
in[i] = &*block.getByPosition(arguments[i]).column;
|
|
|
|
|
}
|
|
|
|
|
size_t n = in[0]->size();
|
|
|
|
|
|
|
|
|
|
/// Скомбинируем все константные столбцы в одно значение.
|
|
|
|
|
UInt8 const_val = 0;
|
|
|
|
|
bool has_consts = extractConstColumns(in, const_val);
|
|
|
|
|
|
|
|
|
|
// Если это значение однозначно определяет результат, вернем его.
|
|
|
|
|
if (has_consts && (in.empty() || Impl<UInt8>::apply(const_val, 0) == Impl<UInt8>::apply(const_val, 1)))
|
|
|
|
|
{
|
|
|
|
|
if (!in.empty())
|
|
|
|
|
const_val = Impl<UInt8>::apply(const_val, 0);
|
2016-05-28 05:31:36 +00:00
|
|
|
|
auto col_res = std::make_shared<ColumnConst<UInt8>>(n, const_val);
|
2014-02-13 10:24:56 +00:00
|
|
|
|
block.getByPosition(result).column = col_res;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Если это значение - нейтральный элемент, забудем про него.
|
|
|
|
|
if (has_consts && Impl<UInt8>::apply(const_val, 0) == 0 && Impl<UInt8>::apply(const_val, 1) == 1)
|
|
|
|
|
has_consts = false;
|
|
|
|
|
|
2016-05-28 05:31:36 +00:00
|
|
|
|
auto col_res = std::make_shared<ColumnUInt8>();
|
2014-02-13 10:24:56 +00:00
|
|
|
|
block.getByPosition(result).column = col_res;
|
|
|
|
|
UInt8Container & vec_res = col_res->getData();
|
|
|
|
|
|
|
|
|
|
if (has_consts)
|
|
|
|
|
{
|
|
|
|
|
vec_res.assign(n, const_val);
|
2016-05-28 05:31:36 +00:00
|
|
|
|
in.push_back(col_res.get());
|
2014-02-13 10:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vec_res.resize(n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Разделим входные столбцы на UInt8 и остальные. Первые обработаем более эффективно.
|
|
|
|
|
/// col_res в каждый момент будет либо находится в конце uint8_in, либо не содержаться в uint8_in.
|
|
|
|
|
UInt8ColumnPtrs uint8_in;
|
|
|
|
|
ColumnPlainPtrs other_in;
|
|
|
|
|
for (IColumn * column : in)
|
|
|
|
|
{
|
2016-05-28 05:31:36 +00:00
|
|
|
|
if (auto uint8_column = typeid_cast<const ColumnUInt8 *>(column))
|
2014-02-13 10:24:56 +00:00
|
|
|
|
uint8_in.push_back(uint8_column);
|
|
|
|
|
else
|
|
|
|
|
other_in.push_back(column);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Нужен хотя бы один столбец в uint8_in, чтобы было с кем комбинировать столбцы из other_in.
|
|
|
|
|
if (uint8_in.empty())
|
|
|
|
|
{
|
|
|
|
|
if (other_in.empty())
|
|
|
|
|
throw Exception("Hello, I'm a bug", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
|
|
convertToUInt8(other_in.back(), vec_res);
|
|
|
|
|
other_in.pop_back();
|
2016-05-28 05:31:36 +00:00
|
|
|
|
uint8_in.push_back(col_res.get());
|
2014-02-13 10:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Эффективно скомбинируем все столбцы правильного типа.
|
|
|
|
|
while (uint8_in.size() > 1)
|
|
|
|
|
{
|
2014-02-20 07:55:41 +00:00
|
|
|
|
/// При большом размере блока объединять по 6 толбцов за проход быстрее всего.
|
|
|
|
|
/// При маленьком - чем больше, тем быстрее.
|
2014-02-21 16:32:52 +00:00
|
|
|
|
AssociativeOperationImpl<Impl<UInt8>, 10>::execute(uint8_in, vec_res);
|
2016-05-28 05:31:36 +00:00
|
|
|
|
uint8_in.push_back(col_res.get());
|
2014-02-13 10:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// По одному добавим все столбцы неправильного типа.
|
|
|
|
|
while (!other_in.empty())
|
|
|
|
|
{
|
2014-02-13 11:21:06 +00:00
|
|
|
|
executeUInt8Other(uint8_in[0]->getData(), other_in.back(), vec_res);
|
2014-02-13 10:24:56 +00:00
|
|
|
|
other_in.pop_back();
|
2016-05-28 05:31:36 +00:00
|
|
|
|
uint8_in[0] = col_res.get();
|
2014-02-13 10:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Такое возможно, если среди аргументов ровно один неконстантный, и он имеет тип UInt8.
|
2016-05-28 05:31:36 +00:00
|
|
|
|
if (uint8_in[0] != col_res.get())
|
2014-02-13 10:24:56 +00:00
|
|
|
|
{
|
|
|
|
|
vec_res.assign(uint8_in[0]->getData());
|
|
|
|
|
}
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <template <typename> class Impl, typename Name>
|
|
|
|
|
class FunctionUnaryLogical : public IFunction
|
|
|
|
|
{
|
2014-11-12 17:23:26 +00:00
|
|
|
|
public:
|
|
|
|
|
static constexpr auto name = Name::name;
|
|
|
|
|
static IFunction * create(const Context & context) { return new FunctionUnaryLogical; };
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2014-11-12 17:23:26 +00:00
|
|
|
|
private:
|
2011-08-22 01:01:01 +00:00
|
|
|
|
template <typename T>
|
2011-09-24 20:32:41 +00:00
|
|
|
|
bool executeType(Block & block, const ColumnNumbers & arguments, size_t result)
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-06-26 00:58:14 +00:00
|
|
|
|
if (ColumnVector<T> * col = typeid_cast<ColumnVector<T> *>(&*block.getByPosition(arguments[0]).column))
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2016-05-28 05:31:36 +00:00
|
|
|
|
auto col_res = std::make_shared<ColumnUInt8>();
|
2011-09-24 20:32:41 +00:00
|
|
|
|
block.getByPosition(result).column = col_res;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2016-05-28 05:31:36 +00:00
|
|
|
|
typename ColumnUInt8::Container_t & vec_res = col_res->getData();
|
2011-08-22 01:01:01 +00:00
|
|
|
|
vec_res.resize(col->getData().size());
|
2014-02-13 10:24:56 +00:00
|
|
|
|
UnaryOperationImpl<T, Impl<T> >::vector(col->getData(), vec_res);
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-06-26 00:58:14 +00:00
|
|
|
|
else if (ColumnConst<T> * col = typeid_cast<ColumnConst<T> *>(&*block.getByPosition(arguments[0]).column))
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
|
|
|
|
UInt8 res = 0;
|
2014-02-13 10:24:56 +00:00
|
|
|
|
UnaryOperationImpl<T, Impl<T> >::constant(col->getData(), res);
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2016-05-28 05:31:36 +00:00
|
|
|
|
auto col_res = std::make_shared<ColumnConst<UInt8>>(col->size(), res);
|
2011-09-24 20:32:41 +00:00
|
|
|
|
block.getByPosition(result).column = col_res;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/// Получить имя функции.
|
2015-10-11 23:36:45 +00:00
|
|
|
|
String getName() const override
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
2014-11-12 17:23:26 +00:00
|
|
|
|
return name;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Получить типы результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение.
|
2015-10-11 23:36:45 +00:00
|
|
|
|
DataTypePtr getReturnType(const DataTypes & arguments) const override
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
|
|
|
|
if (arguments.size() != 1)
|
|
|
|
|
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
|
2013-06-21 20:34:19 +00:00
|
|
|
|
+ toString(arguments.size()) + ", should be 1.",
|
2011-08-22 01:01:01 +00:00
|
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
|
|
|
|
|
if (!arguments[0]->isNumeric())
|
|
|
|
|
throw Exception("Illegal type ("
|
|
|
|
|
+ arguments[0]->getName()
|
|
|
|
|
+ ") of argument of function " + getName(),
|
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
|
2016-05-28 07:48:40 +00:00
|
|
|
|
return std::make_shared<DataTypeUInt8>();
|
2011-08-22 01:01:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Выполнить функцию над блоком.
|
2015-10-11 23:36:45 +00:00
|
|
|
|
void execute(Block & block, const ColumnNumbers & arguments, size_t result) override
|
2011-08-22 01:01:01 +00:00
|
|
|
|
{
|
|
|
|
|
if (!( executeType<UInt8>(block, arguments, result)
|
|
|
|
|
|| executeType<UInt16>(block, arguments, result)
|
|
|
|
|
|| executeType<UInt32>(block, arguments, result)
|
|
|
|
|
|| executeType<UInt64>(block, arguments, result)
|
|
|
|
|
|| executeType<Int8>(block, arguments, result)
|
|
|
|
|
|| executeType<Int16>(block, arguments, result)
|
|
|
|
|
|| executeType<Int32>(block, arguments, result)
|
|
|
|
|
|| executeType<Int64>(block, arguments, result)
|
|
|
|
|
|| executeType<Float32>(block, arguments, result)
|
|
|
|
|
|| executeType<Float64>(block, arguments, result)))
|
2011-08-28 00:31:30 +00:00
|
|
|
|
throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName()
|
|
|
|
|
+ " of argument of function " + getName(),
|
2011-08-22 01:01:01 +00:00
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2014-11-12 17:23:26 +00:00
|
|
|
|
struct NameAnd { static constexpr auto name = "and"; };
|
|
|
|
|
struct NameOr { static constexpr auto name = "or"; };
|
|
|
|
|
struct NameXor { static constexpr auto name = "xor"; };
|
|
|
|
|
struct NameNot { static constexpr auto name = "not"; };
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using FunctionAnd = FunctionAnyArityLogical <AndImpl, NameAnd>;
|
|
|
|
|
using FunctionOr = FunctionAnyArityLogical <OrImpl, NameOr> ;
|
|
|
|
|
using FunctionXor = FunctionAnyArityLogical <XorImpl, NameXor>;
|
|
|
|
|
using FunctionNot = FunctionUnaryLogical <NotImpl, NameNot>;
|
2011-08-22 01:01:01 +00:00
|
|
|
|
|
|
|
|
|
}
|