summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/matcher/expression_algo_test.cpp16
-rw-r--r--src/mongo/db/matcher/expression_leaf.cpp1
-rw-r--r--src/mongo/db/matcher/expression_parser_leaf_test.cpp25
-rw-r--r--src/mongo/db/ops/modifier_bit_test.cpp9
-rw-r--r--src/mongo/db/ops/modifier_inc_test.cpp123
5 files changed, 173 insertions, 1 deletions
diff --git a/src/mongo/db/matcher/expression_algo_test.cpp b/src/mongo/db/matcher/expression_algo_test.cpp
index 9effbf6b0b9..e3fb3e504ea 100644
--- a/src/mongo/db/matcher/expression_algo_test.cpp
+++ b/src/mongo/db/matcher/expression_algo_test.cpp
@@ -37,6 +37,7 @@
#include "mongo/db/matcher/expression.h"
#include "mongo/db/matcher/expression_algo.h"
#include "mongo/db/matcher/expression_parser.h"
+#include "mongo/platform/decimal128.h"
namespace mongo {
@@ -121,6 +122,21 @@ TEST(ExpressionAlgoIsSubsetOf, Compare_NaN) {
ASSERT_FALSE(expression::isSubsetOf(gt.get(), nan.get()));
ASSERT_FALSE(expression::isSubsetOf(nan.get(), in.get()));
ASSERT_FALSE(expression::isSubsetOf(in.get(), nan.get()));
+
+ if (Decimal128::enabled) {
+ ParsedMatchExpression decNan("{x : NumberDecimal(\"NaN\") }");
+ ASSERT_TRUE(expression::isSubsetOf(decNan.get(), decNan.get()));
+ ASSERT_TRUE(expression::isSubsetOf(nan.get(), decNan.get()));
+ ASSERT_TRUE(expression::isSubsetOf(decNan.get(), nan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(decNan.get(), lt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(lt.get(), decNan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(decNan.get(), lte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(lte.get(), decNan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(decNan.get(), gte.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gte.get(), decNan.get()));
+ ASSERT_FALSE(expression::isSubsetOf(decNan.get(), gt.get()));
+ ASSERT_FALSE(expression::isSubsetOf(gt.get(), decNan.get()));
+ }
}
TEST(ExpressionAlgoIsSubsetOf, Compare_EQ) {
diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp
index 79836a43f2c..903b8c434a1 100644
--- a/src/mongo/db/matcher/expression_leaf.cpp
+++ b/src/mongo/db/matcher/expression_leaf.cpp
@@ -416,6 +416,7 @@ const std::unordered_map<std::string, BSONType> TypeMatchExpression::typeAliasMa
{"int", NumberInt},
{"timestamp", bsonTimestamp},
{"long", NumberLong},
+ {"decimal", NumberDecimal},
{"maxKey", MaxKey},
{"minKey", MinKey}};
diff --git a/src/mongo/db/matcher/expression_parser_leaf_test.cpp b/src/mongo/db/matcher/expression_parser_leaf_test.cpp
index cb1cd8ff375..c5650c25d67 100644
--- a/src/mongo/db/matcher/expression_parser_leaf_test.cpp
+++ b/src/mongo/db/matcher/expression_parser_leaf_test.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/json.h"
#include "mongo/db/matcher/expression.h"
#include "mongo/db/matcher/expression_leaf.h"
+#include "mongo/platform/decimal128.h"
#include "mongo/util/log.h"
namespace mongo {
@@ -608,6 +609,17 @@ TEST(MatchExpressionParserLeafTest, TypeDoubleOperator) {
ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5)));
}
+TEST(MatchExpressionParserLeafTest, TypeDecimalOperator) {
+ if (Decimal128::enabled) {
+ BSONObj query = BSON("x" << BSON("$type" << mongo::NumberDecimal));
+ StatusWithMatchExpression result = MatchExpressionParser::parse(query);
+ ASSERT_TRUE(result.isOK());
+
+ ASSERT_FALSE(result.getValue()->matchesBSON(BSON("x" << 5.3)));
+ ASSERT_TRUE(result.getValue()->matchesBSON(BSON("x" << mongo::Decimal128("1"))));
+ }
+}
+
TEST(MatchExpressionParserLeafTest, TypeNull) {
BSONObj query = BSON("x" << BSON("$type" << jstNULL));
StatusWithMatchExpression result = MatchExpressionParser::parse(query);
@@ -657,6 +669,19 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameDouble) {
ASSERT_FALSE(tmeNumberDouble->matchesBSON(fromjson("{a: NumberInt(5)}")));
}
+TEST(MatchExpressionParserLeafTest, TypeStringNameNumberDecimal) {
+ if (Decimal128::enabled) {
+ StatusWithMatchExpression typeNumberDecimal =
+ MatchExpressionParser::parse(fromjson("{a: {$type: 'decimal'}}"));
+ ASSERT_OK(typeNumberDecimal.getStatus());
+ TypeMatchExpression* tmeNumberDecimal =
+ static_cast<TypeMatchExpression*>(typeNumberDecimal.getValue().get());
+ ASSERT(tmeNumberDecimal->getType() == NumberDecimal);
+ ASSERT_TRUE(tmeNumberDecimal->matchesBSON(BSON("a" << mongo::Decimal128("1"))));
+ ASSERT_FALSE(tmeNumberDecimal->matchesBSON(fromjson("{a: true}")));
+ }
+}
+
TEST(MatchExpressionParserLeafTest, TypeStringnameNumberInt) {
StatusWithMatchExpression typeNumberInt =
MatchExpressionParser::parse(fromjson("{a: {$type: 'int'}}"));
diff --git a/src/mongo/db/ops/modifier_bit_test.cpp b/src/mongo/db/ops/modifier_bit_test.cpp
index b6a4fb38a7b..2e63dbe4953 100644
--- a/src/mongo/db/ops/modifier_bit_test.cpp
+++ b/src/mongo/db/ops/modifier_bit_test.cpp
@@ -37,11 +37,13 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/ops/log_builder.h"
+#include "mongo/platform/decimal128.h"
#include "mongo/unittest/unittest.h"
namespace {
using mongo::BSONObj;
+using mongo::Decimal128;
using mongo::LogBuilder;
using mongo::ModifierBit;
using mongo::ModifierInterface;
@@ -116,6 +118,13 @@ TEST(Init, FailToInitWithInvalidValue) {
modObj = fromjson("{ $bit : { a : { or : 1.0 } } }");
ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(),
ModifierInterface::Options::normal()));
+
+ if (mongo::Decimal128::enabled) {
+ // The argument to the sub-operator must be integral
+ modObj = fromjson("{ $bit : { a : { or : NumberDecimal(\"1.0\") } } }");
+ ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(),
+ ModifierInterface::Options::normal()));
+ }
}
TEST(Init, ParsesAndInt) {
diff --git a/src/mongo/db/ops/modifier_inc_test.cpp b/src/mongo/db/ops/modifier_inc_test.cpp
index 6a0e3a332bd..52c829f7842 100644
--- a/src/mongo/db/ops/modifier_inc_test.cpp
+++ b/src/mongo/db/ops/modifier_inc_test.cpp
@@ -39,11 +39,13 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/ops/log_builder.h"
+#include "mongo/platform/decimal128.h"
#include "mongo/unittest/unittest.h"
namespace {
using mongo::BSONObj;
+using mongo::Decimal128;
using mongo::LogBuilder;
using mongo::ModifierInc;
using mongo::ModifierInterface;
@@ -122,6 +124,12 @@ TEST(Init, InitParsesNumberDouble) {
Mod incMod(BSON("$inc" << BSON("a" << 1.0)));
}
+TEST(Init, InitParsesNumberDecimal) {
+ if (mongo::Decimal128::enabled) {
+ Mod incMod(BSON("$inc" << BSON("a" << Decimal128(1.0))));
+ }
+}
+
TEST(SimpleMod, PrepareSimpleOK) {
Document doc(fromjson("{ a : 1 }"));
Mod incMod(fromjson("{ $inc: { a : 1 }}"));
@@ -275,6 +283,16 @@ TEST(NoOp, Double) {
ASSERT_TRUE(execInfo.noOp);
}
+TEST(NoOp, Decimal) {
+ if (mongo::Decimal128::enabled) {
+ Document doc(BSON("a" << Decimal128("1.0")));
+ Mod incMod(BSON("$inc" << BSON("a" << Decimal128("0.0"))));
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(incMod.prepare(doc.root(), "", &execInfo));
+ ASSERT_TRUE(execInfo.noOp);
+ }
+}
+
TEST(Upcasting, UpcastIntToLong) {
// Checks that $inc : NumberLong(0) turns a NumberInt into a NumberLong and logs it
// correctly.
@@ -370,9 +388,112 @@ TEST(Upcasting, DoublesStayDoubles) {
ASSERT_EQUALS(mongo::NumberDouble, logDoc.root()["$set"]["a"].getType());
}
+TEST(Upcasting, UpcastIntToDecimal) {
+ if (mongo::Decimal128::enabled) {
+ // Checks that $inc : NumberDecimal(0) turns a NumberInt into a NumberDecimal and logs it
+ // correctly.
+ Document doc(BSON("a" << static_cast<int>(1)));
+ ASSERT_EQUALS(mongo::NumberInt, doc.root()["a"].getType());
+
+ Mod incMod(fromjson("{ $inc : { a : NumberDecimal(\"0\") }}"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(incMod.prepare(doc.root(), "", &execInfo));
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(incMod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : NumberDecimal(\"1.0\") }"), doc);
+ ASSERT_EQUALS(mongo::NumberDecimal, doc.root()["a"].getType());
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : NumberDecimal(\"1.0\") }}"), logDoc);
+ ASSERT_EQUALS(mongo::NumberDecimal, logDoc.root()["$set"]["a"].getType());
+ }
+}
+
+TEST(Upcasting, UpcastLongToDecimal) {
+ if (mongo::Decimal128::enabled) {
+ // Checks that $inc : NumberDecimal(0) turns a NumberLong into a NumberDecimal and logs it
+ // correctly.
+ Document doc(BSON("a" << static_cast<long long>(1)));
+ ASSERT_EQUALS(mongo::NumberLong, doc.root()["a"].getType());
+
+ Mod incMod(fromjson("{ $inc : { a : NumberDecimal(\"0\") }}"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(incMod.prepare(doc.root(), "", &execInfo));
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(incMod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : NumberDecimal(\"1.0\") }"), doc);
+ ASSERT_EQUALS(mongo::NumberDecimal, doc.root()["a"].getType());
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : NumberDecimal(\"1.0\") }}"), logDoc);
+ ASSERT_EQUALS(mongo::NumberDecimal, logDoc.root()["$set"]["a"].getType());
+ }
+}
+
+TEST(Upcasting, UpcastDoubleToDecimal) {
+ if (mongo::Decimal128::enabled) {
+ // Checks that $inc : NumberDecimal(0) turns a double into a NumberDecimal and logs it
+ // correctly.
+ Document doc(BSON("a" << static_cast<double>(1.0)));
+ ASSERT_EQUALS(mongo::NumberDouble, doc.root()["a"].getType());
+
+ Mod incMod(fromjson("{ $inc : { a : NumberDecimal(\"0\") }}"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(incMod.prepare(doc.root(), "", &execInfo));
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(incMod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : NumberDecimal(\"1.0\") }"), doc);
+ ASSERT_EQUALS(mongo::NumberDecimal, doc.root()["a"].getType());
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : NumberDecimal(\"1.0\") }}"), logDoc);
+ ASSERT_EQUALS(mongo::NumberDecimal, logDoc.root()["$set"]["a"].getType());
+ }
+}
+
+TEST(Upcasting, DecimalsStayDecimals) {
+ if (mongo::Decimal128::enabled) {
+ // Checks that $inc : NumberDecimal(1) keeps a NumberDecimal as a NumberDecimal and logs it
+ // correctly.
+ Document doc(BSON("a" << mongo::Decimal128("1.0")));
+ ASSERT_EQUALS(mongo::NumberDecimal, doc.root()["a"].getType());
+
+ Mod incMod(fromjson("{ $inc : { a : NumberDecimal(\"1\") }}"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(incMod.prepare(doc.root(), "", &execInfo));
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(incMod.apply());
+ ASSERT_TRUE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : NumberDecimal(\"2.0\") }"), doc);
+ ASSERT_EQUALS(mongo::NumberDecimal, doc.root()["a"].getType());
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : NumberDecimal(\"2.0\") }}"), logDoc);
+ ASSERT_EQUALS(mongo::NumberDecimal, logDoc.root()["$set"]["a"].getType());
+ }
+}
+
// The only interesting overflow cases are int->long via increment: we never overflow to
// double, and we never decrease precision on decrement.
-
TEST(Spilling, OverflowIntToLong) {
const int initial_value = std::numeric_limits<int32_t>::max();