ClickHouse/dbms/src/Functions/FunctionsRound.h

655 lines
21 KiB
C++
Raw Normal View History

#pragma once
#include <Functions/FunctionsArithmetic.h>
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
#include <Functions/FunctionHelpers.h>
#include <IO/WriteHelpers.h>
2015-05-14 12:08:27 +00:00
#include <cmath>
#include <type_traits>
#include <array>
#include <ext/bit_cast.h>
#if __SSE4_1__
#include <smmintrin.h>
#endif
namespace DB
{
2017-06-13 02:06:53 +00:00
namespace ErrorCodes
{
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
}
2017-05-27 15:45:25 +00:00
/** Rounding Functions:
* round(x, N) - rounding to nearest (N = 0 by default). Use banker's rounding for floating point numbers.
* floor(x, N) is the largest number <= x (N = 0 by default).
* ceil(x, N) is the smallest number >= x (N = 0 by default).
* trunc(x, N) - is the largest by absolute value number that is not greater than x by absolute value (N = 0 by default).
*
* The value of the parameter N (scale):
2017-05-27 15:45:25 +00:00
* - N > 0: round to the number with N decimal places after the decimal point
* - N < 0: round to an integer with N zero characters
* - N = 0: round to an integer
*
* Type of the result is the type of argument.
* For integer arguments, when passing negative scale, overflow can occur.
* In that case, the behavior is implementation specific.
*
* roundToExp2 - down to the nearest power of two (see below);
*
* Deprecated functions:
* roundDuration - down to the nearest of: 0, 1, 10, 30, 60, 120, 180, 240, 300, 600, 1200, 1800, 3600, 7200, 18000, 36000;
* roundAge - down to the nearest of: 0, 18, 25, 35, 45, 55.
*/
template <typename T>
2017-12-25 04:01:46 +00:00
inline std::enable_if_t<std::is_integral_v<T> && (sizeof(T) <= sizeof(UInt32)), T>
roundDownToPowerOfTwo(T x)
{
return x <= 0 ? 0 : (T(1) << (31 - __builtin_clz(x)));
}
template <typename T>
2017-12-25 04:01:46 +00:00
inline std::enable_if_t<std::is_integral_v<T> && (sizeof(T) == sizeof(UInt64)), T>
roundDownToPowerOfTwo(T x)
{
return x <= 0 ? 0 : (T(1) << (63 - __builtin_clzll(x)));
}
template <typename T>
2017-12-25 04:01:46 +00:00
inline std::enable_if_t<std::is_same_v<T, Float32>, T>
roundDownToPowerOfTwo(T x)
{
return ext::bit_cast<T>(ext::bit_cast<UInt32>(x) & ~((1ULL << 23) - 1));
}
template <typename T>
2017-12-25 04:01:46 +00:00
inline std::enable_if_t<std::is_same_v<T, Float64>, T>
roundDownToPowerOfTwo(T x)
{
return ext::bit_cast<T>(ext::bit_cast<UInt64>(x) & ~((1ULL << 52) - 1));
}
/** For integer data types:
* - if number is greater than zero, round it down to nearest power of two (example: roundToExp2(100) = 64, roundToExp2(64) = 64);
* - otherwise, return 0.
*
* For floating point data types: zero out mantissa, but leave exponent.
* - if number is greater than zero, round it down to nearest power of two (example: roundToExp2(3) = 2);
* - negative powers are also used (example: roundToExp2(0.7) = 0.5);
* - if number is zero, return zero;
* - if number is less than zero, the result is symmetrical: roundToExp2(x) = -roundToExp2(-x). (example: roundToExp2(-0.3) = -0.25);
*/
template <typename T>
struct RoundToExp2Impl
{
using ResultType = T;
static inline T apply(T x)
{
return roundDownToPowerOfTwo<T>(x);
}
#if USE_EMBEDDED_COMPILER
static constexpr bool compilable = false;
#endif
};
2017-09-15 12:16:12 +00:00
template <typename A>
struct RoundDurationImpl
{
using ResultType = UInt16;
static inline ResultType apply(A x)
{
return x < 1 ? 0
: (x < 10 ? 1
: (x < 30 ? 10
: (x < 60 ? 30
: (x < 120 ? 60
: (x < 180 ? 120
: (x < 240 ? 180
: (x < 300 ? 240
: (x < 600 ? 300
: (x < 1200 ? 600
: (x < 1800 ? 1200
: (x < 3600 ? 1800
: (x < 7200 ? 3600
: (x < 18000 ? 7200
: (x < 36000 ? 18000
: 36000))))))))))))));
}
#if USE_EMBEDDED_COMPILER
static constexpr bool compilable = false;
#endif
};
2017-09-15 12:16:12 +00:00
template <typename A>
struct RoundAgeImpl
{
using ResultType = UInt8;
static inline ResultType apply(A x)
{
return x < 1 ? 0
: (x < 18 ? 17
: (x < 25 ? 18
: (x < 35 ? 25
: (x < 45 ? 35
: (x < 55 ? 45
: 55)))));
}
#if USE_EMBEDDED_COMPILER
static constexpr bool compilable = false;
#endif
};
2017-05-27 15:45:25 +00:00
/** This parameter controls the behavior of the rounding functions.
*/
enum class ScaleMode
{
Positive, // round to a number with N decimal places after the decimal point
Negative, // round to an integer with N zero characters
Zero, // round to an integer
};
2015-05-19 13:23:13 +00:00
enum class RoundingMode
{
#if __SSE4_1__
Round = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC,
Floor = _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC,
Ceil = _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC,
Trunc = _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC,
#else
Round = 8, /// Values are correspond to above just in case.
Floor = 9,
Ceil = 10,
Trunc = 11,
#endif
};
/** Rounding functions for integer values.
*/
template <typename T, RoundingMode rounding_mode, ScaleMode scale_mode>
struct IntegerRoundingComputation
{
static const size_t data_count = 1;
static size_t prepare(size_t scale)
{
return scale;
}
static ALWAYS_INLINE T computeImpl(T x, T scale)
{
switch (rounding_mode)
{
case RoundingMode::Trunc:
{
return x / scale * scale;
}
case RoundingMode::Floor:
{
if (x < 0)
x -= scale - 1;
return x / scale * scale;
}
case RoundingMode::Ceil:
{
if (x >= 0)
x += scale - 1;
return x / scale * scale;
}
case RoundingMode::Round:
{
bool negative = x < 0;
if (negative)
x = -x;
x = (x + scale / 2) / scale * scale;
if (negative)
x = -x;
return x;
}
default:
__builtin_unreachable();
}
}
static ALWAYS_INLINE T compute(T x, T scale)
{
switch (scale_mode)
{
case ScaleMode::Zero:
return x;
case ScaleMode::Positive:
return x;
case ScaleMode::Negative:
return computeImpl(x, scale);
default:
__builtin_unreachable();
}
}
static ALWAYS_INLINE void compute(const T * __restrict in, size_t scale, T * __restrict out)
{
*out = compute(*in, scale);
}
};
#if __SSE4_1__
template <typename T>
class BaseFloatRoundingComputation;
template <>
class BaseFloatRoundingComputation<Float32>
{
public:
using ScalarType = Float32;
using VectorType = __m128;
static const size_t data_count = 4;
static VectorType load(const ScalarType * in) { return _mm_loadu_ps(in); }
static VectorType load1(const ScalarType in) { return _mm_load1_ps(&in); }
static void store(ScalarType * out, VectorType val) { _mm_storeu_ps(out, val);}
static VectorType multiply(VectorType val, VectorType scale) { return _mm_mul_ps(val, scale); }
static VectorType divide(VectorType val, VectorType scale) { return _mm_div_ps(val, scale); }
template <RoundingMode mode> static VectorType apply(VectorType val) { return _mm_round_ps(val, int(mode)); }
static VectorType prepare(size_t scale)
{
return load1(scale);
}
};
template <>
class BaseFloatRoundingComputation<Float64>
{
public:
using ScalarType = Float64;
using VectorType = __m128d;
static const size_t data_count = 2;
2015-05-19 13:23:13 +00:00
static VectorType load(const ScalarType * in) { return _mm_loadu_pd(in); }
static VectorType load1(const ScalarType in) { return _mm_load1_pd(&in); }
static void store(ScalarType * out, VectorType val) { _mm_storeu_pd(out, val);}
static VectorType multiply(VectorType val, VectorType scale) { return _mm_mul_pd(val, scale); }
static VectorType divide(VectorType val, VectorType scale) { return _mm_div_pd(val, scale); }
template <RoundingMode mode> static VectorType apply(VectorType val) { return _mm_round_pd(val, int(mode)); }
static VectorType prepare(size_t scale)
{
return load1(scale);
}
};
#else
/// Implementation for ARM. Not vectorized.
inline float roundWithMode(float x, RoundingMode mode)
{
switch (mode)
{
case RoundingMode::Round: return roundf(x);
case RoundingMode::Floor: return floorf(x);
case RoundingMode::Ceil: return ceilf(x);
case RoundingMode::Trunc: return truncf(x);
2017-09-24 13:59:18 +00:00
default:
throw Exception("Logical error: unexpected 'mode' parameter passed to function roundWithMode", ErrorCodes::LOGICAL_ERROR);
}
}
inline double roundWithMode(double x, RoundingMode mode)
{
switch (mode)
{
case RoundingMode::Round: return round(x);
case RoundingMode::Floor: return floor(x);
case RoundingMode::Ceil: return ceil(x);
case RoundingMode::Trunc: return trunc(x);
2017-09-24 13:59:18 +00:00
default:
throw Exception("Logical error: unexpected 'mode' parameter passed to function roundWithMode", ErrorCodes::LOGICAL_ERROR);
}
}
template <typename T>
class BaseFloatRoundingComputation
{
public:
using ScalarType = T;
using VectorType = T;
static const size_t data_count = 1;
static VectorType load(const ScalarType * in) { return *in; }
static VectorType load1(const ScalarType in) { return in; }
static VectorType store(ScalarType * out, ScalarType val) { return *out = val;}
static VectorType multiply(VectorType val, VectorType scale) { return val * scale; }
static VectorType divide(VectorType val, VectorType scale) { return val / scale; }
template <RoundingMode mode> static VectorType apply(VectorType val) { return roundWithMode(val, mode); }
static VectorType prepare(size_t scale)
{
return load1(scale);
}
};
#endif
/** Implementation of low-level round-off functions for floating-point values.
*/
template <typename T, RoundingMode rounding_mode, ScaleMode scale_mode>
class FloatRoundingComputation : public BaseFloatRoundingComputation<T>
{
using Base = BaseFloatRoundingComputation<T>;
public:
static inline void compute(const T * __restrict in, const typename Base::VectorType & scale, T * __restrict out)
{
auto val = Base::load(in);
if (scale_mode == ScaleMode::Positive)
val = Base::multiply(val, scale);
else if (scale_mode == ScaleMode::Negative)
val = Base::divide(val, scale);
val = Base::template apply<rounding_mode>(val);
if (scale_mode == ScaleMode::Positive)
val = Base::divide(val, scale);
else if (scale_mode == ScaleMode::Negative)
val = Base::multiply(val, scale);
Base::store(out, val);
}
};
2015-05-19 13:23:13 +00:00
/** Implementing high-level rounding functions.
*/
template <typename T, RoundingMode rounding_mode, ScaleMode scale_mode>
struct FloatRoundingImpl
{
private:
using Op = FloatRoundingComputation<T, rounding_mode, scale_mode>;
using Data = std::array<T, Op::data_count>;
2015-05-19 13:23:13 +00:00
public:
static NO_INLINE void apply(const PaddedPODArray<T> & in, size_t scale, typename ColumnVector<T>::Container & out)
{
auto mm_scale = Op::prepare(scale);
const size_t data_count = std::tuple_size<Data>();
const T* end_in = in.data() + in.size();
const T* limit = in.data() + in.size() / data_count * data_count;
const T* __restrict p_in = in.data();
T* __restrict p_out = out.data();
while (p_in < limit)
{
Op::compute(p_in, mm_scale, p_out);
p_in += data_count;
p_out += data_count;
}
if (p_in < end_in)
{
Data tmp_src{{}};
Data tmp_dst;
size_t tail_size_bytes = (end_in - p_in) * sizeof(*p_in);
memcpy(&tmp_src, p_in, tail_size_bytes);
Op::compute(reinterpret_cast<T *>(&tmp_src), mm_scale, reinterpret_cast<T *>(&tmp_dst));
memcpy(p_out, &tmp_dst, tail_size_bytes);
}
}
};
2015-05-14 12:08:27 +00:00
template <typename T, RoundingMode rounding_mode, ScaleMode scale_mode>
struct IntegerRoundingImpl
{
private:
using Op = IntegerRoundingComputation<T, rounding_mode, scale_mode>;
using Data = T;
public:
template <size_t scale>
static NO_INLINE void applyImpl(const PaddedPODArray<T> & in, typename ColumnVector<T>::Container & out)
{
const T* end_in = in.data() + in.size();
const T* __restrict p_in = in.data();
T* __restrict p_out = out.data();
while (p_in < end_in)
{
Op::compute(p_in, scale, p_out);
++p_in;
++p_out;
}
}
static NO_INLINE void apply(const PaddedPODArray<T> & in, size_t scale, typename ColumnVector<T>::Container & out)
{
/// Manual function cloning for compiler to generate integer division by constant.
switch (scale)
{
case 1ULL: return applyImpl<1ULL>(in, out);
case 10ULL: return applyImpl<10ULL>(in, out);
case 100ULL: return applyImpl<100ULL>(in, out);
case 1000ULL: return applyImpl<1000ULL>(in, out);
case 10000ULL: return applyImpl<10000ULL>(in, out);
case 100000ULL: return applyImpl<100000ULL>(in, out);
case 1000000ULL: return applyImpl<1000000ULL>(in, out);
case 10000000ULL: return applyImpl<10000000ULL>(in, out);
case 100000000ULL: return applyImpl<100000000ULL>(in, out);
case 1000000000ULL: return applyImpl<1000000000ULL>(in, out);
case 10000000000ULL: return applyImpl<10000000000ULL>(in, out);
case 100000000000ULL: return applyImpl<100000000000ULL>(in, out);
case 1000000000000ULL: return applyImpl<1000000000000ULL>(in, out);
case 10000000000000ULL: return applyImpl<10000000000000ULL>(in, out);
case 100000000000000ULL: return applyImpl<100000000000000ULL>(in, out);
case 1000000000000000ULL: return applyImpl<1000000000000000ULL>(in, out);
case 10000000000000000ULL: return applyImpl<10000000000000000ULL>(in, out);
case 100000000000000000ULL: return applyImpl<100000000000000000ULL>(in, out);
case 1000000000000000000ULL: return applyImpl<1000000000000000000ULL>(in, out);
case 10000000000000000000ULL: return applyImpl<10000000000000000000ULL>(in, out);
default:
throw Exception("Logical error: unexpected 'scale' parameter passed to function IntegerRoundingComputation::compute",
ErrorCodes::LOGICAL_ERROR);
}
}
};
template <typename T, RoundingMode rounding_mode, ScaleMode scale_mode>
2017-12-25 04:01:46 +00:00
using FunctionRoundingImpl = std::conditional_t<std::is_floating_point_v<T>,
FloatRoundingImpl<T, rounding_mode, scale_mode>,
2017-12-25 04:01:46 +00:00
IntegerRoundingImpl<T, rounding_mode, scale_mode>>;
/** Select the appropriate processing algorithm depending on the scale.
*/
template <typename T, RoundingMode rounding_mode>
struct Dispatcher
{
static void apply(Block & block, const ColumnVector<T> * col, const ColumnNumbers & arguments, size_t result)
{
size_t scale = 1;
Int64 scale_arg = 0;
if (arguments.size() == 2)
{
const IColumn & scale_column = *block.getByPosition(arguments[1]).column;
if (!scale_column.isColumnConst())
throw Exception("Scale argument for rounding functions must be constant.", ErrorCodes::ILLEGAL_COLUMN);
Field scale_field = static_cast<const ColumnConst &>(scale_column).getField();
if (scale_field.getType() != Field::Types::UInt64
&& scale_field.getType() != Field::Types::Int64)
throw Exception("Scale argument for rounding functions must have integer type.", ErrorCodes::ILLEGAL_COLUMN);
scale_arg = scale_field.get<Int64>();
}
auto col_res = ColumnVector<T>::create();
typename ColumnVector<T>::Container & vec_res = col_res->getData();
vec_res.resize(col->getData().size());
if (vec_res.empty())
{
block.getByPosition(result).column = std::move(col_res);
return;
}
if (scale_arg == 0)
{
scale = 1;
FunctionRoundingImpl<T, rounding_mode, ScaleMode::Zero>::apply(col->getData(), scale, vec_res);
}
else if (scale_arg > 0)
{
scale = pow(10, scale_arg);
FunctionRoundingImpl<T, rounding_mode, ScaleMode::Positive>::apply(col->getData(), scale, vec_res);
}
else
{
scale = pow(10, -scale_arg);
FunctionRoundingImpl<T, rounding_mode, ScaleMode::Negative>::apply(col->getData(), scale, vec_res);
}
block.getByPosition(result).column = std::move(col_res);
}
};
2017-05-27 15:45:25 +00:00
/** A template for functions that round the value of an input parameter of type
* (U)Int8/16/32/64 or Float32/64, and accept an additional optional
* parameter (default is 0).
*/
template <typename Name, RoundingMode rounding_mode>
class FunctionRounding : public IFunction
{
public:
static constexpr auto name = Name::name;
2017-12-02 02:47:12 +00:00
static FunctionPtr create(const Context &) { return std::make_shared<FunctionRounding>(); }
private:
2017-09-15 12:16:12 +00:00
template <typename T>
bool executeForType(Block & block, const ColumnNumbers & arguments, size_t result)
{
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
if (auto col = checkAndGetColumn<ColumnVector<T>>(block.getByPosition(arguments[0]).column.get()))
{
Dispatcher<T, rounding_mode>::apply(block, col, arguments, result);
return true;
}
return false;
}
2015-05-14 12:08:27 +00:00
public:
String getName() const override
{
return name;
}
bool isVariadic() const override { return true; }
size_t getNumberOfArguments() const override { return 0; }
2017-05-27 15:45:25 +00:00
/// Get result types by argument types. If the function does not apply to these arguments, throw an exception.
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
if ((arguments.size() < 1) || (arguments.size() > 2))
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
+ toString(arguments.size()) + ", should be 1 or 2.",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
for (const auto & type : arguments)
if (!isNumber(type))
throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
return arguments[0];
}
bool useDefaultImplementationForConstants() const override { return true; }
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
2018-04-24 07:16:39 +00:00
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
{
if (!( executeForType<UInt8>(block, arguments, result)
|| executeForType<UInt16>(block, arguments, result)
|| executeForType<UInt32>(block, arguments, result)
|| executeForType<UInt64>(block, arguments, result)
|| executeForType<Int8>(block, arguments, result)
|| executeForType<Int16>(block, arguments, result)
|| executeForType<Int32>(block, arguments, result)
|| executeForType<Int64>(block, arguments, result)
|| executeForType<Float32>(block, arguments, result)
|| executeForType<Float64>(block, arguments, result)))
{
ColumnConst unification (#1011) * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * Fixed error in ColumnArray::replicateGeneric [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150]. * ColumnConst: unification (incomplete) [#CLICKHOUSE-3150].
2017-07-21 06:35:58 +00:00
throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName()
+ " of argument of function " + getName(),
ErrorCodes::ILLEGAL_COLUMN);
}
}
bool hasInformationAboutMonotonicity() const override
{
return true;
}
2017-12-02 02:47:12 +00:00
Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override
{
return { true, true, true };
}
};
2015-05-14 12:08:27 +00:00
struct NameRoundToExp2 { static constexpr auto name = "roundToExp2"; };
struct NameRoundDuration { static constexpr auto name = "roundDuration"; };
struct NameRoundAge { static constexpr auto name = "roundAge"; };
struct NameRound { static constexpr auto name = "round"; };
struct NameCeil { static constexpr auto name = "ceil"; };
struct NameFloor { static constexpr auto name = "floor"; };
struct NameTrunc { static constexpr auto name = "trunc"; };
using FunctionRoundToExp2 = FunctionUnaryArithmetic<RoundToExp2Impl, NameRoundToExp2, false>;
using FunctionRoundDuration = FunctionUnaryArithmetic<RoundDurationImpl, NameRoundDuration, false>;
using FunctionRoundAge = FunctionUnaryArithmetic<RoundAgeImpl, NameRoundAge, false>;
using FunctionRound = FunctionRounding<NameRound, RoundingMode::Round>;
using FunctionFloor = FunctionRounding<NameFloor, RoundingMode::Floor>;
using FunctionCeil = FunctionRounding<NameCeil, RoundingMode::Ceil>;
using FunctionTrunc = FunctionRounding<NameTrunc, RoundingMode::Trunc>;
struct PositiveMonotonicity
{
static bool has() { return true; }
2017-12-02 02:47:12 +00:00
static IFunction::Monotonicity get(const Field &, const Field &)
{
return { true };
}
};
template <> struct FunctionUnaryArithmeticMonotonicity<NameRoundToExp2> : PositiveMonotonicity {};
template <> struct FunctionUnaryArithmeticMonotonicity<NameRoundDuration> : PositiveMonotonicity {};
template <> struct FunctionUnaryArithmeticMonotonicity<NameRoundAge> : PositiveMonotonicity {};
}