diff options
author | Kshitij Gupta <kshitij.gupta@mongodb.com> | 2020-07-15 15:06:01 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-08-03 16:33:05 +0000 |
commit | d57e17494ceade881013e2e99606cc92d4a38605 (patch) | |
tree | 0aede55cbb5c2751374cef684cc0c21c7117741f /src/mongo/db | |
parent | 9cfe13115e92a43d1b9273ee1d5817d548264ba7 (diff) | |
download | mongo-d57e17494ceade881013e2e99606cc92d4a38605.tar.gz |
SERVER-49214: Add $toHashedIndexKey expression.
Diffstat (limited to 'src/mongo/db')
-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 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_stage_builder_expression.cpp | 6 |
6 files changed, 140 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 diff --git a/src/mongo/db/query/sbe_stage_builder_expression.cpp b/src/mongo/db/query/sbe_stage_builder_expression.cpp index 7250ba476df..b4fe30cf997 100644 --- a/src/mongo/db/query/sbe_stage_builder_expression.cpp +++ b/src/mongo/db/query/sbe_stage_builder_expression.cpp @@ -467,6 +467,7 @@ public: void visit(ExpressionInternalFindElemMatch* expr) final {} void visit(ExpressionFunction* expr) final {} void visit(ExpressionRandom* expr) final {} + void visit(ExpressionToHashedIndexKey* expr) final {} private: void visitMultiBranchLogicExpression(Expression* expr, sbe::EPrimBinary::Op logicOp) { @@ -652,6 +653,7 @@ public: void visit(ExpressionInternalFindElemMatch* expr) final {} void visit(ExpressionFunction* expr) final {} void visit(ExpressionRandom* expr) final {} + void visit(ExpressionToHashedIndexKey* expr) final {} private: void visitMultiBranchLogicExpression(Expression* expr, sbe::EPrimBinary::Op logicOp) { @@ -1509,6 +1511,10 @@ public: unsupportedExpression(expr->getOpName()); } + void visit(ExpressionToHashedIndexKey* expr) final { + unsupportedExpression("$toHashedIndexKey"); + } + private: /** * Shared logic for $and, $or. Converts each child into an EExpression that evaluates to Boolean |