diff options
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/matcher/expression_algo_test.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_leaf_test.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/ops/modifier_bit_test.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/ops/modifier_inc_test.cpp | 123 |
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(); |