summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/pipeline/expression.cpp40
-rw-r--r--src/mongo/db/pipeline/expression_test.cpp30
2 files changed, 45 insertions, 25 deletions
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index cd9dad85e5b..d8ab5bce397 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -4843,32 +4843,24 @@ static Value evaluateRoundOrTrunc(const Document& root,
str::stream() << opName << " only supports numeric types, not "
<< typeName(numericArg.getType()),
numericArg.numeric());
- if (children.size() == 1) {
- switch (numericArg.getType()) {
- case BSONType::NumberDecimal:
- return Value(
- numericArg.getDecimal().quantize(Decimal128::kNormalizedZero, roundingMode));
- case BSONType::NumberDouble:
- return Value(doubleOp(numericArg.getDouble()));
- // There's no point to round/trunc integers or longs without precision argument, it will
- // have no effect.
- default:
- return numericArg;
+
+ long long precisionValue = 0;
+ if (children.size() > 1) {
+ auto precisionArg = Value(children[1]->evaluate(root));
+ if (precisionArg.nullish()) {
+ return Value(BSONNULL);
}
+ precisionValue = precisionArg.coerceToLong();
+ uassert(51082,
+ str::stream() << "precision argument to " << opName << " must be a integral value",
+ precisionArg.integral());
+ uassert(51083,
+ str::stream() << "cannot apply " << opName << " with precision value "
+ << precisionValue
+ << " value must be in [-20, 100]",
+ minPrecision <= precisionValue && precisionValue <= maxPrecision);
}
- // Else, if precision is specified, round to the specified precision.
- auto precisionArg = Value(children[1]->evaluate(root));
- if (precisionArg.nullish()) {
- return Value(BSONNULL);
- }
- uassert(51082,
- str::stream() << "precision argument to " << opName << " must be a integral value",
- precisionArg.integral());
- auto precisionValue = precisionArg.coerceToLong();
- uassert(51083,
- str::stream() << "cannot apply " << opName << " with precision value " << precisionValue
- << " value must be in [-20, 100]",
- minPrecision <= precisionValue && precisionValue <= maxPrecision);
+
// Construct 10^-precisionValue, which will be used as the quantize reference.
auto quantum = Decimal128(0LL, Decimal128::kExponentBias - precisionValue, 0LL, 1LL);
switch (numericArg.getType()) {
diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp
index ceff19672a2..58e1000ed08 100644
--- a/src/mongo/db/pipeline/expression_test.cpp
+++ b/src/mongo/db/pipeline/expression_test.cpp
@@ -997,8 +997,13 @@ TEST_F(ExpressionRoundOneArgTest, DoubleArg1) {
assertEval(-2.0, -2.0);
assertEval(0.9, 1.0);
assertEval(0.1, 0.0);
+ assertEval(1.5, 2.0);
+ assertEval(2.5, 2.0);
+ assertEval(3.5, 4.0);
assertEval(-1.2, -1.0);
assertEval(-1.7, -2.0);
+ assertEval(-1.5, -2.0);
+ assertEval(-2.5, -2.0);
// Outside the range of long longs (there isn't enough precision for decimals in this range, so
// should just preserve the number).
@@ -1013,8 +1018,13 @@ TEST_F(ExpressionRoundTwoArgTest, DoubleArg2) {
assertEval(-2.0, 2.0, -2.0);
assertEval(0.9, 0, 1.0);
assertEval(0.1, 0, 0.0);
+ assertEval(1.5, 0, 2.0);
+ assertEval(2.5, 0, 2.0);
+ assertEval(3.5, 0, 4.0);
assertEval(-1.2, 0, -1.0);
assertEval(-1.7, 0, -2.0);
+ assertEval(-1.5, 0, -2.0);
+ assertEval(-2.5, 0, -2.0);
assertEval(-3.14159265, 0, -3.0);
assertEval(-3.14159265, 1, -3.1);
@@ -1044,6 +1054,9 @@ TEST_F(ExpressionRoundOneArgTest, DecimalArg1) {
assertEval(Decimal128("-2"), Decimal128("-2.0"));
assertEval(Decimal128("0.9"), Decimal128("1.0"));
assertEval(Decimal128("0.1"), Decimal128("0.0"));
+ assertEval(Decimal128("0.5"), Decimal128("0.0"));
+ assertEval(Decimal128("1.5"), Decimal128("2.0"));
+ assertEval(Decimal128("2.5"), Decimal128("2.0"));
assertEval(Decimal128("-1.2"), Decimal128("-1.0"));
assertEval(Decimal128("-1.7"), Decimal128("-2.0"));
assertEval(Decimal128("123456789.9999999999999999999999999"), Decimal128("123456790"));
@@ -1057,6 +1070,9 @@ TEST_F(ExpressionRoundTwoArgTest, DecimalArg2) {
assertEval(Decimal128("-2"), 0, Decimal128("-2.0"));
assertEval(Decimal128("0.9"), 0, Decimal128("1.0"));
assertEval(Decimal128("0.1"), 0, Decimal128("0.0"));
+ assertEval(Decimal128("0.5"), 0, Decimal128("0.0"));
+ assertEval(Decimal128("1.5"), 0, Decimal128("2.0"));
+ assertEval(Decimal128("2.5"), 0, Decimal128("2.0"));
assertEval(Decimal128("-1.2"), 0, Decimal128("-1.0"));
assertEval(Decimal128("-1.7"), 0, Decimal128("-2.0"));
assertEval(Decimal128("123456789.9999999999999999999999999"), 0, Decimal128("123456790"));
@@ -1120,6 +1136,7 @@ public:
TEST_F(ExpressionTruncOneArgTest, IntArg1) {
assertEval(0, 0);
+ assertEval(0, 0);
assertEval(numeric_limits<int>::min(), numeric_limits<int>::min());
assertEval(numeric_limits<int>::max(), numeric_limits<int>::max());
}
@@ -1151,8 +1168,14 @@ TEST_F(ExpressionTruncOneArgTest, DoubleArg1) {
assertEval(-2.0, -2.0);
assertEval(0.9, 0.0);
assertEval(0.1, 0.0);
+ assertEval(0.5, 0.0);
+ assertEval(1.5, 1.0);
+ assertEval(2.5, 2.0);
assertEval(-1.2, -1.0);
assertEval(-1.7, -1.0);
+ assertEval(-0.5, -0.0);
+ assertEval(-1.5, -1.0);
+ assertEval(-2.5, -2.0);
// Outside the range of long longs (there isn't enough precision for decimals in this range, so
// should just preserve the number).
@@ -1167,9 +1190,14 @@ TEST_F(ExpressionTruncTwoArgTest, DoubleArg2) {
assertEval(-2.0, 2.0, -2.0);
assertEval(0.9, 0, 0.0);
assertEval(0.1, 0, 0.0);
+ assertEval(0.5, 0, 0.0);
+ assertEval(1.5, 0, 1.0);
+ assertEval(2.5, 0, 2.0);
assertEval(-1.2, 0, -1.0);
assertEval(-1.7, 0, -1.0);
-
+ assertEval(-0.5, 0, -0.0);
+ assertEval(-1.5, 0, -1.0);
+ assertEval(-2.5, 0, -2.0);
assertEval(-3.14159265, 0, -3.0);
assertEval(-3.14159265, 1, -3.1);