summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/window_function
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-18 17:02:53 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-18 17:02:53 -0300
commit959575a5ca598bf5f37fb5cebe7ed1d80d3d71f7 (patch)
treeacc8d60aedb12b70048e676e8a7349deb0010db8 /src/mongo/db/pipeline/window_function
parent76588293975fc059cf076779e4283e6ffaf8afff (diff)
New upstream version 6.0.20upstream
Diffstat (limited to 'src/mongo/db/pipeline/window_function')
-rw-r--r--src/mongo/db/pipeline/window_function/partition_iterator.cpp22
-rw-r--r--src/mongo/db/pipeline/window_function/window_bounds.cpp34
-rw-r--r--src/mongo/db/pipeline/window_function/window_bounds.h2
-rw-r--r--src/mongo/db/pipeline/window_function/window_function_expression.cpp6
-rw-r--r--src/mongo/db/pipeline/window_function/window_function_expression.h35
-rw-r--r--src/mongo/db/pipeline/window_function/window_function_shift.cpp10
-rw-r--r--src/mongo/db/pipeline/window_function/window_function_shift.h2
7 files changed, 65 insertions, 46 deletions
diff --git a/src/mongo/db/pipeline/window_function/partition_iterator.cpp b/src/mongo/db/pipeline/window_function/partition_iterator.cpp
index 83925b862b3..6188845d516 100644
--- a/src/mongo/db/pipeline/window_function/partition_iterator.cpp
+++ b/src/mongo/db/pipeline/window_function/partition_iterator.cpp
@@ -205,15 +205,6 @@ optional<int> numericBound(WindowBounds::Bound<int> bound) {
bound);
}
-// Assumes both arguments are numeric, and performs Decimal128 addition on them.
-Value decimalAdd(const Value& left, const Value& right) {
- // Widening to Decimal128 is a convenient way to avoid having many cases for different numeric
- // types. The 'threshold' values we compute are only used to choose a set of documents; the
- // user can't observe the type.
- return Value(left.coerceToDecimal().add(right.coerceToDecimal()));
-}
-
-
} // namespace
optional<std::pair<int, int>> PartitionIterator::getEndpointsRangeBased(
@@ -247,7 +238,18 @@ optional<std::pair<int, int>> PartitionIterator::getEndpointsRangeBased(
dateAdd(base.coerceToDate(), *range.unit, delta.coerceToInt(), TimeZone())};
} else {
tassert(5429406, "Range-based bounds are specified as a number", delta.numeric());
- return decimalAdd(base, delta);
+ if (base.getType() == BSONType::NumberDouble) {
+ // When we compare a double and a Decimal128, we convert the Decimal128 to double
+ // and compare two double values. Since converting a double to Decimal128 is
+ // expensive and since during the comparison we will convert the Decimal128 to
+ // double, we compute the threshold as double from the beginning when the base
+ // value is already a double.
+ return Value(base.getDouble() + delta.coerceToDouble());
+ }
+ // Widening to Decimal128 is a convenient way to avoid having many cases for different
+ // numeric types. The 'threshold' values we compute are only used to choose a set of
+ // documents; the user can't observe the type.
+ return Value(base.coerceToDecimal().add(delta.coerceToDecimal()));
}
};
auto hasExpectedType = [&](const Value& v) -> bool {
diff --git a/src/mongo/db/pipeline/window_function/window_bounds.cpp b/src/mongo/db/pipeline/window_function/window_bounds.cpp
index dd082135e02..7ede49d0065 100644
--- a/src/mongo/db/pipeline/window_function/window_bounds.cpp
+++ b/src/mongo/db/pipeline/window_function/window_bounds.cpp
@@ -63,12 +63,19 @@ WindowBounds::Bound<T> parseBound(ExpressionContext* expCtx,
}
template <class T>
-Value serializeBound(const WindowBounds::Bound<T>& bound) {
+Value serializeBound(const WindowBounds::Bound<T>& bound,
+ const SerializationOptions& opts,
+ const Value& representativeValue) {
return stdx::visit(
visit_helper::Overloaded{
- [](const WindowBounds::Unbounded&) { return Value(WindowBounds::kValUnbounded); },
- [](const WindowBounds::Current&) { return Value(WindowBounds::kValCurrent); },
- [](const T& n) { return Value(n); },
+ [&](const WindowBounds::Unbounded&) { return Value(WindowBounds::kValUnbounded); },
+ [&](const WindowBounds::Current&) { return Value(WindowBounds::kValCurrent); },
+ [&](const T& n) {
+ // If not "unbounded" or "current", n must be a literal constant
+ // The upper bound must be greater than the lower bound. We override the
+ // representative value to meet this constraint.
+ return opts.serializeLiteral(n, representativeValue);
+ },
},
bound);
}
@@ -215,22 +222,31 @@ WindowBounds WindowBounds::parse(BSONObj args,
uassert(5339902,
"Range-based bounds require sortBy a single field",
sortBy && sortBy->size() == 1);
+ const SortPattern::SortPatternPart& part = *sortBy->begin();
+ uassert(8947400,
+ "Range-based bounds require a non-expression sortBy",
+ part.fieldPath && !part.expression);
+ uassert(8947401, "Range-based bounds require an ascending sortBy", part.isAscending);
return bounds;
}
}
-void WindowBounds::serialize(MutableDocument& args) const {
+void WindowBounds::serialize(MutableDocument& args, const SerializationOptions& opts) const {
stdx::visit(
visit_helper::Overloaded{
[&](const DocumentBased& docBounds) {
args[kArgDocuments] = Value{std::vector<Value>{
- serializeBound(docBounds.lower),
- serializeBound(docBounds.upper),
+ serializeBound(
+ docBounds.lower, opts, /* representative value, if needed */ Value(0LL)),
+ serializeBound(
+ docBounds.upper, opts, /* representative value, if needed */ Value(1LL)),
}};
},
[&](const RangeBased& rangeBounds) {
args[kArgRange] = Value{std::vector<Value>{
- serializeBound(rangeBounds.lower),
- serializeBound(rangeBounds.upper),
+ serializeBound(
+ rangeBounds.lower, opts, /* representative value, if needed */ Value(0LL)),
+ serializeBound(
+ rangeBounds.upper, opts, /* representative value, if needed */ Value(1LL)),
}};
if (rangeBounds.unit) {
args[kArgUnit] = Value{serializeTimeUnit(*rangeBounds.unit)};
diff --git a/src/mongo/db/pipeline/window_function/window_bounds.h b/src/mongo/db/pipeline/window_function/window_bounds.h
index 6999f8fcdbc..90d0adf0371 100644
--- a/src/mongo/db/pipeline/window_function/window_bounds.h
+++ b/src/mongo/db/pipeline/window_function/window_bounds.h
@@ -121,7 +121,7 @@ struct WindowBounds {
const boost::optional<SortPattern>& sortBy,
ExpressionContext* expCtx);
- void serialize(MutableDocument& args) const;
+ void serialize(MutableDocument& args, const SerializationOptions& opts) const;
};
} // namespace mongo
diff --git a/src/mongo/db/pipeline/window_function/window_function_expression.cpp b/src/mongo/db/pipeline/window_function/window_function_expression.cpp
index 0d43689c977..a46bac72dfa 100644
--- a/src/mongo/db/pipeline/window_function/window_function_expression.cpp
+++ b/src/mongo/db/pipeline/window_function/window_function_expression.cpp
@@ -310,12 +310,12 @@ boost::intrusive_ptr<Expression> ExpressionFirstLast::parse(
template <typename WindowFunctionN, typename AccumulatorNType>
Value ExpressionN<WindowFunctionN, AccumulatorNType>::serialize(
- boost::optional<ExplainOptions::Verbosity> explain) const {
+ const SerializationOptions& opts) const {
auto acc = buildAccumulatorOnly();
- MutableDocument result(acc->serialize(nExpr, _input, static_cast<bool>(explain)));
+ MutableDocument result(acc->serialize(nExpr, _input, opts));
MutableDocument windowField;
- _bounds.serialize(windowField);
+ _bounds.serialize(windowField, opts);
result[kWindowArg] = windowField.freezeToValue();
return result.freezeToValue();
}
diff --git a/src/mongo/db/pipeline/window_function/window_function_expression.h b/src/mongo/db/pipeline/window_function/window_function_expression.h
index 261d4212fe5..b14a81d1ae3 100644
--- a/src/mongo/db/pipeline/window_function/window_function_expression.h
+++ b/src/mongo/db/pipeline/window_function/window_function_expression.h
@@ -189,17 +189,16 @@ public:
}
};
- virtual Value serialize(boost::optional<ExplainOptions::Verbosity> explain) const {
+ virtual Value serialize(const SerializationOptions& opts) const {
MutableDocument args;
- args[_accumulatorName] = _input->serialize(static_cast<bool>(explain));
+ args[_accumulatorName] = _input->serialize(opts);
MutableDocument windowField;
- _bounds.serialize(windowField);
+ _bounds.serialize(windowField, opts);
args[kWindowArg] = windowField.freezeToValue();
return args.freezeToValue();
}
-
protected:
ExpressionContext* _expCtx;
std::string _accumulatorName;
@@ -326,9 +325,9 @@ public:
<< " is not supported as a removable window function");
}
- Value serialize(boost::optional<ExplainOptions::Verbosity> explain) const final {
+ Value serialize(const SerializationOptions& opts) const final {
MutableDocument args;
- args.addField(_accumulatorName, Value(_input->serialize(static_cast<bool>(explain))));
+ args.addField(_accumulatorName, Value(_input->serialize(opts)));
return args.freezeToValue();
}
};
@@ -444,7 +443,7 @@ public:
<< " is not supported with a removable window");
}
- Value serialize(boost::optional<ExplainOptions::Verbosity> explain) const final {
+ Value serialize(const SerializationOptions& opts) const final {
MutableDocument args;
args.addField(_accumulatorName, Value(Document()));
return args.freezeToValue();
@@ -493,15 +492,17 @@ public:
<< " is not supported with a removable window");
}
- Value serialize(boost::optional<ExplainOptions::Verbosity> explain) const final {
+ Value serialize(const SerializationOptions& opts) const final {
MutableDocument subObj;
tassert(5433604, "ExpMovingAvg neither N nor alpha was set", _N || _alpha);
if (_N) {
- subObj[kNArg] = Value(_N.get());
+ subObj[kNArg] = opts.serializeLiteral(_N.get());
} else {
- subObj[kAlphaArg] = Value(_alpha.get());
+ // Alpha must be between zero and one (exclusive), so choose a legal representative
+ // value if applicable.
+ subObj[kAlphaArg] = opts.serializeLiteral(_alpha.get(), Value(0.1));
}
- subObj[kInputArg] = _input->serialize(static_cast<bool>(explain));
+ subObj[kInputArg] = _input->serialize(opts);
MutableDocument outerObj;
outerObj[kAccName] = subObj.freezeToValue();
return outerObj.freezeToValue();
@@ -528,15 +529,15 @@ public:
return _unit;
}
- Value serialize(boost::optional<ExplainOptions::Verbosity> explain) const final {
+ Value serialize(const SerializationOptions& opts) const final {
MutableDocument result;
- result[_accumulatorName][kArgInput] = _input->serialize(static_cast<bool>(explain));
+ result[_accumulatorName][kArgInput] = _input->serialize(opts);
if (_unit) {
result[_accumulatorName][kArgUnit] = Value(serializeTimeUnit(*_unit));
}
MutableDocument windowField;
- _bounds.serialize(windowField);
+ _bounds.serialize(windowField, opts);
result[kWindowArg] = windowField.freezeToValue();
return result.freezeToValue();
}
@@ -810,9 +811,9 @@ public:
MONGO_UNREACHABLE_TASSERT(5490705);
}
- Value serialize(boost::optional<ExplainOptions::Verbosity> explain) const final {
+ Value serialize(const SerializationOptions& opts) const final {
MutableDocument args;
- args.addField(_accumulatorName, Value(_input->serialize(static_cast<bool>(explain))));
+ args.addField(_accumulatorName, Value(_input->serialize(opts)));
return args.freezeToValue();
}
};
@@ -904,7 +905,7 @@ public:
nExpr(std::move(nExpr)),
sortPattern(std::move(sortPattern)) {}
- Value serialize(boost::optional<ExplainOptions::Verbosity> explain) const final;
+ Value serialize(const SerializationOptions& opts) const final;
boost::intrusive_ptr<AccumulatorState> buildAccumulatorOnly() const final;
diff --git a/src/mongo/db/pipeline/window_function/window_function_shift.cpp b/src/mongo/db/pipeline/window_function/window_function_shift.cpp
index c74424e74e7..0ae15c4e3f0 100644
--- a/src/mongo/db/pipeline/window_function/window_function_shift.cpp
+++ b/src/mongo/db/pipeline/window_function/window_function_shift.cpp
@@ -119,12 +119,12 @@ boost::intrusive_ptr<Expression> ExpressionShift::parse(BSONObj obj,
return shiftExpr;
}
-Value ExpressionShift::serialize(boost::optional<ExplainOptions::Verbosity> explain) const {
+Value ExpressionShift::serialize(const SerializationOptions& opts) const {
MutableDocument args;
- args.addField(kByArg, Value(_offset));
- args.addField(kOutputArg, _input->serialize(static_cast<bool>(explain)));
- args.addField(kDefaultArg, _defaultVal.get_value_or(mongo::Value(BSONNULL)));
-
+ args.addField(kByArg, opts.serializeLiteral(_offset));
+ args.addField(kOutputArg, _input->serialize(opts));
+ args.addField(kDefaultArg,
+ opts.serializeLiteral(_defaultVal.get_value_or(mongo::Value(BSONNULL))));
MutableDocument windowFun;
windowFun.addField(_accumulatorName, args.freezeToValue());
return windowFun.freezeToValue();
diff --git a/src/mongo/db/pipeline/window_function/window_function_shift.h b/src/mongo/db/pipeline/window_function/window_function_shift.h
index 99a45dd3f84..649e90ce7e4 100644
--- a/src/mongo/db/pipeline/window_function/window_function_shift.h
+++ b/src/mongo/db/pipeline/window_function/window_function_shift.h
@@ -68,7 +68,7 @@ public:
MONGO_UNREACHABLE_TASSERT(5424302);
}
- Value serialize(boost::optional<ExplainOptions::Verbosity> explain) const final;
+ Value serialize(const SerializationOptions& opts) const final;
private:
static boost::intrusive_ptr<Expression> parseShiftArgs(BSONObj obj,