diff options
author | Kshitij Gupta <kshitij.gupta@mongodb.com> | 2020-07-15 15:06:01 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-01-24 14:27:29 +0000 |
commit | 23973e8051d03576f83adf10b0f39c711e03d08d (patch) | |
tree | 3c8d9c2f259d5e180d40c14893fd444d274b8893 | |
parent | 63fa196dd22e3e075ebfc250acf2a0c62b73997a (diff) | |
download | mongo-r4.2.24-rc0.tar.gz |
SERVER-49214: Add $toHashedIndexKey expression.r4.2.24-rc0
(cherry picked from commit d57e17494ceade881013e2e99606cc92d4a38605)
(cherry picked from commit 3f3f5cc03a6587f9d0cfc3bdcb3f8aa13fe2356c)
-rw-r--r-- | src/mongo/db/pipeline/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 32 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.h | 23 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_test.cpp | 90 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_visitor.h | 2 |
5 files changed, 148 insertions, 0 deletions
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript index f034f2f87fb..db5c5a9f439 100644 --- a/src/mongo/db/pipeline/SConscript +++ b/src/mongo/db/pipeline/SConscript @@ -148,6 +148,7 @@ env.Library( 'expression_context', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/mongohasher', '$BUILD_DIR/mongo/db/query/query_knobs', ] ) diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index ea28f3e13cc..437fe7d9d45 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -41,6 +41,7 @@ #include <vector> #include "mongo/db/commands/feature_compatibility_version_documentation.h" +#include "mongo/db/hasher.h" #include "mongo/db/jsobj.h" #include "mongo/db/pipeline/document.h" #include "mongo/db/pipeline/expression_context.h" @@ -6233,4 +6234,35 @@ Value ExpressionRegexMatch::evaluate(const Document& root, Variables* variables) return executionState.nullish() ? Value(false) : Value(execute(&executionState) > 0); } +/* ------------------------- ExpressionToHashedIndexKey -------------------------- */ +REGISTER_EXPRESSION_WITH_MIN_VERSION( + toHashedIndexKey, + ExpressionToHashedIndexKey::parse, + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo42); + +boost::intrusive_ptr<Expression> ExpressionToHashedIndexKey::parse( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + BSONElement expr, + const VariablesParseState& vps) { + return new ExpressionToHashedIndexKey(expCtx, parseOperand(expCtx, expr, vps)); +} + +Value ExpressionToHashedIndexKey::evaluate(const Document& root, Variables* variables) const { + Value inpVal(_children[0]->evaluate(root, variables)); + if (inpVal.missing()) { + inpVal = Value(BSONNULL); + } + + return Value(BSONElementHasher::hash64(BSON("" << inpVal).firstElement(), + BSONElementHasher::DEFAULT_HASH_SEED)); +} + +Value ExpressionToHashedIndexKey::serialize(bool explain) const { + return Value(DOC("$toHashedIndexKey" << _children[0]->serialize(explain))); +} + +void ExpressionToHashedIndexKey::_doAddDependencies(DepsTracker* deps) const { + _children[0]->addDependencies(deps); +} + } // namespace mongo diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h index f1daa29afe9..e73f4d82166 100644 --- a/src/mongo/db/pipeline/expression.h +++ b/src/mongo/db/pipeline/expression.h @@ -2713,4 +2713,27 @@ public: using ExpressionRegex::ExpressionRegex; }; + +class ExpressionToHashedIndexKey : public Expression { +public: + ExpressionToHashedIndexKey(const boost::intrusive_ptr<ExpressionContext>& expCtx, + boost::intrusive_ptr<Expression> inputExpression) + : Expression(expCtx, {inputExpression}){}; + + static boost::intrusive_ptr<Expression> parse( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + BSONElement expr, + const VariablesParseState& vps); + + void acceptVisitor(ExpressionVisitor* visitor) final { + return visitor->visit(this); + } + + Value evaluate(const Document& root, Variables* variables) const; + Value serialize(bool explain) const final; + +protected: + void _doAddDependencies(DepsTracker* deps) const final; +}; + } // namespace mongo diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp index 54a959e0d0f..dd74505263b 100644 --- a/src/mongo/db/pipeline/expression_test.cpp +++ b/src/mongo/db/pipeline/expression_test.cpp @@ -31,6 +31,7 @@ #include "mongo/bson/bsonmisc.h" #include "mongo/config.h" +#include "mongo/db/hasher.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/pipeline/accumulator.h" @@ -6450,4 +6451,93 @@ TEST(ExpressionSubtractTest, OverflowLong) { ASSERT_EQ(result.getType(), BSONType::NumberDouble); ASSERT_EQ(result.getDouble(), static_cast<double>(minLong) * -1); } + +namespace ExpressionToHashedIndexKeyTest { + +TEST(ExpressionToHashedIndexKeyTest, StringInputSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" + << "hashThisStringLiteral"_sd); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(-5776344739422278694)); +} + +TEST(ExpressionToHashedIndexKeyTest, IntInputSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" << 123); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(-6548868637522515075)); +} + +TEST(ExpressionToHashedIndexKeyTest, TimestampInputSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" << Timestamp(0, 0)); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(-7867208682377458672)); +} + +TEST(ExpressionToHashedIndexKeyTest, ObjectIdInputSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" << OID("47cc67093475061e3d95369d")); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(1576265281381834298)); +} + +TEST(ExpressionToHashedIndexKeyTest, DateInputSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" << Date_t()); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(-1178696894582842035)); +} + +TEST(ExpressionToHashedIndexKeyTest, MissingInputValueSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" + << "$missingField"); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(2338878944348059895)); +} + +TEST(ExpressionToHashedIndexKeyTest, NullInputSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" << BSONNULL); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(2338878944348059895)); +} + +TEST(ExpressionToHashedIndexKeyTest, ExpressionInputSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" << BSON("$pow" << BSON_ARRAY(2 << 4))); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(2598032665634823220)); +} + +TEST(ExpressionToHashedIndexKeyTest, UndefinedInputSucceeds) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" << BSONUndefined); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + Value result = expression->evaluate({}, &(expCtx->variables)); + ASSERT_VALUE_EQ(result, Value::createIntOrLong(40158834000849533LL)); +} + +TEST(ExpressionToHashedIndexKeyTest, DoesAddInputDependencies) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const BSONObj obj = BSON("$toHashedIndexKey" + << "$someValue"); + auto expression = Expression::parseExpression(expCtx, obj, expCtx->variablesParseState); + + DepsTracker deps; + expression->addDependencies(&deps); + ASSERT_EQ(deps.fields.count("someValue"), 1u); + ASSERT_EQ(deps.fields.size(), 1u); +} +} // namespace ExpressionToHashedIndexKeyTest } // namespace ExpressionTests diff --git a/src/mongo/db/pipeline/expression_visitor.h b/src/mongo/db/pipeline/expression_visitor.h index 7141547ad54..6b77982df28 100644 --- a/src/mongo/db/pipeline/expression_visitor.h +++ b/src/mongo/db/pipeline/expression_visitor.h @@ -65,6 +65,7 @@ class ExpressionExp; class ExpressionFieldPath; class ExpressionFilter; class ExpressionFloor; +class ExpressionToHashedIndexKey; class ExpressionHour; class ExpressionIfNull; class ExpressionIn; @@ -273,6 +274,7 @@ public: virtual void visit(ExpressionFromAccumulator<AccumulatorSum>*) = 0; virtual void visit(ExpressionFromAccumulator<AccumulatorMergeObjects>*) = 0; virtual void visit(ExpressionTests::Testable*) = 0; + virtual void visit(ExpressionToHashedIndexKey*) = 0; }; } // namespace mongo |