diff options
author | Tess Avitabile <tess.avitabile@mongodb.com> | 2016-04-13 16:51:54 -0400 |
---|---|---|
committer | Tess Avitabile <tess.avitabile@mongodb.com> | 2016-04-26 17:31:35 -0400 |
commit | d6a77a0135db56972b2626a08e20a240a770f66f (patch) | |
tree | 787d6af56c956cf0fab3d12d584668f58d50d105 /src/mongo | |
parent | bfc1cf3a390099be0c031d2533aa5d090fc0acd6 (diff) | |
download | mongo-d6a77a0135db56972b2626a08e20a240a770f66f.tar.gz |
SERVER-23608 Make MatchExpressionParser take a CollatorInterface*
Diffstat (limited to 'src/mongo')
44 files changed, 1350 insertions, 517 deletions
diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp index 5bb10a57f3c..47f65d888c4 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp @@ -274,8 +274,9 @@ Status AuthzManagerExternalStateMock::_queryVector( const NamespaceString& collectionName, const BSONObj& query, std::vector<BSONObjCollection::iterator>* result) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression parseResult = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); if (!parseResult.isOK()) { return parseResult.getStatus(); } diff --git a/src/mongo/db/catalog/apply_ops.cpp b/src/mongo/db/catalog/apply_ops.cpp index 39a6ee25740..5fd501ddab3 100644 --- a/src/mongo/db/catalog/apply_ops.cpp +++ b/src/mongo/db/catalog/apply_ops.cpp @@ -78,7 +78,8 @@ Status applyOps(OperationContext* txn, // Apply-ops would never have a $where/$text matcher. Using the "DisallowExtensions" // callback ensures that parsing will throw an error if $where or $text are found. - Matcher m(f["res"].Obj(), ExtensionsCallbackDisallowExtensions()); + // TODO SERVER-23690: Pass the appropriate CollatorInterface* instead of nullptr. + Matcher m(f["res"].Obj(), ExtensionsCallbackDisallowExtensions(), nullptr); if (!m.matches(realres)) { result->append("got", realres); result->append("whatFailed", f); diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp index da4583d9693..61ef5390201 100644 --- a/src/mongo/db/catalog/collection.cpp +++ b/src/mongo/db/catalog/collection.cpp @@ -300,8 +300,9 @@ StatusWithMatchExpression Collection::parseValidator(const BSONObj& validator) c return status; } + // TODO SERVER-23687: Pass the appropriate CollatorInterface* instead of nullptr. auto statusWithMatcher = - MatchExpressionParser::parse(validator, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(validator, ExtensionsCallbackDisallowExtensions(), nullptr); if (!statusWithMatcher.isOK()) return statusWithMatcher.getStatus(); diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp index a64f43284ca..2a23509fd0a 100644 --- a/src/mongo/db/catalog/index_catalog.cpp +++ b/src/mongo/db/catalog/index_catalog.cpp @@ -545,8 +545,9 @@ Status IndexCatalog::_isSpecOk(OperationContext* txn, const BSONObj& spec) const return Status(ErrorCodes::CannotCreateIndex, "\"partialFilterExpression\" for an index must be a document"); } + // TODO SERVER-23618: pass the appropriate CollatorInterface* instead of nullptr. StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filterElement.Obj(), ExtensionsCallbackDisallowExtensions()); + filterElement.Obj(), ExtensionsCallbackDisallowExtensions(), nullptr); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } diff --git a/src/mongo/db/catalog/index_catalog_entry.cpp b/src/mongo/db/catalog/index_catalog_entry.cpp index dcc5f01f5b8..239cb7e4fc0 100644 --- a/src/mongo/db/catalog/index_catalog_entry.cpp +++ b/src/mongo/db/catalog/index_catalog_entry.cpp @@ -104,8 +104,9 @@ void IndexCatalogEntry::init(OperationContext* txn, IndexAccessMethod* accessMet if (BSONElement filterElement = _descriptor->getInfoElement("partialFilterExpression")) { invariant(filterElement.isABSONObj()); BSONObj filter = filterElement.Obj(); + // TODO SERVER-23618: pass the appropriate CollatorInterface* instead of nullptr. StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filter, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(filter, ExtensionsCallbackDisallowExtensions(), nullptr); // this should be checked in create, so can blow up here invariantOK(statusWithMatcher.getStatus()); _filterExpression = std::move(statusWithMatcher.getValue()); diff --git a/src/mongo/db/clientlistplugin.cpp b/src/mongo/db/clientlistplugin.cpp index ccb799571c5..ef241ed7185 100644 --- a/src/mongo/db/clientlistplugin.cpp +++ b/src/mongo/db/clientlistplugin.cpp @@ -168,8 +168,9 @@ public: BSONObjBuilder& result) { unique_ptr<MatchExpression> filter; if (cmdObj["filter"].isABSONObj()) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - cmdObj["filter"].Obj(), ExtensionsCallbackDisallowExtensions()); + cmdObj["filter"].Obj(), ExtensionsCallbackDisallowExtensions(), collator); if (!statusWithMatcher.isOK()) { return appendCommandStatus(result, statusWithMatcher.getStatus()); } diff --git a/src/mongo/db/commands/current_op.cpp b/src/mongo/db/commands/current_op.cpp index fed56b550ad..2f5798b410f 100644 --- a/src/mongo/db/commands/current_op.cpp +++ b/src/mongo/db/commands/current_op.cpp @@ -105,7 +105,8 @@ public: // collection, we pass in a fake collection name (and this is okay, because $where parsing // only relies on the database part of the namespace). const NamespaceString fakeNS(db, "$cmd"); - const Matcher matcher(filter, ExtensionsCallbackReal(txn, &fakeNS)); + CollatorInterface* collator = nullptr; + const Matcher matcher(filter, ExtensionsCallbackReal(txn, &fakeNS), collator); BSONArrayBuilder inprogBuilder(result.subarrayStart("inprog")); diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp index 0f9876420de..a20179c2bae 100644 --- a/src/mongo/db/commands/list_collections.cpp +++ b/src/mongo/db/commands/list_collections.cpp @@ -191,8 +191,10 @@ public: return appendCommandStatus( result, Status(ErrorCodes::BadValue, "\"filter\" must be an object")); } + // The collator is null because collection objects are compared using binary comparison. + CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filterElt.Obj(), ExtensionsCallbackDisallowExtensions()); + filterElt.Obj(), ExtensionsCallbackDisallowExtensions(), collator); if (!statusWithMatcher.isOK()) { return appendCommandStatus(result, statusWithMatcher.getStatus()); } diff --git a/src/mongo/db/exec/projection_exec.cpp b/src/mongo/db/exec/projection_exec.cpp index a399f33e9eb..f653e8494b3 100644 --- a/src/mongo/db/exec/projection_exec.cpp +++ b/src/mongo/db/exec/projection_exec.cpp @@ -125,8 +125,9 @@ ProjectionExec::ProjectionExec(const BSONObj& spec, BSONObj elemMatchObj = e.wrap(); verify(elemMatchObj.isOwned()); _elemMatchObjs.push_back(elemMatchObj); + // TODO SERVER-23680: pass the appropriate CollatorInterface* instead of nullptr. StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(elemMatchObj, extensionsCallback); + MatchExpressionParser::parse(elemMatchObj, extensionsCallback, nullptr); verify(statusWithMatcher.isOK()); // And store it in _matchers. _matchers[mongoutils::str::before(e.fieldName(), '.').c_str()] = diff --git a/src/mongo/db/exec/projection_exec_test.cpp b/src/mongo/db/exec/projection_exec_test.cpp index 9245cf8d18e..69fab9eafe3 100644 --- a/src/mongo/db/exec/projection_exec_test.cpp +++ b/src/mongo/db/exec/projection_exec_test.cpp @@ -49,8 +49,9 @@ using std::unique_ptr; * Utility function to create MatchExpression */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(status.isOK()); return std::move(status.getValue()); } diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index a56f7417063..d43a892bd8c 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -249,8 +249,9 @@ public: } BSONObj argObj = e.Obj(); if (filterTag == e.fieldName()) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - argObj, ExtensionsCallbackReal(txn, &collection->ns())); + argObj, ExtensionsCallbackReal(txn, &collection->ns()), collator); if (!statusWithMatcher.isOK()) { return NULL; } diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript index 5edaa348843..c22650d40ca 100644 --- a/src/mongo/db/matcher/SConscript +++ b/src/mongo/db/matcher/SConscript @@ -78,6 +78,7 @@ env.CppUnitTest( 'expression_parser_tree_test.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', 'expressions', ], ) diff --git a/src/mongo/db/matcher/expression_algo_test.cpp b/src/mongo/db/matcher/expression_algo_test.cpp index c89c95f5d63..807b35aee62 100644 --- a/src/mongo/db/matcher/expression_algo_test.cpp +++ b/src/mongo/db/matcher/expression_algo_test.cpp @@ -52,8 +52,9 @@ using std::unique_ptr; class ParsedMatchExpression { public: ParsedMatchExpression(const std::string& str) : _obj(fromjson(str)) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(_obj, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(_obj, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(result.getStatus()); _expr = std::move(result.getValue()); } @@ -71,9 +72,10 @@ TEST(ExpressionAlgoIsSubsetOf, NullAndOmittedField) { // Verify that ComparisonMatchExpression::init() prohibits creating a match expression with // an Undefined type. BSONObj undefined = fromjson("{a: undefined}"); + CollatorInterface* collator = nullptr; ASSERT_EQUALS(ErrorCodes::BadValue, - MatchExpressionParser::parse(undefined, ExtensionsCallbackDisallowExtensions()) - .getStatus()); + MatchExpressionParser::parse( + undefined, ExtensionsCallbackDisallowExtensions(), collator).getStatus()); ParsedMatchExpression empty("{}"); ParsedMatchExpression null("{a: null}"); @@ -653,8 +655,9 @@ TEST(ExpressionAlgoIsSubsetOf, Compare_Exists_NE) { TEST(IsIndependent, AndIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 1}]}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -664,8 +667,9 @@ TEST(IsIndependent, AndIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, ElemMatchIsNotIndependent) { BSONObj matchPredicate = fromjson("{x: {$elemMatch: {y: 1}}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -676,8 +680,9 @@ TEST(IsIndependent, ElemMatchIsNotIndependent) { TEST(IsIndependent, NorIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$nor: [{a: 1}, {b: 1}]}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -687,8 +692,9 @@ TEST(IsIndependent, NorIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, NotIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -698,8 +704,9 @@ TEST(IsIndependent, NotIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, OrIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$or: [{a: 1}, {b: 1}]}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -709,8 +716,9 @@ TEST(IsIndependent, OrIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, AndWithDottedFieldPathsIsNotIndependent) { BSONObj matchPredicate = fromjson("{$and: [{'a': 1}, {'a.b': 1}]}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -720,8 +728,9 @@ TEST(IsIndependent, AndWithDottedFieldPathsIsNotIndependent) { TEST(IsIndependent, BallIsIndependentOfBalloon) { BSONObj matchPredicate = fromjson("{'a.ball': 4}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -732,8 +741,9 @@ TEST(IsIndependent, BallIsIndependentOfBalloon) { TEST(SplitMatchExpression, AndWithSplittableChildrenIsSplittable) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 1}]}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -753,8 +763,9 @@ TEST(SplitMatchExpression, AndWithSplittableChildrenIsSplittable) { TEST(SplitMatchExpression, NorWithIndependentChildrenIsSplittable) { BSONObj matchPredicate = fromjson("{$nor: [{a: 1}, {b: 1}]}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -774,8 +785,9 @@ TEST(SplitMatchExpression, NorWithIndependentChildrenIsSplittable) { TEST(SplitMatchExpression, NotWithIndependentChildIsSplittable) { BSONObj matchPredicate = fromjson("{x: {$not: {$gt: 4}}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -791,8 +803,9 @@ TEST(SplitMatchExpression, NotWithIndependentChildIsSplittable) { TEST(SplitMatchExpression, OrWithOnlyIndependentChildrenIsNotSplittable) { BSONObj matchPredicate = fromjson("{$or: [{a: 1}, {b: 1}]}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -811,8 +824,9 @@ TEST(SplitMatchExpression, ComplexMatchExpressionSplitsCorrectly) { "{$and: [{x: {$not: {$size: 2}}}," "{$or: [{'a.b' : 3}, {'a.b.c': 4}]}," "{$nor: [{x: {$gt: 4}}, {$and: [{x: {$not: {$eq: 1}}}, {y: 3}]}]}]}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -836,7 +850,9 @@ TEST(SplitMatchExpression, ComplexMatchExpressionSplitsCorrectly) { TEST(MapOverMatchExpression, DoesMapOverLogicalNodes) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); - auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + auto swMatchExpression = + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(swMatchExpression.getStatus()); bool hasLogicalNode = false; @@ -852,7 +868,9 @@ TEST(MapOverMatchExpression, DoesMapOverLogicalNodes) { TEST(MapOverMatchExpression, DoesMapOverLeafNodes) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); - auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + auto swMatchExpression = + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(swMatchExpression.getStatus()); bool hasLeafNode = false; @@ -868,7 +886,9 @@ TEST(MapOverMatchExpression, DoesMapOverLeafNodes) { TEST(MapOverMatchExpression, DoesPassPath) { BSONObj matchPredicate = fromjson("{a: {$elemMatch: {b: 1}}}"); - auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + auto swMatchExpression = + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(swMatchExpression.getStatus()); std::vector<std::string> paths; @@ -885,7 +905,9 @@ TEST(MapOverMatchExpression, DoesPassPath) { TEST(MapOverMatchExpression, DoesMapOverNodesWithMultipleChildren) { BSONObj matchPredicate = fromjson("{$and: [{a: {$gt: 1}}, {b: {$lte: 2}}]}"); - auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + auto swMatchExpression = + MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); ASSERT_OK(swMatchExpression.getStatus()); size_t nodeCount = 0; diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index f86ba0f55e4..a650ff2e88d 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -95,8 +95,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField(const BSONObj& c // TODO: these should move to getGtLtOp, or its replacement if (mongoutils::str::equals("$eq", e.fieldName())) - // TODO SERVER-23608: Pass our CollatorInterface* to EqualityMatchExpression(). - return _parseComparison(name, new EqualityMatchExpression(nullptr), e); + return _parseComparison(name, new EqualityMatchExpression(_collator), e); if (mongoutils::str::equals("$not", e.fieldName())) { return _parseNot(name, e, level); @@ -113,26 +112,21 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField(const BSONObj& c return {Status(ErrorCodes::BadValue, mongoutils::str::stream() << "unknown operator: " << e.fieldName())}; case BSONObj::LT: - // TODO SERVER-23608: Pass our CollatorInterface* to LTMatchExpression(). - return _parseComparison(name, new LTMatchExpression(nullptr), e); + return _parseComparison(name, new LTMatchExpression(_collator), e); case BSONObj::LTE: - // TODO SERVER-23608: Pass our CollatorInterface* to LTEMatchExpression(). - return _parseComparison(name, new LTEMatchExpression(nullptr), e); + return _parseComparison(name, new LTEMatchExpression(_collator), e); case BSONObj::GT: - // TODO SERVER-23608: Pass our CollatorInterface* to GTMatchExpression(). - return _parseComparison(name, new GTMatchExpression(nullptr), e); + return _parseComparison(name, new GTMatchExpression(_collator), e); case BSONObj::GTE: - // TODO SERVER-23608: Pass our CollatorInterface* to GTEMatchExpression(). - return _parseComparison(name, new GTEMatchExpression(nullptr), e); + return _parseComparison(name, new GTEMatchExpression(_collator), e); case BSONObj::NE: { if (RegEx == e.type()) { // Just because $ne can be rewritten as the negation of an // equality does not mean that $ne of a regex is allowed. See SERVER-1705. return {Status(ErrorCodes::BadValue, "Can't have regex as arg to $ne.")}; } - // TODO SERVER-23608: Pass our CollatorInterface* to EqualityMatchExpression(). StatusWithMatchExpression s = - _parseComparison(name, new EqualityMatchExpression(nullptr), e); + _parseComparison(name, new EqualityMatchExpression(_collator), e); if (!s.isOK()) return s; std::unique_ptr<NotMatchExpression> n = stdx::make_unique<NotMatchExpression>(); @@ -142,14 +136,13 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField(const BSONObj& c return {std::move(n)}; } case BSONObj::Equality: - // TODO SERVER-23608: Pass our CollatorInterface* to EqualityMatchExpression(). - return _parseComparison(name, new EqualityMatchExpression(nullptr), e); + return _parseComparison(name, new EqualityMatchExpression(_collator), e); case BSONObj::opIN: { if (e.type() != Array) return {Status(ErrorCodes::BadValue, "$in needs an array")}; - // TODO SERVER-23608: Pass our CollatorInterface* to InMatchExpression(). - std::unique_ptr<InMatchExpression> temp = stdx::make_unique<InMatchExpression>(nullptr); + std::unique_ptr<InMatchExpression> temp = + stdx::make_unique<InMatchExpression>(_collator); Status s = temp->init(name); if (!s.isOK()) return s; @@ -162,8 +155,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField(const BSONObj& c case BSONObj::NIN: { if (e.type() != Array) return {Status(ErrorCodes::BadValue, "$nin needs an array")}; - // TODO SERVER-23608: Pass our CollatorInterface* to InMatchExpression(). - std::unique_ptr<InMatchExpression> temp = stdx::make_unique<InMatchExpression>(nullptr); + std::unique_ptr<InMatchExpression> temp = + stdx::make_unique<InMatchExpression>(_collator); Status s = temp->init(name); if (!s.isOK()) return s; @@ -354,10 +347,10 @@ StatusWithMatchExpression MatchExpressionParser::_parse(const BSONObj& obj, int } else if (mongoutils::str::equals("ref", rest) || mongoutils::str::equals("id", rest) || mongoutils::str::equals("db", rest)) { // DBRef fields. - // TODO SERVER-23608: Pass our CollatorInterface* to EqualityMatchExpression() in - // the "id" case. + // 'id' is collation-aware. 'ref' and 'db' are compared using binary comparison. + CollatorInterface* collator = (str::equals("id", rest) ? _collator : nullptr); std::unique_ptr<ComparisonMatchExpression> eq = - stdx::make_unique<EqualityMatchExpression>(nullptr); + stdx::make_unique<EqualityMatchExpression>(collator); Status s = eq->init(e.fieldName(), e); if (!s.isOK()) return s; @@ -387,9 +380,8 @@ StatusWithMatchExpression MatchExpressionParser::_parse(const BSONObj& obj, int continue; } - // TODO SERVER-23608: Pass our CollatorInterface* to EqualityMatchExpression(). std::unique_ptr<ComparisonMatchExpression> eq = - stdx::make_unique<EqualityMatchExpression>(nullptr); + stdx::make_unique<EqualityMatchExpression>(_collator); Status s = eq->init(e.fieldName(), e); if (!s.isOK()) return s; @@ -807,9 +799,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseAll(const char* name, } else if (e.type() == Object && e.Obj().firstElement().getGtLtOp(-1) != -1) { return {Status(ErrorCodes::BadValue, "no $ expressions in $all")}; } else { - // TODO SERVER-23608: Pass our CollatorInterface* to EqualityMatchExpression(). std::unique_ptr<EqualityMatchExpression> x = - stdx::make_unique<EqualityMatchExpression>(nullptr); + stdx::make_unique<EqualityMatchExpression>(_collator); Status s = x->init(name, e); if (!s.isOK()) return s; diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h index 9fc5d18ccc2..0bde5027338 100644 --- a/src/mongo/db/matcher/expression_parser.h +++ b/src/mongo/db/matcher/expression_parser.h @@ -40,6 +40,7 @@ namespace mongo { +class CollatorInterface; class OperationContext; class MatchExpressionParser { @@ -47,16 +48,18 @@ public: /** * caller has to maintain ownership obj * the tree has views (BSONElement) into obj + * 'collator' must outlive the returned MatchExpression and any clones made of it. */ static StatusWithMatchExpression parse(const BSONObj& obj, - const ExtensionsCallback& extensionsCallback) { + const ExtensionsCallback& extensionsCallback, + CollatorInterface* collator) { // The 0 initializes the match expression tree depth. - return MatchExpressionParser(&extensionsCallback)._parse(obj, 0); + return MatchExpressionParser(&extensionsCallback, collator)._parse(obj, 0); } private: - explicit MatchExpressionParser(const ExtensionsCallback* extensionsCallback) - : _extensionsCallback(extensionsCallback) {} + MatchExpressionParser(const ExtensionsCallback* extensionsCallback, CollatorInterface* collator) + : _extensionsCallback(extensionsCallback), _collator(collator) {} /** * 5 = false @@ -149,6 +152,10 @@ private: // Performs parsing for the match extensions. We do not own this pointer - it has to live // as long as the parser is active. const ExtensionsCallback* _extensionsCallback; + + // Collator that constructed collation-aware MatchExpressions will use. + // We do not own this pointer - it has to live as long as the parser is active. + CollatorInterface* _collator; }; typedef stdx::function<StatusWithMatchExpression( diff --git a/src/mongo/db/matcher/expression_parser_array_test.cpp b/src/mongo/db/matcher/expression_parser_array_test.cpp index 48972f3ef1e..c215ea33c9b 100644 --- a/src/mongo/db/matcher/expression_parser_array_test.cpp +++ b/src/mongo/db/matcher/expression_parser_array_test.cpp @@ -39,6 +39,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_array.h" #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" +#include "mongo/db/query/collation/collator_interface_mock.h" namespace mongo { @@ -46,8 +47,9 @@ using std::string; TEST(MatchExpressionParserArrayTest, Size1) { BSONObj query = BSON("x" << BSON("$size" << 2)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -58,8 +60,9 @@ TEST(MatchExpressionParserArrayTest, Size1) { TEST(MatchExpressionParserArrayTest, SizeAsLong) { BSONObj query = BSON("x" << BSON("$size" << 2LL)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -70,30 +73,34 @@ TEST(MatchExpressionParserArrayTest, SizeAsLong) { TEST(MatchExpressionParserArrayTest, SizeAsNegativeLong) { BSONObj query = BSON("x" << BSON("$size" << -2LL)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeTooLarge) { BSONObj query = BSON("x" << BSON("$size" << std::numeric_limits<long long>::max())); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeAsString) { BSONObj query = BSON("x" << BSON("$size" << "a")); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithIntegralDouble) { BSONObj query = BSON("x" << BSON("$size" << 2.0)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -104,29 +111,33 @@ TEST(MatchExpressionParserArrayTest, SizeWithIntegralDouble) { TEST(MatchExpressionParserArrayTest, SizeWithNegativeIntegralDouble) { BSONObj query = BSON("x" << BSON("$size" << -2.0)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithDouble) { BSONObj query = BSON("x" << BSON("$size" << 2.5)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithNegative) { BSONObj query = BSON("x" << BSON("$size" << -2)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeBad) { BSONObj query = BSON("x" << BSON("$size" << BSONNULL)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -134,8 +145,9 @@ TEST(MatchExpressionParserArrayTest, SizeBad) { TEST(MatchExpressionParserArrayTest, ElemMatchArr1) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("x" << 1 << "y" << 2))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -147,8 +159,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchArr1) { TEST(MatchExpressionParserArrayTest, ElemMatchAnd) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$and" << BSON_ARRAY(BSON("x" << 1 << "y" << 2))))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -159,8 +172,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchAnd) { TEST(MatchExpressionParserArrayTest, ElemMatchNor) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$nor" << BSON_ARRAY(BSON("x" << 1))))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -172,8 +186,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchNor) { TEST(MatchExpressionParserArrayTest, ElemMatchOr) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$or" << BSON_ARRAY(BSON("x" << 1 << "y" << 2))))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -184,8 +199,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchOr) { TEST(MatchExpressionParserArrayTest, ElemMatchVal1) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$gt" << 5))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -207,8 +223,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef1) { << "db"); BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$eq" << match))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -229,8 +246,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef2) { << "db"); BSONObj query = BSON("x" << BSON("$elemMatch" << match)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -250,8 +268,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef3) { << "$id" << oidx << "foo" << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << match)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -283,8 +302,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef4) { << "db"); BSONObj query = BSON("x" << BSON("$elemMatch" << matchOutOfOrder)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -307,8 +327,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef5) { << "$id" << oidx << "foo" << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << matchOutOfOrder)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -336,8 +357,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef6) { << "$id" << oid << "foo" << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << matchMissingID)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -364,8 +386,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef7) { << "$id" << oidx << "foo" << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << matchMissingRef)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -397,8 +420,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef8) { << "foo" << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << matchDBOnly)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -416,8 +440,9 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef8) { TEST(MatchExpressionParserArrayTest, All1) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(1 << 2))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -433,8 +458,9 @@ TEST(MatchExpressionParserArrayTest, All1) { TEST(MatchExpressionParserArrayTest, AllNull) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(BSONNULL))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -448,8 +474,9 @@ TEST(MatchExpressionParserArrayTest, AllNull) { TEST(MatchExpressionParserArrayTest, AllBadArg) { BSONObj query = BSON("x" << BSON("$all" << 1)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -462,8 +489,9 @@ TEST(MatchExpressionParserArrayTest, AllBadRegexArg) { BSONObj query = BSON("x" << operand.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -476,8 +504,9 @@ TEST(MatchExpressionParserArrayTest, AllRegex1) { all.appendArray("$all", allArray.obj()); BSONObj query = BSON("a" << all.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -503,8 +532,9 @@ TEST(MatchExpressionParserArrayTest, AllRegex2) { all.appendArray("$all", allArray.obj()); BSONObj query = BSON("a" << all.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -521,8 +551,9 @@ TEST(MatchExpressionParserArrayTest, AllRegex2) { TEST(MatchExpressionParserArrayTest, AllNonArray) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(5))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -538,8 +569,9 @@ TEST(MatchExpressionParserArrayTest, AllNonArray) { TEST(MatchExpressionParserArrayTest, AllElemMatch1) { BSONObj internal = BSON("x" << 1 << "y" << 2); BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(BSON("$elemMatch" << internal)))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to an AND with a single ELEM_MATCH_OBJECT child. @@ -559,8 +591,9 @@ TEST(MatchExpressionParserArrayTest, AllElemMatch1) { TEST(MatchExpressionParserArrayTest, AllElemMatch2) { BSONObj internal = BSON("z" << 1); BSONObj query = BSON("x.y" << BSON("$all" << BSON_ARRAY(BSON("$elemMatch" << internal)))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to an AND with a single ELEM_MATCH_OBJECT child. @@ -595,8 +628,9 @@ TEST(MatchExpressionParserArrayTest, AllElemMatch2) { // are correct. TEST(MatchExpressionParserArrayTest, AllElemMatch3) { BSONObj query = fromjson("{x: {$all: [{$elemMatch: {y: 1, z: 1}}]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); std::unique_ptr<MatchExpression> expr = std::move(result.getValue()); @@ -631,12 +665,13 @@ TEST(MatchExpressionParserArrayTest, AllElemMatchBad) { BSONObj internal = BSON("x" << 1 << "y" << 2); BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(BSON("$elemMatch" << internal) << 5))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$all" << BSON_ARRAY(5 << BSON("$elemMatch" << internal)))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -644,34 +679,36 @@ TEST(MatchExpressionParserArrayTest, AllElemMatchBad) { TEST(MatchExpressionParserArrayTest, AllElemMatchBadMixed) { // $elemMatch first, equality second. BSONObj bad1 = fromjson("{x: {$all: [{$elemMatch: {y: 1}}, 3]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result1 = - MatchExpressionParser::parse(bad1, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(bad1, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result1.isOK()); // equality first, $elemMatch second BSONObj bad2 = fromjson("{x: {$all: [3, {$elemMatch: {y: 1}}]}}"); StatusWithMatchExpression result2 = - MatchExpressionParser::parse(bad2, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(bad2, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result1.isOK()); // $elemMatch first, object second BSONObj bad3 = fromjson("{x: {$all: [{$elemMatch: {y: 1}}, {z: 1}]}}"); StatusWithMatchExpression result3 = - MatchExpressionParser::parse(bad3, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(bad3, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result3.isOK()); // object first, $elemMatch second BSONObj bad4 = fromjson("{x: {$all: [{z: 1}, {$elemMatch: {y: 1}}]}}"); StatusWithMatchExpression result4 = - MatchExpressionParser::parse(bad4, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(bad4, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result4.isOK()); } // $all with empty string. TEST(MatchExpressionParserArrayTest, AllEmptyString) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(""))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -695,8 +732,9 @@ TEST(MatchExpressionParserArrayTest, AllISODate) { const Date_t& notMatch = notMatchResult.getValue(); BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(match))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << notMatch))); @@ -711,8 +749,9 @@ TEST(MatchExpressionParserArrayTest, AllISODate) { // $all on array element with empty string. TEST(MatchExpressionParserArrayTest, AllDottedEmptyString) { BSONObj query = BSON("x.1" << BSON("$all" << BSON_ARRAY(""))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -738,8 +777,9 @@ TEST(MatchExpressionParserArrayTest, AllDottedISODate) { const Date_t& notMatch = notMatchResult.getValue(); BSONObj query = BSON("x.1" << BSON("$all" << BSON_ARRAY(match))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << notMatch))); @@ -752,4 +792,32 @@ TEST(MatchExpressionParserArrayTest, AllDottedISODate) { ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSONNULL << match)))); ASSERT(result.getValue()->matchesBSON(BSON("x" << BSON_ARRAY(BSONObj() << match)))); } + +TEST(MatchExpressionParserArrayTest, AllStringNullCollation) { + BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY("string"))); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::AND, result.getValue()->matchType()); + ASSERT_EQUALS(1U, result.getValue()->numChildren()); + MatchExpression* child = result.getValue()->getChild(0); + ASSERT_EQUALS(MatchExpression::EQ, child->matchType()); + EqualityMatchExpression* eqMatch = static_cast<EqualityMatchExpression*>(child); + ASSERT_TRUE(eqMatch->getCollator() == collator); +} + +TEST(MatchExpressionParserArrayTest, AllStringCollation) { + BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY("string"))); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::AND, result.getValue()->matchType()); + ASSERT_EQUALS(1U, result.getValue()->numChildren()); + MatchExpression* child = result.getValue()->getChild(0); + ASSERT_EQUALS(MatchExpression::EQ, child->matchType()); + EqualityMatchExpression* eqMatch = static_cast<EqualityMatchExpression*>(child); + ASSERT_TRUE(eqMatch->getCollator() == &collator); +} } diff --git a/src/mongo/db/matcher/expression_parser_geo_test.cpp b/src/mongo/db/matcher/expression_parser_geo_test.cpp index cb2e98942d4..5724cff0d51 100644 --- a/src/mongo/db/matcher/expression_parser_geo_test.cpp +++ b/src/mongo/db/matcher/expression_parser_geo_test.cpp @@ -43,8 +43,9 @@ namespace mongo { TEST(MatchExpressionParserGeo, WithinBox) { BSONObj query = fromjson("{a:{$within:{$box:[{x: 4, y:4},[6,6]]}}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(fromjson("{a: [3,4]}"))); @@ -59,8 +60,9 @@ TEST(MatchExpressionParserGeoNear, ParseNear) { "{loc:{$near:{$maxDistance:100, " "$geometry:{type:\"Point\", coordinates:[0,0]}}}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -76,8 +78,10 @@ TEST(MatchExpressionParserGeoNear, ParseNearExtraField) { "{loc:{$near:{$maxDistance:100, " "$geometry:{type:\"Point\", coordinates:[0,0]}}, foo: 1}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } // For $near, $nearSphere, and $geoNear syntax of: @@ -89,8 +93,9 @@ TEST(MatchExpressionParserGeoNear, ParseNearExtraField) { TEST(MatchExpressionParserGeoNear, ParseValidNear) { BSONObj query = fromjson("{loc: {$near: [0,0], $maxDistance: 100, $minDistance: 50}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -104,53 +109,66 @@ TEST(MatchExpressionParserGeoNear, ParseValidNear) { TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $near: [0,0]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$minDistance: 100, $near: [0,0]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$near: [0,0], $maxDistance: {}}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } { BSONObj query = fromjson("{loc: {$near: [0,0], $minDistance: {}}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } { BSONObj query = fromjson("{loc: {$near: [0,0], $eq: 40}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } { BSONObj query = fromjson("{loc: {$eq: 40, $near: [0,0]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson( "{loc: {$near: [0,0], $geoWithin: {$geometry: {type: \"Polygon\", coordinates: []}}}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } { BSONObj query = fromjson("{loc: {$near: {$foo: 1}}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$minDistance: 10}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } } @@ -158,8 +176,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { TEST(MatchExpressionParserGeoNear, ParseValidGeoNear) { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $maxDistance: 100, $minDistance: 50}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -173,38 +192,47 @@ TEST(MatchExpressionParserGeoNear, ParseValidGeoNear) { TEST(MatchExpressionParserGeoNear, ParseInvalidGeoNear) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $geoNear: [0,0]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$minDistance: 100, $geoNear: [0,0]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $eq: 1}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $maxDistance: {}}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $minDistance: {}}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } } TEST(MatchExpressionParserGeoNear, ParseValidNearSphere) { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $maxDistance: 100, $minDistance: 50}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -218,30 +246,38 @@ TEST(MatchExpressionParserGeoNear, ParseValidNearSphere) { TEST(MatchExpressionParserGeoNear, ParseInvalidNearSphere) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $nearSphere: [0,0]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$minDistance: 100, $nearSphere: [0,0]}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $maxDistance: {}}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $minDistance: {}}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $eq: 1}}"); - ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()), - UserException); + CollatorInterface* collator = nullptr; + ASSERT_THROWS( + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator), + UserException); } } diff --git a/src/mongo/db/matcher/expression_parser_leaf_test.cpp b/src/mongo/db/matcher/expression_parser_leaf_test.cpp index 23eb7e79ac1..b3a3639defd 100644 --- a/src/mongo/db/matcher/expression_parser_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_parser_leaf_test.cpp @@ -39,6 +39,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" +#include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/platform/decimal128.h" #include "mongo/util/log.h" @@ -47,10 +48,36 @@ namespace mongo { using std::endl; using std::string; +TEST(MatchExpressionParserLeafTest, NullCollation) { + BSONObj query = BSON("x" + << "string"); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); + EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == collator); +} + + +TEST(MatchExpressionParserLeafTest, Collation) { + BSONObj query = BSON("x" + << "string"); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); + EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == &collator); +} + TEST(MatchExpressionParserLeafTest, SimpleEQ2) { BSONObj query = BSON("x" << BSON("$eq" << 2)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -60,25 +87,78 @@ TEST(MatchExpressionParserLeafTest, SimpleEQ2) { TEST(MatchExpressionParserLeafTest, SimpleEQUndefined) { BSONObj query = BSON("x" << BSON("$eq" << BSONUndefined)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } +TEST(MatchExpressionParserLeafTest, EQNullCollation) { + BSONObj query = BSON("x" << BSON("$eq" + << "string")); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); + EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == collator); +} + + +TEST(MatchExpressionParserLeafTest, EQCollation) { + BSONObj query = BSON("x" << BSON("$eq" + << "string")); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); + EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == &collator); +} + TEST(MatchExpressionParserLeafTest, SimpleGT1) { BSONObj query = BSON("x" << BSON("$gt" << 2)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 2))); ASSERT(result.getValue()->matchesBSON(BSON("x" << 3))); } +TEST(MatchExpressionParserLeafTest, GTNullCollation) { + BSONObj query = BSON("x" << BSON("$gt" + << "abc")); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::GT, result.getValue()->matchType()); + GTMatchExpression* match = static_cast<GTMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == collator); +} + + +TEST(MatchExpressionParserLeafTest, GTCollation) { + BSONObj query = BSON("x" << BSON("$gt" + << "abc")); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::GT, result.getValue()->matchType()); + GTMatchExpression* match = static_cast<GTMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == &collator); +} + TEST(MatchExpressionParserLeafTest, SimpleLT1) { BSONObj query = BSON("x" << BSON("$lt" << 2)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -86,10 +166,36 @@ TEST(MatchExpressionParserLeafTest, SimpleLT1) { ASSERT(!result.getValue()->matchesBSON(BSON("x" << 3))); } +TEST(MatchExpressionParserLeafTest, LTNullCollation) { + BSONObj query = BSON("x" << BSON("$lt" + << "abc")); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::LT, result.getValue()->matchType()); + LTMatchExpression* match = static_cast<LTMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == collator); +} + + +TEST(MatchExpressionParserLeafTest, LTCollation) { + BSONObj query = BSON("x" << BSON("$lt" + << "abc")); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::LT, result.getValue()->matchType()); + LTMatchExpression* match = static_cast<LTMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == &collator); +} + TEST(MatchExpressionParserLeafTest, SimpleGTE1) { BSONObj query = BSON("x" << BSON("$gte" << 2)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -97,10 +203,36 @@ TEST(MatchExpressionParserLeafTest, SimpleGTE1) { ASSERT(result.getValue()->matchesBSON(BSON("x" << 3))); } +TEST(MatchExpressionParserLeafTest, GTENullCollation) { + BSONObj query = BSON("x" << BSON("$gte" + << "abc")); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::GTE, result.getValue()->matchType()); + GTEMatchExpression* match = static_cast<GTEMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == collator); +} + + +TEST(MatchExpressionParserLeafTest, GTECollation) { + BSONObj query = BSON("x" << BSON("$gte" + << "abc")); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::GTE, result.getValue()->matchType()); + GTEMatchExpression* match = static_cast<GTEMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == &collator); +} + TEST(MatchExpressionParserLeafTest, SimpleLTE1) { BSONObj query = BSON("x" << BSON("$lte" << 2)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -108,10 +240,36 @@ TEST(MatchExpressionParserLeafTest, SimpleLTE1) { ASSERT(!result.getValue()->matchesBSON(BSON("x" << 3))); } +TEST(MatchExpressionParserLeafTest, LTENullCollation) { + BSONObj query = BSON("x" << BSON("$lte" + << "abc")); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::LTE, result.getValue()->matchType()); + LTEMatchExpression* match = static_cast<LTEMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == collator); +} + + +TEST(MatchExpressionParserLeafTest, LTECollation) { + BSONObj query = BSON("x" << BSON("$lte" + << "abc")); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::LTE, result.getValue()->matchType()); + LTEMatchExpression* match = static_cast<LTEMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == &collator); +} + TEST(MatchExpressionParserLeafTest, SimpleNE1) { BSONObj query = BSON("x" << BSON("$ne" << 2)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -119,37 +277,68 @@ TEST(MatchExpressionParserLeafTest, SimpleNE1) { ASSERT(result.getValue()->matchesBSON(BSON("x" << 3))); } +TEST(MatchExpressionParserLeafTest, NENullCollation) { + BSONObj query = BSON("x" << BSON("$ne" + << "string")); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); + MatchExpression* child = result.getValue()->getChild(0); + ASSERT_EQUALS(MatchExpression::EQ, child->matchType()); + EqualityMatchExpression* eqMatch = static_cast<EqualityMatchExpression*>(child); + ASSERT_TRUE(eqMatch->getCollator() == collator); +} + + +TEST(MatchExpressionParserLeafTest, NECollation) { + BSONObj query = BSON("x" << BSON("$ne" + << "string")); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); + MatchExpression* child = result.getValue()->getChild(0); + ASSERT_EQUALS(MatchExpression::EQ, child->matchType()); + EqualityMatchExpression* eqMatch = static_cast<EqualityMatchExpression*>(child); + ASSERT_TRUE(eqMatch->getCollator() == &collator); +} + TEST(MatchExpressionParserLeafTest, SimpleModBad1) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); query = BSON("x" << BSON("$mod" << BSON_ARRAY(3))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(!result.isOK()); query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2 << 4))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(!result.isOK()); query = BSON("x" << BSON("$mod" << BSON_ARRAY("q" << 2))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(!result.isOK()); query = BSON("x" << BSON("$mod" << 3)); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(!result.isOK()); query = BSON("x" << BSON("$mod" << BSON("a" << 1 << "b" << 2))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(!result.isOK()); } TEST(MatchExpressionParserLeafTest, SimpleMod1) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5))); @@ -159,8 +348,9 @@ TEST(MatchExpressionParserLeafTest, SimpleMod1) { TEST(MatchExpressionParserLeafTest, SimpleModNotNumber) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(2 << "r"))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -170,11 +360,59 @@ TEST(MatchExpressionParserLeafTest, SimpleModNotNumber) { << "a"))); } +TEST(MatchExpressionParserLeafTest, IdCollation) { + BSONObj query = BSON("$id" + << "string"); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); + EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == collator); +} + +TEST(MatchExpressionParserLeafTest, IdNullCollation) { + BSONObj query = BSON("$id" + << "string"); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); + EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == &collator); +} + +TEST(MatchExpressionParserLeafTest, RefCollation) { + BSONObj query = BSON("$ref" + << "coll"); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); + EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == nullptr); +} + +TEST(MatchExpressionParserLeafTest, DbCollation) { + BSONObj query = BSON("$db" + << "db"); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); + EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == nullptr); +} TEST(MatchExpressionParserLeafTest, SimpleIN1) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(2 << 3))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -182,14 +420,37 @@ TEST(MatchExpressionParserLeafTest, SimpleIN1) { ASSERT(result.getValue()->matchesBSON(BSON("x" << 3))); } +TEST(MatchExpressionParserLeafTest, INNullCollation) { + BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY("string"))); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::MATCH_IN, result.getValue()->matchType()); + InMatchExpression* match = static_cast<InMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == collator); +} + +TEST(MatchExpressionParserLeafTest, INCollation) { + BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY("string"))); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::MATCH_IN, result.getValue()->matchType()); + InMatchExpression* match = static_cast<InMatchExpression*>(result.getValue().get()); + ASSERT_TRUE(match->getCollator() == &collator); +} + TEST(MatchExpressionParserLeafTest, INSingleDBRef) { OID oid = OID::gen(); BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oid << "$db" << "db")))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); OID oidx = OID::gen(); @@ -251,8 +512,9 @@ TEST(MatchExpressionParserLeafTest, INMultipleDBRef) { << "coll" << "$id" << oid << "$db" << "db")))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); OID oidx = OID::gen(); @@ -351,8 +613,9 @@ TEST(MatchExpressionParserLeafTest, INDBRefWithOptionalField1) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll" << "$id" << oid << "foo" << 12345)))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); OID oidx = OID::gen(); @@ -377,57 +640,62 @@ TEST(MatchExpressionParserLeafTest, INInvalidDBRefs) { // missing $id BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll")))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); // second field is not $id query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll" << "$foo" << 1)))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); OID oid = OID::gen(); // missing $ref field query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$id" << oid << "foo" << 3)))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); // missing $id and $ref field query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$db" << "test" << "foo" << 3)))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INExpressionDocument) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$foo" << 1)))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INNotArray) { BSONObj query = BSON("x" << BSON("$in" << 5)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INUndefined) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSONUndefined))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INNotElemMatch) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$elemMatch" << 1)))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -438,16 +706,18 @@ TEST(MatchExpressionParserLeafTest, INRegexTooLong) { BSONObjBuilder operand; operand.appendArray("$in", inArray.obj()); BSONObj query = BSON("x" << operand.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, INRegexTooLong2) { string tooLargePattern(50 * 1000, 'z'); BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$regex" << tooLargePattern)))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -460,8 +730,9 @@ TEST(MatchExpressionParserLeafTest, INRegexStuff) { operand.appendArray("$in", inArray.obj()); BSONObj query = BSON("a" << operand.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); BSONObj matchFirst = BSON("a" @@ -486,8 +757,9 @@ TEST(MatchExpressionParserLeafTest, INRegexStuff) { TEST(MatchExpressionParserLeafTest, SimpleNIN1) { BSONObj query = BSON("x" << BSON("$nin" << BSON_ARRAY(2 << 3))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -497,18 +769,45 @@ TEST(MatchExpressionParserLeafTest, SimpleNIN1) { TEST(MatchExpressionParserLeafTest, NINNotArray) { BSONObj query = BSON("x" << BSON("$nin" << 5)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } +TEST(MatchExpressionParserLeafTest, NINNullCollation) { + BSONObj query = BSON("x" << BSON("$nin" << BSON_ARRAY("string"))); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); + MatchExpression* child = result.getValue()->getChild(0); + ASSERT_EQUALS(MatchExpression::MATCH_IN, child->matchType()); + InMatchExpression* inMatch = static_cast<InMatchExpression*>(child); + ASSERT_TRUE(inMatch->getCollator() == collator); +} + +TEST(MatchExpressionParserLeafTest, NINCollation) { + BSONObj query = BSON("x" << BSON("$nin" << BSON_ARRAY("string"))); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + ASSERT_TRUE(result.isOK()); + ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); + MatchExpression* child = result.getValue()->getChild(0); + ASSERT_EQUALS(MatchExpression::MATCH_IN, child->matchType()); + InMatchExpression* inMatch = static_cast<InMatchExpression*>(child); + ASSERT_TRUE(inMatch->getCollator() == &collator); +} TEST(MatchExpressionParserLeafTest, Regex1) { BSONObjBuilder b; b.appendRegex("x", "abc", "i"); BSONObj query = b.obj(); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -524,8 +823,9 @@ TEST(MatchExpressionParserLeafTest, Regex2) { << "abc" << "$options" << "i")); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -541,8 +841,9 @@ TEST(MatchExpressionParserLeafTest, Regex3) { << "i" << "$regex" << "abc")); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); log() << "result: " << result.getStatus() << endl; ASSERT_TRUE(result.isOK()); @@ -560,35 +861,37 @@ TEST(MatchExpressionParserLeafTest, RegexBad) { << "abc" << "$optionas" << "i")); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); // $regex does not with numbers query = BSON("x" << BSON("$regex" << 123)); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$regex" << BSON_ARRAY("abc"))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$optionas" << "i")); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$options" << "i")); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, RegexEmbeddedNULByte) { BSONObj query = BSON("x" << BSON("$regex" << "^a\\x00b")); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); StringData value("a\0b", StringData::LiteralTag()); @@ -601,8 +904,9 @@ TEST(MatchExpressionParserLeafTest, ExistsYes1) { BSONObjBuilder b; b.appendBool("$exists", true); BSONObj query = BSON("x" << b.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -615,8 +919,9 @@ TEST(MatchExpressionParserLeafTest, ExistsNO1) { BSONObjBuilder b; b.appendBool("$exists", false); BSONObj query = BSON("x" << b.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -627,8 +932,9 @@ TEST(MatchExpressionParserLeafTest, ExistsNO1) { TEST(MatchExpressionParserLeafTest, Type1) { BSONObj query = BSON("x" << BSON("$type" << String)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -638,8 +944,9 @@ TEST(MatchExpressionParserLeafTest, Type1) { TEST(MatchExpressionParserLeafTest, Type2) { BSONObj query = BSON("x" << BSON("$type" << (double)NumberDouble)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -648,8 +955,9 @@ TEST(MatchExpressionParserLeafTest, Type2) { TEST(MatchExpressionParserLeafTest, TypeDoubleOperator) { BSONObj query = BSON("x" << BSON("$type" << 1.5)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -659,8 +967,9 @@ TEST(MatchExpressionParserLeafTest, TypeDoubleOperator) { TEST(MatchExpressionParserLeafTest, TypeDecimalOperator) { if (Decimal128::enabled) { BSONObj query = BSON("x" << BSON("$type" << mongo::NumberDecimal)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT_FALSE(result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -670,8 +979,9 @@ TEST(MatchExpressionParserLeafTest, TypeDecimalOperator) { TEST(MatchExpressionParserLeafTest, TypeNull) { BSONObj query = BSON("x" << BSON("$type" << jstNULL)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSONObj())); @@ -685,35 +995,44 @@ TEST(MatchExpressionParserLeafTest, TypeBadType) { BSONObjBuilder b; b.append("$type", (JSTypeMax + 1)); BSONObj query = BSON("x" << b.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, TypeBad) { BSONObj query = BSON("x" << BSON("$type" << BSON("x" << 1))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserLeafTest, TypeBadString) { + CollatorInterface* collator = nullptr; ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: null}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: true}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: {}}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse(fromjson("{a: {$type: ObjectId('000000000000000000000000')}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: []}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); } TEST(MatchExpressionParserLeafTest, TypeStringnameDouble) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeNumberDouble = MatchExpressionParser::parse( - fromjson("{a: {$type: 'double'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'double'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeNumberDouble.getStatus()); TypeMatchExpression* tmeNumberDouble = static_cast<TypeMatchExpression*>(typeNumberDouble.getValue().get()); @@ -724,8 +1043,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameDouble) { TEST(MatchExpressionParserLeafTest, TypeStringNameNumberDecimal) { if (Decimal128::enabled) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeNumberDecimal = MatchExpressionParser::parse( - fromjson("{a: {$type: 'decimal'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'decimal'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeNumberDecimal.getStatus()); TypeMatchExpression* tmeNumberDecimal = static_cast<TypeMatchExpression*>(typeNumberDecimal.getValue().get()); @@ -736,8 +1056,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringNameNumberDecimal) { } TEST(MatchExpressionParserLeafTest, TypeStringnameNumberInt) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeNumberInt = MatchExpressionParser::parse( - fromjson("{a: {$type: 'int'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'int'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeNumberInt.getStatus()); TypeMatchExpression* tmeNumberInt = static_cast<TypeMatchExpression*>(typeNumberInt.getValue().get()); @@ -747,8 +1068,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumberInt) { } TEST(MatchExpressionParserLeafTest, TypeStringnameNumberLong) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeNumberLong = MatchExpressionParser::parse( - fromjson("{a: {$type: 'long'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'long'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeNumberLong.getStatus()); TypeMatchExpression* tmeNumberLong = static_cast<TypeMatchExpression*>(typeNumberLong.getValue().get()); @@ -758,8 +1080,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumberLong) { } TEST(MatchExpressionParserLeafTest, TypeStringnameString) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeString = MatchExpressionParser::parse( - fromjson("{a: {$type: 'string'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'string'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeString.getStatus()); TypeMatchExpression* tmeString = static_cast<TypeMatchExpression*>(typeString.getValue().get()); ASSERT(tmeString->getType() == String); @@ -768,8 +1091,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameString) { } TEST(MatchExpressionParserLeafTest, TypeStringnamejstOID) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typejstOID = MatchExpressionParser::parse( - fromjson("{a: {$type: 'objectId'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'objectId'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typejstOID.getStatus()); TypeMatchExpression* tmejstOID = static_cast<TypeMatchExpression*>(typejstOID.getValue().get()); ASSERT(tmejstOID->getType() == jstOID); @@ -778,8 +1102,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnamejstOID) { } TEST(MatchExpressionParserLeafTest, TypeStringnamejstNULL) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typejstNULL = MatchExpressionParser::parse( - fromjson("{a: {$type: 'null'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'null'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typejstNULL.getStatus()); TypeMatchExpression* tmejstNULL = static_cast<TypeMatchExpression*>(typejstNULL.getValue().get()); @@ -789,8 +1114,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnamejstNULL) { } TEST(MatchExpressionParserLeafTest, TypeStringnameBool) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeBool = MatchExpressionParser::parse( - fromjson("{a: {$type: 'bool'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'bool'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeBool.getStatus()); TypeMatchExpression* tmeBool = static_cast<TypeMatchExpression*>(typeBool.getValue().get()); ASSERT(tmeBool->getType() == Bool); @@ -799,8 +1125,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameBool) { } TEST(MatchExpressionParserLeafTest, TypeStringnameObject) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeObject = MatchExpressionParser::parse( - fromjson("{a: {$type: 'object'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'object'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeObject.getStatus()); TypeMatchExpression* tmeObject = static_cast<TypeMatchExpression*>(typeObject.getValue().get()); ASSERT(tmeObject->getType() == Object); @@ -809,8 +1136,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameObject) { } TEST(MatchExpressionParserLeafTest, TypeStringnameArray) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeArray = MatchExpressionParser::parse( - fromjson("{a: {$type: 'array'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'array'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeArray.getStatus()); TypeMatchExpression* tmeArray = static_cast<TypeMatchExpression*>(typeArray.getValue().get()); ASSERT(tmeArray->getType() == Array); @@ -819,8 +1147,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameArray) { } TEST(MatchExpressionParserLeafTest, TypeStringnameNumber) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeNumber = MatchExpressionParser::parse( - fromjson("{a: {$type: 'number'}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 'number'}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(typeNumber.getStatus()); TypeMatchExpression* tmeNumber = static_cast<TypeMatchExpression*>(typeNumber.getValue().get()); ASSERT_TRUE(tmeNumber->matchesBSON(fromjson("{a: 5.4}"))); @@ -830,20 +1159,23 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumber) { } TEST(MatchExpressionParserLeafTest, InvalidTypeCodeLessThanMinKeyFailsToParse) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeNumber = MatchExpressionParser::parse( - fromjson("{a: {$type: -20}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: -20}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_NOT_OK(typeNumber.getStatus()); } TEST(MatchExpressionParserLeafTest, InvalidTypeCodeGreaterThanMaxKeyFailsToParse) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeNumber = MatchExpressionParser::parse( - fromjson("{a: {$type: 400}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 400}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_NOT_OK(typeNumber.getStatus()); } TEST(MatchExpressionParserLeafTest, InvalidTypeCodeUnusedBetweenMinAndMaxFailsToParse) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression typeNumber = MatchExpressionParser::parse( - fromjson("{a: {$type: 62}}"), ExtensionsCallbackDisallowExtensions()); + fromjson("{a: {$type: 62}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT_NOT_OK(typeNumber.getStatus()); } @@ -855,8 +1187,9 @@ TEST(MatchExpressionParserLeafTest, ValidTypeCodesParseSuccessfully) { for (auto type : validTypes) { BSONObj predicate = BSON("a" << BSON("$type" << type)); - auto expression = - MatchExpressionParser::parse(predicate, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + auto expression = MatchExpressionParser::parse( + predicate, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(expression.getStatus()); auto typeExpression = static_cast<TypeMatchExpression*>(expression.getValue().get()); ASSERT_EQ(type, typeExpression->getType()); @@ -866,45 +1199,62 @@ TEST(MatchExpressionParserLeafTest, ValidTypeCodesParseSuccessfully) { TEST(MatchExpressionParserTest, BitTestMatchExpressionValidMask) { const double k2Power53 = scalbn(1, 32); + CollatorInterface* collator = nullptr; ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << 54)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<long long>::max())), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53 - 1)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << 54)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<long long>::max())), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << k2Power53)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << k2Power53 - 1)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << 54)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<long long>::max())), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53 - 1)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << 54)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<long long>::max())), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53 - 1)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionValidArray) { @@ -914,335 +1264,460 @@ TEST(MatchExpressionParserTest, BitTestMatchExpressionValidArray) { ASSERT_EQ(BSONType::NumberLong, bsonArrayLongLong[2].type()); ASSERT_EQ(BSONType::NumberLong, bsonArrayLongLong[3].type()); + CollatorInterface* collator = nullptr; ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0 << 1 << 2 << 3))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << bsonArrayLongLong)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<int>::max()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0 << 1 << 2 << 3))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << bsonArrayLongLong)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<int>::max()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0 << 1 << 2 << 3))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << bsonArrayLongLong)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<int>::max()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0 << 1 << 2 << 3))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << bsonArrayLongLong)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<int>::max()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionValidBinData) { + CollatorInterface* collator = nullptr; ASSERT_OK( MatchExpressionParser::parse( fromjson("{a: {$bitsAllSet: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAllClear: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK( MatchExpressionParser::parse( fromjson("{a: {$bitsAnySet: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAnyClear: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidMaskType) { + CollatorInterface* collator = nullptr; ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: null}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: true}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: {}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ''}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: null}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: true}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: {}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ''}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( fromjson("{a: {$bitsAllClear: ObjectId('000000000000000000000000')}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: null}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: true}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: {}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ''}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( fromjson("{a: {$bitsAnySet: ObjectId('000000000000000000000000')}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: null}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: true}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: {}}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ''}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( fromjson("{a: {$bitsAnyClear: ObjectId('000000000000000000000000')}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidMaskValue) { const double kLongLongMaxAsDouble = scalbn(1, std::numeric_limits<long long>::digits); + CollatorInterface* collator = nullptr; ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: NaN}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: -54}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<double>::max())), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << kLongLongMaxAsDouble)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: 2.5}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: NaN}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: -54}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<double>::max())), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << kLongLongMaxAsDouble)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: 2.5}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: NaN}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: -54}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<double>::max())), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << kLongLongMaxAsDouble)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: 2.5}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: NaN}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: -54}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<double>::max())), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << kLongLongMaxAsDouble)), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: 2.5}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidArray) { + CollatorInterface* collator = nullptr; ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [null]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [true]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ['']}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [{}]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [[]]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAllSet: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [null]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [true]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ['']}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [{}]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [[]]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAllClear: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [null]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [true]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ['']}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [{}]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [[]]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAnySet: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [null]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [true]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ['']}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [{}]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [[]]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAnyClear: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidArrayValue) { + CollatorInterface* collator = nullptr; ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-54]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [NaN]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [1e100]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1e100]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-54]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [NaN]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [1e100]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1e100]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-54]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [NaN]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [1e100]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1e100]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-54]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [NaN]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [1e100]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1e100]}}"), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - ExtensionsCallbackDisallowExtensions()).getStatus()); + ExtensionsCallbackDisallowExtensions(), + collator).getStatus()); } } diff --git a/src/mongo/db/matcher/expression_parser_test.cpp b/src/mongo/db/matcher/expression_parser_test.cpp index 0c800d2863b..35b55c0b9f6 100644 --- a/src/mongo/db/matcher/expression_parser_test.cpp +++ b/src/mongo/db/matcher/expression_parser_test.cpp @@ -42,8 +42,9 @@ namespace mongo { TEST(MatchExpressionParserTest, SimpleEQ1) { BSONObj query = BSON("x" << 2); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -52,8 +53,9 @@ TEST(MatchExpressionParserTest, SimpleEQ1) { TEST(MatchExpressionParserTest, Multiple1) { BSONObj query = BSON("x" << 5 << "y" << BSON("$gt" << 5 << "$lt" << 8)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5 << "y" << 7))); @@ -65,23 +67,25 @@ TEST(MatchExpressionParserTest, Multiple1) { TEST(AtomicMatchExpressionTest, AtomicOperator1) { BSONObj query = BSON("x" << 5 << "$atomic" << BSON("$gt" << 5 << "$lt" << 8)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); query = BSON("x" << 5 << "$isolated" << 1); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); query = BSON("x" << 5 << "y" << BSON("$isolated" << 1)); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserTest, MinDistanceWithoutNearFailsToParse) { BSONObj query = fromjson("{loc: {$minDistance: 10}}"); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } diff --git a/src/mongo/db/matcher/expression_parser_tree_test.cpp b/src/mongo/db/matcher/expression_parser_tree_test.cpp index a5a3413eec2..01e52c33841 100644 --- a/src/mongo/db/matcher/expression_parser_tree_test.cpp +++ b/src/mongo/db/matcher/expression_parser_tree_test.cpp @@ -42,8 +42,9 @@ namespace mongo { TEST(MatchExpressionParserTreeTest, OR1) { BSONObj query = BSON("$or" << BSON_ARRAY(BSON("x" << 1) << BSON("y" << 2))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -55,8 +56,9 @@ TEST(MatchExpressionParserTreeTest, OR1) { TEST(MatchExpressionParserTreeTest, OREmbedded) { BSONObj query1 = BSON("$or" << BSON_ARRAY(BSON("x" << 1) << BSON("y" << 2))); BSONObj query2 = BSON("$or" << BSON_ARRAY(query1)); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query2, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query2, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -68,8 +70,9 @@ TEST(MatchExpressionParserTreeTest, OREmbedded) { TEST(MatchExpressionParserTreeTest, AND1) { BSONObj query = BSON("$and" << BSON_ARRAY(BSON("x" << 1) << BSON("y" << 2))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -82,8 +85,9 @@ TEST(MatchExpressionParserTreeTest, AND1) { TEST(MatchExpressionParserTreeTest, NOREmbedded) { BSONObj query = BSON("$nor" << BSON_ARRAY(BSON("x" << 1) << BSON("y" << 2))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -94,8 +98,9 @@ TEST(MatchExpressionParserTreeTest, NOREmbedded) { TEST(MatchExpressionParserTreeTest, NOT1) { BSONObj query = BSON("x" << BSON("$not" << BSON("$gt" << 5))); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -116,8 +121,9 @@ TEST(MatchExpressionParserTreeTest, MaximumTreeDepthNotExceed) { } BSONObj query = fromjson(ss.str()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT(result.isOK()); } @@ -135,8 +141,9 @@ TEST(MatchExpressionParserTreeTest, MaximumTreeDepthExceed) { } BSONObj query = fromjson(ss.str()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -155,8 +162,9 @@ TEST(MatchExpressionParserTreeTest, MaximumTreeDepthExceededNestedNots) { } BSONObj query = fromjson(ss.str()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -174,8 +182,9 @@ TEST(MatchExpressionParserTreeTest, MaximumTreeDepthExceededNestedElemMatch) { } BSONObj query = fromjson(ss.str()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_FALSE(result.isOK()); } @@ -183,8 +192,9 @@ TEST(MatchExpressionParserLeafTest, NotRegex1) { BSONObjBuilder b; b.appendRegex("$not", "abc", "i"); BSONObj query = BSON("x" << b.obj()); + CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" diff --git a/src/mongo/db/matcher/expression_serialization_test.cpp b/src/mongo/db/matcher/expression_serialization_test.cpp index 39a472adef6..43f6f6ebf25 100644 --- a/src/mongo/db/matcher/expression_serialization_test.cpp +++ b/src/mongo/db/matcher/expression_serialization_test.cpp @@ -51,8 +51,10 @@ BSONObj serialize(MatchExpression* match) { } TEST(SerializeBasic, AndExpressionWithOneChildSerializesCorrectly) { - Matcher original(fromjson("{$and: [{x: 0}]}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{$and: [{x: 0}]}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 0}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -64,8 +66,10 @@ TEST(SerializeBasic, AndExpressionWithOneChildSerializesCorrectly) { } TEST(SerializeBasic, AndExpressionWithTwoChildrenSerializesCorrectly) { - Matcher original(fromjson("{$and: [{x: 1}, {x: 2}]}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{$and: [{x: 1}, {x: 2}]}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 2}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -77,8 +81,10 @@ TEST(SerializeBasic, AndExpressionWithTwoChildrenSerializesCorrectly) { } TEST(SerializeBasic, AndExpressionWithTwoIdenticalChildrenSerializesCorrectly) { - Matcher original(fromjson("{$and: [{x: 1}, {x: 1}]}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{$and: [{x: 1}, {x: 1}]}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 1}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -90,8 +96,10 @@ TEST(SerializeBasic, AndExpressionWithTwoIdenticalChildrenSerializesCorrectly) { } TEST(SerializeBasic, ExpressionOr) { - Matcher original(fromjson("{$or: [{x: 'A'}, {x: 'B'}]}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{$or: [{x: 'A'}, {x: 'B'}]}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$or: [{x: {$eq: 'A'}}, {x: {$eq: 'B'}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -103,9 +111,12 @@ TEST(SerializeBasic, ExpressionOr) { } TEST(SerializeBasic, ExpressionElemMatchObjectSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original(fromjson("{x: {$elemMatch: {a: {$gt: 0}, b: {$gt: 0}}}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$elemMatch: {$and: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -118,9 +129,12 @@ TEST(SerializeBasic, ExpressionElemMatchObjectSerializesCorrectly) { } TEST(SerializeBasic, ExpressionElemMatchObjectWithEmptyStringSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original(fromjson("{'': {$elemMatch: {a: {$gt: 0}, b: {$gt: 0}}}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{'': {$elemMatch: {$and: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -133,8 +147,11 @@ TEST(SerializeBasic, ExpressionElemMatchObjectWithEmptyStringSerializesCorrectly } TEST(SerializeBasic, ExpressionElemMatchValueSerializesCorrectly) { - Matcher original(fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original( + fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -149,8 +166,11 @@ TEST(SerializeBasic, ExpressionElemMatchValueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionElemMatchValueWithEmptyStringSerializesCorrectly) { - Matcher original(fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original( + fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -165,8 +185,10 @@ TEST(SerializeBasic, ExpressionElemMatchValueWithEmptyStringSerializesCorrectly) } TEST(SerializeBasic, ExpressionSizeSerializesCorrectly) { - Matcher original(fromjson("{x: {$size: 2}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$size: 2}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$size: 2}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -178,8 +200,10 @@ TEST(SerializeBasic, ExpressionSizeSerializesCorrectly) { } TEST(SerializeBasic, ExpressionAllSerializesCorrectly) { - Matcher original(fromjson("{x: {$all: [1, 2]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$all: [1, 2]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 2}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -191,8 +215,10 @@ TEST(SerializeBasic, ExpressionAllSerializesCorrectly) { } TEST(SerializeBasic, ExpressionAllWithEmptyArraySerializesCorrectly) { - Matcher original(fromjson("{x: {$all: []}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$all: []}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$all: []}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -201,8 +227,11 @@ TEST(SerializeBasic, ExpressionAllWithEmptyArraySerializesCorrectly) { } TEST(SerializeBasic, ExpressionAllWithRegex) { - Matcher original(fromjson("{x: {$all: [/a.b.c/, /.d.e./]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original( + fromjson("{x: {$all: [/a.b.c/, /.d.e./]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: /a.b.c/}, {x: /.d.e./}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -214,8 +243,10 @@ TEST(SerializeBasic, ExpressionAllWithRegex) { } TEST(SerializeBasic, ExpressionEqSerializesCorrectly) { - Matcher original(fromjson("{x: {$eq: {a: 1}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$eq: {a: 1}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$eq: {a: 1}}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -230,8 +261,10 @@ TEST(SerializeBasic, ExpressionEqSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNeSerializesCorrectly) { - Matcher original(fromjson("{x: {$ne: {a: 1}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$ne: {a: 1}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$eq: {a: 1}}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -243,8 +276,10 @@ TEST(SerializeBasic, ExpressionNeSerializesCorrectly) { } TEST(SerializeBasic, ExpressionLtSerializesCorrectly) { - Matcher original(fromjson("{x: {$lt: 3}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$lt: 3}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$lt: 3}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -256,8 +291,10 @@ TEST(SerializeBasic, ExpressionLtSerializesCorrectly) { } TEST(SerializeBasic, ExpressionGtSerializesCorrectly) { - Matcher original(fromjson("{x: {$gt: 3}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$gt: 3}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$gt: 3}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -269,8 +306,10 @@ TEST(SerializeBasic, ExpressionGtSerializesCorrectly) { } TEST(SerializeBasic, ExpressionGteSerializesCorrectly) { - Matcher original(fromjson("{x: {$gte: 3}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$gte: 3}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$gte: 3}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -282,8 +321,10 @@ TEST(SerializeBasic, ExpressionGteSerializesCorrectly) { } TEST(SerializeBasic, ExpressionLteSerializesCorrectly) { - Matcher original(fromjson("{x: {$lte: 3}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$lte: 3}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$lte: 3}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -295,8 +336,10 @@ TEST(SerializeBasic, ExpressionLteSerializesCorrectly) { } TEST(SerializeBasic, ExpressionRegexWithObjSerializesCorrectly) { - Matcher original(fromjson("{x: {$regex: 'a.b'}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$regex: 'a.b'}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$regex: 'a.b'}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -308,8 +351,10 @@ TEST(SerializeBasic, ExpressionRegexWithObjSerializesCorrectly) { } TEST(SerializeBasic, ExpressionRegexWithValueSerializesCorrectly) { - Matcher original(fromjson("{x: /a.b/i}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: /a.b/i}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$regex: 'a.b', $options: 'i'}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -321,8 +366,10 @@ TEST(SerializeBasic, ExpressionRegexWithValueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionRegexWithValueAndOptionsSerializesCorrectly) { - Matcher original(fromjson("{x: /a.b/}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: /a.b/}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$regex: 'a.b'}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -334,8 +381,10 @@ TEST(SerializeBasic, ExpressionRegexWithValueAndOptionsSerializesCorrectly) { } TEST(SerializeBasic, ExpressionRegexWithEqObjSerializesCorrectly) { - Matcher original(fromjson("{x: {$eq: {$regex: 'a.b'}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$eq: {$regex: 'a.b'}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$eq: {$regex: 'a.b'}}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -350,8 +399,10 @@ TEST(SerializeBasic, ExpressionRegexWithEqObjSerializesCorrectly) { } TEST(SerializeBasic, ExpressionModSerializesCorrectly) { - Matcher original(fromjson("{x: {$mod: [2, 1]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$mod: [2, 1]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$mod: [2, 1]}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -363,8 +414,10 @@ TEST(SerializeBasic, ExpressionModSerializesCorrectly) { } TEST(SerializeBasic, ExpressionExistsTrueSerializesCorrectly) { - Matcher original(fromjson("{x: {$exists: true}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$exists: true}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$exists: true}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -376,8 +429,10 @@ TEST(SerializeBasic, ExpressionExistsTrueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionExistsFalseSerializesCorrectly) { - Matcher original(fromjson("{x: {$exists: false}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$exists: false}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$exists: true}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -389,8 +444,10 @@ TEST(SerializeBasic, ExpressionExistsFalseSerializesCorrectly) { } TEST(SerializeBasic, ExpressionInSerializesCorrectly) { - Matcher original(fromjson("{x: {$in: [1, 2, 3]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$in: [1, 2, 3]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$in: [1, 2, 3]}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -405,8 +462,10 @@ TEST(SerializeBasic, ExpressionInSerializesCorrectly) { } TEST(SerializeBasic, ExpressionInWithEmptyArraySerializesCorrectly) { - Matcher original(fromjson("{x: {$in: []}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$in: []}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$in: []}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -415,8 +474,10 @@ TEST(SerializeBasic, ExpressionInWithEmptyArraySerializesCorrectly) { } TEST(SerializeBasic, ExpressionInWithRegexSerializesCorrectly) { - Matcher original(fromjson("{x: {$in: [/\\d+/, /\\w+/]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$in: [/\\d+/, /\\w+/]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$in: [/\\d+/, /\\w+/]}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -431,8 +492,10 @@ TEST(SerializeBasic, ExpressionInWithRegexSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNinSerializesCorrectly) { - Matcher original(fromjson("{x: {$nin: [1, 2, 3]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$nin: [1, 2, 3]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$in: [1, 2, 3]}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -447,8 +510,10 @@ TEST(SerializeBasic, ExpressionNinSerializesCorrectly) { } TEST(SerializeBasic, ExpressionBitsAllSetSerializesCorrectly) { - Matcher original(fromjson("{x: {$bitsAllSet: [1, 3]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$bitsAllSet: [1, 3]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAllSet: [1, 3]}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -460,8 +525,10 @@ TEST(SerializeBasic, ExpressionBitsAllSetSerializesCorrectly) { } TEST(SerializeBasic, ExpressionBitsAllClearSerializesCorrectly) { - Matcher original(fromjson("{x: {$bitsAllClear: [1, 3]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$bitsAllClear: [1, 3]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAllClear: [1, 3]}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -473,8 +540,10 @@ TEST(SerializeBasic, ExpressionBitsAllClearSerializesCorrectly) { } TEST(SerializeBasic, ExpressionBitsAnySetSerializesCorrectly) { - Matcher original(fromjson("{x: {$bitsAnySet: [1, 3]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$bitsAnySet: [1, 3]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAnySet: [1, 3]}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -486,8 +555,10 @@ TEST(SerializeBasic, ExpressionBitsAnySetSerializesCorrectly) { } TEST(SerializeBasic, ExpressionBitsAnyClearSerializesCorrectly) { - Matcher original(fromjson("{x: {$bitsAnyClear: [1, 3]}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$bitsAnyClear: [1, 3]}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAnyClear: [1, 3]}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -502,8 +573,10 @@ TEST(SerializeBasic, ExpressionBitsAnyClearSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: {$eq: 3}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$not: {$eq: 3}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$eq: 3}}]}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -515,8 +588,10 @@ TEST(SerializeBasic, ExpressionNotSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithMultipleChildrenSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: {$lt: 1, $gt: 3}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$not: {$lt: 1, $gt: 3}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$lt: 1}}, {x: {$gt: 3}}]}]}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -529,8 +604,11 @@ TEST(SerializeBasic, ExpressionNotWithMultipleChildrenSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithBitTestSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: {$bitsAnySet: [1, 3]}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original( + fromjson("{x: {$not: {$bitsAnySet: [1, 3]}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$bitsAnySet: [1, 3]}}]}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -542,8 +620,10 @@ TEST(SerializeBasic, ExpressionNotWithBitTestSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithRegexObjSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: {$regex: 'a.b'}}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$not: {$regex: 'a.b'}}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: /a.b/}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -555,8 +635,10 @@ TEST(SerializeBasic, ExpressionNotWithRegexObjSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithRegexValueSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: /a.b/}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$not: /a.b/}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: /a.b/}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -568,8 +650,10 @@ TEST(SerializeBasic, ExpressionNotWithRegexValueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithRegexValueAndOptionsSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: /a.b/i}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$not: /a.b/i}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: /a.b/i}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -581,12 +665,15 @@ TEST(SerializeBasic, ExpressionNotWithRegexValueAndOptionsSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithGeoSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original(fromjson( "{x: {$not: {$geoIntersects: {$geometry: {type: 'Polygon', " "coordinates: [[[0,0], [5,0], " "[5, 5], [0, 5], [0, 0]]]}}}}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson( "{$nor: [{$and: [{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: " @@ -609,8 +696,11 @@ TEST(SerializeBasic, ExpressionNotWithGeoSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNorSerializesCorrectly) { - Matcher original(fromjson("{$nor: [{x: 3}, {x: {$lt: 1}}]}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original( + fromjson("{$nor: [{x: 3}, {x: {$lt: 1}}]}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$eq: 3}}, {x: {$lt: 1}}]}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -625,8 +715,10 @@ TEST(SerializeBasic, ExpressionNorSerializesCorrectly) { } TEST(SerializeBasic, ExpressionTypeSerializesCorrectly) { - Matcher original(fromjson("{x: {$type: 2}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$type: 2}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$type: 2}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -638,8 +730,10 @@ TEST(SerializeBasic, ExpressionTypeSerializesCorrectly) { } TEST(SerializeBasic, ExpressionTypeWithNumberSerializesCorrectly) { - Matcher original(fromjson("{x: {$type: 'number'}}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{x: {$type: 'number'}}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{x: {$type: 'number'}}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -651,8 +745,10 @@ TEST(SerializeBasic, ExpressionTypeWithNumberSerializesCorrectly) { } TEST(SerializeBasic, ExpressionEmptySerializesCorrectly) { - Matcher original(fromjson("{}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -661,25 +757,32 @@ TEST(SerializeBasic, ExpressionEmptySerializesCorrectly) { } TEST(SerializeBasic, ExpressionWhereSerializesCorrectly) { - Matcher original(fromjson("{$where: 'this.a == this.b'}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{$where: 'this.a == this.b'}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), BSONObjBuilder().appendCodeWScope("$where", "this.a == this.b", BSONObj()).obj()); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeBasic, ExpressionWhereWithScopeSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original(BSON("$where" << BSONCodeWScope("this.a == this.b", BSON("x" << 3))), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), BSON("$where" << BSONCodeWScope("this.a == this.b", BSON("x" << 3)))); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeBasic, ExpressionCommentSerializesCorrectly) { - Matcher original(fromjson("{$comment: 'Hello'}"), ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + Matcher original(fromjson("{$comment: 'Hello'}"), ExtensionsCallbackNoop(), collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson("{}")); ASSERT_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -691,12 +794,15 @@ TEST(SerializeBasic, ExpressionCommentSerializesCorrectly) { } TEST(SerializeBasic, ExpressionGeoWithinSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original( fromjson( "{x: {$geoWithin: {$geometry: " "{type: 'Polygon', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]]}}}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson( "{x: {$geoWithin: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [10,0], " @@ -711,12 +817,15 @@ TEST(SerializeBasic, ExpressionGeoWithinSerializesCorrectly) { } TEST(SerializeBasic, ExpressionGeoIntersectsSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original( fromjson( "{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [5,0], [5, " "5], [0, 5], [0, 0]]]}}}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson( "{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [5,0], " @@ -738,12 +847,15 @@ TEST(SerializeBasic, ExpressionGeoIntersectsSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNearSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original( fromjson( "{x: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " "$minDistance: 1}}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson( "{x: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " @@ -752,12 +864,15 @@ TEST(SerializeBasic, ExpressionNearSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNearSphereSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original( fromjson( "{x: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " "$minDistance: 1}}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson( "{x: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}, " @@ -766,9 +881,12 @@ TEST(SerializeBasic, ExpressionNearSphereSerializesCorrectly) { } TEST(SerializeBasic, ExpressionTextSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original(fromjson("{$text: {$search: 'a', $language: 'en', $caseSensitive: true}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson( "{$text: {$search: 'a', $language: 'en', $caseSensitive: true, " @@ -777,9 +895,12 @@ TEST(SerializeBasic, ExpressionTextSerializesCorrectly) { } TEST(SerializeBasic, ExpressionTextWithDefaultLanguageSerializesCorrectly) { + CollatorInterface* collator = nullptr; Matcher original(fromjson("{$text: {$search: 'a', $caseSensitive: false}}"), - ExtensionsCallbackNoop()); - Matcher reserialized(serialize(original.getMatchExpression()), ExtensionsCallbackNoop()); + ExtensionsCallbackNoop(), + collator); + Matcher reserialized( + serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), collator); ASSERT_EQ(*reserialized.getQuery(), fromjson( "{$text: {$search: 'a', $language: '', $caseSensitive: false, " diff --git a/src/mongo/db/matcher/matcher.cpp b/src/mongo/db/matcher/matcher.cpp index c0ed2bf6985..0668848c4ad 100644 --- a/src/mongo/db/matcher/matcher.cpp +++ b/src/mongo/db/matcher/matcher.cpp @@ -41,10 +41,12 @@ namespace mongo { -Matcher::Matcher(const BSONObj& pattern, const ExtensionsCallback& extensionsCallback) +Matcher::Matcher(const BSONObj& pattern, + const ExtensionsCallback& extensionsCallback, + CollatorInterface* collator) : _pattern(pattern) { StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(pattern, extensionsCallback); + MatchExpressionParser::parse(pattern, extensionsCallback, collator); uassert(16810, mongoutils::str::stream() << "bad query: " << statusWithMatcher.getStatus().toString(), statusWithMatcher.isOK()); diff --git a/src/mongo/db/matcher/matcher.h b/src/mongo/db/matcher/matcher.h index 99b54b37a8a..3d64908036e 100644 --- a/src/mongo/db/matcher/matcher.h +++ b/src/mongo/db/matcher/matcher.h @@ -41,6 +41,8 @@ namespace mongo { +class CollatorInterface; + /** * Matcher is a simple wrapper around a BSONObj and the MatchExpression created from it. */ @@ -48,7 +50,12 @@ class Matcher { MONGO_DISALLOW_COPYING(Matcher); public: - explicit Matcher(const BSONObj& pattern, const ExtensionsCallback& extensionsCallback); + /** + * 'collator' must outlive the returned Matcher and any MatchExpression cloned from it. + */ + explicit Matcher(const BSONObj& pattern, + const ExtensionsCallback& extensionsCallback, + CollatorInterface* collator); bool matches(const BSONObj& doc, MatchDetails* details = NULL) const; diff --git a/src/mongo/db/ops/modifier_pull.cpp b/src/mongo/db/ops/modifier_pull.cpp index 2986af6d86f..f73f853be1d 100644 --- a/src/mongo/db/ops/modifier_pull.cpp +++ b/src/mongo/db/ops/modifier_pull.cpp @@ -118,8 +118,9 @@ Status ModifierPull::init(const BSONElement& modExpr, const Options& opts, bool* // Build the matcher around the object we built above. Currently, we do not allow $pull // operations to contain $text/$where clauses, so preserving this behaviour. + // TODO SERVER-23689: Pass the appropriate CollatorInterface* instead of nullptr. StatusWithMatchExpression parseResult = - MatchExpressionParser::parse(_exprObj, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(_exprObj, ExtensionsCallbackDisallowExtensions(), nullptr); if (!parseResult.isOK()) { return parseResult.getStatus(); } diff --git a/src/mongo/db/ops/path_support_test.cpp b/src/mongo/db/ops/path_support_test.cpp index 310a6eb2f72..a5d5e060de9 100644 --- a/src/mongo/db/ops/path_support_test.cpp +++ b/src/mongo/db/ops/path_support_test.cpp @@ -521,7 +521,8 @@ TEST_F(ArrayDoc, NonNumericPathInArray) { // static MatchExpression* makeExpr(const BSONObj& exprBSON) { - return MatchExpressionParser::parse(exprBSON, ExtensionsCallbackDisallowExtensions()) + CollatorInterface* collator = nullptr; + return MatchExpressionParser::parse(exprBSON, ExtensionsCallbackDisallowExtensions(), collator) .getValue() .release(); } diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp index 87866267ea2..21f7dab580c 100644 --- a/src/mongo/db/pipeline/document_source_match.cpp +++ b/src/mongo/db/pipeline/document_source_match.cpp @@ -357,8 +357,9 @@ bool DocumentSourceMatch::isTextQuery(const BSONObj& query) { void DocumentSourceMatch::joinMatchWith(intrusive_ptr<DocumentSourceMatch> other) { _predicate = BSON("$and" << BSON_ARRAY(_predicate << other->getQuery())); - StatusWithMatchExpression status = - uassertStatusOK(MatchExpressionParser::parse(_predicate, ExtensionsCallbackNoop())); + // TODO SERVER-23349: Pass the appropriate CollatorInterface* instead of nullptr. + StatusWithMatchExpression status = uassertStatusOK( + MatchExpressionParser::parse(_predicate, ExtensionsCallbackNoop(), nullptr)); _expression = std::move(status.getValue()); } @@ -492,8 +493,10 @@ void DocumentSourceMatch::addDependencies(DepsTracker* deps) const { DocumentSourceMatch::DocumentSourceMatch(const BSONObj& query, const intrusive_ptr<ExpressionContext>& pExpCtx) : DocumentSource(pExpCtx), _predicate(query.getOwned()), _isTextQuery(isTextQuery(query)) { - StatusWithMatchExpression status = - uassertStatusOK(MatchExpressionParser::parse(_predicate, ExtensionsCallbackNoop())); + // TODO SERVER-23349: Pass the appropriate CollatorInterface* instead of nullptr. + StatusWithMatchExpression status = uassertStatusOK( + MatchExpressionParser::parse(_predicate, ExtensionsCallbackNoop(), nullptr)); + _expression = std::move(status.getValue()); getDependencies(&_dependencies); } diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index 5e3f5a2b1a1..5cc41126c79 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -213,8 +213,9 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( std::unique_ptr<LiteParsedQuery> autoLpq(lpq); // Make MatchExpression. + // TODO SERVER-23610: pass our CollatorInterface* instead of nullptr. StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(autoLpq->getFilter(), extensionsCallback); + MatchExpressionParser::parse(autoLpq->getFilter(), extensionsCallback, nullptr); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } @@ -292,8 +293,9 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( auto& lpq = lpqStatus.getValue(); // Build a parse tree from the BSONObj in the parsed query. + // TODO SERVER-23610: pass our CollatorInterface* instead of nullptr. StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(lpq->getFilter(), extensionsCallback); + MatchExpressionParser::parse(lpq->getFilter(), extensionsCallback, nullptr); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } diff --git a/src/mongo/db/query/canonical_query_test.cpp b/src/mongo/db/query/canonical_query_test.cpp index 50574135059..dcfbefcaf77 100644 --- a/src/mongo/db/query/canonical_query_test.cpp +++ b/src/mongo/db/query/canonical_query_test.cpp @@ -51,7 +51,9 @@ static const NamespaceString nss("testdb.testcoll"); * and return the MatchExpression*. */ MatchExpression* parseMatchExpression(const BSONObj& obj) { - StatusWithMatchExpression status = MatchExpressionParser::parse(obj, ExtensionsCallbackNoop()); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression status = + MatchExpressionParser::parse(obj, ExtensionsCallbackNoop(), collator); if (!status.isOK()) { mongoutils::str::stream ss; ss << "failed to parse query: " << obj.toString() diff --git a/src/mongo/db/query/index_bounds_builder_test.cpp b/src/mongo/db/query/index_bounds_builder_test.cpp index d29500d16cd..3380562599b 100644 --- a/src/mongo/db/query/index_bounds_builder_test.cpp +++ b/src/mongo/db/query/index_bounds_builder_test.cpp @@ -59,8 +59,9 @@ double NaN = numeric_limits<double>::quiet_NaN(); * Utility function to create MatchExpression */ MatchExpression* parseMatchExpression(const BSONObj& obj) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(status.isOK()); MatchExpression* expr(status.getValue().release()); return expr; diff --git a/src/mongo/db/query/parsed_projection.cpp b/src/mongo/db/query/parsed_projection.cpp index d8d490c2ab7..621b3ce5bc9 100644 --- a/src/mongo/db/query/parsed_projection.cpp +++ b/src/mongo/db/query/parsed_projection.cpp @@ -123,8 +123,9 @@ Status ParsedProjection::make(const BSONObj& spec, invariant(elemMatchObj.isOwned()); // TODO: Is there a faster way of validating the elemMatchObj? + // TODO SERVER-23680: pass the appropriate CollatorInterface* instead of nullptr. StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(elemMatchObj, extensionsCallback); + MatchExpressionParser::parse(elemMatchObj, extensionsCallback, nullptr); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } diff --git a/src/mongo/db/query/parsed_projection_test.cpp b/src/mongo/db/query/parsed_projection_test.cpp index 64c379dacb2..5b246d8f4d4 100644 --- a/src/mongo/db/query/parsed_projection_test.cpp +++ b/src/mongo/db/query/parsed_projection_test.cpp @@ -47,8 +47,9 @@ using namespace mongo; // unique_ptr<ParsedProjection> createParsedProjection(const BSONObj& query, const BSONObj& projObj) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT(statusWithMatcher.isOK()); std::unique_ptr<MatchExpression> queryMatchExpr = std::move(statusWithMatcher.getValue()); ParsedProjection* out = NULL; @@ -75,8 +76,9 @@ unique_ptr<ParsedProjection> createParsedProjection(const char* queryStr, const void assertInvalidProjection(const char* queryStr, const char* projStr) { BSONObj query = fromjson(queryStr); BSONObj projObj = fromjson(projStr); + CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT(statusWithMatcher.isOK()); std::unique_ptr<MatchExpression> queryMatchExpr = std::move(statusWithMatcher.getValue()); ParsedProjection* out = NULL; diff --git a/src/mongo/db/query/plan_cache_indexability_test.cpp b/src/mongo/db/query/plan_cache_indexability_test.cpp index bef185e8503..9d64ea157c2 100644 --- a/src/mongo/db/query/plan_cache_indexability_test.cpp +++ b/src/mongo/db/query/plan_cache_indexability_test.cpp @@ -36,8 +36,9 @@ namespace mongo { namespace { std::unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); if (!status.isOK()) { FAIL(str::stream() << "failed to parse query: " << obj.toString() << ". Reason: " << status.getStatus().toString()); diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp index 48aa9b2bb89..51ae170d3ae 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -151,8 +151,9 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, * Utility function to create MatchExpression */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); if (!status.isOK()) { str::stream ss; ss << "failed to parse query: " << obj.toString() diff --git a/src/mongo/db/query/planner_ixselect_test.cpp b/src/mongo/db/query/planner_ixselect_test.cpp index 934079fcf24..47c64a049ae 100644 --- a/src/mongo/db/query/planner_ixselect_test.cpp +++ b/src/mongo/db/query/planner_ixselect_test.cpp @@ -53,8 +53,9 @@ using std::vector; * Utility function to create MatchExpression */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_TRUE(status.isOK()); return std::move(status.getValue()); } diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp index e690d5ff48b..288c010c8dd 100644 --- a/src/mongo/db/query/query_planner_test_fixture.cpp +++ b/src/mongo/db/query/query_planner_test_fixture.cpp @@ -374,8 +374,9 @@ void QueryPlannerTest::assertHasOneSolutionOf(const std::vector<std::string>& so } std::unique_ptr<MatchExpression> QueryPlannerTest::parseMatchExpression(const BSONObj& obj) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); if (!status.isOK()) { FAIL(str::stream() << "failed to parse query: " << obj.toString() << ". Reason: " << status.getStatus().toString()); diff --git a/src/mongo/db/query/query_planner_test_lib.cpp b/src/mongo/db/query/query_planner_test_lib.cpp index fe9daeffaae..ba0bc5d569a 100644 --- a/src/mongo/db/query/query_planner_test_lib.cpp +++ b/src/mongo/db/query/query_planner_test_lib.cpp @@ -52,8 +52,9 @@ bool filterMatches(const BSONObj& testFilter, const QuerySolutionNode* trueFilte if (NULL == trueFilterNode->filter) { return false; } + CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(testFilter, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(testFilter, ExtensionsCallbackDisallowExtensions(), collator); if (!statusWithMatcher.isOK()) { return false; } diff --git a/src/mongo/db/query/query_solution_test.cpp b/src/mongo/db/query/query_solution_test.cpp index ed7b4cdf615..913a76609f0 100644 --- a/src/mongo/db/query/query_solution_test.cpp +++ b/src/mongo/db/query/query_solution_test.cpp @@ -251,8 +251,9 @@ TEST(QuerySolutionTest, IntervalListSomePoints) { std::unique_ptr<ParsedProjection> createParsedProjection(const BSONObj& query, const BSONObj& projObj) { + CollatorInterface* collator = nullptr; StatusWithMatchExpression queryMatchExpr = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()); + MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT(queryMatchExpr.isOK()); ParsedProjection* out = nullptr; Status status = ParsedProjection::make( diff --git a/src/mongo/dbtests/matchertests.cpp b/src/mongo/dbtests/matchertests.cpp index ef4c6498384..ce24738b325 100644 --- a/src/mongo/dbtests/matchertests.cpp +++ b/src/mongo/dbtests/matchertests.cpp @@ -39,6 +39,8 @@ #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/matcher/matcher.h" +#include "mongo/db/operation_context_impl.h" +#include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/dbtests/dbtests.h" #include "mongo/util/timer.h" @@ -60,7 +62,8 @@ class Basic { public: void run() { BSONObj query = fromjson("{\"a\":\"b\"}"); - M m(query, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M m(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT(m.matches(fromjson("{\"a\":\"b\"}"))); } }; @@ -70,7 +73,8 @@ class DoubleEqual { public: void run() { BSONObj query = fromjson("{\"a\":5}"); - M m(query, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M m(query, ExtensionsCallbackDisallowExtensions(), collator); ASSERT(m.matches(fromjson("{\"a\":5}"))); } }; @@ -81,7 +85,8 @@ public: void run() { BSONObjBuilder query; query.append("a", 5); - M m(query.done(), ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M m(query.done(), ExtensionsCallbackDisallowExtensions(), collator); ASSERT(m.matches(fromjson("{\"a\":5}"))); } }; @@ -91,7 +96,8 @@ class MixedNumericGt { public: void run() { BSONObj query = fromjson("{\"a\":{\"$gt\":4}}"); - M m(query, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M m(query, ExtensionsCallbackDisallowExtensions(), collator); BSONObjBuilder b; b.append("a", 5); ASSERT(m.matches(b.done())); @@ -106,7 +112,8 @@ public: ASSERT_EQUALS(4, query["a"].embeddedObject()["$in"].embeddedObject()["0"].number()); ASSERT_EQUALS(NumberInt, query["a"].embeddedObject()["$in"].embeddedObject()["0"].type()); - M m(query, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M m(query, ExtensionsCallbackDisallowExtensions(), collator); { BSONObjBuilder b; @@ -133,7 +140,8 @@ template <typename M> class MixedNumericEmbedded { public: void run() { - M m(BSON("a" << BSON("x" << 1)), ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M m(BSON("a" << BSON("x" << 1)), ExtensionsCallbackDisallowExtensions(), collator); ASSERT(m.matches(BSON("a" << BSON("x" << 1)))); ASSERT(m.matches(BSON("a" << BSON("x" << 1.0)))); } @@ -143,7 +151,8 @@ template <typename M> class Size { public: void run() { - M m(fromjson("{a:{$size:4}}"), ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M m(fromjson("{a:{$size:4}}"), ExtensionsCallbackDisallowExtensions(), collator); ASSERT(m.matches(fromjson("{a:[1,2,3,4]}"))); ASSERT(!m.matches(fromjson("{a:[1,2,3]}"))); ASSERT(!m.matches(fromjson("{a:[1,2,3,'a','b']}"))); @@ -155,8 +164,10 @@ template <typename M> class WithinBox { public: void run() { + CollatorInterface* collator = nullptr; M m(fromjson("{loc:{$within:{$box:[{x: 4, y:4},[6,6]]}}}"), - ExtensionsCallbackDisallowExtensions()); + ExtensionsCallbackDisallowExtensions(), + collator); ASSERT(!m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: [4,4]}"))); ASSERT(m.matches(fromjson("{loc: [5,5]}"))); @@ -169,8 +180,10 @@ template <typename M> class WithinPolygon { public: void run() { + CollatorInterface* collator = nullptr; M m(fromjson("{loc:{$within:{$polygon:[{x:0,y:0},[0,5],[5,5],[5,0]]}}}"), - ExtensionsCallbackDisallowExtensions()); + ExtensionsCallbackDisallowExtensions(), + collator); ASSERT(m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: [4,4]}"))); ASSERT(m.matches(fromjson("{loc: {x:5,y:5}}"))); @@ -183,8 +196,10 @@ template <typename M> class WithinCenter { public: void run() { + CollatorInterface* collator = nullptr; M m(fromjson("{loc:{$within:{$center:[{x:30,y:30},10]}}}"), - ExtensionsCallbackDisallowExtensions()); + ExtensionsCallbackDisallowExtensions(), + collator); ASSERT(!m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: {x:30,y:30}}"))); ASSERT(m.matches(fromjson("{loc: [20,30]}"))); @@ -200,7 +215,8 @@ template <typename M> class ElemMatchKey { public: void run() { - M matcher(BSON("a.b" << 1), ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M matcher(BSON("a.b" << 1), ExtensionsCallbackDisallowExtensions(), collator); MatchDetails details; details.requestElemMatchKey(); ASSERT(!details.hasElemMatchKey()); @@ -220,9 +236,11 @@ public: const NamespaceString nss("unittests.matchertests"); AutoGetCollectionForRead ctx(&txn, nss); + CollatorInterface* collator = nullptr; M m(BSON("$where" << "function(){ return this.a == 1; }"), - ExtensionsCallbackReal(&txn, &nss)); + ExtensionsCallbackReal(&txn, &nss), + collator); ASSERT(m.matches(BSON("a" << 1))); ASSERT(!m.matches(BSON("a" << 2))); } @@ -232,7 +250,8 @@ template <typename M> class TimingBase { public: long dotime(const BSONObj& patt, const BSONObj& obj) { - M m(patt, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + M m(patt, ExtensionsCallbackDisallowExtensions(), collator); Timer t; for (int i = 0; i < 900000; i++) { if (!m.matches(obj)) { @@ -257,6 +276,35 @@ public: } }; +/** Test that 'collator' is passed to MatchExpressionParser::parse(). */ +template <typename M> +class NullCollator { +public: + void run() { + CollatorInterface* collator = nullptr; + M matcher(BSON("a" + << "string"), + ExtensionsCallbackDisallowExtensions(), + collator); + ASSERT(!matcher.matches(BSON("a" + << "string2"))); + } +}; + +/** Test that 'collator' is passed to MatchExpressionParser::parse(). */ +template <typename M> +class Collator { +public: + void run() { + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + M matcher(BSON("a" + << "string"), + ExtensionsCallbackDisallowExtensions(), + &collator); + ASSERT(matcher.matches(BSON("a" + << "string2"))); + } +}; class All : public Suite { public: @@ -278,6 +326,8 @@ public: ADD_BOTH(WithinBox); ADD_BOTH(WithinCenter); ADD_BOTH(WithinPolygon); + ADD_BOTH(NullCollator); + ADD_BOTH(Collator); } }; diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp index c233155af77..cac7a702028 100644 --- a/src/mongo/dbtests/query_stage_collscan.cpp +++ b/src/mongo/dbtests/query_stage_collscan.cpp @@ -90,8 +90,9 @@ public: params.tailable = false; // Make the filter. - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterObj, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( + filterObj, ExtensionsCallbackDisallowExtensions(), collator); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue()); diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp index f325004216f..82a645bdcde 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -145,8 +145,9 @@ public: unique_ptr<WorkingSet> ws(new WorkingSet); + CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - request.getQuery(), ExtensionsCallbackDisallowExtensions()); + request.getQuery(), ExtensionsCallbackDisallowExtensions(), collator); ASSERT(statusWithMatcher.isOK()); unique_ptr<MatchExpression> expression = std::move(statusWithMatcher.getValue()); diff --git a/src/mongo/dbtests/query_stage_fetch.cpp b/src/mongo/dbtests/query_stage_fetch.cpp index 451b4b3069a..60158a3fd92 100644 --- a/src/mongo/dbtests/query_stage_fetch.cpp +++ b/src/mongo/dbtests/query_stage_fetch.cpp @@ -195,8 +195,9 @@ public: // Make the filter. BSONObj filterObj = BSON("foo" << 6); - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterObj, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( + filterObj, ExtensionsCallbackDisallowExtensions(), collator); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue()); diff --git a/src/mongo/dbtests/query_stage_multiplan.cpp b/src/mongo/dbtests/query_stage_multiplan.cpp index 4056c439545..250eb5c380f 100644 --- a/src/mongo/dbtests/query_stage_multiplan.cpp +++ b/src/mongo/dbtests/query_stage_multiplan.cpp @@ -149,8 +149,9 @@ public: // Make the filter. BSONObj filterObj = BSON("foo" << 7); - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterObj, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( + filterObj, ExtensionsCallbackDisallowExtensions(), collator); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filter = std::move(statusWithMatcher.getValue()); // Make the stage. diff --git a/src/mongo/dbtests/query_stage_subplan.cpp b/src/mongo/dbtests/query_stage_subplan.cpp index a5253a5ee94..09f27a679e4 100644 --- a/src/mongo/dbtests/query_stage_subplan.cpp +++ b/src/mongo/dbtests/query_stage_subplan.cpp @@ -447,8 +447,9 @@ public: // Rewrite (AND (OR a b) e) => (OR (AND a e) (AND b e)) { BSONObj queryObj = fromjson("{$or:[{a:1}, {b:1}], e:1}"); - StatusWithMatchExpression expr = - MatchExpressionParser::parse(queryObj, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression expr = MatchExpressionParser::parse( + queryObj, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(expr.getStatus()); std::unique_ptr<MatchExpression> rewrittenExpr = SubplanStage::rewriteToRootedOr(std::move(expr.getValue())); @@ -464,8 +465,9 @@ public: // Rewrite (AND (OR a b) e f) => (OR (AND a e f) (AND b e f)) { BSONObj queryObj = fromjson("{$or:[{a:1}, {b:1}], e:1, f:1}"); - StatusWithMatchExpression expr = - MatchExpressionParser::parse(queryObj, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression expr = MatchExpressionParser::parse( + queryObj, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(expr.getStatus()); std::unique_ptr<MatchExpression> rewrittenExpr = SubplanStage::rewriteToRootedOr(std::move(expr.getValue())); @@ -481,8 +483,9 @@ public: // Rewrite (AND (OR (AND a b) (AND c d) e f) => (OR (AND a b e f) (AND c d e f)) { BSONObj queryObj = fromjson("{$or:[{a:1,b:1}, {c:1,d:1}], e:1,f:1}"); - StatusWithMatchExpression expr = - MatchExpressionParser::parse(queryObj, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression expr = MatchExpressionParser::parse( + queryObj, ExtensionsCallbackDisallowExtensions(), collator); ASSERT_OK(expr.getStatus()); std::unique_ptr<MatchExpression> rewrittenExpr = SubplanStage::rewriteToRootedOr(std::move(expr.getValue())); diff --git a/src/mongo/dbtests/query_stage_tests.cpp b/src/mongo/dbtests/query_stage_tests.cpp index 5e3bdbb50fc..acd5010e01c 100644 --- a/src/mongo/dbtests/query_stage_tests.cpp +++ b/src/mongo/dbtests/query_stage_tests.cpp @@ -80,8 +80,9 @@ public: int countResults(const IndexScanParams& params, BSONObj filterObj = BSONObj()) { AutoGetCollectionForRead ctx(&_txn, ns()); - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterObj, ExtensionsCallbackDisallowExtensions()); + CollatorInterface* collator = nullptr; + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( + filterObj, ExtensionsCallbackDisallowExtensions(), collator); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue()); |