diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 40 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_test.cpp | 30 |
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); |