Making Monotonicity an aggregate to use with designated initializers

This commit is contained in:
Mike Kot 2021-09-29 18:01:26 +02:00
parent 340fb049cf
commit 61e0c6208b
18 changed files with 54 additions and 57 deletions

View File

@ -130,20 +130,17 @@ public:
Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override
{ {
IFunction::Monotonicity is_monotonic{true}; if constexpr (std::is_same_v<typename Transform::FactorTransform, ZeroTransform>)
IFunction::Monotonicity is_not_monotonic; return { .is_monotonic = true, .is_always_monotonic = true };
if (std::is_same_v<typename Transform::FactorTransform, ZeroTransform>) const IFunction::Monotonicity is_monotonic = { .is_monotonic = true };
{ const IFunction::Monotonicity is_not_monotonic;
is_monotonic.is_always_monotonic = true;
return is_monotonic;
}
/// This method is called only if the function has one argument. Therefore, we do not care about the non-local time zone. /// This method is called only if the function has one argument. Therefore, we do not care about the non-local time zone.
const DateLUTImpl & date_lut = DateLUT::instance(); const DateLUTImpl & date_lut = DateLUT::instance();
if (left.isNull() || right.isNull()) if (left.isNull() || right.isNull())
return is_not_monotonic; return {};
/// The function is monotonous on the [left, right] segment, if the factor transformation returns the same values for them. /// The function is monotonous on the [left, right] segment, if the factor transformation returns the same values for them.

View File

@ -128,14 +128,11 @@ public:
Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override
{ {
IFunction::Monotonicity is_monotonic { true }; if constexpr (std::is_same_v<typename Transform::FactorTransform, ZeroTransform>)
IFunction::Monotonicity is_not_monotonic; return { .is_monotonic = true, .is_always_monotonic = true };
if (std::is_same_v<typename Transform::FactorTransform, ZeroTransform>) const IFunction::Monotonicity is_monotonic = { .is_monotonic = true };
{ const IFunction::Monotonicity is_not_monotonic;
is_monotonic.is_always_monotonic = true;
return is_monotonic;
}
/// This method is called only if the function has one argument. Therefore, we do not care about the non-local time zone. /// This method is called only if the function has one argument. Therefore, we do not care about the non-local time zone.
const DateLUTImpl & date_lut = DateLUT::instance(); const DateLUTImpl & date_lut = DateLUT::instance();

View File

@ -290,7 +290,7 @@ struct PositiveMonotonicity
static bool has() { return true; } static bool has() { return true; }
static IFunction::Monotonicity get(const Field &, const Field &) static IFunction::Monotonicity get(const Field &, const Field &)
{ {
return { true }; return { .is_monotonic = true };
} }
}; };

View File

@ -1954,7 +1954,7 @@ struct PositiveMonotonicity
static bool has() { return true; } static bool has() { return true; }
static IFunction::Monotonicity get(const IDataType &, const Field &, const Field &) static IFunction::Monotonicity get(const IDataType &, const Field &, const Field &)
{ {
return { true }; return { .is_monotonic = true };
} }
}; };
@ -1963,7 +1963,7 @@ struct UnknownMonotonicity
static bool has() { return false; } static bool has() { return false; }
static IFunction::Monotonicity get(const IDataType &, const Field &, const Field &) static IFunction::Monotonicity get(const IDataType &, const Field &, const Field &)
{ {
return { false }; return { };
} }
}; };
@ -1989,13 +1989,13 @@ struct ToNumberMonotonicity
/// (Enum has separate case, because it is different data type) /// (Enum has separate case, because it is different data type)
if (checkAndGetDataType<DataTypeNumber<T>>(&type) || if (checkAndGetDataType<DataTypeNumber<T>>(&type) ||
checkAndGetDataType<DataTypeEnum<T>>(&type)) checkAndGetDataType<DataTypeEnum<T>>(&type))
return { true, true, true }; return { .is_monotonic = true, .is_always_monotonic = true };
/// Float cases. /// Float cases.
/// When converting to Float, the conversion is always monotonic. /// When converting to Float, the conversion is always monotonic.
if (std::is_floating_point_v<T>) if constexpr (std::is_floating_point_v<T>)
return {true, true, true}; return { .is_monotonic = true, .is_always_monotonic = true };
/// If converting from Float, for monotonicity, arguments must fit in range of result type. /// If converting from Float, for monotonicity, arguments must fit in range of result type.
if (WhichDataType(type).isFloat()) if (WhichDataType(type).isFloat())
@ -2010,7 +2010,7 @@ struct ToNumberMonotonicity
&& left_float <= static_cast<Float64>(std::numeric_limits<T>::max()) && left_float <= static_cast<Float64>(std::numeric_limits<T>::max())
&& right_float >= static_cast<Float64>(std::numeric_limits<T>::min()) && right_float >= static_cast<Float64>(std::numeric_limits<T>::min())
&& right_float <= static_cast<Float64>(std::numeric_limits<T>::max())) && right_float <= static_cast<Float64>(std::numeric_limits<T>::max()))
return { true }; return { .is_monotonic = true };
return {}; return {};
} }
@ -2035,10 +2035,10 @@ struct ToNumberMonotonicity
if (size_of_from == size_of_to) if (size_of_from == size_of_to)
{ {
if (from_is_unsigned == to_is_unsigned) if (from_is_unsigned == to_is_unsigned)
return {true, true, true}; return { .is_monotonic = true, .is_always_monotonic = true };
if (left_in_first_half == right_in_first_half) if (left_in_first_half == right_in_first_half)
return {true}; return { .is_monotonic = true };
return {}; return {};
} }
@ -2047,14 +2047,14 @@ struct ToNumberMonotonicity
if (size_of_from < size_of_to) if (size_of_from < size_of_to)
{ {
if (from_is_unsigned == to_is_unsigned) if (from_is_unsigned == to_is_unsigned)
return {true, true, true}; return { .is_monotonic = true, .is_always_monotonic = true };
if (!to_is_unsigned) if (!to_is_unsigned)
return {true, true, true}; return { .is_monotonic = true, .is_always_monotonic = true };
/// signed -> unsigned. If arguments from the same half, then function is monotonic. /// signed -> unsigned. If arguments from the same half, then function is monotonic.
if (left_in_first_half == right_in_first_half) if (left_in_first_half == right_in_first_half)
return {true}; return { .is_monotonic = true };
return {}; return {};
} }
@ -2071,10 +2071,14 @@ struct ToNumberMonotonicity
return {}; return {};
if (to_is_unsigned) if (to_is_unsigned)
return {true}; return { .is_monotonic = true };
else else
{
// If To is signed, it's possible that the signedness is different after conversion. So we check it explicitly. // If To is signed, it's possible that the signedness is different after conversion. So we check it explicitly.
return {(T(left.get<UInt64>()) >= 0) == (T(right.get<UInt64>()) >= 0)}; const bool is_monotonic = (T(left.get<UInt64>()) >= 0) == (T(right.get<UInt64>()) >= 0);
return { .is_monotonic = is_monotonic };
}
} }
__builtin_unreachable(); __builtin_unreachable();
@ -2089,7 +2093,7 @@ struct ToDateMonotonicity
{ {
auto which = WhichDataType(type); auto which = WhichDataType(type);
if (which.isDateOrDate32() || which.isDateTime() || which.isDateTime64() || which.isInt8() || which.isInt16() || which.isUInt8() || which.isUInt16()) if (which.isDateOrDate32() || which.isDateTime() || which.isDateTime64() || which.isInt8() || which.isInt16() || which.isUInt8() || which.isUInt16())
return {true, true, true}; return { .is_monotonic = true, .is_always_monotonic = true };
else if ( else if (
(which.isUInt() && ((left.isNull() || left.get<UInt64>() < 0xFFFF) && (right.isNull() || right.get<UInt64>() >= 0xFFFF))) (which.isUInt() && ((left.isNull() || left.get<UInt64>() < 0xFFFF) && (right.isNull() || right.get<UInt64>() >= 0xFFFF)))
|| (which.isInt() && ((left.isNull() || left.get<Int64>() < 0xFFFF) && (right.isNull() || right.get<Int64>() >= 0xFFFF))) || (which.isInt() && ((left.isNull() || left.get<Int64>() < 0xFFFF) && (right.isNull() || right.get<Int64>() >= 0xFFFF)))
@ -2097,7 +2101,7 @@ struct ToDateMonotonicity
|| !type.isValueRepresentedByNumber()) || !type.isValueRepresentedByNumber())
return {}; return {};
else else
return {true, true, true}; return { .is_monotonic = true, .is_always_monotonic = true };
} }
}; };
@ -2108,7 +2112,7 @@ struct ToDateTimeMonotonicity
static IFunction::Monotonicity get(const IDataType & type, const Field &, const Field &) static IFunction::Monotonicity get(const IDataType & type, const Field &, const Field &)
{ {
if (type.isValueRepresentedByNumber()) if (type.isValueRepresentedByNumber())
return {true, true, true}; return { .is_monotonic = true, .is_always_monotonic = true };
else else
return {}; return {};
} }
@ -2123,7 +2127,7 @@ struct ToStringMonotonicity
static IFunction::Monotonicity get(const IDataType & type, const Field & left, const Field & right) static IFunction::Monotonicity get(const IDataType & type, const Field & left, const Field & right)
{ {
IFunction::Monotonicity positive(true, true); IFunction::Monotonicity positive{ .is_monotonic = true };
IFunction::Monotonicity not_monotonic; IFunction::Monotonicity not_monotonic;
const auto * type_ptr = &type; const auto * type_ptr = &type;

View File

@ -614,7 +614,7 @@ public:
Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override
{ {
return { true, true, true }; return { .is_monotonic = true, .is_always_monotonic = true };
} }
}; };

View File

@ -250,12 +250,9 @@ public:
/// The property of monotonicity for a certain range. /// The property of monotonicity for a certain range.
struct Monotonicity struct Monotonicity
{ {
bool is_monotonic = false; /// Is the function monotonous (nondecreasing or nonincreasing). bool is_monotonic = false; /// Is the function monotonous (non-decreasing or non-increasing).
bool is_positive = true; /// true if the function is nondecreasing, false, if notincreasing. If is_monotonic = false, then it does not matter. bool is_positive = true; /// true if the function is non-decreasing, false if non-increasing. If is_monotonic = false, then it does not matter.
bool is_always_monotonic = false; /// Is true if function is monotonic on the whole input range I bool is_always_monotonic = false; /// Is true if function is monotonic on the whole input range I
Monotonicity(bool is_monotonic_ = false, bool is_positive_ = true, bool is_always_monotonic_ = false)
: is_monotonic(is_monotonic_), is_positive(is_positive_), is_always_monotonic(is_always_monotonic_) {}
}; };
/** Get information about monotonicity on a range of values. Call only if hasInformationAboutMonotonicity. /** Get information about monotonicity on a range of values. Call only if hasInformationAboutMonotonicity.

View File

@ -46,7 +46,7 @@ template <> struct FunctionUnaryArithmeticMonotonicity<NameAbs>
if ((left_float < 0 && right_float > 0) || (left_float > 0 && right_float < 0)) if ((left_float < 0 && right_float > 0) || (left_float > 0 && right_float < 0))
return {}; return {};
return { true, (left_float > 0) }; return { .is_monotonic = true, .is_positive = left_float > 0 };
} }
}; };

View File

@ -143,7 +143,7 @@ public:
Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override
{ {
return { true, true, true }; return { .is_monotonic = true, .is_always_monotonic = true };
} }
private: private:

View File

@ -139,10 +139,7 @@ namespace DB
Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override
{ {
return Monotonicity( return { .is_monotonic = true, .is_always_monotonic = true };
true, // is_monotonic
true, // is_positive
true); // is_always_monotonic
} }
private: private:

View File

@ -55,7 +55,7 @@ template <> struct FunctionUnaryArithmeticMonotonicity<NameIntExp10>
if (left_float < 0 || right_float > 19) if (left_float < 0 || right_float > 19)
return {}; return {};
return { true }; return { .is_monotonic = true };
} }
}; };

View File

@ -58,7 +58,7 @@ template <> struct FunctionUnaryArithmeticMonotonicity<NameIntExp2>
if (left_float < 0 || right_float > 63) if (left_float < 0 || right_float > 63)
return {}; return {};
return { true }; return { .is_monotonic = true };
} }
}; };

View File

@ -42,7 +42,7 @@ template <> struct FunctionUnaryArithmeticMonotonicity<NameNegate>
static bool has() { return true; } static bool has() { return true; }
static IFunction::Monotonicity get(const Field &, const Field &) static IFunction::Monotonicity get(const Field &, const Field &)
{ {
return { true, false }; return { .is_monotonic = true, .is_positive = false };
} }
}; };

View File

@ -37,7 +37,10 @@ template <>
struct FunctionUnaryArithmeticMonotonicity<NameSign> struct FunctionUnaryArithmeticMonotonicity<NameSign>
{ {
static bool has() { return true; } static bool has() { return true; }
static IFunction::Monotonicity get(const Field &, const Field &) { return {true, true, false}; } static IFunction::Monotonicity get(const Field &, const Field &)
{
return { .is_monotonic = true };
}
}; };
void registerFunctionSign(FunctionFactory & factory) void registerFunctionSign(FunctionFactory & factory)

View File

@ -157,10 +157,7 @@ namespace DB
Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override
{ {
return Monotonicity( return { .is_monotonic = true, .is_always_monotonic = true };
true, // is_monotonic
true, // is_positive
true); // is_always_monotonic
} }
private: private:

View File

@ -311,7 +311,7 @@ public:
Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override
{ {
return { true, true, true }; return { .is_monotonic = true, .is_always_monotonic = true };
} }
private: private:

View File

@ -66,7 +66,8 @@ public:
Monotonicity getMonotonicityForRange(const IDataType & /*type*/, const Field & /*left*/, const Field & /*right*/) const override Monotonicity getMonotonicityForRange(const IDataType & /*type*/, const Field & /*left*/, const Field & /*right*/) const override
{ {
return {is_constant_timezone, is_constant_timezone, is_constant_timezone}; const bool b = is_constant_timezone;
return { .is_monotonic = b, .is_positive = b, .is_always_monotonic = b };
} }
private: private:

View File

@ -239,7 +239,9 @@ public:
const IDataType * type_ptr = &type; const IDataType * type_ptr = &type;
Field left_mut = left; Field left_mut = left;
Field right_mut = right; Field right_mut = right;
Monotonicity result(true, true, true);
Monotonicity result = { .is_monotonic = true, .is_positive = true, .is_always_monotonic = true };
/// monotonicity is only defined for unary functions, so the chain must describe a sequence of nested calls /// monotonicity is only defined for unary functions, so the chain must describe a sequence of nested calls
for (size_t i = 0; i < nested_functions.size(); ++i) for (size_t i = 0; i < nested_functions.size(); ++i)
{ {

View File

@ -28,7 +28,9 @@ public:
const TablesWithColumns & tables; const TablesWithColumns & tables;
ContextPtr context; ContextPtr context;
const std::unordered_set<String> & group_by_function_hashes; const std::unordered_set<String> & group_by_function_hashes;
Monotonicity monotonicity{true, true, true};
Monotonicity monotonicity = { .is_monotonic = true, .is_positive = true, .is_always_monotonic = true };
ASTIdentifier * identifier = nullptr; ASTIdentifier * identifier = nullptr;
DataTypePtr arg_data_type = {}; DataTypePtr arg_data_type = {};