diff options
Diffstat (limited to 'src/mongo/db/pipeline')
-rw-r--r-- | src/mongo/db/pipeline/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 29 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.h | 22 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_test.cpp | 79 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_visitor.h | 2 |
5 files changed, 134 insertions, 0 deletions
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript index 71f7524be9c..1929babc330 100644 --- a/src/mongo/db/pipeline/SConscript +++ b/src/mongo/db/pipeline/SConscript @@ -83,6 +83,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/vector_clock', + '$BUILD_DIR/mongo/db/mongohasher', ], ) @@ -392,6 +393,7 @@ env.CppUnitTest( '$BUILD_DIR/mongo/db/cst/cst', '$BUILD_DIR/mongo/db/exec/document_value/document_value', '$BUILD_DIR/mongo/db/exec/document_value/document_value_test_util', + '$BUILD_DIR/mongo/db/mongohasher', '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/repl/oplog_entry', diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index 8c5ef56f5f2..71d24d13528 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -42,6 +42,7 @@ #include "mongo/db/commands/feature_compatibility_version_documentation.h" #include "mongo/db/exec/document_value/document.h" #include "mongo/db/exec/document_value/value.h" +#include "mongo/db/hasher.h" #include "mongo/db/jsobj.h" #include "mongo/db/pipeline/expression_context.h" #include "mongo/db/query/datetime/date_time_support.h" @@ -6481,4 +6482,32 @@ void ExpressionRandom::_doAddDependencies(DepsTracker* deps) const { Value ExpressionRandom::serialize(const bool explain) const { return Value(DOC(getOpName() << Document())); } + +/* ------------------------- ExpressionToHashedIndexKey -------------------------- */ +REGISTER_EXPRESSION(toHashedIndexKey, ExpressionToHashedIndexKey::parse); + +boost::intrusive_ptr<Expression> ExpressionToHashedIndexKey::parse(ExpressionContext* const expCtx, + BSONElement expr, + const VariablesParseState& vps) { + return make_intrusive<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 { + // Nothing to do +} + } // namespace mongo diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h index 862a6a31da6..32b47f4562a 100644 --- a/src/mongo/db/pipeline/expression.h +++ b/src/mongo/db/pipeline/expression.h @@ -2908,4 +2908,26 @@ private: double getRandomValue() const; }; + +class ExpressionToHashedIndexKey : public Expression { +public: + ExpressionToHashedIndexKey(ExpressionContext* const expCtx, + boost::intrusive_ptr<Expression> inputExpression) + : Expression(expCtx, {inputExpression}){}; + + static boost::intrusive_ptr<Expression> parse(ExpressionContext* const 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 cf3929bf7aa..5288fe96c00 100644 --- a/src/mongo/db/pipeline/expression_test.cpp +++ b/src/mongo/db/pipeline/expression_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/exec/document_value/document.h" #include "mongo/db/exec/document_value/document_value_test_util.h" #include "mongo/db/exec/document_value/value_comparator.h" +#include "mongo/db/hasher.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/pipeline/accumulator.h" @@ -2983,4 +2984,82 @@ TEST(ExpressionRandom, Basic) { }; assertRandomProperties(randFn); } + +namespace ExpressionToHashedIndexKeyTest { + +TEST(ExpressionToHashedIndexKeyTest, StringInputSucceeds) { + auto expCtx = 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) { + auto expCtx = 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) { + auto expCtx = 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) { + auto expCtx = 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) { + auto expCtx = 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) { + auto expCtx = 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) { + auto expCtx = 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) { + auto expCtx = 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) { + auto expCtx = 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)); +} + +} // namespace ExpressionToHashedIndexKeyTest } // namespace ExpressionTests diff --git a/src/mongo/db/pipeline/expression_visitor.h b/src/mongo/db/pipeline/expression_visitor.h index d6b2b9d5042..a8b3d08e6c7 100644 --- a/src/mongo/db/pipeline/expression_visitor.h +++ b/src/mongo/db/pipeline/expression_visitor.h @@ -68,6 +68,7 @@ class ExpressionExp; class ExpressionFieldPath; class ExpressionFilter; class ExpressionFloor; +class ExpressionToHashedIndexKey; class ExpressionHour; class ExpressionIfNull; class ExpressionIn; @@ -299,6 +300,7 @@ public: virtual void visit(ExpressionInternalFindSlice*) = 0; virtual void visit(ExpressionInternalFindPositional*) = 0; virtual void visit(ExpressionInternalFindElemMatch*) = 0; + virtual void visit(ExpressionToHashedIndexKey*) = 0; }; } // namespace mongo |