diff --git a/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h b/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h index ebc283c03fc..11ec01e52e4 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h @@ -9,6 +9,7 @@ #include #include +#include #include @@ -90,8 +91,11 @@ public: PointType left = static_cast &>(*columns[0]).getData()[row_num]; PointType right = static_cast &>(*columns[1]).getData()[row_num]; - this->data(place).value.push_back(std::make_pair(left, Int64(1)), arena); - this->data(place).value.push_back(std::make_pair(right, Int64(-1)), arena); + if (!isNaN(left)) + this->data(place).value.push_back(std::make_pair(left, Int64(1)), arena); + + if (!isNaN(right)) + this->data(place).value.push_back(std::make_pair(right, Int64(-1)), arena); } void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override @@ -133,7 +137,6 @@ public: /// const_cast because we will sort the array auto & array = const_cast::Array &>(this->data(place).value); - /// TODO NaNs? std::sort(array.begin(), array.end(), [](const auto & a, const auto & b) { return a.first < b.first; }); for (const auto & point_weight : array) diff --git a/dbms/src/AggregateFunctions/QuantileExact.h b/dbms/src/AggregateFunctions/QuantileExact.h index c134ad1653d..568ad8d0950 100644 --- a/dbms/src/AggregateFunctions/QuantileExact.h +++ b/dbms/src/AggregateFunctions/QuantileExact.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -32,7 +33,9 @@ struct QuantileExact void add(const Value & x) { - array.push_back(x); + /// We must skip NaNs as they are not compatible with comparison sorting. + if (!isNaN(x)) + array.push_back(x); } template diff --git a/dbms/src/AggregateFunctions/QuantileExactWeighted.h b/dbms/src/AggregateFunctions/QuantileExactWeighted.h index f524426392a..76e65f07dac 100644 --- a/dbms/src/AggregateFunctions/QuantileExactWeighted.h +++ b/dbms/src/AggregateFunctions/QuantileExactWeighted.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace DB @@ -33,12 +34,15 @@ struct QuantileExactWeighted void add(const Value & x) { - ++map[x]; + /// We must skip NaNs as they are not compatible with comparison sorting. + if (!isNaN(x)) + ++map[x]; } void add(const Value & x, const Weight & weight) { - map[x] += weight; + if (!isNaN(x)) + map[x] += weight; } void merge(const QuantileExactWeighted & rhs) diff --git a/dbms/src/AggregateFunctions/QuantilesCommon.h b/dbms/src/AggregateFunctions/QuantilesCommon.h index 53802834379..1f70fde74dd 100644 --- a/dbms/src/AggregateFunctions/QuantilesCommon.h +++ b/dbms/src/AggregateFunctions/QuantilesCommon.h @@ -4,6 +4,7 @@ #include #include +#include namespace DB @@ -12,6 +13,7 @@ namespace DB namespace ErrorCodes { extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int PARAMETER_OUT_OF_BOUND; } @@ -55,6 +57,10 @@ struct QuantileLevels for (size_t i = 0; i < size; ++i) { levels[i] = applyVisitor(FieldVisitorConvertToNumber(), params[i]); + + if (isNaN(levels[i]) || levels[i] < 0 || levels[i] > 1) + throw Exception("Quantile level is out of range [0..1]", ErrorCodes::PARAMETER_OUT_OF_BOUND); + permutation[i] = i; } diff --git a/dbms/src/AggregateFunctions/ReservoirSampler.h b/dbms/src/AggregateFunctions/ReservoirSampler.h index 77d9f7285b7..ad5bf10f48f 100644 --- a/dbms/src/AggregateFunctions/ReservoirSampler.h +++ b/dbms/src/AggregateFunctions/ReservoirSampler.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,9 @@ public: void insert(const T & v) { + if (isNaN(v)) + return; + sorted = false; ++total_values; if (samples.size() < sample_count) diff --git a/dbms/src/AggregateFunctions/ReservoirSamplerDeterministic.h b/dbms/src/AggregateFunctions/ReservoirSamplerDeterministic.h index bff3fcb78ea..44760d8e5a5 100644 --- a/dbms/src/AggregateFunctions/ReservoirSamplerDeterministic.h +++ b/dbms/src/AggregateFunctions/ReservoirSamplerDeterministic.h @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -66,6 +67,9 @@ public: void insert(const T & v, const UInt64 determinator) { + if (isNaN(v)) + return; + const UInt32 hash = intHash64(determinator); if (!good(hash)) return; diff --git a/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.reference b/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.reference new file mode 100644 index 00000000000..d00491fd7e5 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.reference @@ -0,0 +1 @@ +1 diff --git a/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.sql b/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.sql new file mode 100644 index 00000000000..c89883e356b --- /dev/null +++ b/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.sql @@ -0,0 +1 @@ +SELECT DISTINCT eq FROM (WITH range(number % 10) AS arr, arrayMap(x -> x = intDiv(number, 10) ? nan : x, arr) AS arr_with_nan, arrayFilter(x -> x != intDiv(number, 10), arr) AS arr_filtered SELECT number, arrayReduce('quantileExact', arr_with_nan) AS q1, arrayReduce('quantileExact', arr_filtered) AS q2, q1 = q2 AS eq FROM numbers(100)); \ No newline at end of file