diff options
155 files changed, 3141 insertions, 3114 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 ca77d4184a7..fbf8a3b2251 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp @@ -112,7 +112,7 @@ Status AuthzManagerExternalStateMock::findOne(OperationContext* opCtx, const BSONObj& query, BSONObj* result) { BSONObjCollection::iterator iter; - Status status = _findOneIter(collectionName, query, &iter); + Status status = _findOneIter(opCtx, collectionName, query, &iter); if (!status.isOK()) return status; *result = iter->copy(); @@ -126,7 +126,7 @@ Status AuthzManagerExternalStateMock::query( const BSONObj&, const stdx::function<void(const BSONObj&)>& resultProcessor) { std::vector<BSONObjCollection::iterator> iterVector; - Status status = _queryVector(collectionName, query, &iterVector); + Status status = _queryVector(opCtx, collectionName, query, &iterVector); if (!status.isOK()) { return status; } @@ -177,7 +177,9 @@ Status AuthzManagerExternalStateMock::updateOne(OperationContext* opCtx, bool upsert, const BSONObj& writeConcern) { namespace mmb = mutablebson; - UpdateDriver::Options updateOptions; + const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, collator)); + UpdateDriver::Options updateOptions(std::move(expCtx)); UpdateDriver driver(updateOptions); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; Status status = driver.parse(updatePattern, arrayFilters); @@ -185,7 +187,7 @@ Status AuthzManagerExternalStateMock::updateOne(OperationContext* opCtx, return status; BSONObjCollection::iterator iter; - status = _findOneIter(collectionName, query, &iter); + status = _findOneIter(opCtx, collectionName, query, &iter); mmb::Document document; if (status.isOK()) { document.reset(*iter, mmb::Document::kInPlaceDisabled); @@ -257,7 +259,7 @@ Status AuthzManagerExternalStateMock::remove(OperationContext* opCtx, int* numRemoved) { int n = 0; BSONObjCollection::iterator iter; - while (_findOneIter(collectionName, query, &iter).isOK()) { + while (_findOneIter(opCtx, collectionName, query, &iter).isOK()) { BSONObj idQuery = (*iter)["_id"].wrap(); _documents[collectionName].erase(iter); ++n; @@ -275,11 +277,12 @@ std::vector<BSONObj> AuthzManagerExternalStateMock::getCollectionContents( return mapFindWithDefault(_documents, collectionName, std::vector<BSONObj>()); } -Status AuthzManagerExternalStateMock::_findOneIter(const NamespaceString& collectionName, +Status AuthzManagerExternalStateMock::_findOneIter(OperationContext* opCtx, + const NamespaceString& collectionName, const BSONObj& query, BSONObjCollection::iterator* result) { std::vector<BSONObjCollection::iterator> iterVector; - Status status = _queryVector(collectionName, query, &iterVector); + Status status = _queryVector(opCtx, collectionName, query, &iterVector); if (!status.isOK()) { return status; } @@ -291,11 +294,13 @@ Status AuthzManagerExternalStateMock::_findOneIter(const NamespaceString& collec } Status AuthzManagerExternalStateMock::_queryVector( + OperationContext* opCtx, const NamespaceString& collectionName, const BSONObj& query, std::vector<BSONObjCollection::iterator>* result) { - CollatorInterface* collator = nullptr; - StatusWithMatchExpression parseResult = MatchExpressionParser::parse(query, collator); + const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, collator)); + StatusWithMatchExpression parseResult = MatchExpressionParser::parse(query, std::move(expCtx)); if (!parseResult.isOK()) { return parseResult.getStatus(); } diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.h b/src/mongo/db/auth/authz_manager_external_state_mock.h index 4d90099f120..0cfe9b9d775 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.h +++ b/src/mongo/db/auth/authz_manager_external_state_mock.h @@ -112,11 +112,13 @@ private: typedef std::vector<BSONObj> BSONObjCollection; typedef std::map<NamespaceString, BSONObjCollection> NamespaceDocumentMap; - Status _findOneIter(const NamespaceString& collectionName, + Status _findOneIter(OperationContext* opCtx, + const NamespaceString& collectionName, const BSONObj& query, BSONObjCollection::iterator* result); - Status _queryVector(const NamespaceString& collectionName, + Status _queryVector(OperationContext* opCtx, + const NamespaceString& collectionName, const BSONObj& query, std::vector<BSONObjCollection::iterator>* result); diff --git a/src/mongo/db/auth/role_graph_update.cpp b/src/mongo/db/auth/role_graph_update.cpp index 9b5629cd3ab..96988cd5d80 100644 --- a/src/mongo/db/auth/role_graph_update.cpp +++ b/src/mongo/db/auth/role_graph_update.cpp @@ -202,7 +202,8 @@ Status handleOplogUpdate(OperationContext* opCtx, if (!status.isOK()) return status; - UpdateDriver::Options updateOptions; + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, nullptr)); + UpdateDriver::Options updateOptions(std::move(expCtx)); updateOptions.modOptions.fromOplogApplication = true; UpdateDriver driver(updateOptions); diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index 59e8623ac7a..1a24d9a8caa 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -180,7 +180,7 @@ StatusWith<CollModRequest> parseCollModRequest(OperationContext* opCtx, // instances, as indicated by !validateFeaturesAsMaster. allowedFeatures |= MatchExpressionParser::kJSONSchema; } - auto statusW = coll->parseValidator(e.Obj(), allowedFeatures); + auto statusW = coll->parseValidator(opCtx, e.Obj(), allowedFeatures); if (!statusW.isOK()) { if (statusW.getStatus().code() == ErrorCodes::JSONSchemaNotAllowed) { // The default error message for disallowed $jsonSchema is not descriptive diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h index fd0f9b3b1b4..5d30401e2b6 100644 --- a/src/mongo/db/catalog/collection.h +++ b/src/mongo/db/catalog/collection.h @@ -302,6 +302,7 @@ public: virtual void cappedTruncateAfter(OperationContext* opCtx, RecordId end, bool inclusive) = 0; virtual StatusWithMatchExpression parseValidator( + OperationContext* opCtx, const BSONObj& validator, MatchExpressionParser::AllowedFeatureSet allowedFeatures) const = 0; @@ -627,8 +628,10 @@ public: * Returns a non-ok Status if validator is not legal for this collection. */ inline StatusWithMatchExpression parseValidator( - const BSONObj& validator, MatchExpressionParser::AllowedFeatureSet allowedFeatures) const { - return this->_impl().parseValidator(validator, allowedFeatures); + OperationContext* opCtx, + const BSONObj& validator, + MatchExpressionParser::AllowedFeatureSet allowedFeatures) const { + return this->_impl().parseValidator(opCtx, validator, allowedFeatures); } static StatusWith<ValidationLevel> parseValidationLevel(StringData); diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index 26af94b10ff..f41d9d2a467 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -160,7 +160,8 @@ CollectionImpl::CollectionImpl(Collection* _this_init, _collator(parseCollation(opCtx, _ns, _details->getCollectionOptions(opCtx).collation)), _validatorDoc(_details->getCollectionOptions(opCtx).validator.getOwned()), _validator( - uassertStatusOK(parseValidator(_validatorDoc, + uassertStatusOK(parseValidator(opCtx, + _validatorDoc, MatchExpressionParser::kAllowAllSpecialFeatures & ~MatchExpressionParser::AllowedFeatures::kExpr))), _validationAction(uassertStatusOK( @@ -268,7 +269,9 @@ Status CollectionImpl::checkValidation(OperationContext* opCtx, const BSONObj& d } StatusWithMatchExpression CollectionImpl::parseValidator( - const BSONObj& validator, MatchExpressionParser::AllowedFeatureSet allowedFeatures) const { + OperationContext* opCtx, + const BSONObj& validator, + MatchExpressionParser::AllowedFeatureSet allowedFeatures) const { if (validator.isEmpty()) return {nullptr}; @@ -285,8 +288,9 @@ StatusWithMatchExpression CollectionImpl::parseValidator( << " database"}; } + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, _collator.get())); auto statusWithMatcher = MatchExpressionParser::parse( - validator, _collator.get(), nullptr, ExtensionsCallbackNoop(), allowedFeatures); + validator, std::move(expCtx), ExtensionsCallbackNoop(), allowedFeatures); if (!statusWithMatcher.isOK()) return statusWithMatcher.getStatus(); @@ -894,7 +898,8 @@ Status CollectionImpl::setValidator(OperationContext* opCtx, BSONObj validatorDo // Note that, by the time we reach this, we should have already done a pre-parse that checks for // banned features, so we don't need to include that check again. - auto statusWithMatcher = parseValidator(validatorDoc, + auto statusWithMatcher = parseValidator(opCtx, + validatorDoc, MatchExpressionParser::kAllowAllSpecialFeatures & ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithMatcher.isOK()) diff --git a/src/mongo/db/catalog/collection_impl.h b/src/mongo/db/catalog/collection_impl.h index f8db017330e..cba3445042e 100644 --- a/src/mongo/db/catalog/collection_impl.h +++ b/src/mongo/db/catalog/collection_impl.h @@ -284,6 +284,7 @@ public: * Returns a non-ok Status if validator is not legal for this collection. */ StatusWithMatchExpression parseValidator( + OperationContext* opCtx, const BSONObj& validator, MatchExpressionParser::AllowedFeatureSet allowedFeatures) const final; diff --git a/src/mongo/db/catalog/collection_mock.h b/src/mongo/db/catalog/collection_mock.h index e9ecffc144b..405a3fde968 100644 --- a/src/mongo/db/catalog/collection_mock.h +++ b/src/mongo/db/catalog/collection_mock.h @@ -221,7 +221,9 @@ public: } StatusWithMatchExpression parseValidator( - const BSONObj& validator, MatchExpressionParser::AllowedFeatureSet allowedFeatures) const { + OperationContext* opCtx, + const BSONObj& validator, + MatchExpressionParser::AllowedFeatureSet allowedFeatures) const { std::abort(); } diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp index 5f6f7d61748..ad186e8f06b 100644 --- a/src/mongo/db/catalog/database_impl.cpp +++ b/src/mongo/db/catalog/database_impl.cpp @@ -1013,9 +1013,10 @@ auto mongo::userCreateNSImpl(OperationContext* opCtx, // the secondary or on a backup instance, as indicated by !validateFeaturesAsMaster. allowedFeatures |= MatchExpressionParser::kJSONSchema; } + boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx, collator.get())); auto statusWithMatcher = MatchExpressionParser::parse(collectionOptions.validator, - collator.get(), - nullptr, + std::move(expCtx), ExtensionsCallbackNoop(), allowedFeatures); diff --git a/src/mongo/db/catalog/index_catalog_entry_impl.cpp b/src/mongo/db/catalog/index_catalog_entry_impl.cpp index 7f46d56dac8..afa073f7ce0 100644 --- a/src/mongo/db/catalog/index_catalog_entry_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_entry_impl.cpp @@ -127,8 +127,10 @@ IndexCatalogEntryImpl::IndexCatalogEntryImpl(IndexCatalogEntry* const this_, if (BSONElement filterElement = _descriptor->getInfoElement("partialFilterExpression")) { invariant(filterElement.isABSONObj()); BSONObj filter = filterElement.Obj(); + boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx, _collator.get())); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filter, _collator.get()); + MatchExpressionParser::parse(filter, std::move(expCtx)); // 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/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp index b128061a1c1..726dc2f5e28 100644 --- a/src/mongo/db/catalog/index_catalog_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_impl.cpp @@ -666,8 +666,10 @@ Status IndexCatalogImpl::_isSpecOk(OperationContext* opCtx, const BSONObj& spec) } // The collator must outlive the constructed MatchExpression. + boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx, collator.get())); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterElement.Obj(), collator.get()); + MatchExpressionParser::parse(filterElement.Obj(), std::move(expCtx)); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp index c952573ac14..20560d3a4c9 100644 --- a/src/mongo/db/commands/list_collections.cpp +++ b/src/mongo/db/commands/list_collections.cpp @@ -244,8 +244,9 @@ public: } // The collator is null because collection objects are compared using binary comparison. const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, collator)); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterElt.Obj(), collator); + MatchExpressionParser::parse(filterElt.Obj(), std::move(expCtx)); if (!statusWithMatcher.isOK()) { return appendCommandStatus(result, statusWithMatcher.getStatus()); } diff --git a/src/mongo/db/commands/list_databases.cpp b/src/mongo/db/commands/list_databases.cpp index 232803320d0..fb719e1bda6 100644 --- a/src/mongo/db/commands/list_databases.cpp +++ b/src/mongo/db/commands/list_databases.cpp @@ -99,7 +99,9 @@ public: // The collator is null because database metadata objects are compared using simple // binary comparison. const CollatorInterface* collator = nullptr; - auto statusWithMatcher = MatchExpressionParser::parse(filterElt.Obj(), collator); + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, collator)); + auto statusWithMatcher = + MatchExpressionParser::parse(filterElt.Obj(), std::move(expCtx)); if (!statusWithMatcher.isOK()) { return appendCommandStatus(result, statusWithMatcher.getStatus()); } diff --git a/src/mongo/db/exec/SConscript b/src/mongo/db/exec/SConscript index 409ada6c1dd..04dd3a7e647 100644 --- a/src/mongo/db/exec/SConscript +++ b/src/mongo/db/exec/SConscript @@ -153,6 +153,7 @@ env.CppUnitTest( ], LIBDEPS = [ "$BUILD_DIR/mongo/db/query/collation/collator_interface_mock", + "$BUILD_DIR/mongo/db/query/query_test_service_context", "$BUILD_DIR/mongo/db/serveronly", "exec", ], diff --git a/src/mongo/db/exec/projection.cpp b/src/mongo/db/exec/projection.cpp index 65ee238c4a0..370a8e87892 100644 --- a/src/mongo/db/exec/projection.cpp +++ b/src/mongo/db/exec/projection.cpp @@ -61,7 +61,8 @@ ProjectionStage::ProjectionStage(OperationContext* opCtx, _projObj = params.projObj; if (ProjectionStageParams::NO_FAST_PATH == _projImpl) { - _exec.reset(new ProjectionExec(params.projObj, params.fullExpression, params.collator)); + _exec.reset( + new ProjectionExec(opCtx, params.projObj, params.fullExpression, params.collator)); } else { // We shouldn't need the full expression if we're fast-pathing. invariant(NULL == params.fullExpression); diff --git a/src/mongo/db/exec/projection_exec.cpp b/src/mongo/db/exec/projection_exec.cpp index d4842ac1e74..ae17257c9ef 100644 --- a/src/mongo/db/exec/projection_exec.cpp +++ b/src/mongo/db/exec/projection_exec.cpp @@ -77,7 +77,8 @@ ProjectionExec::ProjectionExec() _queryExpression(NULL), _hasReturnKey(false) {} -ProjectionExec::ProjectionExec(const BSONObj& spec, +ProjectionExec::ProjectionExec(OperationContext* opCtx, + const BSONObj& spec, const MatchExpression* queryExpression, const CollatorInterface* collator) : _include(true), @@ -131,8 +132,10 @@ ProjectionExec::ProjectionExec(const BSONObj& spec, BSONObj elemMatchObj = e.wrap(); verify(elemMatchObj.isOwned()); _elemMatchObjs.push_back(elemMatchObj); + boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx, _collator)); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(elemMatchObj, _collator); + MatchExpressionParser::parse(elemMatchObj, std::move(expCtx)); 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.h b/src/mongo/db/exec/projection_exec.h index 9575d59042f..829cdf0d43a 100644 --- a/src/mongo/db/exec/projection_exec.h +++ b/src/mongo/db/exec/projection_exec.h @@ -66,7 +66,8 @@ public: typedef StringMap<MatchExpression*> Matchers; typedef StringMap<MetaProjection> MetaMap; - ProjectionExec(const BSONObj& spec, + ProjectionExec(OperationContext* opCtx, + const BSONObj& spec, const MatchExpression* queryExpression, const CollatorInterface* collator); diff --git a/src/mongo/db/exec/projection_exec_test.cpp b/src/mongo/db/exec/projection_exec_test.cpp index 41c40c2b287..b5e10f92bd9 100644 --- a/src/mongo/db/exec/projection_exec_test.cpp +++ b/src/mongo/db/exec/projection_exec_test.cpp @@ -35,6 +35,7 @@ #include "mongo/db/exec/working_set_computed_data.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/unittest.h" #include <memory> @@ -49,8 +50,8 @@ using std::unique_ptr; * Utility function to create MatchExpression */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, std::move(expCtx)); ASSERT_TRUE(status.isOK()); return std::move(status.getValue()); } @@ -83,7 +84,9 @@ void testTransform(const char* specStr, BSONObj spec = fromjson(specStr); BSONObj query = fromjson(queryStr); unique_ptr<MatchExpression> queryExpression = parseMatchExpression(query); - ProjectionExec exec(spec, queryExpression.get(), collator); + QueryTestServiceContext serviceCtx; + auto opCtx = serviceCtx.makeOperationContext(); + ProjectionExec exec(opCtx.get(), spec, queryExpression.get(), collator); // Create working set member. WorkingSetMember wsm; @@ -166,7 +169,9 @@ BSONObj transformMetaSortKeyCovered(const BSONObj& sortKey, wsm->addComputed(new SortKeyComputedData(sortKey)); ws.transitionToRecordIdAndIdx(wsid); - ProjectionExec projExec(fromjson(projSpec), nullptr, nullptr); + QueryTestServiceContext serviceCtx; + auto opCtx = serviceCtx.makeOperationContext(); + ProjectionExec projExec(opCtx.get(), fromjson(projSpec), nullptr, nullptr); ASSERT_OK(projExec.transform(wsm)); return wsm->obj.value(); @@ -179,7 +184,9 @@ BSONObj transformCovered(BSONObj projSpec, const IndexKeyDatum& ikd) { wsm->keyData.push_back(ikd); ws.transitionToRecordIdAndIdx(wsid); - ProjectionExec projExec(projSpec, nullptr, nullptr); + QueryTestServiceContext serviceCtx; + auto opCtx = serviceCtx.makeOperationContext(); + ProjectionExec projExec(opCtx.get(), projSpec, nullptr, nullptr); ASSERT_OK(projExec.transform(wsm)); return wsm->obj.value(); diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index d8186f637e0..f3d9c92cafd 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -248,10 +248,10 @@ public: BSONObj argObj = e.Obj(); if (filterTag == e.fieldName()) { const CollatorInterface* collator = nullptr; - boost::intrusive_ptr<ExpressionContext> expCtx; + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx, collator)); StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( argObj, - collator, expCtx, ExtensionsCallbackReal(opCtx, &collection->ns()), MatchExpressionParser::kAllowAllSpecialFeatures & diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript index a795325d185..2d4d9341c9e 100644 --- a/src/mongo/db/matcher/SConscript +++ b/src/mongo/db/matcher/SConscript @@ -114,6 +114,7 @@ env.CppUnitTest( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'expressions', ], ) @@ -131,6 +132,7 @@ env.CppUnitTest( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'expressions', ], ) @@ -143,6 +145,7 @@ env.CppUnitTest( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'expressions', ], ) @@ -173,6 +176,7 @@ env.CppUnitTest( 'expression_serialization_test.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'expressions', ], ) diff --git a/src/mongo/db/matcher/copyable_match_expression.h b/src/mongo/db/matcher/copyable_match_expression.h index a1557b6f382..423a04dc147 100644 --- a/src/mongo/db/matcher/copyable_match_expression.h +++ b/src/mongo/db/matcher/copyable_match_expression.h @@ -51,41 +51,23 @@ public: * encounter an error. */ CopyableMatchExpression(BSONObj matchAST, - const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr, + const boost::intrusive_ptr<ExpressionContext>& expCtx, std::unique_ptr<const ExtensionsCallback> extensionsCallback = stdx::make_unique<ExtensionsCallbackNoop>(), MatchExpressionParser::AllowedFeatureSet allowedFeatures = MatchExpressionParser::kDefaultSpecialFeatures) : _matchAST(matchAST), _extensionsCallback(std::move(extensionsCallback)) { - StatusWithMatchExpression parseResult = MatchExpressionParser::parse( - _matchAST, collator, expCtx, *_extensionsCallback, allowedFeatures); + StatusWithMatchExpression parseResult = + MatchExpressionParser::parse(_matchAST, expCtx, *_extensionsCallback, allowedFeatures); uassertStatusOK(parseResult.getStatus()); _matchExpr = std::move(parseResult.getValue()); } /** - * Semantically, this behaves as if the client called setCollator() on the underlying - * MatchExpression (which is impossible, because it's const). - * - * Behind the scenes, it actually makes a new MatchExpression with the new collator. That way, - * if there other CopyableMatchExpression objects referencing this MatchExpression, they don't - * see the change in collator. + * Sets the collator on the underlying MatchExpression and all clones(!). */ - void setCollator(const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr) { - // We can allow all features because any features that were allowed in the original - // MatchExpression construction should be allowed now. - MatchExpressionParser::AllowedFeatureSet allowedFeatures = - MatchExpressionParser::kAllowAllSpecialFeatures; - if (!expCtx) { - allowedFeatures = allowedFeatures & ~MatchExpressionParser::AllowedFeatures::kExpr; - } - - StatusWithMatchExpression parseResult = MatchExpressionParser::parse( - _matchAST, collator, expCtx, *_extensionsCallback, allowedFeatures); - invariantOK(parseResult.getStatus()); - _matchExpr = std::move(parseResult.getValue()); + void setCollator(const CollatorInterface* collator) { + _matchExpr->setCollator(collator); } /** @@ -107,7 +89,7 @@ public: private: BSONObj _matchAST; std::shared_ptr<const ExtensionsCallback> _extensionsCallback; - std::shared_ptr<const MatchExpression> _matchExpr; + std::shared_ptr<MatchExpression> _matchExpr; }; } // namespace mongo diff --git a/src/mongo/db/matcher/expression_algo_test.cpp b/src/mongo/db/matcher/expression_algo_test.cpp index cb803819b69..d1ec11137dd 100644 --- a/src/mongo/db/matcher/expression_algo_test.cpp +++ b/src/mongo/db/matcher/expression_algo_test.cpp @@ -37,6 +37,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/platform/decimal128.h" @@ -52,7 +53,9 @@ class ParsedMatchExpression { public: ParsedMatchExpression(const std::string& str, const CollatorInterface* collator = nullptr) : _obj(fromjson(str)) { - StatusWithMatchExpression result = MatchExpressionParser::parse(_obj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(_obj, std::move(expCtx)); ASSERT_OK(result.getStatus()); _expr = std::move(result.getValue()); } @@ -70,9 +73,9 @@ TEST(ExpressionAlgoIsSubsetOf, NullAndOmittedField) { // Verify that ComparisonMatchExpression::init() prohibits creating a match expression with // an Undefined type. BSONObj undefined = fromjson("{a: undefined}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_EQUALS(ErrorCodes::BadValue, - MatchExpressionParser::parse(undefined, collator).getStatus()); + MatchExpressionParser::parse(undefined, std::move(expCtx)).getStatus()); ParsedMatchExpression empty("{}"); ParsedMatchExpression null("{a: null}"); @@ -708,8 +711,9 @@ TEST(ExpressionAlgoIsSubsetOf, NonMatchingCollationsNoStringComparison) { TEST(IsIndependent, AndIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 1}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -719,8 +723,9 @@ TEST(IsIndependent, AndIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, ElemMatchIsNotIndependent) { BSONObj matchPredicate = fromjson("{x: {$elemMatch: {y: 1}}}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -731,8 +736,9 @@ TEST(IsIndependent, ElemMatchIsNotIndependent) { TEST(IsIndependent, NorIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$nor: [{a: 1}, {b: 1}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -742,8 +748,9 @@ TEST(IsIndependent, NorIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, NotIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -753,8 +760,9 @@ TEST(IsIndependent, NotIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, OrIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$or: [{a: 1}, {b: 1}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -764,8 +772,9 @@ TEST(IsIndependent, OrIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, AndWithDottedFieldPathsIsNotIndependent) { BSONObj matchPredicate = fromjson("{$and: [{'a': 1}, {'a.b': 1}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -775,8 +784,9 @@ TEST(IsIndependent, AndWithDottedFieldPathsIsNotIndependent) { TEST(IsIndependent, BallIsIndependentOfBalloon) { BSONObj matchPredicate = fromjson("{'a.ball': 4}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -787,8 +797,9 @@ TEST(IsIndependent, BallIsIndependentOfBalloon) { TEST(SplitMatchExpression, AndWithSplittableChildrenIsSplittable) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 1}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -808,8 +819,9 @@ TEST(SplitMatchExpression, AndWithSplittableChildrenIsSplittable) { TEST(SplitMatchExpression, NorWithIndependentChildrenIsSplittable) { BSONObj matchPredicate = fromjson("{$nor: [{a: 1}, {b: 1}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -829,8 +841,9 @@ TEST(SplitMatchExpression, NorWithIndependentChildrenIsSplittable) { TEST(SplitMatchExpression, NotWithIndependentChildIsSplittable) { BSONObj matchPredicate = fromjson("{x: {$not: {$gt: 4}}}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -846,8 +859,9 @@ TEST(SplitMatchExpression, NotWithIndependentChildIsSplittable) { TEST(SplitMatchExpression, OrWithOnlyIndependentChildrenIsNotSplittable) { BSONObj matchPredicate = fromjson("{$or: [{a: 1}, {b: 1}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -866,8 +880,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}]}]}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -891,8 +906,9 @@ TEST(SplitMatchExpression, ComplexMatchExpressionSplitsCorrectly) { TEST(SplitMatchExpression, ShouldNotExtractPrefixOfDottedPathAsIndependent) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {'a.b': 1}, {'a.c': 1}]}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = + MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -912,8 +928,8 @@ TEST(SplitMatchExpression, ShouldNotExtractPrefixOfDottedPathAsIndependent) { TEST(SplitMatchExpression, ShouldMoveIndependentLeafPredicateAcrossRename) { BSONObj matchPredicate = fromjson("{a: 1}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "b"}}; @@ -930,8 +946,8 @@ TEST(SplitMatchExpression, ShouldMoveIndependentLeafPredicateAcrossRename) { TEST(SplitMatchExpression, ShouldMoveIndependentAndPredicateAcrossRename) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 2}]}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -948,8 +964,8 @@ TEST(SplitMatchExpression, ShouldMoveIndependentAndPredicateAcrossRename) { TEST(SplitMatchExpression, ShouldSplitPartiallyDependentAndPredicateAcrossRename) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 2}]}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -969,8 +985,8 @@ TEST(SplitMatchExpression, ShouldSplitPartiallyDependentAndPredicateAcrossRename TEST(SplitMatchExpression, ShouldSplitPartiallyDependentComplexPredicateMultipleRenames) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {$or: [{b: 2}, {c: 3}]}]}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"b", "d"}, {"c", "e"}}; @@ -991,8 +1007,8 @@ TEST(SplitMatchExpression, ShouldSplitPartiallyDependentComplexPredicateMultiple TEST(SplitMatchExpression, ShouldSplitPartiallyDependentComplexPredicateMultipleRenamesDottedPaths) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {$or: [{'d.e.f': 2}, {'e.f.g': 3}]}]}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"d.e.f", "x"}, {"e.f.g", "y"}}; @@ -1012,8 +1028,8 @@ TEST(SplitMatchExpression, TEST(SplitMatchExpression, ShouldNotMoveElemMatchObjectAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$elemMatch: {b: 3}}}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1030,8 +1046,8 @@ TEST(SplitMatchExpression, ShouldNotMoveElemMatchObjectAcrossRename) { TEST(SplitMatchExpression, ShouldNotMoveElemMatchValueAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$elemMatch: {$eq: 3}}}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1048,8 +1064,8 @@ TEST(SplitMatchExpression, ShouldNotMoveElemMatchValueAcrossRename) { TEST(SplitMatchExpression, ShouldMoveTypeAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$type: 16}}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1066,8 +1082,8 @@ TEST(SplitMatchExpression, ShouldMoveTypeAcrossRename) { TEST(SplitMatchExpression, ShouldNotMoveSizeAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$size: 3}}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1084,8 +1100,8 @@ TEST(SplitMatchExpression, ShouldNotMoveSizeAcrossRename) { TEST(SplitMatchExpression, ShouldNotMoveMinItemsAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaMinItems: 3}}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1102,8 +1118,8 @@ TEST(SplitMatchExpression, ShouldNotMoveMinItemsAcrossRename) { TEST(SplitMatchExpression, ShouldNotMoveMaxItemsAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaMaxItems: 3}}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1120,8 +1136,8 @@ TEST(SplitMatchExpression, ShouldNotMoveMaxItemsAcrossRename) { TEST(SplitMatchExpression, ShouldMoveMinLengthAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaMinLength: 3}}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1138,8 +1154,8 @@ TEST(SplitMatchExpression, ShouldMoveMinLengthAcrossRename) { TEST(SplitMatchExpression, ShouldMoveMaxLengthAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaMaxLength: 3}}"); - const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matcher = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1156,8 +1172,8 @@ TEST(SplitMatchExpression, ShouldMoveMaxLengthAcrossRename) { TEST(MapOverMatchExpression, DoesMapOverLogicalNodes) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); - const CollatorInterface* collator = nullptr; - auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(swMatchExpression.getStatus()); bool hasLogicalNode = false; @@ -1174,8 +1190,8 @@ TEST(MapOverMatchExpression, DoesMapOverLogicalNodes) { TEST(MapOverMatchExpression, DoesMapOverLeafNodes) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); - const CollatorInterface* collator = nullptr; - auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(swMatchExpression.getStatus()); bool hasLeafNode = false; @@ -1192,8 +1208,8 @@ TEST(MapOverMatchExpression, DoesMapOverLeafNodes) { TEST(MapOverMatchExpression, DoesPassPath) { BSONObj matchPredicate = fromjson("{a: {$elemMatch: {b: 1}}}"); - const CollatorInterface* collator = nullptr; - auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(swMatchExpression.getStatus()); std::vector<std::string> paths; @@ -1210,8 +1226,8 @@ TEST(MapOverMatchExpression, DoesPassPath) { TEST(MapOverMatchExpression, DoesMapOverNodesWithMultipleChildren) { BSONObj matchPredicate = fromjson("{$and: [{a: {$gt: 1}}, {b: {$lte: 2}}]}"); - const CollatorInterface* collator = nullptr; - auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, std::move(expCtx)); ASSERT_OK(swMatchExpression.getStatus()); size_t nodeCount = 0; diff --git a/src/mongo/db/matcher/expression_expr_test.cpp b/src/mongo/db/matcher/expression_expr_test.cpp index e0dfae1bb38..1d7e6e1b4be 100644 --- a/src/mongo/db/matcher/expression_expr_test.cpp +++ b/src/mongo/db/matcher/expression_expr_test.cpp @@ -31,7 +31,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_expr.h" #include "mongo/db/matcher/matcher.h" -#include "mongo/db/pipeline/aggregation_context_fixture.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -39,15 +39,12 @@ namespace mongo { namespace { TEST(ExprMatchExpression, ComparisonToConstantMatchesCorrectly) { - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* kSimpleCollator = nullptr; - + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto match = BSON("a" << 5); auto notMatch = BSON("a" << 6); auto expression1 = BSON("$expr" << BSON("$eq" << BSON_ARRAY("$a" << 5))); Matcher matcher1(expression1, - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -59,7 +56,6 @@ TEST(ExprMatchExpression, ComparisonToConstantMatchesCorrectly) { auto expression2 = BSON("$expr" << BSON("$eq" << BSON_ARRAY("$a" << "$$var"))); Matcher matcher2(expression2, - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -68,17 +64,15 @@ TEST(ExprMatchExpression, ComparisonToConstantMatchesCorrectly) { } TEST(ExprMatchExpression, ComparisonBetweenTwoFieldPathsMatchesCorrectly) { - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto expression = BSON("$expr" << BSON("$gt" << BSON_ARRAY("$a" << "$b"))); auto match = BSON("a" << 10 << "b" << 2); auto notMatch = BSON("a" << 2 << "b" << 10); - const CollatorInterface* kSimpleCollator = nullptr; Matcher matcher(expression, - kSimpleCollator, - expCtx, + std::move(expCtx), ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -87,10 +81,11 @@ TEST(ExprMatchExpression, ComparisonBetweenTwoFieldPathsMatchesCorrectly) { } TEST(ExprMatchExpression, ComparisonThrowsWithUnboundVariable) { - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto expression = BSON("$expr" << BSON("$eq" << BSON_ARRAY("$a" << "$$var"))); - ASSERT_THROWS(ExprMatchExpression pipelineExpr(expression.firstElement(), expCtx), DBException); + ASSERT_THROWS(ExprMatchExpression pipelineExpr(expression.firstElement(), std::move(expCtx)), + DBException); } // TODO SERVER-30991: Uncomment once MatchExpression::optimize() is in place and handles @@ -103,7 +98,7 @@ TEST(ExprMatchExpression, IdenticalPostOptimizedExpressionsAreEquivalent) { BSONObj expressionEquiv = BSON("$expr" << BSON("$const" << 4)); BSONObj expressionNotEquiv = BSON("$expr" << BSON("$const" << 10)); - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ExprMatchExpression pipelineExpr(expression.firstElement(), expCtx); pipelineExpr::optimize(); ASSERT_TRUE(pipelineExpr.equivalent(&pipelineExpr)); @@ -119,8 +114,8 @@ TEST(ExprMatchExpression, IdenticalPostOptimizedExpressionsAreEquivalent) { TEST(ExprMatchExpression, ShallowClonedExpressionIsEquivalentToOriginal) { BSONObj expression = BSON("$expr" << BSON("$eq" << BSON_ARRAY("$a" << 5))); - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ExprMatchExpression pipelineExpr(expression.firstElement(), expCtx); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ExprMatchExpression pipelineExpr(expression.firstElement(), std::move(expCtx)); auto shallowClone = pipelineExpr.shallowClone(); ASSERT_TRUE(pipelineExpr.equivalent(shallowClone.get())); } diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index b1dec5b6a33..de8d2717a96 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -116,7 +116,6 @@ StatusWithMatchExpression MatchExpressionParser::_parseComparison( const char* name, ComparisonMatchExpression* cmp, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures) { std::unique_ptr<ComparisonMatchExpression> temp(cmp); @@ -134,7 +133,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseComparison( return s; } - temp->setCollator(collator); + temp->setCollator(expCtx->getCollator()); return {std::move(temp)}; } @@ -144,16 +143,14 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( const AndMatchExpression* andSoFar, const char* name, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel) { if (mongoutils::str::equals("$eq", e.fieldName())) - return _parseComparison( - name, new EqualityMatchExpression(), e, collator, expCtx, allowedFeatures); + return _parseComparison(name, new EqualityMatchExpression(), e, expCtx, allowedFeatures); if (mongoutils::str::equals("$not", e.fieldName())) { - return _parseNot(name, e, collator, expCtx, allowedFeatures, topLevel); + return _parseNot(name, e, expCtx, allowedFeatures, topLevel); } auto parseExpMatchType = MatchExpressionParser::parsePathAcceptingKeyword(e); @@ -169,25 +166,21 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( switch (*parseExpMatchType) { case PathAcceptingKeyword::LESS_THAN: - return _parseComparison( - name, new LTMatchExpression(), e, collator, expCtx, allowedFeatures); + return _parseComparison(name, new LTMatchExpression(), e, expCtx, allowedFeatures); case PathAcceptingKeyword::LESS_THAN_OR_EQUAL: - return _parseComparison( - name, new LTEMatchExpression(), e, collator, expCtx, allowedFeatures); + return _parseComparison(name, new LTEMatchExpression(), e, expCtx, allowedFeatures); case PathAcceptingKeyword::GREATER_THAN: - return _parseComparison( - name, new GTMatchExpression(), e, collator, expCtx, allowedFeatures); + return _parseComparison(name, new GTMatchExpression(), e, expCtx, allowedFeatures); case PathAcceptingKeyword::GREATER_THAN_OR_EQUAL: - return _parseComparison( - name, new GTEMatchExpression(), e, collator, expCtx, allowedFeatures); + return _parseComparison(name, new GTEMatchExpression(), e, expCtx, allowedFeatures); case PathAcceptingKeyword::NOT_EQUAL: { 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.")}; } - StatusWithMatchExpression s = _parseComparison( - name, new EqualityMatchExpression(), e, collator, expCtx, allowedFeatures); + StatusWithMatchExpression s = + _parseComparison(name, new EqualityMatchExpression(), e, expCtx, allowedFeatures); if (!s.isOK()) return s; std::unique_ptr<NotMatchExpression> n = stdx::make_unique<NotMatchExpression>(); @@ -198,7 +191,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( } case PathAcceptingKeyword::EQUALITY: return _parseComparison( - name, new EqualityMatchExpression(), e, collator, expCtx, allowedFeatures); + name, new EqualityMatchExpression(), e, expCtx, allowedFeatures); case PathAcceptingKeyword::IN_EXPR: { if (e.type() != Array) @@ -207,7 +200,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( Status s = temp->init(name); if (!s.isOK()) return s; - s = _parseInExpression(temp.get(), e.Obj(), collator, expCtx); + s = _parseInExpression(temp.get(), e.Obj(), expCtx); if (!s.isOK()) return s; return {std::move(temp)}; @@ -220,7 +213,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( Status s = temp->init(name); if (!s.isOK()) return s; - s = _parseInExpression(temp.get(), e.Obj(), collator, expCtx); + s = _parseInExpression(temp.get(), e.Obj(), expCtx); if (!s.isOK()) return s; @@ -306,10 +299,10 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( } case PathAcceptingKeyword::ELEM_MATCH: - return _parseElemMatch(name, e, collator, expCtx, allowedFeatures, topLevel); + return _parseElemMatch(name, e, expCtx, allowedFeatures, topLevel); case PathAcceptingKeyword::ALL: - return _parseAll(name, e, collator, expCtx, allowedFeatures, topLevel); + return _parseAll(name, e, expCtx, allowedFeatures, topLevel); case PathAcceptingKeyword::WITHIN: case PathAcceptingKeyword::GEO_INTERSECTS: @@ -356,7 +349,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( str::stream() << "$_internalSchemaObjectMatch must be an object"); } - auto parsedSubObjExpr = _parse(e.Obj(), collator, expCtx, allowedFeatures, topLevel); + auto parsedSubObjExpr = _parse(e.Obj(), expCtx, allowedFeatures, topLevel); if (!parsedSubObjExpr.isOK()) { return parsedSubObjExpr; } @@ -394,7 +387,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( } case PathAcceptingKeyword::INTERNAL_SCHEMA_MATCH_ARRAY_INDEX: { - return _parseInternalSchemaMatchArrayIndex(name, e, collator); + return _parseInternalSchemaMatchArrayIndex(name, e, expCtx); } case PathAcceptingKeyword::INTERNAL_SCHEMA_ALL_ELEM_MATCH_FROM_INDEX: { @@ -443,7 +436,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( } auto exprWithPlaceholder = - ExpressionWithPlaceholder::parse(second.embeddedObject(), collator); + ExpressionWithPlaceholder::parse(second.embeddedObject(), expCtx); if (!exprWithPlaceholder.isOK()) { return exprWithPlaceholder.getStatus(); } @@ -477,7 +470,6 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( StatusWithMatchExpression MatchExpressionParser::_parse( const BSONObj& obj, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel) { @@ -494,8 +486,8 @@ StatusWithMatchExpression MatchExpressionParser::_parse( if (e.type() != Array) return {Status(ErrorCodes::BadValue, "$or must be an array")}; std::unique_ptr<OrMatchExpression> temp = stdx::make_unique<OrMatchExpression>(); - Status s = _parseTreeList( - e.Obj(), temp.get(), collator, expCtx, allowedFeatures, childIsTopLevel); + Status s = + _parseTreeList(e.Obj(), temp.get(), expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; root->add(temp.release()); @@ -503,8 +495,8 @@ StatusWithMatchExpression MatchExpressionParser::_parse( if (e.type() != Array) return {Status(ErrorCodes::BadValue, "$and must be an array")}; std::unique_ptr<AndMatchExpression> temp = stdx::make_unique<AndMatchExpression>(); - Status s = _parseTreeList( - e.Obj(), temp.get(), collator, expCtx, allowedFeatures, childIsTopLevel); + Status s = + _parseTreeList(e.Obj(), temp.get(), expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; root->add(temp.release()); @@ -512,8 +504,8 @@ StatusWithMatchExpression MatchExpressionParser::_parse( if (e.type() != Array) return {Status(ErrorCodes::BadValue, "$nor must be an array")}; std::unique_ptr<NorMatchExpression> temp = stdx::make_unique<NorMatchExpression>(); - Status s = _parseTreeList( - e.Obj(), temp.get(), collator, expCtx, allowedFeatures, childIsTopLevel); + Status s = + _parseTreeList(e.Obj(), temp.get(), expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; root->add(temp.release()); @@ -562,11 +554,11 @@ StatusWithMatchExpression MatchExpressionParser::_parse( if (!s.isOK()) return s; // 'id' is collation-aware. 'ref' and 'db' are compared using binary comparison. - eq->setCollator(str::equals("id", rest) ? collator : nullptr); + eq->setCollator(str::equals("id", rest) ? expCtx->getCollator() : nullptr); root->add(eq.release()); } else if (mongoutils::str::equals("_internalSchemaAllowedProperties", rest)) { - auto allowedProperties = _parseInternalSchemaAllowedProperties(e, collator); + auto allowedProperties = _parseInternalSchemaAllowedProperties(e, expCtx); if (!allowedProperties.isOK()) { return allowedProperties.getStatus(); } @@ -574,11 +566,7 @@ StatusWithMatchExpression MatchExpressionParser::_parse( } else if (mongoutils::str::equals("_internalSchemaCond", rest)) { auto condExpr = _parseInternalSchemaFixedArityArgument<InternalSchemaCondMatchExpression>( - InternalSchemaCondMatchExpression::kName, - e, - collator, - expCtx, - allowedFeatures); + InternalSchemaCondMatchExpression::kName, e, expCtx, allowedFeatures); if (!condExpr.isOK()) { return condExpr.getStatus(); } @@ -590,7 +578,7 @@ StatusWithMatchExpression MatchExpressionParser::_parse( Status(ErrorCodes::TypeMismatch, "$_internalSchemaXor must be an array")}; auto xorExpr = stdx::make_unique<InternalSchemaXorMatchExpression>(); Status s = _parseTreeList( - e.Obj(), xorExpr.get(), collator, expCtx, allowedFeatures, childIsTopLevel); + e.Obj(), xorExpr.get(), expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; root->add(xorExpr.release()); @@ -676,13 +664,8 @@ StatusWithMatchExpression MatchExpressionParser::_parse( } if (_isExpressionDocument(e, false)) { - Status s = _parseSub(e.fieldName(), - e.Obj(), - root.get(), - collator, - expCtx, - allowedFeatures, - childIsTopLevel); + Status s = _parseSub( + e.fieldName(), e.Obj(), root.get(), expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; continue; @@ -697,7 +680,7 @@ StatusWithMatchExpression MatchExpressionParser::_parse( } auto eq = _parseComparison( - e.fieldName(), new EqualityMatchExpression(), e, collator, expCtx, allowedFeatures); + e.fieldName(), new EqualityMatchExpression(), e, expCtx, allowedFeatures); if (!eq.isOK()) return eq; @@ -716,7 +699,6 @@ StatusWithMatchExpression MatchExpressionParser::_parse( Status MatchExpressionParser::_parseSub(const char* name, const BSONObj& sub, AndMatchExpression* root, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel) { @@ -752,8 +734,8 @@ Status MatchExpressionParser::_parseSub(const char* name, BSONElement deep = j.next(); const bool childIsTopLevel = false; - StatusWithMatchExpression s = _parseSubField( - sub, root, name, deep, collator, expCtx, allowedFeatures, childIsTopLevel); + StatusWithMatchExpression s = + _parseSubField(sub, root, name, deep, expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s.getStatus(); @@ -909,9 +891,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseRegexDocument(const char* Status MatchExpressionParser::_parseInExpression( InMatchExpression* inExpression, const BSONObj& theArray, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx) { - inExpression->setCollator(collator); + inExpression->setCollator(expCtx->getCollator()); std::vector<BSONElement> equalities; BSONObjIterator i(theArray); while (i.more()) { @@ -963,7 +944,6 @@ StatusWithMatchExpression MatchExpressionParser::_parseType(const char* name, StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( const char* name, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel) { @@ -994,7 +974,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( // value case AndMatchExpression theAnd; - Status s = _parseSub("", obj, &theAnd, collator, expCtx, allowedFeatures, topLevel); + Status s = _parseSub("", obj, &theAnd, expCtx, allowedFeatures, topLevel); if (!s.isOK()) return s; @@ -1018,7 +998,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( // object case - StatusWithMatchExpression subRaw = _parse(obj, collator, expCtx, allowedFeatures, topLevel); + StatusWithMatchExpression subRaw = _parse(obj, expCtx, allowedFeatures, topLevel); if (!subRaw.isOK()) return subRaw; std::unique_ptr<MatchExpression> sub = std::move(subRaw.getValue()); @@ -1041,7 +1021,6 @@ StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( StatusWithMatchExpression MatchExpressionParser::_parseAll( const char* name, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel) { @@ -1075,7 +1054,6 @@ StatusWithMatchExpression MatchExpressionParser::_parseAll( const bool childIsTopLevel = false; StatusWithMatchExpression inner = _parseElemMatch(name, hopefullyElemMatchObj.firstElement(), - collator, expCtx, allowedFeatures, childIsTopLevel); @@ -1105,7 +1083,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseAll( Status s = x->init(name, e); if (!s.isOK()) return s; - x->setCollator(collator); + x->setCollator(expCtx->getCollator()); myAnd->add(x.release()); } } @@ -1328,7 +1306,6 @@ template <class T> StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaFixedArityArgument( StringData name, const BSONElement& input, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures) { constexpr auto arity = T::arity(); @@ -1359,7 +1336,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaFixedArityA } const bool isTopLevel = false; - auto subexpr = _parse(elem.embeddedObject(), collator, expCtx, allowedFeatures, isTopLevel); + auto subexpr = _parse(elem.embeddedObject(), expCtx, allowedFeatures, isTopLevel); if (!subexpr.isOK()) { return subexpr.getStatus(); } @@ -1439,7 +1416,7 @@ StatusWith<std::unique_ptr<ExpressionWithPlaceholder>> parseExprWithPlaceholder( StringData exprWithPlaceholderFieldName, StringData expressionName, StringData expectedPlaceholder, - const CollatorInterface* collator) { + const boost::intrusive_ptr<ExpressionContext>& expCtx) { auto exprWithPlaceholderElem = containingObject[exprWithPlaceholderFieldName]; if (!exprWithPlaceholderElem) { return {ErrorCodes::FailedToParse, @@ -1453,7 +1430,7 @@ StatusWith<std::unique_ptr<ExpressionWithPlaceholder>> parseExprWithPlaceholder( } auto result = - ExpressionWithPlaceholder::parse(exprWithPlaceholderElem.embeddedObject(), collator); + ExpressionWithPlaceholder::parse(exprWithPlaceholderElem.embeddedObject(), expCtx); if (!result.isOK()) { return result.getStatus(); } @@ -1475,7 +1452,7 @@ StatusWith<std::unique_ptr<ExpressionWithPlaceholder>> parseExprWithPlaceholder( StatusWith<std::vector<InternalSchemaAllowedPropertiesMatchExpression::PatternSchema>> parsePatternProperties(BSONElement patternPropertiesElem, StringData expectedPlaceholder, - const CollatorInterface* collator) { + const boost::intrusive_ptr<ExpressionContext>& expCtx) { if (!patternPropertiesElem) { return {ErrorCodes::FailedToParse, str::stream() << InternalSchemaAllowedPropertiesMatchExpression::kName @@ -1508,7 +1485,7 @@ parsePatternProperties(BSONElement patternPropertiesElem, "expression"_sd, InternalSchemaAllowedPropertiesMatchExpression::kName, expectedPlaceholder, - collator); + expCtx); if (!expressionWithPlaceholder.isOK()) { return expressionWithPlaceholder.getStatus(); } @@ -1570,7 +1547,9 @@ StatusWith<boost::container::flat_set<StringData>> parseProperties(BSONElement p } // namespace StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaMatchArrayIndex( - const char* path, const BSONElement& elem, const CollatorInterface* collator) { + const char* path, + const BSONElement& elem, + const boost::intrusive_ptr<ExpressionContext>& expCtx) { if (elem.type() != BSONType::Object) { return {ErrorCodes::TypeMismatch, str::stream() << InternalSchemaMatchArrayIndexMatchExpression::kName @@ -1601,7 +1580,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaMatchArrayI "expression"_sd, InternalSchemaMatchArrayIndexMatchExpression::kName, namePlaceholder.getValue(), - collator); + expCtx); if (!expressionWithPlaceholder.isOK()) { return expressionWithPlaceholder.getStatus(); } @@ -1616,7 +1595,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaMatchArrayI } StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaAllowedProperties( - const BSONElement& elem, const CollatorInterface* collator) { + const BSONElement& elem, const boost::intrusive_ptr<ExpressionContext>& expCtx) { if (elem.type() != BSONType::Object) { return {ErrorCodes::TypeMismatch, str::stream() << InternalSchemaAllowedPropertiesMatchExpression::kName @@ -1638,7 +1617,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaAllowedProp } auto patternProperties = - parsePatternProperties(subobj["patternProperties"], namePlaceholder.getValue(), collator); + parsePatternProperties(subobj["patternProperties"], namePlaceholder.getValue(), expCtx); if (!patternProperties.isOK()) { return patternProperties.getStatus(); } @@ -1647,7 +1626,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaAllowedProp "otherwise"_sd, InternalSchemaAllowedPropertiesMatchExpression::kName, namePlaceholder.getValue(), - collator); + expCtx); if (!otherwise.isOK()) { return otherwise.getStatus(); } diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h index 095bd79212d..44ffd4ae9a0 100644 --- a/src/mongo/db/matcher/expression_parser.h +++ b/src/mongo/db/matcher/expression_parser.h @@ -44,7 +44,6 @@ namespace mongo { -class CollatorInterface; class OperationContext; enum class PathAcceptingKeyword { @@ -123,18 +122,13 @@ public: */ static StatusWithMatchExpression parse( const BSONObj& obj, - const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr, + const boost::intrusive_ptr<ExpressionContext>& expCtx, const ExtensionsCallback& extensionsCallback = ExtensionsCallbackNoop(), AllowedFeatureSet allowedFeatures = kDefaultSpecialFeatures) { - // A non-null ExpressionContext is required for parsing $expr. - if (!expCtx) { - invariant((allowedFeatures & AllowedFeatures::kExpr) == 0u); - } - + invariant(expCtx.get()); const bool topLevelCall = true; return MatchExpressionParser(&extensionsCallback) - ._parse(obj, collator, expCtx, allowedFeatures, topLevelCall); + ._parse(obj, expCtx, allowedFeatures, topLevelCall); } /** @@ -185,14 +179,10 @@ private: /** * Parse 'obj' and return either a MatchExpression or an error. * - * 'collator' is the collator that constructed collation-aware MatchExpressions will use. It - * must outlive the returned MatchExpression and any clones made of it. - * * 'topLevel' indicates whether or not the we are at the top level of the tree across recursive * class to this function. This is used to apply special logic at the top level. */ StatusWithMatchExpression _parse(const BSONObj& obj, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel); @@ -205,7 +195,6 @@ private: Status _parseSub(const char* name, const BSONObj& obj, AndMatchExpression* root, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel); @@ -219,7 +208,6 @@ private: const AndMatchExpression* andSoFar, const char* name, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel); @@ -228,7 +216,6 @@ private: const char* name, ComparisonMatchExpression* cmp, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures); @@ -240,7 +227,6 @@ private: Status _parseInExpression(InMatchExpression* entries, const BSONObj& theArray, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx); template <class T> @@ -259,14 +245,12 @@ private: StatusWithMatchExpression _parseElemMatch(const char* name, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel); StatusWithMatchExpression _parseAll(const char* name, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel); @@ -275,14 +259,12 @@ private: Status _parseTreeList(const BSONObj& arr, ListOfMatchExpression* out, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel); StatusWithMatchExpression _parseNot(const char* name, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel); @@ -307,7 +289,6 @@ private: StatusWithMatchExpression _parseInternalSchemaFixedArityArgument( StringData name, const BSONElement& elem, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures); @@ -331,10 +312,12 @@ private: * Parses 'elem' into an InternalSchemaMatchArrayIndexMatchExpression. */ StatusWithMatchExpression _parseInternalSchemaMatchArrayIndex( - const char* path, const BSONElement& elem, const CollatorInterface* collator); + const char* path, + const BSONElement& elem, + const boost::intrusive_ptr<ExpressionContext>& expCtx); StatusWithMatchExpression _parseInternalSchemaAllowedProperties( - const BSONElement& elem, const CollatorInterface* collator); + const BSONElement& elem, const boost::intrusive_ptr<ExpressionContext>& expCtx); // Performs parsing for the match extensions. We do not own this pointer - it has to live // as long as the parser is active. diff --git a/src/mongo/db/matcher/expression_parser_array_test.cpp b/src/mongo/db/matcher/expression_parser_array_test.cpp index 23cef6b1180..8216c58f8ff 100644 --- a/src/mongo/db/matcher/expression_parser_array_test.cpp +++ b/src/mongo/db/matcher/expression_parser_array_test.cpp @@ -38,6 +38,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_array.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" namespace mongo { @@ -46,8 +47,8 @@ using std::string; TEST(MatchExpressionParserArrayTest, Size1) { BSONObj query = BSON("x" << BSON("$size" << 2)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -58,8 +59,8 @@ TEST(MatchExpressionParserArrayTest, Size1) { TEST(MatchExpressionParserArrayTest, SizeAsLong) { BSONObj query = BSON("x" << BSON("$size" << 2LL)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -70,30 +71,30 @@ TEST(MatchExpressionParserArrayTest, SizeAsLong) { TEST(MatchExpressionParserArrayTest, SizeAsNegativeLong) { BSONObj query = BSON("x" << BSON("$size" << -2LL)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeTooLarge) { BSONObj query = BSON("x" << BSON("$size" << std::numeric_limits<long long>::max())); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeAsString) { BSONObj query = BSON("x" << BSON("$size" << "a")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithIntegralDouble) { BSONObj query = BSON("x" << BSON("$size" << 2.0)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -104,29 +105,29 @@ TEST(MatchExpressionParserArrayTest, SizeWithIntegralDouble) { TEST(MatchExpressionParserArrayTest, SizeWithNegativeIntegralDouble) { BSONObj query = BSON("x" << BSON("$size" << -2.0)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithDouble) { BSONObj query = BSON("x" << BSON("$size" << 2.5)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithNegative) { BSONObj query = BSON("x" << BSON("$size" << -2)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeBad) { BSONObj query = BSON("x" << BSON("$size" << BSONNULL)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } @@ -134,8 +135,8 @@ TEST(MatchExpressionParserArrayTest, SizeBad) { TEST(MatchExpressionParserArrayTest, ElemMatchArr1) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("x" << 1 << "y" << 2))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -147,8 +148,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchArr1) { TEST(MatchExpressionParserArrayTest, ElemMatchAnd) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$and" << BSON_ARRAY(BSON("x" << 1 << "y" << 2))))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -159,8 +160,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchAnd) { TEST(MatchExpressionParserArrayTest, ElemMatchNor) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$nor" << BSON_ARRAY(BSON("x" << 1))))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -172,8 +173,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchNor) { TEST(MatchExpressionParserArrayTest, ElemMatchOr) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$or" << BSON_ARRAY(BSON("x" << 1 << "y" << 2))))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -184,8 +185,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchOr) { TEST(MatchExpressionParserArrayTest, ElemMatchVal1) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$gt" << 5))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -211,8 +212,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef1) { << "db"); BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$eq" << match))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -237,8 +238,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef2) { << "db"); BSONObj query = BSON("x" << BSON("$elemMatch" << match)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -264,8 +265,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef3) { << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << match)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -307,8 +308,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef4) { << "db"); BSONObj query = BSON("x" << BSON("$elemMatch" << matchOutOfOrder)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -337,8 +338,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef5) { << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << matchOutOfOrder)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -377,8 +378,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef6) { << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << matchMissingID)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -415,8 +416,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef7) { << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << matchMissingRef)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -459,8 +460,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef8) { << 12345); BSONObj query = BSON("x" << BSON("$elemMatch" << matchDBOnly)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -482,8 +483,8 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef8) { TEST(MatchExpressionParserArrayTest, All1) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(1 << 2))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -499,8 +500,8 @@ TEST(MatchExpressionParserArrayTest, All1) { TEST(MatchExpressionParserArrayTest, AllNull) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(BSONNULL))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -514,8 +515,8 @@ TEST(MatchExpressionParserArrayTest, AllNull) { TEST(MatchExpressionParserArrayTest, AllBadArg) { BSONObj query = BSON("x" << BSON("$all" << 1)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } @@ -528,8 +529,8 @@ TEST(MatchExpressionParserArrayTest, AllBadRegexArg) { BSONObj query = BSON("x" << operand.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } @@ -542,8 +543,8 @@ TEST(MatchExpressionParserArrayTest, AllRegex1) { all.appendArray("$all", allArray.obj()); BSONObj query = BSON("a" << all.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -569,8 +570,8 @@ TEST(MatchExpressionParserArrayTest, AllRegex2) { all.appendArray("$all", allArray.obj()); BSONObj query = BSON("a" << all.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -587,8 +588,8 @@ TEST(MatchExpressionParserArrayTest, AllRegex2) { TEST(MatchExpressionParserArrayTest, AllNonArray) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(5))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -604,8 +605,8 @@ TEST(MatchExpressionParserArrayTest, AllNonArray) { TEST(MatchExpressionParserArrayTest, AllElemMatch1) { BSONObj internal = BSON("x" << 1 << "y" << 2); BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(BSON("$elemMatch" << internal)))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to an AND with a single ELEM_MATCH_OBJECT child. @@ -625,8 +626,8 @@ TEST(MatchExpressionParserArrayTest, AllElemMatch1) { TEST(MatchExpressionParserArrayTest, AllElemMatch2) { BSONObj internal = BSON("z" << 1); BSONObj query = BSON("x.y" << BSON("$all" << BSON_ARRAY(BSON("$elemMatch" << internal)))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to an AND with a single ELEM_MATCH_OBJECT child. @@ -661,8 +662,8 @@ TEST(MatchExpressionParserArrayTest, AllElemMatch2) { // are correct. TEST(MatchExpressionParserArrayTest, AllElemMatch3) { BSONObj query = fromjson("{x: {$all: [{$elemMatch: {y: 1, z: 1}}]}}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); std::unique_ptr<MatchExpression> expr = std::move(result.getValue()); @@ -697,12 +698,12 @@ TEST(MatchExpressionParserArrayTest, AllElemMatchBad) { BSONObj internal = BSON("x" << 1 << "y" << 2); BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(BSON("$elemMatch" << internal) << 5))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$all" << BSON_ARRAY(5 << BSON("$elemMatch" << internal)))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } @@ -710,31 +711,31 @@ TEST(MatchExpressionParserArrayTest, AllElemMatchBad) { TEST(MatchExpressionParserArrayTest, AllElemMatchBadMixed) { // $elemMatch first, equality second. BSONObj bad1 = fromjson("{x: {$all: [{$elemMatch: {y: 1}}, 3]}}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result1 = MatchExpressionParser::parse(bad1, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result1 = MatchExpressionParser::parse(bad1, expCtx); ASSERT_FALSE(result1.isOK()); // equality first, $elemMatch second BSONObj bad2 = fromjson("{x: {$all: [3, {$elemMatch: {y: 1}}]}}"); - StatusWithMatchExpression result2 = MatchExpressionParser::parse(bad2, collator); + StatusWithMatchExpression result2 = MatchExpressionParser::parse(bad2, expCtx); ASSERT_FALSE(result1.isOK()); // $elemMatch first, object second BSONObj bad3 = fromjson("{x: {$all: [{$elemMatch: {y: 1}}, {z: 1}]}}"); - StatusWithMatchExpression result3 = MatchExpressionParser::parse(bad3, collator); + StatusWithMatchExpression result3 = MatchExpressionParser::parse(bad3, expCtx); ASSERT_FALSE(result3.isOK()); // object first, $elemMatch second BSONObj bad4 = fromjson("{x: {$all: [{z: 1}, {$elemMatch: {y: 1}}]}}"); - StatusWithMatchExpression result4 = MatchExpressionParser::parse(bad4, collator); + StatusWithMatchExpression result4 = MatchExpressionParser::parse(bad4, expCtx); ASSERT_FALSE(result4.isOK()); } // $all with empty string. TEST(MatchExpressionParserArrayTest, AllEmptyString) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(""))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -758,8 +759,8 @@ TEST(MatchExpressionParserArrayTest, AllISODate) { const Date_t& notMatch = notMatchResult.getValue(); BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(match))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << notMatch))); @@ -774,8 +775,8 @@ TEST(MatchExpressionParserArrayTest, AllISODate) { // $all on array element with empty string. TEST(MatchExpressionParserArrayTest, AllDottedEmptyString) { BSONObj query = BSON("x.1" << BSON("$all" << BSON_ARRAY(""))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -801,8 +802,8 @@ TEST(MatchExpressionParserArrayTest, AllDottedISODate) { const Date_t& notMatch = notMatchResult.getValue(); BSONObj query = BSON("x.1" << BSON("$all" << BSON_ARRAY(match))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << notMatch))); @@ -818,21 +819,23 @@ TEST(MatchExpressionParserArrayTest, AllDottedISODate) { TEST(MatchExpressionParserArrayTest, AllStringNullCollation) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY("string"))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); 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); + ASSERT_TRUE(eqMatch->getCollator() == nullptr); } TEST(MatchExpressionParserArrayTest, AllStringCollation) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY("string"))); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT_EQUALS(MatchExpression::AND, result.getValue()->matchType()); ASSERT_EQUALS(1U, result.getValue()->numChildren()); diff --git a/src/mongo/db/matcher/expression_parser_geo_test.cpp b/src/mongo/db/matcher/expression_parser_geo_test.cpp index 38ffdafe4da..7410fb1b01a 100644 --- a/src/mongo/db/matcher/expression_parser_geo_test.cpp +++ b/src/mongo/db/matcher/expression_parser_geo_test.cpp @@ -35,21 +35,16 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_geo.h" #include "mongo/db/matcher/extensions_callback_noop.h" -#include "mongo/db/pipeline/aggregation_context_fixture.h" +#include "mongo/db/pipeline/expression_context_for_test.h" namespace mongo { TEST(MatchExpressionParserGeo, WithinBox) { BSONObj query = fromjson("{a:{$within:{$box:[{x: 4, y:4},[6,6]]}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(fromjson("{a: [3,4]}"))); @@ -64,14 +59,9 @@ TEST(MatchExpressionParserGeoNear, ParseNear) { "{loc:{$near:{$maxDistance:100, " "$geometry:{type:\"Point\", coordinates:[0,0]}}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -87,10 +77,8 @@ TEST(MatchExpressionParserGeoNear, ParseNearExtraField) { "{loc:{$near:{$maxDistance:100, " "$geometry:{type:\"Point\", coordinates:[0,0]}}, foo: 1}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -107,14 +95,9 @@ TEST(MatchExpressionParserGeoNear, ParseNearExtraField) { TEST(MatchExpressionParserGeoNear, ParseValidNear) { BSONObj query = fromjson("{loc: {$near: [0,0], $maxDistance: 100, $minDistance: 50}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -128,11 +111,9 @@ TEST(MatchExpressionParserGeoNear, ParseValidNear) { TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $near: [0,0]}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -140,11 +121,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { } { BSONObj query = fromjson("{loc: {$minDistance: 100, $near: [0,0]}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -152,10 +131,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { } { BSONObj query = fromjson("{loc: {$near: [0,0], $maxDistance: {}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -164,10 +141,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { } { BSONObj query = fromjson("{loc: {$near: [0,0], $minDistance: {}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -176,10 +151,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { } { BSONObj query = fromjson("{loc: {$near: [0,0], $eq: 40}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -188,11 +161,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { } { BSONObj query = fromjson("{loc: {$eq: 40, $near: [0,0]}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -201,10 +172,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { { BSONObj query = fromjson( "{loc: {$near: [0,0], $geoWithin: {$geometry: {type: \"Polygon\", coordinates: []}}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -213,11 +182,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { } { BSONObj query = fromjson("{loc: {$near: {$foo: 1}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -225,11 +192,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { } { BSONObj query = fromjson("{loc: {$minDistance: 10}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -240,14 +205,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { TEST(MatchExpressionParserGeoNear, ParseValidGeoNear) { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $maxDistance: 100, $minDistance: 50}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -261,11 +221,9 @@ TEST(MatchExpressionParserGeoNear, ParseValidGeoNear) { TEST(MatchExpressionParserGeoNear, ParseInvalidGeoNear) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $geoNear: [0,0]}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -273,11 +231,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidGeoNear) { } { BSONObj query = fromjson("{loc: {$minDistance: 100, $geoNear: [0,0]}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -285,10 +241,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidGeoNear) { } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $eq: 1}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -297,10 +251,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidGeoNear) { } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $maxDistance: {}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -309,10 +261,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidGeoNear) { } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $minDistance: {}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -324,14 +274,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidGeoNear) { TEST(MatchExpressionParserGeoNear, ParseValidNearSphere) { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $maxDistance: 100, $minDistance: 50}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -345,11 +290,9 @@ TEST(MatchExpressionParserGeoNear, ParseValidNearSphere) { TEST(MatchExpressionParserGeoNear, ParseInvalidNearSphere) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $nearSphere: [0,0]}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -357,11 +300,9 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNearSphere) { } { BSONObj query = fromjson("{loc: {$minDistance: 100, $nearSphere: [0,0]}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -369,10 +310,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNearSphere) { } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $maxDistance: {}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -381,10 +320,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNearSphere) { } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $minDistance: {}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) @@ -393,10 +330,8 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNearSphere) { } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $eq: 1}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_THROWS(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures) diff --git a/src/mongo/db/matcher/expression_parser_leaf_test.cpp b/src/mongo/db/matcher/expression_parser_leaf_test.cpp index 074825045b1..b327ba11d00 100644 --- a/src/mongo/db/matcher/expression_parser_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_parser_leaf_test.cpp @@ -34,6 +34,7 @@ #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/extensions_callback_noop.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/platform/decimal128.h" #include "mongo/unittest/death_test.h" @@ -47,12 +48,12 @@ using std::string; TEST(MatchExpressionParserLeafTest, NullCollation) { BSONObj query = BSON("x" << "string"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); - ASSERT_TRUE(match->getCollator() == collator); + ASSERT_TRUE(match->getCollator() == nullptr); } @@ -60,7 +61,9 @@ TEST(MatchExpressionParserLeafTest, Collation) { BSONObj query = BSON("x" << "string"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -69,8 +72,8 @@ TEST(MatchExpressionParserLeafTest, Collation) { TEST(MatchExpressionParserLeafTest, SimpleEQ2) { BSONObj query = BSON("x" << BSON("$eq" << 2)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -80,20 +83,20 @@ TEST(MatchExpressionParserLeafTest, SimpleEQ2) { TEST(MatchExpressionParserLeafTest, SimpleEQUndefined) { BSONObj query = BSON("x" << BSON("$eq" << BSONUndefined)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, EQNullCollation) { BSONObj query = BSON("x" << BSON("$eq" << "string")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); - ASSERT_TRUE(match->getCollator() == collator); + ASSERT_TRUE(match->getCollator() == nullptr); } @@ -101,7 +104,9 @@ TEST(MatchExpressionParserLeafTest, EQCollation) { BSONObj query = BSON("x" << BSON("$eq" << "string")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -110,8 +115,8 @@ TEST(MatchExpressionParserLeafTest, EQCollation) { TEST(MatchExpressionParserLeafTest, SimpleGT1) { BSONObj query = BSON("x" << BSON("$gt" << 2)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 2))); @@ -121,12 +126,12 @@ TEST(MatchExpressionParserLeafTest, SimpleGT1) { TEST(MatchExpressionParserLeafTest, GTNullCollation) { BSONObj query = BSON("x" << BSON("$gt" << "abc")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GT, result.getValue()->matchType()); GTMatchExpression* match = static_cast<GTMatchExpression*>(result.getValue().get()); - ASSERT_TRUE(match->getCollator() == collator); + ASSERT_TRUE(match->getCollator() == nullptr); } @@ -134,7 +139,9 @@ TEST(MatchExpressionParserLeafTest, GTCollation) { BSONObj query = BSON("x" << BSON("$gt" << "abc")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GT, result.getValue()->matchType()); GTMatchExpression* match = static_cast<GTMatchExpression*>(result.getValue().get()); @@ -143,8 +150,8 @@ TEST(MatchExpressionParserLeafTest, GTCollation) { TEST(MatchExpressionParserLeafTest, SimpleLT1) { BSONObj query = BSON("x" << BSON("$lt" << 2)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -155,12 +162,12 @@ TEST(MatchExpressionParserLeafTest, SimpleLT1) { TEST(MatchExpressionParserLeafTest, LTNullCollation) { BSONObj query = BSON("x" << BSON("$lt" << "abc")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LT, result.getValue()->matchType()); LTMatchExpression* match = static_cast<LTMatchExpression*>(result.getValue().get()); - ASSERT_TRUE(match->getCollator() == collator); + ASSERT_TRUE(match->getCollator() == nullptr); } @@ -168,7 +175,9 @@ TEST(MatchExpressionParserLeafTest, LTCollation) { BSONObj query = BSON("x" << BSON("$lt" << "abc")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LT, result.getValue()->matchType()); LTMatchExpression* match = static_cast<LTMatchExpression*>(result.getValue().get()); @@ -177,8 +186,8 @@ TEST(MatchExpressionParserLeafTest, LTCollation) { TEST(MatchExpressionParserLeafTest, SimpleGTE1) { BSONObj query = BSON("x" << BSON("$gte" << 2)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -189,12 +198,12 @@ TEST(MatchExpressionParserLeafTest, SimpleGTE1) { TEST(MatchExpressionParserLeafTest, GTENullCollation) { BSONObj query = BSON("x" << BSON("$gte" << "abc")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GTE, result.getValue()->matchType()); GTEMatchExpression* match = static_cast<GTEMatchExpression*>(result.getValue().get()); - ASSERT_TRUE(match->getCollator() == collator); + ASSERT_TRUE(match->getCollator() == nullptr); } @@ -202,7 +211,9 @@ TEST(MatchExpressionParserLeafTest, GTECollation) { BSONObj query = BSON("x" << BSON("$gte" << "abc")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GTE, result.getValue()->matchType()); GTEMatchExpression* match = static_cast<GTEMatchExpression*>(result.getValue().get()); @@ -211,8 +222,8 @@ TEST(MatchExpressionParserLeafTest, GTECollation) { TEST(MatchExpressionParserLeafTest, SimpleLTE1) { BSONObj query = BSON("x" << BSON("$lte" << 2)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -223,12 +234,12 @@ TEST(MatchExpressionParserLeafTest, SimpleLTE1) { TEST(MatchExpressionParserLeafTest, LTENullCollation) { BSONObj query = BSON("x" << BSON("$lte" << "abc")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LTE, result.getValue()->matchType()); LTEMatchExpression* match = static_cast<LTEMatchExpression*>(result.getValue().get()); - ASSERT_TRUE(match->getCollator() == collator); + ASSERT_TRUE(match->getCollator() == nullptr); } @@ -236,7 +247,9 @@ TEST(MatchExpressionParserLeafTest, LTECollation) { BSONObj query = BSON("x" << BSON("$lte" << "abc")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LTE, result.getValue()->matchType()); LTEMatchExpression* match = static_cast<LTEMatchExpression*>(result.getValue().get()); @@ -245,8 +258,8 @@ TEST(MatchExpressionParserLeafTest, LTECollation) { TEST(MatchExpressionParserLeafTest, SimpleNE1) { BSONObj query = BSON("x" << BSON("$ne" << 2)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -257,14 +270,14 @@ TEST(MatchExpressionParserLeafTest, SimpleNE1) { TEST(MatchExpressionParserLeafTest, NENullCollation) { BSONObj query = BSON("x" << BSON("$ne" << "string")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); 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); + ASSERT_TRUE(eqMatch->getCollator() == nullptr); } @@ -272,7 +285,9 @@ TEST(MatchExpressionParserLeafTest, NECollation) { BSONObj query = BSON("x" << BSON("$ne" << "string")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); MatchExpression* child = result.getValue()->getChild(0); @@ -283,35 +298,35 @@ TEST(MatchExpressionParserLeafTest, NECollation) { TEST(MatchExpressionParserLeafTest, SimpleModBad1) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << BSON_ARRAY(3))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2 << 4))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << BSON_ARRAY("q" << 2))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << 3)); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << BSON("a" << 1 << "b" << 2))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, SimpleMod1) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5))); @@ -321,8 +336,8 @@ TEST(MatchExpressionParserLeafTest, SimpleMod1) { TEST(MatchExpressionParserLeafTest, SimpleModNotNumber) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(2 << "r"))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -335,19 +350,21 @@ TEST(MatchExpressionParserLeafTest, SimpleModNotNumber) { TEST(MatchExpressionParserLeafTest, IdCollation) { BSONObj query = BSON("$id" << "string"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); - ASSERT_TRUE(match->getCollator() == collator); + ASSERT_TRUE(match->getCollator() == nullptr); } TEST(MatchExpressionParserLeafTest, IdNullCollation) { BSONObj query = BSON("$id" << "string"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -358,7 +375,9 @@ TEST(MatchExpressionParserLeafTest, RefCollation) { BSONObj query = BSON("$ref" << "coll"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -369,7 +388,9 @@ TEST(MatchExpressionParserLeafTest, DbCollation) { BSONObj query = BSON("$db" << "db"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -378,8 +399,8 @@ TEST(MatchExpressionParserLeafTest, DbCollation) { TEST(MatchExpressionParserLeafTest, SimpleIN1) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(2 << 3))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -389,18 +410,20 @@ TEST(MatchExpressionParserLeafTest, SimpleIN1) { TEST(MatchExpressionParserLeafTest, INNullCollation) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY("string"))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::MATCH_IN, result.getValue()->matchType()); InMatchExpression* match = static_cast<InMatchExpression*>(result.getValue().get()); - ASSERT_TRUE(match->getCollator() == collator); + ASSERT_TRUE(match->getCollator() == nullptr); } TEST(MatchExpressionParserLeafTest, INCollation) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY("string"))); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::MATCH_IN, result.getValue()->matchType()); InMatchExpression* match = static_cast<InMatchExpression*>(result.getValue().get()); @@ -415,8 +438,8 @@ TEST(MatchExpressionParserLeafTest, INSingleDBRef) { << oid << "$db" << "db")))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); OID oidx = OID::gen(); @@ -497,8 +520,8 @@ TEST(MatchExpressionParserLeafTest, INMultipleDBRef) { << oid << "$db" << "db")))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); OID oidx = OID::gen(); @@ -638,8 +661,8 @@ TEST(MatchExpressionParserLeafTest, INDBRefWithOptionalField1) { << oid << "foo" << 12345)))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); OID oidx = OID::gen(); @@ -673,23 +696,23 @@ TEST(MatchExpressionParserLeafTest, INInvalidDBRefs) { // missing $id BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll")))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); - result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); + result = MatchExpressionParser::parse(query, expCtx); // second field is not $id query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll" << "$foo" << 1)))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); OID oid = OID::gen(); // missing $ref field query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$id" << oid << "foo" << 3)))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); // missing $id and $ref field @@ -697,35 +720,35 @@ TEST(MatchExpressionParserLeafTest, INInvalidDBRefs) { << "test" << "foo" << 3)))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, INExpressionDocument) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$foo" << 1)))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, INNotArray) { BSONObj query = BSON("x" << BSON("$in" << 5)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, INUndefined) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSONUndefined))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, INNotElemMatch) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$elemMatch" << 1)))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } @@ -736,16 +759,16 @@ TEST(MatchExpressionParserLeafTest, INRegexTooLong) { BSONObjBuilder operand; operand.appendArray("$in", inArray.obj()); BSONObj query = BSON("x" << operand.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, INRegexTooLong2) { string tooLargePattern(50 * 1000, 'z'); BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$regex" << tooLargePattern)))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } @@ -758,8 +781,8 @@ TEST(MatchExpressionParserLeafTest, INRegexStuff) { operand.appendArray("$in", inArray.obj()); BSONObj query = BSON("a" << operand.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); BSONObj matchFirst = BSON("a" @@ -784,8 +807,8 @@ TEST(MatchExpressionParserLeafTest, INRegexStuff) { TEST(MatchExpressionParserLeafTest, SimpleNIN1) { BSONObj query = BSON("x" << BSON("$nin" << BSON_ARRAY(2 << 3))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -795,27 +818,29 @@ TEST(MatchExpressionParserLeafTest, SimpleNIN1) { TEST(MatchExpressionParserLeafTest, NINNotArray) { BSONObj query = BSON("x" << BSON("$nin" << 5)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, NINNullCollation) { BSONObj query = BSON("x" << BSON("$nin" << BSON_ARRAY("string"))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); 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); + ASSERT_TRUE(inMatch->getCollator() == nullptr); } TEST(MatchExpressionParserLeafTest, NINCollation) { BSONObj query = BSON("x" << BSON("$nin" << BSON_ARRAY("string"))); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); MatchExpression* child = result.getValue()->getChild(0); @@ -828,8 +853,8 @@ TEST(MatchExpressionParserLeafTest, Regex1) { BSONObjBuilder b; b.appendRegex("x", "abc", "i"); BSONObj query = b.obj(); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -845,8 +870,8 @@ TEST(MatchExpressionParserLeafTest, Regex2) { << "abc" << "$options" << "i")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -862,8 +887,8 @@ TEST(MatchExpressionParserLeafTest, Regex3) { << "i" << "$regex" << "abc")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -880,35 +905,35 @@ TEST(MatchExpressionParserLeafTest, RegexBad) { << "abc" << "$optionas" << "i")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); // $regex does not with numbers query = BSON("x" << BSON("$regex" << 123)); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$regex" << BSON_ARRAY("abc"))); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$optionas" << "i")); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$options" << "i")); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, RegexEmbeddedNULByte) { BSONObj query = BSON("x" << BSON("$regex" << "^a\\x00b")); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); const auto value = "a\0b"_sd; @@ -921,8 +946,8 @@ TEST(MatchExpressionParserLeafTest, ExistsYes1) { BSONObjBuilder b; b.appendBool("$exists", true); BSONObj query = BSON("x" << b.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -935,8 +960,8 @@ TEST(MatchExpressionParserLeafTest, ExistsNO1) { BSONObjBuilder b; b.appendBool("$exists", false); BSONObj query = BSON("x" << b.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -947,8 +972,8 @@ TEST(MatchExpressionParserLeafTest, ExistsNO1) { TEST(MatchExpressionParserLeafTest, Type1) { BSONObj query = BSON("x" << BSON("$type" << String)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -958,8 +983,8 @@ TEST(MatchExpressionParserLeafTest, Type1) { TEST(MatchExpressionParserLeafTest, Type2) { BSONObj query = BSON("x" << BSON("$type" << (double)NumberDouble)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -968,8 +993,8 @@ TEST(MatchExpressionParserLeafTest, Type2) { TEST(MatchExpressionParserLeafTest, TypeDoubleOperator) { BSONObj query = BSON("x" << BSON("$type" << 1.5)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -978,8 +1003,8 @@ TEST(MatchExpressionParserLeafTest, TypeDoubleOperator) { TEST(MatchExpressionParserLeafTest, TypeDecimalOperator) { BSONObj query = BSON("x" << BSON("$type" << mongo::NumberDecimal)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_FALSE(result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -988,8 +1013,8 @@ TEST(MatchExpressionParserLeafTest, TypeDecimalOperator) { TEST(MatchExpressionParserLeafTest, TypeNull) { BSONObj query = BSON("x" << BSON("$type" << jstNULL)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSONObj())); @@ -1003,36 +1028,33 @@ TEST(MatchExpressionParserLeafTest, TypeBadType) { BSONObjBuilder b; b.append("$type", (JSTypeMax + 1)); BSONObj query = BSON("x" << b.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, TypeBad) { BSONObj query = BSON("x" << BSON("$type" << BSON("x" << 1))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, TypeBadString) { - const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$type: null}}"), collator).getStatus()); - ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$type: true}}"), collator).getStatus()); - ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$type: {}}}}"), collator).getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: null}}"), expCtx).getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: true}}"), expCtx).getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: {}}}}"), expCtx).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - fromjson("{a: {$type: ObjectId('000000000000000000000000')}}"), collator) + fromjson("{a: {$type: ObjectId('000000000000000000000000')}}"), expCtx) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: []}}"), collator).getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: []}}"), expCtx).getStatus()); } TEST(MatchExpressionParserLeafTest, TypeStringnameDouble) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumberDouble = - MatchExpressionParser::parse(fromjson("{a: {$type: 'double'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'double'}}"), expCtx); ASSERT_OK(typeNumberDouble.getStatus()); TypeMatchExpression* tmeNumberDouble = static_cast<TypeMatchExpression*>(typeNumberDouble.getValue().get()); @@ -1044,9 +1066,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameDouble) { } TEST(MatchExpressionParserLeafTest, TypeStringNameNumberDecimal) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumberDecimal = - MatchExpressionParser::parse(fromjson("{a: {$type: 'decimal'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'decimal'}}"), expCtx); ASSERT_OK(typeNumberDecimal.getStatus()); TypeMatchExpression* tmeNumberDecimal = static_cast<TypeMatchExpression*>(typeNumberDecimal.getValue().get()); @@ -1058,9 +1080,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringNameNumberDecimal) { } TEST(MatchExpressionParserLeafTest, TypeStringnameNumberInt) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumberInt = - MatchExpressionParser::parse(fromjson("{a: {$type: 'int'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'int'}}"), expCtx); ASSERT_OK(typeNumberInt.getStatus()); TypeMatchExpression* tmeNumberInt = static_cast<TypeMatchExpression*>(typeNumberInt.getValue().get()); @@ -1072,9 +1094,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumberInt) { } TEST(MatchExpressionParserLeafTest, TypeStringnameNumberLong) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumberLong = - MatchExpressionParser::parse(fromjson("{a: {$type: 'long'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'long'}}"), expCtx); ASSERT_OK(typeNumberLong.getStatus()); TypeMatchExpression* tmeNumberLong = static_cast<TypeMatchExpression*>(typeNumberLong.getValue().get()); @@ -1086,9 +1108,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumberLong) { } TEST(MatchExpressionParserLeafTest, TypeStringnameString) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeString = - MatchExpressionParser::parse(fromjson("{a: {$type: 'string'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'string'}}"), expCtx); ASSERT_OK(typeString.getStatus()); TypeMatchExpression* tmeString = static_cast<TypeMatchExpression*>(typeString.getValue().get()); ASSERT_FALSE(tmeString->typeSet().allNumbers); @@ -1099,9 +1121,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameString) { } TEST(MatchExpressionParserLeafTest, TypeStringnamejstOID) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typejstOID = - MatchExpressionParser::parse(fromjson("{a: {$type: 'objectId'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'objectId'}}"), expCtx); ASSERT_OK(typejstOID.getStatus()); TypeMatchExpression* tmejstOID = static_cast<TypeMatchExpression*>(typejstOID.getValue().get()); ASSERT_FALSE(tmejstOID->typeSet().allNumbers); @@ -1112,9 +1134,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnamejstOID) { } TEST(MatchExpressionParserLeafTest, TypeStringnamejstNULL) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typejstNULL = - MatchExpressionParser::parse(fromjson("{a: {$type: 'null'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'null'}}"), expCtx); ASSERT_OK(typejstNULL.getStatus()); TypeMatchExpression* tmejstNULL = static_cast<TypeMatchExpression*>(typejstNULL.getValue().get()); @@ -1126,9 +1148,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnamejstNULL) { } TEST(MatchExpressionParserLeafTest, TypeStringnameBool) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeBool = - MatchExpressionParser::parse(fromjson("{a: {$type: 'bool'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'bool'}}"), expCtx); ASSERT_OK(typeBool.getStatus()); TypeMatchExpression* tmeBool = static_cast<TypeMatchExpression*>(typeBool.getValue().get()); ASSERT_FALSE(tmeBool->typeSet().allNumbers); @@ -1139,9 +1161,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameBool) { } TEST(MatchExpressionParserLeafTest, TypeStringnameObject) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeObject = - MatchExpressionParser::parse(fromjson("{a: {$type: 'object'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'object'}}"), expCtx); ASSERT_OK(typeObject.getStatus()); TypeMatchExpression* tmeObject = static_cast<TypeMatchExpression*>(typeObject.getValue().get()); ASSERT_FALSE(tmeObject->typeSet().allNumbers); @@ -1152,9 +1174,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameObject) { } TEST(MatchExpressionParserLeafTest, TypeStringnameArray) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeArray = - MatchExpressionParser::parse(fromjson("{a: {$type: 'array'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'array'}}"), expCtx); ASSERT_OK(typeArray.getStatus()); TypeMatchExpression* tmeArray = static_cast<TypeMatchExpression*>(typeArray.getValue().get()); ASSERT_FALSE(tmeArray->typeSet().allNumbers); @@ -1165,9 +1187,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameArray) { } TEST(MatchExpressionParserLeafTest, TypeStringnameNumber) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumber = - MatchExpressionParser::parse(fromjson("{a: {$type: 'number'}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 'number'}}"), expCtx); ASSERT_OK(typeNumber.getStatus()); TypeMatchExpression* tmeNumber = static_cast<TypeMatchExpression*>(typeNumber.getValue().get()); ASSERT_TRUE(tmeNumber->typeSet().allNumbers); @@ -1179,9 +1201,9 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumber) { } TEST(MatchExpressionParserLeafTest, CanParseArrayOfTypes) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumber = - MatchExpressionParser::parse(fromjson("{a: {$type: ['number', 2, 'object']}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: ['number', 2, 'object']}}"), expCtx); ASSERT_OK(typeNumber.getStatus()); TypeMatchExpression* tme = static_cast<TypeMatchExpression*>(typeNumber.getValue().get()); ASSERT_TRUE(tme->typeSet().allNumbers); @@ -1191,30 +1213,30 @@ TEST(MatchExpressionParserLeafTest, CanParseArrayOfTypes) { } TEST(MatchExpressionParserLeafTest, EmptyArrayFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumber = - MatchExpressionParser::parse(fromjson("{a: {$type: []}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: []}}"), expCtx); ASSERT_NOT_OK(typeNumber.getStatus()); } TEST(MatchExpressionParserLeafTest, InvalidTypeCodeLessThanMinKeyFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumber = - MatchExpressionParser::parse(fromjson("{a: {$type: -20}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: -20}}"), expCtx); ASSERT_NOT_OK(typeNumber.getStatus()); } TEST(MatchExpressionParserLeafTest, InvalidTypeCodeGreaterThanMaxKeyFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumber = - MatchExpressionParser::parse(fromjson("{a: {$type: 400}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 400}}"), expCtx); ASSERT_NOT_OK(typeNumber.getStatus()); } TEST(MatchExpressionParserLeafTest, InvalidTypeCodeUnusedBetweenMinAndMaxFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression typeNumber = - MatchExpressionParser::parse(fromjson("{a: {$type: 62}}"), collator); + MatchExpressionParser::parse(fromjson("{a: {$type: 62}}"), expCtx); ASSERT_NOT_OK(typeNumber.getStatus()); } @@ -1226,8 +1248,8 @@ TEST(MatchExpressionParserLeafTest, ValidTypeCodesParseSuccessfully) { for (auto type : validTypes) { BSONObj predicate = BSON("a" << BSON("$type" << type)); - const CollatorInterface* collator = nullptr; - auto expression = MatchExpressionParser::parse(predicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expression = MatchExpressionParser::parse(predicate, expCtx); ASSERT_OK(expression.getStatus()); auto typeExpression = static_cast<TypeMatchExpression*>(expression.getValue().get()); ASSERT_FALSE(typeExpression->typeSet().allNumbers); @@ -1240,55 +1262,51 @@ TEST(MatchExpressionParserLeafTest, ValidTypeCodesParseSuccessfully) { TEST(MatchExpressionParserTest, BitTestMatchExpressionValidMask) { const double k2Power53 = scalbn(1, 32); - const CollatorInterface* collator = nullptr; - ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << 54)), collator).getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK( - MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<long long>::max())), collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53)), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << 54)), expCtx).getStatus()); + ASSERT_OK(MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<long long>::max())), expCtx) .getStatus()); - ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53 - 1)), collator) - .getStatus()); - - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << 54)), collator) + ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53)), expCtx) .getStatus()); ASSERT_OK( - MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<long long>::max())), collator) - .getStatus()); - ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << k2Power53)), collator) - .getStatus()); - ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << k2Power53 - 1)), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53 - 1)), expCtx) .getStatus()); ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << 54)), collator).getStatus()); + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << 54)), expCtx).getStatus()); ASSERT_OK( MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<long long>::max())), collator) + BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<long long>::max())), expCtx) .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53)), collator) + ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << k2Power53)), expCtx) .getStatus()); ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53 - 1)), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << k2Power53 - 1)), expCtx) .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << 54)), collator) + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << 54)), expCtx).getStatus()); + ASSERT_OK(MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<long long>::max())), expCtx) + .getStatus()); + ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53)), expCtx) .getStatus()); ASSERT_OK( - MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<long long>::max())), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53 - 1)), expCtx) .getStatus()); + + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << 54)), expCtx).getStatus()); ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53)), collator) + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<long long>::max())), expCtx) .getStatus()); + ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53)), expCtx) + .getStatus()); ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53 - 1)), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53 - 1)), expCtx) .getStatus()); } @@ -1299,392 +1317,391 @@ TEST(MatchExpressionParserTest, BitTestMatchExpressionValidArray) { ASSERT_EQ(BSONType::NumberLong, bsonArrayLongLong[2].type()); ASSERT_EQ(BSONType::NumberLong, bsonArrayLongLong[3].type()); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0))), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0))), expCtx) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0 << 1 << 2 << 3))), collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << bsonArrayLongLong)), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<int>::max()))), - collator) + BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0 << 1 << 2 << 3))), expCtx) .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << bsonArrayLongLong)), expCtx) + .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<int>::max()))), expCtx) + .getStatus()); ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0))), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0))), expCtx) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0 << 1 << 2 << 3))), collator) + BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0 << 1 << 2 << 3))), expCtx) .getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << bsonArrayLongLong)), - collator) + expCtx) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<int>::max()))), - collator) + expCtx) .getStatus()); ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0))), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0))), expCtx) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0 << 1 << 2 << 3))), collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << bsonArrayLongLong)), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<int>::max()))), - collator) + BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0 << 1 << 2 << 3))), expCtx) .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << bsonArrayLongLong)), expCtx) + .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<int>::max()))), expCtx) + .getStatus()); ASSERT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0))), collator) + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0))), expCtx) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0 << 1 << 2 << 3))), collator) + BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0 << 1 << 2 << 3))), expCtx) .getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << bsonArrayLongLong)), - collator) + expCtx) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<int>::max()))), - collator) + expCtx) .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionValidBinData) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK( MatchExpressionParser::parse( fromjson("{a: {$bitsAllSet: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - collator) + expCtx) .getStatus()); ASSERT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAllClear: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - collator) + expCtx) .getStatus()); ASSERT_OK( MatchExpressionParser::parse( fromjson("{a: {$bitsAnySet: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - collator) + expCtx) .getStatus()); ASSERT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAnyClear: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - collator) + expCtx) .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidMaskType) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: null}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: null}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: true}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: true}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: {}}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: {}}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ''}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ''}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: null}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: null}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: true}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: true}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: {}}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: {}}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ''}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ''}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( - fromjson("{a: {$bitsAllClear: ObjectId('000000000000000000000000')}}"), collator) + fromjson("{a: {$bitsAllClear: ObjectId('000000000000000000000000')}}"), expCtx) .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: null}}"), collator).getStatus()); - ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: true}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: null}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: {}}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: true}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ''}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: {}}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse( - fromjson("{a: {$bitsAnySet: ObjectId('000000000000000000000000')}}"), collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ''}}"), expCtx).getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse( + fromjson("{a: {$bitsAnySet: ObjectId('000000000000000000000000')}}"), expCtx) + .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: null}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: null}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: true}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: true}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: {}}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: {}}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ''}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ''}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( - fromjson("{a: {$bitsAnyClear: ObjectId('000000000000000000000000')}}"), collator) + fromjson("{a: {$bitsAnyClear: ObjectId('000000000000000000000000')}}"), expCtx) .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidMaskValue) { const double kLongLongMaxAsDouble = scalbn(1, std::numeric_limits<long long>::digits); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: NaN}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: NaN}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: -54}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: -54}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<double>::max())), collator) + BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<double>::max())), expCtx) .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << kLongLongMaxAsDouble)), collator) + BSON("a" << BSON("$bitsAllSet" << kLongLongMaxAsDouble)), expCtx) .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: 2.5}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: 2.5}}"), expCtx).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << Decimal128("2.5"))), collator) - .getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << Decimal128("2.5"))), expCtx) + .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: NaN}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: NaN}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: -54}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: -54}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<double>::max())), collator) + BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<double>::max())), expCtx) .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllClear" << kLongLongMaxAsDouble)), collator) + BSON("a" << BSON("$bitsAllClear" << kLongLongMaxAsDouble)), expCtx) .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: 2.5}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: 2.5}}"), expCtx).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllClear" << Decimal128("2.5"))), collator) + BSON("a" << BSON("$bitsAllClear" << Decimal128("2.5"))), expCtx) .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: NaN}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: NaN}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: -54}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: -54}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<double>::max())), collator) + BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<double>::max())), expCtx) .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << kLongLongMaxAsDouble)), collator) + BSON("a" << BSON("$bitsAnySet" << kLongLongMaxAsDouble)), expCtx) .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: 2.5}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: 2.5}}"), expCtx).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << Decimal128("2.5"))), collator) - .getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << Decimal128("2.5"))), expCtx) + .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: NaN}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: NaN}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: -54}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: -54}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<double>::max())), collator) + BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<double>::max())), expCtx) .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnyClear" << kLongLongMaxAsDouble)), collator) + BSON("a" << BSON("$bitsAnyClear" << kLongLongMaxAsDouble)), expCtx) .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: 2.5}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: 2.5}}"), expCtx).getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnyClear" << Decimal128("2.5"))), collator) + BSON("a" << BSON("$bitsAnyClear" << Decimal128("2.5"))), expCtx) .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidArray) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [null]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [null]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [true]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [true]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ['']}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ['']}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [{}]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [{}]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [[]]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [[]]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAllSet: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - collator) + expCtx) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [null]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [true]}}"), collator) - .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ['']}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [null]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [{}]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [true]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [[]]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ['']}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1]}}"), collator).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [{}]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [[]]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAllClear: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - collator) + expCtx) .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [null]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [null]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [true]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [true]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ['']}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ['']}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [{}]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [{}]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [[]]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [[]]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAnySet: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - collator) + expCtx) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [null]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [true]}}"), collator) - .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ['']}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [null]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [{}]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [true]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [[]]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ['']}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1]}}"), collator).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [{}]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [[]]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAnyClear: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - collator) + expCtx) .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidArrayValue) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-54]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-54]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [NaN]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [NaN]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), collator).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [1e100]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1e100]}}"), collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [1e100]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1e100]}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - collator) + expCtx) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - collator) + expCtx) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-54]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [NaN]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [1e100]}}"), collator) + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-54]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [NaN]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), expCtx).getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [1e100]}}"), expCtx) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1e100]}}"), collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1e100]}}"), expCtx) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - collator) + expCtx) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - collator) + expCtx) .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-54]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-54]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [NaN]}}"), collator).getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [NaN]}}"), expCtx).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), collator).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [1e100]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1e100]}}"), collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [1e100]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1e100]}}"), expCtx).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - collator) + expCtx) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - collator) + expCtx) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-54]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [NaN]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [1e100]}}"), collator) + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-54]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [NaN]}}"), expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), expCtx).getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [1e100]}}"), expCtx) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1e100]}}"), collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1e100]}}"), expCtx) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - collator) + expCtx) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - collator) + expCtx) .getStatus()); } } // namespace mongo diff --git a/src/mongo/db/matcher/expression_parser_test.cpp b/src/mongo/db/matcher/expression_parser_test.cpp index 9d9fe4d7856..ce520064261 100644 --- a/src/mongo/db/matcher/expression_parser_test.cpp +++ b/src/mongo/db/matcher/expression_parser_test.cpp @@ -44,8 +44,8 @@ namespace mongo { TEST(MatchExpressionParserTest, SimpleEQ1) { BSONObj query = BSON("x" << 2); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -54,8 +54,8 @@ TEST(MatchExpressionParserTest, SimpleEQ1) { TEST(MatchExpressionParserTest, Multiple1) { BSONObj query = BSON("x" << 5 << "y" << BSON("$gt" << 5 << "$lt" << 8)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5 << "y" << 7))); @@ -67,23 +67,23 @@ TEST(MatchExpressionParserTest, Multiple1) { TEST(AtomicMatchExpressionTest, AtomicOperator1) { BSONObj query = BSON("x" << 5 << "$atomic" << BSON("$gt" << 5 << "$lt" << 8)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); query = BSON("x" << 5 << "$isolated" << 1); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); query = BSON("x" << 5 << "y" << BSON("$isolated" << 1)); - result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserTest, MinDistanceWithoutNearFailsToParse) { BSONObj query = fromjson("{loc: {$minDistance: 10}}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_FALSE(result.isOK()); } @@ -227,25 +227,27 @@ TEST(StatusWithTest, Fib1) { TEST(MatchExpressionParserTest, AlwaysFalseFailsToParseNonOneArguments) { auto queryIntArgument = BSON(AlwaysFalseMatchExpression::kName << 0); - auto expr = MatchExpressionParser::parse(queryIntArgument, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(queryIntArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryStringArgument = BSON(AlwaysFalseMatchExpression::kName << ""); - expr = MatchExpressionParser::parse(queryStringArgument, nullptr); + expr = MatchExpressionParser::parse(queryStringArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryDoubleArgument = BSON(AlwaysFalseMatchExpression::kName << 1.1); - expr = MatchExpressionParser::parse(queryDoubleArgument, nullptr); + expr = MatchExpressionParser::parse(queryDoubleArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryFalseArgument = BSON(AlwaysFalseMatchExpression::kName << true); - expr = MatchExpressionParser::parse(queryFalseArgument, nullptr); + expr = MatchExpressionParser::parse(queryFalseArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserTest, AlwaysFalseParsesIntegerArgument) { auto query = BSON(AlwaysFalseMatchExpression::kName << 1); - auto expr = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{}"))); @@ -255,25 +257,27 @@ TEST(MatchExpressionParserTest, AlwaysFalseParsesIntegerArgument) { TEST(MatchExpressionParserTest, AlwaysTrueFailsToParseNonOneArguments) { auto queryIntArgument = BSON(AlwaysTrueMatchExpression::kName << 0); - auto expr = MatchExpressionParser::parse(queryIntArgument, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(queryIntArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryStringArgument = BSON(AlwaysTrueMatchExpression::kName << ""); - expr = MatchExpressionParser::parse(queryStringArgument, nullptr); + expr = MatchExpressionParser::parse(queryStringArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryDoubleArgument = BSON(AlwaysTrueMatchExpression::kName << 1.1); - expr = MatchExpressionParser::parse(queryDoubleArgument, nullptr); + expr = MatchExpressionParser::parse(queryDoubleArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryFalseArgument = BSON(AlwaysTrueMatchExpression::kName << true); - expr = MatchExpressionParser::parse(queryFalseArgument, nullptr); + expr = MatchExpressionParser::parse(queryFalseArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserTest, AlwaysTrueParsesIntegerArgument) { auto query = BSON(AlwaysTrueMatchExpression::kName << 1); - auto expr = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{}"))); @@ -283,34 +287,29 @@ TEST(MatchExpressionParserTest, AlwaysTrueParsesIntegerArgument) { TEST(MatchExpressionParserTest, TextFailsToParseWhenDisallowed) { auto query = fromjson("{$text: {$search: 'str'}}"); - const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } TEST(MatchExpressionParserTest, TextParsesSuccessfullyWhenAllowed) { auto query = fromjson("{$text: {$search: 'str'}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ASSERT_OK(MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kText) - .getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_OK( + MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kText) + .getStatus()); } TEST(MatchExpressionParserTest, WhereFailsToParseWhenDisallowed) { auto query = fromjson("{$where: 'this.a == this.b'}"); - const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } TEST(MatchExpressionParserTest, WhereParsesSuccessfullyWhenAllowed) { auto query = fromjson("{$where: 'this.a == this.b'}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kJavascript) @@ -319,16 +318,14 @@ TEST(MatchExpressionParserTest, WhereParsesSuccessfullyWhenAllowed) { TEST(MatchExpressionParserTest, NearSphereFailsToParseWhenDisallowed) { auto query = fromjson("{a: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}"); - const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } TEST(MatchExpressionParserTest, NearSphereParsesSuccessfullyWhenAllowed) { auto query = fromjson("{a: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kGeoNear) @@ -337,16 +334,14 @@ TEST(MatchExpressionParserTest, NearSphereParsesSuccessfullyWhenAllowed) { TEST(MatchExpressionParserTest, GeoNearFailsToParseWhenDisallowed) { auto query = fromjson("{a: {$geoNear: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}"); - const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } TEST(MatchExpressionParserTest, GeoNearParsesSuccessfullyWhenAllowed) { auto query = fromjson("{a: {$geoNear: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kGeoNear) @@ -355,16 +350,14 @@ TEST(MatchExpressionParserTest, GeoNearParsesSuccessfullyWhenAllowed) { TEST(MatchExpressionParserTest, NearFailsToParseWhenDisallowed) { auto query = fromjson("{a: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}"); - const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } TEST(MatchExpressionParserTest, NearParsesSuccessfullyWhenAllowed) { auto query = fromjson("{a: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(MatchExpressionParser::parse(query, - collator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kGeoNear) @@ -373,43 +366,34 @@ TEST(MatchExpressionParserTest, NearParsesSuccessfullyWhenAllowed) { TEST(MatchExpressionParserTest, ExprFailsToParseWhenDisallowed) { auto query = fromjson("{$expr: {$eq: ['$a', 5]}}"); - const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } TEST(MatchExpressionParserTest, ExprParsesSuccessfullyWhenAllowed) { auto query = fromjson("{$expr: {$eq: ['$a', 5]}}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ASSERT_OK(MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_OK( + MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kExpr) + .getStatus()); } TEST(MatchExpressionParserTest, ExprParsesSuccessfullyWithAdditionalTopLevelPredicates) { auto query = fromjson("{x: 1, $expr: {$eq: ['$a', 5]}, y: 1}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ASSERT_OK(MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_OK( + MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kExpr) + .getStatus()); } TEST(MatchExpressionParserTest, ExprFailsToParseWithinTopLevelOr) { auto query = fromjson("{$or: [{x: 1}, {$expr: {$eq: ['$a', 5]}}]}"); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ASSERT_NOT_OK(MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK( + MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kExpr) + .getStatus()); } } diff --git a/src/mongo/db/matcher/expression_parser_tree.cpp b/src/mongo/db/matcher/expression_parser_tree.cpp index 58365df9ff6..3491d0ff734 100644 --- a/src/mongo/db/matcher/expression_parser_tree.cpp +++ b/src/mongo/db/matcher/expression_parser_tree.cpp @@ -41,7 +41,6 @@ namespace mongo { Status MatchExpressionParser::_parseTreeList(const BSONObj& arr, ListOfMatchExpression* out, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel) { @@ -55,8 +54,7 @@ Status MatchExpressionParser::_parseTreeList(const BSONObj& arr, if (e.type() != Object) return Status(ErrorCodes::BadValue, "$or/$and/$nor entries need to be full objects"); - StatusWithMatchExpression sub = - _parse(e.Obj(), collator, expCtx, allowedFeatures, topLevel); + StatusWithMatchExpression sub = _parse(e.Obj(), expCtx, allowedFeatures, topLevel); if (!sub.isOK()) return sub.getStatus(); @@ -68,7 +66,6 @@ Status MatchExpressionParser::_parseTreeList(const BSONObj& arr, StatusWithMatchExpression MatchExpressionParser::_parseNot( const char* name, const BSONElement& e, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures, bool topLevel) { @@ -91,8 +88,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseNot( return StatusWithMatchExpression(ErrorCodes::BadValue, "$not cannot be empty"); std::unique_ptr<AndMatchExpression> theAnd = stdx::make_unique<AndMatchExpression>(); - Status s = - _parseSub(name, notObject, theAnd.get(), collator, expCtx, allowedFeatures, topLevel); + Status s = _parseSub(name, notObject, theAnd.get(), expCtx, allowedFeatures, topLevel); if (!s.isOK()) return StatusWithMatchExpression(s); diff --git a/src/mongo/db/matcher/expression_parser_tree_test.cpp b/src/mongo/db/matcher/expression_parser_tree_test.cpp index d223a672c95..5047eee8448 100644 --- a/src/mongo/db/matcher/expression_parser_tree_test.cpp +++ b/src/mongo/db/matcher/expression_parser_tree_test.cpp @@ -36,13 +36,14 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" +#include "mongo/db/pipeline/expression_context_for_test.h" namespace mongo { TEST(MatchExpressionParserTreeTest, OR1) { BSONObj query = BSON("$or" << BSON_ARRAY(BSON("x" << 1) << BSON("y" << 2))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -54,8 +55,8 @@ 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)); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query2, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query2, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -67,8 +68,8 @@ TEST(MatchExpressionParserTreeTest, OREmbedded) { TEST(MatchExpressionParserTreeTest, AND1) { BSONObj query = BSON("$and" << BSON_ARRAY(BSON("x" << 1) << BSON("y" << 2))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -81,8 +82,8 @@ TEST(MatchExpressionParserTreeTest, AND1) { TEST(MatchExpressionParserTreeTest, NOREmbedded) { BSONObj query = BSON("$nor" << BSON_ARRAY(BSON("x" << 1) << BSON("y" << 2))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -93,8 +94,8 @@ TEST(MatchExpressionParserTreeTest, NOREmbedded) { TEST(MatchExpressionParserTreeTest, NOT1) { BSONObj query = BSON("x" << BSON("$not" << BSON("$gt" << 5))); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -105,8 +106,8 @@ TEST(MatchExpressionParserLeafTest, NotRegex1) { BSONObjBuilder b; b.appendRegex("$not", "abc", "i"); BSONObj query = BSON("x" << b.obj()); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); 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 1971087ed30..ca6e1ec0567 100644 --- a/src/mongo/db/matcher/expression_serialization_test.cpp +++ b/src/mongo/db/matcher/expression_serialization_test.cpp @@ -46,8 +46,6 @@ using std::pair; using std::string; using std::unique_ptr; -constexpr CollatorInterface* kSimpleCollator = nullptr; - BSONObj serialize(MatchExpression* match) { BSONObjBuilder bob; match->serialize(&bob); @@ -57,12 +55,10 @@ BSONObj serialize(MatchExpression* match) { TEST(SerializeBasic, AndExpressionWithOneChildSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$and: [{x: 0}]}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -79,12 +75,10 @@ TEST(SerializeBasic, AndExpressionWithOneChildSerializesCorrectly) { TEST(SerializeBasic, AndExpressionWithTwoChildrenSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$and: [{x: 1}, {x: 2}]}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -101,12 +95,10 @@ TEST(SerializeBasic, AndExpressionWithTwoChildrenSerializesCorrectly) { TEST(SerializeBasic, AndExpressionWithTwoIdenticalChildrenSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$and: [{x: 1}, {x: 1}]}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -123,12 +115,10 @@ TEST(SerializeBasic, AndExpressionWithTwoIdenticalChildrenSerializesCorrectly) { TEST(SerializeBasic, ExpressionOr) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$or: [{x: 'A'}, {x: 'B'}]}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -149,7 +139,6 @@ TEST(SerializeBasic, ExpressionOrWithNoChildrenSerializesCorrectly) { // parser, since the parser does not permit a $or with no children. OrMatchExpression original; Matcher reserialized(serialize(&original), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -159,12 +148,10 @@ TEST(SerializeBasic, ExpressionOrWithNoChildrenSerializesCorrectly) { TEST(SerializeBasic, ExpressionElemMatchObjectSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$elemMatch: {a: {$gt: 0}, b: {$gt: 0}}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -182,12 +169,10 @@ TEST(SerializeBasic, ExpressionElemMatchObjectSerializesCorrectly) { TEST(SerializeBasic, ExpressionElemMatchObjectWithEmptyStringSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{'': {$elemMatch: {a: {$gt: 0}, b: {$gt: 0}}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -205,12 +190,10 @@ TEST(SerializeBasic, ExpressionElemMatchObjectWithEmptyStringSerializesCorrectly TEST(SerializeBasic, ExpressionElemMatchValueSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -233,13 +216,9 @@ TEST(SerializeBasic, ExpressionElemMatchValueWithRegexSerializesCorrectly) { << "abc" << "$options" << "i"))); - Matcher original(match, - kSimpleCollator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher original( + match, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -259,12 +238,10 @@ TEST(SerializeBasic, ExpressionElemMatchValueWithRegexSerializesCorrectly) { TEST(SerializeBasic, ExpressionElemMatchValueWithEmptyStringSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -284,12 +261,10 @@ TEST(SerializeBasic, ExpressionElemMatchValueWithEmptyStringSerializesCorrectly) TEST(SerializeBasic, ExpressionSizeSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$size: 2}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -306,12 +281,10 @@ TEST(SerializeBasic, ExpressionSizeSerializesCorrectly) { TEST(SerializeBasic, ExpressionAllSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$all: [1, 2]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -328,12 +301,10 @@ TEST(SerializeBasic, ExpressionAllSerializesCorrectly) { TEST(SerializeBasic, ExpressionAllWithEmptyArraySerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$all: []}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -347,12 +318,10 @@ TEST(SerializeBasic, ExpressionAllWithEmptyArraySerializesCorrectly) { TEST(SerializeBasic, ExpressionAllWithRegex) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$all: [/a.b.c/, /.d.e./]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -374,12 +343,10 @@ TEST(SerializeBasic, ExpressionAllWithRegex) { TEST(SerializeBasic, ExpressionEqSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$eq: {a: 1}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -399,12 +366,10 @@ TEST(SerializeBasic, ExpressionEqSerializesCorrectly) { TEST(SerializeBasic, ExpressionNeSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$ne: {a: 1}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -422,12 +387,10 @@ TEST(SerializeBasic, ExpressionNeWithRegexObjectSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(BSON("x" << BSON("$ne" << BSON("$regex" << "abc"))), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -446,12 +409,10 @@ TEST(SerializeBasic, ExpressionNeWithRegexObjectSerializesCorrectly) { TEST(SerializeBasic, ExpressionLtSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$lt: 3}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -468,12 +429,10 @@ TEST(SerializeBasic, ExpressionLtSerializesCorrectly) { TEST(SerializeBasic, ExpressionGtSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$gt: 3}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -490,12 +449,10 @@ TEST(SerializeBasic, ExpressionGtSerializesCorrectly) { TEST(SerializeBasic, ExpressionGteSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$gte: 3}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -512,12 +469,10 @@ TEST(SerializeBasic, ExpressionGteSerializesCorrectly) { TEST(SerializeBasic, ExpressionLteSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$lte: 3}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -534,12 +489,10 @@ TEST(SerializeBasic, ExpressionLteSerializesCorrectly) { TEST(SerializeBasic, ExpressionRegexWithObjSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$regex: 'a.b'}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -558,12 +511,10 @@ TEST(SerializeBasic, ExpressionRegexWithObjSerializesCorrectly) { TEST(SerializeBasic, ExpressionRegexWithValueAndOptionsSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: /a.b/i}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -584,12 +535,10 @@ TEST(SerializeBasic, ExpressionRegexWithValueAndOptionsSerializesCorrectly) { TEST(SerializeBasic, ExpressionRegexWithValueSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: /a.b/}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -608,12 +557,10 @@ TEST(SerializeBasic, ExpressionRegexWithValueSerializesCorrectly) { TEST(SerializeBasic, ExpressionRegexWithEqObjSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$eq: {$regex: 'a.b'}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -633,12 +580,10 @@ TEST(SerializeBasic, ExpressionRegexWithEqObjSerializesCorrectly) { TEST(SerializeBasic, ExpressionModSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$mod: [2, 1]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -655,12 +600,10 @@ TEST(SerializeBasic, ExpressionModSerializesCorrectly) { TEST(SerializeBasic, ExpressionExistsTrueSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$exists: true}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -677,12 +620,10 @@ TEST(SerializeBasic, ExpressionExistsTrueSerializesCorrectly) { TEST(SerializeBasic, ExpressionExistsFalseSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$exists: false}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -699,12 +640,10 @@ TEST(SerializeBasic, ExpressionExistsFalseSerializesCorrectly) { TEST(SerializeBasic, ExpressionInSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$in: [1, 2, 3]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -724,12 +663,10 @@ TEST(SerializeBasic, ExpressionInSerializesCorrectly) { TEST(SerializeBasic, ExpressionInWithEmptyArraySerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$in: []}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -743,12 +680,10 @@ TEST(SerializeBasic, ExpressionInWithEmptyArraySerializesCorrectly) { TEST(SerializeBasic, ExpressionInWithRegexSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$in: [/\\d+/, /\\w+/]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -768,12 +703,10 @@ TEST(SerializeBasic, ExpressionInWithRegexSerializesCorrectly) { TEST(SerializeBasic, ExpressionNinSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$nin: [1, 2, 3]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -793,12 +726,10 @@ TEST(SerializeBasic, ExpressionNinSerializesCorrectly) { TEST(SerializeBasic, ExpressionNinWithRegexValueSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$nin: [/abc/, /def/, /xyz/]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -818,12 +749,10 @@ TEST(SerializeBasic, ExpressionNinWithRegexValueSerializesCorrectly) { TEST(SerializeBasic, ExpressionBitsAllSetSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$bitsAllSet: [1, 3]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -840,12 +769,10 @@ TEST(SerializeBasic, ExpressionBitsAllSetSerializesCorrectly) { TEST(SerializeBasic, ExpressionBitsAllClearSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$bitsAllClear: [1, 3]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -862,12 +789,10 @@ TEST(SerializeBasic, ExpressionBitsAllClearSerializesCorrectly) { TEST(SerializeBasic, ExpressionBitsAnySetSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$bitsAnySet: [1, 3]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -884,12 +809,10 @@ TEST(SerializeBasic, ExpressionBitsAnySetSerializesCorrectly) { TEST(SerializeBasic, ExpressionBitsAnyClearSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$bitsAnyClear: [1, 3]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -909,12 +832,10 @@ TEST(SerializeBasic, ExpressionBitsAnyClearSerializesCorrectly) { TEST(SerializeBasic, ExpressionNotSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$not: {$eq: 3}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -931,12 +852,10 @@ TEST(SerializeBasic, ExpressionNotSerializesCorrectly) { TEST(SerializeBasic, ExpressionNotWithMultipleChildrenSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$not: {$lt: 1, $gt: 3}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -954,12 +873,10 @@ TEST(SerializeBasic, ExpressionNotWithMultipleChildrenSerializesCorrectly) { TEST(SerializeBasic, ExpressionNotWithBitTestSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$not: {$bitsAnySet: [1, 3]}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -977,12 +894,10 @@ TEST(SerializeBasic, ExpressionNotWithBitTestSerializesCorrectly) { TEST(SerializeBasic, ExpressionNotWithRegexObjSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$not: {$regex: 'a.b'}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1001,12 +916,10 @@ TEST(SerializeBasic, ExpressionNotWithRegexObjSerializesCorrectly) { TEST(SerializeBasic, ExpressionNotWithRegexValueSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$not: /a.b/}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1025,12 +938,10 @@ TEST(SerializeBasic, ExpressionNotWithRegexValueSerializesCorrectly) { TEST(SerializeBasic, ExpressionNotWithRegexValueAndOptionsSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$not: /a.b/i}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1053,12 +964,10 @@ TEST(SerializeBasic, ExpressionNotWithGeoSerializesCorrectly) { Matcher original(fromjson("{x: {$not: {$geoIntersects: {$geometry: {type: 'Polygon', " "coordinates: [[[0,0], [5,0], " "[5, 5], [0, 5], [0, 0]]]}}}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1086,12 +995,10 @@ TEST(SerializeBasic, ExpressionNotWithGeoSerializesCorrectly) { TEST(SerializeBasic, ExpressionNorSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$nor: [{x: 3}, {x: {$lt: 1}}]}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1111,12 +1018,10 @@ TEST(SerializeBasic, ExpressionNorSerializesCorrectly) { TEST(SerializeBasic, ExpressionTypeSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$type: 2}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1133,12 +1038,10 @@ TEST(SerializeBasic, ExpressionTypeSerializesCorrectly) { TEST(SerializeBasic, ExpressionTypeWithNumberSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$type: 'number'}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1153,9 +1056,9 @@ TEST(SerializeBasic, ExpressionTypeWithNumberSerializesCorrectly) { } TEST(SerializeBasic, ExpressionTypeWithMultipleTypesSerializesCorrectly) { - Matcher original(fromjson("{x: {$type: ['double', 'string', 'object', 'number']}}"), - kSimpleCollator); - Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher original(fromjson("{x: {$type: ['double', 'string', 'object', 'number']}}"), expCtx); + Matcher reserialized(serialize(original.getMatchExpression()), expCtx); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$type: ['number', 1, 2, 3]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -1170,8 +1073,9 @@ TEST(SerializeBasic, ExpressionTypeWithMultipleTypesSerializesCorrectly) { } TEST(SerializeInternalSchema, InternalSchemaTypeExpressionSerializesCorrectly) { - Matcher original(fromjson("{x: {$_internalSchemaType: 2}}"), kSimpleCollator); - Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher original(fromjson("{x: {$_internalSchemaType: 2}}"), expCtx); + Matcher reserialized(serialize(original.getMatchExpression()), expCtx); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaType: [2]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -1183,8 +1087,9 @@ TEST(SerializeInternalSchema, InternalSchemaTypeExpressionSerializesCorrectly) { } TEST(SerializeInternalSchema, InternalSchemaTypeExpressionWithNumberSerializesCorrectly) { - Matcher original(fromjson("{x: {$_internalSchemaType: 'number'}}"), kSimpleCollator); - Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher original(fromjson("{x: {$_internalSchemaType: 'number'}}"), expCtx); + Matcher reserialized(serialize(original.getMatchExpression()), expCtx); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaType: ['number']}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -1197,10 +1102,10 @@ TEST(SerializeInternalSchema, InternalSchemaTypeExpressionWithNumberSerializesCo } TEST(SerializeInternalSchema, InternalSchemaTypeWithMultipleTypesSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original( - fromjson("{x: {$_internalSchemaType: ['double', 'string', 'object', 'number']}}"), - kSimpleCollator); - Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); + fromjson("{x: {$_internalSchemaType: ['double', 'string', 'object', 'number']}}"), expCtx); + Matcher reserialized(serialize(original.getMatchExpression()), expCtx); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaType: ['number', 1, 2, 3]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -1218,12 +1123,10 @@ TEST(SerializeInternalSchema, InternalSchemaTypeWithMultipleTypesSerializesCorre TEST(SerializeBasic, ExpressionEmptySerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1237,12 +1140,10 @@ TEST(SerializeBasic, ExpressionEmptySerializesCorrectly) { TEST(SerializeBasic, ExpressionWhereSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$where: 'this.a == this.b'}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1255,12 +1156,10 @@ TEST(SerializeBasic, ExpressionWhereSerializesCorrectly) { TEST(SerializeBasic, ExpressionWhereWithScopeSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(BSON("$where" << BSONCodeWScope("this.a == this.b", BSON("x" << 3))), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1272,12 +1171,10 @@ TEST(SerializeBasic, ExpressionWhereWithScopeSerializesCorrectly) { TEST(SerializeBasic, ExpressionExprSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$expr: {$eq: ['$a', 2]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1295,12 +1192,10 @@ TEST(SerializeBasic, ExpressionExprSerializesCorrectly) { TEST(SerializeBasic, ExpressionCommentSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$comment: 'Hello'}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1320,12 +1215,10 @@ TEST(SerializeBasic, ExpressionGeoWithinSerializesCorrectly) { fromjson( "{x: {$geoWithin: {$geometry: " "{type: 'Polygon', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]]}}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1348,12 +1241,10 @@ TEST(SerializeBasic, ExpressionGeoIntersectsSerializesCorrectly) { fromjson( "{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [5,0], [5, " "5], [0, 5], [0, 0]]]}}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1382,12 +1273,10 @@ TEST(SerializeBasic, ExpressionNearSerializesCorrectly) { Matcher original( fromjson("{x: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " "$minDistance: 1}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1404,12 +1293,10 @@ TEST(SerializeBasic, ExpressionNearSphereSerializesCorrectly) { fromjson( "{x: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " "$minDistance: 1}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1423,12 +1310,10 @@ TEST(SerializeBasic, ExpressionNearSphereSerializesCorrectly) { TEST(SerializeBasic, ExpressionTextSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$text: {$search: 'a', $language: 'en', $caseSensitive: true}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1441,12 +1326,10 @@ TEST(SerializeBasic, ExpressionTextSerializesCorrectly) { TEST(SerializeBasic, ExpressionTextWithDefaultLanguageSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$text: {$search: 'a', $caseSensitive: false}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1459,12 +1342,10 @@ TEST(SerializeBasic, ExpressionTextWithDefaultLanguageSerializesCorrectly) { TEST(SerializeBasic, ExpressionAlwaysTrueSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(BSON(AlwaysTrueMatchExpression::kName << 1), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1475,12 +1356,10 @@ TEST(SerializeBasic, ExpressionAlwaysTrueSerializesCorrectly) { TEST(SerializeBasic, ExpressionAlwaysFalseSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(BSON(AlwaysFalseMatchExpression::kName << 1), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1491,12 +1370,10 @@ TEST(SerializeBasic, ExpressionAlwaysFalseSerializesCorrectly) { TEST(SerializeInternalSchema, ExpressionInternalSchemaAllElemMatchFromIndexSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaAllElemMatchFromIndex: [2, {y: 1}]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1507,12 +1384,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaAllElemMatchFromIndexSeria TEST(SerializeInternalSchema, ExpressionInternalSchemaMinItemsSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaMinItems: 1}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1523,12 +1398,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaMinItemsSerializesCorrectl TEST(SerializeInternalSchema, ExpressionInternalSchemaMaxItemsSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaMaxItems: 1}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1539,12 +1412,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaMaxItemsSerializesCorrectl TEST(SerializeInternalSchema, ExpressionInternalSchemaUniqueItemsSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaUniqueItems: true}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1556,12 +1427,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaUniqueItemsSerializesCorre TEST(SerializeInternalSchema, ExpressionInternalSchemaObjectMatchSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaObjectMatch: {y: 1}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1572,12 +1441,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaObjectMatchSerializesCorre TEST(SerializeInternalSchema, ExpressionInternalSchemaMinLengthSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaMinLength: 1}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1588,12 +1455,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaMinLengthSerializesCorrect TEST(SerializeInternalSchema, ExpressionInternalSchemaMaxLengthSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaMaxLength: 1}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1604,12 +1469,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaMaxLengthSerializesCorrect TEST(SerializeInternalSchema, ExpressionInternalSchemaCondSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$_internalSchemaCond: [{a: 1}, {b: 2}, {c: 3}]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1623,12 +1486,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaCondSerializesCorrectly) { TEST(SerializeInternalSchema, ExpressionInternalSchemaMinPropertiesSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$_internalSchemaMinProperties: 1}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1639,12 +1500,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaMinPropertiesSerializesCor TEST(SerializeInternalSchema, ExpressionInternalSchemaMaxPropertiesSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$_internalSchemaMaxProperties: 1}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1656,12 +1515,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaFmodSerializesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original( fromjson("{a: {$_internalSchemaFmod: [NumberDecimal('2.3'), NumberDecimal('1.1')]}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1680,12 +1537,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaMatchArrayIndexSerializesC boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{a: {$_internalSchemaMatchArrayIndex:" "{index: 2, namePlaceholder: 'i', expression: {i: {$lt: 3}}}}}"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1703,12 +1558,10 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaAllowedPropertiesSerialize namePlaceholder: 'i', patternProperties: [{regex: /b/, expression: {i: {$type: 'number'}}}] }})"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1730,12 +1583,10 @@ TEST(SerializeInternalSchema, namePlaceholder: 'i', patternProperties: [] }})"), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - kSimpleCollator, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); @@ -1749,16 +1600,18 @@ TEST(SerializeInternalSchema, } TEST(SerializeInternalSchema, ExpressionInternalSchemaEqSerializesCorrectly) { - Matcher original(fromjson("{x: {$_internalSchemaEq: {y: 1}}}"), kSimpleCollator); - Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher original(fromjson("{x: {$_internalSchemaEq: {y: 1}}}"), expCtx); + Matcher reserialized(serialize(original.getMatchExpression()), expCtx); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaEq: {y: 1}}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaRootDocEqSerializesCorrectly) { - Matcher original(fromjson("{$_internalSchemaRootDocEq: {y: 1}}"), kSimpleCollator); - Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher original(fromjson("{$_internalSchemaRootDocEq: {y: 1}}"), expCtx); + Matcher reserialized(serialize(original.getMatchExpression()), expCtx); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$_internalSchemaRootDocEq: {y: 1}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); diff --git a/src/mongo/db/matcher/expression_with_placeholder.cpp b/src/mongo/db/matcher/expression_with_placeholder.cpp index 35f8cc1b2bb..cd68587b057 100644 --- a/src/mongo/db/matcher/expression_with_placeholder.cpp +++ b/src/mongo/db/matcher/expression_with_placeholder.cpp @@ -89,8 +89,8 @@ const std::regex ExpressionWithPlaceholder::placeholderRegex("^[a-z][a-zA-Z0-9]* // static StatusWith<std::unique_ptr<ExpressionWithPlaceholder>> ExpressionWithPlaceholder::parse( - BSONObj rawFilter, const CollatorInterface* collator) { - StatusWithMatchExpression statusWithFilter = MatchExpressionParser::parse(rawFilter, collator); + BSONObj rawFilter, const boost::intrusive_ptr<ExpressionContext>& expCtx) { + StatusWithMatchExpression statusWithFilter = MatchExpressionParser::parse(rawFilter, expCtx); if (!statusWithFilter.isOK()) { return statusWithFilter.getStatus(); diff --git a/src/mongo/db/matcher/expression_with_placeholder.h b/src/mongo/db/matcher/expression_with_placeholder.h index 27047def6d2..a60b55c0bc2 100644 --- a/src/mongo/db/matcher/expression_with_placeholder.h +++ b/src/mongo/db/matcher/expression_with_placeholder.h @@ -51,7 +51,7 @@ public: * ownership of 'rawFilter'. */ static StatusWith<std::unique_ptr<ExpressionWithPlaceholder>> parse( - BSONObj rawFilter, const CollatorInterface* collator); + BSONObj rawFilter, const boost::intrusive_ptr<ExpressionContext>& expCtx); /** * Construct a new ExpressionWithPlaceholder. 'filter' must point to a valid MatchExpression. diff --git a/src/mongo/db/matcher/expression_with_placeholder_test.cpp b/src/mongo/db/matcher/expression_with_placeholder_test.cpp index 1d717bb1f19..7bd19b12d00 100644 --- a/src/mongo/db/matcher/expression_with_placeholder_test.cpp +++ b/src/mongo/db/matcher/expression_with_placeholder_test.cpp @@ -31,6 +31,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_always_boolean.h" #include "mongo/db/matcher/expression_with_placeholder.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/unittest.h" @@ -41,9 +42,9 @@ namespace { using unittest::assertGet; TEST(ExpressionWithPlaceholderTest, ParseBasic) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{i: 0}"); - auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(filter->getPlaceholder()); ASSERT_EQ(*filter->getPlaceholder(), "i"); ASSERT_TRUE(filter->getFilter()->matchesBSON(fromjson("{i: 0}"))); @@ -51,9 +52,9 @@ TEST(ExpressionWithPlaceholderTest, ParseBasic) { } TEST(ExpressionWithPlaceholderTest, ParseDottedField) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{'i.a': 0, 'i.b': 1}"); - auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(filter->getPlaceholder()); ASSERT_EQ(*filter->getPlaceholder(), "i"); ASSERT_TRUE(filter->getFilter()->matchesBSON(fromjson("{i: {a: 0, b: 1}}"))); @@ -61,9 +62,9 @@ TEST(ExpressionWithPlaceholderTest, ParseDottedField) { } TEST(ExpressionWithPlaceholderTest, ParseLogicalQuery) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{$and: [{i: {$gte: 0}}, {i: {$lte: 0}}]}"); - auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(filter->getPlaceholder()); ASSERT_EQ(*filter->getPlaceholder(), "i"); ASSERT_TRUE(filter->getFilter()->matchesBSON(fromjson("{i: 0}"))); @@ -71,9 +72,9 @@ TEST(ExpressionWithPlaceholderTest, ParseLogicalQuery) { } TEST(ExpressionWithPlaceholderTest, ParseElemMatch) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{i: {$elemMatch: {a: 0}}}"); - auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(filter->getPlaceholder()); ASSERT_EQ(*filter->getPlaceholder(), "i"); ASSERT_TRUE(filter->getFilter()->matchesBSON(fromjson("{i: [{a: 0}]}"))); @@ -82,8 +83,10 @@ TEST(ExpressionWithPlaceholderTest, ParseElemMatch) { TEST(ExpressionWithPlaceholderTest, ParseCollation) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); auto rawFilter = fromjson("{i: 'abc'}"); - auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, &collator)); + auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(filter->getPlaceholder()); ASSERT_EQ(*filter->getPlaceholder(), "i"); ASSERT_TRUE(filter->getFilter()->matchesBSON(fromjson("{i: 'cba'}"))); @@ -91,9 +94,9 @@ TEST(ExpressionWithPlaceholderTest, ParseCollation) { } TEST(ExpressionWithPlaceholderTest, ParseIdContainsNumbersAndCapitals) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{iA3: 0}"); - auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto filter = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(filter->getPlaceholder()); ASSERT_EQ(*filter->getPlaceholder(), "iA3"); ASSERT_TRUE(filter->getFilter()->matchesBSON(fromjson("{'iA3': 0}"))); @@ -101,250 +104,250 @@ TEST(ExpressionWithPlaceholderTest, ParseIdContainsNumbersAndCapitals) { } TEST(ExpressionWithPlaceholderTest, BadMatchExpressionFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{$and: 0}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, EmptyMatchExpressionParsesSuccessfully) { - constexpr CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{}"); - auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT_FALSE(result->getPlaceholder()); } TEST(ExpressionWithPlaceholderTest, NestedEmptyMatchExpressionParsesSuccessfully) { - constexpr CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{$or: [{$and: [{}]}]}"); - auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT_FALSE(result->getPlaceholder()); } TEST(ExpressionWithPlaceholderTest, NestedMatchExpressionParsesSuccessfullyWhenSomeClausesHaveNoFieldName) { - constexpr CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{$or: [{$and: [{}]}, {i: 0}, {i: 1}, {$and: [{}]}]}"); - auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(result->getPlaceholder()); ASSERT_EQ(*result->getPlaceholder(), "i"_sd); } TEST(ExpressionWithPlaceholderTest, SuccessfullyParsesExpressionsWithTypeOther) { - constexpr CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{a: {$_internalSchemaObjectMatch: {$_internalSchemaMinProperties: 5}}}"); - auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(result->getPlaceholder()); ASSERT_EQ(*result->getPlaceholder(), "a"_sd); rawFilter = fromjson("{a: {$_internalSchemaType: 'string'}}"); - result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT(result->getPlaceholder()); ASSERT_EQ(*result->getPlaceholder(), "a"_sd); rawFilter = fromjson("{$_internalSchemaMinProperties: 1}}"); - result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT_FALSE(result->getPlaceholder()); rawFilter = fromjson("{$_internalSchemaCond: [{a: {$exists: true}}, {b: 1}, {c: 1}]}"); - result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT_FALSE(result->getPlaceholder()); } TEST(ExpressionWithPlaceholderTest, SuccessfullyParsesAlwaysTrue) { - constexpr CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = BSON(AlwaysTrueMatchExpression::kName << 1); - auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT_FALSE(result->getPlaceholder()); } TEST(ExpressionWithPlaceholderTest, SuccessfullyParsesAlwaysFalse) { - constexpr CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = BSON(AlwaysFalseMatchExpression::kName << 1); - auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator)); + auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, expCtx)); ASSERT_FALSE(result->getPlaceholder()); } TEST(ExpressionWithPlaceholderTest, EmptyFieldNameFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{'': 0}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, EmptyElemMatchFieldNameFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{'': {$elemMatch: {a: 0}}}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, EmptyTopLevelFieldNameFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{'.i': 0}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, MultipleTopLevelFieldsFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{$and: [{i: 0}, {j: 0}]}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, SpecialCharactersInFieldNameFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{'i&': 0}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, FieldNameStartingWithNumberFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{'3i': 0}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, FieldNameStartingWithCapitalFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{'Ai': 0}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, TextSearchExpressionFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{$text: {$search: 'search terms'}}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, WhereExpressionFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{$where: 'sleep(100)'}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, GeoNearExpressionFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{i: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, ExprExpressionFailsToParse) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter = fromjson("{$expr: {$eq: ['$i', 5]}}"); - auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); } TEST(ExpressionWithPlaceholderTest, EquivalentIfPlaceholderAndExpressionMatch) { - constexpr auto collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter1 = fromjson("{i: 5}}"); - auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator); + auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, expCtx); ASSERT_OK(expressionWithPlaceholder1.getStatus()); auto rawFilter2 = fromjson("{i: 5}"); - auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator); + auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, expCtx); ASSERT_OK(expressionWithPlaceholder2.getStatus()); ASSERT_TRUE(expressionWithPlaceholder1.getValue()->equivalent( expressionWithPlaceholder2.getValue().get())); } TEST(ExpressionWithPlaceholderTest, EmptyMatchExpressionsAreEquivalent) { - constexpr auto collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter1 = fromjson("{}"); - auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator); + auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, expCtx); ASSERT_OK(expressionWithPlaceholder1.getStatus()); auto rawFilter2 = fromjson("{}"); - auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator); + auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, expCtx); ASSERT_OK(expressionWithPlaceholder2.getStatus()); ASSERT(expressionWithPlaceholder1.getValue()->equivalent( expressionWithPlaceholder2.getValue().get())); } TEST(ExpressionWithPlaceholderTest, NestedEmptyMatchExpressionsAreEquivalent) { - constexpr auto collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter1 = fromjson("{$or: [{$and: [{}]}]}"); - auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator); + auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, expCtx); ASSERT_OK(expressionWithPlaceholder1.getStatus()); auto rawFilter2 = fromjson("{$or: [{$and: [{}]}]}"); - auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator); + auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, expCtx); ASSERT_OK(expressionWithPlaceholder2.getStatus()); ASSERT(expressionWithPlaceholder1.getValue()->equivalent( expressionWithPlaceholder2.getValue().get())); } TEST(ExpressionWithPlaceholderTest, SameObjectMatchesAreEquivalent) { - constexpr auto collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter1 = fromjson("{a: {$_internalSchemaObjectMatch: {$_internalSchemaMaxProperties: 2}}}"); - auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator); + auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, expCtx); ASSERT_OK(expressionWithPlaceholder1.getStatus()); auto rawFilter2 = fromjson("{a: {$_internalSchemaObjectMatch: {$_internalSchemaMaxProperties: 2}}}"); - auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator); + auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, expCtx); ASSERT_OK(expressionWithPlaceholder2.getStatus()); ASSERT(expressionWithPlaceholder1.getValue()->equivalent( expressionWithPlaceholder2.getValue().get())); } TEST(ExpressionWithPlaceholderTest, AlwaysTruesAreEquivalent) { - constexpr auto collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter1 = BSON(AlwaysTrueMatchExpression::kName << 1); - auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator); + auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, expCtx); ASSERT_OK(expressionWithPlaceholder1.getStatus()); auto rawFilter2 = BSON(AlwaysTrueMatchExpression::kName << 1); - auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator); + auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, expCtx); ASSERT_OK(expressionWithPlaceholder2.getStatus()); ASSERT(expressionWithPlaceholder1.getValue()->equivalent( expressionWithPlaceholder2.getValue().get())); } TEST(ExpressionWithPlaceholderTest, NotEquivalentIfPlaceholderDoesNotMatch) { - constexpr auto collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter1 = fromjson("{i: {$type: 'array'}}"); - auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator); + auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, expCtx); ASSERT_OK(expressionWithPlaceholder1.getStatus()); auto rawFilter2 = fromjson("{j: {$type: 'array'}}"); - auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator); + auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, expCtx); ASSERT_OK(expressionWithPlaceholder2.getStatus()); ASSERT_FALSE(expressionWithPlaceholder1.getValue()->equivalent( expressionWithPlaceholder2.getValue().get())); } TEST(ExpressionWithPlaceholder, NotEquivalentIfOnePlaceholderIsEmpty) { - constexpr auto collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter1 = fromjson("{}"); - auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator); + auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, expCtx); ASSERT_OK(expressionWithPlaceholder1.getStatus()); auto rawFilter2 = fromjson("{i: 5}"); - auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator); + auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, expCtx); ASSERT_OK(expressionWithPlaceholder2.getStatus()); ASSERT_FALSE(expressionWithPlaceholder1.getValue()->equivalent( expressionWithPlaceholder2.getValue().get())); } TEST(ExpressionWithPlaceholderTest, NotEquivalentIfExpressionDoesNotMatch) { - constexpr auto collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto rawFilter1 = fromjson("{i: {$lte: 5}}"); - auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator); + auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, expCtx); ASSERT_OK(expressionWithPlaceholder1.getStatus()); auto rawFilter2 = fromjson("{i: {$gte: 5}}"); - auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator); + auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, expCtx); ASSERT_OK(expressionWithPlaceholder2.getStatus()); ASSERT_FALSE(expressionWithPlaceholder1.getValue()->equivalent( expressionWithPlaceholder2.getValue().get())); diff --git a/src/mongo/db/matcher/matcher.cpp b/src/mongo/db/matcher/matcher.cpp index 5648a4f15d5..bea280d4d0b 100644 --- a/src/mongo/db/matcher/matcher.cpp +++ b/src/mongo/db/matcher/matcher.cpp @@ -42,13 +42,12 @@ namespace mongo { Matcher::Matcher(const BSONObj& pattern, - const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, const ExtensionsCallback& extensionsCallback, const MatchExpressionParser::AllowedFeatureSet allowedFeatures) : _pattern(pattern) { - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - pattern, collator, expCtx, extensionsCallback, allowedFeatures); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(pattern, expCtx, extensionsCallback, allowedFeatures); 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 4d1c8783747..1e4fbd999c0 100644 --- a/src/mongo/db/matcher/matcher.h +++ b/src/mongo/db/matcher/matcher.h @@ -55,8 +55,7 @@ public: * 'collator' must outlive the returned Matcher and any MatchExpression cloned from it. */ Matcher(const BSONObj& pattern, - const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr, + const boost::intrusive_ptr<ExpressionContext>& expCtx, const ExtensionsCallback& extensionsCallback = ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatureSet allowedFeatures = MatchExpressionParser::kDefaultSpecialFeatures); diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index_test.cpp index f21d80676f8..1d4fecbf366 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index_test.cpp @@ -32,24 +32,25 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace { -constexpr CollatorInterface* kSimpleCollator = nullptr; - TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchesEmptyQuery) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {}]}}"); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(BSON("a" << BSON_ARRAY(1 << 2 << 3 << 4)))); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchesValidQueries) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(BSON("a" << BSON_ARRAY(1 << 2 << 3 << 4)))); @@ -61,21 +62,24 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchesValidQueries) { TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, RejectsNonArrayElements) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(BSON("a" << BSON("a" << 1)))); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchesArraysWithLessElementsThanIndex) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(BSON("a" << BSON_ARRAY(1)))); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, NestedArraysMatchSubexpression) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE( expr.getValue()->matchesBSON(BSON("a" << BSON_ARRAY(1 << 2 << BSON_ARRAY(3 << 4) << 4)))); @@ -87,7 +91,8 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, NestedArraysMatchSubexp TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchedQueriesWithDottedPaths) { auto query = fromjson("{'a.b': {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE( expr.getValue()->matchesBSON(BSON("a" << BSON("b" << BSON_ARRAY(1 << 2 << 3 << 4))))); @@ -95,7 +100,8 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchedQueriesWithDotte TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, HasSingleChild) { auto query = fromjson("{'a.b': {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); ASSERT_EQ(objMatch.getValue()->numChildren(), 1U); @@ -106,7 +112,8 @@ DEATH_TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, GetChildFailsIndexGreaterThanOne, "Invariant failure i == 0") { auto query = fromjson("{'a.b': {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); objMatch.getValue()->getChild(1); diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties_test.cpp index 01dac629ea1..e0956999840 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties_test.cpp @@ -31,17 +31,18 @@ #include "mongo/bson/json.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/schema/expression_internal_schema_allowed_properties.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { -constexpr auto kSimpleCollator = nullptr; TEST(InternalSchemaAllowedPropertiesMatchExpression, MatchesObjectsWithListedProperties) { auto filter = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['a', 'b']," "namePlaceholder: 'i', patternProperties: [], otherwise: {i: 0}}}"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{a: 1, b: 1}"))); @@ -60,7 +61,8 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, MatchesObjectsWithMatchingP ], otherwise: {i: {$type: 'string'}} }})"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{puppies: 2, kittens: 3, phoneNum: 1234}"))); @@ -73,7 +75,8 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, auto filter = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['a'], namePlaceholder: 'a'," "patternProperties: [{regex: /a/, expression: {a: {$gt: 5}}}], otherwise: {a: 0}}}"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{a: 6}"))); @@ -92,7 +95,8 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, OtherwiseEnforcedWhenApprop ], otherwise: {i: {$type: 'string'}} }})"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{foo: 'bar'}"))); @@ -103,7 +107,8 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, EquivalentToClone) { auto filter = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['a'], namePlaceholder: 'i'," "patternProperties: [{regex: /a/, expression: {i: 1}}], otherwise: {i: 7}}}"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); auto clone = expr.getValue()->shallowClone(); ASSERT_TRUE(expr.getValue()->equivalent(clone.get())); @@ -111,7 +116,7 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, EquivalentToClone) { filter = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [], otherwise: {}}}"); - expr = MatchExpressionParser::parse(filter, kSimpleCollator); + expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); clone = expr.getValue()->shallowClone(); ASSERT_TRUE(expr.getValue()->equivalent(clone.get())); @@ -121,7 +126,8 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, HasCorrectNumberOfChilden) auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['a'], namePlaceholder: 'i'," "patternProperties: [{regex: /a/, expression: {i: 1}}], otherwise: {i: 7}}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); ASSERT_EQ(objMatch.getValue()->numChildren(), 2U); @@ -134,7 +140,8 @@ DEATH_TEST(InternalSchemaAllowedPropertiesMatchExpression, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['a'], namePlaceholder: 'i'," "patternProperties: [{regex: /a/, expression: {i: 1}}], otherwise: {i: 7}}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); const size_t numChildren = 2; diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_cond_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_cond_test.cpp index b1cbb03d18a..f1a022da7c4 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_cond_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_cond_test.cpp @@ -32,6 +32,7 @@ #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/schema/expression_internal_schema_cond.h" #include "mongo/db/matcher/schema/expression_internal_schema_object_match.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -44,12 +45,12 @@ std::unique_ptr<InternalSchemaCondMatchExpression> createCondMatchExpression(BSO BSONObj elseBranch) { auto cond = stdx::make_unique<InternalSchemaCondMatchExpression>(); - const CollatorInterface* kSimpleCollator = nullptr; - auto conditionExpr = MatchExpressionParser::parse(condition, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto conditionExpr = MatchExpressionParser::parse(condition, expCtx); ASSERT_OK(conditionExpr.getStatus()); - auto thenBranchExpr = MatchExpressionParser::parse(thenBranch, kSimpleCollator); + auto thenBranchExpr = MatchExpressionParser::parse(thenBranch, expCtx); ASSERT_OK(thenBranchExpr.getStatus()); - auto elseBranchExpr = MatchExpressionParser::parse(elseBranch, kSimpleCollator); + auto elseBranchExpr = MatchExpressionParser::parse(elseBranch, expCtx); cond->init({{std::move(conditionExpr.getValue()), std::move(thenBranchExpr.getValue()), diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_eq_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_eq_test.cpp index f82f0b34bf0..3ccc5175092 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_eq_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_eq_test.cpp @@ -31,6 +31,7 @@ #include "mongo/bson/json.h" #include "mongo/db/matcher/matcher.h" #include "mongo/db/matcher/schema/expression_internal_schema_eq.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -118,26 +119,28 @@ TEST(InternalSchemaEqMatchExpression, EquivalentReturnsCorrectResults) { {a: {$_internalSchemaEq: { b: {c: 1, d: 1} }}})"); - Matcher eqExpr(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher eqExpr(query, expCtx); query = fromjson(R"( {a: {$_internalSchemaEq: { b: {d: 1, c: 1} }}})"); - Matcher eqExprEq(query, nullptr); + Matcher eqExprEq(query, expCtx); ASSERT_TRUE(eqExpr.getMatchExpression()->equivalent(eqExprEq.getMatchExpression())); query = fromjson(R"( {a: {$_internalSchemaEq: { b: {d: 1} }}})"); - Matcher eqExprNotEq(query, nullptr); + Matcher eqExprNotEq(query, expCtx); ASSERT_FALSE(eqExpr.getMatchExpression()->equivalent(eqExprNotEq.getMatchExpression())); } TEST(InternalSchemaEqMatchExpression, EquivalentToClone) { auto query = fromjson("{a: {$_internalSchemaEq: {a:1, b: {c: 1, d: [1]}}}}"); - Matcher rootDocEq(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher rootDocEq(query, expCtx); auto clone = rootDocEq.getMatchExpression()->shallowClone(); ASSERT_TRUE(rootDocEq.getMatchExpression()->equivalent(clone.get())); } diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index_test.cpp index fcceda2f0d3..cc2c51e3dce 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index_test.cpp @@ -32,19 +32,20 @@ #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/expression_with_placeholder.h" #include "mongo/db/matcher/schema/expression_internal_schema_match_array_index.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace { -constexpr auto kSimpleCollator = nullptr; TEST(InternalSchemaMatchArrayIndexMatchExpression, RejectsNonArrays) { auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$gt: 7}}}}}"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{foo: 'blah'}"))); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{foo: 7}"))); @@ -55,7 +56,8 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, MatchesArraysWithMatchingElem auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$elemMatch: {'bar': 7}}}}}}"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{foo: [[{bar: 7}], [{bar: 5}]]}"))); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{foo: [[{bar: [3, 5, 7]}], [{bar: 5}]]}"))); @@ -63,7 +65,7 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, MatchesArraysWithMatchingElem filter = fromjson( "{baz: {$_internalSchemaMatchArrayIndex:" "{index: 2, namePlaceholder: 'i', expression: {i: {$type: 'string'}}}}}"); - expr = MatchExpressionParser::parse(filter, kSimpleCollator); + expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{baz: [0, 1, '2']}"))); } @@ -72,14 +74,15 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, DoesNotMatchArrayIfMatchingEl auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$lte: 7}}}}}"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{foo: [33, 0, 1, 2]}"))); filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 1, namePlaceholder: 'i', expression: {i: {$lte: 7}}}}}"); - expr = MatchExpressionParser::parse(filter, kSimpleCollator); + expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{foo: [0, 99, 1, 2]}"))); } @@ -88,14 +91,15 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, MatchesIfNotEnoughArrayElemen auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: 1}}}}"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{foo: []}"))); filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 4, namePlaceholder: 'i', expression: {i: 1}}}}"); - expr = MatchExpressionParser::parse(filter, kSimpleCollator); + expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{foo: ['no', 'no', 'no', 'no']}"))); } @@ -104,7 +108,8 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, EquivalentToClone) { auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$type: 'number'}}}}}"); - auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(filter, expCtx); ASSERT_OK(expr.getStatus()); auto clone = expr.getValue()->shallowClone(); ASSERT_TRUE(expr.getValue()->equivalent(clone.get())); @@ -114,7 +119,8 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, HasSingleChild) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$type: 'number'}}}}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); ASSERT_EQ(objMatch.getValue()->numChildren(), 1U); @@ -127,7 +133,8 @@ DEATH_TEST(InternalSchemaMatchArrayIndexMatchExpression, auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$type: 'number'}}}}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); objMatch.getValue()->getChild(1); diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_object_match_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_object_match_test.cpp index 22137895c3d..a6d0ff5b5f9 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_object_match_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_object_match_test.cpp @@ -31,6 +31,7 @@ #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/matcher.h" #include "mongo/db/matcher/schema/expression_internal_schema_object_match.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" @@ -40,7 +41,8 @@ namespace mongo { namespace { TEST(InternalSchemaObjectMatchExpression, RejectsNonObjectElements) { - auto subExpr = MatchExpressionParser::parse(BSON("b" << 1), nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto subExpr = MatchExpressionParser::parse(BSON("b" << 1), expCtx); ASSERT_OK(subExpr.getStatus()); InternalSchemaObjectMatchExpression objMatch; @@ -53,9 +55,10 @@ TEST(InternalSchemaObjectMatchExpression, RejectsNonObjectElements) { } TEST(InternalSchemaObjectMatchExpression, RejectsObjectsThatDontMatch) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto subExpr = MatchExpressionParser::parse(BSON("b" << BSON("$type" << "string")), - nullptr); + expCtx); ASSERT_OK(subExpr.getStatus()); InternalSchemaObjectMatchExpression objMatch; @@ -66,9 +69,10 @@ TEST(InternalSchemaObjectMatchExpression, RejectsObjectsThatDontMatch) { } TEST(InternalSchemaObjectMatchExpression, AcceptsObjectsThatMatch) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto subExpr = MatchExpressionParser::parse(BSON("b" << BSON("$type" << "string")), - nullptr); + expCtx); ASSERT_OK(subExpr.getStatus()); InternalSchemaObjectMatchExpression objMatch; @@ -87,9 +91,10 @@ TEST(InternalSchemaObjectMatchExpression, AcceptsObjectsThatMatch) { } TEST(InternalSchemaObjectMatchExpression, DottedPathAcceptsObjectsThatMatch) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto subExpr = MatchExpressionParser::parse(BSON("b.c.d" << BSON("$type" << "string")), - nullptr); + expCtx); ASSERT_OK(subExpr.getStatus()); InternalSchemaObjectMatchExpression objMatch; @@ -103,7 +108,8 @@ TEST(InternalSchemaObjectMatchExpression, DottedPathAcceptsObjectsThatMatch) { } TEST(InternalSchemaObjectMatchExpression, EmptyMatchAcceptsAllObjects) { - auto subExpr = MatchExpressionParser::parse(BSONObj(), nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto subExpr = MatchExpressionParser::parse(BSONObj(), expCtx); ASSERT_OK(subExpr.getStatus()); InternalSchemaObjectMatchExpression objMatch; @@ -125,7 +131,8 @@ TEST(InternalSchemaObjectMatchExpression, NestedObjectMatchReturnsCorrectPath) { " $or: [{c: {$type: 'string'}}, {c: {$gt: 0}}]" " }}}" " }}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); ASSERT_EQ(objMatch.getValue()->path(), "a"); @@ -139,7 +146,8 @@ TEST(InternalSchemaObjectMatchExpression, MatchesNestedObjectMatch) { " c: 3" " }}}" " }}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); ASSERT_FALSE(objMatch.getValue()->matchesBSON(fromjson("{a: 1}"))); @@ -153,31 +161,34 @@ TEST(InternalSchemaObjectMatchExpression, EquivalentReturnsCorrectResults) { " {a: {$_internalSchemaObjectMatch: {" " b: 3" " }}}"); - Matcher objectMatch(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher objectMatch(query, expCtx); query = fromjson( " {a: {$_internalSchemaObjectMatch: {" " b: {$eq: 3}" " }}}"); - Matcher objectMatchEq(query, nullptr); + Matcher objectMatchEq(query, expCtx); ASSERT_TRUE(objectMatch.getMatchExpression()->equivalent(objectMatchEq.getMatchExpression())); query = fromjson( " {a: {$_internalSchemaObjectMatch: {" " c: {$eq: 3}" " }}}"); - Matcher objectMatchNotEq(query, nullptr); + Matcher objectMatchNotEq(query, expCtx); ASSERT_FALSE( objectMatch.getMatchExpression()->equivalent(objectMatchNotEq.getMatchExpression())); } TEST(InternalSchemaObjectMatchExpression, SubExpressionRespectsCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); auto query = fromjson( "{a: {$_internalSchemaObjectMatch: {" " b: {$eq: 'FOO'}" "}}}"); - auto objectMatch = MatchExpressionParser::parse(query, &collator); + auto objectMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objectMatch.getStatus()); ASSERT_TRUE(objectMatch.getValue()->matchesBSON(fromjson("{a: {b: 'FOO'}}"))); @@ -187,7 +198,8 @@ TEST(InternalSchemaObjectMatchExpression, SubExpressionRespectsCollator) { TEST(InternalSchemaObjectMatchExpression, RejectsArraysContainingMatchingSubObject) { auto query = fromjson("{a: {$_internalSchemaObjectMatch: {b: 1}}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); ASSERT_FALSE(objMatch.getValue()->matchesBSON(fromjson("{a: 1}"))); @@ -201,7 +213,8 @@ TEST(InternalSchemaObjectMatchExpression, HasSingleChild) { " {a: {$_internalSchemaObjectMatch: {" " c: {$eq: 3}" " }}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); ASSERT_EQ(objMatch.getValue()->numChildren(), 1U); @@ -215,7 +228,8 @@ DEATH_TEST(InternalSchemaObjectMatchExpression, " {a: {$_internalSchemaObjectMatch: {" " c: {$eq: 3}" " }}}"); - auto objMatch = MatchExpressionParser::parse(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); objMatch.getValue()->getChild(1); diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq_test.cpp index 4b46779b173..ade721236d3 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq_test.cpp @@ -31,6 +31,7 @@ #include "mongo/bson/json.h" #include "mongo/db/matcher/matcher.h" #include "mongo/db/matcher/schema/expression_internal_schema_root_doc_eq.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -92,26 +93,28 @@ TEST(InternalSchemaRootDocEqMatchExpression, EquivalentReturnsCorrectResults) { {$_internalSchemaRootDocEq: { b: 1, c: 1 }})"); - Matcher rootDocEq(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher rootDocEq(query, expCtx); query = fromjson(R"( {$_internalSchemaRootDocEq: { c: 1, b: 1 }})"); - Matcher exprEq(query, nullptr); + Matcher exprEq(query, expCtx); ASSERT_TRUE(rootDocEq.getMatchExpression()->equivalent(exprEq.getMatchExpression())); query = fromjson(R"( {$_internalSchemaRootDocEq: { c: 1 }})"); - Matcher exprNotEq(query, nullptr); + Matcher exprNotEq(query, expCtx); ASSERT_FALSE(rootDocEq.getMatchExpression()->equivalent(exprNotEq.getMatchExpression())); } TEST(InternalSchemaRootDocEqMatchExpression, EquivalentToClone) { auto query = fromjson("{$_internalSchemaRootDocEq: {a:1, b: {c: 1, d: [1]}}}"); - Matcher rootDocEq(query, nullptr); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher rootDocEq(query, expCtx); auto clone = rootDocEq.getMatchExpression()->shallowClone(); ASSERT_TRUE(rootDocEq.getMatchExpression()->equivalent(clone.get())); } diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_xor_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_xor_test.cpp index 37f6ff4f6c2..60d7e4d90e8 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_xor_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_xor_test.cpp @@ -34,6 +34,7 @@ #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/schema/expression_internal_schema_xor.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -48,8 +49,8 @@ TEST(InternalSchemaXorOp, MatchesNothingWhenHasNoClauses) { TEST(InternalSchemaXorOp, MatchesSingleClause) { BSONObj matchPredicate = fromjson("{$_internalSchemaXor: [{a: { $ne: 5 }}]}"); - const CollatorInterface* collator = nullptr; - auto expr = MatchExpressionParser::parse(matchPredicate, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(matchPredicate, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(BSON("a" << 4))); @@ -59,11 +60,11 @@ TEST(InternalSchemaXorOp, MatchesSingleClause) { } TEST(InternalSchemaXorOp, MatchesThreeClauses) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BSONObj matchPredicate = fromjson("{$_internalSchemaXor: [{a: { $gt: 10 }}, {a: { $lt: 0 }}, {b: 0}]}"); - auto expr = MatchExpressionParser::parse(matchPredicate, collator); + auto expr = MatchExpressionParser::parse(matchPredicate, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(BSON("a" << -1))); @@ -77,11 +78,11 @@ TEST(InternalSchemaXorOp, MatchesThreeClauses) { } TEST(InternalSchemaXorOp, DoesNotUseElemMatchKey) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BSONObj matchPredicate = fromjson("{$_internalSchemaXor: [{a: 1}, {b: 2}]}"); - auto expr = MatchExpressionParser::parse(matchPredicate, collator); + auto expr = MatchExpressionParser::parse(matchPredicate, expCtx); MatchDetails details; details.requestElemMatchKey(); ASSERT_OK(expr.getStatus()); diff --git a/src/mongo/db/matcher/schema/expression_parser_schema_test.cpp b/src/mongo/db/matcher/schema/expression_parser_schema_test.cpp index ac6fb95f42b..ff3aa8beac4 100644 --- a/src/mongo/db/matcher/schema/expression_parser_schema_test.cpp +++ b/src/mongo/db/matcher/schema/expression_parser_schema_test.cpp @@ -38,17 +38,17 @@ #include "mongo/db/matcher/schema/expression_internal_schema_min_length.h" #include "mongo/db/matcher/schema/expression_internal_schema_object_match.h" #include "mongo/db/matcher/schema/expression_internal_schema_unique_items.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace { -constexpr CollatorInterface* kSimpleCollator = nullptr; - TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesIntegerArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinItems" << 2)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -59,7 +59,8 @@ TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesIntegerArgument) { TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesLongArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinItems" << 2LL)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -70,7 +71,8 @@ TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesLongArgument) { TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesDoubleArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinItems" << 2.0)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -81,7 +83,8 @@ TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesDoubleArgumentAsInt TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesDecimalArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinItems" << Decimal128("2"))); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -92,7 +95,8 @@ TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesDecimalArgumentAsIn TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesIntegerArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxItems" << 2)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -103,7 +107,8 @@ TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesIntegerArgument) { TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesLongArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxItems" << 2LL)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -115,7 +120,8 @@ TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesLongArgument) { TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesDoubleArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxItems" << 2.0)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -126,7 +132,8 @@ TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesDoubleArgumentAsInt TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesDecimalArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxItems" << Decimal128("2"))); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -137,26 +144,28 @@ TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesDecimalArgumentAsIn TEST(MatchExpressionParserSchemaTest, UniqueItemsFailsToParseNonTrueArguments) { auto queryIntArgument = BSON("x" << BSON("$_internalSchemaUniqueItems" << 0)); - auto expr = MatchExpressionParser::parse(queryIntArgument, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(queryIntArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryStringArgument = BSON("x" << BSON("$_internalSchemaUniqueItems" << "")); - expr = MatchExpressionParser::parse(queryStringArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryStringArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryDoubleArgument = BSON("x" << BSON("$_internalSchemaUniqueItems" << 1.0)); - expr = MatchExpressionParser::parse(queryDoubleArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryDoubleArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryFalseArgument = BSON("x" << BSON("$_internalSchemaUniqueItems" << false)); - expr = MatchExpressionParser::parse(queryFalseArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryFalseArgument, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, UniqueItemsParsesTrueBooleanArgument) { auto query = BSON("x" << BSON("$_internalSchemaUniqueItems" << true)); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{x: 1}"))); @@ -170,17 +179,18 @@ TEST(MatchExpressionParserSchemaTest, UniqueItemsParsesTrueBooleanArgument) { TEST(MatchExpressionParserSchemaTest, ObjectMatchOnlyAcceptsAnObjectArgument) { auto query = BSON("a" << BSON("$_internalSchemaObjectMatch" << 1)); - auto result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto result = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); query = BSON("a" << BSON("$_internalSchemaObjectMatch" << "string")); - result = MatchExpressionParser::parse(query, kSimpleCollator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); query = BSON( "a" << BSON("$_internalSchemaObjectMatch" << BSON_ARRAY(BSON("a" << 1) << BSON("b" << 1)))); - result = MatchExpressionParser::parse(query, kSimpleCollator); + result = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); } @@ -190,7 +200,8 @@ TEST(MatchExpressionParserSchemaTest, ObjectMatchCorrectlyParsesObjects) { " b: {$gte: 0}" " }}" "}"); - auto result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT_FALSE(result.getValue()->matchesBSON(fromjson("{a: 1}"))); @@ -207,7 +218,8 @@ TEST(MatchExpressionParserSchemaTest, ObjectMatchCorrectlyParsesNestedObjectMatc " $or: [{c: {$type: 'string'}}, {c: {$gt: 0}}]" " }}" "}}}"); - auto result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto result = MatchExpressionParser::parse(query, expCtx); ASSERT_TRUE(result.isOK()); ASSERT_FALSE(result.getValue()->matchesBSON(fromjson("{a: 1}"))); @@ -224,7 +236,8 @@ TEST(MatchExpressionParserSchemaTest, ObjectMatchSubExprRejectsTopLevelOperators "{a: {$_internalSchemaObjectMatch: {" " $isolated: 1" "}}}"); - auto result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto result = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(result.getStatus(), ErrorCodes::BadValue); } @@ -233,7 +246,8 @@ TEST(MatchExpressionParserSchemaTest, ObjectMatchSubExprRejectsTopLevelOperators // TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesIntegerArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinLength" << 2)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -246,7 +260,8 @@ TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesIntegerArgument) { TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesLongArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinLength" << 2LL)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -259,7 +274,8 @@ TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesLongArgument) { TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesDoubleArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinLength" << 2.0)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -272,7 +288,8 @@ TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesDoubleArgumentAsIn TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesDecimalArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinLength" << Decimal128("2"))); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -286,24 +303,25 @@ TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesDecimalArgumentAsI TEST(MatchExpressionParserSchemaTest, MinLengthFailsToParseNonIntegerArguments) { auto queryStringArgument = BSON("x" << BSON("$_internalSchemaMinLength" << "abc")); - auto expr = MatchExpressionParser::parse(queryStringArgument, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(queryStringArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); auto queryEmptyStringArgument = BSON("x" << BSON("$_internalSchemaMinLength" << "")); - expr = MatchExpressionParser::parse(queryEmptyStringArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryEmptyStringArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); auto queryDoubleArgument = BSON("x" << BSON("$_internalSchemaMinLength" << 1.5)); - expr = MatchExpressionParser::parse(queryDoubleArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryDoubleArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); auto queryFalseArgument = BSON("x" << BSON("$_internalSchemaMinLength" << false)); - expr = MatchExpressionParser::parse(queryFalseArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryFalseArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); auto queryArrArgument = BSON("x" << BSON("$_internalSchemaMinLength" << BSON_ARRAY(1))); - expr = MatchExpressionParser::parse(queryArrArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryArrArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); } @@ -312,7 +330,8 @@ TEST(MatchExpressionParserSchemaTest, MinLengthFailsToParseNonIntegerArguments) // TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesIntegerArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxLength" << 2)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -325,7 +344,8 @@ TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesIntegerArgument) { TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesLongArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxLength" << 2LL)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -338,7 +358,8 @@ TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesLongArgument) { TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesDoubleArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxLength" << 2.0)); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -351,7 +372,8 @@ TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesDoubleArgumentAsIn TEST(MatchExpressionParserSchemaTest, MaxLengthorrectlyParsesDecimalArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxLength" << Decimal128("2"))); - StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -365,62 +387,66 @@ TEST(MatchExpressionParserSchemaTest, MaxLengthorrectlyParsesDecimalArgumentAsIn TEST(MatchExpressionParserSchemaTest, MaxLengthFailsToParseNonIntegerArguments) { auto queryStringArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << "abc")); - auto expr = MatchExpressionParser::parse(queryStringArgument, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(queryStringArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); auto queryEmptyStringArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << "")); - expr = MatchExpressionParser::parse(queryEmptyStringArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryEmptyStringArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); auto queryDoubleArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << 1.5)); - expr = MatchExpressionParser::parse(queryDoubleArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryDoubleArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); auto queryFalseArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << false)); - expr = MatchExpressionParser::parse(queryFalseArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryFalseArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); auto queryArrArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << BSON_ARRAY(1))); - expr = MatchExpressionParser::parse(queryArrArgument, kSimpleCollator); + expr = MatchExpressionParser::parse(queryArrArgument, expCtx); ASSERT_NOT_OK(expr.getStatus()); } TEST(MatchExpressionParserSchemaTest, CondFailsToParseNonObjectArguments) { auto queryWithInteger = fromjson("{$_internalSchemaCond: [1, {foo: 'bar'}, {baz: 7}]}"); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse(queryWithInteger, kSimpleCollator).getStatus()); + MatchExpressionParser::parse(queryWithInteger, expCtx).getStatus()); auto queryWithArray = fromjson("{$_internalSchemaCond: [{foo: 'bar'}, [{qux: 3}], {baz: 7}]}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse(queryWithArray, kSimpleCollator).getStatus()); + MatchExpressionParser::parse(queryWithArray, expCtx).getStatus()); auto queryWithString = fromjson("{$_internalSchemaCond: [{foo: 'bar'}, {baz: 7}, 'blah']}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse(queryWithString, kSimpleCollator).getStatus()); + MatchExpressionParser::parse(queryWithString, expCtx).getStatus()); } TEST(MatchExpressionParserSchemaTest, CondFailsToParseIfNotExactlyThreeArguments) { auto queryNoArguments = fromjson("{$_internalSchemaCond: []}"); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse(queryNoArguments, kSimpleCollator).getStatus()); + MatchExpressionParser::parse(queryNoArguments, expCtx).getStatus()); auto queryOneArgument = fromjson("{$_internalSchemaCond: [{height: 171}]}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse(queryOneArgument, kSimpleCollator).getStatus()); + MatchExpressionParser::parse(queryOneArgument, expCtx).getStatus()); auto queryFourArguments = fromjson( "{$_internalSchemaCond: [{make: 'lamborghini'}, {model: 'ghost'}, {color: 'celadon'}, " "{used: false}]}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse(queryFourArguments, kSimpleCollator).getStatus()); + MatchExpressionParser::parse(queryFourArguments, expCtx).getStatus()); } TEST(MatchExpressionParserSchemaTest, CondParsesThreeMatchExpresssions) { auto query = fromjson( "{$_internalSchemaCond: [{climate: 'rainy'}, {clothing: 'jacket'}, {clothing: 'shirt'}]}"); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON( @@ -434,79 +460,73 @@ TEST(MatchExpressionParserSchemaTest, CondParsesThreeMatchExpresssions) { TEST(MatchExpressionParserSchemaTest, MatchArrayIndexFailsToParseNonObjectArguments) { auto query = fromjson("{foo: {$_internalSchemaMatchArrayIndex: 7}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson("{foo: {$_internalSchemaMatchArrayIndex: []}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "[{index: 5, namePlaceholder: 'i', expression: {i: 1}}]}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, MatchArrayIndexFailsToParseIfPlaceholderNotValid) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 5, namePlaceholder: 7, expression: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 5, namePlaceholder: 'Z', expression: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, MatchArrayIndexFailsToParseIfIndexNotANonnegativeInteger) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 'blah', namePlaceholder: 'i', expression: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: -1, namePlaceholder: 'i', expression: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 3.14, namePlaceholder: 'i', expression: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, MatchArrayIndexFailsToParseIfExpressionNotValid) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: 'blah'}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {doesntMatchThePlaceholder: 7}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {$invalid: 'blah'}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::BadValue); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::BadValue); } TEST(MatchExpressionParserSchemaTest, MatchArrayIndexParsesSuccessfully) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$lt: 0}}}}}"); - auto matchArrayIndex = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matchArrayIndex = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(matchArrayIndex.getStatus()); ASSERT_TRUE(matchArrayIndex.getValue()->matchesBSON(fromjson("{foo: [-1, 0, 1]}"))); @@ -517,32 +537,37 @@ TEST(MatchExpressionParserSchemaTest, MatchArrayIndexParsesSuccessfully) { TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FailsToParseWithNegativeIndex) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [-2, {a: { $lt: 0 }}]}}"); - auto expr = MatchExpressionParser::parse(matchPredicate, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(matchPredicate, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::TypeMismatch); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FailsToParseWithNonObjectExpression) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [-2, 4]}}"); - auto expr = MatchExpressionParser::parse(matchPredicate, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(matchPredicate, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::TypeMismatch); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FailsToParseWithInvalidExpression) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [-2, {$fakeExpression: 4}]}}"); - auto expr = MatchExpressionParser::parse(matchPredicate, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(matchPredicate, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::TypeMismatch); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FailsToParseWithEmptyArray) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: []}}"); - auto expr = MatchExpressionParser::parse(matchPredicate, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(matchPredicate, expCtx); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, ParsesCorreclyWithValidInput) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {a: { $lt: 4 }}]}}"); - auto expr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto expr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{a: [5, 3, 3, 3, 3, 3]}"))); @@ -551,14 +576,16 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, ParsesCorreclyWithValid TEST(MatchExpressionParserSchemaTest, InternalTypeFailsToParseOnTypeMismatch) { BSONObj query = BSON("x" << BSON("$_internalSchemaType" << BSONObj())); - auto result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto result = MatchExpressionParser::parse(query, expCtx); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseNumberAlias) { BSONObj query = BSON("x" << BSON("$_internalSchemaType" << "number")); - auto result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQ(result.getValue()->matchType(), MatchExpression::INTERNAL_SCHEMA_TYPE); @@ -569,7 +596,8 @@ TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseNumberAlias) { TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseLongAlias) { BSONObj query = BSON("x" << BSON("$_internalSchemaType" << "long")); - auto result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQ(result.getValue()->matchType(), MatchExpression::INTERNAL_SCHEMA_TYPE); @@ -581,7 +609,8 @@ TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseLongAlias) { TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseLongCode) { BSONObj query = BSON("x" << BSON("$_internalSchemaType" << 18)); - auto result = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto result = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(result.getStatus()); ASSERT_EQ(result.getValue()->matchType(), MatchExpression::INTERNAL_SCHEMA_TYPE); @@ -595,68 +624,62 @@ TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfAFieldIsMis auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{namePlaceholder: 'i', patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: []}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfNamePlaceholderNotAString) { auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 7, patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: /i/, patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfNamePlaceholderNotValid) { auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'Capital'," "patternProperties: [], otherwise: {Capital: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::BadValue); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::BadValue); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: '', patternProperties: [], otherwise: {'': 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::BadValue); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::BadValue); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfPropertiesNotAllStrings) { auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [7], namePlaceholder: 'i', patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['x', {}], namePlaceholder: 'i'," "patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, @@ -664,14 +687,13 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: ['blah'], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 1}, patternProperties: [{regex: /a/, expression: {i: 0}}, 'blah']}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, @@ -679,14 +701,13 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [{foo: 1, bar: 1}], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [{regex: /a/, blah: 0}], otherwise: {i: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, @@ -694,20 +715,18 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{expression: {i: 0}}]}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: 7, expression: {i: 0}}]}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: 'notARegex', expression: {i: 0}}]}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, @@ -715,14 +734,13 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: /a/}]}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: /a/, expression: 'blah'}]}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, @@ -730,44 +748,42 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: /a/i, expression: {i: 0}}]}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::BadValue); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::BadValue); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfMismatchingNamePlaceholders) { auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: {j: 1}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [{regex: /a/, expression: {w: 7}}], otherwise: {i: 'foo'}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfOtherwiseIncorrectType) { auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: false}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: [{i: 7}]}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfOtherwiseNotAValidExpression) { auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [], otherwise: {i: {$invalid: 1}}}}}}"); - ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), - ErrorCodes::BadValue); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(query, expCtx).getStatus(), ErrorCodes::BadValue); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesParsesSuccessfully) { @@ -775,7 +791,8 @@ TEST(MatchExpressionParserSchemaTest, AllowedPropertiesParsesSuccessfully) { "{$_internalSchemaAllowedProperties: {properties: ['phoneNumber', 'address']," "namePlaceholder: 'i', otherwise: {i: {$gt: 10}}," "patternProperties: [{regex: /[nN]umber/, expression: {i: {$type: 'number'}}}]}}}"); - auto allowedProperties = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto allowedProperties = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(allowedProperties.getStatus()); ASSERT_TRUE(allowedProperties.getValue()->matchesBSON( @@ -792,7 +809,8 @@ TEST(MatchExpressionParserSchemaTest, AllowedPropertiesAcceptsEmptyPropertiesAnd auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: {i: 1}}}}"); - auto allowedProperties = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto allowedProperties = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(allowedProperties.getStatus()); ASSERT_TRUE(allowedProperties.getValue()->matchesBSON(BSONObj())); @@ -802,7 +820,8 @@ TEST(MatchExpressionParserSchemaTest, AllowedPropertiesAcceptsEmptyOtherwiseExpr auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: {}}}}}"); - auto allowedProperties = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto allowedProperties = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(allowedProperties.getStatus()); ASSERT_TRUE(allowedProperties.getValue()->matchesBSON(BSONObj())); @@ -810,7 +829,8 @@ TEST(MatchExpressionParserSchemaTest, AllowedPropertiesAcceptsEmptyOtherwiseExpr TEST(MatchExpressionParserSchemaTest, EqParsesSuccessfully) { auto query = fromjson("{foo: {$_internalSchemaEq: 1}}"); - auto eqExpr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto eqExpr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(eqExpr.getStatus()); ASSERT_TRUE(eqExpr.getValue()->matchesBSON(fromjson("{foo: 1}"))); @@ -820,31 +840,34 @@ TEST(MatchExpressionParserSchemaTest, EqParsesSuccessfully) { TEST(MatchExpressionParserSchemaTest, RootDocEqFailsToParseNonObjects) { auto query = fromjson("{$_internalSchemaRootDocEq: 1}"); - auto rootDocEq = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto rootDocEq = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(rootDocEq.getStatus(), ErrorCodes::TypeMismatch); query = fromjson("{$_internalSchemaRootDocEq: [{}]}"); - rootDocEq = MatchExpressionParser::parse(query, kSimpleCollator); + rootDocEq = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(rootDocEq.getStatus(), ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, RootDocEqMustBeTopLevel) { auto query = fromjson("{a: {$_internalSchemaRootDocEq: 1}}"); - auto rootDocEq = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto rootDocEq = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(rootDocEq.getStatus(), ErrorCodes::BadValue); query = fromjson("{$or: [{a: 1}, {$_internalSchemaRootDocEq: 1}]}"); - rootDocEq = MatchExpressionParser::parse(query, kSimpleCollator); + rootDocEq = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(rootDocEq.getStatus(), ErrorCodes::FailedToParse); query = fromjson("{a: {$elemMatch: {$_internalSchemaRootDocEq: 1}}}"); - rootDocEq = MatchExpressionParser::parse(query, kSimpleCollator); + rootDocEq = MatchExpressionParser::parse(query, expCtx); ASSERT_EQ(rootDocEq.getStatus(), ErrorCodes::BadValue); } TEST(MatchExpressionParserSchemaTest, RootDocEqParsesSuccessfully) { auto query = fromjson("{$_internalSchemaRootDocEq: {}}"); - auto eqExpr = MatchExpressionParser::parse(query, kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto eqExpr = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(eqExpr.getStatus()); ASSERT_TRUE(eqExpr.getValue()->matchesBSON(fromjson("{}"))); diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript index beadfc36549..c0ced70109d 100644 --- a/src/mongo/db/ops/SConscript +++ b/src/mongo/db/ops/SConscript @@ -50,116 +50,31 @@ env.Library( ) env.CppUnitTest( - target='modifier_add_to_set_test', - source='modifier_add_to_set_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_bit_test', - source='modifier_bit_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_compare_test', - source='modifier_compare_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', + target='modifier_update_test', + source=[ + 'modifier_add_to_set_test.cpp', + 'modifier_bit_test.cpp', + 'modifier_compare_test.cpp', + 'modifier_current_date_test.cpp', + 'modifier_inc_test.cpp', + 'modifier_pop_test.cpp', + 'modifier_pull_all_test.cpp', + 'modifier_pull_test.cpp', + 'modifier_push_test.cpp', + 'modifier_rename_test.cpp', + 'modifier_set_test.cpp', + 'modifier_unset_test.cpp', ], -) - -env.CppUnitTest( - target='modifier_current_date_test', - source='modifier_current_date_test.cpp', LIBDEPS=[ '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', + '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', + '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/service_context_noop_init', '$BUILD_DIR/mongo/db/logical_clock', 'update', ], ) -env.CppUnitTest( - target='modifier_inc_test', - source='modifier_inc_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_pop_test', - source='modifier_pop_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_pull_all_test', - source='modifier_pull_all_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_pull_test', - source='modifier_pull_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_push_test', - source='modifier_push_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_rename_test', - source='modifier_rename_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_set_test', - source='modifier_set_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_unset_test', - source='modifier_unset_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update', - ], -) - env.Library( target='write_ops_parsers', source=[ diff --git a/src/mongo/db/ops/modifier_add_to_set.cpp b/src/mongo/db/ops/modifier_add_to_set.cpp index acf34b2f544..32016419151 100644 --- a/src/mongo/db/ops/modifier_add_to_set.cpp +++ b/src/mongo/db/ops/modifier_add_to_set.cpp @@ -169,7 +169,7 @@ Status ModifierAddToSet::init(const BSONElement& modExpr, const Options& opts, b _val = each; } - setCollator(opts.collator); + setCollator(opts.expCtx->getCollator()); return Status::OK(); } diff --git a/src/mongo/db/ops/modifier_add_to_set_test.cpp b/src/mongo/db/ops/modifier_add_to_set_test.cpp index e24515d1d56..68fe447dbbd 100644 --- a/src/mongo/db/ops/modifier_add_to_set_test.cpp +++ b/src/mongo/db/ops/modifier_add_to_set_test.cpp @@ -36,6 +36,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" @@ -44,6 +45,7 @@ namespace { using mongo::BSONObj; using mongo::CollatorInterfaceMock; +using mongo::ExpressionContextForTest; using mongo::LogBuilder; using mongo::ModifierAddToSet; using mongo::ModifierInterface; @@ -59,7 +61,8 @@ public: Mod() : _mod() {} explicit Mod(BSONObj modObj, - ModifierInterface::Options options = ModifierInterface::Options::normal()) + ModifierInterface::Options options = + ModifierInterface::Options::normal(new ExpressionContextForTest())) : _modObj(modObj), _mod() { ASSERT_OK(_mod.init(_modObj["$addToSet"].embeddedObject().firstElement(), options)); } @@ -401,9 +404,11 @@ TEST(Deduplication, ExistingDuplicatesArePreservedWithRespectToCollation) { TEST(Collation, AddToSetRespectsCollationFromModifierOptions) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); Document doc(fromjson("{ a : ['not'] }")); Mod mod(fromjson("{ $addToSet : { a : 'equal' } }"), - ModifierInterface::Options::normal(&collator)); + ModifierInterface::Options::normal(expCtx)); ModifierInterface::ExecInfo execInfo; ASSERT_OK(mod.prepare(doc.root(), "", &execInfo)); diff --git a/src/mongo/db/ops/modifier_bit_test.cpp b/src/mongo/db/ops/modifier_bit_test.cpp index 3c8fed4330e..204e2bd16a6 100644 --- a/src/mongo/db/ops/modifier_bit_test.cpp +++ b/src/mongo/db/ops/modifier_bit_test.cpp @@ -36,6 +36,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/log_builder.h" #include "mongo/platform/decimal128.h" #include "mongo/unittest/unittest.h" @@ -44,6 +45,7 @@ namespace { using mongo::BSONObj; using mongo::Decimal128; +using mongo::ExpressionContextForTest; using mongo::LogBuilder; using mongo::ModifierBit; using mongo::ModifierInterface; @@ -61,7 +63,7 @@ public: explicit Mod(BSONObj modObj) : _modObj(modObj), _mod() { ASSERT_OK(_mod.init(_modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(new ExpressionContextForTest()))); } Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) { @@ -89,50 +91,51 @@ private: TEST(Init, FailToInitWithInvalidValue) { BSONObj modObj; ModifierBit mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); // Double is an invalid $bit argument modObj = fromjson("{ $bit : { a : 0 } }"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // String is an invalid $bit argument modObj = fromjson("{ $bit : { a : '' } }"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // Array is an invalid $bit argument modObj = fromjson("{ $bit : { a : [] } }"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // An empty document is an invalid $bit argument. modObj = fromjson("{$bit: {a: {}}}"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // An object with value not in ('and', 'or') is an invalid $bit argument modObj = fromjson("{ $bit : { a : { foo : 4 } } }"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // The argument to the sub-operator must be numeric modObj = fromjson("{ $bit : { a : { or : [] } } }"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); modObj = fromjson("{ $bit : { a : { or : 'foo' } } }"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // The argument to the sub-operator must be integral modObj = fromjson("{ $bit : { a : { or : 1.0 } } }"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // The argument to the sub-operator must be integral modObj = fromjson("{ $bit : { a : { or : NumberDecimal(\"1.0\") } } }"); ASSERT_NOT_OK(mod.init(modObj["$bit"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, ParsesAndInt) { diff --git a/src/mongo/db/ops/modifier_compare.cpp b/src/mongo/db/ops/modifier_compare.cpp index 5f579e65cc6..a63d224a94f 100644 --- a/src/mongo/db/ops/modifier_compare.cpp +++ b/src/mongo/db/ops/modifier_compare.cpp @@ -84,7 +84,7 @@ Status ModifierCompare::init(const BSONElement& modExpr, const Options& opts, bo // Store value for later. _val = modExpr; - _collator = opts.collator; + _collator = opts.expCtx->getCollator(); return Status::OK(); } diff --git a/src/mongo/db/ops/modifier_compare_test.cpp b/src/mongo/db/ops/modifier_compare_test.cpp index c454e741368..839697c899a 100644 --- a/src/mongo/db/ops/modifier_compare_test.cpp +++ b/src/mongo/db/ops/modifier_compare_test.cpp @@ -35,6 +35,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" @@ -43,6 +44,7 @@ namespace { using mongo::BSONObj; using mongo::CollatorInterfaceMock; +using mongo::ExpressionContextForTest; using mongo::LogBuilder; using mongo::ModifierCompare; using mongo::ModifierInterface; @@ -62,7 +64,8 @@ public: Mod() : _mod() {} explicit Mod(BSONObj modObj, - ModifierInterface::Options options = ModifierInterface::Options::normal()) + ModifierInterface::Options options = + ModifierInterface::Options::normal(new ExpressionContextForTest())) : _modObj(modObj), _mod((modObj.firstElement().fieldNameStringData() == "$min") ? ModifierCompare::MIN : ModifierCompare::MAX) { @@ -94,18 +97,19 @@ private: TEST(Init, ValidValues) { BSONObj modObj; ModifierCompare mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); modObj = fromjson("{ $min : { a : 2 } }"); ASSERT_OK(mod.init(modObj[kModNameMin].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); modObj = fromjson("{ $max : { a : 1 } }"); ASSERT_OK(mod.init(modObj[kModNameMax].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); modObj = fromjson("{ $min : { a : {$date : 0 } } }"); ASSERT_OK(mod.init(modObj[kModNameMin].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(ExistingNumber, MaxSameNumber) { @@ -297,7 +301,9 @@ TEST(ExistingEmbeddedDoc, MaxNumber) { TEST(Collation, MinRespectsCollationFromModifierInterfaceOptions) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); Document doc(fromjson("{a: 'cbc'}")); - ModifierInterface::Options options = ModifierInterface::Options::normal(&collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); + ModifierInterface::Options options = ModifierInterface::Options::normal(expCtx); Mod mod(fromjson("{$min: {a: 'dba'}}"), options); ModifierInterface::ExecInfo execInfo; diff --git a/src/mongo/db/ops/modifier_current_date_test.cpp b/src/mongo/db/ops/modifier_current_date_test.cpp index 79f0e409aa8..cd0f872d018 100644 --- a/src/mongo/db/ops/modifier_current_date_test.cpp +++ b/src/mongo/db/ops/modifier_current_date_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/logical_clock.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/service_context_noop.h" #include "mongo/db/update/log_builder.h" #include "mongo/stdx/memory.h" @@ -44,6 +45,7 @@ namespace { using mongo::BSONObj; +using mongo::ExpressionContextForTest; using mongo::LogBuilder; using mongo::ModifierCurrentDate; using mongo::ModifierInterface; @@ -101,7 +103,7 @@ public: explicit Mod(BSONObj modObj) : _modObj(modObj), _mod() { ASSERT_OK(_mod.init(_modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(new ExpressionContextForTest()))); } Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) { @@ -128,68 +130,70 @@ private: TEST_F(Init, ValidValues) { BSONObj modObj; ModifierCurrentDate mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); modObj = fromjson("{ $currentDate : { a : true } }"); ASSERT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); modObj = fromjson("{ $currentDate : { a : {$type : 'timestamp' } } }"); ASSERT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); modObj = fromjson("{ $currentDate : { a : {$type : 'date' } } }"); ASSERT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST_F(Init, FailToInitWithInvalidValue) { BSONObj modObj; ModifierCurrentDate mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); // String is an invalid $currentDate argument modObj = fromjson("{ $currentDate : { a : 'Oct 11, 2001' } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // Array is an invalid $currentDate argument modObj = fromjson("{ $currentDate : { a : [] } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // Number is an invalid $currentDate argument modObj = fromjson("{ $currentDate : { a : 1 } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // Regex is an invalid $currentDate argument modObj = fromjson("{ $currentDate : { a : /1/ } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // An object with missing $type field is an invalid $currentDate argument modObj = fromjson("{ $currentDate : { a : { foo : 4 } } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // An object with extra fields, including the $type field is bad modObj = fromjson("{ $currentDate : { a : { $type: 'date', foo : 4 } } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // An object with extra fields, including the $type field is bad modObj = fromjson("{ $currentDate : { a : { foo: 4, $type : 'date' } } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // An object with non-date/timestamp $type field is an invalid $currentDate argument modObj = fromjson("{ $currentDate : { a : { $type : 4 } } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // An object with non-date/timestamp $type field is an invalid $currentDate argument modObj = fromjson("{ $currentDate : { a : { $type : 'foo' } } }"); ASSERT_NOT_OK(mod.init(modObj["$currentDate"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST_F(BoolInput, EmptyStartDoc) { diff --git a/src/mongo/db/ops/modifier_inc_test.cpp b/src/mongo/db/ops/modifier_inc_test.cpp index ec12b8deb66..ec0a1b38690 100644 --- a/src/mongo/db/ops/modifier_inc_test.cpp +++ b/src/mongo/db/ops/modifier_inc_test.cpp @@ -38,6 +38,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/log_builder.h" #include "mongo/platform/decimal128.h" #include "mongo/unittest/unittest.h" @@ -46,6 +47,7 @@ namespace { using mongo::BSONObj; using mongo::Decimal128; +using mongo::ExpressionContextForTest; using mongo::LogBuilder; using mongo::ModifierInc; using mongo::ModifierInterface; @@ -68,7 +70,7 @@ public: : ModifierInc::MODE_INC) { StringData modName = modObj.firstElement().fieldName(); ASSERT_OK(_mod.init(_modObj[modName].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(new ExpressionContextForTest()))); } Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) { @@ -95,21 +97,22 @@ private: TEST(Init, FailToInitWithInvalidValue) { BSONObj modObj; ModifierInc mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); // String is an invalid increment argument modObj = fromjson("{ $inc : { a : '' } }"); ASSERT_NOT_OK(mod.init(modObj["$inc"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // Object is an invalid increment argument modObj = fromjson("{ $inc : { a : {} } }"); ASSERT_NOT_OK(mod.init(modObj["$inc"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); // Array is an invalid increment argument modObj = fromjson("{ $inc : { a : [] } }"); ASSERT_NOT_OK(mod.init(modObj["$inc"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, InitParsesNumberInt) { diff --git a/src/mongo/db/ops/modifier_interface.h b/src/mongo/db/ops/modifier_interface.h index 77e85a2d447..cb104069ca9 100644 --- a/src/mongo/db/ops/modifier_interface.h +++ b/src/mongo/db/ops/modifier_interface.h @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/element.h" #include "mongo/db/field_ref.h" #include "mongo/db/jsobj.h" +#include "mongo/db/pipeline/expression_context.h" namespace mongo { @@ -168,20 +169,19 @@ public: * Options used to control Modifier behavior */ struct ModifierInterface::Options { - Options() = default; - Options(bool fromOpLog, bool ofs, const CollatorInterface* collator) - : fromOplogApplication(fromOpLog), enforceOkForStorage(ofs), collator(collator) {} + Options(bool fromOpLog, bool ofs, boost::intrusive_ptr<ExpressionContext> expCtx) + : fromOplogApplication(fromOpLog), enforceOkForStorage(ofs), expCtx(std::move(expCtx)) {} - static Options normal(const CollatorInterface* collator = nullptr) { - return Options(false, true, collator); + static Options normal(boost::intrusive_ptr<ExpressionContext> expCtx) { + return Options(false, true, std::move(expCtx)); } - static Options fromRepl(const CollatorInterface* collator = nullptr) { - return Options(true, false, collator); + static Options fromRepl(boost::intrusive_ptr<ExpressionContext> expCtx) { + return Options(true, false, std::move(expCtx)); } bool fromOplogApplication = false; bool enforceOkForStorage = true; - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContext> expCtx; }; struct ModifierInterface::ExecInfo { diff --git a/src/mongo/db/ops/modifier_pop_test.cpp b/src/mongo/db/ops/modifier_pop_test.cpp index 75cb61fac71..f899cedcdd4 100644 --- a/src/mongo/db/ops/modifier_pop_test.cpp +++ b/src/mongo/db/ops/modifier_pop_test.cpp @@ -38,6 +38,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" @@ -45,6 +46,7 @@ namespace { using mongo::Array; using mongo::BSONObj; +using mongo::ExpressionContextForTest; using mongo::LogBuilder; using mongo::fromjson; using mongo::ModifierInterface; @@ -62,7 +64,7 @@ public: explicit Mod(BSONObj modObj) { _modObj = modObj; ASSERT_OK(_mod.init(_modObj["$pop"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(new ExpressionContextForTest()))); } Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) { @@ -97,22 +99,25 @@ private: TEST(Init, StringArg) { BSONObj modObj = fromjson("{$pop: {a: 'hi'}}"); ModifierPop mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$pop"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, BoolTrueArg) { BSONObj modObj = fromjson("{$pop: {a: true}}"); ModifierPop mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$pop"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, BoolFalseArg) { BSONObj modObj = fromjson("{$pop: {a: false}}"); ModifierPop mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$pop"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(MissingField, AllButApply) { diff --git a/src/mongo/db/ops/modifier_pull.cpp b/src/mongo/db/ops/modifier_pull.cpp index bb18a80b723..a030e4e5598 100644 --- a/src/mongo/db/ops/modifier_pull.cpp +++ b/src/mongo/db/ops/modifier_pull.cpp @@ -99,7 +99,7 @@ Status ModifierPull::init(const BSONElement& modExpr, const Options& opts, bool* _exprElt = modExpr; - _collator = opts.collator; + _collator = opts.expCtx->getCollator(); // If the element in the mod is actually an object or a regular expression, we need to // build a matcher, instead of just doing an equality comparision. @@ -123,7 +123,7 @@ 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/$geoNear/$near/$nearSphere/$expr clauses. - StatusWithMatchExpression parseResult = MatchExpressionParser::parse(_exprObj, _collator); + StatusWithMatchExpression parseResult = MatchExpressionParser::parse(_exprObj, opts.expCtx); if (!parseResult.isOK()) { return parseResult.getStatus(); } diff --git a/src/mongo/db/ops/modifier_pull_all.cpp b/src/mongo/db/ops/modifier_pull_all.cpp index 0659e91ef38..21455cb66a0 100644 --- a/src/mongo/db/ops/modifier_pull_all.cpp +++ b/src/mongo/db/ops/modifier_pull_all.cpp @@ -125,7 +125,7 @@ Status ModifierPullAll::init(const BSONElement& modExpr, const Options& opts, bo // store the stuff to remove later _elementsToFind = modExpr.Array(); - setCollator(opts.collator); + setCollator(opts.expCtx->getCollator()); return Status::OK(); } diff --git a/src/mongo/db/ops/modifier_pull_all_test.cpp b/src/mongo/db/ops/modifier_pull_all_test.cpp index f24c770aa48..8454e5ff616 100644 --- a/src/mongo/db/ops/modifier_pull_all_test.cpp +++ b/src/mongo/db/ops/modifier_pull_all_test.cpp @@ -38,6 +38,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" @@ -46,6 +47,7 @@ namespace { using mongo::BSONObj; using mongo::CollatorInterfaceMock; +using mongo::ExpressionContextForTest; using mongo::LogBuilder; using mongo::ModifierPullAll; using mongo::ModifierInterface; @@ -63,7 +65,8 @@ public: Mod() : _mod() {} explicit Mod(BSONObj modObj, - ModifierInterface::Options options = ModifierInterface::Options::normal()) + ModifierInterface::Options options = + ModifierInterface::Options::normal(new ExpressionContextForTest())) : _modObj(modObj), _mod() { ASSERT_OK(_mod.init(_modObj["$pullAll"].embeddedObject().firstElement(), options)); } @@ -92,22 +95,23 @@ private: TEST(Init, BadThings) { BSONObj modObj; ModifierPullAll mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); modObj = fromjson("{$pullAll: {a:1}}"); ASSERT_NOT_OK(mod.init(modObj["$pullAll"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); modObj = fromjson("{$pullAll: {a:'test'}}"); ASSERT_NOT_OK(mod.init(modObj["$pullAll"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); modObj = fromjson("{$pullAll: {a:{}}}"); ASSERT_NOT_OK(mod.init(modObj["$pullAll"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); modObj = fromjson("{$pullAll: {a:true}}"); ASSERT_NOT_OK(mod.init(modObj["$pullAll"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(PrepareApply, SimpleNumber) { @@ -252,8 +256,10 @@ TEST(Prepare, FromArrayElementPath) { TEST(Collation, RespectsCollationFromOptions) { Document doc(fromjson("{ a : ['foo', 'bar' ] }")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); Mod mod(fromjson("{ $pullAll : { 'a' : ['FOO', 'BAR'] } }"), - ModifierInterface::Options::normal(&collator)); + ModifierInterface::Options::normal(expCtx)); ModifierInterface::ExecInfo execInfo; ASSERT_OK(mod.prepare(doc.root(), "", &execInfo)); diff --git a/src/mongo/db/ops/modifier_pull_test.cpp b/src/mongo/db/ops/modifier_pull_test.cpp index 471ed3c18b3..ee5a2025310 100644 --- a/src/mongo/db/ops/modifier_pull_test.cpp +++ b/src/mongo/db/ops/modifier_pull_test.cpp @@ -36,6 +36,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" @@ -54,12 +55,14 @@ public: explicit Mod(BSONObj modObj) : _modObj(modObj), _mod() { ASSERT_OK(_mod.init(_modObj["$pull"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(new ExpressionContextForTest()))); } Mod(BSONObj modObj, const CollatorInterface* collator) : _modObj(modObj), _mod() { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(collator); ASSERT_OK(_mod.init(_modObj["$pull"].embeddedObject().firstElement(), - ModifierInterface::Options::normal(collator))); + ModifierInterface::Options::normal(std::move(expCtx)))); } Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) { @@ -85,18 +88,18 @@ private: TEST(SimpleMod, InitWithTextFails) { auto update = fromjson("{$pull: {a: {$text: {$search: 'str'}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ModifierPull node; - auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(expCtx)); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(SimpleMod, InitWithWhereFails) { auto update = fromjson("{$pull: {a: {$where: 'this.a == this.b'}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ModifierPull node; - auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(expCtx)); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -104,9 +107,9 @@ TEST(SimpleMod, InitWithWhereFails) { TEST(SimpleMod, InitWithGeoNearElemFails) { auto update = fromjson("{$pull: {a: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ModifierPull node; - auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(expCtx)); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -114,27 +117,27 @@ TEST(SimpleMod, InitWithGeoNearElemFails) { TEST(SimpleMod, InitWithGeoNearObjectFails) { auto update = fromjson( "{$pull: {a: {b: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ModifierPull node; - auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(expCtx)); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(SimpleMod, InitWithExprElemFails) { auto update = fromjson("{$pull: {a: {$expr: {$eq: ['$a', 5]}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ModifierPull node; - auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(expCtx)); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(SimpleMod, InitWithExprObjectFails) { auto update = fromjson("{$pull: {a: {$expr: {$eq: ['$a', {$literal: {b: 5}}]}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ModifierPull node; - auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(expCtx)); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } diff --git a/src/mongo/db/ops/modifier_push.cpp b/src/mongo/db/ops/modifier_push.cpp index acd6232841a..c062a4e9c34 100644 --- a/src/mongo/db/ops/modifier_push.cpp +++ b/src/mongo/db/ops/modifier_push.cpp @@ -338,7 +338,7 @@ Status ModifierPush::init(const BSONElement& modExpr, const Options& opts, bool* } } - _sort = PatternElementCmp(sortElem.embeddedObject(), opts.collator); + _sort = PatternElementCmp(sortElem.embeddedObject(), opts.expCtx->getCollator()); } else { // Ensure the sortElem number is valid. if (!isPatternElement(sortElem)) { @@ -346,7 +346,7 @@ Status ModifierPush::init(const BSONElement& modExpr, const Options& opts, bool* "The $sort element value must be either 1 or -1"); } - _sort = PatternElementCmp(BSON("" << sortElem.number()), opts.collator); + _sort = PatternElementCmp(BSON("" << sortElem.number()), opts.expCtx->getCollator()); } _sortPresent = true; diff --git a/src/mongo/db/ops/modifier_push_test.cpp b/src/mongo/db/ops/modifier_push_test.cpp index cd06eb7d7ff..7c2d65bb485 100644 --- a/src/mongo/db/ops/modifier_push_test.cpp +++ b/src/mongo/db/ops/modifier_push_test.cpp @@ -42,6 +42,7 @@ #include "mongo/db/bson/dotted_path_support.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" @@ -53,6 +54,7 @@ using mongo::BSONObj; using mongo::BSONObjBuilder; using mongo::BSONArrayBuilder; using mongo::CollatorInterfaceMock; +using mongo::ExpressionContextForTest; using mongo::fromjson; using mongo::LogBuilder; using mongo::ModifierInterface; @@ -165,8 +167,9 @@ void combineAndSortVec(const vector<BSONObj>& origVec, TEST(Init, SimplePush) { BSONObj modObj = fromjson("{$push: {x: 0}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } // @@ -176,46 +179,52 @@ TEST(Init, SimplePush) { TEST(Init, PushEachNormal) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, 2]}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachMixed) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, {a: 2}]}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachObject) { // $each must be an array BSONObj modObj = fromjson("{$push: {x: {$each: {'0': 1}}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachSimpleType) { // $each must be an array. BSONObj modObj = fromjson("{$push: {x: {$each: 1}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachEmpty) { BSONObj modObj = fromjson("{$push: {x: {$each: []}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachInvalidType) { // $each must be an array. BSONObj modObj = fromjson("{$push: {x: {$each: {b: 1}}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } // @@ -225,50 +234,57 @@ TEST(Init, PushEachInvalidType) { TEST(Init, PushEachWithSliceBottom) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, 2], $slice: -3}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithSliceTop) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, 2], $slice: 3}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithInvalidSliceObject) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, 2], $slice: {a: 1}}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithInvalidSliceDouble) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, 2], $slice: -2.1}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithValidSliceDouble) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, 2], $slice: -2.0}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithUnsupportedFullSlice) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, 2], $slice: [1,2]}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithWrongTypeSlice) { BSONObj modObj = fromjson("{$push: {x: {$each: [1, 2], $slice: '-1'}}}"); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } // @@ -279,88 +295,99 @@ TEST(Init, PushEachWithObjectSort) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: {a:1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithNumbericSort) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort:1 }}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithInvalidSortType) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: [{a:1}]}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachDuplicateSortPattern) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: [{a:1,a:1}]}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithInvalidSortValue) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: {a:100}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithEmptySortField) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: {'':1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithEmptyDottedSortField) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: {'.':1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithMissingSortFieldSuffix) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: {'a.':1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithMissingSortFieldPreffix) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: {'.b':1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithMissingSortFieldMiddle) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: {'a..b':1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithEmptySort) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort:{} }}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } // @@ -371,64 +398,72 @@ TEST(Init, PushEachWithSortMissingSlice) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $sort:{a:1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachInvalidClause) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $xxx: -1, $sort:{a:1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachExtraField) { const char* c = "{$push: {x: {$each: [{a:1},{a:2}], $slice: -2.0, $sort: {a:1}, b: 1}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachDuplicateSortClause) { const char* c = "{$push: {x:{$each:[{a:1},{a:2}], $slice:-2.0, $sort:{a:1}, $sort:{a:1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachDuplicateSliceClause) { const char* c = "{$push: {x: {$each:[{a:1},{a:2}], $slice:-2.0, $slice:-2, $sort:{a:1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachDuplicateEachClause) { const char* c = "{$push: {x: {$each:[{a:1}], $each:[{a:2}], $slice:-3, $sort:{a:1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithSliceFirst) { const char* c = "{$push: {x: {$slice: -2.0, $each: [{a:1},{a:2}], $sort: {a:1}}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } TEST(Init, PushEachWithSortFirst) { const char* c = "{$push: {x: {$sort: {a:1}, $slice: -2.0, $each: [{a:1},{a:2}]}}}"; BSONObj modObj = fromjson(c); ModifierPush mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(mod.init(modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } // @@ -441,7 +476,8 @@ public: Mod() : _mod() {} explicit Mod(BSONObj modObj, - ModifierInterface::Options options = ModifierInterface::Options::normal()) + ModifierInterface::Options options = + ModifierInterface::Options::normal(new ExpressionContextForTest())) : _mod() { _modObj = modObj; StringData modName = modObj.firstElement().fieldName(); @@ -904,8 +940,10 @@ TEST(SortPushEach, MixedSortEmbeddedField) { TEST(SortPushEach, SortRespectsCollationFromOptions) { Document doc(fromjson("{a: ['dd', 'fc', 'gb'] }")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); Mod pushMod(fromjson("{$push: {a: {$each: ['ha'], $sort: 1}}}"), - ModifierInterface::Options::normal(&collator)); + ModifierInterface::Options::normal(expCtx)); const BSONObj expectedObj = fromjson("{a: ['ha', 'gb', 'fc', 'dd']}"); ModifierInterface::ExecInfo execInfo; @@ -967,8 +1005,9 @@ public: _modObj = BSON("$push" << BSON("a" << BSON("$each" << arrBuilder.arr() << "$slice" << slice))); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(_mod.init(_modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } /** Sets up the mod to be {$push: {a: {$each:[<Obj>,...], $slice:<slice>, $sort:<Obj>}}} */ @@ -982,8 +1021,9 @@ public: "$push" << BSON( "a" << BSON("$each" << arrBuilder.arr() << "$slice" << slice << "$sort" << sort))); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_OK(_mod.init(_modObj["$push"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } /** Returns an object {a: [<'vec's content>]} */ @@ -1190,6 +1230,8 @@ TEST_F(SlicedMod, ObjectArrayFromExisting) { // Push to position tests TEST(ToPosition, BadInputs) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const char* const bad[] = { "{$push: {a: { $each: [1], $position:'s'}}}", "{$push: {a: { $each: [1], $position:{}}}}", @@ -1209,7 +1251,7 @@ TEST(ToPosition, BadInputs) { ModifierPush pushMod; BSONObj modObj = fromjson(bad[i]); ASSERT_NOT_OK(pushMod.init(modObj.firstElement().embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); i++; } } diff --git a/src/mongo/db/ops/modifier_rename_test.cpp b/src/mongo/db/ops/modifier_rename_test.cpp index fc1c4ee108d..b13337430f2 100644 --- a/src/mongo/db/ops/modifier_rename_test.cpp +++ b/src/mongo/db/ops/modifier_rename_test.cpp @@ -37,13 +37,13 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace mongo { using mutablebson::ConstElement; -using mutablebson::Document; using mutablebson::Element; /** Helper to build and manipulate the mod. */ @@ -54,7 +54,7 @@ public: explicit Mod(BSONObj modObj) { _modObj = modObj; ASSERT_OK(_mod.init(_modObj["$rename"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(new ExpressionContextForTest()))); } Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) { @@ -86,55 +86,57 @@ private: */ TEST(InvalidInit, FromDbTests) { ModifierRename mod; - ASSERT_NOT_OK( - mod.init(fromjson("{'a.$':'b'}").firstElement(), ModifierInterface::Options::normal())); - ASSERT_NOT_OK( - mod.init(fromjson("{'a':'b.$'}").firstElement(), ModifierInterface::Options::normal())); - ASSERT_NOT_OK( - mod.init(fromjson("{'.b':'a'}").firstElement(), ModifierInterface::Options::normal())); - ASSERT_NOT_OK( - mod.init(fromjson("{'b.':'a'}").firstElement(), ModifierInterface::Options::normal())); - ASSERT_NOT_OK( - mod.init(fromjson("{'b':'.a'}").firstElement(), ModifierInterface::Options::normal())); - ASSERT_NOT_OK( - mod.init(fromjson("{'b':'a.'}").firstElement(), ModifierInterface::Options::normal())); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(mod.init(fromjson("{'a.$':'b'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); + ASSERT_NOT_OK(mod.init(fromjson("{'a':'b.$'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); + ASSERT_NOT_OK(mod.init(fromjson("{'.b':'a'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); + ASSERT_NOT_OK(mod.init(fromjson("{'b.':'a'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); + ASSERT_NOT_OK(mod.init(fromjson("{'b':'.a'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); + ASSERT_NOT_OK(mod.init(fromjson("{'b':'a.'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); } TEST(InvalidInit, ToFieldCannotContainEmbeddedNullByte) { ModifierRename mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); { const auto embeddedNull = "a\0b"_sd; ASSERT_NOT_OK(mod.init(BSON("a" << embeddedNull).firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } { const auto singleNullByte = "\0"_sd; ASSERT_NOT_OK(mod.init(BSON("a" << singleNullByte).firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } { const auto leadingNullByte = "\0bbbb"_sd; ASSERT_NOT_OK(mod.init(BSON("a" << leadingNullByte).firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } { const auto trailingNullByte = "bbbb\0"_sd; ASSERT_NOT_OK(mod.init(BSON("a" << trailingNullByte).firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } } TEST(MissingFrom, InitPrepLog) { - Document doc(fromjson("{a: 2}")); + mutablebson::Document doc(fromjson("{a: 2}")); Mod setMod(fromjson("{$rename: {'b':'a'}}")); ModifierInterface::ExecInfo execInfo; ASSERT_OK(setMod.prepare(doc.root(), "", &execInfo)); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -142,14 +144,14 @@ TEST(MissingFrom, InitPrepLog) { } TEST(MissingFromDotted, InitPrepLog) { - Document doc(fromjson("{a: {r:2}}")); + mutablebson::Document doc(fromjson("{a: {r:2}}")); Mod setMod(fromjson("{$rename: {'a.b':'a.c'}}")); ModifierInterface::ExecInfo execInfo; ASSERT_OK(setMod.prepare(doc.root(), "", &execInfo)); ASSERT_TRUE(execInfo.noOp); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -157,30 +159,33 @@ TEST(MissingFromDotted, InitPrepLog) { } TEST(BasicInit, DifferentRoots) { - Document doc(fromjson("{a: 2}")); + mutablebson::Document doc(fromjson("{a: 2}")); Mod setMod(fromjson("{$rename: {'a':'f.g'}}")); } TEST(MoveOnSamePath, MoveUp) { ModifierRename mod; - ASSERT_NOT_OK( - mod.init(fromjson("{'b.a':'b'}").firstElement(), ModifierInterface::Options::normal())); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(mod.init(fromjson("{'b.a':'b'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); } TEST(MoveOnSamePath, MoveDown) { ModifierRename mod; - ASSERT_NOT_OK( - mod.init(fromjson("{'b':'b.a'}").firstElement(), ModifierInterface::Options::normal())); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(mod.init(fromjson("{'b':'b.a'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); } TEST(MoveOnSamePath, MoveToSelf) { ModifierRename mod; - ASSERT_NOT_OK( - mod.init(fromjson("{'b.a':'b.a'}").firstElement(), ModifierInterface::Options::normal())); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_NOT_OK(mod.init(fromjson("{'b.a':'b.a'}").firstElement(), + ModifierInterface::Options::normal(expCtx))); } TEST(MissingTo, SimpleNumberAtRoot) { - Document doc(fromjson("{a: 2}")); + mutablebson::Document doc(fromjson("{a: 2}")); Mod setMod(fromjson("{$rename: {'a':'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -194,7 +199,7 @@ TEST(MissingTo, SimpleNumberAtRoot) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{b:2}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'b': 2}, $unset: {'a': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -202,7 +207,7 @@ TEST(MissingTo, SimpleNumberAtRoot) { } TEST(SimpleReplace, SameLevel) { - Document doc(fromjson("{a: 2, b: 1}")); + mutablebson::Document doc(fromjson("{a: 2, b: 1}")); Mod setMod(fromjson("{$rename: {'a':'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -216,7 +221,7 @@ TEST(SimpleReplace, SameLevel) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{b:2}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'b': 2}, $unset: {'a': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -224,7 +229,7 @@ TEST(SimpleReplace, SameLevel) { } TEST(SimpleReplace, FromDottedElement) { - Document doc(fromjson("{a: {c: {d: 6}}, b: 1}")); + mutablebson::Document doc(fromjson("{a: {c: {d: 6}}, b: 1}")); Mod setMod(fromjson("{$rename: {'a.c':'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -238,7 +243,7 @@ TEST(SimpleReplace, FromDottedElement) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{a: {}, b:{ d: 6}}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'b': {d: 6}}, $unset: {'a.c': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -246,7 +251,7 @@ TEST(SimpleReplace, FromDottedElement) { } TEST(SimpleReplace, RenameToExistingFieldDoesNotReorderFields) { - Document doc(fromjson("{a: 1, b: 2, c: 3}")); + mutablebson::Document doc(fromjson("{a: 1, b: 2, c: 3}")); Mod setMod(fromjson("{$rename: {a: 'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -259,7 +264,7 @@ TEST(SimpleReplace, RenameToExistingFieldDoesNotReorderFields) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{b: 1, c: 3}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set: {b: 1}, $unset: {a: true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -267,7 +272,7 @@ TEST(SimpleReplace, RenameToExistingFieldDoesNotReorderFields) { } TEST(SimpleReplace, RenameToExistingNestedFieldDoesNotReorderFields) { - Document doc(fromjson("{a: {b: {c: 1, d: 2}}, b: 3, c: {d: 4}}")); + mutablebson::Document doc(fromjson("{a: {b: {c: 1, d: 2}}, b: 3, c: {d: 4}}")); Mod setMod(fromjson("{$rename: {'c.d': 'a.b.c'}}")); ModifierInterface::ExecInfo execInfo; @@ -280,7 +285,7 @@ TEST(SimpleReplace, RenameToExistingNestedFieldDoesNotReorderFields) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{a: {b: {c: 4, d: 2}}, b: 3, c: {}}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set: {'a.b.c': 4}, $unset: {'c.d': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -288,7 +293,7 @@ TEST(SimpleReplace, RenameToExistingNestedFieldDoesNotReorderFields) { } TEST(DottedTo, MissingCompleteTo) { - Document doc(fromjson("{a: 2, b: 1, c: {}}")); + mutablebson::Document doc(fromjson("{a: 2, b: 1, c: {}}")); Mod setMod(fromjson("{$rename: {'a':'c.r.d'}}")); ModifierInterface::ExecInfo execInfo; @@ -302,7 +307,7 @@ TEST(DottedTo, MissingCompleteTo) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{b:1, c: { r: { d: 2}}}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'c.r.d': 2}, $unset: {'a': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -310,7 +315,7 @@ TEST(DottedTo, MissingCompleteTo) { } TEST(DottedTo, ToIsCompletelyMissing) { - Document doc(fromjson("{a: 2}")); + mutablebson::Document doc(fromjson("{a: 2}")); Mod setMod(fromjson("{$rename: {'a':'b.c.d'}}")); ModifierInterface::ExecInfo execInfo; @@ -324,7 +329,7 @@ TEST(DottedTo, ToIsCompletelyMissing) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{b: {c: {d: 2}}}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'b.c.d': 2}, $unset: {'a': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -332,7 +337,7 @@ TEST(DottedTo, ToIsCompletelyMissing) { } TEST(FromArrayOfEmbeddedDocs, ToMissingDottedField) { - Document doc(fromjson("{a: [ {a:2, b:1} ] }")); + mutablebson::Document doc(fromjson("{a: [ {a:2, b:1} ] }")); Mod setMod(fromjson("{$rename: {'a':'b.c.d'}}")); ModifierInterface::ExecInfo execInfo; @@ -346,7 +351,7 @@ TEST(FromArrayOfEmbeddedDocs, ToMissingDottedField) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{b: {c: {d: [ {a:2, b:1} ]}}}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'b.c.d': [ {a:2, b:1} ]}, $unset: {'a': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -354,7 +359,7 @@ TEST(FromArrayOfEmbeddedDocs, ToMissingDottedField) { } TEST(FromArrayOfEmbeddedDocs, ToArray) { - Document doc(fromjson("{a: [ {a:2, b:1} ] }")); + mutablebson::Document doc(fromjson("{a: [ {a:2, b:1} ] }")); Mod setMod(fromjson("{$rename: {'a.a':'a.b'}}")); ModifierInterface::ExecInfo execInfo; @@ -362,7 +367,7 @@ TEST(FromArrayOfEmbeddedDocs, ToArray) { } TEST(Arrays, MoveInto) { - Document doc(fromjson("{a: [1, 2], b:2}")); + mutablebson::Document doc(fromjson("{a: [1, 2], b:2}")); Mod setMod(fromjson("{$rename: {'b':'a.2'}}")); ModifierInterface::ExecInfo execInfo; @@ -370,7 +375,7 @@ TEST(Arrays, MoveInto) { } TEST(Arrays, MoveOut) { - Document doc(fromjson("{a: [1, 2]}")); + mutablebson::Document doc(fromjson("{a: [1, 2]}")); Mod setMod(fromjson("{$rename: {'a.0':'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -378,7 +383,7 @@ TEST(Arrays, MoveOut) { } TEST(Arrays, MoveNonexistantEmbeddedFieldOut) { - Document doc(fromjson("{a: [{a:1}, {b:2}]}")); + mutablebson::Document doc(fromjson("{a: [{a:1}, {b:2}]}")); Mod setMod(fromjson("{$rename: {'a.a':'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -386,7 +391,7 @@ TEST(Arrays, MoveNonexistantEmbeddedFieldOut) { } TEST(Arrays, MoveEmbeddedFieldOutWithElementNumber) { - Document doc(fromjson("{a: [{a:1}, {b:2}]}")); + mutablebson::Document doc(fromjson("{a: [{a:1}, {b:2}]}")); Mod setMod(fromjson("{$rename: {'a.0.a':'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -394,7 +399,7 @@ TEST(Arrays, MoveEmbeddedFieldOutWithElementNumber) { } TEST(Arrays, ReplaceArrayField) { - Document doc(fromjson("{a: 2, b: []}")); + mutablebson::Document doc(fromjson("{a: 2, b: []}")); Mod setMod(fromjson("{$rename: {'a':'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -408,7 +413,7 @@ TEST(Arrays, ReplaceArrayField) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{b:2}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'b': 2}, $unset: {'a': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -417,7 +422,7 @@ TEST(Arrays, ReplaceArrayField) { TEST(Arrays, ReplaceWithArrayField) { - Document doc(fromjson("{a: [], b: 2}")); + mutablebson::Document doc(fromjson("{a: [], b: 2}")); Mod setMod(fromjson("{$rename: {'a':'b'}}")); ModifierInterface::ExecInfo execInfo; @@ -431,7 +436,7 @@ TEST(Arrays, ReplaceWithArrayField) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{b:[]}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'b': []}, $unset: {'a': true}}"); ASSERT_OK(setMod.log(&logBuilder)); @@ -439,7 +444,7 @@ TEST(Arrays, ReplaceWithArrayField) { } TEST(LegacyData, CanRenameFromInvalidFieldName) { - Document doc(fromjson("{$a: 2}")); + mutablebson::Document doc(fromjson("{$a: 2}")); Mod setMod(fromjson("{$rename: {'$a':'a'}}")); ModifierInterface::ExecInfo execInfo; @@ -453,7 +458,7 @@ TEST(LegacyData, CanRenameFromInvalidFieldName) { ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(doc, fromjson("{a:2}")); - Document logDoc; + mutablebson::Document logDoc; LogBuilder logBuilder(logDoc.root()); BSONObj logObj = fromjson("{$set:{ 'a': 2}, $unset: {'$a': true}}"); ASSERT_OK(setMod.log(&logBuilder)); diff --git a/src/mongo/db/ops/modifier_set.cpp b/src/mongo/db/ops/modifier_set.cpp index fa0e11126c9..60f2fa07608 100644 --- a/src/mongo/db/ops/modifier_set.cpp +++ b/src/mongo/db/ops/modifier_set.cpp @@ -60,7 +60,7 @@ struct ModifierSet::PreparedState { }; ModifierSet::ModifierSet(ModifierSet::ModifierSetMode mode) - : _fieldRef(), _posDollar(0), _setMode(mode), _val(), _modOptions() {} + : _fieldRef(), _posDollar(0), _setMode(mode), _val() {} ModifierSet::~ModifierSet() {} @@ -100,7 +100,7 @@ Status ModifierSet::init(const BSONElement& modExpr, const Options& opts, bool* return Status(ErrorCodes::BadValue, "cannot $set an empty value"); _val = modExpr; - _modOptions = opts; + _fromOplogApplication = opts.fromOplogApplication; return Status::OK(); } @@ -133,7 +133,7 @@ Status ModifierSet::prepare(mutablebson::Element root, // proceed. if (status.code() == ErrorCodes::NonExistentPath) { _preparedState->elemFound = root.getDocument().end(); - } else if (_modOptions.fromOplogApplication && status.code() == ErrorCodes::PathNotViable) { + } else if (_fromOplogApplication && status.code() == ErrorCodes::PathNotViable) { // If we are applying an oplog entry and it is an invalid path, then push on indicating that // we had a blocking element, which we stopped at _preparedState->elemIsBlocking = true; @@ -211,7 +211,7 @@ Status ModifierSet::apply() const { } // Remove the blocking element, if we are from replication applier. See comment below. - if (_modOptions.fromOplogApplication && !destExists && _preparedState->elemFound.ok() && + if (_fromOplogApplication && !destExists && _preparedState->elemFound.ok() && _preparedState->elemIsBlocking && (!(_preparedState->elemFound.isType(Array)) || !(_preparedState->elemFound.isType(Object)))) { /** diff --git a/src/mongo/db/ops/modifier_set.h b/src/mongo/db/ops/modifier_set.h index 4363fa89933..cac403f50a6 100644 --- a/src/mongo/db/ops/modifier_set.h +++ b/src/mongo/db/ops/modifier_set.h @@ -97,8 +97,7 @@ private: // Element of the $set expression. BSONElement _val; - // See the class comments in modifier_interface.h - ModifierInterface::Options _modOptions; + bool _fromOplogApplication = false; // The instance of the field in the provided doc. This state is valid after a // prepare() was issued and until a log() is issued. The document this mod is diff --git a/src/mongo/db/ops/modifier_set_test.cpp b/src/mongo/db/ops/modifier_set_test.cpp index 45c26e495a2..f4ca9c86359 100644 --- a/src/mongo/db/ops/modifier_set_test.cpp +++ b/src/mongo/db/ops/modifier_set_test.cpp @@ -38,12 +38,14 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { using mongo::BSONObj; +using mongo::ExpressionContextForTest; using mongo::fromjson; using mongo::LogBuilder; using mongo::ModifierInterface; @@ -67,9 +69,10 @@ public: : ModifierSet::SET_NORMAL) { _modObj = modObj; StringData modName = modObj.firstElement().fieldName(); - ASSERT_OK(_mod.init(_modObj[modName].embeddedObject().firstElement(), - !fromRepl ? ModifierInterface::Options::normal() - : ModifierInterface::Options::fromRepl())); + ASSERT_OK(_mod.init( + _modObj[modName].embeddedObject().firstElement(), + !fromRepl ? ModifierInterface::Options::normal(new ExpressionContextForTest()) + : ModifierInterface::Options::fromRepl(new ExpressionContextForTest()))); } Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) { @@ -100,8 +103,9 @@ private: TEST(Init, EmptyOperation) { BSONObj modObj = fromjson("{$set: {}}"); ModifierSet mod; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ASSERT_NOT_OK(mod.init(modObj["$set"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(expCtx))); } // diff --git a/src/mongo/db/ops/modifier_unset_test.cpp b/src/mongo/db/ops/modifier_unset_test.cpp index dfffe5be383..a4f159e3347 100644 --- a/src/mongo/db/ops/modifier_unset_test.cpp +++ b/src/mongo/db/ops/modifier_unset_test.cpp @@ -38,6 +38,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" @@ -45,6 +46,7 @@ namespace { using mongo::Array; using mongo::BSONObj; +using mongo::ExpressionContextForTest; using mongo::fromjson; using mongo::LogBuilder; using mongo::ModifierInterface; @@ -62,7 +64,7 @@ public: explicit Mod(BSONObj modObj) { _modObj = modObj; ASSERT_OK(_mod.init(_modObj["$unset"].embeddedObject().firstElement(), - ModifierInterface::Options::normal())); + ModifierInterface::Options::normal(new ExpressionContextForTest()))); } Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) { diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index 576147bdcee..c3da51e352e 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -41,7 +41,10 @@ namespace mongo { ParsedUpdate::ParsedUpdate(OperationContext* opCtx, const UpdateRequest* request) - : _opCtx(opCtx), _request(request), _driver(UpdateDriver::Options()), _canonicalQuery() {} + : _opCtx(opCtx), + _request(request), + _driver(UpdateDriver::Options(new ExpressionContext(opCtx, nullptr))), + _canonicalQuery() {} Status ParsedUpdate::parseRequest() { // It is invalid to request that the UpdateStage return the prior or newly-updated version @@ -112,11 +115,11 @@ Status ParsedUpdate::parseQueryToCQ() { qr->setLimit(1); } - const boost::intrusive_ptr<ExpressionContext> expCtx; + boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(_opCtx, std::move(qr), - expCtx, + std::move(expCtx), extensionsCallback, MatchExpressionParser::kAllowAllSpecialFeatures & ~MatchExpressionParser::AllowedFeatures::kExpr); @@ -138,8 +141,9 @@ Status ParsedUpdate::parseUpdate() { !(_request->isFromOplogApplication() || ns.isConfigDB() || _request->isFromMigration()); _driver.setLogOp(true); + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(_opCtx, _collator.get())); _driver.setModOptions(ModifierInterface::Options( - _request->isFromOplogApplication(), shouldValidate, _collator.get())); + _request->isFromOplogApplication(), shouldValidate, std::move(expCtx))); return _driver.parse(_request->getUpdates(), _arrayFilters, _request->isMulti()); } @@ -156,7 +160,10 @@ Status ParsedUpdate::parseArrayFilters() { } for (auto rawArrayFilter : _request->getArrayFilters()) { - auto arrayFilterStatus = ExpressionWithPlaceholder::parse(rawArrayFilter, _collator.get()); + boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(_opCtx, _collator.get())); + auto arrayFilterStatus = + ExpressionWithPlaceholder::parse(rawArrayFilter, std::move(expCtx)); if (!arrayFilterStatus.isOK()) { return Status(arrayFilterStatus.getStatus().code(), str::stream() << "Error parsing array filter: " diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index 9c661c03925..8c5b31ab53a 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -108,8 +108,12 @@ UpdateResult update(OperationContext* opCtx, Database* db, const UpdateRequest& return UpdateStage::makeUpdateResult(updateStats); } -BSONObj applyUpdateOperators(const BSONObj& from, const BSONObj& operators) { - UpdateDriver::Options opts; +BSONObj applyUpdateOperators(OperationContext* opCtx, + const BSONObj& from, + const BSONObj& operators) { + const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, collator)); + UpdateDriver::Options opts(std::move(expCtx)); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; Status status = driver.parse(operators, arrayFilters); diff --git a/src/mongo/db/ops/update.h b/src/mongo/db/ops/update.h index 5b7f0a4e324..8555401cde9 100644 --- a/src/mongo/db/ops/update.h +++ b/src/mongo/db/ops/update.h @@ -56,5 +56,7 @@ UpdateResult update(OperationContext* opCtx, Database* db, const UpdateRequest& * applyUpdateOperators( BSON( "x" << 1 ) , BSON( "$inc" << BSON( "x" << 1 ) ) ); * returns: { x : 2 } */ -BSONObj applyUpdateOperators(const BSONObj& from, const BSONObj& operators); +BSONObj applyUpdateOperators(OperationContext* opCtx, + const BSONObj& from, + const BSONObj& operators); } // namespace mongo diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript index 4d249a56456..c15481279a2 100644 --- a/src/mongo/db/pipeline/SConscript +++ b/src/mongo/db/pipeline/SConscript @@ -156,9 +156,9 @@ env.CppUnitTest( 'document_source', 'document_source_facet', 'document_source_lookup', + 'document_source_mock', 'document_value_test_util', '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init', - '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/repl/oplog_entry', '$BUILD_DIR/mongo/db/repl/replmocks', '$BUILD_DIR/mongo/db/service_context', @@ -250,7 +250,6 @@ docSourceEnv.Library( 'document_source_list_sessions.cpp', 'document_source_match.cpp', 'document_source_merge_cursors.cpp', - 'document_source_mock.cpp', 'document_source_out.cpp', 'document_source_project.cpp', 'document_source_redact.cpp', @@ -291,6 +290,17 @@ docSourceEnv.Library( ) env.Library( + target='document_source_mock', + source=[ + 'document_source_mock.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/query_test_service_context', + 'document_source', + ] +) + +env.Library( target='lite_parsed_document_source', source=[ 'lite_parsed_document_source.cpp', @@ -353,10 +363,10 @@ env.CppUnitTest( source='document_source_facet_test.cpp', LIBDEPS=[ '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init', - '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/service_context_noop_init', '$BUILD_DIR/mongo/s/is_mongos', 'document_source_facet', + 'document_source_mock', 'document_value_test_util', ], ) @@ -369,6 +379,7 @@ env.CppUnitTest( '$BUILD_DIR/mongo/db/service_context_noop_init', '$BUILD_DIR/mongo/s/is_mongos', 'document_source_facet', + 'document_source_mock', 'document_value_test_util', ], ) @@ -389,6 +400,7 @@ env.CppUnitTest( source='accumulator_test.cpp', LIBDEPS=[ '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'accumulator', 'document_value_test_util', ], @@ -403,13 +415,13 @@ env.CppUnitTest( LIBDEPS=[ '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init', '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', - '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/repl/replmocks', '$BUILD_DIR/mongo/db/service_context', '$BUILD_DIR/mongo/db/service_context_noop_init', '$BUILD_DIR/mongo/s/is_mongos', 'document_value_test_util', 'document_source_lookup', + 'document_source_mock', 'pipeline', ], ) @@ -446,6 +458,7 @@ env.CppUnitTest( target='parsed_exclusion_projection_test', source='parsed_exclusion_projection_test.cpp', LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'document_value_test_util', 'parsed_aggregation_projection', ], @@ -455,6 +468,7 @@ env.CppUnitTest( target='parsed_aggregation_projection_test', source='parsed_aggregation_projection_test.cpp', LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'parsed_aggregation_projection', ], ) @@ -463,6 +477,7 @@ env.CppUnitTest( target='parsed_inclusion_projection_test', source='parsed_inclusion_projection_test.cpp', LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'document_value_test_util', 'parsed_aggregation_projection', ], @@ -475,6 +490,7 @@ env.CppUnitTest( 'granularity_rounder_preferred_numbers_test.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'document_value_test_util', 'granularity_rounder', ], @@ -484,6 +500,7 @@ env.CppUnitTest( target='parsed_add_fields_test', source='parsed_add_fields_test.cpp', LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'document_value_test_util', 'parsed_aggregation_projection', ], diff --git a/src/mongo/db/pipeline/accumulator_test.cpp b/src/mongo/db/pipeline/accumulator_test.cpp index 4ed1a6b486b..a50676d1734 100644 --- a/src/mongo/db/pipeline/accumulator_test.cpp +++ b/src/mongo/db/pipeline/accumulator_test.cpp @@ -213,8 +213,8 @@ TEST(Accumulators, Min) { TEST(Accumulators, MinRespectsCollation) { intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - expCtx->setCollator( - stdx::make_unique<CollatorInterfaceMock>(CollatorInterfaceMock::MockType::kReverseString)); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + expCtx->setCollator(&collator); assertExpectedResults("$min", expCtx, {{{Value("abc"_sd), Value("cba"_sd)}, Value("cba"_sd)}}); } @@ -239,8 +239,8 @@ TEST(Accumulators, Max) { TEST(Accumulators, MaxRespectsCollation) { intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - expCtx->setCollator( - stdx::make_unique<CollatorInterfaceMock>(CollatorInterfaceMock::MockType::kReverseString)); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + expCtx->setCollator(&collator); assertExpectedResults("$max", expCtx, {{{Value("abc"_sd), Value("cba"_sd)}, Value("abc"_sd)}}); } @@ -336,8 +336,8 @@ TEST(Accumulators, Sum) { TEST(Accumulators, AddToSetRespectsCollation) { intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - expCtx->setCollator( - stdx::make_unique<CollatorInterfaceMock>(CollatorInterfaceMock::MockType::kAlwaysEqual)); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + expCtx->setCollator(&collator); assertExpectedResults("$addToSet", expCtx, {{{Value("a"_sd), Value("b"_sd), Value("c"_sd)}, diff --git a/src/mongo/db/pipeline/aggregation_context_fixture.h b/src/mongo/db/pipeline/aggregation_context_fixture.h index b2b538159f0..b2833c5a70b 100644 --- a/src/mongo/db/pipeline/aggregation_context_fixture.h +++ b/src/mongo/db/pipeline/aggregation_context_fixture.h @@ -31,11 +31,7 @@ #include <boost/intrusive_ptr.hpp> #include <memory> -#include "mongo/db/client.h" #include "mongo/db/pipeline/expression_context_for_test.h" -#include "mongo/db/query/datetime/date_time_support.h" -#include "mongo/db/query/query_test_service_context.h" -#include "mongo/db/service_context_noop.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" @@ -49,21 +45,13 @@ public: AggregationContextFixture() : AggregationContextFixture(NamespaceString("unittests.pipeline_test")) {} - AggregationContextFixture(NamespaceString nss) - : _queryServiceContext(stdx::make_unique<QueryTestServiceContext>()), - _opCtx(_queryServiceContext->makeOperationContext()), - _expCtx(new ExpressionContextForTest(_opCtx.get(), AggregationRequest(nss, {}))) { - TimeZoneDatabase::set(_queryServiceContext->getServiceContext(), - stdx::make_unique<TimeZoneDatabase>()); - } + AggregationContextFixture(NamespaceString nss) : _expCtx(new ExpressionContextForTest(nss)) {} boost::intrusive_ptr<ExpressionContextForTest> getExpCtx() { return _expCtx.get(); } private: - std::unique_ptr<QueryTestServiceContext> _queryServiceContext; - ServiceContext::UniqueOperationContext _opCtx; boost::intrusive_ptr<ExpressionContextForTest> _expCtx; }; } // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp index efac859eed0..19f49a2b2a7 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp @@ -545,7 +545,7 @@ intrusive_ptr<DocumentSource> DocumentSourceGraphLookUp::createFromBson( // We don't need to keep ahold of the MatchExpression, but we do need to ensure that // the specified object is parseable and does not contain extensions. auto parsedMatchExpression = - MatchExpressionParser::parse(argument.embeddedObject(), nullptr); + MatchExpressionParser::parse(argument.embeddedObject(), expCtx); uassert(40186, str::stream() diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp index 5a954c63358..c3003eb1d68 100644 --- a/src/mongo/db/pipeline/document_source_match.cpp +++ b/src/mongo/db/pipeline/document_source_match.cpp @@ -371,7 +371,6 @@ void DocumentSourceMatch::joinMatchWith(intrusive_ptr<DocumentSourceMatch> other StatusWithMatchExpression status = uassertStatusOK( MatchExpressionParser::parse(_predicate, - pExpCtx->getCollator(), pExpCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kText | @@ -499,12 +498,8 @@ DocumentSourceMatch::DocumentSourceMatch(const BSONObj& query, _isTextQuery(isTextQuery(query)), _dependencies(_isTextQuery ? DepsTracker::MetadataAvailable::kTextScore : DepsTracker::MetadataAvailable::kNoMetadata) { - StatusWithMatchExpression status = - uassertStatusOK(MatchExpressionParser::parse(_predicate, - pExpCtx->getCollator(), - pExpCtx, - ExtensionsCallbackNoop(), - Pipeline::kAllowedMatcherFeatures)); + StatusWithMatchExpression status = uassertStatusOK(MatchExpressionParser::parse( + _predicate, pExpCtx, ExtensionsCallbackNoop(), Pipeline::kAllowedMatcherFeatures)); _expression = std::move(status.getValue()); getDependencies(&_dependencies); diff --git a/src/mongo/db/pipeline/document_source_match_test.cpp b/src/mongo/db/pipeline/document_source_match_test.cpp index b327f811cd1..a22eabc993d 100644 --- a/src/mongo/db/pipeline/document_source_match_test.cpp +++ b/src/mongo/db/pipeline/document_source_match_test.cpp @@ -521,7 +521,7 @@ DEATH_TEST_F(DocumentSourceMatchTest, const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a.b" << 1 << "b.c" << 1); const auto matchExpression = - unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx->getCollator())); + unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx)); DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); } @@ -531,7 +531,7 @@ DEATH_TEST_F(DocumentSourceMatchTest, const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a" << BSON("$elemMatch" << BSON("a.b" << 1))); const auto matchExpression = - unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx->getCollator())); + unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx)); BSONObjBuilder out; matchExpression->serialize(&out); DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); @@ -546,7 +546,7 @@ DEATH_TEST_F(DocumentSourceMatchTest, const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a" << BSON("$elemMatch" << BSON("$gt" << 0))); const auto matchExpression = - unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx->getCollator())); + unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx)); DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); } @@ -554,7 +554,7 @@ TEST_F(DocumentSourceMatchTest, ShouldMatchCorrectlyAfterDescendingMatch) { const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a.b" << 1 << "a.c" << 1 << "a.d" << 1); const auto matchExpression = - unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx->getCollator())); + unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx)); const auto descendedMatch = DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); diff --git a/src/mongo/db/pipeline/expression_context.cpp b/src/mongo/db/pipeline/expression_context.cpp index db80c5f7234..37c2f957983 100644 --- a/src/mongo/db/pipeline/expression_context.cpp +++ b/src/mongo/db/pipeline/expression_context.cpp @@ -43,35 +43,40 @@ ExpressionContext::ExpressionContext(OperationContext* opCtx, const AggregationRequest& request, std::unique_ptr<CollatorInterface> collator, StringMap<ResolvedNamespace> resolvedNamespaces) - : explain(request.getExplain()), - fromMongos(request.isFromMongos()), - needsMerge(request.needsMerge()), - allowDiskUse(request.shouldAllowDiskUse()), - bypassDocumentValidation(request.shouldBypassDocumentValidation()), - from34Mongos(request.isFrom34Mongos()), - ns(request.getNamespaceString()), - opCtx(opCtx), - collation(request.getCollation()), + : ExpressionContext(opCtx, collator.get()) { + explain = request.getExplain(); + fromMongos = request.isFromMongos(); + needsMerge = request.needsMerge(); + allowDiskUse = request.shouldAllowDiskUse(); + bypassDocumentValidation = request.shouldBypassDocumentValidation(); + from34Mongos = request.isFrom34Mongos(); + ns = request.getNamespaceString(); + collation = request.getCollation(); + _ownedCollator = std::move(collator); + _resolvedNamespaces = std::move(resolvedNamespaces); +} +ExpressionContext::ExpressionContext(OperationContext* opCtx, const CollatorInterface* collator) + : opCtx(opCtx), variablesParseState(variables.useIdGenerator()), - _collator(std::move(collator)), - _documentComparator(_collator.get()), - _valueComparator(_collator.get()), - _resolvedNamespaces(std::move(resolvedNamespaces)) {} + _collator(collator), + _documentComparator(_collator), + _valueComparator(_collator) {} void ExpressionContext::checkForInterrupt() { // This check could be expensive, at least in relative terms, so don't check every time. if (--_interruptCounter == 0) { + invariant(opCtx); opCtx->checkForInterrupt(); _interruptCounter = kInterruptCheckPeriod; } } -void ExpressionContext::setCollator(std::unique_ptr<CollatorInterface> coll) { - _collator = std::move(coll); +void ExpressionContext::setCollator(const CollatorInterface* collator) { + _collator = collator; // Document/Value comparisons must be aware of the collation. - _documentComparator = DocumentComparator(_collator.get()); - _valueComparator = ValueComparator(_collator.get()); + _documentComparator = DocumentComparator(_collator); + _valueComparator = ValueComparator(_collator); } intrusive_ptr<ExpressionContext> ExpressionContext::copyWith(NamespaceString ns, @@ -92,8 +97,10 @@ intrusive_ptr<ExpressionContext> ExpressionContext::copyWith(NamespaceString ns, expCtx->opCtx = opCtx; expCtx->collation = collation; - if (_collator) { - expCtx->setCollator(_collator->clone()); + if (_ownedCollator) { + expCtx->setCollator(_ownedCollator->clone()); + } else if (_collator) { + expCtx->setCollator(_collator); } expCtx->_resolvedNamespaces = _resolvedNamespaces; diff --git a/src/mongo/db/pipeline/expression_context.h b/src/mongo/db/pipeline/expression_context.h index d580644eeba..0e7488aaa55 100644 --- a/src/mongo/db/pipeline/expression_context.h +++ b/src/mongo/db/pipeline/expression_context.h @@ -70,15 +70,23 @@ public: StringMap<ExpressionContext::ResolvedNamespace> resolvedNamespaces); /** + * Constructs an ExpressionContext to be used for MatchExpression parsing outside of the context + * of aggregation. + */ + ExpressionContext(OperationContext* opCtx, const CollatorInterface* collator); + + /** * Used by a pipeline to check for interrupts so that killOp() works. Throws a UserAssertion if * this aggregation pipeline has been interrupted. */ void checkForInterrupt(); const CollatorInterface* getCollator() const { - return _collator.get(); + return _collator; } + void setCollator(const CollatorInterface* collator); + const DocumentComparator& getDocumentComparator() const { return _documentComparator; } @@ -148,15 +156,23 @@ protected: : ns(std::move(nss)), variablesParseState(variables.useIdGenerator()) {} /** - * Sets '_collator' and resets '_documentComparator' and '_valueComparator'. + * Sets '_ownedCollator' and resets '_collator', 'documentComparator' and 'valueComparator'. * - * Use with caution - it is illegal to change the collation once a Pipeline has been parsed with - * this ExpressionContext. + * Use with caution - '_ownedCollator' is used in the context of a Pipeline, and it is illegal + * to change the collation once a Pipeline has been parsed with this ExpressionContext. */ - void setCollator(std::unique_ptr<CollatorInterface> collator); + void setCollator(std::unique_ptr<CollatorInterface> collator) { + _ownedCollator = std::move(collator); + setCollator(_ownedCollator.get()); + } + + // Collator used for comparisons. This is owned in the context of a Pipeline. + // TODO SERVER-31294: Move ownership of an aggregation's collator elsewhere. + std::unique_ptr<CollatorInterface> _ownedCollator; - // Collator used for comparisons. - std::unique_ptr<CollatorInterface> _collator; + // Collator used for comparisons. If '_ownedCollator' is non-null, then this must point to the + // same collator object. + const CollatorInterface* _collator = nullptr; // Used for all comparisons of Document/Value during execution of the aggregation operation. // Must not be changed after parsing a Pipeline with this ExpressionContext. diff --git a/src/mongo/db/pipeline/expression_context_for_test.h b/src/mongo/db/pipeline/expression_context_for_test.h index 542e5b91eea..b54bb82094f 100644 --- a/src/mongo/db/pipeline/expression_context_for_test.h +++ b/src/mongo/db/pipeline/expression_context_for_test.h @@ -29,38 +29,42 @@ #pragma once #include "mongo/db/pipeline/expression_context.h" +#include "mongo/db/query/datetime/date_time_support.h" +#include "mongo/db/query/query_test_service_context.h" namespace mongo { /** - * An ExpressionContext that can have state like the collation and resolved namespace map - * manipulated after construction. In contrast, a regular ExpressionContext requires the collation - * and resolved namespaces to be provided on construction and does not allow them to be subsequently + * An ExpressionContext with a default OperationContext that can have state (like the resolved + * namespace map) manipulated after construction. In contrast, a regular ExpressionContext requires + * the resolved namespaces to be provided on construction and does not allow them to be subsequently * mutated. */ class ExpressionContextForTest : public ExpressionContext { public: - ExpressionContextForTest() : ExpressionContext(NamespaceString{"test"_sd, "namespace"_sd}) {} + ExpressionContextForTest() + : ExpressionContextForTest(NamespaceString{"test"_sd, "namespace"_sd}) {} - ExpressionContextForTest(NamespaceString nss) : ExpressionContext(std::move(nss)) {} + ExpressionContextForTest(NamespaceString nss) + : ExpressionContext(std::move(nss)), _testOpCtx(_serviceContext.makeOperationContext()) { + TimeZoneDatabase::set(_serviceContext.getServiceContext(), + stdx::make_unique<TimeZoneDatabase>()); + opCtx = _testOpCtx.get(); + } ExpressionContextForTest(OperationContext* opCtx, const AggregationRequest& request) : ExpressionContext(opCtx, request, nullptr, {}) {} /** - * Changes the collation used by this ExpressionContext. Must not be changed after parsing a - * Pipeline with this ExpressionContext. - */ - void setCollator(std::unique_ptr<CollatorInterface> collator) { - ExpressionContext::setCollator(std::move(collator)); - } - - /** * Sets the resolved definition for an involved namespace. */ void setResolvedNamespace(const NamespaceString& nss, ResolvedNamespace resolvedNamespace) { _resolvedNamespaces[nss.coll()] = std::move(resolvedNamespace); } + +private: + QueryTestServiceContext _serviceContext; + ServiceContext::UniqueOperationContext _testOpCtx; }; } // namespace mongo diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index f3b5fd2546c..6a0d30887b6 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -73,7 +73,6 @@ env.Library( "internal_plans", "query_common", "query_planner", - "query_planner_test_lib", '$BUILD_DIR/mongo/db/catalog/collection', '$BUILD_DIR/mongo/db/catalog/database', '$BUILD_DIR/mongo/db/catalog/index_catalog', @@ -279,7 +278,6 @@ env.Library( ], LIBDEPS=[ "query_planner_test_lib", - "query_test_service_context", "$BUILD_DIR/mongo/unittest/unittest", ], ) @@ -292,6 +290,7 @@ env.Library( LIBDEPS=[ "collation/collator_factory_mock", "query_planner", + "query_test_service_context", ], ) @@ -325,6 +324,7 @@ env.CppUnitTest( LIBDEPS=[ "collation/collator_interface_mock", "index_bounds", + "query_test_service_context", ], ) @@ -366,6 +366,7 @@ env.CppUnitTest( ], LIBDEPS=[ "query_planner", + "query_test_service_context", ], ) @@ -388,6 +389,7 @@ env.CppUnitTest( LIBDEPS=[ "collation/collator_interface_mock", "query_planner", + "query_test_service_context", ], ) @@ -409,6 +411,7 @@ env.CppUnitTest( LIBDEPS=[ "collation/collator_interface_mock", "query_planner", + "query_test_service_context", ], ) @@ -435,6 +438,7 @@ env.CppUnitTest( LIBDEPS=[ "collation/collator_factory_mock", "query_planner", + "query_test_service_context", ], ) diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index 1df80364b65..515ba518658 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -147,8 +147,14 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( } // Make MatchExpression. + boost::intrusive_ptr<ExpressionContext> newExpCtx; + if (!expCtx.get()) { + newExpCtx.reset(new ExpressionContext(opCtx, collator.get())); + } else { + newExpCtx = expCtx; + } StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - qr->getFilter(), collator.get(), expCtx, extensionsCallback, allowedFeatures); + qr->getFilter(), newExpCtx, extensionsCallback, allowedFeatures); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } @@ -158,7 +164,8 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery()); Status initStatus = - cq->init(std::move(qr), + cq->init(opCtx, + std::move(qr), parsingCanProduceNoopMatchNodes(extensionsCallback, allowedFeatures), me.release(), std::move(collator)); @@ -192,7 +199,8 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( // Make the CQ we'll hopefully return. std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery()); - Status initStatus = cq->init(std::move(qr), + Status initStatus = cq->init(opCtx, + std::move(qr), baseQuery.canHaveNoopMatchNodes(), root->shallowClone().release(), std::move(collator)); @@ -203,7 +211,8 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( return std::move(cq); } -Status CanonicalQuery::init(std::unique_ptr<QueryRequest> qr, +Status CanonicalQuery::init(OperationContext* opCtx, + std::unique_ptr<QueryRequest> qr, bool canHaveNoopMatchNodes, MatchExpression* root, std::unique_ptr<CollatorInterface> collator) { @@ -226,7 +235,7 @@ Status CanonicalQuery::init(std::unique_ptr<QueryRequest> qr, // Validate the projection if there is one. if (!_qr->getProj().isEmpty()) { ParsedProjection* pp; - Status projStatus = ParsedProjection::make(_qr->getProj(), _root.get(), &pp); + Status projStatus = ParsedProjection::make(opCtx, _qr->getProj(), _root.get(), &pp); if (!projStatus.isOK()) { return projStatus; } diff --git a/src/mongo/db/query/canonical_query.h b/src/mongo/db/query/canonical_query.h index 392c75ca704..eb3d077c6ca 100644 --- a/src/mongo/db/query/canonical_query.h +++ b/src/mongo/db/query/canonical_query.h @@ -190,7 +190,8 @@ private: // You must go through canonicalize to create a CanonicalQuery. CanonicalQuery() {} - Status init(std::unique_ptr<QueryRequest> qr, + Status init(OperationContext* opCtx, + std::unique_ptr<QueryRequest> qr, bool canHaveNoopMatchNodes, MatchExpression* root, std::unique_ptr<CollatorInterface> collator); diff --git a/src/mongo/db/query/canonical_query_test.cpp b/src/mongo/db/query/canonical_query_test.cpp index 04048242c64..1ab63a0c16f 100644 --- a/src/mongo/db/query/canonical_query_test.cpp +++ b/src/mongo/db/query/canonical_query_test.cpp @@ -54,12 +54,10 @@ static const NamespaceString nss("testdb.testcoll"); * and return the MatchExpression*. */ MatchExpression* parseMatchExpression(const BSONObj& obj) { - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression status = MatchExpressionParser::parse(obj, - collator, - expCtx, + std::move(expCtx), ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); if (!status.isOK()) { diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 0560aa907f3..cf241557d19 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -662,7 +662,7 @@ StatusWith<unique_ptr<PlanStage>> applyProjection(OperationContext* opCtx, invariant(!proj.isEmpty()); ParsedProjection* rawParsedProj; - Status ppStatus = ParsedProjection::make(proj.getOwned(), cq->root(), &rawParsedProj); + Status ppStatus = ParsedProjection::make(opCtx, proj.getOwned(), cq->root(), &rawParsedProj); if (!ppStatus.isOK()) { return ppStatus; } diff --git a/src/mongo/db/query/index_bounds_builder_test.cpp b/src/mongo/db/query/index_bounds_builder_test.cpp index ec85f567ae1..f7d0e23794e 100644 --- a/src/mongo/db/query/index_bounds_builder_test.cpp +++ b/src/mongo/db/query/index_bounds_builder_test.cpp @@ -35,6 +35,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/expression_index.h" #include "mongo/unittest/unittest.h" @@ -58,8 +59,8 @@ double NaN = numeric_limits<double>::quiet_NaN(); * Utility function to create MatchExpression */ MatchExpression* parseMatchExpression(const BSONObj& obj) { - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, std::move(expCtx)); 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 575c5d5dff5..069ff5a235e 100644 --- a/src/mongo/db/query/parsed_projection.cpp +++ b/src/mongo/db/query/parsed_projection.cpp @@ -46,7 +46,8 @@ using std::string; * Returns a Status indicating how it's invalid otherwise. */ // static -Status ParsedProjection::make(const BSONObj& spec, +Status ParsedProjection::make(OperationContext* opCtx, + const BSONObj& spec, const MatchExpression* const query, ParsedProjection** out) { // Whether we're including or excluding fields. @@ -129,8 +130,10 @@ Status ParsedProjection::make(const BSONObj& spec, // Match expression extensions such as $text, $where, $geoNear, $near, $nearSphere, // and $expr are not allowed in $elemMatch projections. const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx, collator)); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(elemMatchObj, collator); + MatchExpressionParser::parse(elemMatchObj, std::move(expCtx)); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } diff --git a/src/mongo/db/query/parsed_projection.h b/src/mongo/db/query/parsed_projection.h index 2f273c5d303..82544e82c47 100644 --- a/src/mongo/db/query/parsed_projection.h +++ b/src/mongo/db/query/parsed_projection.h @@ -45,7 +45,8 @@ public: * Returns Status::OK() if it's a valid spec. * Returns a Status indicating how it's invalid otherwise. */ - static Status make(const BSONObj& spec, + static Status make(OperationContext* opCtx, + const BSONObj& spec, const MatchExpression* const query, ParsedProjection** out); diff --git a/src/mongo/db/query/parsed_projection_test.cpp b/src/mongo/db/query/parsed_projection_test.cpp index 22046f8b531..e184cef3d6a 100644 --- a/src/mongo/db/query/parsed_projection_test.cpp +++ b/src/mongo/db/query/parsed_projection_test.cpp @@ -31,6 +31,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_always_boolean.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/query/query_test_service_context.h" #include "mongo/unittest/unittest.h" #include <memory> @@ -47,12 +48,17 @@ using namespace mongo; // unique_ptr<ParsedProjection> createParsedProjection(const BSONObj& query, const BSONObj& projObj) { + QueryTestServiceContext serviceCtx; + auto opCtx = serviceCtx.makeOperationContext(); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(query, collator); + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx.get(), collator)); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(query, std::move(expCtx)); ASSERT(statusWithMatcher.isOK()); std::unique_ptr<MatchExpression> queryMatchExpr = std::move(statusWithMatcher.getValue()); ParsedProjection* out = NULL; - Status status = ParsedProjection::make(projObj, queryMatchExpr.get(), &out); + Status status = ParsedProjection::make(opCtx.get(), projObj, queryMatchExpr.get(), &out); if (!status.isOK()) { FAIL(mongoutils::str::stream() << "failed to parse projection " << projObj << " (query: " << query @@ -76,12 +82,17 @@ unique_ptr<ParsedProjection> createParsedProjection(const char* queryStr, const void assertInvalidProjection(const char* queryStr, const char* projStr) { BSONObj query = fromjson(queryStr); BSONObj projObj = fromjson(projStr); + QueryTestServiceContext serviceCtx; + auto opCtx = serviceCtx.makeOperationContext(); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(query, collator); + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx.get(), collator)); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(query, std::move(expCtx)); ASSERT(statusWithMatcher.isOK()); std::unique_ptr<MatchExpression> queryMatchExpr = std::move(statusWithMatcher.getValue()); ParsedProjection* out = NULL; - Status status = ParsedProjection::make(projObj, queryMatchExpr.get(), &out); + Status status = ParsedProjection::make(opCtx.get(), projObj, queryMatchExpr.get(), &out); std::unique_ptr<ParsedProjection> destroy(out); ASSERT(!status.isOK()); } @@ -199,18 +210,20 @@ TEST(ParsedProjectionTest, ValidPositionalOperatorProjections) { // to achieve the same effect. // Projection parser should handle this the same way as an empty path. TEST(ParsedProjectionTest, InvalidPositionalProjectionDefaultPathMatchExpression) { + QueryTestServiceContext serviceCtx; + auto opCtx = serviceCtx.makeOperationContext(); unique_ptr<MatchExpression> queryMatchExpr(new AlwaysFalseMatchExpression()); ASSERT(NULL == queryMatchExpr->path().rawData()); ParsedProjection* out = NULL; BSONObj projObj = fromjson("{'a.$': 1}"); - Status status = ParsedProjection::make(projObj, queryMatchExpr.get(), &out); + Status status = ParsedProjection::make(opCtx.get(), projObj, queryMatchExpr.get(), &out); ASSERT(!status.isOK()); std::unique_ptr<ParsedProjection> destroy(out); // Projecting onto empty field should fail. BSONObj emptyFieldProjObj = fromjson("{'.$': 1}"); - status = ParsedProjection::make(emptyFieldProjObj, queryMatchExpr.get(), &out); + status = ParsedProjection::make(opCtx.get(), emptyFieldProjObj, queryMatchExpr.get(), &out); ASSERT(!status.isOK()); } diff --git a/src/mongo/db/query/plan_cache_indexability_test.cpp b/src/mongo/db/query/plan_cache_indexability_test.cpp index 11635c4b665..5d008f9665a 100644 --- a/src/mongo/db/query/plan_cache_indexability_test.cpp +++ b/src/mongo/db/query/plan_cache_indexability_test.cpp @@ -30,6 +30,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/index_entry.h" #include "mongo/db/query/plan_cache_indexability.h" @@ -40,7 +41,9 @@ namespace { std::unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj, const CollatorInterface* collator = nullptr) { - StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, std::move(expCtx)); 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 b94ab624fe1..eb588910785 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -73,7 +73,7 @@ unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(queryObj); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -101,7 +101,7 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, qr->setSort(fromjson(sortStr)); qr->setProj(fromjson(projStr)); qr->setCollation(fromjson(collationStr)); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -136,7 +136,7 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, qr->setHint(fromjson(hintStr)); qr->setMin(fromjson(minStr)); qr->setMax(fromjson(maxStr)); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -175,7 +175,7 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, qr->setMax(fromjson(maxStr)); qr->setSnapshot(snapshot); qr->setExplain(explain); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -190,12 +190,10 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, * Utility function to create MatchExpression */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { - const CollatorInterface* collator = nullptr; boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression status = MatchExpressionParser::parse(obj, - collator, - expCtx, + std::move(expCtx), ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); if (!status.isOK()) { @@ -589,7 +587,7 @@ protected: qr->setMin(minObj); qr->setMax(maxObj); qr->setSnapshot(snapshot); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -616,7 +614,7 @@ protected: std::unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -702,7 +700,7 @@ protected: qr->setSort(sort); qr->setProj(proj); qr->setCollation(collation); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), diff --git a/src/mongo/db/query/planner_ixselect_test.cpp b/src/mongo/db/query/planner_ixselect_test.cpp index 6d90afdb275..50053c7659b 100644 --- a/src/mongo/db/query/planner_ixselect_test.cpp +++ b/src/mongo/db/query/planner_ixselect_test.cpp @@ -34,6 +34,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/index_tag.h" #include "mongo/unittest/unittest.h" @@ -54,8 +55,8 @@ using std::vector; * Utility function to create MatchExpression */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, std::move(expCtx)); 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 ae04eec22a4..5ba4eb2648e 100644 --- a/src/mongo/db/query/query_planner_test_fixture.cpp +++ b/src/mongo/db/query/query_planner_test_fixture.cpp @@ -249,7 +249,7 @@ void QueryPlannerTest::runQueryFull(const BSONObj& query, qr->setMin(minObj); qr->setMax(maxObj); qr->setSnapshot(snapshot); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -333,7 +333,7 @@ void QueryPlannerTest::runInvalidQueryFull(const BSONObj& query, qr->setMin(minObj); qr->setMax(maxObj); qr->setSnapshot(snapshot); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -359,7 +359,7 @@ void QueryPlannerTest::runQueryAsCommand(const BSONObj& cmdObj) { std::unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -385,7 +385,7 @@ void QueryPlannerTest::runInvalidQueryAsCommand(const BSONObj& cmdObj) { std::unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -472,7 +472,9 @@ void QueryPlannerTest::assertHasOneSolutionOf(const std::vector<std::string>& so std::unique_ptr<MatchExpression> QueryPlannerTest::parseMatchExpression( const BSONObj& obj, const CollatorInterface* collator) { - StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, std::move(expCtx)); 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 c1920f821d0..377bbb791ae 100644 --- a/src/mongo/db/query/query_planner_test_lib.cpp +++ b/src/mongo/db/query/query_planner_test_lib.cpp @@ -36,6 +36,7 @@ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_factory_mock.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/query/query_solution.h" @@ -66,8 +67,10 @@ bool filterMatches(const BSONObj& testFilter, testCollator = std::move(collator.getValue()); } + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(testCollator.get()); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(testFilter, testCollator.get()); + MatchExpressionParser::parse(testFilter, std::move(expCtx)); 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 821b1efd4e9..0e07d9669a6 100644 --- a/src/mongo/db/query/query_solution_test.cpp +++ b/src/mongo/db/query/query_solution_test.cpp @@ -34,6 +34,7 @@ #include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/index_entry.h" #include "mongo/db/query/query_solution.h" +#include "mongo/db/query/query_test_service_context.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" @@ -685,11 +686,17 @@ TEST(QuerySolutionTest, IndexScanNodeHasFieldExcludesSimpleBoundsStringFieldWhen std::unique_ptr<ParsedProjection> createParsedProjection(const BSONObj& query, const BSONObj& projObj) { + QueryTestServiceContext serviceCtx; + auto opCtx = serviceCtx.makeOperationContext(); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression queryMatchExpr = MatchExpressionParser::parse(query, collator); + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtx.get(), collator)); + StatusWithMatchExpression queryMatchExpr = + MatchExpressionParser::parse(query, std::move(expCtx)); ASSERT(queryMatchExpr.isOK()); ParsedProjection* out = nullptr; - Status status = ParsedProjection::make(projObj, queryMatchExpr.getValue().get(), &out); + Status status = + ParsedProjection::make(opCtx.get(), projObj, queryMatchExpr.getValue().get(), &out); if (!status.isOK()) { FAIL(mongoutils::str::stream() << "failed to parse projection " << projObj << " (query: " << query diff --git a/src/mongo/db/repl/apply_ops.cpp b/src/mongo/db/repl/apply_ops.cpp index af561045a00..cf634cb4712 100644 --- a/src/mongo/db/repl/apply_ops.cpp +++ b/src/mongo/db/repl/apply_ops.cpp @@ -309,7 +309,8 @@ Status _checkPrecondition(OperationContext* opCtx, // applyOps does not allow any extensions, such as $text, $where, $geoNear, $near, // $nearSphere, or $expr. - Matcher matcher(preCondition["res"].Obj(), collator); + boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, collator)); + Matcher matcher(preCondition["res"].Obj(), std::move(expCtx)); if (!matcher.matches(realres)) { result->append("got", realres); result->append("whatFailed", preCondition); diff --git a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp index ee8a60a9fa3..98f3808f9ef 100644 --- a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp +++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp @@ -386,7 +386,7 @@ void NamespaceDetailsCollectionCatalogEntry::_updateSystemNamespaces(OperationCo return; RecordData entry = _namespacesRecordStore->dataFor(opCtx, _namespacesRecordId); - const BSONObj newEntry = applyUpdateOperators(entry.releaseToBson(), update); + const BSONObj newEntry = applyUpdateOperators(opCtx, entry.releaseToBson(), update); Status result = _namespacesRecordStore->updateRecord( opCtx, _namespacesRecordId, newEntry.objdata(), newEntry.objsize(), false, NULL); diff --git a/src/mongo/db/update/SConscript b/src/mongo/db/update/SConscript index 2bbb89d7db5..082ae597b66 100644 --- a/src/mongo/db/update/SConscript +++ b/src/mongo/db/update/SConscript @@ -49,6 +49,7 @@ env.CppUnitTest( LIBDEPS=[ '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', '$BUILD_DIR/mongo/db/matcher/expressions', + '$BUILD_DIR/mongo/db/query/query_test_service_context', 'update_common', ], ) @@ -118,6 +119,7 @@ env.CppUnitTest( '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', '$BUILD_DIR/mongo/db/logical_clock', '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', + '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/service_context_noop_init', 'update', ], diff --git a/src/mongo/db/update/addtoset_node.cpp b/src/mongo/db/update/addtoset_node.cpp index f0a43dca382..89eb53f8bd6 100644 --- a/src/mongo/db/update/addtoset_node.cpp +++ b/src/mongo/db/update/addtoset_node.cpp @@ -61,7 +61,8 @@ void deduplicate(std::vector<BSONElement>& elements, const CollatorInterface* co } // namespace -Status AddToSetNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status AddToSetNode::init(BSONElement modExpr, + const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); bool isEach = false; @@ -92,7 +93,7 @@ Status AddToSetNode::init(BSONElement modExpr, const CollatorInterface* collator _elements.push_back(modExpr); } - setCollator(collator); + setCollator(expCtx->getCollator()); return Status::OK(); } diff --git a/src/mongo/db/update/addtoset_node.h b/src/mongo/db/update/addtoset_node.h index b5677caf169..25fcddffcb5 100644 --- a/src/mongo/db/update/addtoset_node.h +++ b/src/mongo/db/update/addtoset_node.h @@ -38,7 +38,7 @@ namespace mongo { */ class AddToSetNode : public ModifierNode { public: - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<AddToSetNode>(*this); diff --git a/src/mongo/db/update/addtoset_node_test.cpp b/src/mongo/db/update/addtoset_node_test.cpp index 26e6e1ea4fc..7fe1e95ca45 100644 --- a/src/mongo/db/update/addtoset_node_test.cpp +++ b/src/mongo/db/update/addtoset_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" @@ -47,16 +48,16 @@ using mongo::mutablebson::countChildren; DEATH_TEST(AddToSetNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") { auto update = fromjson("{$addToSet: {}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - node.init(update["$addToSet"].embeddedObject().firstElement(), collator).transitional_ignore(); + node.init(update["$addToSet"].embeddedObject().firstElement(), expCtx).transitional_ignore(); } TEST(AddToSetNodeTest, InitFailsIfEachIsNotArray) { auto update = fromjson("{$addToSet: {a: {$each: {}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - auto result = node.init(update["$addToSet"]["a"], collator); + auto result = node.init(update["$addToSet"]["a"], expCtx); ASSERT_NOT_OK(result); ASSERT_EQ(result.code(), ErrorCodes::TypeMismatch); ASSERT_EQ(result.reason(), @@ -65,9 +66,9 @@ TEST(AddToSetNodeTest, InitFailsIfEachIsNotArray) { TEST(AddToSetNodeTest, InitFailsIfThereAreFieldsAfterEach) { auto update = fromjson("{$addToSet: {a: {$each: [], bad: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - auto result = node.init(update["$addToSet"]["a"], collator); + auto result = node.init(update["$addToSet"]["a"], expCtx); ASSERT_NOT_OK(result); ASSERT_EQ(result.code(), ErrorCodes::BadValue); ASSERT_EQ(result.reason(), @@ -76,37 +77,37 @@ TEST(AddToSetNodeTest, InitFailsIfThereAreFieldsAfterEach) { TEST(AddToSetNodeTest, InitSucceedsWithFailsBeforeEach) { auto update = fromjson("{$addToSet: {a: {other: 1, $each: []}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); } TEST(AddToSetNodeTest, InitSucceedsWithObject) { auto update = fromjson("{$addToSet: {a: {}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); } TEST(AddToSetNodeTest, InitSucceedsWithArray) { auto update = fromjson("{$addToSet: {a: []}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); } TEST(AddToSetNodeTest, InitSucceedsWithScaler) { auto update = fromjson("{$addToSet: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); } TEST_F(AddToSetNodeTest, ApplyFailsOnNonArray) { auto update = fromjson("{$addToSet: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 2}")); setPathTaken("a"); @@ -119,9 +120,9 @@ TEST_F(AddToSetNodeTest, ApplyFailsOnNonArray) { TEST_F(AddToSetNodeTest, ApplyNonEach) { auto update = fromjson("{$addToSet: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -136,9 +137,9 @@ TEST_F(AddToSetNodeTest, ApplyNonEach) { TEST_F(AddToSetNodeTest, ApplyNonEachArray) { auto update = fromjson("{$addToSet: {a: [1]}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -153,9 +154,9 @@ TEST_F(AddToSetNodeTest, ApplyNonEachArray) { TEST_F(AddToSetNodeTest, ApplyEach) { auto update = fromjson("{$addToSet: {a: {$each: [1, 2]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -170,9 +171,9 @@ TEST_F(AddToSetNodeTest, ApplyEach) { TEST_F(AddToSetNodeTest, ApplyToEmptyArray) { auto update = fromjson("{$addToSet: {a: {$each: [1, 2]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -187,9 +188,9 @@ TEST_F(AddToSetNodeTest, ApplyToEmptyArray) { TEST_F(AddToSetNodeTest, ApplyDeduplicateElementsToAdd) { auto update = fromjson("{$addToSet: {a: {$each: [1, 1]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -204,9 +205,9 @@ TEST_F(AddToSetNodeTest, ApplyDeduplicateElementsToAdd) { TEST_F(AddToSetNodeTest, ApplyDoNotAddExistingElements) { auto update = fromjson("{$addToSet: {a: {$each: [0, 1]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -221,9 +222,9 @@ TEST_F(AddToSetNodeTest, ApplyDoNotAddExistingElements) { TEST_F(AddToSetNodeTest, ApplyDoNotDeduplicateExistingElements) { auto update = fromjson("{$addToSet: {a: {$each: [1]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 0]}")); setPathTaken("a"); @@ -238,9 +239,9 @@ TEST_F(AddToSetNodeTest, ApplyDoNotDeduplicateExistingElements) { TEST_F(AddToSetNodeTest, ApplyNoElementsToAdd) { auto update = fromjson("{$addToSet: {a: {$each: []}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -255,9 +256,9 @@ TEST_F(AddToSetNodeTest, ApplyNoElementsToAdd) { TEST_F(AddToSetNodeTest, ApplyNoNonDuplicateElementsToAdd) { auto update = fromjson("{$addToSet: {a: {$each: [0]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -272,9 +273,9 @@ TEST_F(AddToSetNodeTest, ApplyNoNonDuplicateElementsToAdd) { TEST_F(AddToSetNodeTest, ApplyCreateArray) { auto update = fromjson("{$addToSet: {a: {$each: [0, 1]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -289,9 +290,9 @@ TEST_F(AddToSetNodeTest, ApplyCreateArray) { TEST_F(AddToSetNodeTest, ApplyCreateEmptyArrayIsNotNoop) { auto update = fromjson("{$addToSet: {a: {$each: []}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -306,9 +307,11 @@ TEST_F(AddToSetNodeTest, ApplyCreateEmptyArrayIsNotNoop) { TEST_F(AddToSetNodeTest, ApplyDeduplicationOfElementsToAddRespectsCollation) { auto update = fromjson("{$addToSet: {a: {$each: ['abc', 'ABC', 'def', 'abc']}}}"); - const CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], &collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -323,9 +326,11 @@ TEST_F(AddToSetNodeTest, ApplyDeduplicationOfElementsToAddRespectsCollation) { TEST_F(AddToSetNodeTest, ApplyComparisonToExistingElementsRespectsCollation) { auto update = fromjson("{$addToSet: {a: {$each: ['abc', 'def']}}}"); - const CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], &collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: ['ABC']}")); setPathTaken("a"); @@ -340,9 +345,9 @@ TEST_F(AddToSetNodeTest, ApplyComparisonToExistingElementsRespectsCollation) { TEST_F(AddToSetNodeTest, ApplyRespectsCollationFromSetCollator) { auto update = fromjson("{$addToSet: {a: {$each: ['abc', 'ABC', 'def', 'abc']}}}"); - const CollatorInterface* binaryComparisonCollator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], binaryComparisonCollator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); const CollatorInterfaceMock caseInsensitiveCollator( CollatorInterfaceMock::MockType::kToLowerString); @@ -361,18 +366,19 @@ TEST_F(AddToSetNodeTest, ApplyRespectsCollationFromSetCollator) { DEATH_TEST(AddToSetNodeTest, CannotSetCollatorIfCollatorIsNonNull, "Invariant failure !_collator") { auto update = fromjson("{$addToSet: {a: 1}}"); - const CollatorInterfaceMock caseInsensitiveCollator( - CollatorInterfaceMock::MockType::kToLowerString); + CollatorInterfaceMock caseInsensitiveCollator(CollatorInterfaceMock::MockType::kToLowerString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&caseInsensitiveCollator); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], &caseInsensitiveCollator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); node.setCollator(&caseInsensitiveCollator); } DEATH_TEST(AddToSetNodeTest, CannotSetCollatorTwice, "Invariant failure !_collator") { auto update = fromjson("{$addToSet: {a: 1}}"); - const CollatorInterface* binaryComparisonCollator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], binaryComparisonCollator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); const CollatorInterfaceMock caseInsensitiveCollator( CollatorInterfaceMock::MockType::kToLowerString); @@ -382,9 +388,9 @@ DEATH_TEST(AddToSetNodeTest, CannotSetCollatorTwice, "Invariant failure !_collat TEST_F(AddToSetNodeTest, ApplyNestedArray) { auto update = fromjson("{ $addToSet : { 'a.1' : 1 } }"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a.1"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a.1"], expCtx)); mutablebson::Document doc(fromjson("{ _id : 1, a : [ 1, [ ] ] }")); setPathTaken("a.1"); @@ -399,9 +405,9 @@ TEST_F(AddToSetNodeTest, ApplyNestedArray) { TEST_F(AddToSetNodeTest, ApplyIndexesNotAffected) { auto update = fromjson("{$addToSet: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -415,9 +421,9 @@ TEST_F(AddToSetNodeTest, ApplyIndexesNotAffected) { TEST_F(AddToSetNodeTest, ApplyNoIndexDataOrLogBuilder) { auto update = fromjson("{$addToSet: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); AddToSetNode node; - ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); + ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); diff --git a/src/mongo/db/update/arithmetic_node.cpp b/src/mongo/db/update/arithmetic_node.cpp index c5b7a3373f7..ab46e854616 100644 --- a/src/mongo/db/update/arithmetic_node.cpp +++ b/src/mongo/db/update/arithmetic_node.cpp @@ -58,7 +58,8 @@ const char* getModifierNameForOp(ArithmeticNode::ArithmeticOp op) { } } // namespace -Status ArithmeticNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status ArithmeticNode::init(BSONElement modExpr, + const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); if (!modExpr.isNumber()) { diff --git a/src/mongo/db/update/arithmetic_node.h b/src/mongo/db/update/arithmetic_node.h index 14981e0778e..cc5e9b23dc8 100644 --- a/src/mongo/db/update/arithmetic_node.h +++ b/src/mongo/db/update/arithmetic_node.h @@ -42,7 +42,7 @@ public: explicit ArithmeticNode(ArithmeticOp op) : _op(op) {} - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<ArithmeticNode>(*this); diff --git a/src/mongo/db/update/arithmetic_node_test.cpp b/src/mongo/db/update/arithmetic_node_test.cpp index 64f1ad3c8d3..f8cd87927c6 100644 --- a/src/mongo/db/update/arithmetic_node_test.cpp +++ b/src/mongo/db/update/arithmetic_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" @@ -46,44 +47,44 @@ using mongo::mutablebson::countChildren; DEATH_TEST(ArithmeticNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") { auto update = fromjson("{$inc: {}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - node.init(update["$inc"].embeddedObject().firstElement(), collator).transitional_ignore(); + node.init(update["$inc"].embeddedObject().firstElement(), expCtx).transitional_ignore(); } TEST(ArithmeticNodeTest, InitSucceedsForNumberIntElement) { auto update = fromjson("{$inc: {a: NumberInt(5)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); } TEST(ArithmeticNodeTest, InitSucceedsForNumberLongElement) { auto update = fromjson("{$inc: {a: NumberLong(5)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); } TEST(ArithmeticNodeTest, InitSucceedsForDoubleElement) { auto update = fromjson("{$inc: {a: 5.1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); } TEST(ArithmeticNodeTest, InitSucceedsForDecimalElement) { auto update = fromjson("{$inc: {a: NumberDecimal(\"5.1\")}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); } TEST(ArithmeticNodeTest, InitFailsForNonNumericElement) { auto update = fromjson("{$inc: {a: 'foo'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - Status result = node.init(update["$inc"]["a"], collator); + Status result = node.init(update["$inc"]["a"], expCtx); ASSERT_NOT_OK(result); ASSERT_EQ(result.code(), ErrorCodes::TypeMismatch); ASSERT_EQ(result.reason(), "Cannot increment with non-numeric argument: {a: \"foo\"}"); @@ -91,9 +92,9 @@ TEST(ArithmeticNodeTest, InitFailsForNonNumericElement) { TEST(ArithmeticNodeTest, InitFailsForObjectElement) { auto update = fromjson("{$mul: {a: {b: 6}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - Status result = node.init(update["$mul"]["a"], collator); + Status result = node.init(update["$mul"]["a"], expCtx); ASSERT_NOT_OK(result); ASSERT_EQ(result.code(), ErrorCodes::TypeMismatch); ASSERT_EQ(result.reason(), "Cannot multiply with non-numeric argument: {a: { b: 6 }}"); @@ -101,9 +102,9 @@ TEST(ArithmeticNodeTest, InitFailsForObjectElement) { TEST(ArithmeticNodeTest, InitFailsForArrayElement) { auto update = fromjson("{$mul: {a: []}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - Status result = node.init(update["$mul"]["a"], collator); + Status result = node.init(update["$mul"]["a"], expCtx); ASSERT_NOT_OK(result); ASSERT_EQ(result.code(), ErrorCodes::TypeMismatch); ASSERT_EQ(result.reason(), "Cannot multiply with non-numeric argument: {a: []}"); @@ -111,9 +112,9 @@ TEST(ArithmeticNodeTest, InitFailsForArrayElement) { TEST_F(ArithmeticNodeTest, ApplyIncNoOp) { auto update = fromjson("{$inc: {a: 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -128,9 +129,9 @@ TEST_F(ArithmeticNodeTest, ApplyIncNoOp) { TEST_F(ArithmeticNodeTest, ApplyMulNoOp) { auto update = fromjson("{$mul: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - ASSERT_OK(node.init(update["$mul"]["a"], collator)); + ASSERT_OK(node.init(update["$mul"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -145,9 +146,9 @@ TEST_F(ArithmeticNodeTest, ApplyMulNoOp) { TEST_F(ArithmeticNodeTest, ApplyRoundingNoOp) { auto update = fromjson("{$inc: {a: 1.0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 6.022e23}")); setPathTaken("a"); @@ -162,9 +163,9 @@ TEST_F(ArithmeticNodeTest, ApplyRoundingNoOp) { TEST_F(ArithmeticNodeTest, ApplyEmptyPathToCreate) { auto update = fromjson("{$inc: {a: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -179,9 +180,9 @@ TEST_F(ArithmeticNodeTest, ApplyEmptyPathToCreate) { TEST_F(ArithmeticNodeTest, ApplyCreatePath) { auto update = fromjson("{$inc: {'a.b.c': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {d: 5}}")); setPathToCreate("b.c"); @@ -197,9 +198,9 @@ TEST_F(ArithmeticNodeTest, ApplyCreatePath) { TEST_F(ArithmeticNodeTest, ApplyExtendPath) { auto update = fromjson("{$inc: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {c: 1}}")); setPathToCreate("b"); @@ -214,9 +215,9 @@ TEST_F(ArithmeticNodeTest, ApplyExtendPath) { TEST_F(ArithmeticNodeTest, ApplyCreatePathFromRoot) { auto update = fromjson("{$inc: {'a.b': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{c: 5}")); setPathToCreate("a.b"); @@ -231,9 +232,9 @@ TEST_F(ArithmeticNodeTest, ApplyCreatePathFromRoot) { TEST_F(ArithmeticNodeTest, ApplyPositional) { auto update = fromjson("{$inc: {'a.$': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.$"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.$"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2]}")); setPathTaken("a.1"); @@ -249,9 +250,9 @@ TEST_F(ArithmeticNodeTest, ApplyPositional) { TEST_F(ArithmeticNodeTest, ApplyNonViablePathToInc) { auto update = fromjson("{$inc: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathToCreate("b"); @@ -265,9 +266,9 @@ TEST_F(ArithmeticNodeTest, ApplyNonViablePathToInc) { TEST_F(ArithmeticNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) { auto update = fromjson("{$inc: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathToCreate("b"); @@ -284,9 +285,9 @@ TEST_F(ArithmeticNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) { TEST_F(ArithmeticNodeTest, ApplyNoIndexDataNoLogBuilder) { auto update = fromjson("{$inc: {a: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -300,9 +301,9 @@ TEST_F(ArithmeticNodeTest, ApplyNoIndexDataNoLogBuilder) { TEST_F(ArithmeticNodeTest, ApplyDoesNotAffectIndexes) { auto update = fromjson("{$inc: {a: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -316,9 +317,9 @@ TEST_F(ArithmeticNodeTest, ApplyDoesNotAffectIndexes) { TEST_F(ArithmeticNodeTest, IncTypePromotionIsNotANoOp) { auto update = fromjson("{$inc: {a: NumberLong(0)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: NumberInt(2)}")); setPathTaken("a"); @@ -332,9 +333,9 @@ TEST_F(ArithmeticNodeTest, IncTypePromotionIsNotANoOp) { TEST_F(ArithmeticNodeTest, MulTypePromotionIsNotANoOp) { auto update = fromjson("{$mul: {a: NumberLong(1)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - ASSERT_OK(node.init(update["$mul"]["a"], collator)); + ASSERT_OK(node.init(update["$mul"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: NumberInt(2)}")); setPathTaken("a"); @@ -348,9 +349,9 @@ TEST_F(ArithmeticNodeTest, MulTypePromotionIsNotANoOp) { TEST_F(ArithmeticNodeTest, TypePromotionFromIntToDecimalIsNotANoOp) { auto update = fromjson("{$inc: {a: NumberDecimal(\"0.0\")}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: NumberInt(5)}")); setPathTaken("a"); @@ -365,9 +366,9 @@ TEST_F(ArithmeticNodeTest, TypePromotionFromIntToDecimalIsNotANoOp) { TEST_F(ArithmeticNodeTest, TypePromotionFromLongToDecimalIsNotANoOp) { auto update = fromjson("{$inc: {a: NumberDecimal(\"0.0\")}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: NumberLong(5)}")); setPathTaken("a"); @@ -382,9 +383,9 @@ TEST_F(ArithmeticNodeTest, TypePromotionFromLongToDecimalIsNotANoOp) { TEST_F(ArithmeticNodeTest, TypePromotionFromDoubleToDecimalIsNotANoOp) { auto update = fromjson("{$inc: {a: NumberDecimal(\"0.0\")}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5.25}")); setPathTaken("a"); @@ -399,9 +400,9 @@ TEST_F(ArithmeticNodeTest, TypePromotionFromDoubleToDecimalIsNotANoOp) { TEST_F(ArithmeticNodeTest, ApplyPromoteToFloatingPoint) { auto update = fromjson("{$inc: {a: 0.2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: NumberLong(1)}")); setPathTaken("a"); @@ -415,9 +416,9 @@ TEST_F(ArithmeticNodeTest, ApplyPromoteToFloatingPoint) { TEST_F(ArithmeticNodeTest, IncrementedDecimalStaysDecimal) { auto update = fromjson("{$inc: {a: 5.25}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: NumberDecimal(\"6.25\")}")); setPathTaken("a"); @@ -432,9 +433,9 @@ TEST_F(ArithmeticNodeTest, IncrementedDecimalStaysDecimal) { TEST_F(ArithmeticNodeTest, OverflowIntToLong) { auto update = fromjson("{$inc: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); const int initialValue = std::numeric_limits<int>::max(); mutablebson::Document doc(BSON("a" << initialValue)); @@ -451,9 +452,9 @@ TEST_F(ArithmeticNodeTest, OverflowIntToLong) { TEST_F(ArithmeticNodeTest, UnderflowIntToLong) { auto update = fromjson("{$inc: {a: -1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); const int initialValue = std::numeric_limits<int>::min(); mutablebson::Document doc(BSON("a" << initialValue)); @@ -470,9 +471,9 @@ TEST_F(ArithmeticNodeTest, UnderflowIntToLong) { TEST_F(ArithmeticNodeTest, IncModeCanBeReused) { auto update = fromjson("{$inc: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc1(fromjson("{a: 1}")); mutablebson::Document doc2(fromjson("{a: 2}")); @@ -496,9 +497,9 @@ TEST_F(ArithmeticNodeTest, IncModeCanBeReused) { TEST_F(ArithmeticNodeTest, CreatedNumberHasSameTypeAsInc) { auto update = fromjson("{$inc: {a: NumberLong(5)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{b: 6}")); setPathToCreate("a"); @@ -512,9 +513,9 @@ TEST_F(ArithmeticNodeTest, CreatedNumberHasSameTypeAsInc) { TEST_F(ArithmeticNodeTest, CreatedNumberHasSameTypeAsMul) { auto update = fromjson("{$mul: {a: NumberLong(5)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - ASSERT_OK(node.init(update["$mul"]["a"], collator)); + ASSERT_OK(node.init(update["$mul"]["a"], expCtx)); mutablebson::Document doc(fromjson("{b: 6}")); setPathToCreate("a"); @@ -528,9 +529,9 @@ TEST_F(ArithmeticNodeTest, CreatedNumberHasSameTypeAsMul) { TEST_F(ArithmeticNodeTest, ApplyEmptyDocument) { auto update = fromjson("{$inc: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -544,9 +545,9 @@ TEST_F(ArithmeticNodeTest, ApplyEmptyDocument) { TEST_F(ArithmeticNodeTest, ApplyIncToObjectFails) { auto update = fromjson("{$inc: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: {b: 1}}")); setPathTaken("a"); @@ -560,9 +561,9 @@ TEST_F(ArithmeticNodeTest, ApplyIncToObjectFails) { TEST_F(ArithmeticNodeTest, ApplyIncToArrayFails) { auto update = fromjson("{$inc: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: []}")); setPathTaken("a"); @@ -576,9 +577,9 @@ TEST_F(ArithmeticNodeTest, ApplyIncToArrayFails) { TEST_F(ArithmeticNodeTest, ApplyIncToStringFails) { auto update = fromjson("{$inc: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: \"foo\"}")); setPathTaken("a"); @@ -592,9 +593,9 @@ TEST_F(ArithmeticNodeTest, ApplyIncToStringFails) { TEST_F(ArithmeticNodeTest, OverflowingOperationFails) { auto update = fromjson("{$mul: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - ASSERT_OK(node.init(update["$mul"]["a"], collator)); + ASSERT_OK(node.init(update["$mul"]["a"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: NumberLong(9223372036854775807)}")); setPathTaken("a"); @@ -609,9 +610,9 @@ TEST_F(ArithmeticNodeTest, OverflowingOperationFails) { TEST_F(ArithmeticNodeTest, ApplyNewPath) { auto update = fromjson("{$inc: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{b: 1}")); setPathToCreate("a"); @@ -625,9 +626,9 @@ TEST_F(ArithmeticNodeTest, ApplyNewPath) { TEST_F(ArithmeticNodeTest, ApplyEmptyIndexData) { auto update = fromjson("{$inc: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a"], collator)); + ASSERT_OK(node.init(update["$inc"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -640,9 +641,9 @@ TEST_F(ArithmeticNodeTest, ApplyEmptyIndexData) { TEST_F(ArithmeticNodeTest, ApplyNoOpDottedPath) { auto update = fromjson("{$inc: {'a.b': 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a.b"); @@ -656,9 +657,9 @@ TEST_F(ArithmeticNodeTest, ApplyNoOpDottedPath) { TEST_F(ArithmeticNodeTest, TypePromotionOnDottedPathIsNotANoOp) { auto update = fromjson("{$inc: {'a.b': NumberLong(0)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: NumberInt(2)}}")); setPathTaken("a.b"); @@ -672,9 +673,9 @@ TEST_F(ArithmeticNodeTest, TypePromotionOnDottedPathIsNotANoOp) { TEST_F(ArithmeticNodeTest, ApplyPathNotViableArray) { auto update = fromjson("{$inc: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a:[{b:1}]}")); setPathToCreate("b"); @@ -687,9 +688,9 @@ TEST_F(ArithmeticNodeTest, ApplyPathNotViableArray) { TEST_F(ArithmeticNodeTest, ApplyInPlaceDottedPath) { auto update = fromjson("{$inc: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathTaken("a.b"); @@ -703,9 +704,9 @@ TEST_F(ArithmeticNodeTest, ApplyInPlaceDottedPath) { TEST_F(ArithmeticNodeTest, ApplyPromotionDottedPath) { auto update = fromjson("{$inc: {'a.b': NumberLong(2)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: NumberInt(3)}}")); setPathTaken("a.b"); @@ -719,9 +720,9 @@ TEST_F(ArithmeticNodeTest, ApplyPromotionDottedPath) { TEST_F(ArithmeticNodeTest, ApplyDottedPathEmptyDoc) { auto update = fromjson("{$inc: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a.b"); @@ -735,9 +736,9 @@ TEST_F(ArithmeticNodeTest, ApplyDottedPathEmptyDoc) { TEST_F(ArithmeticNodeTest, ApplyFieldWithDot) { auto update = fromjson("{$inc: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{'a.b':4}")); setPathToCreate("a.b"); @@ -751,9 +752,9 @@ TEST_F(ArithmeticNodeTest, ApplyFieldWithDot) { TEST_F(ArithmeticNodeTest, ApplyNoOpArrayIndex) { auto update = fromjson("{$inc: {'a.2.b': 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}")); setPathTaken("a.2.b"); @@ -767,9 +768,9 @@ TEST_F(ArithmeticNodeTest, ApplyNoOpArrayIndex) { TEST_F(ArithmeticNodeTest, TypePromotionInArrayIsNotANoOp) { auto update = fromjson("{$set: {'a.2.b': NumberLong(0)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc( fromjson("{a: [{b: NumberInt(0)},{b: NumberInt(1)},{b: NumberInt(2)}]}")); @@ -784,9 +785,9 @@ TEST_F(ArithmeticNodeTest, TypePromotionInArrayIsNotANoOp) { TEST_F(ArithmeticNodeTest, ApplyNonViablePathThroughArray) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathToCreate("2.b"); @@ -799,9 +800,9 @@ TEST_F(ArithmeticNodeTest, ApplyNonViablePathThroughArray) { TEST_F(ArithmeticNodeTest, ApplyInPlaceArrayIndex) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 1}]}")); setPathTaken("a.2.b"); @@ -815,9 +816,9 @@ TEST_F(ArithmeticNodeTest, ApplyInPlaceArrayIndex) { TEST_F(ArithmeticNodeTest, ApplyAppendArray) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0},{b: 1}]}")); setPathToCreate("2.b"); @@ -832,9 +833,9 @@ TEST_F(ArithmeticNodeTest, ApplyAppendArray) { TEST_F(ArithmeticNodeTest, ApplyPaddingArray) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0}]}")); setPathToCreate("2.b"); @@ -849,9 +850,9 @@ TEST_F(ArithmeticNodeTest, ApplyPaddingArray) { TEST_F(ArithmeticNodeTest, ApplyNumericObject) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 0}}")); setPathToCreate("2.b"); @@ -866,9 +867,9 @@ TEST_F(ArithmeticNodeTest, ApplyNumericObject) { TEST_F(ArithmeticNodeTest, ApplyNumericField) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {'2': {b: 1}}}")); setPathTaken("a.2.b"); @@ -882,9 +883,9 @@ TEST_F(ArithmeticNodeTest, ApplyNumericField) { TEST_F(ArithmeticNodeTest, ApplyExtendNumericField) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {'2': {c: 1}}}")); setPathToCreate("b"); @@ -899,9 +900,9 @@ TEST_F(ArithmeticNodeTest, ApplyExtendNumericField) { TEST_F(ArithmeticNodeTest, ApplyNumericFieldToEmptyObject) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {}}")); setPathToCreate("2.b"); @@ -916,9 +917,9 @@ TEST_F(ArithmeticNodeTest, ApplyNumericFieldToEmptyObject) { TEST_F(ArithmeticNodeTest, ApplyEmptyArray) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathToCreate("2.b"); @@ -933,9 +934,9 @@ TEST_F(ArithmeticNodeTest, ApplyEmptyArray) { TEST_F(ArithmeticNodeTest, ApplyLogDottedPath) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b:0}, {b:1}]}")); setPathToCreate("2.b"); @@ -949,9 +950,9 @@ TEST_F(ArithmeticNodeTest, ApplyLogDottedPath) { TEST_F(ArithmeticNodeTest, LogEmptyArray) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathToCreate("2.b"); @@ -965,9 +966,9 @@ TEST_F(ArithmeticNodeTest, LogEmptyArray) { TEST_F(ArithmeticNodeTest, LogEmptyObject) { auto update = fromjson("{$inc: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd); - ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$inc"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {}}")); setPathToCreate("2.b"); @@ -981,9 +982,9 @@ TEST_F(ArithmeticNodeTest, LogEmptyObject) { TEST_F(ArithmeticNodeTest, ApplyDeserializedDocNotNoOp) { auto update = fromjson("{$mul: {b: NumberInt(1)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - ASSERT_OK(node.init(update["$mul"]["b"], collator)); + ASSERT_OK(node.init(update["$mul"]["b"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); // De-serialize the int. @@ -1000,9 +1001,9 @@ TEST_F(ArithmeticNodeTest, ApplyDeserializedDocNotNoOp) { TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNoOp) { auto update = fromjson("{$mul: {a: NumberInt(1)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - ASSERT_OK(node.init(update["$mul"]["a"], collator)); + ASSERT_OK(node.init(update["$mul"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); // De-serialize the int. @@ -1019,9 +1020,9 @@ TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNoOp) { TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNestedNoop) { auto update = fromjson("{$mul: {'a.b': NumberInt(1)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - ASSERT_OK(node.init(update["$mul"]["a.b"], collator)); + ASSERT_OK(node.init(update["$mul"]["a.b"], expCtx)); mutablebson::Document doc{BSONObj()}; // De-serialize the int. @@ -1038,9 +1039,9 @@ TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNestedNoop) { TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNestedNotNoop) { auto update = fromjson("{$mul: {'a.b': 3}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply); - ASSERT_OK(node.init(update["$mul"]["a.b"], collator)); + ASSERT_OK(node.init(update["$mul"]["a.b"], expCtx)); mutablebson::Document doc{BSONObj()}; // De-serialize the int. diff --git a/src/mongo/db/update/bit_node.cpp b/src/mongo/db/update/bit_node.cpp index f2123d6324e..c2ca50dae32 100644 --- a/src/mongo/db/update/bit_node.cpp +++ b/src/mongo/db/update/bit_node.cpp @@ -34,7 +34,7 @@ namespace mongo { -Status BitNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status BitNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); if (modExpr.type() != mongo::Object) { diff --git a/src/mongo/db/update/bit_node.h b/src/mongo/db/update/bit_node.h index 2f23d9a53df..f5cecf9220b 100644 --- a/src/mongo/db/update/bit_node.h +++ b/src/mongo/db/update/bit_node.h @@ -38,7 +38,7 @@ namespace mongo { */ class BitNode : public ModifierNode { public: - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<BitNode>(*this); diff --git a/src/mongo/db/update/bit_node_test.cpp b/src/mongo/db/update/bit_node_test.cpp index 868d064f66b..b6c94542e09 100644 --- a/src/mongo/db/update/bit_node_test.cpp +++ b/src/mongo/db/update/bit_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" @@ -45,115 +46,115 @@ using mongo::mutablebson::Element; using mongo::mutablebson::countChildren; TEST(BitNodeTest, InitWithDoubleFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: 0}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, InitWithStringFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: ''}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, InitWithArrayFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: []}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, InitWithEmptyDocumentFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: {}}}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, InitWithUnknownOperatorFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: {foo: 4}}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, InitWithArrayArgumentToOperatorFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: {or: []}}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, InitWithStringArgumentToOperatorFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: {or: 'foo'}}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, InitWithDoubleArgumentToOperatorFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: {or: 1.0}}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, InitWithDecimalArgumentToOperatorFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$bit: {a: {or: NumberDecimal(\"1.0\")}}}"); BitNode node; - ASSERT_NOT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, ParsesAndInt) { auto update = fromjson("{$bit: {a: {and: NumberInt(1)}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, ParsesOrInt) { auto update = fromjson("{$bit: {a: {or: NumberInt(1)}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, ParsesXorInt) { auto update = fromjson("{$bit: {a: {xor: NumberInt(1)}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, ParsesAndLong) { auto update = fromjson("{$bit: {a: {and: NumberLong(1)}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, ParsesOrLong) { auto update = fromjson("{$bit: {a: {or: NumberLong(1)}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST(BitNodeTest, ParsesXorLong) { auto update = fromjson("{$bit: {a: {xor: NumberLong(1)}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); } TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentAnd) { auto update = fromjson("{$bit: {a: {and: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -166,9 +167,9 @@ TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentAnd) { TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentOr) { auto update = fromjson("{$bit: {a: {or: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -181,9 +182,9 @@ TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentOr) { TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentXor) { auto update = fromjson("{$bit: {a: {xor: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -196,9 +197,9 @@ TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentXor) { TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentAnd) { auto update = BSON("$bit" << BSON("a" << BSON("and" << 0b0110))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(BSON("a" << 0b0101)); setPathTaken("a"); @@ -211,9 +212,9 @@ TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentAnd) { TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentOr) { auto update = BSON("$bit" << BSON("a" << BSON("or" << 0b0110))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(BSON("a" << 0b0101)); setPathTaken("a"); @@ -226,9 +227,9 @@ TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentOr) { TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentXor) { auto update = BSON("$bit" << BSON("a" << BSON("xor" << 0b0110))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(BSON("a" << 0b0101)); setPathTaken("a"); @@ -241,9 +242,9 @@ TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentXor) { TEST_F(BitNodeTest, ApplyShouldReportNoOp) { auto update = BSON("$bit" << BSON("a" << BSON("and" << static_cast<int>(1)))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(BSON("a" << 1)); setPathTaken("a"); @@ -261,9 +262,9 @@ TEST_F(BitNodeTest, ApplyMultipleBitOps) { "or" << 0b1100110011001100 // << // "xor" << 0b1010101010101010))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(BSON("a" << 0b1111111100000000)); setPathTaken("a"); @@ -276,9 +277,9 @@ TEST_F(BitNodeTest, ApplyMultipleBitOps) { TEST_F(BitNodeTest, ApplyRepeatedBitOps) { auto update = BSON("$bit" << BSON("a" << BSON("xor" << 0b11001100 << "xor" << 0b10101010))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); BitNode node; - ASSERT_OK(node.init(update["$bit"]["a"], collator)); + ASSERT_OK(node.init(update["$bit"]["a"], expCtx)); mutablebson::Document doc(BSON("a" << 0b11110000)); setPathTaken("a"); diff --git a/src/mongo/db/update/compare_node.cpp b/src/mongo/db/update/compare_node.cpp index 744a452002b..fd4e1202a94 100644 --- a/src/mongo/db/update/compare_node.cpp +++ b/src/mongo/db/update/compare_node.cpp @@ -34,10 +34,11 @@ namespace mongo { -Status CompareNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status CompareNode::init(BSONElement modExpr, + const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); _val = modExpr; - setCollator(collator); + setCollator(expCtx->getCollator()); return Status::OK(); } diff --git a/src/mongo/db/update/compare_node.h b/src/mongo/db/update/compare_node.h index 6fe9cbd3084..580d0542201 100644 --- a/src/mongo/db/update/compare_node.h +++ b/src/mongo/db/update/compare_node.h @@ -42,7 +42,7 @@ public: explicit CompareNode(CompareMode mode) : _mode(mode) {} - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<CompareNode>(*this); diff --git a/src/mongo/db/update/compare_node_test.cpp b/src/mongo/db/update/compare_node_test.cpp index 37949aef2dc..16aa4258222 100644 --- a/src/mongo/db/update/compare_node_test.cpp +++ b/src/mongo/db/update/compare_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" @@ -47,16 +48,16 @@ using mongo::mutablebson::countChildren; DEATH_TEST(CompareNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") { auto update = fromjson("{$max: {}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - node.init(update["$max"].embeddedObject().firstElement(), collator).ignore(); + node.init(update["$max"].embeddedObject().firstElement(), expCtx).ignore(); } TEST_F(CompareNodeTest, ApplyMaxSameNumber) { auto update = fromjson("{$max: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -71,9 +72,9 @@ TEST_F(CompareNodeTest, ApplyMaxSameNumber) { TEST_F(CompareNodeTest, ApplyMinSameNumber) { auto update = fromjson("{$min: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMin); - ASSERT_OK(node.init(update["$min"]["a"], collator)); + ASSERT_OK(node.init(update["$min"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -88,9 +89,9 @@ TEST_F(CompareNodeTest, ApplyMinSameNumber) { TEST_F(CompareNodeTest, ApplyMaxNumberIsLess) { auto update = fromjson("{$max: {a: 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -105,9 +106,9 @@ TEST_F(CompareNodeTest, ApplyMaxNumberIsLess) { TEST_F(CompareNodeTest, ApplyMinNumberIsMore) { auto update = fromjson("{$min: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMin); - ASSERT_OK(node.init(update["$min"]["a"], collator)); + ASSERT_OK(node.init(update["$min"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -122,9 +123,9 @@ TEST_F(CompareNodeTest, ApplyMinNumberIsMore) { TEST_F(CompareNodeTest, ApplyMaxSameValInt) { auto update = BSON("$max" << BSON("a" << 1LL)); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1.0}")); setPathTaken("a"); @@ -139,9 +140,9 @@ TEST_F(CompareNodeTest, ApplyMaxSameValInt) { TEST_F(CompareNodeTest, ApplyMaxSameValIntZero) { auto update = BSON("$max" << BSON("a" << 0LL)); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0.0}")); setPathTaken("a"); @@ -156,9 +157,9 @@ TEST_F(CompareNodeTest, ApplyMaxSameValIntZero) { TEST_F(CompareNodeTest, ApplyMinSameValIntZero) { auto update = BSON("$min" << BSON("a" << 0LL)); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMin); - ASSERT_OK(node.init(update["$min"]["a"], collator)); + ASSERT_OK(node.init(update["$min"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0.0}")); setPathTaken("a"); @@ -173,9 +174,9 @@ TEST_F(CompareNodeTest, ApplyMinSameValIntZero) { TEST_F(CompareNodeTest, ApplyMissingFieldMinNumber) { auto update = fromjson("{$min: {a: 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMin); - ASSERT_OK(node.init(update["$min"]["a"], collator)); + ASSERT_OK(node.init(update["$min"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -190,9 +191,9 @@ TEST_F(CompareNodeTest, ApplyMissingFieldMinNumber) { TEST_F(CompareNodeTest, ApplyExistingNumberMinNumber) { auto update = fromjson("{$min: {a: 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMin); - ASSERT_OK(node.init(update["$min"]["a"], collator)); + ASSERT_OK(node.init(update["$min"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -207,9 +208,9 @@ TEST_F(CompareNodeTest, ApplyExistingNumberMinNumber) { TEST_F(CompareNodeTest, ApplyMissingFieldMaxNumber) { auto update = fromjson("{$max: {a: 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -224,9 +225,9 @@ TEST_F(CompareNodeTest, ApplyMissingFieldMaxNumber) { TEST_F(CompareNodeTest, ApplyExistingNumberMaxNumber) { auto update = fromjson("{$max: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -241,9 +242,9 @@ TEST_F(CompareNodeTest, ApplyExistingNumberMaxNumber) { TEST_F(CompareNodeTest, ApplyExistingDateMaxDate) { auto update = fromjson("{$max: {a: {$date: 123123123}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {$date: 0}}")); setPathTaken("a"); @@ -258,9 +259,9 @@ TEST_F(CompareNodeTest, ApplyExistingDateMaxDate) { TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxDoc) { auto update = fromjson("{$max: {a: {b: 3}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a"); @@ -275,9 +276,9 @@ TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxDoc) { TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxNumber) { auto update = fromjson("{$max: {a: 3}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a"); @@ -292,9 +293,11 @@ TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxNumber) { TEST_F(CompareNodeTest, ApplyMinRespectsCollation) { auto update = fromjson("{$min: {a: 'dba'}}"); - const CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); CompareNode node(CompareNode::CompareMode::kMin); - ASSERT_OK(node.init(update["$min"]["a"], &collator)); + ASSERT_OK(node.init(update["$min"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 'cbc'}")); setPathTaken("a"); @@ -309,9 +312,9 @@ TEST_F(CompareNodeTest, ApplyMinRespectsCollation) { TEST_F(CompareNodeTest, ApplyMinRespectsCollationFromSetCollator) { auto update = fromjson("{$min: {a: 'dba'}}"); - const CollatorInterface* binaryComparisonCollator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMin); - ASSERT_OK(node.init(update["$min"]["a"], binaryComparisonCollator)); + ASSERT_OK(node.init(update["$min"]["a"], expCtx)); const CollatorInterfaceMock reverseStringCollator( CollatorInterfaceMock::MockType::kReverseString); @@ -330,9 +333,9 @@ TEST_F(CompareNodeTest, ApplyMinRespectsCollationFromSetCollator) { TEST_F(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) { auto update = fromjson("{$max: {a: 'abd'}}"); - const CollatorInterface* binaryComparisonCollator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], binaryComparisonCollator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); const CollatorInterfaceMock reverseStringCollator( CollatorInterfaceMock::MockType::kReverseString); @@ -351,18 +354,19 @@ TEST_F(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) { DEATH_TEST(CompareNodeTest, CannotSetCollatorIfCollatorIsNonNull, "Invariant failure !_collator") { auto update = fromjson("{$max: {a: 1}}"); - const CollatorInterfaceMock caseInsensitiveCollator( - CollatorInterfaceMock::MockType::kToLowerString); + CollatorInterfaceMock caseInsensitiveCollator(CollatorInterfaceMock::MockType::kToLowerString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&caseInsensitiveCollator); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], &caseInsensitiveCollator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); node.setCollator(&caseInsensitiveCollator); } DEATH_TEST(CompareNodeTest, CannotSetCollatorTwice, "Invariant failure !_collator") { auto update = fromjson("{$max: {a: 1}}"); - const CollatorInterface* binaryComparisonCollator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], binaryComparisonCollator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); const CollatorInterfaceMock caseInsensitiveCollator( CollatorInterfaceMock::MockType::kToLowerString); @@ -372,9 +376,9 @@ DEATH_TEST(CompareNodeTest, CannotSetCollatorTwice, "Invariant failure !_collato TEST_F(CompareNodeTest, ApplyIndexesNotAffected) { auto update = fromjson("{$max: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathTaken("a"); @@ -389,9 +393,9 @@ TEST_F(CompareNodeTest, ApplyIndexesNotAffected) { TEST_F(CompareNodeTest, ApplyNoIndexDataOrLogBuilder) { auto update = fromjson("{$max: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CompareNode node(CompareNode::CompareMode::kMax); - ASSERT_OK(node.init(update["$max"]["a"], collator)); + ASSERT_OK(node.init(update["$max"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathTaken("a"); diff --git a/src/mongo/db/update/conflict_placeholder_node.h b/src/mongo/db/update/conflict_placeholder_node.h index ceb88d69e20..66be569ff7c 100644 --- a/src/mongo/db/update/conflict_placeholder_node.h +++ b/src/mongo/db/update/conflict_placeholder_node.h @@ -44,7 +44,7 @@ namespace mongo { */ class ConflictPlaceholderNode : public UpdateLeafNode { public: - Status init(BSONElement modExpr, const CollatorInterface* collator) final { + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final { return Status::OK(); } diff --git a/src/mongo/db/update/current_date_node.cpp b/src/mongo/db/update/current_date_node.cpp index 4d6075a65f7..057ce2c1779 100644 --- a/src/mongo/db/update/current_date_node.cpp +++ b/src/mongo/db/update/current_date_node.cpp @@ -51,7 +51,8 @@ void setValue(mutablebson::Element* element, bool typeIsDate) { } } // namespace -Status CurrentDateNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status CurrentDateNode::init(BSONElement modExpr, + const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); if (modExpr.type() == BSONType::Bool) { diff --git a/src/mongo/db/update/current_date_node.h b/src/mongo/db/update/current_date_node.h index bac2eb5c857..369ae7037ee 100644 --- a/src/mongo/db/update/current_date_node.h +++ b/src/mongo/db/update/current_date_node.h @@ -38,7 +38,7 @@ namespace mongo { */ class CurrentDateNode : public ModifierNode { public: - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<CurrentDateNode>(*this); diff --git a/src/mongo/db/update/current_date_node_test.cpp b/src/mongo/db/update/current_date_node_test.cpp index 689ada219f6..e9cb5d5a8c8 100644 --- a/src/mongo/db/update/current_date_node_test.cpp +++ b/src/mongo/db/update/current_date_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" @@ -46,86 +47,86 @@ using mongo::mutablebson::countChildren; DEATH_TEST(CurrentDateNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") { auto update = fromjson("{$currentDate: {}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CurrentDateNode node; - node.init(update["$currentDate"].embeddedObject().firstElement(), collator).ignore(); + node.init(update["$currentDate"].embeddedObject().firstElement(), expCtx).ignore(); } TEST(CurrentDateNodeTest, InitWithNonBoolNonObjectFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: 0}}"); CurrentDateNode node; - ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithTrueSucceeds) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: true}}"); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithFalseSucceeds) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: false}}"); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithoutTypeFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: {}}}"); CurrentDateNode node; - ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithNonStringTypeFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: {$type: 1}}}"); CurrentDateNode node; - ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithBadValueTypeFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: {$type: 'bad'}}}"); CurrentDateNode node; - ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithTypeDateSucceeds) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: {$type: 'date'}}}"); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithTypeTimestampSucceeds) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: {$type: 'timestamp'}}}"); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithExtraFieldBeforeFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: {$bad: 1, $type: 'date'}}}"); CurrentDateNode node; - ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST(CurrentDateNodeTest, InitWithExtraFieldAfterFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto update = fromjson("{$currentDate: {a: {$type: 'date', $bad: 1}}}"); CurrentDateNode node; - ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_NOT_OK(node.init(update["$currentDate"]["a"], expCtx)); } TEST_F(CurrentDateNodeTest, ApplyTrue) { auto update = fromjson("{$currentDate: {a: true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathTaken("a"); @@ -147,9 +148,9 @@ TEST_F(CurrentDateNodeTest, ApplyTrue) { TEST_F(CurrentDateNodeTest, ApplyFalse) { auto update = fromjson("{$currentDate: {a: false}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathTaken("a"); @@ -171,9 +172,9 @@ TEST_F(CurrentDateNodeTest, ApplyFalse) { TEST_F(CurrentDateNodeTest, ApplyDate) { auto update = fromjson("{$currentDate: {a: {$type: 'date'}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathTaken("a"); @@ -195,9 +196,9 @@ TEST_F(CurrentDateNodeTest, ApplyDate) { TEST_F(CurrentDateNodeTest, ApplyTimestamp) { auto update = fromjson("{$currentDate: {a: {$type: 'timestamp'}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathTaken("a"); @@ -219,9 +220,9 @@ TEST_F(CurrentDateNodeTest, ApplyTimestamp) { TEST_F(CurrentDateNodeTest, ApplyFieldDoesNotExist) { auto update = fromjson("{$currentDate: {a: true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -243,9 +244,9 @@ TEST_F(CurrentDateNodeTest, ApplyFieldDoesNotExist) { TEST_F(CurrentDateNodeTest, ApplyIndexesNotAffected) { auto update = fromjson("{$currentDate: {a: true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathTaken("a"); @@ -267,9 +268,9 @@ TEST_F(CurrentDateNodeTest, ApplyIndexesNotAffected) { TEST_F(CurrentDateNodeTest, ApplyNoIndexDataOrLogBuilder) { auto update = fromjson("{$currentDate: {a: true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); CurrentDateNode node; - ASSERT_OK(node.init(update["$currentDate"]["a"], collator)); + ASSERT_OK(node.init(update["$currentDate"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathTaken("a"); diff --git a/src/mongo/db/update/path_support_test.cpp b/src/mongo/db/update/path_support_test.cpp index 3de5e8eff00..cb397c01bd1 100644 --- a/src/mongo/db/update/path_support_test.cpp +++ b/src/mongo/db/update/path_support_test.cpp @@ -48,6 +48,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" #include "mongo/util/mongoutils/str.h" @@ -588,8 +589,8 @@ TEST_F(ArrayDoc, CreatePathAtFailsIfElemFoundIsArrayAndIdxFoundFieldIsNonNumeric // static MatchExpression* makeExpr(const BSONObj& exprBSON) { - const CollatorInterface* collator = nullptr; - return MatchExpressionParser::parse(exprBSON, collator).getValue().release(); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + return MatchExpressionParser::parse(exprBSON, std::move(expCtx)).getValue().release(); } static void assertContains(const EqualityMatches& equalities, const BSONObj& wrapped) { diff --git a/src/mongo/db/update/pop_node.cpp b/src/mongo/db/update/pop_node.cpp index 96c495c29a5..412e913455b 100644 --- a/src/mongo/db/update/pop_node.cpp +++ b/src/mongo/db/update/pop_node.cpp @@ -34,7 +34,7 @@ namespace mongo { -Status PopNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status PopNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { auto popVal = MatchExpressionParser::parseIntegerElementToLong(modExpr); if (!popVal.isOK()) { return popVal.getStatus(); diff --git a/src/mongo/db/update/pop_node.h b/src/mongo/db/update/pop_node.h index 2b8d99ce1e7..aaeba88b439 100644 --- a/src/mongo/db/update/pop_node.h +++ b/src/mongo/db/update/pop_node.h @@ -35,7 +35,7 @@ namespace mongo { class PopNode final : public ModifierNode { public: - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; ModifyResult updateExistingElement(mutablebson::Element* element, std::shared_ptr<FieldRef> elementPath) const final; diff --git a/src/mongo/db/update/pop_node_test.cpp b/src/mongo/db/update/pop_node_test.cpp index 8057331fab5..6f431fdb0fa 100644 --- a/src/mongo/db/update/pop_node_test.cpp +++ b/src/mongo/db/update/pop_node_test.cpp @@ -32,6 +32,7 @@ #include "mongo/bson/json.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" @@ -44,67 +45,67 @@ using PopNodeTest = UpdateNodeTest; TEST(PopNodeTest, InitSucceedsPositiveOne) { auto update = fromjson("{$pop: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a"], expCtx)); ASSERT_FALSE(popNode.popFromFront()); } TEST(PopNodeTest, InitSucceedsNegativeOne) { auto update = fromjson("{$pop: {a: -1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a"], expCtx)); ASSERT_TRUE(popNode.popFromFront()); } TEST(PopNodeTest, InitFailsOnePointOne) { auto update = fromjson("{$pop: {a: 1.1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], collator)); + ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], expCtx)); } TEST(PopNodeTest, InitFailsZero) { auto update = fromjson("{$pop: {a: 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], collator)); + ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], expCtx)); } TEST(PopNodeTest, InitFailsString) { auto update = fromjson("{$pop: {a: 'foo'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], collator)); + ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], expCtx)); } TEST(PopNodeTest, InitFailsNestedObject) { auto update = fromjson("{$pop: {a: {b: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], collator)); + ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], expCtx)); } TEST(PopNodeTest, InitFailsNestedArray) { auto update = fromjson("{$pop: {a: [{b: 1}]}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], collator)); + ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], expCtx)); } TEST(PopNodeTest, InitFailsBool) { auto update = fromjson("{$pop: {a: true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], collator)); + ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], expCtx)); } TEST_F(PopNodeTest, NoopWhenFirstPathComponentDoesNotExist) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{b: [1, 2, 3]}")); setPathToCreate("a.b"); @@ -118,9 +119,9 @@ TEST_F(PopNodeTest, NoopWhenFirstPathComponentDoesNotExist) { TEST_F(PopNodeTest, NoopWhenPathPartiallyExists) { auto update = fromjson("{$pop: {'a.b.c': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b.c"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b.c"], expCtx)); mmb::Document doc(fromjson("{a: {}}")); setPathToCreate("b.c"); @@ -135,9 +136,9 @@ TEST_F(PopNodeTest, NoopWhenPathPartiallyExists) { TEST_F(PopNodeTest, NoopWhenNumericalPathComponentExceedsArrayLength) { auto update = fromjson("{$pop: {'a.0': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.0"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.0"], expCtx)); mmb::Document doc(fromjson("{a: []}")); setPathToCreate("0"); @@ -152,9 +153,9 @@ TEST_F(PopNodeTest, NoopWhenNumericalPathComponentExceedsArrayLength) { TEST_F(PopNodeTest, ThrowsWhenPathIsBlockedByAScalar) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{a: 'foo'}")); setPathToCreate("b"); @@ -171,9 +172,9 @@ DEATH_TEST_F(PopNodeTest, NonOkElementWhenPathExistsIsFatal, "Invariant failure applyParams.element.ok()") { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}")); setPathTaken("a.b"); @@ -183,9 +184,9 @@ DEATH_TEST_F(PopNodeTest, TEST_F(PopNodeTest, ThrowsWhenPathExistsButDoesNotContainAnArray) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{a: {b: 'foo'}}")); setPathTaken("a.b"); @@ -198,9 +199,9 @@ TEST_F(PopNodeTest, ThrowsWhenPathExistsButDoesNotContainAnArray) { TEST_F(PopNodeTest, NoopWhenPathContainsAnEmptyArray) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{a: {b: []}}")); setPathTaken("a.b"); @@ -214,9 +215,9 @@ TEST_F(PopNodeTest, NoopWhenPathContainsAnEmptyArray) { TEST_F(PopNodeTest, PopsSingleElementFromTheBack) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); ASSERT_FALSE(popNode.popFromFront()); mmb::Document doc(fromjson("{a: {b: [1]}}")); @@ -231,9 +232,9 @@ TEST_F(PopNodeTest, PopsSingleElementFromTheBack) { TEST_F(PopNodeTest, PopsSingleElementFromTheFront) { auto update = fromjson("{$pop: {'a.b': -1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); ASSERT_TRUE(popNode.popFromFront()); mmb::Document doc(fromjson("{a: {b: [[1]]}}")); @@ -248,9 +249,9 @@ TEST_F(PopNodeTest, PopsSingleElementFromTheFront) { TEST_F(PopNodeTest, PopsFromTheBackOfMultiElementArray) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); ASSERT_FALSE(popNode.popFromFront()); mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}")); @@ -265,9 +266,9 @@ TEST_F(PopNodeTest, PopsFromTheBackOfMultiElementArray) { TEST_F(PopNodeTest, PopsFromTheFrontOfMultiElementArray) { auto update = fromjson("{$pop: {'a.b': -1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); ASSERT_TRUE(popNode.popFromFront()); mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}")); @@ -282,9 +283,9 @@ TEST_F(PopNodeTest, PopsFromTheFrontOfMultiElementArray) { TEST_F(PopNodeTest, PopsFromTheFrontOfMultiElementArrayWithoutAffectingIndexes) { auto update = fromjson("{$pop: {'a.b': -1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); ASSERT_TRUE(popNode.popFromFront()); mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}")); @@ -299,9 +300,9 @@ TEST_F(PopNodeTest, PopsFromTheFrontOfMultiElementArrayWithoutAffectingIndexes) TEST_F(PopNodeTest, SucceedsWithNullUpdateIndexData) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); ASSERT_FALSE(popNode.popFromFront()); mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}")); @@ -315,9 +316,9 @@ TEST_F(PopNodeTest, SucceedsWithNullUpdateIndexData) { TEST_F(PopNodeTest, SucceedsWithNullLogBuilder) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); ASSERT_FALSE(popNode.popFromFront()); mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}")); @@ -332,9 +333,9 @@ TEST_F(PopNodeTest, SucceedsWithNullLogBuilder) { TEST_F(PopNodeTest, ThrowsWhenPathIsImmutable) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{a: {b: [0]}}")); setPathTaken("a.b"); @@ -354,9 +355,9 @@ TEST_F(PopNodeTest, ThrowsWhenPathIsPrefixOfImmutable) { // array in it. auto update = fromjson("{$pop: {'a': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a"], expCtx)); mmb::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -371,9 +372,9 @@ TEST_F(PopNodeTest, ThrowsWhenPathIsPrefixOfImmutable) { TEST_F(PopNodeTest, ThrowsWhenPathIsSuffixOfImmutable) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{a: {b: [0]}}")); setPathTaken("a.b"); @@ -388,9 +389,9 @@ TEST_F(PopNodeTest, ThrowsWhenPathIsSuffixOfImmutable) { TEST_F(PopNodeTest, NoopOnImmutablePathSucceeds) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; - ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator)); + ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{a: {b: []}}")); setPathTaken("a.b"); diff --git a/src/mongo/db/update/pull_node.cpp b/src/mongo/db/update/pull_node.cpp index 9ef4e02724b..b712e2ece4e 100644 --- a/src/mongo/db/update/pull_node.cpp +++ b/src/mongo/db/update/pull_node.cpp @@ -41,8 +41,8 @@ namespace mongo { */ class PullNode::ObjectMatcher final : public PullNode::ElementMatcher { public: - ObjectMatcher(BSONObj matchCondition, const CollatorInterface* collator) - : _matchExpr(matchCondition, collator) {} + ObjectMatcher(BSONObj matchCondition, const boost::intrusive_ptr<ExpressionContext>& expCtx) + : _matchExpr(matchCondition, expCtx) {} std::unique_ptr<ElementMatcher> clone() const final { return stdx::make_unique<ObjectMatcher>(*this); @@ -73,8 +73,9 @@ private: */ class PullNode::WrappedObjectMatcher final : public PullNode::ElementMatcher { public: - WrappedObjectMatcher(BSONElement matchCondition, const CollatorInterface* collator) - : _matchExpr(matchCondition.wrap(""), collator) {} + WrappedObjectMatcher(BSONElement matchCondition, + const boost::intrusive_ptr<ExpressionContext>& expCtx) + : _matchExpr(matchCondition.wrap(""), expCtx) {} std::unique_ptr<ElementMatcher> clone() const final { return stdx::make_unique<WrappedObjectMatcher>(*this); @@ -119,18 +120,18 @@ private: const CollatorInterface* _collator; }; -Status PullNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status PullNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); try { if (modExpr.type() == mongo::Object && !MatchExpressionParser::parsePathAcceptingKeyword( modExpr.embeddedObject().firstElement())) { - _matcher = stdx::make_unique<ObjectMatcher>(modExpr.embeddedObject(), collator); + _matcher = stdx::make_unique<ObjectMatcher>(modExpr.embeddedObject(), expCtx); } else if (modExpr.type() == mongo::Object || modExpr.type() == mongo::RegEx) { - _matcher = stdx::make_unique<WrappedObjectMatcher>(modExpr, collator); + _matcher = stdx::make_unique<WrappedObjectMatcher>(modExpr, expCtx); } else { - _matcher = stdx::make_unique<EqualityMatcher>(modExpr, collator); + _matcher = stdx::make_unique<EqualityMatcher>(modExpr, expCtx->getCollator()); } } catch (AssertionException& exception) { return exception.toStatus(); diff --git a/src/mongo/db/update/pull_node.h b/src/mongo/db/update/pull_node.h index 346c6da7f04..c12019686e5 100644 --- a/src/mongo/db/update/pull_node.h +++ b/src/mongo/db/update/pull_node.h @@ -42,7 +42,7 @@ namespace mongo { */ class PullNode final : public ArrayCullingNode { public: - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<PullNode>(*this); diff --git a/src/mongo/db/update/pull_node_test.cpp b/src/mongo/db/update/pull_node_test.cpp index 2fc996d05f1..744abd739f4 100644 --- a/src/mongo/db/update/pull_node_test.cpp +++ b/src/mongo/db/update/pull_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" @@ -47,36 +48,36 @@ using mongo::mutablebson::countChildren; TEST(PullNodeTest, InitWithBadMatchExpressionFails) { auto update = fromjson("{$pull: {a: {b: {$foo: 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - auto status = node.init(update["$pull"]["a"], collator); + auto status = node.init(update["$pull"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PullNodeTest, InitWithBadTopLevelOperatorFails) { auto update = fromjson("{$pull: {a: {$foo: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - auto status = node.init(update["$pull"]["a"], collator); + auto status = node.init(update["$pull"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PullNodeTest, InitWithTextFails) { auto update = fromjson("{$pull: {a: {$text: {$search: 'str'}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - auto status = node.init(update["$pull"]["a"], collator); + auto status = node.init(update["$pull"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PullNodeTest, InitWithWhereFails) { auto update = fromjson("{$pull: {a: {$where: 'this.a == this.b'}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - auto status = node.init(update["$pull"]["a"], collator); + auto status = node.init(update["$pull"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -84,9 +85,9 @@ TEST(PullNodeTest, InitWithWhereFails) { TEST(PullNodeTest, InitWithGeoNearElemFails) { auto update = fromjson("{$pull: {a: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - auto status = node.init(update["$pull"]["a"], collator); + auto status = node.init(update["$pull"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -94,36 +95,36 @@ TEST(PullNodeTest, InitWithGeoNearElemFails) { TEST(PullNodeTest, InitWithGeoNearObjectFails) { auto update = fromjson( "{$pull: {a: {b: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - auto status = node.init(update["$pull"]["a"], collator); + auto status = node.init(update["$pull"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PullNodeTest, InitWithExprElemFails) { auto update = fromjson("{$pull: {a: {$expr: {$eq: [5, 5]}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - auto status = node.init(update["$pull"]["a"], collator); + auto status = node.init(update["$pull"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PullNodeTest, InitWithExprObjectFails) { auto update = fromjson("{$pull: {a: {$expr: {$eq: ['$a', {$literal: {b: 5}}]}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - auto status = node.init(update["$pull"]["a"], collator); + auto status = node.init(update["$pull"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST_F(PullNodeTest, TargetNotFound) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -138,9 +139,9 @@ TEST_F(PullNodeTest, TargetNotFound) { TEST_F(PullNodeTest, ApplyToStringFails) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 'foo'}")); setPathTaken("a"); @@ -153,9 +154,9 @@ TEST_F(PullNodeTest, ApplyToStringFails) { TEST_F(PullNodeTest, ApplyToObjectFails) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {foo: 'bar'}}")); setPathTaken("a"); @@ -168,9 +169,9 @@ TEST_F(PullNodeTest, ApplyToObjectFails) { TEST_F(PullNodeTest, ApplyToNonViablePathFails) { auto update = fromjson("{$pull : {'a.b': {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a.b"], collator)); + ASSERT_OK(node.init(update["$pull"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathToCreate("b"); @@ -185,9 +186,9 @@ TEST_F(PullNodeTest, ApplyToNonViablePathFails) { TEST_F(PullNodeTest, ApplyToMissingElement) { auto update = fromjson("{$pull: {'a.b.c.d': {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a.b.c.d"], collator)); + ASSERT_OK(node.init(update["$pull"]["a.b.c.d"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: {}}}}")); setPathToCreate("d"); @@ -203,9 +204,9 @@ TEST_F(PullNodeTest, ApplyToMissingElement) { TEST_F(PullNodeTest, ApplyToEmptyArray) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -220,9 +221,9 @@ TEST_F(PullNodeTest, ApplyToEmptyArray) { TEST_F(PullNodeTest, ApplyToArrayMatchingNone) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [2, 3, 4, 5]}")); setPathTaken("a"); @@ -237,9 +238,9 @@ TEST_F(PullNodeTest, ApplyToArrayMatchingNone) { TEST_F(PullNodeTest, ApplyToArrayMatchingOne) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2, 3]}")); setPathTaken("a"); @@ -254,9 +255,9 @@ TEST_F(PullNodeTest, ApplyToArrayMatchingOne) { TEST_F(PullNodeTest, ApplyToArrayMatchingSeveral) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]}")); setPathTaken("a"); @@ -271,9 +272,9 @@ TEST_F(PullNodeTest, ApplyToArrayMatchingSeveral) { TEST_F(PullNodeTest, ApplyToArrayMatchingAll) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, -1, -2, -3, -4, -5]}")); setPathTaken("a"); @@ -288,9 +289,9 @@ TEST_F(PullNodeTest, ApplyToArrayMatchingAll) { TEST_F(PullNodeTest, ApplyNoIndexDataNoLogBuilder) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2, 3]}")); setPathTaken("a"); @@ -307,8 +308,10 @@ TEST_F(PullNodeTest, ApplyWithCollation) { // reverse of the "abc" string. auto update = fromjson("{$pull : {a: {$gt: 'abc'}}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], &collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: ['zaa', 'zcc', 'zbb', 'zee']}")); setPathTaken("a"); @@ -324,8 +327,10 @@ TEST_F(PullNodeTest, ApplyWithCollation) { TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectNonStringMatches) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], &collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [2, 1, 0, -1, -2, -3]}")); setPathTaken("a"); @@ -341,8 +346,10 @@ TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectNonStringMatches) { TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectRegexMatches) { auto update = fromjson("{$pull : {a: /a/}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], &collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: ['b', 'a', 'aab', 'cb', 'bba']}")); setPathTaken("a"); @@ -358,8 +365,10 @@ TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectRegexMatches) { TEST_F(PullNodeTest, ApplyStringLiteralMatchWithCollation) { auto update = fromjson("{$pull : {a: 'c'}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], &collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: ['b', 'a', 'aab', 'cb', 'bba']}")); setPathTaken("a"); @@ -375,8 +384,10 @@ TEST_F(PullNodeTest, ApplyStringLiteralMatchWithCollation) { TEST_F(PullNodeTest, ApplyCollationDoesNotAffectNumberLiteralMatches) { auto update = fromjson("{$pull : {a: 99}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], &collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: ['a', 99, 'b', 2, 'c', 99, 'd']}")); setPathTaken("a"); @@ -392,8 +403,8 @@ TEST_F(PullNodeTest, ApplyCollationDoesNotAffectNumberLiteralMatches) { TEST_F(PullNodeTest, ApplyStringMatchAfterSetCollator) { auto update = fromjson("{$pull : {a: 'c'}}"); PullNode node; - const CollatorInterface* collator = nullptr; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); // First without a collator. mutablebson::Document doc(fromjson("{ a : ['a', 'b', 'c', 'd'] }")); @@ -420,8 +431,8 @@ TEST_F(PullNodeTest, ApplyStringMatchAfterSetCollator) { TEST_F(PullNodeTest, ApplyElementMatchAfterSetCollator) { auto update = fromjson("{$pull : {a: {$gte: 'c'}}}"); PullNode node; - const CollatorInterface* collator = nullptr; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); // First without a collator. mutablebson::Document doc(fromjson("{ a : ['a', 'b', 'c', 'd'] }")); @@ -448,8 +459,8 @@ TEST_F(PullNodeTest, ApplyElementMatchAfterSetCollator) { TEST_F(PullNodeTest, ApplyObjectMatchAfterSetCollator) { auto update = fromjson("{$pull : {a: {b: 'y'}}}"); PullNode node; - const CollatorInterface* collator = nullptr; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); // First without a collator. mutablebson::Document doc(fromjson("{a : [{b: 'w'}, {b: 'x'}, {b: 'y'}, {b: 'z'}]}")); @@ -476,8 +487,8 @@ TEST_F(PullNodeTest, ApplyObjectMatchAfterSetCollator) { TEST_F(PullNodeTest, SetCollatorDoesNotAffectClone) { auto update = fromjson("{$pull : {a: 'c'}}"); PullNode node; - const CollatorInterface* collator = nullptr; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); auto cloneNode = node.clone(); @@ -510,9 +521,9 @@ TEST_F(PullNodeTest, ApplyComplexDocAndMatching1) { " {'y': {$exists: true }}," " {'z' : {$exists : true}} " "]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a.b"], collator)); + ASSERT_OK(node.init(update["$pull"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: [{x: 1}, {y: 'y'}, {x: 2}, {z: 'z'}]}}")); setPathTaken("a.b"); @@ -527,9 +538,9 @@ TEST_F(PullNodeTest, ApplyComplexDocAndMatching1) { TEST_F(PullNodeTest, ApplyComplexDocAndMatching2) { auto update = fromjson("{$pull: {'a.b': {'y': {$exists: true}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a.b"], collator)); + ASSERT_OK(node.init(update["$pull"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: [{x: 1}, {y: 'y'}, {x: 2}, {z: 'z'}]}}")); setPathTaken("a.b"); @@ -544,9 +555,9 @@ TEST_F(PullNodeTest, ApplyComplexDocAndMatching2) { TEST_F(PullNodeTest, ApplyComplexDocAndMatching3) { auto update = fromjson("{$pull: {'a.b': {$in: [{x: 1}, {y: 'y'}]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a.b"], collator)); + ASSERT_OK(node.init(update["$pull"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: [{x: 1}, {y: 'y'}, {x: 2}, {z: 'z'}]}}")); setPathTaken("a.b"); @@ -562,8 +573,10 @@ TEST_F(PullNodeTest, ApplyComplexDocAndMatching3) { TEST_F(PullNodeTest, ApplyFullPredicateWithCollation) { auto update = fromjson("{$pull: {'a.b': {x: 'blah'}}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a.b"], &collator)); + ASSERT_OK(node.init(update["$pull"]["a.b"], expCtx)); mutablebson::Document doc( fromjson("{a: {b: [{x: 'foo', y: 1}, {x: 'bar', y: 2}, {x: 'baz', y: 3}]}}")); @@ -579,9 +592,9 @@ TEST_F(PullNodeTest, ApplyFullPredicateWithCollation) { TEST_F(PullNodeTest, ApplyScalarValueMod) { auto update = fromjson("{$pull: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 2, 1, 2, 1, 2]}")); setPathTaken("a"); @@ -596,9 +609,9 @@ TEST_F(PullNodeTest, ApplyScalarValueMod) { TEST_F(PullNodeTest, ApplyObjectValueMod) { auto update = fromjson("{$pull: {a: {y: 2}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [{x: 1}, {y: 2}, {x: 1}, {y: 2}]}")); setPathTaken("a"); @@ -613,9 +626,9 @@ TEST_F(PullNodeTest, ApplyObjectValueMod) { TEST_F(PullNodeTest, DocumentationExample1) { auto update = fromjson("{$pull: {flags: 'msr'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["flags"], collator)); + ASSERT_OK(node.init(update["$pull"]["flags"], expCtx)); mutablebson::Document doc( fromjson("{flags: ['vme', 'de', 'pse', 'tsc', 'msr', 'pae', 'mce']}")); @@ -632,9 +645,9 @@ TEST_F(PullNodeTest, DocumentationExample1) { TEST_F(PullNodeTest, DocumentationExample2a) { auto update = fromjson("{$pull: {votes: 7}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["votes"], collator)); + ASSERT_OK(node.init(update["$pull"]["votes"], expCtx)); mutablebson::Document doc(fromjson("{votes: [3, 5, 6, 7, 7, 8]}")); setPathTaken("votes"); @@ -649,9 +662,9 @@ TEST_F(PullNodeTest, DocumentationExample2a) { TEST_F(PullNodeTest, DocumentationExample2b) { auto update = fromjson("{$pull: {votes: {$gt: 6}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["votes"], collator)); + ASSERT_OK(node.init(update["$pull"]["votes"], expCtx)); mutablebson::Document doc(fromjson("{votes: [3, 5, 6, 7, 7, 8]}")); setPathTaken("votes"); @@ -666,9 +679,9 @@ TEST_F(PullNodeTest, DocumentationExample2b) { TEST_F(PullNodeTest, ApplyPullWithObjectValueToArrayWithNonObjectValue) { auto update = fromjson("{$pull: {a: {x: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["a"], collator)); + ASSERT_OK(node.init(update["$pull"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [{x: 1}, 2]}")); setPathTaken("a"); @@ -683,9 +696,9 @@ TEST_F(PullNodeTest, ApplyPullWithObjectValueToArrayWithNonObjectValue) { TEST_F(PullNodeTest, CannotModifyImmutableField) { auto update = fromjson("{$pull: {'_id.a': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["_id.a"], collator)); + ASSERT_OK(node.init(update["$pull"]["_id.a"], expCtx)); mutablebson::Document doc(fromjson("{_id: {a: [0, 1, 2]}}")); setPathTaken("_id.a"); @@ -699,9 +712,9 @@ TEST_F(PullNodeTest, CannotModifyImmutableField) { TEST_F(PullNodeTest, SERVER_3988) { auto update = fromjson("{$pull: {y: /yz/}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullNode node; - ASSERT_OK(node.init(update["$pull"]["y"], collator)); + ASSERT_OK(node.init(update["$pull"]["y"], expCtx)); mutablebson::Document doc(fromjson("{x: 1, y: [2, 3, 4, 'abc', 'xyz']}")); setPathTaken("y"); diff --git a/src/mongo/db/update/pullall_node.cpp b/src/mongo/db/update/pullall_node.cpp index afdceaac3d5..ec54796eb3e 100644 --- a/src/mongo/db/update/pullall_node.cpp +++ b/src/mongo/db/update/pullall_node.cpp @@ -61,7 +61,8 @@ private: const CollatorInterface* _collator; }; -Status PullAllNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status PullAllNode::init(BSONElement modExpr, + const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); if (modExpr.type() != Array) { @@ -70,7 +71,7 @@ Status PullAllNode::init(BSONElement modExpr, const CollatorInterface* collator) << typeName(modExpr.type())); } - _matcher = stdx::make_unique<SetMatcher>(modExpr.Array(), collator); + _matcher = stdx::make_unique<SetMatcher>(modExpr.Array(), expCtx->getCollator()); return Status::OK(); } diff --git a/src/mongo/db/update/pullall_node.h b/src/mongo/db/update/pullall_node.h index b1d960976ed..0a552323f19 100644 --- a/src/mongo/db/update/pullall_node.h +++ b/src/mongo/db/update/pullall_node.h @@ -42,7 +42,7 @@ namespace mongo { class PullAllNode final : public ArrayCullingNode { public: - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<PullAllNode>(*this); diff --git a/src/mongo/db/update/pullall_node_test.cpp b/src/mongo/db/update/pullall_node_test.cpp index 03ba5290d62..edcc22370ed 100644 --- a/src/mongo/db/update/pullall_node_test.cpp +++ b/src/mongo/db/update/pullall_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" @@ -47,45 +48,45 @@ using mongo::mutablebson::countChildren; TEST(PullAllNodeTest, InitWithIntFails) { auto update = fromjson("{$pullAll: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - auto status = node.init(update["$pullAll"]["a"], collator); + auto status = node.init(update["$pullAll"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PullAllNodeTest, InitWithStringFails) { auto update = fromjson("{$pullAll: {a: 'test'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - auto status = node.init(update["$pullAll"]["a"], collator); + auto status = node.init(update["$pullAll"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PullAllNodeTest, InitWithObjectFails) { auto update = fromjson("{$pullAll: {a: {}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - auto status = node.init(update["$pullAll"]["a"], collator); + auto status = node.init(update["$pullAll"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PullAllNodeTest, InitWithBoolFails) { auto update = fromjson("{$pullAll: {a: true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - auto status = node.init(update["$pullAll"]["a"], collator); + auto status = node.init(update["$pullAll"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST_F(PullAllNodeTest, TargetNotFound) { auto update = fromjson("{$pullAll : {b: [1]}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["b"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["b"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}")); setPathToCreate("b"); @@ -100,9 +101,9 @@ TEST_F(PullAllNodeTest, TargetNotFound) { TEST_F(PullAllNodeTest, TargetArrayElementNotFound) { auto update = fromjson("{$pullAll : {'a.2': [1]}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a.2"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a.2"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 2]}")); setPathToCreate("2"); @@ -118,9 +119,9 @@ TEST_F(PullAllNodeTest, TargetArrayElementNotFound) { TEST_F(PullAllNodeTest, ApplyToNonArrayFails) { auto update = fromjson("{$pullAll : {'a.0': [1, 2]}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a.0"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a.0"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 2]}")); setPathTaken("a.0"); @@ -133,9 +134,9 @@ TEST_F(PullAllNodeTest, ApplyToNonArrayFails) { TEST_F(PullAllNodeTest, ApplyWithSingleNumber) { auto update = fromjson("{$pullAll : {a: [1]}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}")); setPathTaken("a"); @@ -150,9 +151,9 @@ TEST_F(PullAllNodeTest, ApplyWithSingleNumber) { TEST_F(PullAllNodeTest, ApplyNoIndexDataNoLogBuilder) { auto update = fromjson("{$pullAll : {a: [1]}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}")); setPathTaken("a"); @@ -166,9 +167,9 @@ TEST_F(PullAllNodeTest, ApplyNoIndexDataNoLogBuilder) { TEST_F(PullAllNodeTest, ApplyWithElementNotPresentInArray) { auto update = fromjson("{$pullAll : {a: ['r']}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}")); setPathTaken("a"); @@ -183,9 +184,9 @@ TEST_F(PullAllNodeTest, ApplyWithElementNotPresentInArray) { TEST_F(PullAllNodeTest, ApplyWithWithTwoElements) { auto update = fromjson("{$pullAll : {a: [1, 'a']}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}")); setPathTaken("a"); @@ -200,9 +201,9 @@ TEST_F(PullAllNodeTest, ApplyWithWithTwoElements) { TEST_F(PullAllNodeTest, ApplyWithAllArrayElements) { auto update = fromjson("{$pullAll : {a: [1, 'a', {r: 1, b: 2}]}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}")); setPathTaken("a"); @@ -217,9 +218,9 @@ TEST_F(PullAllNodeTest, ApplyWithAllArrayElements) { TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsButOutOfOrder) { auto update = fromjson("{$pullAll : {a: [{r: 1, b: 2}, 1, 'a']}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}")); setPathTaken("a"); @@ -234,9 +235,9 @@ TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsButOutOfOrder) { TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsAndThenSome) { auto update = fromjson("{$pullAll : {a: [2, 3, 1, 'r', {r: 1, b: 2}, 'a']}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}")); setPathTaken("a"); @@ -252,8 +253,10 @@ TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsAndThenSome) { TEST_F(PullAllNodeTest, ApplyWithCollator) { auto update = fromjson("{$pullAll : {a: ['FOO', 'BAR']}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], &collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: ['foo', 'bar', 'baz']}")); setPathTaken("a"); @@ -268,9 +271,9 @@ TEST_F(PullAllNodeTest, ApplyWithCollator) { TEST_F(PullAllNodeTest, ApplyAfterSetCollator) { auto update = fromjson("{$pullAll : {a: ['FOO', 'BAR']}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PullAllNode node; - ASSERT_OK(node.init(update["$pullAll"]["a"], collator)); + ASSERT_OK(node.init(update["$pullAll"]["a"], expCtx)); // First without a collator. mutablebson::Document doc(fromjson("{a: ['foo', 'bar', 'baz']}")); diff --git a/src/mongo/db/update/push_node.cpp b/src/mongo/db/update/push_node.cpp index 84748ae7caa..ac235e722f9 100644 --- a/src/mongo/db/update/push_node.cpp +++ b/src/mongo/db/update/push_node.cpp @@ -82,7 +82,7 @@ Status checkSortClause(const BSONObj& sortObject) { } // namespace -Status PushNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status PushNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); if (modExpr.type() == BSONType::Object && modExpr[kEachClauseName]) { @@ -148,14 +148,14 @@ Status PushNode::init(BSONElement modExpr, const CollatorInterface* collator) { auto status = checkSortClause(sortClause.embeddedObject()); if (status.isOK()) { - _sort = PatternElementCmp(sortClause.embeddedObject(), collator); + _sort = PatternElementCmp(sortClause.embeddedObject(), expCtx->getCollator()); } else { return status; } } else if (sortClause.isNumber()) { double orderVal = sortClause.Number(); if (orderVal == -1 || orderVal == 1) { - _sort = PatternElementCmp(BSON("" << orderVal), collator); + _sort = PatternElementCmp(BSON("" << orderVal), expCtx->getCollator()); } else { return Status(ErrorCodes::BadValue, "The $sort element value must be either 1 or -1"); diff --git a/src/mongo/db/update/push_node.h b/src/mongo/db/update/push_node.h index 66e93d03393..cf636820d8a 100644 --- a/src/mongo/db/update/push_node.h +++ b/src/mongo/db/update/push_node.h @@ -43,7 +43,7 @@ public: PushNode() : _slice(std::numeric_limits<long long>::max()), _position(std::numeric_limits<long long>::max()) {} - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<PushNode>(*this); diff --git a/src/mongo/db/update/push_node_test.cpp b/src/mongo/db/update/push_node_test.cpp index 3525a4b8767..6eefb09bd53 100644 --- a/src/mongo/db/update/push_node_test.cpp +++ b/src/mongo/db/update/push_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" @@ -47,123 +48,123 @@ using mongo::mutablebson::countChildren; TEST(PushNodeTest, EachClauseWithNonArrayObjectFails) { auto update = fromjson("{$push: {x: {$each: {'0': 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, EachClauseWithPrimitiveFails) { auto update = fromjson("{$push: {x: {$each: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, PositionClauseWithObjectFails) { auto update = fromjson("{$push: {x: {$each: [1, 2], $position: {a: 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, PositionClauseWithNonIntegerFails) { auto update = fromjson("{$push: {x: {$each: [1, 2], $position: -2.1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, PositionClauseWithIntegerDoubleSucceeds) { auto update = fromjson("{$push: {x: {$each: [1, 2], $position: -2.0}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_OK(status); } TEST(PushNodeTest, SliceClauseWithObjectFails) { auto update = fromjson("{$push: {x: {$each: [1, 2], $slice: {a: 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, SliceClauseWithNonIntegerFails) { auto update = fromjson("{$push: {x: {$each: [1, 2], $slice: -2.1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, SliceClauseWithIntegerDoubleSucceeds) { auto update = fromjson("{$push: {x: {$each: [1, 2], $slice: 2.0}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["x"], collator)); + ASSERT_OK(node.init(update["$push"]["x"], expCtx)); } TEST(PushNodeTest, SliceClauseWithArrayFails) { auto update = fromjson("{$push: {x: {$each: [1, 2], $slice: [1, 2]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, SliceClauseWithStringFails) { auto update = fromjson("{$push: {x: {$each: [1, 2], $slice: '-1'}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, SortClauseWithArrayFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: [{a: 1}]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, SortClauseWithInvalidSortPatternFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: {a: 100}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, SortClauseWithEmptyPathFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: {'': 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, SortClauseWithEmptyFieldNamesFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: {'.': 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -171,9 +172,9 @@ TEST(PushNodeTest, SortClauseWithEmptyFieldNamesFails) { TEST(PushNodeTest, SortClauseWithEmptyFieldSuffixFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: {'a.': 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -181,9 +182,9 @@ TEST(PushNodeTest, SortClauseWithEmptyFieldSuffixFails) { TEST(PushNodeTest, SortClauseWithEmptyFieldPrefixFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: {'.b': 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -191,27 +192,27 @@ TEST(PushNodeTest, SortClauseWithEmptyFieldPrefixFails) { TEST(PushNodeTest, SortClauseWithEmptyFieldInfixFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: {'a..b': 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, SortClauseWithEmptyObjectFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: {}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, PushEachWithInvalidClauseFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1}, {a: 2}], $xxx: -1, $sort: {a: 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -219,9 +220,9 @@ TEST(PushNodeTest, PushEachWithInvalidClauseFails) { TEST(PushNodeTest, PushEachWithDuplicateSortClauseFails) { auto update = fromjson( "{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $sort: {a: 1}, $sort: {a: 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -229,9 +230,9 @@ TEST(PushNodeTest, PushEachWithDuplicateSortClauseFails) { TEST(PushNodeTest, PushEachWithDuplicateSliceClauseFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1},{a: 2}], $slice: -2.0, $slice: -2, $sort: {a: 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -239,27 +240,27 @@ TEST(PushNodeTest, PushEachWithDuplicateSliceClauseFails) { TEST(PushNodeTest, PushEachWithDuplicateEachClauseFails) { auto update = fromjson("{$push: {x: {$each:[{a: 1}], $each:[{a: 2}], $slice: -3, $sort: {a: 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(PushNodeTest, PushEachWithDuplicatePositionClauseFails) { auto update = fromjson("{$push: {x: {$each: [{a: 1}], $position: 1, $position: 2}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - auto status = node.init(update["$push"]["x"], collator); + auto status = node.init(update["$push"]["x"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST_F(PushNodeTest, ApplyToNonArrayFails) { auto update = fromjson("{$push: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: 1}")); setPathTaken("a"); @@ -273,9 +274,9 @@ TEST_F(PushNodeTest, ApplyToNonArrayFails) { TEST_F(PushNodeTest, ApplyToEmptyArray) { auto update = fromjson("{$push: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -290,9 +291,9 @@ TEST_F(PushNodeTest, ApplyToEmptyArray) { TEST_F(PushNodeTest, ApplyToEmptyDocument) { auto update = fromjson("{$push: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -307,9 +308,9 @@ TEST_F(PushNodeTest, ApplyToEmptyDocument) { TEST_F(PushNodeTest, ApplyToArrayWithOneElement) { auto update = fromjson("{$push: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -324,9 +325,9 @@ TEST_F(PushNodeTest, ApplyToArrayWithOneElement) { TEST_F(PushNodeTest, ApplyToDottedPathElement) { auto update = fromjson("{$push: {'choices.first.votes': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["choices.first.votes"], collator)); + ASSERT_OK(node.init(update["$push"]["choices.first.votes"], expCtx)); mutablebson::Document doc( fromjson("{_id : 1 , " @@ -352,9 +353,9 @@ TEST_F(PushNodeTest, ApplyToDottedPathElement) { TEST_F(PushNodeTest, ApplySimpleEachToEmptyArray) { auto update = fromjson("{$push: {a: {$each: [1]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -369,9 +370,9 @@ TEST_F(PushNodeTest, ApplySimpleEachToEmptyArray) { TEST_F(PushNodeTest, ApplySimpleEachToEmptyDocument) { auto update = fromjson("{$push: {a: {$each: [1]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -386,9 +387,9 @@ TEST_F(PushNodeTest, ApplySimpleEachToEmptyDocument) { TEST_F(PushNodeTest, ApplyMultipleEachToEmptyDocument) { auto update = fromjson("{$push: {a: {$each: [1, 2]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -403,9 +404,9 @@ TEST_F(PushNodeTest, ApplyMultipleEachToEmptyDocument) { TEST_F(PushNodeTest, ApplySimpleEachToArrayWithOneElement) { auto update = fromjson("{$push: {a: {$each: [1]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -420,9 +421,9 @@ TEST_F(PushNodeTest, ApplySimpleEachToArrayWithOneElement) { TEST_F(PushNodeTest, ApplyMultipleEachToArrayWithOneElement) { auto update = fromjson("{$push: {a: {$each: [1, 2]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -437,9 +438,9 @@ TEST_F(PushNodeTest, ApplyMultipleEachToArrayWithOneElement) { TEST_F(PushNodeTest, ApplyEmptyEachToEmptyArray) { auto update = fromjson("{$push: {a: {$each: []}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -454,9 +455,9 @@ TEST_F(PushNodeTest, ApplyEmptyEachToEmptyArray) { TEST_F(PushNodeTest, ApplyEmptyEachToEmptyDocument) { auto update = fromjson("{$push: {a: {$each: []}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -471,9 +472,9 @@ TEST_F(PushNodeTest, ApplyEmptyEachToEmptyDocument) { TEST_F(PushNodeTest, ApplyEmptyEachToArrayWithOneElement) { auto update = fromjson("{$push: {a: {$each: []}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -488,9 +489,9 @@ TEST_F(PushNodeTest, ApplyEmptyEachToArrayWithOneElement) { TEST_F(PushNodeTest, ApplyToArrayWithSlice) { auto update = fromjson("{$push: {a: {$each: [2, -1], $slice: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [3]}")); setPathTaken("a"); @@ -505,9 +506,9 @@ TEST_F(PushNodeTest, ApplyToArrayWithSlice) { TEST_F(PushNodeTest, ApplyWithNumericSort) { auto update = fromjson("{$push: {a: {$each: [2, -1], $sort: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [3]}")); setPathTaken("a"); @@ -522,9 +523,9 @@ TEST_F(PushNodeTest, ApplyWithNumericSort) { TEST_F(PushNodeTest, ApplyWithReverseNumericSort) { auto update = fromjson("{$push: {a: {$each: [4, -1], $sort: -1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [3]}")); setPathTaken("a"); @@ -539,9 +540,9 @@ TEST_F(PushNodeTest, ApplyWithReverseNumericSort) { TEST_F(PushNodeTest, ApplyWithMixedSort) { auto update = fromjson("{$push: {a: {$each: [4, -1], $sort: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [3, 't', {b: 1}, {a: 1}]}")); setPathTaken("a"); @@ -556,9 +557,9 @@ TEST_F(PushNodeTest, ApplyWithMixedSort) { TEST_F(PushNodeTest, ApplyWithReverseMixedSort) { auto update = fromjson("{$push: {a: {$each: [4, -1], $sort: -1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [3, 't', {b: 1}, {a: 1}]}")); setPathTaken("a"); @@ -573,9 +574,9 @@ TEST_F(PushNodeTest, ApplyWithReverseMixedSort) { TEST_F(PushNodeTest, ApplyWithEmbeddedFieldSort) { auto update = fromjson("{$push: {a: {$each: [4, -1], $sort: {a: 1}}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [3, 't', {b: 1}, {a: 1}]}")); setPathTaken("a"); @@ -591,8 +592,10 @@ TEST_F(PushNodeTest, ApplyWithEmbeddedFieldSort) { TEST_F(PushNodeTest, ApplySortWithCollator) { auto update = fromjson("{$push: {a: {$each: ['ha'], $sort: 1}}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], &collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: ['dd', 'fc', 'gb']}")); setPathTaken("a"); @@ -607,9 +610,9 @@ TEST_F(PushNodeTest, ApplySortWithCollator) { TEST_F(PushNodeTest, ApplySortAfterSetCollator) { auto update = fromjson("{$push: {a: {$each: ['ha'], $sort: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: ['dd', 'fc', 'gb']}")); setPathTaken("a"); @@ -666,9 +669,9 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithSliceValues) { for (const auto& data : testDataList) { auto update = BSON( "$push" << BSON("a" << BSON("$each" << BSON_ARRAY(1) << "$slice" << data.sliceValue))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -698,9 +701,9 @@ TEST_F(PushNodeTest, ApplyToPopulatedArrayWithSliceValues) { for (const auto& data : testDataList) { auto update = BSON( "$push" << BSON("a" << BSON("$each" << BSON_ARRAY(1) << "$slice" << data.sliceValue))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [2, 3]}")); setPathTaken("a"); @@ -799,9 +802,9 @@ TEST_F(PushNodeTest, ApplyToPopulatedArrayWithSortAndSliceValues) { << data.sliceValue << "$sort" << data.sortOrder))); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [{a: 2, b: 3}, {a: 3, b: 1}]}")); setPathTaken("a"); @@ -813,9 +816,9 @@ TEST_F(PushNodeTest, ApplyToPopulatedArrayWithSortAndSliceValues) { TEST_F(PushNodeTest, ApplyToEmptyArrayWithPositionZero) { auto update = fromjson("{$push: {a: {$each: [1], $position: 0}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -830,9 +833,9 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithPositionZero) { TEST_F(PushNodeTest, ApplyToEmptyArrayWithPositionOne) { auto update = fromjson("{$push: {a: {$each: [1], $position: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -847,9 +850,9 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithPositionOne) { TEST_F(PushNodeTest, ApplyToEmptyArrayWithLargePosition) { auto update = fromjson("{$push: {a: {$each: [1], $position: 1000}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -864,9 +867,9 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithLargePosition) { TEST_F(PushNodeTest, ApplyToSingletonArrayWithPositionZero) { auto update = fromjson("{$push: {a: {$each: [1], $position: 0}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -881,9 +884,9 @@ TEST_F(PushNodeTest, ApplyToSingletonArrayWithPositionZero) { TEST_F(PushNodeTest, ApplyToSingletonArrayWithLargePosition) { auto update = fromjson("{$push: {a: {$each: [1], $position: 1000}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -898,9 +901,9 @@ TEST_F(PushNodeTest, ApplyToSingletonArrayWithLargePosition) { TEST_F(PushNodeTest, ApplyToEmptyArrayWithNegativePosition) { auto update = fromjson("{$push: {a: {$each: [1], $position: -1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathTaken("a"); @@ -915,9 +918,9 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithNegativePosition) { TEST_F(PushNodeTest, ApplyToSingletonArrayWithNegativePosition) { auto update = fromjson("{$push: {a: {$each: [1], $position: -1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0]}")); setPathTaken("a"); @@ -932,9 +935,9 @@ TEST_F(PushNodeTest, ApplyToSingletonArrayWithNegativePosition) { TEST_F(PushNodeTest, ApplyToPopulatedArrayWithNegativePosition) { auto update = fromjson("{$push: {a: {$each: [5], $position: -2}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2, 3, 4]}")); setPathTaken("a"); @@ -949,9 +952,9 @@ TEST_F(PushNodeTest, ApplyToPopulatedArrayWithNegativePosition) { TEST_F(PushNodeTest, ApplyToPopulatedArrayWithOutOfBoundsNegativePosition) { auto update = fromjson("{$push: {a: {$each: [5], $position: -1000}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2, 3, 4]}")); setPathTaken("a"); @@ -966,9 +969,9 @@ TEST_F(PushNodeTest, ApplyToPopulatedArrayWithOutOfBoundsNegativePosition) { TEST_F(PushNodeTest, ApplyMultipleElementsPushWithNegativePosition) { auto update = fromjson("{$push: {a: {$each: [5, 6, 7], $position: -2}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PushNode node; - ASSERT_OK(node.init(update["$push"]["a"], collator)); + ASSERT_OK(node.init(update["$push"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2, 3, 4]}")); setPathTaken("a"); diff --git a/src/mongo/db/update/rename_node.cpp b/src/mongo/db/update/rename_node.cpp index fc50de42567..bae93e460de 100644 --- a/src/mongo/db/update/rename_node.cpp +++ b/src/mongo/db/update/rename_node.cpp @@ -60,7 +60,7 @@ public: void setCollator(const CollatorInterface* collator) final {} - Status init(BSONElement modExpr, const CollatorInterface* collator) { + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { return Status::OK(); } @@ -99,7 +99,8 @@ private: } // namespace -Status RenameNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status RenameNode::init(BSONElement modExpr, + const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); invariant(BSONType::String == modExpr.type()); diff --git a/src/mongo/db/update/rename_node.h b/src/mongo/db/update/rename_node.h index 240ac32ebd4..d58b8e29e68 100644 --- a/src/mongo/db/update/rename_node.h +++ b/src/mongo/db/update/rename_node.h @@ -43,7 +43,7 @@ public: * This init provides input validation on the source field (stored as the field name in * "modExpr") and the destination field (stored as the value in "modExpr"). */ - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<RenameNode>(*this); diff --git a/src/mongo/db/update/rename_node_test.cpp b/src/mongo/db/update/rename_node_test.cpp index 1ac25292bab..e78ddf091d8 100644 --- a/src/mongo/db/update/rename_node_test.cpp +++ b/src/mongo/db/update/rename_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" @@ -46,36 +47,36 @@ using mongo::mutablebson::countChildren; TEST(RenameNodeTest, PositionalNotAllowedInFromField) { auto update = fromjson("{$rename: {'a.$': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - Status status = node.init(update["$rename"]["a.$"], collator); + Status status = node.init(update["$rename"]["a.$"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(RenameNodeTest, PositionalNotAllowedInToField) { auto update = fromjson("{$rename: {'a': 'b.$'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - Status status = node.init(update["$rename"]["a"], collator); + Status status = node.init(update["$rename"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(RenameNodeTest, ArrayFilterNotAllowedInFromField) { auto update = fromjson("{$rename: {'a.$[i]': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - Status status = node.init(update["$rename"]["a.$[i]"], collator); + Status status = node.init(update["$rename"]["a.$[i]"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(RenameNodeTest, ArrayFilterNotAllowedInToField) { auto update = fromjson("{$rename: {'a': 'b.$[i]'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - Status status = node.init(update["$rename"]["a"], collator); + Status status = node.init(update["$rename"]["a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } @@ -83,36 +84,36 @@ TEST(RenameNodeTest, ArrayFilterNotAllowedInToField) { TEST(RenameNodeTest, MoveUpNotAllowed) { auto update = fromjson("{$rename: {'b.a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - Status status = node.init(update["$rename"]["b.a"], collator); + Status status = node.init(update["$rename"]["b.a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(RenameNodeTest, MoveDownNotAllowed) { auto update = fromjson("{$rename: {'b': 'b.a'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - Status status = node.init(update["$rename"]["b"], collator); + Status status = node.init(update["$rename"]["b"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST(RenameNodeTest, MoveToSelfNotAllowed) { auto update = fromjson("{$rename: {'b.a': 'b.a'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - Status status = node.init(update["$rename"]["b.a"], collator); + Status status = node.init(update["$rename"]["b.a"], expCtx); ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } TEST_F(RenameNodeTest, SimpleNumberAtRoot) { auto update = fromjson("{$rename: {'a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 2}")); setPathToCreate("b"); @@ -126,9 +127,9 @@ TEST_F(RenameNodeTest, SimpleNumberAtRoot) { TEST_F(RenameNodeTest, ToExistsAtSameLevel) { auto update = fromjson("{$rename: {'a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 2, b: 1}")); setPathTaken("b"); @@ -142,9 +143,9 @@ TEST_F(RenameNodeTest, ToExistsAtSameLevel) { TEST_F(RenameNodeTest, ToAndFromHaveSameValue) { auto update = fromjson("{$rename: {'a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 2, b: 2}")); setPathTaken("b"); @@ -158,9 +159,9 @@ TEST_F(RenameNodeTest, ToAndFromHaveSameValue) { TEST_F(RenameNodeTest, FromDottedElement) { auto update = fromjson("{$rename: {'a.c': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.c"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {c: {d: 6}}, b: 1}")); setPathTaken("b"); @@ -174,9 +175,9 @@ TEST_F(RenameNodeTest, FromDottedElement) { TEST_F(RenameNodeTest, RenameToExistingNestedFieldDoesNotReorderFields) { auto update = fromjson("{$rename: {'c.d': 'a.b.c'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["c.d"], collator)); + ASSERT_OK(node.init(update["$rename"]["c.d"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 1, d: 2}}, b: 3, c: {d: 4}}")); setPathTaken("a.b.c"); @@ -190,9 +191,9 @@ TEST_F(RenameNodeTest, RenameToExistingNestedFieldDoesNotReorderFields) { TEST_F(RenameNodeTest, MissingCompleteTo) { auto update = fromjson("{$rename: {a: 'c.r.d'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 2, b: 1, c: {}}")); setPathToCreate("r.d"); @@ -207,9 +208,9 @@ TEST_F(RenameNodeTest, MissingCompleteTo) { TEST_F(RenameNodeTest, ToIsCompletelyMissing) { auto update = fromjson("{$rename: {a: 'b.c.d'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 2}")); setPathToCreate("b.c.d"); @@ -223,9 +224,9 @@ TEST_F(RenameNodeTest, ToIsCompletelyMissing) { TEST_F(RenameNodeTest, ToMissingDottedField) { auto update = fromjson("{$rename: {a: 'b.c.d'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [{a:2, b:1}]}")); setPathToCreate("b.c.d"); @@ -239,9 +240,9 @@ TEST_F(RenameNodeTest, ToMissingDottedField) { TEST_F(RenameNodeTest, MoveIntoArray) { auto update = fromjson("{$rename: {b: 'a.2'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["b"], collator)); + ASSERT_OK(node.init(update["$rename"]["b"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: [1, 2], b: 2}")); setPathToCreate("2"); @@ -256,9 +257,9 @@ TEST_F(RenameNodeTest, MoveIntoArray) { TEST_F(RenameNodeTest, MoveIntoArrayNoId) { auto update = fromjson("{$rename: {b: 'a.2'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["b"], collator)); + ASSERT_OK(node.init(update["$rename"]["b"], expCtx)); mutablebson::Document doc(fromjson("{a: [1, 2], b: 2}")); setPathToCreate("2"); @@ -273,9 +274,9 @@ TEST_F(RenameNodeTest, MoveIntoArrayNoId) { TEST_F(RenameNodeTest, MoveToArrayElement) { auto update = fromjson("{$rename: {b: 'a.1'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["b"], collator)); + ASSERT_OK(node.init(update["$rename"]["b"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: [1, 2], b: 2}")); setPathTaken("a.1"); @@ -289,9 +290,9 @@ TEST_F(RenameNodeTest, MoveToArrayElement) { TEST_F(RenameNodeTest, MoveOutOfArray) { auto update = fromjson("{$rename: {'a.0': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.0"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.0"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: [1, 2]}")); setPathToCreate("b"); @@ -305,9 +306,9 @@ TEST_F(RenameNodeTest, MoveOutOfArray) { TEST_F(RenameNodeTest, MoveNonexistentEmbeddedFieldOut) { auto update = fromjson("{$rename: {'a.a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.a"], expCtx)); mutablebson::Document doc(fromjson("{a: [{a: 1}, {b: 2}]}")); setPathToCreate("b"); @@ -321,9 +322,9 @@ TEST_F(RenameNodeTest, MoveNonexistentEmbeddedFieldOut) { TEST_F(RenameNodeTest, MoveEmbeddedFieldOutWithElementNumber) { auto update = fromjson("{$rename: {'a.0.a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.0.a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.0.a"], expCtx)); mutablebson::Document doc(fromjson("{_id: 'test_object', a: [{a: 1}, {b: 2}]}")); setPathToCreate("b"); @@ -337,9 +338,9 @@ TEST_F(RenameNodeTest, MoveEmbeddedFieldOutWithElementNumber) { TEST_F(RenameNodeTest, ReplaceArrayField) { auto update = fromjson("{$rename: {a: 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 2, b: []}")); setPathTaken("b"); @@ -353,9 +354,9 @@ TEST_F(RenameNodeTest, ReplaceArrayField) { TEST_F(RenameNodeTest, ReplaceWithArrayField) { auto update = fromjson("{$rename: {a: 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [], b: 2}")); setPathTaken("b"); @@ -369,9 +370,9 @@ TEST_F(RenameNodeTest, ReplaceWithArrayField) { TEST_F(RenameNodeTest, CanRenameFromInvalidFieldName) { auto update = fromjson("{$rename: {'$a': 'a'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["$a"], collator)); + ASSERT_OK(node.init(update["$rename"]["$a"], expCtx)); mutablebson::Document doc(fromjson("{$a: 2}")); setPathToCreate("a"); @@ -385,9 +386,9 @@ TEST_F(RenameNodeTest, CanRenameFromInvalidFieldName) { TEST_F(RenameNodeTest, RenameWithoutLogBuilderOrIndexData) { auto update = fromjson("{$rename: {'a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 2}")); setPathToCreate("b"); @@ -399,9 +400,9 @@ TEST_F(RenameNodeTest, RenameWithoutLogBuilderOrIndexData) { TEST_F(RenameNodeTest, RenameFromNonExistentPathIsNoOp) { auto update = fromjson("{$rename: {'a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{b: 2}")); setPathTaken("b"); @@ -415,9 +416,9 @@ TEST_F(RenameNodeTest, RenameFromNonExistentPathIsNoOp) { TEST_F(RenameNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) { auto update = fromjson("{$rename: {'a.$id': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.$id"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.$id"], expCtx)); mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}")); setPathToCreate("b"); @@ -429,9 +430,9 @@ TEST_F(RenameNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) { TEST_F(RenameNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) { auto update = fromjson("{$rename: {'a.$id': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.$id"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.$id"], expCtx)); mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}")); setPathToCreate("b"); @@ -451,9 +452,9 @@ TEST_F(RenameNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFa TEST_F(RenameNodeTest, ApplyCannotRemoveImmutablePath) { auto update = fromjson("{$rename: {'a.b': 'c'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.b"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathToCreate("c"); @@ -467,9 +468,9 @@ TEST_F(RenameNodeTest, ApplyCannotRemoveImmutablePath) { TEST_F(RenameNodeTest, ApplyCannotRemovePrefixOfImmutablePath) { auto update = fromjson("{$rename: {a: 'c'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathToCreate("c"); @@ -483,9 +484,9 @@ TEST_F(RenameNodeTest, ApplyCannotRemovePrefixOfImmutablePath) { TEST_F(RenameNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) { auto update = fromjson("{$rename: {'a.b.c': 'd'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 1}}}")); setPathToCreate("d"); @@ -499,9 +500,9 @@ TEST_F(RenameNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) { TEST_F(RenameNodeTest, ApplyCanRemoveImmutablePathIfNoop) { auto update = fromjson("{$rename: {'a.b.c': 'd'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$rename"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {}}}")); setPathToCreate("d"); @@ -517,9 +518,9 @@ TEST_F(RenameNodeTest, ApplyCanRemoveImmutablePathIfNoop) { TEST_F(RenameNodeTest, ApplyCannotCreateDollarPrefixedField) { auto update = fromjson("{$rename: {a: '$bad'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathToCreate("$bad"); @@ -532,9 +533,9 @@ TEST_F(RenameNodeTest, ApplyCannotCreateDollarPrefixedField) { TEST_F(RenameNodeTest, ApplyCannotOverwriteImmutablePath) { auto update = fromjson("{$rename: {a: 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); RenameNode node; - ASSERT_OK(node.init(update["$rename"]["a"], collator)); + ASSERT_OK(node.init(update["$rename"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 0, b: 1}")); setPathTaken("b"); diff --git a/src/mongo/db/update/set_node.cpp b/src/mongo/db/update/set_node.cpp index db107e32f39..7411da5beb4 100644 --- a/src/mongo/db/update/set_node.cpp +++ b/src/mongo/db/update/set_node.cpp @@ -34,7 +34,7 @@ namespace mongo { -Status SetNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status SetNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); _val = modExpr; diff --git a/src/mongo/db/update/set_node.h b/src/mongo/db/update/set_node.h index 3312042f2b2..7eea1ee1cec 100644 --- a/src/mongo/db/update/set_node.h +++ b/src/mongo/db/update/set_node.h @@ -40,7 +40,7 @@ class SetNode : public ModifierNode { public: explicit SetNode(Context context = Context::kAll) : ModifierNode(context) {} - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<SetNode>(*this); diff --git a/src/mongo/db/update/set_node_test.cpp b/src/mongo/db/update/set_node_test.cpp index 5363c7ea654..705be2f6071 100644 --- a/src/mongo/db/update/set_node_test.cpp +++ b/src/mongo/db/update/set_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" @@ -46,23 +47,23 @@ using mongo::mutablebson::countChildren; DEATH_TEST(SetNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") { auto update = fromjson("{$set: {}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - node.init(update["$set"].embeddedObject().firstElement(), collator).transitional_ignore(); + node.init(update["$set"].embeddedObject().firstElement(), expCtx).transitional_ignore(); } TEST(SetNodeTest, InitSucceedsForNonemptyElement) { auto update = fromjson("{$set: {a: 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); } TEST_F(SetNodeTest, ApplyNoOp) { auto update = fromjson("{$set: {a: 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -77,9 +78,9 @@ TEST_F(SetNodeTest, ApplyNoOp) { TEST_F(SetNodeTest, ApplyEmptyPathToCreate) { auto update = fromjson("{$set: {a: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -94,9 +95,9 @@ TEST_F(SetNodeTest, ApplyEmptyPathToCreate) { TEST_F(SetNodeTest, ApplyCreatePath) { auto update = fromjson("{$set: {'a.b.c': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {d: 5}}")); setPathToCreate("b.c"); @@ -112,9 +113,9 @@ TEST_F(SetNodeTest, ApplyCreatePath) { TEST_F(SetNodeTest, ApplyCreatePathFromRoot) { auto update = fromjson("{$set: {'a.b': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{c: 5}")); setPathToCreate("a.b"); @@ -129,9 +130,9 @@ TEST_F(SetNodeTest, ApplyCreatePathFromRoot) { TEST_F(SetNodeTest, ApplyPositional) { auto update = fromjson("{$set: {'a.$': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.$"], collator)); + ASSERT_OK(node.init(update["$set"]["a.$"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2]}")); setPathTaken("a.1"); @@ -147,9 +148,9 @@ TEST_F(SetNodeTest, ApplyPositional) { TEST_F(SetNodeTest, ApplyNonViablePathToCreate) { auto update = fromjson("{$set: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathToCreate("b"); @@ -163,9 +164,9 @@ TEST_F(SetNodeTest, ApplyNonViablePathToCreate) { TEST_F(SetNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) { auto update = fromjson("{$set: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathToCreate("b"); @@ -182,9 +183,9 @@ TEST_F(SetNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) { TEST_F(SetNodeTest, ApplyNoIndexDataNoLogBuilder) { auto update = fromjson("{$set: {a: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -198,9 +199,9 @@ TEST_F(SetNodeTest, ApplyNoIndexDataNoLogBuilder) { TEST_F(SetNodeTest, ApplyDoesNotAffectIndexes) { auto update = fromjson("{$set: {a: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -214,9 +215,9 @@ TEST_F(SetNodeTest, ApplyDoesNotAffectIndexes) { TEST_F(SetNodeTest, TypeChangeIsNotANoop) { auto update = fromjson("{$set: {a: NumberLong(2)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: NumberInt(2)}")); setPathTaken("a"); @@ -231,9 +232,9 @@ TEST_F(SetNodeTest, TypeChangeIsNotANoop) { TEST_F(SetNodeTest, IdentityOpOnDeserializedIsNotANoOp) { // Apply an op that would be a no-op. auto update = fromjson("{$set: {a: {b : NumberInt(2)}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: { b: NumberInt(0)}}")); // Apply a mutation to the document that will make it non-serialized. @@ -250,9 +251,9 @@ TEST_F(SetNodeTest, IdentityOpOnDeserializedIsNotANoOp) { TEST_F(SetNodeTest, ApplyEmptyDocument) { auto update = fromjson("{$set: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -266,9 +267,9 @@ TEST_F(SetNodeTest, ApplyEmptyDocument) { TEST_F(SetNodeTest, ApplyInPlace) { auto update = fromjson("{$set: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -282,9 +283,9 @@ TEST_F(SetNodeTest, ApplyInPlace) { TEST_F(SetNodeTest, ApplyOverridePath) { auto update = fromjson("{$set: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathTaken("a"); @@ -298,9 +299,9 @@ TEST_F(SetNodeTest, ApplyOverridePath) { TEST_F(SetNodeTest, ApplyChangeType) { auto update = fromjson("{$set: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 'str'}")); setPathTaken("a"); @@ -314,9 +315,9 @@ TEST_F(SetNodeTest, ApplyChangeType) { TEST_F(SetNodeTest, ApplyNewPath) { auto update = fromjson("{$set: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{b: 1}")); setPathToCreate("a"); @@ -330,9 +331,9 @@ TEST_F(SetNodeTest, ApplyNewPath) { TEST_F(SetNodeTest, ApplyLog) { auto update = fromjson("{$set: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -345,9 +346,9 @@ TEST_F(SetNodeTest, ApplyLog) { TEST_F(SetNodeTest, ApplyNoOpDottedPath) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a.b"); @@ -361,9 +362,9 @@ TEST_F(SetNodeTest, ApplyNoOpDottedPath) { TEST_F(SetNodeTest, TypeChangeOnDottedPathIsNotANoOp) { auto update = fromjson("{$set: {'a.b': NumberInt(2)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: NumberLong(2)}}")); setPathTaken("a.b"); @@ -377,9 +378,9 @@ TEST_F(SetNodeTest, TypeChangeOnDottedPathIsNotANoOp) { TEST_F(SetNodeTest, ApplyPathNotViable) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a:1}")); setPathToCreate("b"); @@ -392,9 +393,9 @@ TEST_F(SetNodeTest, ApplyPathNotViable) { TEST_F(SetNodeTest, ApplyPathNotViableArrray) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a:[{b:1}]}")); setPathToCreate("b"); @@ -407,9 +408,9 @@ TEST_F(SetNodeTest, ApplyPathNotViableArrray) { TEST_F(SetNodeTest, ApplyInPlaceDottedPath) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathTaken("a.b"); @@ -423,9 +424,9 @@ TEST_F(SetNodeTest, ApplyInPlaceDottedPath) { TEST_F(SetNodeTest, ApplyChangeTypeDottedPath) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 'str'}}")); setPathTaken("a.b"); @@ -439,9 +440,9 @@ TEST_F(SetNodeTest, ApplyChangeTypeDottedPath) { TEST_F(SetNodeTest, ApplyChangePath) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 1}}}")); setPathTaken("a.b"); @@ -455,9 +456,9 @@ TEST_F(SetNodeTest, ApplyChangePath) { TEST_F(SetNodeTest, ApplyExtendPath) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {c: 1}}")); setPathToCreate("b"); @@ -472,9 +473,9 @@ TEST_F(SetNodeTest, ApplyExtendPath) { TEST_F(SetNodeTest, ApplyNewDottedPath) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{c: 1}")); setPathToCreate("a.b"); @@ -488,9 +489,9 @@ TEST_F(SetNodeTest, ApplyNewDottedPath) { TEST_F(SetNodeTest, ApplyEmptyDoc) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a.b"); @@ -504,9 +505,9 @@ TEST_F(SetNodeTest, ApplyEmptyDoc) { TEST_F(SetNodeTest, ApplyFieldWithDot) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{'a.b':4}")); setPathToCreate("a.b"); @@ -520,9 +521,9 @@ TEST_F(SetNodeTest, ApplyFieldWithDot) { TEST_F(SetNodeTest, ApplyNoOpArrayIndex) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}")); setPathTaken("a.2.b"); @@ -536,9 +537,9 @@ TEST_F(SetNodeTest, ApplyNoOpArrayIndex) { TEST_F(SetNodeTest, TypeChangeInArrayIsNotANoOp) { auto update = fromjson("{$set: {'a.2.b': NumberInt(2)}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 2.0}]}")); setPathTaken("a.2.b"); @@ -552,9 +553,9 @@ TEST_F(SetNodeTest, TypeChangeInArrayIsNotANoOp) { TEST_F(SetNodeTest, ApplyNonViablePath) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 0}")); setPathToCreate("2.b"); @@ -567,9 +568,9 @@ TEST_F(SetNodeTest, ApplyNonViablePath) { TEST_F(SetNodeTest, ApplyInPlaceArrayIndex) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 1}]}")); setPathTaken("a.2.b"); @@ -583,9 +584,9 @@ TEST_F(SetNodeTest, ApplyInPlaceArrayIndex) { TEST_F(SetNodeTest, ApplyNormalArray) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0},{b: 1}]}")); setPathToCreate("2.b"); @@ -600,9 +601,9 @@ TEST_F(SetNodeTest, ApplyNormalArray) { TEST_F(SetNodeTest, ApplyPaddingArray) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 0}]}")); setPathToCreate("2.b"); @@ -617,9 +618,9 @@ TEST_F(SetNodeTest, ApplyPaddingArray) { TEST_F(SetNodeTest, ApplyNumericObject) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 0}}")); setPathToCreate("2.b"); @@ -634,9 +635,9 @@ TEST_F(SetNodeTest, ApplyNumericObject) { TEST_F(SetNodeTest, ApplyNumericField) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {'2': {b: 1}}}")); setPathTaken("a.2.b"); @@ -650,9 +651,9 @@ TEST_F(SetNodeTest, ApplyNumericField) { TEST_F(SetNodeTest, ApplyExtendNumericField) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {'2': {c: 1}}}")); setPathToCreate("b"); @@ -667,9 +668,9 @@ TEST_F(SetNodeTest, ApplyExtendNumericField) { TEST_F(SetNodeTest, ApplyEmptyObject) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {}}")); setPathToCreate("2.b"); @@ -684,9 +685,9 @@ TEST_F(SetNodeTest, ApplyEmptyObject) { TEST_F(SetNodeTest, ApplyEmptyArray) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathToCreate("2.b"); @@ -701,9 +702,9 @@ TEST_F(SetNodeTest, ApplyEmptyArray) { TEST_F(SetNodeTest, ApplyLogDottedPath) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b:0}, {b:1}]}")); setPathToCreate("2.b"); @@ -717,9 +718,9 @@ TEST_F(SetNodeTest, ApplyLogDottedPath) { TEST_F(SetNodeTest, LogEmptyArray) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: []}")); setPathToCreate("2.b"); @@ -733,9 +734,9 @@ TEST_F(SetNodeTest, LogEmptyArray) { TEST_F(SetNodeTest, LogEmptyObject) { auto update = fromjson("{$set: {'a.2.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.2.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.2.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {}}")); setPathToCreate("2.b"); @@ -749,9 +750,9 @@ TEST_F(SetNodeTest, LogEmptyObject) { TEST_F(SetNodeTest, ApplyNoOpComplex) { auto update = fromjson("{$set: {'a.1.b': {c: 1, d: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.1.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.1.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: {c: 0, d: 0}}, {b: {c: 1, d: 1}}]}}")); setPathTaken("a.1.b"); @@ -765,9 +766,9 @@ TEST_F(SetNodeTest, ApplyNoOpComplex) { TEST_F(SetNodeTest, ApplySameStructure) { auto update = fromjson("{$set: {'a.1.b': {c: 1, d: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.1.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.1.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: {c: 0, d: 0}}, {b: {c: 1, xxx: 1}}]}}")); setPathTaken("a.1.b"); @@ -781,9 +782,9 @@ TEST_F(SetNodeTest, ApplySameStructure) { TEST_F(SetNodeTest, NonViablePathWithoutRepl) { auto update = fromjson("{$set: {'a.1.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.1.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.1.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathToCreate("1.b"); @@ -796,9 +797,9 @@ TEST_F(SetNodeTest, NonViablePathWithoutRepl) { TEST_F(SetNodeTest, SingleFieldFromReplication) { auto update = fromjson("{$set: {'a.1.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.1.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.1.b"], expCtx)); mutablebson::Document doc(fromjson("{_id:1, a: 1}")); setPathToCreate("1.b"); @@ -814,9 +815,9 @@ TEST_F(SetNodeTest, SingleFieldFromReplication) { TEST_F(SetNodeTest, SingleFieldNoIdFromReplication) { auto update = fromjson("{$set: {'a.1.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.1.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.1.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathToCreate("1.b"); @@ -832,9 +833,9 @@ TEST_F(SetNodeTest, SingleFieldNoIdFromReplication) { TEST_F(SetNodeTest, NestedFieldFromReplication) { auto update = fromjson("{$set: {'a.a.1.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.a.1.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.a.1.b"], expCtx)); mutablebson::Document doc(fromjson("{_id:1, a: {a: 1}}")); setPathToCreate("1.b"); @@ -850,9 +851,9 @@ TEST_F(SetNodeTest, NestedFieldFromReplication) { TEST_F(SetNodeTest, DoubleNestedFieldFromReplication) { auto update = fromjson("{$set: {'a.b.c.d': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b.c.d"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b.c.d"], expCtx)); mutablebson::Document doc(fromjson("{_id:1, a: {b: {c: 1}}}")); setPathToCreate("d"); @@ -868,9 +869,9 @@ TEST_F(SetNodeTest, DoubleNestedFieldFromReplication) { TEST_F(SetNodeTest, NestedFieldNoIdFromReplication) { auto update = fromjson("{$set: {'a.a.1.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.a.1.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.a.1.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {a: 1}}")); setPathToCreate("1.b"); @@ -886,9 +887,9 @@ TEST_F(SetNodeTest, NestedFieldNoIdFromReplication) { TEST_F(SetNodeTest, ReplayArrayFieldNotAppendedIntermediateFromReplication) { auto update = fromjson("{$set: {'a.0.b': [0,2]}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.0.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.0.b"], expCtx)); mutablebson::Document doc(fromjson("{_id: 0, a: [1, {b: [1]}]}")); setPathToCreate("b"); @@ -904,9 +905,9 @@ TEST_F(SetNodeTest, ReplayArrayFieldNotAppendedIntermediateFromReplication) { TEST_F(SetNodeTest, Set6) { auto update = fromjson("{$set: {'r.a': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["r.a"], collator)); + ASSERT_OK(node.init(update["$set"]["r.a"], expCtx)); mutablebson::Document doc(fromjson("{_id: 1, r: {a:1, b:2}}")); setPathTaken("r.a"); @@ -922,9 +923,9 @@ TEST_F(SetNodeTest, Set6) { TEST_F(SetNodeTest, Set6FromRepl) { auto update = fromjson("{$set: { 'r.a': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["r.a"], collator)); + ASSERT_OK(node.init(update["$set"]["r.a"], expCtx)); mutablebson::Document doc(fromjson("{_id: 1, r: {a:1, b:2}}")); setPathTaken("r.a"); @@ -944,9 +945,9 @@ TEST_F(SetNodeTest, ApplySetModToEphemeralDocument) { // latent debug only defect in mutable BSON, so this is more a test of mutable than // $set. auto update = fromjson("{ $set: { x: { a: 100, b: 2 }}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["x"], collator)); + ASSERT_OK(node.init(update["$set"]["x"], expCtx)); mutablebson::Document doc; Element x = doc.makeElementObject("x"); @@ -965,9 +966,9 @@ TEST_F(SetNodeTest, ApplySetModToEphemeralDocument) { TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInsideSetElement) { auto update = fromjson("{$set: {a: {$bad: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -980,9 +981,9 @@ TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInsideSetElement) { TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtStartOfPath) { auto update = fromjson("{$set: {'$bad.a': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["$bad.a"], collator)); + ASSERT_OK(node.init(update["$set"]["$bad.a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("$bad.a"); @@ -995,9 +996,9 @@ TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtStartOfPath) { TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInMiddleOfPath) { auto update = fromjson("{$set: {'a.$bad.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.$bad.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.$bad.b"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a.$bad.b"); @@ -1010,9 +1011,9 @@ TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInMiddleOfPath) { TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtEndOfPath) { auto update = fromjson("{$set: {'a.$bad': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.$bad"], collator)); + ASSERT_OK(node.init(update["$set"]["a.$bad"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a.$bad"); @@ -1025,9 +1026,9 @@ TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtEndOfPath) { TEST_F(SetNodeTest, ApplyCanCreateDollarPrefixedFieldNameWhenValidateForStorageIsFalse) { auto update = fromjson("{$set: {$bad: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["$bad"], collator)); + ASSERT_OK(node.init(update["$set"]["$bad"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("$bad"); @@ -1044,9 +1045,9 @@ TEST_F(SetNodeTest, ApplyCanCreateDollarPrefixedFieldNameWhenValidateForStorageI TEST_F(SetNodeTest, ApplyCannotOverwriteImmutablePath) { auto update = fromjson("{$set: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a.b"); @@ -1060,9 +1061,9 @@ TEST_F(SetNodeTest, ApplyCannotOverwriteImmutablePath) { TEST_F(SetNodeTest, ApplyCanPerformNoopOnImmutablePath) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a.b"); @@ -1079,9 +1080,9 @@ TEST_F(SetNodeTest, ApplyCanPerformNoopOnImmutablePath) { TEST_F(SetNodeTest, ApplyCannotOverwritePrefixToRemoveImmutablePath) { auto update = fromjson("{$set: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a"); @@ -1095,9 +1096,9 @@ TEST_F(SetNodeTest, ApplyCannotOverwritePrefixToRemoveImmutablePath) { TEST_F(SetNodeTest, ApplyCannotOverwritePrefixToModifyImmutablePath) { auto update = fromjson("{$set: {a: {b: 1}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a"); @@ -1111,9 +1112,9 @@ TEST_F(SetNodeTest, ApplyCannotOverwritePrefixToModifyImmutablePath) { TEST_F(SetNodeTest, ApplyCanPerformNoopOnPrefixOfImmutablePath) { auto update = fromjson("{$set: {a: {b: 2}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a"); @@ -1130,9 +1131,9 @@ TEST_F(SetNodeTest, ApplyCanPerformNoopOnPrefixOfImmutablePath) { TEST_F(SetNodeTest, ApplyCanOverwritePrefixToCreateImmutablePath) { auto update = fromjson("{$set: {a: {b: 2}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); @@ -1149,9 +1150,9 @@ TEST_F(SetNodeTest, ApplyCanOverwritePrefixToCreateImmutablePath) { TEST_F(SetNodeTest, ApplyCanOverwritePrefixOfImmutablePathIfNoopOnImmutablePath) { auto update = fromjson("{$set: {a: {b: 2, c: 3}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 2}}")); setPathTaken("a"); @@ -1168,9 +1169,9 @@ TEST_F(SetNodeTest, ApplyCanOverwritePrefixOfImmutablePathIfNoopOnImmutablePath) TEST_F(SetNodeTest, ApplyCannotOverwriteSuffixOfImmutablePath) { auto update = fromjson("{$set: {'a.b.c': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 2}}}")); setPathTaken("a.b.c"); @@ -1184,9 +1185,9 @@ TEST_F(SetNodeTest, ApplyCannotOverwriteSuffixOfImmutablePath) { TEST_F(SetNodeTest, ApplyCanPerformNoopOnSuffixOfImmutablePath) { auto update = fromjson("{$set: {'a.b.c': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 2}}}")); setPathTaken("a.b.c"); @@ -1203,9 +1204,9 @@ TEST_F(SetNodeTest, ApplyCanPerformNoopOnSuffixOfImmutablePath) { TEST_F(SetNodeTest, ApplyCannotCreateFieldAtEndOfImmutablePath) { auto update = fromjson("{$set: {'a.b.c': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {}}}")); setPathToCreate("c"); @@ -1220,9 +1221,9 @@ TEST_F(SetNodeTest, ApplyCannotCreateFieldAtEndOfImmutablePath) { TEST_F(SetNodeTest, ApplyCannotCreateFieldBeyondEndOfImmutablePath) { auto update = fromjson("{$set: {'a.b.c': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {}}}")); setPathToCreate("c"); @@ -1237,9 +1238,9 @@ TEST_F(SetNodeTest, ApplyCannotCreateFieldBeyondEndOfImmutablePath) { TEST_F(SetNodeTest, ApplyCanCreateImmutablePath) { auto update = fromjson("{$set: {'a.b': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a.b"], collator)); + ASSERT_OK(node.init(update["$set"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {}}")); setPathToCreate("b"); @@ -1257,9 +1258,9 @@ TEST_F(SetNodeTest, ApplyCanCreateImmutablePath) { TEST_F(SetNodeTest, ApplyCanCreatePrefixOfImmutablePath) { auto update = fromjson("{$set: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node; - ASSERT_OK(node.init(update["$set"]["a"], collator)); + ASSERT_OK(node.init(update["$set"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -1276,9 +1277,9 @@ TEST_F(SetNodeTest, ApplyCanCreatePrefixOfImmutablePath) { TEST_F(SetNodeTest, ApplySetOnInsertIsNoopWhenInsertIsFalse) { auto update = fromjson("{$setOnInsert: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node(UpdateNode::Context::kInsertOnly); - ASSERT_OK(node.init(update["$setOnInsert"]["a"], collator)); + ASSERT_OK(node.init(update["$setOnInsert"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -1293,9 +1294,9 @@ TEST_F(SetNodeTest, ApplySetOnInsertIsNoopWhenInsertIsFalse) { TEST_F(SetNodeTest, ApplySetOnInsertIsAppliedWhenInsertIsTrue) { auto update = fromjson("{$setOnInsert: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node(UpdateNode::Context::kInsertOnly); - ASSERT_OK(node.init(update["$setOnInsert"]["a"], collator)); + ASSERT_OK(node.init(update["$setOnInsert"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -1311,9 +1312,9 @@ TEST_F(SetNodeTest, ApplySetOnInsertIsAppliedWhenInsertIsTrue) { TEST_F(SetNodeTest, ApplySetOnInsertExistingPath) { auto update = fromjson("{$setOnInsert: {a: 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); SetNode node(UpdateNode::Context::kInsertOnly); - ASSERT_OK(node.init(update["$setOnInsert"]["a"], collator)); + ASSERT_OK(node.init(update["$setOnInsert"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 1}")); setPathTaken("a"); diff --git a/src/mongo/db/update/unset_node.cpp b/src/mongo/db/update/unset_node.cpp index 5ff55a0bf64..9c07e1ea0b0 100644 --- a/src/mongo/db/update/unset_node.cpp +++ b/src/mongo/db/update/unset_node.cpp @@ -34,7 +34,7 @@ namespace mongo { -Status UnsetNode::init(BSONElement modExpr, const CollatorInterface* collator) { +Status UnsetNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { // Note that we don't need to store modExpr, because $unset does not do anything with its value. invariant(modExpr.ok()); return Status::OK(); diff --git a/src/mongo/db/update/unset_node.h b/src/mongo/db/update/unset_node.h index 645497ef6a9..93fa314ad33 100644 --- a/src/mongo/db/update/unset_node.h +++ b/src/mongo/db/update/unset_node.h @@ -38,7 +38,7 @@ namespace mongo { */ class UnsetNode : public ModifierNode { public: - Status init(BSONElement modExpr, const CollatorInterface* collator) final; + Status init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) final; std::unique_ptr<UpdateNode> clone() const final { return stdx::make_unique<UnsetNode>(*this); diff --git a/src/mongo/db/update/unset_node_test.cpp b/src/mongo/db/update/unset_node_test.cpp index 26c89e05048..1c68c8520dd 100644 --- a/src/mongo/db/update/unset_node_test.cpp +++ b/src/mongo/db/update/unset_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" @@ -46,16 +47,16 @@ using mongo::mutablebson::countChildren; DEATH_TEST(UnsetNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") { auto update = fromjson("{$unset: {}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - node.init(update["$unset"].embeddedObject().firstElement(), collator).transitional_ignore(); + node.init(update["$unset"].embeddedObject().firstElement(), expCtx).transitional_ignore(); } DEATH_TEST_F(UnsetNodeTest, ApplyToRootFails, "Invariant failure !applyParams.pathTaken->empty()") { auto update = fromjson("{$unset: {}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"], collator)); + ASSERT_OK(node.init(update["$unset"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); node.apply(getApplyParams(doc.root())); @@ -63,17 +64,17 @@ DEATH_TEST_F(UnsetNodeTest, ApplyToRootFails, "Invariant failure !applyParams.pa TEST(UnsetNodeTest, InitSucceedsForNonemptyElement) { auto update = fromjson("{$unset: {a: 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a"], collator)); + ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); } /* This is a no-op because we are unsetting a field that does not exit. */ TEST_F(UnsetNodeTest, UnsetNoOp) { auto update = fromjson("{$unset: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a"], collator)); + ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); mutablebson::Document doc(fromjson("{b: 5}")); setPathToCreate("a"); @@ -88,9 +89,9 @@ TEST_F(UnsetNodeTest, UnsetNoOp) { TEST_F(UnsetNodeTest, UnsetNoOpDottedPath) { auto update = fromjson("{$unset: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.b"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathToCreate("b"); @@ -106,9 +107,9 @@ TEST_F(UnsetNodeTest, UnsetNoOpDottedPath) { TEST_F(UnsetNodeTest, UnsetNoOpThroughArray) { auto update = fromjson("{$unset: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.b"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a:[{b:1}]}")); setPathToCreate("b"); @@ -124,9 +125,9 @@ TEST_F(UnsetNodeTest, UnsetNoOpThroughArray) { TEST_F(UnsetNodeTest, UnsetNoOpEmptyDoc) { auto update = fromjson("{$unset: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a"], collator)); + ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); mutablebson::Document doc(fromjson("{}")); setPathToCreate("a"); @@ -141,9 +142,9 @@ TEST_F(UnsetNodeTest, UnsetNoOpEmptyDoc) { TEST_F(UnsetNodeTest, UnsetTopLevelPath) { auto update = fromjson("{$unset: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a"], collator)); + ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -158,9 +159,9 @@ TEST_F(UnsetNodeTest, UnsetTopLevelPath) { TEST_F(UnsetNodeTest, UnsetNestedPath) { auto update = fromjson("{$unset: {'a.b.c': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 6}}}}")); setPathTaken("a.b.c"); @@ -175,9 +176,9 @@ TEST_F(UnsetNodeTest, UnsetNestedPath) { TEST_F(UnsetNodeTest, UnsetObject) { auto update = fromjson("{$unset: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.b"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 6}}}}")); setPathTaken("a.b"); @@ -192,9 +193,9 @@ TEST_F(UnsetNodeTest, UnsetObject) { TEST_F(UnsetNodeTest, UnsetArrayElement) { auto update = fromjson("{$unset: {'a.0': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.0"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.0"], expCtx)); mutablebson::Document doc(fromjson("{a:[1], b:1}")); setPathTaken("a.0"); @@ -209,9 +210,9 @@ TEST_F(UnsetNodeTest, UnsetArrayElement) { TEST_F(UnsetNodeTest, UnsetPositional) { auto update = fromjson("{$unset: {'a.$': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.$"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.$"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2]}")); setPathTaken("a.1"); @@ -227,9 +228,9 @@ TEST_F(UnsetNodeTest, UnsetPositional) { TEST_F(UnsetNodeTest, UnsetEntireArray) { auto update = fromjson("{$unset: {'a': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a"], collator)); + ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2]}")); setPathTaken("a"); @@ -244,9 +245,9 @@ TEST_F(UnsetNodeTest, UnsetEntireArray) { TEST_F(UnsetNodeTest, UnsetFromObjectInArray) { auto update = fromjson("{$unset: {'a.0.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.0.b"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.0.b"], expCtx)); mutablebson::Document doc(fromjson("{a: [{b: 1}]}")); setPathTaken("a.0.b"); @@ -261,9 +262,9 @@ TEST_F(UnsetNodeTest, UnsetFromObjectInArray) { TEST_F(UnsetNodeTest, CanUnsetInvalidField) { auto update = fromjson("{$unset: {'a.$.$b': true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.$.$b"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.$.$b"], expCtx)); mutablebson::Document doc(fromjson("{b: 1, a: [{$b: 1}]}")); setPathTaken("a.0.$b"); @@ -278,9 +279,9 @@ TEST_F(UnsetNodeTest, CanUnsetInvalidField) { TEST_F(UnsetNodeTest, ApplyNoIndexDataNoLogBuilder) { auto update = fromjson("{$unset: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a"], collator)); + ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -294,9 +295,9 @@ TEST_F(UnsetNodeTest, ApplyNoIndexDataNoLogBuilder) { TEST_F(UnsetNodeTest, ApplyDoesNotAffectIndexes) { auto update = fromjson("{$unset: {a: 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a"], collator)); + ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: 5}")); setPathTaken("a"); @@ -311,9 +312,9 @@ TEST_F(UnsetNodeTest, ApplyDoesNotAffectIndexes) { TEST_F(UnsetNodeTest, ApplyFieldWithDot) { auto update = fromjson("{$unset: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.b"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{'a.b':4, a: {b: 2}}")); setPathTaken("a.b"); @@ -328,9 +329,9 @@ TEST_F(UnsetNodeTest, ApplyFieldWithDot) { TEST_F(UnsetNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) { auto update = fromjson("{$unset: {'a.$id': true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.$id"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.$id"], expCtx)); mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}")); setPathTaken("a.$id"); @@ -342,9 +343,9 @@ TEST_F(UnsetNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) { TEST_F(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) { auto update = fromjson("{$unset: {'a.$id': true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.$id"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.$id"], expCtx)); mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}")); setPathTaken("a.$id"); @@ -362,9 +363,9 @@ TEST_F(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFal TEST_F(UnsetNodeTest, ApplyCannotRemoveImmutablePath) { auto update = fromjson("{$unset: {'a.b': true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.b"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.b"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathTaken("a.b"); @@ -378,9 +379,9 @@ TEST_F(UnsetNodeTest, ApplyCannotRemoveImmutablePath) { TEST_F(UnsetNodeTest, ApplyCannotRemovePrefixOfImmutablePath) { auto update = fromjson("{$unset: {a: true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a"], collator)); + ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathTaken("a"); @@ -394,9 +395,9 @@ TEST_F(UnsetNodeTest, ApplyCannotRemovePrefixOfImmutablePath) { TEST_F(UnsetNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) { auto update = fromjson("{$unset: {'a.b.c': true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 1}}}")); setPathTaken("a.b.c"); @@ -410,9 +411,9 @@ TEST_F(UnsetNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) { TEST_F(UnsetNodeTest, ApplyCanRemoveImmutablePathIfNoop) { auto update = fromjson("{$unset: {'a.b.c': true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; - ASSERT_OK(node.init(update["$unset"]["a.b.c"], collator)); + ASSERT_OK(node.init(update["$unset"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathToCreate("c"); diff --git a/src/mongo/db/update/update_array_node_test.cpp b/src/mongo/db/update/update_array_node_test.cpp index cd573a7dc80..38004cd39f9 100644 --- a/src/mongo/db/update/update_array_node_test.cpp +++ b/src/mongo/db/update/update_array_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/update/update_node_test_fixture.h" #include "mongo/db/update/update_object_node.h" #include "mongo/unittest/death_test.h" @@ -47,15 +48,15 @@ using mongo::mutablebson::Element; TEST_F(UpdateArrayNodeTest, ApplyCreatePathFails) { auto update = fromjson("{$set: {'a.b.$[i]': 0}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -71,15 +72,15 @@ TEST_F(UpdateArrayNodeTest, ApplyCreatePathFails) { TEST_F(UpdateArrayNodeTest, ApplyToNonArrayFails) { auto update = fromjson("{$set: {'a.$[i]': 0}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -94,15 +95,15 @@ TEST_F(UpdateArrayNodeTest, ApplyToNonArrayFails) { TEST_F(UpdateArrayNodeTest, UpdateIsAppliedToAllMatchingElements) { auto update = fromjson("{$set: {'a.$[i]': 2}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -121,15 +122,15 @@ DEATH_TEST_F(UpdateArrayNodeTest, "Invariant failure childElement.hasValue()") { auto update = fromjson("{$set: {'a.$[i].b': 0}}"); auto arrayFilter = fromjson("{'i.c': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -142,14 +143,14 @@ DEATH_TEST_F(UpdateArrayNodeTest, TEST_F(UpdateArrayNodeTest, UpdateForEmptyIdentifierIsAppliedToAllArrayElements) { auto update = fromjson("{$set: {'a.$[]': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -168,29 +169,29 @@ TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElement) { auto arrayFilterI = fromjson("{'i.b': 0}"); auto arrayFilterJ = fromjson("{'j.c': 0}"); auto arrayFilterK = fromjson("{'k.d': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); - arrayFilters["k"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterK, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); + arrayFilters["k"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterK, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[j].c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[k].d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -208,22 +209,22 @@ TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsUsingMergedChildr auto update = fromjson("{$set: {'a.$[i].b': 1, 'a.$[j].c': 1}}"); auto arrayFilterI = fromjson("{'i.b': 0}"); auto arrayFilterJ = fromjson("{'j.c': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[j].c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -242,29 +243,29 @@ TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsWithoutMergedChil auto arrayFilterI = fromjson("{'i.b': 0}"); auto arrayFilterJ = fromjson("{'j.c': 0}"); auto arrayFilterK = fromjson("{'k.d': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); - arrayFilters["k"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterK, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); + arrayFilters["k"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterK, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[j].c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[k].d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -280,20 +281,20 @@ TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsWithoutMergedChil TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementWithEmptyIdentifiers) { auto update = fromjson("{$set: {'a.$[].b': 1, 'a.$[].c': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[].c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -313,24 +314,24 @@ TEST_F(UpdateArrayNodeTest, ApplyNestedArrayUpdates) { auto arrayFilterJ = fromjson("{'j.c': 0}"); auto arrayFilterK = fromjson("{'k.x': 0}"); auto arrayFilterL = fromjson("{'l.d': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); - arrayFilters["k"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterK, collator)); - arrayFilters["l"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterL, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); + arrayFilters["k"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterK, expCtx)); + arrayFilters["l"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterL, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b.$[j].c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[k].b.$[l].d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -348,22 +349,22 @@ TEST_F(UpdateArrayNodeTest, ApplyUpdatesWithMergeConflictToArrayElementFails) { auto update = fromjson("{$set: {'a.$[i]': 1, 'a.$[j]': 1}}"); auto arrayFilterI = fromjson("{'i': 0}"); auto arrayFilterJ = fromjson("{'j': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[j]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -379,22 +380,22 @@ TEST_F(UpdateArrayNodeTest, ApplyUpdatesWithEmptyIdentifiersWithMergeConflictToA auto update = fromjson("{$set: {'a.$[].b.$[i]': 1, 'a.$[].b.$[j]': 1}}"); auto arrayFilterI = fromjson("{'i': 0}"); auto arrayFilterJ = fromjson("{'j': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[].b.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[].b.$[j]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -412,24 +413,24 @@ TEST_F(UpdateArrayNodeTest, ApplyNestedArrayUpdatesWithMergeConflictFails) { auto arrayFilterJ = fromjson("{j: 0}"); auto arrayFilterK = fromjson("{'k.c': 0}"); auto arrayFilterL = fromjson("{l: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); - arrayFilters["k"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterK, collator)); - arrayFilters["l"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterL, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); + arrayFilters["k"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterK, expCtx)); + arrayFilters["l"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterL, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b.$[j]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[k].b.$[l]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -444,15 +445,15 @@ TEST_F(UpdateArrayNodeTest, ApplyNestedArrayUpdatesWithMergeConflictFails) { TEST_F(UpdateArrayNodeTest, NoArrayElementsMatch) { auto update = fromjson("{$set: {'a.$[i]': 1}}"); auto arrayFilter = fromjson("{'i': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -469,15 +470,15 @@ TEST_F(UpdateArrayNodeTest, NoArrayElementsMatch) { TEST_F(UpdateArrayNodeTest, UpdatesToAllArrayElementsAreNoops) { auto update = fromjson("{$set: {'a.$[i]': 1}}"); auto arrayFilter = fromjson("{'i': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -494,15 +495,15 @@ TEST_F(UpdateArrayNodeTest, UpdatesToAllArrayElementsAreNoops) { TEST_F(UpdateArrayNodeTest, NoArrayElementAffectsIndexes) { auto update = fromjson("{$set: {'a.$[i].b': 0}}"); auto arrayFilter = fromjson("{'i.c': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -519,15 +520,15 @@ TEST_F(UpdateArrayNodeTest, NoArrayElementAffectsIndexes) { TEST_F(UpdateArrayNodeTest, WhenOneElementIsMatchedLogElementUpdateDirectly) { auto update = fromjson("{$set: {'a.$[i].b': 0}}"); auto arrayFilter = fromjson("{'i.c': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -544,15 +545,15 @@ TEST_F(UpdateArrayNodeTest, WhenOneElementIsMatchedLogElementUpdateDirectly) { TEST_F(UpdateArrayNodeTest, WhenOneElementIsModifiedLogElement) { auto update = fromjson("{$set: {'a.$[i].b': 0}}"); auto arrayFilter = fromjson("{'i.c': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -568,14 +569,14 @@ TEST_F(UpdateArrayNodeTest, WhenOneElementIsModifiedLogElement) { TEST_F(UpdateArrayNodeTest, ArrayUpdateOnEmptyArrayIsANoop) { auto update = fromjson("{$set: {'a.$[]': 0}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -592,15 +593,15 @@ TEST_F(UpdateArrayNodeTest, ArrayUpdateOnEmptyArrayIsANoop) { TEST_F(UpdateArrayNodeTest, ApplyPositionalInsideArrayUpdate) { auto update = fromjson("{$set: {'a.$[i].b.$': 1}}"); auto arrayFilter = fromjson("{'i.c': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -618,15 +619,15 @@ TEST_F(UpdateArrayNodeTest, ApplyPositionalInsideArrayUpdate) { TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateFromReplication) { auto update = fromjson("{$set: {'a.$[i].b': 1}}"); auto arrayFilter = fromjson("{'i': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -644,15 +645,15 @@ TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateFromReplication) { TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateNotFromReplication) { auto update = fromjson("{$set: {'a.$[i].b': 1}}"); auto arrayFilter = fromjson("{'i': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -667,15 +668,15 @@ TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateNotFromReplication) { TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateWithoutLogBuilderOrIndexData) { auto update = fromjson("{$set: {'a.$[i]': 1}}"); auto arrayFilter = fromjson("{'i': 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); diff --git a/src/mongo/db/update/update_driver.cpp b/src/mongo/db/update/update_driver.cpp index cfcc2d891fd..7eb4f4ffd7c 100644 --- a/src/mongo/db/update/update_driver.cpp +++ b/src/mongo/db/update/update_driver.cpp @@ -107,7 +107,7 @@ modifiertable::ModifierType validateMod(BSONElement mod) { bool parseUpdateExpression( BSONObj updateExpr, UpdateObjectNode* root, - const CollatorInterface* collator, + const boost::intrusive_ptr<ExpressionContext>& expCtx, const std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>>& arrayFilters) { bool positional = false; std::set<std::string> foundIdentifiers; @@ -127,7 +127,7 @@ bool parseUpdateExpression( auto modType = validateMod(mod); for (auto&& field : mod.Obj()) { auto statusWithPositional = UpdateObjectNode::parseAndMerge( - root, modType, field, collator, arrayFilters, foundIdentifiers); + root, modType, field, expCtx, arrayFilters, foundIdentifiers); uassertStatusOK(statusWithPositional); positional = positional || statusWithPositional.getValue(); } @@ -239,7 +239,7 @@ Status UpdateDriver::parse( case UpdateSemantics::kUpdateNode: { auto root = stdx::make_unique<UpdateObjectNode>(); _positional = - parseUpdateExpression(updateExpr, root.get(), _modOptions.collator, arrayFilters); + parseUpdateExpression(updateExpr, root.get(), _modOptions.expCtx, arrayFilters); _root = std::move(root); break; } @@ -555,7 +555,7 @@ void UpdateDriver::setCollator(const CollatorInterface* collator) { mod->setCollator(collator); } - _modOptions.collator = collator; + _modOptions.expCtx->setCollator(collator); } void UpdateDriver::clear() { diff --git a/src/mongo/db/update/update_driver.h b/src/mongo/db/update/update_driver.h index 3a74b1ca753..337a1abfe87 100644 --- a/src/mongo/db/update/update_driver.h +++ b/src/mongo/db/update/update_driver.h @@ -218,7 +218,8 @@ struct UpdateDriver::Options { bool logOp; ModifierInterface::Options modOptions; - Options() : logOp(false), modOptions() {} + explicit Options(const boost::intrusive_ptr<ExpressionContext>& expCtx) + : logOp(false), modOptions(ModifierInterface::Options::normal(expCtx)) {} }; } // namespace mongo diff --git a/src/mongo/db/update/update_driver_test.cpp b/src/mongo/db/update/update_driver_test.cpp index 52a4baa8b9a..f64c1e353d3 100644 --- a/src/mongo/db/update/update_driver_test.cpp +++ b/src/mongo/db/update/update_driver_test.cpp @@ -39,6 +39,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/field_ref.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/query_test_service_context.h" #include "mongo/db/update_index_data.h" @@ -50,7 +51,8 @@ namespace { using mongoutils::str::stream; TEST(Parse, Normal) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_OK(driver.parse(fromjson("{$set:{a:1}}"), arrayFilters)); @@ -59,7 +61,8 @@ TEST(Parse, Normal) { } TEST(Parse, MultiMods) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_OK(driver.parse(fromjson("{$set:{a:1, b:1}}"), arrayFilters)); @@ -68,7 +71,8 @@ TEST(Parse, MultiMods) { } TEST(Parse, MixingMods) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_OK(driver.parse(fromjson("{$set:{a:1}, $unset:{b:1}}"), arrayFilters)); @@ -77,7 +81,8 @@ TEST(Parse, MixingMods) { } TEST(Parse, ObjectReplacment) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_OK(driver.parse(fromjson("{obj: \"obj replacement\"}"), arrayFilters)); @@ -85,7 +90,8 @@ TEST(Parse, ObjectReplacment) { } TEST(Parse, EmptyMod) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_THROWS_CODE_AND_WHAT( @@ -96,7 +102,8 @@ TEST(Parse, EmptyMod) { } TEST(Parse, WrongMod) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_THROWS_CODE_AND_WHAT( @@ -107,7 +114,8 @@ TEST(Parse, WrongMod) { } TEST(Parse, WrongType) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_THROWS_CODE_AND_WHAT( @@ -119,7 +127,8 @@ TEST(Parse, WrongType) { } TEST(Parse, ModsWithLaterObjReplacement) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_THROWS_CODE_AND_WHAT( @@ -131,7 +140,8 @@ TEST(Parse, ModsWithLaterObjReplacement) { } TEST(Parse, SetOnInsert) { - UpdateDriver::Options opts; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_OK(driver.parse(fromjson("{$setOnInsert:{a:1}}"), arrayFilters)); @@ -140,9 +150,10 @@ TEST(Parse, SetOnInsert) { } TEST(Collator, SetCollationUpdatesModifierInterfaces) { - CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + CollatorInterfaceMock reverseStringCollator(CollatorInterfaceMock::MockType::kReverseString); BSONObj updateDocument = fromjson("{$max: {a: 'abd'}}"); - UpdateDriver::Options opts; + UpdateDriver::Options opts(expCtx); UpdateDriver driver(opts); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; @@ -154,7 +165,7 @@ TEST(Collator, SetCollationUpdatesModifierInterfaces) { const FieldRefSet emptyImmutablePaths; bool modified = false; mutablebson::Document doc(fromjson("{a: 'cba'}")); - driver.setCollator(&collator); + driver.setCollator(&reverseStringCollator); driver .update(StringData(), original, @@ -178,11 +189,13 @@ TEST(Collator, SetCollationUpdatesModifierInterfaces) { class CreateFromQueryFixture : public mongo::unittest::Test { public: CreateFromQueryFixture() - : _driverOps(new UpdateDriver(UpdateDriver::Options())), - _driverRepl(new UpdateDriver(UpdateDriver::Options())) { + : _opCtx(_serviceContext.makeOperationContext()), + _driverOps(new UpdateDriver( + UpdateDriver::Options(new ExpressionContext(_opCtx.get(), nullptr)))), + _driverRepl(new UpdateDriver( + UpdateDriver::Options(new ExpressionContext(_opCtx.get(), nullptr)))) { _driverOps->parse(fromjson("{$set:{'_':1}}"), _arrayFilters).transitional_ignore(); _driverRepl->parse(fromjson("{}"), _arrayFilters).transitional_ignore(); - _opCtx = _serviceContext.makeOperationContext(); } mutablebson::Document& doc() { diff --git a/src/mongo/db/update/update_leaf_node.h b/src/mongo/db/update/update_leaf_node.h index c268facec30..9a7c53dede9 100644 --- a/src/mongo/db/update/update_leaf_node.h +++ b/src/mongo/db/update/update_leaf_node.h @@ -28,6 +28,7 @@ #pragma once +#include "mongo/db/pipeline/expression_context.h" #include "mongo/db/update/update_node.h" namespace mongo { @@ -47,11 +48,12 @@ public: * root["$set"]["a.b"]. Returns a non-OK status if the value in 'modExpr' is invalid for the * type of leaf node. 'modExpr' must not be empty. * - * Some leaf nodes require a collator during initialization. For example, $pull requires a - * collator to construct a MatchExpression that will be used for applying updates across - * multiple documents. + * Some leaf nodes require an ExpressionContext during initialization. For example, $pull + * requires an ExpressionContext to construct a MatchExpression that will be used for applying + * updates across multiple documents. */ - virtual Status init(BSONElement modExpr, const CollatorInterface* collator) = 0; + virtual Status init(BSONElement modExpr, + const boost::intrusive_ptr<ExpressionContext>& expCtx) = 0; /* Check if it would be possible to create the path at 'pathToCreate' but don't actually create * it. If 'element' is not an embedded object or array (e.g., we are trying to create path diff --git a/src/mongo/db/update/update_object_node.cpp b/src/mongo/db/update/update_object_node.cpp index 9b984eb3a33..542ed8cd201 100644 --- a/src/mongo/db/update/update_object_node.cpp +++ b/src/mongo/db/update/update_object_node.cpp @@ -179,7 +179,7 @@ StatusWith<bool> UpdateObjectNode::parseAndMerge( UpdateObjectNode* root, modifiertable::ModifierType type, BSONElement modExpr, - const CollatorInterface* collator, + const boost::intrusive_ptr<ExpressionContext>& expCtx, const std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>>& arrayFilters, std::set<std::string>& foundIdentifiers) { FieldRef fieldRef; @@ -194,7 +194,7 @@ StatusWith<bool> UpdateObjectNode::parseAndMerge( auto status = parseAndMerge(root, modifiertable::ModifierType::MOD_CONFLICT_PLACEHOLDER, modExpr, - collator, + expCtx, arrayFilters, foundIdentifiers); if (!status.isOK()) { @@ -243,7 +243,7 @@ StatusWith<bool> UpdateObjectNode::parseAndMerge( // Construct and initialize the leaf node. auto leaf = modifiertable::makeUpdateLeafNode(type); invariant(leaf); - status = leaf->init(modExpr, collator); + status = leaf->init(modExpr, expCtx); if (!status.isOK()) { return status; } diff --git a/src/mongo/db/update/update_object_node.h b/src/mongo/db/update/update_object_node.h index 81608da70c1..afa75affef2 100644 --- a/src/mongo/db/update/update_object_node.h +++ b/src/mongo/db/update/update_object_node.h @@ -60,7 +60,7 @@ public: UpdateObjectNode* root, modifiertable::ModifierType type, BSONElement modExpr, - const CollatorInterface* collator, + const boost::intrusive_ptr<ExpressionContext>& expCtx, const std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>>& arrayFilters, std::set<std::string>& foundIdentifiers); diff --git a/src/mongo/db/update/update_object_node_test.cpp b/src/mongo/db/update/update_object_node_test.cpp index 1e699326587..c410553eb9d 100644 --- a/src/mongo/db/update/update_object_node_test.cpp +++ b/src/mongo/db/update/update_object_node_test.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/json.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/update/conflict_placeholder_node.h" #include "mongo/db/update/rename_node.h" @@ -49,14 +50,14 @@ using mongo::mutablebson::Element; TEST(UpdateObjectNodeTest, InvalidPathFailsToParse) { auto update = fromjson("{$set: {'': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"][""], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -66,42 +67,42 @@ TEST(UpdateObjectNodeTest, InvalidPathFailsToParse) { TEST(UpdateObjectNodeTest, ValidIncPathParsesSuccessfully) { auto update = fromjson("{$inc: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_INC, update["$inc"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidMulPathParsesSuccessfully) { auto update = fromjson("{$mul: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_MUL, update["$mul"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidRenamePathParsesSuccessfully) { auto update = fromjson("{$rename: {'a.b': 'c.d'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -122,140 +123,140 @@ TEST(UpdateObjectNodeTest, ValidRenamePathParsesSuccessfully) { TEST(UpdateObjectNodeTest, ValidSetPathParsesSuccessfully) { auto update = fromjson("{$set: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidUnsetPathParsesSuccessfully) { auto update = fromjson("{$unset: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_UNSET, update["$unset"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidAddToSetPathParsesSuccessfully) { auto update = fromjson("{$addToSet: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_ADD_TO_SET, update["$addToSet"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidPopPathParsesSuccessfully) { auto update = fromjson("{$pop: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_POP, update["$pop"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidMaxPathParsesSuccessfully) { auto update = fromjson("{$max: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_MAX, update["$max"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidMinPathParsesSuccessfully) { auto update = fromjson("{$min: {'a.b': 1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_MIN, update["$min"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidCurrentDatePathParsesSuccessfully) { auto update = fromjson("{$currentDate: {'a.b': true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_CURRENTDATE, update["$currentDate"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidSetOnInsertPathParsesSuccessfully) { auto update = fromjson("{$setOnInsert: {'a.b': true}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET_ON_INSERT, update["$setOnInsert"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ValidPushParsesSuccessfully) { auto update = fromjson("{$push: {'a.b': {$each: [0, 1], $sort: 1, $position: 0, $slice: 10}}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_PUSH, update["$push"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, MultiplePositionalElementsFailToParse) { auto update = fromjson("{$set: {'a.$.b.$': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b.$"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -266,14 +267,14 @@ TEST(UpdateObjectNodeTest, MultiplePositionalElementsFailToParse) { TEST(UpdateObjectNodeTest, ParsingSetsPositionalTrue) { auto update = fromjson("{$set: {'a.$.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_OK(result); @@ -282,14 +283,14 @@ TEST(UpdateObjectNodeTest, ParsingSetsPositionalTrue) { TEST(UpdateObjectNodeTest, ParsingSetsPositionalFalse) { auto update = fromjson("{$set: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_OK(result); @@ -298,14 +299,14 @@ TEST(UpdateObjectNodeTest, ParsingSetsPositionalFalse) { TEST(UpdateObjectNodeTest, PositionalElementFirstPositionFailsToParse) { auto update = fromjson("{$set: {'$': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["$"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -316,20 +317,20 @@ TEST(UpdateObjectNodeTest, PositionalElementFirstPositionFailsToParse) { TEST(UpdateObjectNodeTest, TwoModifiersOnSameFieldFailToParse) { auto update = fromjson("{$set: {a: 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -339,40 +340,40 @@ TEST(UpdateObjectNodeTest, TwoModifiersOnSameFieldFailToParse) { TEST(UpdateObjectNodeTest, TwoModifiersOnDifferentFieldsParseSuccessfully) { auto update = fromjson("{$set: {a: 5, b: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, TwoModifiersWithSameDottedPathFailToParse) { auto update = fromjson("{$set: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -383,20 +384,20 @@ TEST(UpdateObjectNodeTest, TwoModifiersWithSameDottedPathFailToParse) { TEST(UpdateObjectNodeTest, FirstModifierPrefixOfSecondFailToParse) { auto update = fromjson("{$set: {a: 5, 'a.b': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -407,20 +408,20 @@ TEST(UpdateObjectNodeTest, FirstModifierPrefixOfSecondFailToParse) { TEST(UpdateObjectNodeTest, FirstModifierDottedPrefixOfSecondFailsToParse) { auto update = fromjson("{$set: {'a.b': 5, 'a.b.c': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -431,20 +432,20 @@ TEST(UpdateObjectNodeTest, FirstModifierDottedPrefixOfSecondFailsToParse) { TEST(UpdateObjectNodeTest, SecondModifierPrefixOfFirstFailsToParse) { auto update = fromjson("{$set: {'a.b': 5, a: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -454,20 +455,20 @@ TEST(UpdateObjectNodeTest, SecondModifierPrefixOfFirstFailsToParse) { TEST(UpdateObjectNodeTest, SecondModifierDottedPrefixOfFirstFailsToParse) { auto update = fromjson("{$set: {'a.b.c': 5, 'a.b': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -478,80 +479,80 @@ TEST(UpdateObjectNodeTest, SecondModifierDottedPrefixOfFirstFailsToParse) { TEST(UpdateObjectNodeTest, ModifiersWithCommonPrefixParseSuccessfully) { auto update = fromjson("{$set: {'a.b': 5, 'a.c': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ModifiersWithCommonDottedPrefixParseSuccessfully) { auto update = fromjson("{$set: {'a.b.c': 5, 'a.b.d': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, ModifiersWithCommonPrefixDottedSuffixParseSuccessfully) { auto update = fromjson("{$set: {'a.b.c': 5, 'a.d.e': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.d.e"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, TwoModifiersOnSamePositionalFieldFailToParse) { auto update = fromjson("{$set: {'a.$': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -562,60 +563,60 @@ TEST(UpdateObjectNodeTest, TwoModifiersOnSamePositionalFieldFailToParse) { TEST(UpdateObjectNodeTest, PositionalFieldsWithDifferentPrefixesParseSuccessfully) { auto update = fromjson("{$set: {'a.$': 5, 'b.$': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["b.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, PositionalAndNonpositionalFieldWithCommonPrefixParseSuccessfully) { auto update = fromjson("{$set: {'a.$': 5, 'a.0': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.0"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, TwoModifiersWithSamePositionalDottedPathFailToParse) { auto update = fromjson("{$set: {'a.$.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -626,20 +627,20 @@ TEST(UpdateObjectNodeTest, TwoModifiersWithSamePositionalDottedPathFailToParse) TEST(UpdateObjectNodeTest, FirstModifierPositionalPrefixOfSecondFailsToParse) { auto update = fromjson("{$set: {'a.$': 5, 'a.$.b': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -650,20 +651,20 @@ TEST(UpdateObjectNodeTest, FirstModifierPositionalPrefixOfSecondFailsToParse) { TEST(UpdateObjectNodeTest, SecondModifierPositionalPrefixOfFirstFailsToParse) { auto update = fromjson("{$set: {'a.$.b': 5, 'a.$': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -674,54 +675,54 @@ TEST(UpdateObjectNodeTest, SecondModifierPositionalPrefixOfFirstFailsToParse) { TEST(UpdateObjectNodeTest, FirstModifierFieldPrefixOfSecondParsesSuccessfully) { auto update = fromjson("{$set: {'a': 5, 'ab': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["ab"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, SecondModifierFieldPrefixOfSecondParsesSuccessfully) { auto update = fromjson("{$set: {'ab': 5, 'a': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["ab"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); } TEST(UpdateObjectNodeTest, IdentifierWithoutArrayFilterFailsToParse) { auto update = fromjson("{$set: {'a.$[i]': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -732,14 +733,14 @@ TEST(UpdateObjectNodeTest, IdentifierWithoutArrayFilterFailsToParse) { TEST(UpdateObjectNodeTest, IdentifierInMiddleOfPathWithoutArrayFilterFailsToParse) { auto update = fromjson("{$set: {'a.$[i].b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -750,14 +751,14 @@ TEST(UpdateObjectNodeTest, IdentifierInMiddleOfPathWithoutArrayFilterFailsToPars TEST(UpdateObjectNodeTest, EmptyIdentifierParsesSuccessfully) { auto update = fromjson("{$set: {'a.$[]': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_TRUE(foundIdentifiers.empty()); @@ -765,14 +766,14 @@ TEST(UpdateObjectNodeTest, EmptyIdentifierParsesSuccessfully) { TEST(UpdateObjectNodeTest, EmptyIdentifierInMiddleOfPathParsesSuccessfully) { auto update = fromjson("{$set: {'a.$[].b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_TRUE(foundIdentifiers.empty()); @@ -781,15 +782,15 @@ TEST(UpdateObjectNodeTest, EmptyIdentifierInMiddleOfPathParsesSuccessfully) { TEST(UpdateObjectNodeTest, IdentifierWithArrayFilterParsesSuccessfully) { auto update = fromjson("{$set: {'a.$[i]': 5}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 1U); @@ -799,15 +800,15 @@ TEST(UpdateObjectNodeTest, IdentifierWithArrayFilterParsesSuccessfully) { TEST(UpdateObjectNodeTest, IdentifierWithArrayFilterInMiddleOfPathParsesSuccessfully) { auto update = fromjson("{$set: {'a.$[i].b': 5}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 1U); @@ -817,15 +818,15 @@ TEST(UpdateObjectNodeTest, IdentifierWithArrayFilterInMiddleOfPathParsesSuccessf TEST(UpdateObjectNodeTest, IdentifierInFirstPositionFailsToParse) { auto update = fromjson("{$set: {'$[i]': 5}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -838,15 +839,15 @@ TEST(UpdateObjectNodeTest, IdentifierInFirstPositionFailsToParse) { TEST(UpdateObjectNodeTest, IdentifierInFirstPositionWithSuffixFailsToParse) { auto update = fromjson("{$set: {'$[i].a': 5}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["$[i].a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -859,15 +860,15 @@ TEST(UpdateObjectNodeTest, IdentifierInFirstPositionWithSuffixFailsToParse) { TEST(UpdateObjectNodeTest, CreateObjectNodeInSamePositionAsArrayNodeFailsToParse) { auto update = fromjson("{$set: {'a.$[i]': 5, 'a.0': 6}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 1U); @@ -875,7 +876,7 @@ TEST(UpdateObjectNodeTest, CreateObjectNodeInSamePositionAsArrayNodeFailsToParse auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.0"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -887,21 +888,21 @@ TEST(UpdateObjectNodeTest, CreateObjectNodeInSamePositionAsArrayNodeFailsToParse TEST(UpdateObjectNodeTest, CreateArrayNodeInSamePositionAsObjectNodeFailsToParse) { auto update = fromjson("{$set: {'a.0': 5, 'a.$[i]': 6}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.0"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -913,15 +914,15 @@ TEST(UpdateObjectNodeTest, CreateArrayNodeInSamePositionAsObjectNodeFailsToParse TEST(UpdateObjectNodeTest, CreateLeafNodeInSamePositionAsArrayNodeFailsToParse) { auto update = fromjson("{$set: {'a.$[i]': 5, a: 6}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 1U); @@ -929,7 +930,7 @@ TEST(UpdateObjectNodeTest, CreateLeafNodeInSamePositionAsArrayNodeFailsToParse) auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -940,21 +941,21 @@ TEST(UpdateObjectNodeTest, CreateLeafNodeInSamePositionAsArrayNodeFailsToParse) TEST(UpdateObjectNodeTest, CreateArrayNodeInSamePositionAsLeafNodeFailsToParse) { auto update = fromjson("{$set: {a: 5, 'a.$[i]': 6}}"); auto arrayFilter = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -967,16 +968,16 @@ TEST(UpdateObjectNodeTest, CreateTwoChildrenOfArrayNodeParsesSuccessfully) { auto update = fromjson("{$set: {'a.$[i]': 5, 'a.$[j]': 6}}"); auto arrayFilterI = fromjson("{i: 0}"); auto arrayFilterJ = fromjson("{j: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 1U); @@ -984,7 +985,7 @@ TEST(UpdateObjectNodeTest, CreateTwoChildrenOfArrayNodeParsesSuccessfully) { ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[j]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 2U); @@ -996,15 +997,15 @@ TEST(UpdateObjectNodeTest, ConflictAtArrayNodeChildFailsToParse) { auto update1 = fromjson("{$set: {'a.$[i]': 5}}"); auto update2 = fromjson("{$set: {'a.$[i]': 6}}"); auto arrayFilterI = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update1["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 1U); @@ -1012,7 +1013,7 @@ TEST(UpdateObjectNodeTest, ConflictAtArrayNodeChildFailsToParse) { auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update2["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -1024,15 +1025,15 @@ TEST(UpdateObjectNodeTest, ConflictAtArrayNodeChildFailsToParse) { TEST(UpdateObjectNodeTest, ConflictThroughArrayNodeChildFailsToParse) { auto update = fromjson("{$set: {'a.$[i].b': 5, 'a.$[i].b.c': 6}}"); auto arrayFilterI = fromjson("{i: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 1U); @@ -1040,7 +1041,7 @@ TEST(UpdateObjectNodeTest, ConflictThroughArrayNodeChildFailsToParse) { auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -1053,16 +1054,16 @@ TEST(UpdateObjectNodeTest, NoConflictDueToDifferentArrayNodeChildrenParsesSucces auto update = fromjson("{$set: {'a.$[i].b': 5, 'a.$[j].b.c': 6}}"); auto arrayFilterI = fromjson("{i: 0}"); auto arrayFilterJ = fromjson("{j: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 1U); @@ -1070,7 +1071,7 @@ TEST(UpdateObjectNodeTest, NoConflictDueToDifferentArrayNodeChildrenParsesSucces ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[j].b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 2U); @@ -1082,16 +1083,16 @@ TEST(UpdateObjectNodeTest, MultipleArrayNodesAlongPathParsesSuccessfully) { auto update = fromjson("{$set: {'a.$[i].$[j].$[i]': 5}}"); auto arrayFilterI = fromjson("{i: 0}"); auto arrayFilterJ = fromjson("{j: 0}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$[i].$[j].$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_EQ(foundIdentifiers.size(), 2U); @@ -1121,20 +1122,20 @@ TEST(UpdateObjectNodeTest, DistinctFieldsMergeCorrectly) { auto setUpdate1 = fromjson("{$set: {'a': 5}}"); auto setUpdate2 = fromjson("{$set: {'ab': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["ab"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1151,20 +1152,20 @@ TEST(UpdateObjectNodeTest, NestedMergeSucceeds) { auto setUpdate1 = fromjson("{$set: {'a.c': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.d': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1187,20 +1188,20 @@ TEST(UpdateObjectNodeTest, DoublyNestedMergeSucceeds) { auto setUpdate1 = fromjson("{$set: {'a.b.c': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.b.d': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1229,20 +1230,20 @@ TEST(UpdateObjectNodeTest, FieldAndPositionalMergeCorrectly) { auto setUpdate1 = fromjson("{$set: {'a.b': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1266,20 +1267,20 @@ TEST(UpdateObjectNodeTest, MergeThroughPositionalSucceeds) { auto setUpdate1 = fromjson("{$set: {'a.$.b': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$.c': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1308,20 +1309,20 @@ TEST(UpdateObjectNodeTest, TopLevelConflictFails) { auto setUpdate1 = fromjson("{$set: {'a': 5}}"); auto setUpdate2 = fromjson("{$set: {'a': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1337,20 +1338,20 @@ TEST(UpdateObjectNodeTest, NestedConflictFails) { auto setUpdate1 = fromjson("{$set: {'a.b': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.b': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1366,20 +1367,20 @@ TEST(UpdateObjectNodeTest, LeftPrefixMergeFails) { auto setUpdate1 = fromjson("{$set: {'a.b': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.b.c': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1395,20 +1396,20 @@ TEST(UpdateObjectNodeTest, RightPrefixMergeFails) { auto setUpdate1 = fromjson("{$set: {'a.b.c': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.b': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1424,20 +1425,20 @@ TEST(UpdateObjectNodeTest, LeftPrefixMergeThroughPositionalFails) { auto setUpdate1 = fromjson("{$set: {'a.$.c': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$.c.d': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$.c.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1453,20 +1454,20 @@ TEST(UpdateObjectNodeTest, RightPrefixMergeThroughPositionalFails) { auto setUpdate1 = fromjson("{$set: {'a.$.c.d': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$.c': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$.c.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1482,20 +1483,20 @@ TEST(UpdateObjectNodeTest, MergeWithConflictingPositionalFails) { auto setUpdate1 = fromjson("{$set: {'a.$': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1513,25 +1514,25 @@ DEATH_TEST(UpdateObjectNodeTest, auto setUpdate1 = fromjson("{$set: {'a.$[i]': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$[j]': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto arrayFilterI = fromjson("{i: 0}"); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters1; - arrayFilters1["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); + arrayFilters1["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); auto arrayFilterJ = fromjson("{j: 0}"); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters2; - arrayFilters2["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); + arrayFilters2["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters1, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$[j]"], - collator, + expCtx, arrayFilters2, foundIdentifiers)); @@ -1542,22 +1543,22 @@ TEST(UpdateObjectNodeTest, MergingArrayNodeWithObjectNodeFails) { auto setUpdate1 = fromjson("{$set: {'a.$[i]': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.b': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto arrayFilter = fromjson("{i: 0}"); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1573,22 +1574,22 @@ TEST(UpdateObjectNodeTest, MergingArrayNodeWithLeafNodeFails) { auto setUpdate1 = fromjson("{$set: {'a.$[i]': 5}}"); auto setUpdate2 = fromjson("{$set: {'a': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto arrayFilter = fromjson("{i: 0}"); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1604,24 +1605,24 @@ TEST(UpdateObjectNodeTest, MergingTwoArrayNodesSucceeds) { auto setUpdate1 = fromjson("{$set: {'a.$[i]': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$[j]': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto arrayFilterI = fromjson("{i: 0}"); auto arrayFilterJ = fromjson("{j: 0}"); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, collator)); - arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterI, expCtx)); + arrayFilters["j"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilterJ, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$[i]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$[j]"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1644,22 +1645,22 @@ TEST(UpdateObjectNodeTest, MergeConflictThroughArrayNodesFails) { auto setUpdate1 = fromjson("{$set: {'a.$[i].b.c': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$[i].b': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto arrayFilter = fromjson("{i: 0}"); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$[i].b.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1675,22 +1676,22 @@ TEST(UpdateObjectNodeTest, NoMergeConflictThroughArrayNodesSucceeds) { auto setUpdate1 = fromjson("{$set: {'a.$[i].b': 5}}"); auto setUpdate2 = fromjson("{$set: {'a.$[i].c': 6}}"); FieldRef fakeFieldRef("root"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto arrayFilter = fromjson("{i: 0}"); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; - arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, collator)); + arrayFilters["i"] = uassertStatusOK(ExpressionWithPlaceholder::parse(arrayFilter, expCtx)); std::set<std::string> foundIdentifiers; UpdateObjectNode setRoot1, setRoot2; ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$[i].b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$[i].c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1717,14 +1718,14 @@ TEST(UpdateObjectNodeTest, NoMergeConflictThroughArrayNodesSucceeds) { TEST_F(UpdateObjectNodeTest, ApplyCreateField) { auto setUpdate = fromjson("{$set: {b: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1740,14 +1741,14 @@ TEST_F(UpdateObjectNodeTest, ApplyCreateField) { TEST_F(UpdateObjectNodeTest, ApplyExistingField) { auto setUpdate = fromjson("{$set: {a: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1763,32 +1764,32 @@ TEST_F(UpdateObjectNodeTest, ApplyExistingField) { TEST_F(UpdateObjectNodeTest, ApplyExistingAndNonexistingFields) { auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7, d: 8}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1804,32 +1805,32 @@ TEST_F(UpdateObjectNodeTest, ApplyExistingAndNonexistingFields) { TEST_F(UpdateObjectNodeTest, ApplyExistingNestedPaths) { auto setUpdate = fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b.e"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1846,32 +1847,32 @@ TEST_F(UpdateObjectNodeTest, ApplyExistingNestedPaths) { TEST_F(UpdateObjectNodeTest, ApplyCreateNestedPaths) { auto setUpdate = fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b.e"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1888,26 +1889,26 @@ TEST_F(UpdateObjectNodeTest, ApplyCreateNestedPaths) { TEST_F(UpdateObjectNodeTest, ApplyCreateDeeplyNestedPaths) { auto setUpdate = fromjson("{$set: {'a.b.c.d': 6, 'a.b.c.e': 7, 'a.f': 8}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b.c.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b.c.e"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.f"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1924,38 +1925,38 @@ TEST_F(UpdateObjectNodeTest, ApplyCreateDeeplyNestedPaths) { TEST_F(UpdateObjectNodeTest, ChildrenShouldBeAppliedInAlphabeticalOrder) { auto setUpdate = fromjson("{$set: {a: 5, d: 6, c: 7, b: 8, z: 9}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["z"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -1972,19 +1973,21 @@ TEST_F(UpdateObjectNodeTest, ChildrenShouldBeAppliedInAlphabeticalOrder) { TEST_F(UpdateObjectNodeTest, CollatorShouldNotAffectUpdateOrder) { auto setUpdate = fromjson("{$set: {abc: 5, cba: 6}}"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["abc"], - &collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["cba"], - &collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2000,26 +2003,26 @@ TEST_F(UpdateObjectNodeTest, CollatorShouldNotAffectUpdateOrder) { TEST_F(UpdateObjectNodeTest, ApplyNoop) { auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2037,26 +2040,26 @@ TEST_F(UpdateObjectNodeTest, ApplyNoop) { TEST_F(UpdateObjectNodeTest, ApplySomeChildrenNoops) { auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2074,14 +2077,14 @@ TEST_F(UpdateObjectNodeTest, ApplySomeChildrenNoops) { TEST_F(UpdateObjectNodeTest, ApplyBlockingElement) { auto setUpdate = fromjson("{$set: {'a.b': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2095,20 +2098,20 @@ TEST_F(UpdateObjectNodeTest, ApplyBlockingElement) { TEST_F(UpdateObjectNodeTest, ApplyBlockingElementFromReplication) { auto setUpdate = fromjson("{$set: {'a.b': 5, b: 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2125,14 +2128,14 @@ TEST_F(UpdateObjectNodeTest, ApplyBlockingElementFromReplication) { TEST_F(UpdateObjectNodeTest, ApplyPositionalMissingMatchedField) { auto setUpdate = fromjson("{$set: {'a.$': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2147,20 +2150,20 @@ TEST_F(UpdateObjectNodeTest, ApplyPositionalMissingMatchedField) { TEST_F(UpdateObjectNodeTest, ApplyMergePositionalChild) { auto setUpdate = fromjson("{$set: {'a.0.b': 5, 'a.$.c': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2177,32 +2180,32 @@ TEST_F(UpdateObjectNodeTest, ApplyMergePositionalChild) { TEST_F(UpdateObjectNodeTest, ApplyOrderMergedPositionalChild) { auto setUpdate = fromjson("{$set: {'a.2': 5, 'a.1.b': 6, 'a.0': 7, 'a.$.c': 8}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.2"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.1.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2220,20 +2223,20 @@ TEST_F(UpdateObjectNodeTest, ApplyOrderMergedPositionalChild) { TEST_F(UpdateObjectNodeTest, ApplyMergeConflictWithPositionalChild) { auto setUpdate = fromjson("{$set: {'a.0': 5, 'a.$': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2248,26 +2251,26 @@ TEST_F(UpdateObjectNodeTest, ApplyMergeConflictWithPositionalChild) { TEST_F(UpdateObjectNodeTest, ApplyDoNotMergePositionalChild) { auto setUpdate = fromjson("{$set: {'a.0': 5, 'a.2': 6, 'a.$': 7}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.2"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2284,26 +2287,26 @@ TEST_F(UpdateObjectNodeTest, ApplyDoNotMergePositionalChild) { TEST_F(UpdateObjectNodeTest, ApplyPositionalChildLast) { auto setUpdate = fromjson("{$set: {'a.$': 5, 'a.0': 6, 'a.1': 7}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.1"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2320,20 +2323,20 @@ TEST_F(UpdateObjectNodeTest, ApplyPositionalChildLast) { TEST_F(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) { auto setUpdate = fromjson("{$set: {'a.0.b': 5, 'a.$.c': 6}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2361,26 +2364,26 @@ TEST_F(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) { TEST_F(UpdateObjectNodeTest, ApplyDoNotUseStoredMergedPositional) { auto setUpdate = fromjson("{$set: {'a.0.b': 5, 'a.$.c': 6, 'a.1.d': 7}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.1.d"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2415,14 +2418,14 @@ TEST_F(UpdateObjectNodeTest, ApplyDoNotUseStoredMergedPositional) { */ TEST_F(UpdateObjectNodeTest, ApplyToArrayByIndexWithLeadingZero) { auto setUpdate = fromjson("{$set: {'a.02': 2}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.02"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2444,20 +2447,20 @@ TEST_F(UpdateObjectNodeTest, ApplyToArrayByIndexWithLeadingZero) { */ TEST_F(UpdateObjectNodeTest, ApplyMultipleArrayUpdates) { auto setUpdate = fromjson("{$set: {'a.2': 2, 'a.10': 10}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.2"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.10"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2475,14 +2478,14 @@ TEST_F(UpdateObjectNodeTest, ApplyMultipleArrayUpdates) { TEST_F(UpdateObjectNodeTest, ApplyUpdateToNonViablePathInArray) { auto setUpdate = fromjson("{$set: {'a.b': 3}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2496,20 +2499,20 @@ TEST_F(UpdateObjectNodeTest, ApplyUpdateToNonViablePathInArray) { TEST_F(UpdateObjectNodeTest, SetAndPopModifiersWithCommonPrefixApplySuccessfully) { auto update = fromjson("{$set: {'a.b': 5}, $pop: {'a.c': -1}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_POP, update["$pop"]["a.c"], - collator, + expCtx, arrayFilters, foundIdentifiers)); @@ -2523,7 +2526,7 @@ TEST_F(UpdateObjectNodeTest, SetAndPopModifiersWithCommonPrefixApplySuccessfully } TEST(ParseRenameTest, RenameToStringWithEmbeddedNullFails) { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; @@ -2535,7 +2538,7 @@ TEST(ParseRenameTest, RenameToStringWithEmbeddedNullFails) { auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2550,7 +2553,7 @@ TEST(ParseRenameTest, RenameToStringWithEmbeddedNullFails) { auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2565,7 +2568,7 @@ TEST(ParseRenameTest, RenameToStringWithEmbeddedNullFails) { auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2580,7 +2583,7 @@ TEST(ParseRenameTest, RenameToStringWithEmbeddedNullFails) { auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a.b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2590,14 +2593,14 @@ TEST(ParseRenameTest, RenameToStringWithEmbeddedNullFails) { TEST(ParseRenameTest, RenameToNonUpdatablePathFails) { auto update = fromjson("{$rename: {'a': 'b.'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2608,14 +2611,14 @@ TEST(ParseRenameTest, RenameToNonUpdatablePathFails) { TEST(ParseRenameTest, RenameFromNonUpdatablePathFails) { auto update = fromjson("{$rename: {'.a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"][".a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2626,14 +2629,14 @@ TEST(ParseRenameTest, RenameFromNonUpdatablePathFails) { TEST(ParseRenameTest, RenameToNonStringPathFails) { auto update = fromjson("{$rename: {'a': 5}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2650,14 +2653,14 @@ TEST(ParseRenameTest, RenameToNonStringPathFails) { */ TEST(ParseRenameTest, RenameWithSameNameFails) { auto update = fromjson("{$rename: {'a': 'a'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2668,14 +2671,14 @@ TEST(ParseRenameTest, RenameWithSameNameFails) { TEST(ParseRenameTest, RenameUpwardFails) { auto update = fromjson("{$rename: {'b.a': 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["b.a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2686,14 +2689,14 @@ TEST(ParseRenameTest, RenameUpwardFails) { TEST(ParseRenameTest, RenameDownwardFails) { auto update = fromjson("{$rename: {'b': 'b.a'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2704,20 +2707,20 @@ TEST(ParseRenameTest, RenameDownwardFails) { TEST(ParseRenameTest, ConflictWithRenameSourceFailsToParse) { auto update = fromjson("{$set: {a: 5}, $rename: {a: 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); @@ -2727,20 +2730,20 @@ TEST(ParseRenameTest, ConflictWithRenameSourceFailsToParse) { TEST(ParseRenameTest, ConflictWithRenameDestinationFailsToParse) { auto update = fromjson("{$set: {b: 5}, $rename: {a: 'b'}}"); - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; std::set<std::string> foundIdentifiers; UpdateObjectNode root; ASSERT_OK(UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_SET, update["$set"]["b"], - collator, + expCtx, arrayFilters, foundIdentifiers)); auto result = UpdateObjectNode::parseAndMerge(&root, modifiertable::ModifierType::MOD_RENAME, update["$rename"]["a"], - collator, + expCtx, arrayFilters, foundIdentifiers); ASSERT_NOT_OK(result); diff --git a/src/mongo/db/views/view_catalog.cpp b/src/mongo/db/views/view_catalog.cpp index 20ddd6066b4..59546ed05df 100644 --- a/src/mongo/db/views/view_catalog.cpp +++ b/src/mongo/db/views/view_catalog.cpp @@ -186,7 +186,7 @@ Status ViewCatalog::_upsertIntoGraph(OperationContext* opCtx, const ViewDefiniti request, CollatorInterface::cloneCollator(viewDef.defaultCollator()), std::move(resolvedNamespaces)); - auto pipelineStatus = Pipeline::parse(viewDef.pipeline(), expCtx); + auto pipelineStatus = Pipeline::parse(viewDef.pipeline(), std::move(expCtx)); if (!pipelineStatus.isOK()) { uassert(40255, str::stream() << "Invalid pipeline for view " << viewDef.name().ns() << "; " diff --git a/src/mongo/dbtests/SConscript b/src/mongo/dbtests/SConscript index ca98dec10cb..156d91111c0 100644 --- a/src/mongo/dbtests/SConscript +++ b/src/mongo/dbtests/SConscript @@ -126,6 +126,7 @@ dbtest = env.Program( "$BUILD_DIR/mongo/db/pipeline/document_value_test_util", "$BUILD_DIR/mongo/db/query/collation/collator_interface_mock", "$BUILD_DIR/mongo/db/query/query", + "$BUILD_DIR/mongo/db/query/query_planner_test_lib", "$BUILD_DIR/mongo/db/query/query_test_service_context", "$BUILD_DIR/mongo/db/repl/drop_pending_collection_reaper", "$BUILD_DIR/mongo/db/repl/repl_coordinator_global", diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp index 9d5fc0b5162..ab3ed2b08a0 100644 --- a/src/mongo/dbtests/documentsourcetests.cpp +++ b/src/mongo/dbtests/documentsourcetests.cpp @@ -325,8 +325,7 @@ TEST_F(DocumentSourceCursorTest, TailableAwaitDataCursorStillUsableAfterTimeout) collScanParams.collection = readLock.getCollection(); collScanParams.tailable = true; auto filter = BSON("a" << 1); - auto matchExpression = - uassertStatusOK(MatchExpressionParser::parse(filter, ctx()->getCollator())); + auto matchExpression = uassertStatusOK(MatchExpressionParser::parse(filter, ctx())); auto collectionScan = stdx::make_unique<CollectionScan>( opCtx(), collScanParams, workingSet.get(), matchExpression.get()); auto queryRequest = stdx::make_unique<QueryRequest>(nss); @@ -364,8 +363,7 @@ TEST_F(DocumentSourceCursorTest, NonAwaitDataCursorShouldErrorAfterTimeout) { CollectionScanParams collScanParams; collScanParams.collection = readLock.getCollection(); auto filter = BSON("a" << 1); - auto matchExpression = - uassertStatusOK(MatchExpressionParser::parse(filter, ctx()->getCollator())); + auto matchExpression = uassertStatusOK(MatchExpressionParser::parse(filter, ctx())); auto collectionScan = stdx::make_unique<CollectionScan>( opCtx(), collScanParams, workingSet.get(), matchExpression.get()); auto queryRequest = stdx::make_unique<QueryRequest>(nss); @@ -405,8 +403,7 @@ TEST_F(DocumentSourceCursorTest, TailableAwaitDataCursorShouldErrorAfterBeingKil collScanParams.collection = readLock.getCollection(); collScanParams.tailable = true; auto filter = BSON("a" << 1); - auto matchExpression = - uassertStatusOK(MatchExpressionParser::parse(filter, ctx()->getCollator())); + auto matchExpression = uassertStatusOK(MatchExpressionParser::parse(filter, ctx())); auto collectionScan = stdx::make_unique<CollectionScan>( opCtx(), collScanParams, workingSet.get(), matchExpression.get()); auto queryRequest = stdx::make_unique<QueryRequest>(nss); @@ -444,8 +441,7 @@ TEST_F(DocumentSourceCursorTest, NormalCursorShouldErrorAfterBeingKilled) { CollectionScanParams collScanParams; collScanParams.collection = readLock.getCollection(); auto filter = BSON("a" << 1); - auto matchExpression = - uassertStatusOK(MatchExpressionParser::parse(filter, ctx()->getCollator())); + auto matchExpression = uassertStatusOK(MatchExpressionParser::parse(filter, ctx())); auto collectionScan = stdx::make_unique<CollectionScan>( opCtx(), collScanParams, workingSet.get(), matchExpression.get()); auto queryRequest = stdx::make_unique<QueryRequest>(nss); diff --git a/src/mongo/dbtests/matchertests.cpp b/src/mongo/dbtests/matchertests.cpp index 3d20d60fde3..ee02b4b24de 100644 --- a/src/mongo/dbtests/matchertests.cpp +++ b/src/mongo/dbtests/matchertests.cpp @@ -61,8 +61,8 @@ class Basic { public: void run() { BSONObj query = fromjson("{\"a\":\"b\"}"); - const CollatorInterface* collator = nullptr; - M m(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(query, expCtx); ASSERT(m.matches(fromjson("{\"a\":\"b\"}"))); } }; @@ -72,8 +72,8 @@ class DoubleEqual { public: void run() { BSONObj query = fromjson("{\"a\":5}"); - const CollatorInterface* collator = nullptr; - M m(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(query, expCtx); ASSERT(m.matches(fromjson("{\"a\":5}"))); } }; @@ -84,8 +84,8 @@ public: void run() { BSONObjBuilder query; query.append("a", 5); - const CollatorInterface* collator = nullptr; - M m(query.done(), collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(query.done(), expCtx); ASSERT(m.matches(fromjson("{\"a\":5}"))); } }; @@ -95,8 +95,8 @@ class MixedNumericGt { public: void run() { BSONObj query = fromjson("{\"a\":{\"$gt\":4}}"); - const CollatorInterface* collator = nullptr; - M m(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(query, expCtx); BSONObjBuilder b; b.append("a", 5); ASSERT(m.matches(b.done())); @@ -111,8 +111,8 @@ public: ASSERT_EQUALS(4, query["a"].embeddedObject()["$in"].embeddedObject()["0"].number()); ASSERT_EQUALS(NumberInt, query["a"].embeddedObject()["$in"].embeddedObject()["0"].type()); - const CollatorInterface* collator = nullptr; - M m(query, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(query, expCtx); { BSONObjBuilder b; @@ -139,8 +139,8 @@ template <typename M> class MixedNumericEmbedded { public: void run() { - const CollatorInterface* collator = nullptr; - M m(BSON("a" << BSON("x" << 1)), collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(BSON("a" << BSON("x" << 1)), expCtx); ASSERT(m.matches(BSON("a" << BSON("x" << 1)))); ASSERT(m.matches(BSON("a" << BSON("x" << 1.0)))); } @@ -150,8 +150,8 @@ template <typename M> class Size { public: void run() { - const CollatorInterface* collator = nullptr; - M m(fromjson("{a:{$size:4}}"), collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(fromjson("{a:{$size:4}}"), expCtx); 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']}"))); @@ -163,8 +163,8 @@ template <typename M> class WithinBox { public: void run() { - const CollatorInterface* collator = nullptr; - M m(fromjson("{loc:{$within:{$box:[{x: 4, y:4},[6,6]]}}}"), collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(fromjson("{loc:{$within:{$box:[{x: 4, y:4},[6,6]]}}}"), expCtx); ASSERT(!m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: [4,4]}"))); ASSERT(m.matches(fromjson("{loc: [5,5]}"))); @@ -177,8 +177,8 @@ template <typename M> class WithinPolygon { public: void run() { - const CollatorInterface* collator = nullptr; - M m(fromjson("{loc:{$within:{$polygon:[{x:0,y:0},[0,5],[5,5],[5,0]]}}}"), collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(fromjson("{loc:{$within:{$polygon:[{x:0,y:0},[0,5],[5,5],[5,0]]}}}"), expCtx); ASSERT(m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: [4,4]}"))); ASSERT(m.matches(fromjson("{loc: {x:5,y:5}}"))); @@ -191,8 +191,8 @@ template <typename M> class WithinCenter { public: void run() { - const CollatorInterface* collator = nullptr; - M m(fromjson("{loc:{$within:{$center:[{x:30,y:30},10]}}}"), collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(fromjson("{loc:{$within:{$center:[{x:30,y:30},10]}}}"), expCtx); ASSERT(!m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: {x:30,y:30}}"))); ASSERT(m.matches(fromjson("{loc: [20,30]}"))); @@ -208,8 +208,8 @@ template <typename M> class ElemMatchKey { public: void run() { - const CollatorInterface* collator = nullptr; - M matcher(BSON("a.b" << 1), collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M matcher(BSON("a.b" << 1), expCtx); MatchDetails details; details.requestElemMatchKey(); ASSERT(!details.hasElemMatchKey()); @@ -230,10 +230,10 @@ public: AutoGetCollectionForReadCommand ctx(&opCtx, nss); const CollatorInterface* collator = nullptr; - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(opCtxPtr.get(), collator)); M m(BSON("$where" << "function(){ return this.a == 1; }"), - collator, expCtx, ExtensionsCallbackReal(&opCtx, &nss), MatchExpressionParser::AllowedFeatures::kJavascript); @@ -246,8 +246,8 @@ template <typename M> class TimingBase { public: long dotime(const BSONObj& patt, const BSONObj& obj) { - const CollatorInterface* collator = nullptr; - M m(patt, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + M m(patt, expCtx); Timer t; for (int i = 0; i < 900000; i++) { if (!m.matches(obj)) { @@ -277,10 +277,10 @@ template <typename M> class NullCollator { public: void run() { - const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); M matcher(BSON("a" << "string"), - collator); + expCtx); ASSERT(!matcher.matches(BSON("a" << "string2"))); } @@ -292,9 +292,11 @@ class Collator { public: void run() { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(&collator); M matcher(BSON("a" << "string"), - &collator); + expCtx); ASSERT(matcher.matches(BSON("a" << "string2"))); } diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp index d17dbdbbcfa..16d016f8eb9 100644 --- a/src/mongo/dbtests/query_stage_collscan.cpp +++ b/src/mongo/dbtests/query_stage_collscan.cpp @@ -93,8 +93,10 @@ public: // Make the filter. const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(&_opCtx, collator)); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterObj, collator); + MatchExpressionParser::parse(filterObj, expCtx); 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 130cd6e3e4b..e28d388d0aa 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -149,8 +149,10 @@ public: unique_ptr<WorkingSet> ws(new WorkingSet); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(&_opCtx, collator)); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(request.getQuery(), collator); + MatchExpressionParser::parse(request.getQuery(), expCtx); 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 e866d2df9c9..ae1dd71152e 100644 --- a/src/mongo/dbtests/query_stage_fetch.cpp +++ b/src/mongo/dbtests/query_stage_fetch.cpp @@ -194,8 +194,10 @@ public: // Make the filter. BSONObj filterObj = BSON("foo" << 6); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(&_opCtx, collator)); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterObj, collator); + MatchExpressionParser::parse(filterObj, expCtx); 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 dd1fc50b924..a76b67ac9d0 100644 --- a/src/mongo/dbtests/query_stage_multiplan.cpp +++ b/src/mongo/dbtests/query_stage_multiplan.cpp @@ -164,7 +164,9 @@ TEST_F(QueryStageMultiPlanTest, MPSCollectionScanVsHighlySelectiveIXScan) { // Make the filter. BSONObj filterObj = BSON("foo" << 7); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(filterObj, collator); + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(_opCtx.get(), collator)); + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(filterObj, expCtx); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filter = std::move(statusWithMatcher.getValue()); // Make the stage. @@ -458,7 +460,9 @@ TEST_F(QueryStageMultiPlanTest, ShouldReportErrorIfExceedsTimeLimitDuringPlannin // Make the filter. BSONObj filterObj = BSON("foo" << 7); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(filterObj, collator); + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(_opCtx.get(), collator)); + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(filterObj, expCtx); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filter = std::move(statusWithMatcher.getValue()); // Make the stage. @@ -521,7 +525,9 @@ TEST_F(QueryStageMultiPlanTest, ShouldReportErrorIfKilledDuringPlanning) { // Make the filter. BSONObj filterObj = BSON("foo" << 7); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(filterObj, collator); + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(_opCtx.get(), collator)); + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(filterObj, expCtx); 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 3b2e474e35a..279eafac9c7 100644 --- a/src/mongo/dbtests/query_stage_subplan.cpp +++ b/src/mongo/dbtests/query_stage_subplan.cpp @@ -452,8 +452,8 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanRewriteToRootedOr) { // Rewrite (AND (OR a b) e) => (OR (AND a e) (AND b e)) { BSONObj queryObj = fromjson("{$or:[{a:1}, {b:1}], e:1}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, expCtx); ASSERT_OK(expr.getStatus()); std::unique_ptr<MatchExpression> rewrittenExpr = SubplanStage::rewriteToRootedOr(std::move(expr.getValue())); @@ -469,8 +469,8 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanRewriteToRootedOr) { // 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}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, expCtx); ASSERT_OK(expr.getStatus()); std::unique_ptr<MatchExpression> rewrittenExpr = SubplanStage::rewriteToRootedOr(std::move(expr.getValue())); @@ -486,8 +486,8 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanRewriteToRootedOr) { // 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}"); - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, collator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, expCtx); 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 6b7893798e5..8f6e5a52373 100644 --- a/src/mongo/dbtests/query_stage_tests.cpp +++ b/src/mongo/dbtests/query_stage_tests.cpp @@ -82,8 +82,10 @@ public: AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(ns())); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContext> expCtx( + new ExpressionContext(&_opCtx, collator)); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(filterObj, collator); + MatchExpressionParser::parse(filterObj, expCtx); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue()); diff --git a/src/mongo/dbtests/query_stage_update.cpp b/src/mongo/dbtests/query_stage_update.cpp index 7ccd6058545..d53d3a2daf4 100644 --- a/src/mongo/dbtests/query_stage_update.cpp +++ b/src/mongo/dbtests/query_stage_update.cpp @@ -189,7 +189,8 @@ public: OldClientWriteContext ctx(&_opCtx, nss.ns()); CurOp& curOp = *CurOp::get(_opCtx); OpDebug* opDebug = &curOp.debug(); - UpdateDriver driver((UpdateDriver::Options())); + const CollatorInterface* collator = nullptr; + UpdateDriver driver((UpdateDriver::Options(new ExpressionContext(&_opCtx, collator)))); Collection* collection = ctx.getCollection(); // Collection should be empty. @@ -259,7 +260,8 @@ public: CurOp& curOp = *CurOp::get(_opCtx); OpDebug* opDebug = &curOp.debug(); - UpdateDriver driver((UpdateDriver::Options())); + const CollatorInterface* collator = nullptr; + UpdateDriver driver((UpdateDriver::Options(new ExpressionContext(&_opCtx, collator)))); Database* db = ctx.db(); Collection* coll = db->getCollection(&_opCtx, nss); @@ -377,7 +379,8 @@ public: Collection* coll = ctx.getCollection(); UpdateLifecycleImpl updateLifecycle(nss); UpdateRequest request(nss); - UpdateDriver driver((UpdateDriver::Options())); + const CollatorInterface* collator = nullptr; + UpdateDriver driver((UpdateDriver::Options(new ExpressionContext(&_opCtx, collator)))); const int targetDocIndex = 0; // We'll be working with the first doc in the collection. const BSONObj query = BSON("foo" << BSON("$gte" << targetDocIndex)); const auto ws = make_unique<WorkingSet>(); @@ -467,7 +470,8 @@ public: Collection* coll = ctx.getCollection(); UpdateLifecycleImpl updateLifecycle(nss); UpdateRequest request(nss); - UpdateDriver driver((UpdateDriver::Options())); + const CollatorInterface* collator = nullptr; + UpdateDriver driver((UpdateDriver::Options(new ExpressionContext(&_opCtx, collator)))); const int targetDocIndex = 10; const BSONObj query = BSON("foo" << BSON("$gte" << targetDocIndex)); const auto ws = make_unique<WorkingSet>(); @@ -553,7 +557,8 @@ public: Collection* coll = ctx.getCollection(); UpdateLifecycleImpl updateLifecycle(nss); UpdateRequest request(nss); - UpdateDriver driver((UpdateDriver::Options())); + const CollatorInterface* collator = nullptr; + UpdateDriver driver((UpdateDriver::Options(new ExpressionContext(&_opCtx, collator)))); const BSONObj query = BSONObj(); const auto ws = make_unique<WorkingSet>(); const unique_ptr<CanonicalQuery> cq(canonicalize(query)); diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index 4d001a6da9a..e3e7a6ce41b 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -305,6 +305,7 @@ env.CppUnitTest( 'chunk_manager_query_test.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/s/catalog/sharding_catalog_test_fixture', 'coreshard', ] |