SERVER-126799: Filter NaN from $percentile/$median window function inputs (#53849)
GitOrigin-RevId: 37e218058da9f66347691c029f86de3e045fdd8e
This commit is contained in:
parent
3e584f02f3
commit
7786bd7265
@ -1367,6 +1367,7 @@ mongo_cc_unit_test(
|
||||
"//src/mongo/db/pipeline/window_function:window_function_min_max_scaler_util_test.cpp",
|
||||
"//src/mongo/db/pipeline/window_function:window_function_min_max_test.cpp",
|
||||
"//src/mongo/db/pipeline/window_function:window_function_n_test.cpp",
|
||||
"//src/mongo/db/pipeline/window_function:window_function_percentile_test.cpp",
|
||||
"//src/mongo/db/pipeline/window_function:window_function_push_test.cpp",
|
||||
"//src/mongo/db/pipeline/window_function:window_function_set_union_test.cpp",
|
||||
"//src/mongo/db/pipeline/window_function:window_function_std_dev_test.cpp",
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
|
||||
#include "mongo/db/pipeline/window_function/window_function_percentile.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace mongo {
|
||||
|
||||
void WindowFunctionPercentileCommon::add(Value value) {
|
||||
@ -36,7 +38,13 @@ void WindowFunctionPercentileCommon::add(Value value) {
|
||||
if (!value.numeric()) {
|
||||
return;
|
||||
}
|
||||
_values.insert(value.coerceToDouble());
|
||||
const double d = value.coerceToDouble();
|
||||
// NaN violates the strict-weak-ordering required by boost::container::flat_multiset
|
||||
// and would corrupt _values, so skip it (matching AccuratePercentile::incorporate).
|
||||
if (std::isnan(d)) {
|
||||
return;
|
||||
}
|
||||
_values.insert(d);
|
||||
_memUsageTracker.add(sizeof(double));
|
||||
}
|
||||
|
||||
@ -45,8 +53,12 @@ void WindowFunctionPercentileCommon::remove(Value value) {
|
||||
if (!value.numeric()) {
|
||||
return;
|
||||
}
|
||||
const double d = value.coerceToDouble();
|
||||
if (std::isnan(d)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = _values.find(value.coerceToDouble());
|
||||
auto iter = _values.find(d);
|
||||
tassert(7455904,
|
||||
"Cannot remove a value not tracked by WindowFunctionPercentile",
|
||||
iter != _values.end());
|
||||
|
||||
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (C) 2026-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#include "mongo/db/pipeline/window_function/window_function_percentile.h"
|
||||
|
||||
#include "mongo/db/exec/document_value/document_value_test_util.h"
|
||||
#include "mongo/db/pipeline/aggregation_context_fixture.h"
|
||||
#include "mongo/platform/decimal128.h"
|
||||
#include "mongo/unittest/unittest.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace mongo {
|
||||
namespace {
|
||||
|
||||
class WindowFunctionPercentileTest : public AggregationContextFixture {
|
||||
public:
|
||||
WindowFunctionPercentileTest()
|
||||
: expCtx(getExpCtx()),
|
||||
medianApprox(expCtx.get(), PercentileMethodEnum::kApproximate),
|
||||
medianDiscrete(expCtx.get(), PercentileMethodEnum::kDiscrete) {}
|
||||
|
||||
const double kNaN = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
boost::intrusive_ptr<ExpressionContext> expCtx;
|
||||
WindowFunctionMedian medianApprox;
|
||||
WindowFunctionMedian medianDiscrete;
|
||||
};
|
||||
|
||||
TEST_F(WindowFunctionPercentileTest, NaNOnlyWindowReturnsNull) {
|
||||
medianApprox.add(Value(kNaN));
|
||||
medianApprox.add(Value(kNaN));
|
||||
ASSERT_VALUE_EQ(medianApprox.getValue(), Value{BSONNULL});
|
||||
}
|
||||
|
||||
TEST_F(WindowFunctionPercentileTest, NaNMixedWithFiniteFiltered) {
|
||||
medianApprox.add(Value(1.0));
|
||||
medianApprox.add(Value(kNaN));
|
||||
medianApprox.add(Value(2.0));
|
||||
ASSERT_VALUE_EQ(medianApprox.getValue(), Value(1.0));
|
||||
}
|
||||
|
||||
TEST_F(WindowFunctionPercentileTest, RemoveFiniteAfterNaNDoesNotCorrupt) {
|
||||
medianDiscrete.add(Value(1.0));
|
||||
medianDiscrete.add(Value(kNaN));
|
||||
medianDiscrete.remove(Value(1.0));
|
||||
medianDiscrete.add(Value(3.0));
|
||||
ASSERT_VALUE_EQ(medianDiscrete.getValue(), Value(3.0));
|
||||
}
|
||||
|
||||
TEST_F(WindowFunctionPercentileTest, DecimalNaNIsFiltered) {
|
||||
medianApprox.add(Value(1.0));
|
||||
medianApprox.add(Value(Decimal128::kPositiveNaN));
|
||||
medianApprox.add(Value(3.0));
|
||||
medianApprox.remove(Value(Decimal128::kPositiveNaN));
|
||||
ASSERT_VALUE_EQ(medianApprox.getValue(), Value(1.0));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mongo
|
||||
Loading…
Reference in New Issue
Block a user