diff options
116 files changed, 2685 insertions, 2203 deletions
diff --git a/jstests/aggregation/bugs/match.js b/jstests/aggregation/bugs/match.js index 2ee646dac7e..0d08c0744b8 100644 --- a/jstests/aggregation/bugs/match.js +++ b/jstests/aggregation/bugs/match.js @@ -51,10 +51,10 @@ function assertResults(expectedResults, matchSpec) { assertError(2, {a: {$mod: [0 /* invalid */, 0]}}); // $where not allowed. -assertError(16395, {$where: 'true'}); +assertError(ErrorCodes.BadValue, {$where: 'true'}); // Geo not allowed. -assertError(16424, {$match: {a: {$near: [0, 0]}}}); +assertError(ErrorCodes.BadValue, {$match: {a: {$near: [0, 0]}}}); // Update modifier not allowed. if (0) { // SERVER-6650 diff --git a/jstests/aggregation/bugs/server6335.js b/jstests/aggregation/bugs/server6335.js index a26568280ce..cecd00f9d4d 100644 --- a/jstests/aggregation/bugs/server6335.js +++ b/jstests/aggregation/bugs/server6335.js @@ -3,5 +3,5 @@ // load the test utilities load('jstests/aggregation/extras/utils.js'); -assertErrorCode(db.foo, {$match: {$where: "return true"}}, 16395); -assertErrorCode(db.foo, {$match: {$and: [{$where: "return true"}]}}, 16395); +assertErrorCode(db.foo, {$match: {$where: "return true"}}, ErrorCodes.BadValue); +assertErrorCode(db.foo, {$match: {$and: [{$where: "return true"}]}}, ErrorCodes.BadValue); diff --git a/jstests/aggregation/bugs/server6530.js b/jstests/aggregation/bugs/server6530.js index de2ec9c0912..22d26143e39 100644 --- a/jstests/aggregation/bugs/server6530.js +++ b/jstests/aggregation/bugs/server6530.js @@ -1,5 +1,6 @@ // server-6530: disallow $near queries in $match operations load('jstests/aggregation/extras/utils.js'); -assertErrorCode(db.foo, {$match: {$near: [0, 0]}}, 16424); -assertErrorCode(db.foo, {$match: {$nearSphere: [2, 2]}}, 16426); +assertErrorCode(db.foo, {$match: {$near: [0, 0]}}, ErrorCodes.BadValue); +assertErrorCode(db.foo, {$match: {$nearSphere: [2, 2]}}, ErrorCodes.BadValue); +assertErrorCode(db.foo, {$match: {$geoNear: [2, 2]}}, ErrorCodes.BadValue); diff --git a/jstests/aggregation/sources/graphLookup/error.js b/jstests/aggregation/sources/graphLookup/error.js index 3ed81a9345d..ab09a851f5d 100644 --- a/jstests/aggregation/sources/graphLookup/error.js +++ b/jstests/aggregation/sources/graphLookup/error.js @@ -272,7 +272,7 @@ load("jstests/aggregation/extras/utils.js"); // For "assertErrorCode". } } }; - assertErrorCode(local, pipeline, 40187, "cannot use $near inside $graphLookup"); + assertErrorCode(local, pipeline, 40186, "cannot use $near inside $graphLookup"); pipeline = { $graphLookup: { @@ -293,7 +293,19 @@ load("jstests/aggregation/extras/utils.js"); // For "assertErrorCode". } } }; - assertErrorCode(local, pipeline, 40187, "cannot use $near inside $graphLookup at any depth"); + assertErrorCode(local, pipeline, 40186, "cannot use $near inside $graphLookup at any depth"); + + pipeline = { + $graphLookup: { + from: 'foreign', + startWith: {$literal: 0}, + connectToField: "a", + connectFromField: "b", + as: "output", + restrictSearchWithMatch: {x: {$expr: 5}} + } + }; + assertErrorCode(local, pipeline, 40186, "cannot use $expr inside $graphLookup"); // $graphLookup can only consume at most 100MB of memory. var foreign = db.foreign; diff --git a/jstests/core/doc_validation_invalid_validators.js b/jstests/core/doc_validation_invalid_validators.js index 45cfa7c2cf4..ec6ccdd7fdb 100644 --- a/jstests/core/doc_validation_invalid_validators.js +++ b/jstests/core/doc_validation_invalid_validators.js @@ -37,7 +37,8 @@ assert.commandWorked(db.createCollection(collName, {validator: {a: {$exists: true}}})); // Verify some invalid match statements can't be passed to collMod. - assert.commandFailed(db.runCommand({"collMod": collName, "validator": {$text: "bob"}})); + assert.commandFailed( + db.runCommand({"collMod": collName, "validator": {$text: {$search: "bob"}}})); assert.commandFailed( db.runCommand({"collMod": collName, "validator": {$where: "this.a == this.b"}})); assert.commandFailed( @@ -46,6 +47,7 @@ db.runCommand({"collMod": collName, "validator": {$geoNear: {place: "holder"}}})); assert.commandFailed( db.runCommand({"collMod": collName, "validator": {$nearSphere: {place: "holder"}}})); + assert.commandFailed(db.runCommand({"collMod": collName, "validator": {a: {$expr: 5}}})); coll.drop(); diff --git a/jstests/core/list_collections_filter.js b/jstests/core/list_collections_filter.js index e0d18f055d0..8590d6ab6cf 100644 --- a/jstests/core/list_collections_filter.js +++ b/jstests/core/list_collections_filter.js @@ -83,4 +83,23 @@ ] }, []); + + // No extensions are allowed in filters. + assert.throws(function() { + mydb.getCollectionInfos({$text: {$search: "str"}}); + }); + assert.throws(function() { + mydb.getCollectionInfos({ + $where: function() { + return true; + } + }); + }); + assert.throws(function() { + mydb.getCollectionInfos( + {a: {$nearSphere: {$geometry: {type: "Point", coordinates: [0, 0]}}}}); + }); + assert.throws(function() { + mydb.getCollectionInfos({a: {$expr: 5}}); + }); }()); diff --git a/jstests/core/list_databases.js b/jstests/core/list_databases.js index 8ea7fbfe255..c308b0bc236 100644 --- a/jstests/core/list_databases.js +++ b/jstests/core/list_databases.js @@ -61,4 +61,20 @@ db.adminCommand({listDatabases: 1, nameOnly: true, filter: {name: /zap/}})); assert.eq(1, cmdRes.databases.length, tojson(cmdRes)); verifyNameOnly(cmdRes); + + // No extensions are allowed in filters. + assert.commandFailed(db.adminCommand({listDatabases: 1, filter: {$text: {$search: "str"}}})); + assert.commandFailed(db.adminCommand({ + listDatabases: 1, + filter: { + $where: function() { + return true; + } + } + })); + assert.commandFailed(db.adminCommand({ + listDatabases: 1, + filter: {a: {$nearSphere: {$geometry: {type: "Point", coordinates: [0, 0]}}}} + })); + assert.commandFailed(db.adminCommand({listDatabases: 1, filter: {a: {$expr: 5}}})); }()); 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 c11f2df00e0..1d2c92ecd2a 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp @@ -39,7 +39,6 @@ #include "mongo/db/auth/privilege_parser.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context_noop.h" #include "mongo/db/update/update_driver.h" @@ -296,8 +295,7 @@ Status AuthzManagerExternalStateMock::_queryVector( const BSONObj& query, std::vector<BSONObjCollection::iterator>* result) { CollatorInterface* collator = nullptr; - StatusWithMatchExpression parseResult = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression parseResult = MatchExpressionParser::parse(query, collator); if (!parseResult.isOK()) { return parseResult.getStatus(); } diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp index f3bbb12e49f..5d8e64a9bdd 100644 --- a/src/mongo/db/catalog/collection.cpp +++ b/src/mongo/db/catalog/collection.cpp @@ -49,7 +49,6 @@ #include "mongo/db/index/index_access_method.h" #include "mongo/db/keypattern.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/op_observer.h" #include "mongo/db/operation_context.h" #include "mongo/db/ops/update_request.h" diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index 58b04a89122..78f2d84c0d4 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -56,7 +56,6 @@ #include "mongo/db/index/index_access_method.h" #include "mongo/db/keypattern.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/op_observer.h" #include "mongo/db/operation_context.h" #include "mongo/db/ops/update_request.h" @@ -108,28 +107,6 @@ MONGO_INITIALIZER(InitializeParseValidationActionImpl)(InitializerContext* const // Used below to fail during inserts. MONGO_FP_DECLARE(failCollectionInserts); -const auto bannedExpressionsInValidators = std::set<StringData>{ - "$geoNear", "$near", "$nearSphere", "$text", "$where", -}; - -Status checkValidatorForBannedExpressions(const BSONObj& validator) { - for (auto field : validator) { - const auto name = field.fieldNameStringData(); - if (name[0] == '$' && bannedExpressionsInValidators.count(name)) { - return {ErrorCodes::InvalidOptions, - str::stream() << name << " is not allowed in collection validators"}; - } - - if (field.type() == Object || field.type() == Array) { - auto status = checkValidatorForBannedExpressions(field.Obj()); - if (!status.isOK()) - return status; - } - } - - return Status::OK(); -} - // Uses the collator factory to convert the BSON representation of a collator to a // CollatorInterface. Returns null if the BSONObj is empty. We expect the stored collation to be // valid, since it gets validated on collection create. @@ -305,14 +282,7 @@ StatusWithMatchExpression CollectionImpl::parseValidator(const BSONObj& validato << " database"}; } - { - auto status = checkValidatorForBannedExpressions(validator); - if (!status.isOK()) - return status; - } - - auto statusWithMatcher = MatchExpressionParser::parse( - validator, ExtensionsCallbackDisallowExtensions(), _collator.get()); + auto statusWithMatcher = MatchExpressionParser::parse(validator, _collator.get()); if (!statusWithMatcher.isOK()) return statusWithMatcher.getStatus(); diff --git a/src/mongo/db/catalog/index_catalog_entry_impl.cpp b/src/mongo/db/catalog/index_catalog_entry_impl.cpp index 5a6cb153456..7f46d56dac8 100644 --- a/src/mongo/db/catalog/index_catalog_entry_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_entry_impl.cpp @@ -44,7 +44,6 @@ #include "mongo/db/index/index_descriptor.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/operation_context.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/service_context.h" @@ -128,8 +127,8 @@ IndexCatalogEntryImpl::IndexCatalogEntryImpl(IndexCatalogEntry* const this_, if (BSONElement filterElement = _descriptor->getInfoElement("partialFilterExpression")) { invariant(filterElement.isABSONObj()); BSONObj filter = filterElement.Obj(); - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), _collator.get()); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(filter, _collator.get()); // 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 40f2ecb1c0d..b128061a1c1 100644 --- a/src/mongo/db/catalog/index_catalog_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_impl.cpp @@ -55,7 +55,6 @@ #include "mongo/db/jsobj.h" #include "mongo/db/keypattern.h" #include "mongo/db/matcher/expression.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/operation_context.h" #include "mongo/db/ops/delete.h" #include "mongo/db/query/collation/collation_spec.h" @@ -667,8 +666,8 @@ Status IndexCatalogImpl::_isSpecOk(OperationContext* opCtx, const BSONObj& spec) } // The collator must outlive the constructed MatchExpression. - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filterElement.Obj(), ExtensionsCallbackDisallowExtensions(), collator.get()); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(filterElement.Obj(), collator.get()); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } diff --git a/src/mongo/db/commands/apply_ops_cmd.cpp b/src/mongo/db/commands/apply_ops_cmd.cpp index 504abd19079..e2c0d9c6f4a 100644 --- a/src/mongo/db/commands/apply_ops_cmd.cpp +++ b/src/mongo/db/commands/apply_ops_cmd.cpp @@ -43,7 +43,6 @@ #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/jsobj.h" -#include "mongo/db/matcher/matcher.h" #include "mongo/db/operation_context.h" #include "mongo/db/repl/apply_ops.h" #include "mongo/db/repl/oplog.h" diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index ef4ddac6eb1..f5cc3803928 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -74,7 +74,6 @@ #include "mongo/db/json.h" #include "mongo/db/keypattern.h" #include "mongo/db/lasterror.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/op_observer.h" #include "mongo/db/ops/insert.h" @@ -696,8 +695,7 @@ public: qr->setFilter(query); qr->setSort(sort); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr)); if (!statusWithCQ.isOK()) { uasserted(17240, "Can't canonicalize query " + query.toString()); return false; diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index f54dbbbf312..fe1d0940ff9 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -151,8 +151,14 @@ public: // Finish the parsing step by using the QueryRequest to create a CanonicalQuery. ExtensionsCallbackReal extensionsCallback(opCtx, &nss); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx, std::move(qrStatus.getValue()), extensionsCallback); + CanonicalQuery::canonicalize(opCtx, + std::move(qrStatus.getValue()), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { return statusWithCQ.getStatus(); } @@ -257,7 +263,14 @@ public: // Finish the parsing step by using the QueryRequest to create a CanonicalQuery. ExtensionsCallbackReal extensionsCallback(opCtx, &nss); - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { return appendCommandStatus(result, statusWithCQ.getStatus()); } diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp index 2a5c5c32d6c..02a57e7d0e8 100644 --- a/src/mongo/db/commands/geo_near_cmd.cpp +++ b/src/mongo/db/commands/geo_near_cmd.cpp @@ -215,7 +215,14 @@ public: qr->setLimit(numWanted); qr->setCollation(collation); const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { errmsg = "Can't parse filter / create query"; return false; diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp index c7e3b2043bc..1992f122edc 100644 --- a/src/mongo/db/commands/index_filter_commands.cpp +++ b/src/mongo/db/commands/index_filter_commands.cpp @@ -310,7 +310,14 @@ Status ClearFilters::clear(OperationContext* opCtx, qr->setSort(entry.sort); qr->setProj(entry.projection); qr->setCollation(entry.collation); - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); invariantOK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); diff --git a/src/mongo/db/commands/index_filter_commands_test.cpp b/src/mongo/db/commands/index_filter_commands_test.cpp index e182aabe539..17dec1cb003 100644 --- a/src/mongo/db/commands/index_filter_commands_test.cpp +++ b/src/mongo/db/commands/index_filter_commands_test.cpp @@ -33,7 +33,6 @@ #include "mongo/db/commands/index_filter_commands.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/operation_context_noop.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/plan_ranker.h" @@ -132,8 +131,7 @@ void addQueryShapeToPlanCache(OperationContext* opCtx, qr->setSort(fromjson(sortStr)); qr->setProj(fromjson(projectionStr)); qr->setCollation(fromjson(collationStr)); - auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -162,8 +160,7 @@ bool planCacheContains(const PlanCache& planCache, qr->setSort(fromjson(sortStr)); qr->setProj(fromjson(projectionStr)); qr->setCollation(fromjson(collationStr)); - auto statusWithInputQuery = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithInputQuery = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithInputQuery.getStatus()); unique_ptr<CanonicalQuery> inputQuery = std::move(statusWithInputQuery.getValue()); @@ -183,8 +180,7 @@ bool planCacheContains(const PlanCache& planCache, qr->setSort(entry->sort); qr->setProj(entry->projection); qr->setCollation(entry->collation); - auto statusWithCurrentQuery = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCurrentQuery = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCurrentQuery.getStatus()); unique_ptr<CanonicalQuery> currentQuery = std::move(statusWithCurrentQuery.getValue()); diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp index 6a619a43861..c952573ac14 100644 --- a/src/mongo/db/commands/list_collections.cpp +++ b/src/mongo/db/commands/list_collections.cpp @@ -49,7 +49,6 @@ #include "mongo/db/exec/queued_data_stage.h" #include "mongo/db/exec/working_set.h" #include "mongo/db/index/index_descriptor.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/cursor_request.h" #include "mongo/db/query/cursor_response.h" #include "mongo/db/query/find_common.h" @@ -245,8 +244,8 @@ public: } // The collator is null because collection objects are compared using binary comparison. const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filterElt.Obj(), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(filterElt.Obj(), collator); 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 b25a13b887b..232803320d0 100644 --- a/src/mongo/db/commands/list_databases.cpp +++ b/src/mongo/db/commands/list_databases.cpp @@ -35,7 +35,6 @@ #include "mongo/db/commands.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/matcher/expression.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/operation_context.h" #include "mongo/db/service_context.h" #include "mongo/db/storage/storage_engine.h" @@ -100,8 +99,7 @@ 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(), ExtensionsCallbackDisallowExtensions(), collator); + auto statusWithMatcher = MatchExpressionParser::parse(filterElt.Obj(), collator); if (!statusWithMatcher.isOK()) { return appendCommandStatus(result, statusWithMatcher.getStatus()); } diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 580918250a0..3cfbad4b4c7 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -53,7 +53,6 @@ #include "mongo/db/exec/working_set_common.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/matcher/extensions_callback_real.h" -#include "mongo/db/matcher/matcher.h" #include "mongo/db/op_observer.h" #include "mongo/db/ops/insert.h" #include "mongo/db/query/find_common.h" @@ -1096,7 +1095,14 @@ void State::finalReduce(OperationContext* opCtx, CurOp* curOp, ProgressMeterHold auto qr = stdx::make_unique<QueryRequest>(_config.incLong); qr->setSort(sortKey); - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); verify(statusWithCQ.isOK()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -1464,8 +1470,14 @@ public: const ExtensionsCallbackReal extensionsCallback(opCtx, &config.nss); - auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = CanonicalQuery::canonicalize( + opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { uasserted(17238, "Can't canonicalize query " + config.filter.toString()); return 0; diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp index f66bc7392b2..031d59e408d 100644 --- a/src/mongo/db/commands/plan_cache_commands.cpp +++ b/src/mongo/db/commands/plan_cache_commands.cpp @@ -207,7 +207,14 @@ StatusWith<unique_ptr<CanonicalQuery>> PlanCacheCommand::canonicalize(OperationC qr->setProj(projObj); qr->setCollation(collationObj); const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { return statusWithCQ.getStatus(); } diff --git a/src/mongo/db/commands/plan_cache_commands_test.cpp b/src/mongo/db/commands/plan_cache_commands_test.cpp index 97b3884f8cd..e8a80bf2266 100644 --- a/src/mongo/db/commands/plan_cache_commands_test.cpp +++ b/src/mongo/db/commands/plan_cache_commands_test.cpp @@ -35,7 +35,6 @@ #include <algorithm> #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/operation_context_noop.h" #include "mongo/db/query/plan_ranker.h" #include "mongo/db/query/query_solution.h" @@ -142,8 +141,7 @@ TEST(PlanCacheCommandsTest, planCacheListQueryShapesOneKey) { qr->setSort(fromjson("{a: -1}")); qr->setProj(fromjson("{_id: 0}")); qr->setCollation(fromjson("{locale: 'mock_reverse_string'}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -174,8 +172,7 @@ TEST(PlanCacheCommandsTest, planCacheClearAllShapes) { // Create a canonical query auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: 1}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -310,14 +307,12 @@ TEST(PlanCacheCommandsTest, planCacheClearOneKey) { // Create 2 canonical queries. auto qrA = stdx::make_unique<QueryRequest>(nss); qrA->setFilter(fromjson("{a: 1}")); - auto statusWithCQA = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qrA), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQA = CanonicalQuery::canonicalize(opCtx.get(), std::move(qrA)); ASSERT_OK(statusWithCQA.getStatus()); auto qrB = stdx::make_unique<QueryRequest>(nss); qrB->setFilter(fromjson("{b: 1}")); unique_ptr<CanonicalQuery> cqA = std::move(statusWithCQA.getValue()); - auto statusWithCQB = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qrB), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQB = CanonicalQuery::canonicalize(opCtx.get(), std::move(qrB)); ASSERT_OK(statusWithCQB.getStatus()); unique_ptr<CanonicalQuery> cqB = std::move(statusWithCQB.getValue()); @@ -365,15 +360,13 @@ TEST(PlanCacheCommandsTest, planCacheClearOneKeyCollation) { // Create 2 canonical queries, one with collation. auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: 'foo'}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); auto qrCollation = stdx::make_unique<QueryRequest>(nss); qrCollation->setFilter(fromjson("{a: 'foo'}")); qrCollation->setCollation(fromjson("{locale: 'mock_reverse_string'}")); - auto statusWithCQCollation = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qrCollation), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQCollation = CanonicalQuery::canonicalize(opCtx.get(), std::move(qrCollation)); ASSERT_OK(statusWithCQCollation.getStatus()); unique_ptr<CanonicalQuery> cqCollation = std::move(statusWithCQCollation.getValue()); @@ -519,8 +512,7 @@ TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionTrue) { // Create a canonical query auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: 1}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -547,8 +539,7 @@ TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionFalse) { // Create a canonical query auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: 1}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -578,15 +569,13 @@ TEST(PlanCacheCommandsTest, planCacheListPlansCollation) { // Create 2 canonical queries, one with collation. auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: 'foo'}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); auto qrCollation = stdx::make_unique<QueryRequest>(nss); qrCollation->setFilter(fromjson("{a: 'foo'}")); qrCollation->setCollation(fromjson("{locale: 'mock_reverse_string'}")); - auto statusWithCQCollation = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qrCollation), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQCollation = CanonicalQuery::canonicalize(opCtx.get(), std::move(qrCollation)); ASSERT_OK(statusWithCQCollation.getStatus()); unique_ptr<CanonicalQuery> cqCollation = std::move(statusWithCQCollation.getValue()); diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index 24f5501dba1..bb27f53b049 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -113,7 +113,14 @@ RecordId Helpers::findOne(OperationContext* opCtx, auto qr = stdx::make_unique<QueryRequest>(collection->ns()); qr->setFilter(query); - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); massert(17244, "Could not canonicalize " + query.toString(), statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); diff --git a/src/mongo/db/exec/projection.cpp b/src/mongo/db/exec/projection.cpp index b16dd789915..65ee238c4a0 100644 --- a/src/mongo/db/exec/projection.cpp +++ b/src/mongo/db/exec/projection.cpp @@ -61,8 +61,7 @@ ProjectionStage::ProjectionStage(OperationContext* opCtx, _projObj = params.projObj; if (ProjectionStageParams::NO_FAST_PATH == _projImpl) { - _exec.reset(new ProjectionExec( - params.projObj, params.fullExpression, params.collator, *params.extensionsCallback)); + _exec.reset(new ProjectionExec(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.h b/src/mongo/db/exec/projection.h index a7422eb180f..185c94ff2be 100644 --- a/src/mongo/db/exec/projection.h +++ b/src/mongo/db/exec/projection.h @@ -38,7 +38,6 @@ namespace mongo { class CollatorInterface; -class ExtensionsCallback; struct ProjectionStageParams { enum ProjectionImplementation { @@ -52,8 +51,6 @@ struct ProjectionStageParams { SIMPLE_DOC }; - ProjectionStageParams(const ExtensionsCallback& wc) : extensionsCallback(&wc) {} - ProjectionImplementation projImpl = NO_FAST_PATH; // The projection object. We lack a ProjectionExpression or similar so we use a BSONObj. @@ -68,9 +65,6 @@ struct ProjectionStageParams { // from. Otherwise, this field is ignored. BSONObj coveredKeyObj; - // Used for creating context for the match extensions processing. Not owned. - const ExtensionsCallback* extensionsCallback; - // The collator this operation should use to compare strings. If null, the collation is a simple // binary compare. const CollatorInterface* collator = nullptr; diff --git a/src/mongo/db/exec/projection_exec.cpp b/src/mongo/db/exec/projection_exec.cpp index 230673dcc7e..d4842ac1e74 100644 --- a/src/mongo/db/exec/projection_exec.cpp +++ b/src/mongo/db/exec/projection_exec.cpp @@ -79,8 +79,7 @@ ProjectionExec::ProjectionExec() ProjectionExec::ProjectionExec(const BSONObj& spec, const MatchExpression* queryExpression, - const CollatorInterface* collator, - const ExtensionsCallback& extensionsCallback) + const CollatorInterface* collator) : _include(true), _special(false), _source(spec), @@ -133,7 +132,7 @@ ProjectionExec::ProjectionExec(const BSONObj& spec, verify(elemMatchObj.isOwned()); _elemMatchObjs.push_back(elemMatchObj); StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(elemMatchObj, extensionsCallback, _collator); + MatchExpressionParser::parse(elemMatchObj, _collator); 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 b06340e5f12..9575d59042f 100644 --- a/src/mongo/db/exec/projection_exec.h +++ b/src/mongo/db/exec/projection_exec.h @@ -68,8 +68,7 @@ public: ProjectionExec(const BSONObj& spec, const MatchExpression* queryExpression, - const CollatorInterface* collator, - const ExtensionsCallback& extensionsCallback); + const CollatorInterface* collator); ~ProjectionExec(); diff --git a/src/mongo/db/exec/projection_exec_test.cpp b/src/mongo/db/exec/projection_exec_test.cpp index 673ad7c3c48..41c40c2b287 100644 --- a/src/mongo/db/exec/projection_exec_test.cpp +++ b/src/mongo/db/exec/projection_exec_test.cpp @@ -35,7 +35,6 @@ #include "mongo/db/exec/working_set_computed_data.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/unittest.h" #include <memory> @@ -51,8 +50,7 @@ using std::unique_ptr; */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); ASSERT_TRUE(status.isOK()); return std::move(status.getValue()); } @@ -85,8 +83,7 @@ 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, ExtensionsCallbackDisallowExtensions()); + ProjectionExec exec(spec, queryExpression.get(), collator); // Create working set member. WorkingSetMember wsm; @@ -169,8 +166,7 @@ BSONObj transformMetaSortKeyCovered(const BSONObj& sortKey, wsm->addComputed(new SortKeyComputedData(sortKey)); ws.transitionToRecordIdAndIdx(wsid); - ProjectionExec projExec( - fromjson(projSpec), nullptr, nullptr, ExtensionsCallbackDisallowExtensions()); + ProjectionExec projExec(fromjson(projSpec), nullptr, nullptr); ASSERT_OK(projExec.transform(wsm)); return wsm->obj.value(); @@ -183,7 +179,7 @@ BSONObj transformCovered(BSONObj projSpec, const IndexKeyDatum& ikd) { wsm->keyData.push_back(ikd); ws.transitionToRecordIdAndIdx(wsid); - ProjectionExec projExec(projSpec, nullptr, nullptr, ExtensionsCallbackDisallowExtensions()); + ProjectionExec projExec(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 dfd382a2aec..d8186f637e0 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -248,8 +248,14 @@ public: BSONObj argObj = e.Obj(); if (filterTag == e.fieldName()) { const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContext> expCtx; StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - argObj, ExtensionsCallbackReal(opCtx, &collection->ns()), collator); + argObj, + collator, + expCtx, + ExtensionsCallbackReal(opCtx, &collection->ns()), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithMatcher.isOK()) { return NULL; } diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp index 672af4c8c75..ca8281aeb6e 100644 --- a/src/mongo/db/exec/subplan.cpp +++ b/src/mongo/db/exec/subplan.cpp @@ -180,8 +180,6 @@ Status SubplanStage::planSubqueries() { LOG(5) << "Subplanner: index " << i << " is " << ie; } - const ExtensionsCallbackReal extensionsCallback(getOpCtx(), &_collection->ns()); - for (size_t i = 0; i < _orExpression->numChildren(); ++i) { // We need a place to shove the results from planning this branch. _branchResults.push_back(stdx::make_unique<BranchPlanningResult>()); @@ -190,8 +188,7 @@ Status SubplanStage::planSubqueries() { MatchExpression* orChild = _orExpression->getChild(i); // Turn the i-th child into its own query. - auto statusWithCQ = - CanonicalQuery::canonicalize(getOpCtx(), *_query, orChild, extensionsCallback); + auto statusWithCQ = CanonicalQuery::canonicalize(getOpCtx(), *_query, orChild); if (!statusWithCQ.isOK()) { mongoutils::str::stream ss; ss << "Can't canonicalize subchild " << orChild->toString() << " " diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript index e8c9146cf69..8d8b89496bd 100644 --- a/src/mongo/db/matcher/SConscript +++ b/src/mongo/db/matcher/SConscript @@ -43,7 +43,6 @@ env.Library( 'expression_where_noop.cpp', 'expression_with_placeholder.cpp', 'extensions_callback.cpp', - 'extensions_callback_disallow_extensions.cpp', 'extensions_callback_noop.cpp', 'match_details.cpp', 'matchable.cpp', diff --git a/src/mongo/db/matcher/copyable_match_expression.h b/src/mongo/db/matcher/copyable_match_expression.h index 9f17fd1b082..8961dce131d 100644 --- a/src/mongo/db/matcher/copyable_match_expression.h +++ b/src/mongo/db/matcher/copyable_match_expression.h @@ -29,6 +29,7 @@ #pragma once #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/extensions_callback_noop.h" namespace mongo { @@ -50,11 +51,15 @@ public: * encounter an error. */ CopyableMatchExpression(BSONObj matchAST, - std::unique_ptr<const ExtensionsCallback> extensionsCallback, - const CollatorInterface* collator) + const CollatorInterface* collator, + const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr, + std::unique_ptr<const ExtensionsCallback> extensionsCallback = + stdx::make_unique<ExtensionsCallbackNoop>(), + MatchExpressionParser::AllowedFeatureSet allowedFeatures = + MatchExpressionParser::kBanAllSpecialFeatures) : _matchAST(matchAST), _extensionsCallback(std::move(extensionsCallback)) { - StatusWithMatchExpression parseResult = - MatchExpressionParser::parse(_matchAST, *_extensionsCallback, collator); + StatusWithMatchExpression parseResult = MatchExpressionParser::parse( + _matchAST, collator, expCtx, *_extensionsCallback, allowedFeatures); uassertStatusOK(parseResult.getStatus()); _matchExpr = std::move(parseResult.getValue()); } @@ -67,9 +72,18 @@ public: * if there other CopyableMatchExpression objects referencing this MatchExpression, they don't * see the change in collator. */ - void setCollator(const CollatorInterface* collator) { - StatusWithMatchExpression parseResult = - MatchExpressionParser::parse(_matchAST, *_extensionsCallback, collator); + 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()); } diff --git a/src/mongo/db/matcher/expression_algo_test.cpp b/src/mongo/db/matcher/expression_algo_test.cpp index c01f77a183b..b97146bc08b 100644 --- a/src/mongo/db/matcher/expression_algo_test.cpp +++ b/src/mongo/db/matcher/expression_algo_test.cpp @@ -37,8 +37,6 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" -#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/platform/decimal128.h" @@ -54,8 +52,7 @@ class ParsedMatchExpression { public: ParsedMatchExpression(const std::string& str, const CollatorInterface* collator = nullptr) : _obj(fromjson(str)) { - StatusWithMatchExpression result = - MatchExpressionParser::parse(_obj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(_obj, collator); ASSERT_OK(result.getStatus()); _expr = std::move(result.getValue()); } @@ -74,10 +71,8 @@ TEST(ExpressionAlgoIsSubsetOf, NullAndOmittedField) { // an Undefined type. BSONObj undefined = fromjson("{a: undefined}"); const CollatorInterface* collator = nullptr; - ASSERT_EQUALS( - ErrorCodes::BadValue, - MatchExpressionParser::parse(undefined, ExtensionsCallbackDisallowExtensions(), collator) - .getStatus()); + ASSERT_EQUALS(ErrorCodes::BadValue, + MatchExpressionParser::parse(undefined, collator).getStatus()); ParsedMatchExpression empty("{}"); ParsedMatchExpression null("{a: null}"); @@ -714,8 +709,7 @@ TEST(ExpressionAlgoIsSubsetOf, NonMatchingCollationsNoStringComparison) { TEST(IsIndependent, AndIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 1}]}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -726,8 +720,7 @@ TEST(IsIndependent, AndIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, ElemMatchIsNotIndependent) { BSONObj matchPredicate = fromjson("{x: {$elemMatch: {y: 1}}}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -739,8 +732,7 @@ TEST(IsIndependent, ElemMatchIsNotIndependent) { TEST(IsIndependent, NorIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$nor: [{a: 1}, {b: 1}]}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -751,8 +743,7 @@ TEST(IsIndependent, NorIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, NotIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -763,8 +754,7 @@ TEST(IsIndependent, NotIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, OrIsIndependentOnlyIfChildrenAre) { BSONObj matchPredicate = fromjson("{$or: [{a: 1}, {b: 1}]}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -775,8 +765,7 @@ TEST(IsIndependent, OrIsIndependentOnlyIfChildrenAre) { TEST(IsIndependent, AndWithDottedFieldPathsIsNotIndependent) { BSONObj matchPredicate = fromjson("{$and: [{'a': 1}, {'a.b': 1}]}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -787,8 +776,7 @@ TEST(IsIndependent, AndWithDottedFieldPathsIsNotIndependent) { TEST(IsIndependent, BallIsIndependentOfBalloon) { BSONObj matchPredicate = fromjson("{'a.ball': 4}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); unique_ptr<MatchExpression> expr = std::move(status.getValue()); @@ -800,8 +788,7 @@ TEST(IsIndependent, BallIsIndependentOfBalloon) { TEST(SplitMatchExpression, AndWithSplittableChildrenIsSplittable) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 1}]}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -822,8 +809,7 @@ TEST(SplitMatchExpression, AndWithSplittableChildrenIsSplittable) { TEST(SplitMatchExpression, NorWithIndependentChildrenIsSplittable) { BSONObj matchPredicate = fromjson("{$nor: [{a: 1}, {b: 1}]}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -844,8 +830,7 @@ TEST(SplitMatchExpression, NorWithIndependentChildrenIsSplittable) { TEST(SplitMatchExpression, NotWithIndependentChildIsSplittable) { BSONObj matchPredicate = fromjson("{x: {$not: {$gt: 4}}}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -862,8 +847,7 @@ TEST(SplitMatchExpression, NotWithIndependentChildIsSplittable) { TEST(SplitMatchExpression, OrWithOnlyIndependentChildrenIsNotSplittable) { BSONObj matchPredicate = fromjson("{$or: [{a: 1}, {b: 1}]}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -883,8 +867,7 @@ TEST(SplitMatchExpression, ComplexMatchExpressionSplitsCorrectly) { "{$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, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -909,8 +892,7 @@ 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, ExtensionsCallbackNoop(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(status.getStatus()); std::pair<unique_ptr<MatchExpression>, unique_ptr<MatchExpression>> splitExpr = @@ -931,7 +913,7 @@ TEST(SplitMatchExpression, ShouldNotExtractPrefixOfDottedPathAsIndependent) { TEST(SplitMatchExpression, ShouldMoveIndependentLeafPredicateAcrossRename) { BSONObj matchPredicate = fromjson("{a: 1}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "b"}}; @@ -949,7 +931,7 @@ TEST(SplitMatchExpression, ShouldMoveIndependentLeafPredicateAcrossRename) { TEST(SplitMatchExpression, ShouldMoveIndependentAndPredicateAcrossRename) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 2}]}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -967,7 +949,7 @@ TEST(SplitMatchExpression, ShouldMoveIndependentAndPredicateAcrossRename) { TEST(SplitMatchExpression, ShouldSplitPartiallyDependentAndPredicateAcrossRename) { BSONObj matchPredicate = fromjson("{$and: [{a: 1}, {b: 2}]}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -988,7 +970,7 @@ 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, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"b", "d"}, {"c", "e"}}; @@ -1010,7 +992,7 @@ 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, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"d.e.f", "x"}, {"e.f.g", "y"}}; @@ -1031,7 +1013,7 @@ TEST(SplitMatchExpression, TEST(SplitMatchExpression, ShouldNotMoveElemMatchObjectAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$elemMatch: {b: 3}}}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1049,7 +1031,7 @@ TEST(SplitMatchExpression, ShouldNotMoveElemMatchObjectAcrossRename) { TEST(SplitMatchExpression, ShouldNotMoveElemMatchValueAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$elemMatch: {$eq: 3}}}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1067,7 +1049,7 @@ TEST(SplitMatchExpression, ShouldNotMoveElemMatchValueAcrossRename) { TEST(SplitMatchExpression, ShouldMoveTypeAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$type: 16}}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1085,7 +1067,7 @@ TEST(SplitMatchExpression, ShouldMoveTypeAcrossRename) { TEST(SplitMatchExpression, ShouldNotMoveSizeAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$size: 3}}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1103,7 +1085,7 @@ TEST(SplitMatchExpression, ShouldNotMoveSizeAcrossRename) { TEST(SplitMatchExpression, ShouldNotMoveMinItemsAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaMinItems: 3}}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1121,7 +1103,7 @@ TEST(SplitMatchExpression, ShouldNotMoveMinItemsAcrossRename) { TEST(SplitMatchExpression, ShouldNotMoveMaxItemsAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaMaxItems: 3}}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1139,7 +1121,7 @@ TEST(SplitMatchExpression, ShouldNotMoveMaxItemsAcrossRename) { TEST(SplitMatchExpression, ShouldMoveMinLengthAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaMinLength: 3}}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1157,7 +1139,7 @@ TEST(SplitMatchExpression, ShouldMoveMinLengthAcrossRename) { TEST(SplitMatchExpression, ShouldMoveMaxLengthAcrossRename) { BSONObj matchPredicate = fromjson("{a: {$_internalSchemaMaxLength: 3}}"); const CollatorInterface* collator = nullptr; - auto matcher = MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto matcher = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(matcher.getStatus()); StringMap<std::string> renames{{"a", "c"}}; @@ -1175,8 +1157,7 @@ TEST(SplitMatchExpression, ShouldMoveMaxLengthAcrossRename) { TEST(MapOverMatchExpression, DoesMapOverLogicalNodes) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); const CollatorInterface* collator = nullptr; - auto swMatchExpression = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(swMatchExpression.getStatus()); bool hasLogicalNode = false; @@ -1194,8 +1175,7 @@ TEST(MapOverMatchExpression, DoesMapOverLogicalNodes) { TEST(MapOverMatchExpression, DoesMapOverLeafNodes) { BSONObj matchPredicate = fromjson("{a: {$not: {$eq: 1}}}"); const CollatorInterface* collator = nullptr; - auto swMatchExpression = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(swMatchExpression.getStatus()); bool hasLeafNode = false; @@ -1213,8 +1193,7 @@ TEST(MapOverMatchExpression, DoesMapOverLeafNodes) { TEST(MapOverMatchExpression, DoesPassPath) { BSONObj matchPredicate = fromjson("{a: {$elemMatch: {b: 1}}}"); const CollatorInterface* collator = nullptr; - auto swMatchExpression = - MatchExpressionParser::parse(matchPredicate, ExtensionsCallbackNoop(), collator); + auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(swMatchExpression.getStatus()); std::vector<std::string> paths; @@ -1232,8 +1211,7 @@ 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, ExtensionsCallbackNoop(), collator); + auto swMatchExpression = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(swMatchExpression.getStatus()); size_t nodeCount = 0; diff --git a/src/mongo/db/matcher/expression_geo_test.cpp b/src/mongo/db/matcher/expression_geo_test.cpp index 52ed8ac77e1..de7bd773c8a 100644 --- a/src/mongo/db/matcher/expression_geo_test.cpp +++ b/src/mongo/db/matcher/expression_geo_test.cpp @@ -36,7 +36,6 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_geo.h" -#include "mongo/db/matcher/matcher.h" #include "mongo/stdx/memory.h" namespace mongo { diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index 051e6a6884c..c49382699db 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -102,7 +102,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseComparison( ComparisonMatchExpression* cmp, const BSONElement& e, const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx) { + const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures) { std::unique_ptr<ComparisonMatchExpression> temp(cmp); // Non-equality comparison match expressions cannot have @@ -114,8 +115,11 @@ StatusWithMatchExpression MatchExpressionParser::_parseComparison( } if (_isAggExpression(e, expCtx)) { - auto expr = _parseAggExpression(e, expCtx); - auto s = temp->init(name, expr); + auto expr = _parseAggExpression(e, expCtx, allowedFeatures); + if (!expr.isOK()) { + return expr.getStatus(); + } + auto s = temp->init(name, expr.getValue()); if (!s.isOK()) { return s; } @@ -138,12 +142,14 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( 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); + return _parseComparison( + name, new EqualityMatchExpression(), e, collator, expCtx, allowedFeatures); if (mongoutils::str::equals("$not", e.fieldName())) { - return _parseNot(name, e, collator, expCtx, topLevel); + return _parseNot(name, e, collator, expCtx, allowedFeatures, topLevel); } auto parseExpMatchType = MatchExpressionParser::parsePathAcceptingKeyword(e); @@ -159,21 +165,25 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( switch (*parseExpMatchType) { case PathAcceptingKeyword::LESS_THAN: - return _parseComparison(name, new LTMatchExpression(), e, collator, expCtx); + return _parseComparison( + name, new LTMatchExpression(), e, collator, expCtx, allowedFeatures); case PathAcceptingKeyword::LESS_THAN_OR_EQUAL: - return _parseComparison(name, new LTEMatchExpression(), e, collator, expCtx); + return _parseComparison( + name, new LTEMatchExpression(), e, collator, expCtx, allowedFeatures); case PathAcceptingKeyword::GREATER_THAN: - return _parseComparison(name, new GTMatchExpression(), e, collator, expCtx); + return _parseComparison( + name, new GTMatchExpression(), e, collator, expCtx, allowedFeatures); case PathAcceptingKeyword::GREATER_THAN_OR_EQUAL: - return _parseComparison(name, new GTEMatchExpression(), e, collator, expCtx); + return _parseComparison( + name, new GTEMatchExpression(), e, collator, 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); + StatusWithMatchExpression s = _parseComparison( + name, new EqualityMatchExpression(), e, collator, expCtx, allowedFeatures); if (!s.isOK()) return s; std::unique_ptr<NotMatchExpression> n = stdx::make_unique<NotMatchExpression>(); @@ -183,7 +193,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( return {std::move(n)}; } case PathAcceptingKeyword::EQUALITY: - return _parseComparison(name, new EqualityMatchExpression(), e, collator, expCtx); + return _parseComparison( + name, new EqualityMatchExpression(), e, collator, expCtx, allowedFeatures); case PathAcceptingKeyword::IN_EXPR: { if (e.type() != Array) @@ -291,14 +302,14 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( } case PathAcceptingKeyword::ELEM_MATCH: - return _parseElemMatch(name, e, collator, expCtx, topLevel); + return _parseElemMatch(name, e, collator, expCtx, allowedFeatures, topLevel); case PathAcceptingKeyword::ALL: - return _parseAll(name, e, collator, expCtx, topLevel); + return _parseAll(name, e, collator, expCtx, allowedFeatures, topLevel); case PathAcceptingKeyword::WITHIN: case PathAcceptingKeyword::GEO_INTERSECTS: - return _parseGeo(name, *parseExpMatchType, context); + return _parseGeo(name, *parseExpMatchType, context, allowedFeatures); case PathAcceptingKeyword::GEO_NEAR: return {Status(ErrorCodes::BadValue, @@ -341,7 +352,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( str::stream() << "$_internalSchemaObjectMatch must be an object"); } - auto parsedSubObjExpr = _parse(e.Obj(), collator, expCtx, topLevel); + auto parsedSubObjExpr = _parse(e.Obj(), collator, expCtx, allowedFeatures, topLevel); if (!parsedSubObjExpr.isOK()) { return parsedSubObjExpr; } @@ -427,7 +438,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( << "must be an object"); } StatusWithMatchExpression query = - _parse(second.embeddedObject(), collator, expCtx, topLevel); + _parse(second.embeddedObject(), collator, expCtx, allowedFeatures, topLevel); if (!query.isOK()) { return query.getStatus(); } @@ -452,6 +463,7 @@ StatusWithMatchExpression MatchExpressionParser::_parse( const BSONObj& obj, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel) { std::unique_ptr<AndMatchExpression> root = stdx::make_unique<AndMatchExpression>(); @@ -466,7 +478,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, childIsTopLevel); + Status s = _parseTreeList( + e.Obj(), temp.get(), collator, expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; root->add(temp.release()); @@ -474,7 +487,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, childIsTopLevel); + Status s = _parseTreeList( + e.Obj(), temp.get(), collator, expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; root->add(temp.release()); @@ -482,7 +496,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, childIsTopLevel); + Status s = _parseTreeList( + e.Obj(), temp.get(), collator, expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; root->add(temp.release()); @@ -494,11 +509,19 @@ StatusWithMatchExpression MatchExpressionParser::_parse( // Don't do anything with the expression; CanonicalQuery::init() will look through // the BSONObj again for a $atomic/$isolated. } else if (mongoutils::str::equals("where", rest)) { + if ((allowedFeatures & AllowedFeatures::kJavascript) == 0u) { + return {Status(ErrorCodes::BadValue, "$where is not allowed in this context")}; + } + StatusWithMatchExpression s = _extensionsCallback->parseWhere(e); if (!s.isOK()) return s; root->add(s.getValue().release()); } else if (mongoutils::str::equals("text", rest)) { + if ((allowedFeatures & AllowedFeatures::kText) == 0u) { + return {Status(ErrorCodes::BadValue, "$text is not allowed in this context")}; + } + StatusWithMatchExpression s = _extensionsCallback->parseText(e); if (!s.isOK()) { return s; @@ -526,7 +549,11 @@ StatusWithMatchExpression MatchExpressionParser::_parse( } else if (mongoutils::str::equals("_internalSchemaCond", rest)) { auto condExpr = _parseInternalSchemaFixedArityArgument<InternalSchemaCondMatchExpression>( - InternalSchemaCondMatchExpression::kName, e, collator, expCtx); + InternalSchemaCondMatchExpression::kName, + e, + collator, + expCtx, + allowedFeatures); if (!condExpr.isOK()) { return condExpr.getStatus(); } @@ -537,8 +564,8 @@ StatusWithMatchExpression MatchExpressionParser::_parse( return { Status(ErrorCodes::TypeMismatch, "$_internalSchemaXor must be an array")}; auto xorExpr = stdx::make_unique<InternalSchemaXorMatchExpression>(); - Status s = - _parseTreeList(e.Obj(), xorExpr.get(), collator, expCtx, childIsTopLevel); + Status s = _parseTreeList( + e.Obj(), xorExpr.get(), collator, expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s; root->add(xorExpr.release()); @@ -587,8 +614,13 @@ StatusWithMatchExpression MatchExpressionParser::_parse( } if (_isExpressionDocument(e, false, expCtx)) { - Status s = - _parseSub(e.fieldName(), e.Obj(), root.get(), collator, expCtx, childIsTopLevel); + Status s = _parseSub(e.fieldName(), + e.Obj(), + root.get(), + collator, + expCtx, + allowedFeatures, + childIsTopLevel); if (!s.isOK()) return s; continue; @@ -602,8 +634,8 @@ StatusWithMatchExpression MatchExpressionParser::_parse( continue; } - auto eq = - _parseComparison(e.fieldName(), new EqualityMatchExpression(), e, collator, expCtx); + auto eq = _parseComparison( + e.fieldName(), new EqualityMatchExpression(), e, collator, expCtx, allowedFeatures); if (!eq.isOK()) return eq; @@ -624,6 +656,7 @@ Status MatchExpressionParser::_parseSub(const char* name, AndMatchExpression* root, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel) { // The one exception to {field : {fully contained argument} } is, of course, geo. Example: // sub == { field : {$near[Sphere]: [0,0], $maxDistance: 1000, $minDistance: 10 } } @@ -638,17 +671,10 @@ Status MatchExpressionParser::_parseSub(const char* name, if (geoIt.more()) { BSONElement firstElt = geoIt.next(); if (firstElt.isABSONObj()) { - const char* fieldName = firstElt.fieldName(); - // TODO: Having these $fields here isn't ideal but we don't want to pull in anything - // from db/geo at this point, since it may not actually be linked in... - if (mongoutils::str::equals(fieldName, "$near") || - mongoutils::str::equals(fieldName, "$nearSphere") || - mongoutils::str::equals(fieldName, "$geoNear")) { + if (MatchExpressionParser::parsePathAcceptingKeyword(firstElt) == + PathAcceptingKeyword::GEO_NEAR) { StatusWithMatchExpression s = - _parseGeo(name, - *MatchExpressionParser::parsePathAcceptingKeyword( - firstElt, PathAcceptingKeyword::EQUALITY), - sub); + _parseGeo(name, PathAcceptingKeyword::GEO_NEAR, sub, allowedFeatures); if (s.isOK()) { root->add(s.getValue().release()); } @@ -664,8 +690,8 @@ Status MatchExpressionParser::_parseSub(const char* name, BSONElement deep = j.next(); const bool childIsTopLevel = false; - StatusWithMatchExpression s = - _parseSubField(sub, root, name, deep, collator, expCtx, childIsTopLevel); + StatusWithMatchExpression s = _parseSubField( + sub, root, name, deep, collator, expCtx, allowedFeatures, childIsTopLevel); if (!s.isOK()) return s.getStatus(); @@ -885,6 +911,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( const BSONElement& e, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel) { if (e.type() != Object) return {Status(ErrorCodes::BadValue, "$elemMatch needs an Object")}; @@ -919,7 +946,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( // value case AndMatchExpression theAnd; - Status s = _parseSub("", obj, &theAnd, collator, expCtx, topLevel); + Status s = _parseSub("", obj, &theAnd, collator, expCtx, allowedFeatures, topLevel); if (!s.isOK()) return s; @@ -943,7 +970,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( // object case - StatusWithMatchExpression subRaw = _parse(obj, collator, expCtx, topLevel); + StatusWithMatchExpression subRaw = _parse(obj, collator, expCtx, allowedFeatures, topLevel); if (!subRaw.isOK()) return subRaw; std::unique_ptr<MatchExpression> sub = std::move(subRaw.getValue()); @@ -968,6 +995,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseAll( const BSONElement& e, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel) { if (e.type() != Array) return {Status(ErrorCodes::BadValue, "$all needs an array")}; @@ -997,8 +1025,12 @@ StatusWithMatchExpression MatchExpressionParser::_parseAll( } const bool childIsTopLevel = false; - StatusWithMatchExpression inner = _parseElemMatch( - name, hopefullyElemMatchObj.firstElement(), collator, expCtx, childIsTopLevel); + StatusWithMatchExpression inner = _parseElemMatch(name, + hopefullyElemMatchObj.firstElement(), + collator, + expCtx, + allowedFeatures, + childIsTopLevel); if (!inner.isOK()) return inner; myAnd->add(inner.getValue().release()); @@ -1249,7 +1281,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaFixedArityA StringData name, const BSONElement& input, const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx) { + const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures) { constexpr auto arity = T::arity(); if (input.type() != BSONType::Array) { return {ErrorCodes::FailedToParse, @@ -1278,7 +1311,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaFixedArityA } const bool isTopLevel = false; - auto subexpr = _parse(elem.embeddedObject(), collator, expCtx, isTopLevel); + auto subexpr = _parse(elem.embeddedObject(), collator, expCtx, allowedFeatures, isTopLevel); if (!subexpr.isOK()) { return subexpr.getStatus(); } @@ -1586,7 +1619,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseInternalSchemaAllowedProp StatusWithMatchExpression MatchExpressionParser::_parseGeo(const char* name, PathAcceptingKeyword type, - const BSONObj& section) { + const BSONObj& section, + AllowedFeatureSet allowedFeatures) { if (PathAcceptingKeyword::WITHIN == type || PathAcceptingKeyword::GEO_INTERSECTS == type) { std::unique_ptr<GeoExpression> gq = stdx::make_unique<GeoExpression>(name); Status parseStatus = gq->parseFrom(section); @@ -1602,6 +1636,12 @@ StatusWithMatchExpression MatchExpressionParser::_parseGeo(const char* name, return {std::move(e)}; } else { invariant(PathAcceptingKeyword::GEO_NEAR == type); + + if ((allowedFeatures & AllowedFeatures::kGeoNear) == 0u) { + return {Status(ErrorCodes::BadValue, + "$geoNear, $near, and $nearSphere are not allowed in this context")}; + } + std::unique_ptr<GeoNearExpression> nq = stdx::make_unique<GeoNearExpression>(name); Status s = nq->parseFrom(section); if (!s.isOK()) { @@ -1633,10 +1673,16 @@ bool MatchExpressionParser::_isAggExpression( return obj.firstElementFieldName() == kAggExpression; } -boost::intrusive_ptr<Expression> MatchExpressionParser::_parseAggExpression( - BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& expCtx) { +StatusWith<boost::intrusive_ptr<Expression>> MatchExpressionParser::_parseAggExpression( + BSONElement elem, + const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures) { invariant(expCtx); + if ((allowedFeatures & AllowedFeatures::kExpr) == 0u) { + return {Status(ErrorCodes::BadValue, "$expr is not allowed in this context")}; + } + auto expr = Expression::parseOperand( expCtx, elem.embeddedObject().firstElement(), expCtx->variablesParseState); return expr->optimize(); diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h index 621a35e4451..75ed1a60dd7 100644 --- a/src/mongo/db/matcher/expression_parser.h +++ b/src/mongo/db/matcher/expression_parser.h @@ -37,6 +37,7 @@ #include "mongo/db/matcher/expression_tree.h" #include "mongo/db/matcher/expression_type.h" #include "mongo/db/matcher/extensions_callback.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/pipeline/expression_context.h" #include "mongo/stdx/functional.h" @@ -84,6 +85,20 @@ enum class PathAcceptingKeyword { class MatchExpressionParser { public: /** + * Features allowed in match expression parsing. + */ + enum AllowedFeatures { + kText = 1, + kGeoNear = 1 << 1, + kJavascript = 1 << 2, + kExpr = 1 << 3, + }; + using AllowedFeatureSet = unsigned long long; + static constexpr AllowedFeatureSet kBanAllSpecialFeatures = 0; + static constexpr AllowedFeatureSet kAllowAllSpecialFeatures = + std::numeric_limits<unsigned long long>::max(); + + /** * Constant double representation of 2^63. */ static const double kLongLongMaxPlusOneAsDouble; @@ -104,12 +119,18 @@ public: */ static StatusWithMatchExpression parse( const BSONObj& obj, - const ExtensionsCallback& extensionsCallback, const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr) { + const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr, + const ExtensionsCallback& extensionsCallback = ExtensionsCallbackNoop(), + AllowedFeatureSet allowedFeatures = kBanAllSpecialFeatures) { + // A non-null ExpressionContext is required for parsing $expr. + if (!expCtx) { + invariant((allowedFeatures & AllowedFeatures::kExpr) == 0u); + } + const bool topLevelCall = true; return MatchExpressionParser(&extensionsCallback) - ._parse(obj, collator, expCtx, topLevelCall); + ._parse(obj, collator, expCtx, allowedFeatures, topLevelCall); } /** @@ -171,6 +192,7 @@ private: StatusWithMatchExpression _parse(const BSONObj& obj, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel); /** @@ -183,6 +205,7 @@ private: AndMatchExpression* root, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel); /** @@ -196,6 +219,7 @@ private: const BSONElement& e, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel); StatusWithMatchExpression _parseComparison( @@ -203,7 +227,8 @@ private: ComparisonMatchExpression* cmp, const BSONElement& e, const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx); + const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures); StatusWithMatchExpression _parseMOD(const char* name, const BSONElement& e, @@ -231,7 +256,8 @@ private: StatusWithMatchExpression _parseGeo(const char* name, PathAcceptingKeyword type, - const BSONObj& section); + const BSONObj& section, + AllowedFeatureSet allowedFeatures); // arrays @@ -239,12 +265,14 @@ private: 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); // tree @@ -253,12 +281,14 @@ private: 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); /** @@ -284,7 +314,8 @@ private: StringData name, const BSONElement& elem, const CollatorInterface* collator, - const boost::intrusive_ptr<ExpressionContext>& expCtx); + const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures); /** * Parses the given BSONElement into a single integer argument and creates a MatchExpression @@ -310,8 +341,10 @@ private: bool _isAggExpression(BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& expCtx); - boost::intrusive_ptr<Expression> _parseAggExpression( - BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& expCtx); + StatusWith<boost::intrusive_ptr<Expression>> _parseAggExpression( + BSONElement elem, + const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures); StatusWithMatchExpression _parseInternalSchemaAllowedProperties( const BSONElement& elem, const CollatorInterface* collator); diff --git a/src/mongo/db/matcher/expression_parser_array_test.cpp b/src/mongo/db/matcher/expression_parser_array_test.cpp index 2a9d0467ce3..23cef6b1180 100644 --- a/src/mongo/db/matcher/expression_parser_array_test.cpp +++ b/src/mongo/db/matcher/expression_parser_array_test.cpp @@ -38,7 +38,6 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_array.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface_mock.h" namespace mongo { @@ -48,8 +47,7 @@ using std::string; TEST(MatchExpressionParserArrayTest, Size1) { BSONObj query = BSON("x" << BSON("$size" << 2)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -61,8 +59,7 @@ TEST(MatchExpressionParserArrayTest, Size1) { TEST(MatchExpressionParserArrayTest, SizeAsLong) { BSONObj query = BSON("x" << BSON("$size" << 2LL)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -74,16 +71,14 @@ TEST(MatchExpressionParserArrayTest, SizeAsLong) { TEST(MatchExpressionParserArrayTest, SizeAsNegativeLong) { BSONObj query = BSON("x" << BSON("$size" << -2LL)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } @@ -91,16 +86,14 @@ TEST(MatchExpressionParserArrayTest, SizeAsString) { BSONObj query = BSON("x" << BSON("$size" << "a")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithIntegralDouble) { BSONObj query = BSON("x" << BSON("$size" << 2.0)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -112,32 +105,28 @@ TEST(MatchExpressionParserArrayTest, SizeWithIntegralDouble) { TEST(MatchExpressionParserArrayTest, SizeWithNegativeIntegralDouble) { BSONObj query = BSON("x" << BSON("$size" << -2.0)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithDouble) { BSONObj query = BSON("x" << BSON("$size" << 2.5)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeWithNegative) { BSONObj query = BSON("x" << BSON("$size" << -2)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserArrayTest, SizeBad) { BSONObj query = BSON("x" << BSON("$size" << BSONNULL)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } @@ -146,8 +135,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -160,8 +148,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -173,8 +160,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -187,8 +173,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -200,8 +185,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchOr) { TEST(MatchExpressionParserArrayTest, ElemMatchVal1) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$gt" << 5))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -228,8 +212,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef1) { BSONObj query = BSON("x" << BSON("$elemMatch" << BSON("$eq" << match))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -255,8 +238,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef2) { BSONObj query = BSON("x" << BSON("$elemMatch" << match)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -283,8 +265,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef3) { BSONObj query = BSON("x" << BSON("$elemMatch" << match)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -327,8 +308,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef4) { BSONObj query = BSON("x" << BSON("$elemMatch" << matchOutOfOrder)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -358,8 +338,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef5) { BSONObj query = BSON("x" << BSON("$elemMatch" << matchOutOfOrder)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -399,8 +378,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef6) { BSONObj query = BSON("x" << BSON("$elemMatch" << matchMissingID)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -438,8 +416,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef7) { BSONObj query = BSON("x" << BSON("$elemMatch" << matchMissingRef)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -483,8 +460,7 @@ TEST(MatchExpressionParserArrayTest, ElemMatchDBRef8) { BSONObj query = BSON("x" << BSON("$elemMatch" << matchDBOnly)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << match))); @@ -507,8 +483,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -525,8 +500,7 @@ TEST(MatchExpressionParserArrayTest, All1) { TEST(MatchExpressionParserArrayTest, AllNull) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(BSONNULL))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -541,8 +515,7 @@ TEST(MatchExpressionParserArrayTest, AllNull) { TEST(MatchExpressionParserArrayTest, AllBadArg) { BSONObj query = BSON("x" << BSON("$all" << 1)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } @@ -556,8 +529,7 @@ TEST(MatchExpressionParserArrayTest, AllBadRegexArg) { BSONObj query = BSON("x" << operand.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } @@ -571,8 +543,7 @@ TEST(MatchExpressionParserArrayTest, AllRegex1) { BSONObj query = BSON("a" << all.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -599,8 +570,7 @@ TEST(MatchExpressionParserArrayTest, AllRegex2) { BSONObj query = BSON("a" << all.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -618,8 +588,7 @@ TEST(MatchExpressionParserArrayTest, AllRegex2) { TEST(MatchExpressionParserArrayTest, AllNonArray) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(5))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to AND. @@ -636,8 +605,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to an AND with a single ELEM_MATCH_OBJECT child. @@ -658,8 +626,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); // Verify that the $all got parsed to an AND with a single ELEM_MATCH_OBJECT child. @@ -695,8 +662,7 @@ TEST(MatchExpressionParserArrayTest, AllElemMatch2) { TEST(MatchExpressionParserArrayTest, AllElemMatch3) { BSONObj query = fromjson("{x: {$all: [{$elemMatch: {y: 1, z: 1}}]}}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); std::unique_ptr<MatchExpression> expr = std::move(result.getValue()); @@ -732,12 +698,11 @@ TEST(MatchExpressionParserArrayTest, AllElemMatchBad) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(BSON("$elemMatch" << internal) << 5))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); query = BSON("x" << BSON("$all" << BSON_ARRAY(5 << BSON("$elemMatch" << internal)))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } @@ -746,26 +711,22 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result1 = MatchExpressionParser::parse(bad1, collator); ASSERT_FALSE(result1.isOK()); // equality first, $elemMatch second BSONObj bad2 = fromjson("{x: {$all: [3, {$elemMatch: {y: 1}}]}}"); - StatusWithMatchExpression result2 = - MatchExpressionParser::parse(bad2, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result2 = MatchExpressionParser::parse(bad2, collator); ASSERT_FALSE(result1.isOK()); // $elemMatch first, object second BSONObj bad3 = fromjson("{x: {$all: [{$elemMatch: {y: 1}}, {z: 1}]}}"); - StatusWithMatchExpression result3 = - MatchExpressionParser::parse(bad3, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result3 = MatchExpressionParser::parse(bad3, collator); ASSERT_FALSE(result3.isOK()); // object first, $elemMatch second BSONObj bad4 = fromjson("{x: {$all: [{z: 1}, {$elemMatch: {y: 1}}]}}"); - StatusWithMatchExpression result4 = - MatchExpressionParser::parse(bad4, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result4 = MatchExpressionParser::parse(bad4, collator); ASSERT_FALSE(result4.isOK()); } @@ -773,8 +734,7 @@ TEST(MatchExpressionParserArrayTest, AllElemMatchBadMixed) { TEST(MatchExpressionParserArrayTest, AllEmptyString) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(""))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -799,8 +759,7 @@ TEST(MatchExpressionParserArrayTest, AllISODate) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY(match))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << notMatch))); @@ -816,8 +775,7 @@ TEST(MatchExpressionParserArrayTest, AllISODate) { TEST(MatchExpressionParserArrayTest, AllDottedEmptyString) { BSONObj query = BSON("x.1" << BSON("$all" << BSON_ARRAY(""))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -844,8 +802,7 @@ TEST(MatchExpressionParserArrayTest, AllDottedISODate) { BSONObj query = BSON("x.1" << BSON("$all" << BSON_ARRAY(match))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << notMatch))); @@ -862,8 +819,7 @@ TEST(MatchExpressionParserArrayTest, AllDottedISODate) { TEST(MatchExpressionParserArrayTest, AllStringNullCollation) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY("string"))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT_EQUALS(MatchExpression::AND, result.getValue()->matchType()); ASSERT_EQUALS(1U, result.getValue()->numChildren()); @@ -876,8 +832,7 @@ TEST(MatchExpressionParserArrayTest, AllStringNullCollation) { TEST(MatchExpressionParserArrayTest, AllStringCollation) { BSONObj query = BSON("x" << BSON("$all" << BSON_ARRAY("string"))); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); 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 c7e82af29ab..b8a17a3ae2f 100644 --- a/src/mongo/db/matcher/expression_parser_geo_test.cpp +++ b/src/mongo/db/matcher/expression_parser_geo_test.cpp @@ -34,7 +34,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_geo.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/pipeline/aggregation_context_fixture.h" namespace mongo { @@ -43,8 +43,13 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(fromjson("{a: [3,4]}"))); @@ -63,7 +68,11 @@ TEST(MatchExpressionParserGeo, RejectsExprAsGeometry) { const CollatorInterface* collator = nullptr; StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_NOT_OK(result.getStatus()); } @@ -73,8 +82,13 @@ TEST(MatchExpressionParserGeoNear, ParseNear) { "$geometry:{type:\"Point\", coordinates:[0,0]}}}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -91,10 +105,14 @@ TEST(MatchExpressionParserGeoNear, ParseNearExtraField) { "$geometry:{type:\"Point\", coordinates:[0,0]}}, foo: 1}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } // For $near, $nearSphere, and $geoNear syntax of: @@ -107,8 +125,13 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -123,69 +146,110 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNear) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $near: [0,0]}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$minDistance: 100, $near: [0,0]}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$near: [0,0], $maxDistance: {}}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } { BSONObj query = fromjson("{loc: {$near: [0,0], $minDistance: {}}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } { BSONObj query = fromjson("{loc: {$near: [0,0], $eq: 40}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } { BSONObj query = fromjson("{loc: {$eq: 40, $near: [0,0]}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson( "{loc: {$near: [0,0], $geoWithin: {$geometry: {type: \"Polygon\", coordinates: []}}}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } { BSONObj query = fromjson("{loc: {$near: {$foo: 1}}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$minDistance: 10}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } } @@ -194,8 +258,13 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -210,40 +279,62 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidGeoNear) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $geoNear: [0,0]}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$minDistance: 100, $geoNear: [0,0]}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $eq: 1}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $maxDistance: {}}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } { BSONObj query = fromjson("{loc: {$geoNear: [0,0], $minDistance: {}}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } } @@ -251,8 +342,13 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_TRUE(result.isOK()); MatchExpression* exp = result.getValue().get(); @@ -267,40 +363,62 @@ TEST(MatchExpressionParserGeoNear, ParseInvalidNearSphere) { { BSONObj query = fromjson("{loc: {$maxDistance: 100, $nearSphere: [0,0]}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$minDistance: 100, $nearSphere: [0,0]}}"); const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_FALSE(result.isOK()); } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $maxDistance: {}}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $minDistance: {}}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } { BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $eq: 1}}"); const CollatorInterface* collator = nullptr; - ASSERT_THROWS( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator) - .status_with_transitional_ignore(), - AssertionException); + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_THROWS(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures) + .status_with_transitional_ignore(), + AssertionException); } } diff --git a/src/mongo/db/matcher/expression_parser_leaf_test.cpp b/src/mongo/db/matcher/expression_parser_leaf_test.cpp index 7181c8dea59..17c6efc8b4f 100644 --- a/src/mongo/db/matcher/expression_parser_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_parser_leaf_test.cpp @@ -33,10 +33,11 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.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" #include "mongo/unittest/unittest.h" namespace mongo { @@ -48,8 +49,7 @@ TEST(MatchExpressionParserLeafTest, NullCollation) { BSONObj query = BSON("x" << "string"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -61,8 +61,7 @@ TEST(MatchExpressionParserLeafTest, Collation) { BSONObj query = BSON("x" << "string"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -79,8 +78,11 @@ TEST(MatchExpressionParserLeafTest, ConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); @@ -101,21 +103,30 @@ TEST(MatchExpressionParserLeafTest, ConstantExprFailsWithMissingVariable) { BSONObj query = BSON("x" << BSON("$expr" << "$$userVar")); - ASSERT_THROWS_CODE(auto sw = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx), - AssertionException, - 17276); + ASSERT_THROWS_CODE( + auto sw = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr), + AssertionException, + 17276); } -TEST(MatchExpressionParserLeafTest, ConstantExprFailsWithMissingExpressionContext) { +DEATH_TEST(MatchExpressionParserLeafTest, + ConstantExprFailsWithMissingExpressionContext, + "Invariant failure (allowedFeatures & AllowedFeatures::kExpr) == 0u") { boost::intrusive_ptr<ExpressionContextForTest> nullExpCtx; const CollatorInterface* collator = nullptr; BSONObj query = BSON("x" << BSON("$expr" << "$$userVar")); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, nullExpCtx); + auto result = MatchExpressionParser::parse(query, + collator, + nullExpCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_NOT_OK(result.getStatus()); } @@ -123,8 +134,7 @@ TEST(MatchExpressionParserLeafTest, ConstantExprFailsWithMissingExpressionContex TEST(MatchExpressionParserLeafTest, SimpleEQ2) { BSONObj query = BSON("x" << BSON("$eq" << 2)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -135,8 +145,7 @@ TEST(MatchExpressionParserLeafTest, SimpleEQ2) { TEST(MatchExpressionParserLeafTest, SimpleEQUndefined) { BSONObj query = BSON("x" << BSON("$eq" << BSONUndefined)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } @@ -144,8 +153,7 @@ TEST(MatchExpressionParserLeafTest, EQNullCollation) { BSONObj query = BSON("x" << BSON("$eq" << "string")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -157,8 +165,7 @@ TEST(MatchExpressionParserLeafTest, EQCollation) { BSONObj query = BSON("x" << BSON("$eq" << "string")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -175,8 +182,11 @@ TEST(MatchExpressionParserLeafTest, EQConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); @@ -193,8 +203,7 @@ TEST(MatchExpressionParserLeafTest, EQConstantExpr) { TEST(MatchExpressionParserLeafTest, SimpleGT1) { BSONObj query = BSON("x" << BSON("$gt" << 2)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 2))); @@ -205,8 +214,7 @@ TEST(MatchExpressionParserLeafTest, GTNullCollation) { BSONObj query = BSON("x" << BSON("$gt" << "abc")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GT, result.getValue()->matchType()); GTMatchExpression* match = static_cast<GTMatchExpression*>(result.getValue().get()); @@ -218,8 +226,7 @@ TEST(MatchExpressionParserLeafTest, GTCollation) { BSONObj query = BSON("x" << BSON("$gt" << "abc")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GT, result.getValue()->matchType()); GTMatchExpression* match = static_cast<GTMatchExpression*>(result.getValue().get()); @@ -236,8 +243,11 @@ TEST(MatchExpressionParserLeafTest, GTConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GT, result.getValue()->matchType()); @@ -254,8 +264,7 @@ TEST(MatchExpressionParserLeafTest, GTConstantExpr) { TEST(MatchExpressionParserLeafTest, SimpleLT1) { BSONObj query = BSON("x" << BSON("$lt" << 2)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -267,8 +276,7 @@ TEST(MatchExpressionParserLeafTest, LTNullCollation) { BSONObj query = BSON("x" << BSON("$lt" << "abc")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LT, result.getValue()->matchType()); LTMatchExpression* match = static_cast<LTMatchExpression*>(result.getValue().get()); @@ -280,8 +288,7 @@ TEST(MatchExpressionParserLeafTest, LTCollation) { BSONObj query = BSON("x" << BSON("$lt" << "abc")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LT, result.getValue()->matchType()); LTMatchExpression* match = static_cast<LTMatchExpression*>(result.getValue().get()); @@ -298,8 +305,11 @@ TEST(MatchExpressionParserLeafTest, LTConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LT, result.getValue()->matchType()); @@ -316,8 +326,7 @@ TEST(MatchExpressionParserLeafTest, LTConstantExpr) { TEST(MatchExpressionParserLeafTest, SimpleGTE1) { BSONObj query = BSON("x" << BSON("$gte" << 2)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -329,8 +338,7 @@ TEST(MatchExpressionParserLeafTest, GTENullCollation) { BSONObj query = BSON("x" << BSON("$gte" << "abc")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GTE, result.getValue()->matchType()); GTEMatchExpression* match = static_cast<GTEMatchExpression*>(result.getValue().get()); @@ -342,8 +350,7 @@ TEST(MatchExpressionParserLeafTest, GTECollation) { BSONObj query = BSON("x" << BSON("$gte" << "abc")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GTE, result.getValue()->matchType()); GTEMatchExpression* match = static_cast<GTEMatchExpression*>(result.getValue().get()); @@ -360,8 +367,11 @@ TEST(MatchExpressionParserLeafTest, GTEConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::GTE, result.getValue()->matchType()); @@ -380,8 +390,7 @@ TEST(MatchExpressionParserLeafTest, GTEConstantExpr) { TEST(MatchExpressionParserLeafTest, SimpleLTE1) { BSONObj query = BSON("x" << BSON("$lte" << 2)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -393,8 +402,7 @@ TEST(MatchExpressionParserLeafTest, LTENullCollation) { BSONObj query = BSON("x" << BSON("$lte" << "abc")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LTE, result.getValue()->matchType()); LTEMatchExpression* match = static_cast<LTEMatchExpression*>(result.getValue().get()); @@ -406,8 +414,7 @@ TEST(MatchExpressionParserLeafTest, LTECollation) { BSONObj query = BSON("x" << BSON("$lte" << "abc")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LTE, result.getValue()->matchType()); LTEMatchExpression* match = static_cast<LTEMatchExpression*>(result.getValue().get()); @@ -424,8 +431,11 @@ TEST(MatchExpressionParserLeafTest, LTEConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::LTE, result.getValue()->matchType()); @@ -444,8 +454,7 @@ TEST(MatchExpressionParserLeafTest, LTEConstantExpr) { TEST(MatchExpressionParserLeafTest, SimpleNE1) { BSONObj query = BSON("x" << BSON("$ne" << 2)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -457,8 +466,7 @@ TEST(MatchExpressionParserLeafTest, NENullCollation) { BSONObj query = BSON("x" << BSON("$ne" << "string")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); MatchExpression* child = result.getValue()->getChild(0); @@ -472,8 +480,7 @@ TEST(MatchExpressionParserLeafTest, NECollation) { BSONObj query = BSON("x" << BSON("$ne" << "string")); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); MatchExpression* child = result.getValue()->getChild(0); @@ -492,8 +499,11 @@ TEST(MatchExpressionParserLeafTest, NEConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); @@ -510,36 +520,34 @@ TEST(MatchExpressionParserLeafTest, NEConstantExpr) { TEST(MatchExpressionParserLeafTest, SimpleModBad1) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << BSON_ARRAY(3))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2 << 4))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << BSON_ARRAY("q" << 2))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << 3)); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$mod" << BSON("a" << 1 << "b" << 2))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5))); @@ -550,8 +558,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -571,8 +578,11 @@ TEST(MatchExpressionParserLeafTest, ModConstantExprFails) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(BSON_ARRAY(10 << 2))); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_NOT_OK(result.getStatus()); ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); } @@ -581,8 +591,7 @@ TEST(MatchExpressionParserLeafTest, IdCollation) { BSONObj query = BSON("$id" << "string"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -593,8 +602,7 @@ TEST(MatchExpressionParserLeafTest, IdNullCollation) { BSONObj query = BSON("$id" << "string"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -611,8 +619,11 @@ TEST(MatchExpressionParserLeafTest, IdConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); @@ -622,8 +633,7 @@ TEST(MatchExpressionParserLeafTest, RefCollation) { BSONObj query = BSON("$ref" << "coll"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -640,8 +650,11 @@ TEST(MatchExpressionParserLeafTest, RefConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(std::string("colName"))); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); @@ -651,8 +664,7 @@ TEST(MatchExpressionParserLeafTest, DbCollation) { BSONObj query = BSON("$db" << "db"); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); EqualityMatchExpression* match = static_cast<EqualityMatchExpression*>(result.getValue().get()); @@ -669,8 +681,11 @@ TEST(MatchExpressionParserLeafTest, DbConstantExpr) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(std::string("dbName"))); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), collator, expCtx); + auto result = MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); @@ -679,8 +694,7 @@ TEST(MatchExpressionParserLeafTest, DbConstantExpr) { TEST(MatchExpressionParserLeafTest, SimpleIN1) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(2 << 3))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -691,8 +705,7 @@ TEST(MatchExpressionParserLeafTest, SimpleIN1) { TEST(MatchExpressionParserLeafTest, INNullCollation) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY("string"))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::MATCH_IN, result.getValue()->matchType()); InMatchExpression* match = static_cast<InMatchExpression*>(result.getValue().get()); @@ -702,8 +715,7 @@ TEST(MatchExpressionParserLeafTest, INNullCollation) { TEST(MatchExpressionParserLeafTest, INCollation) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY("string"))); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::MATCH_IN, result.getValue()->matchType()); InMatchExpression* match = static_cast<InMatchExpression*>(result.getValue().get()); @@ -720,8 +732,12 @@ TEST(MatchExpressionParserLeafTest, INConstantExprFails) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(BSON_ARRAY(1 << 2))); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), &collator, expCtx); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, + &collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_NOT_OK(result.getStatus()); ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); @@ -731,8 +747,11 @@ TEST(MatchExpressionParserLeafTest, INConstantExprFails) { varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), &collator, expCtx); + result = MatchExpressionParser::parse(query, + &collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_NOT_OK(result.getStatus()); ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); } @@ -746,8 +765,7 @@ TEST(MatchExpressionParserLeafTest, INSingleDBRef) { << "$db" << "db")))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); OID oidx = OID::gen(); @@ -829,8 +847,7 @@ TEST(MatchExpressionParserLeafTest, INMultipleDBRef) { << "$db" << "db")))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); OID oidx = OID::gen(); @@ -971,8 +988,7 @@ TEST(MatchExpressionParserLeafTest, INDBRefWithOptionalField1) { << "foo" << 12345)))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); OID oidx = OID::gen(); @@ -1007,23 +1023,22 @@ TEST(MatchExpressionParserLeafTest, INInvalidDBRefs) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll")))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); + result = MatchExpressionParser::parse(query, collator); // second field is not $id query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" << "coll" << "$foo" << 1)))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); 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, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); // missing $id and $ref field @@ -1031,39 +1046,35 @@ TEST(MatchExpressionParserLeafTest, INInvalidDBRefs) { << "test" << "foo" << 3)))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, INNotArray) { BSONObj query = BSON("x" << BSON("$in" << 5)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } @@ -1075,8 +1086,7 @@ TEST(MatchExpressionParserLeafTest, INRegexTooLong) { operand.appendArray("$in", inArray.obj()); BSONObj query = BSON("x" << operand.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } @@ -1084,8 +1094,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } @@ -1099,8 +1108,7 @@ TEST(MatchExpressionParserLeafTest, INRegexStuff) { BSONObj query = BSON("a" << operand.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); BSONObj matchFirst = BSON("a" @@ -1126,8 +1134,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -1138,16 +1145,14 @@ TEST(MatchExpressionParserLeafTest, SimpleNIN1) { TEST(MatchExpressionParserLeafTest, NINNotArray) { BSONObj query = BSON("x" << BSON("$nin" << 5)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); MatchExpression* child = result.getValue()->getChild(0); @@ -1159,8 +1164,7 @@ TEST(MatchExpressionParserLeafTest, NINNullCollation) { TEST(MatchExpressionParserLeafTest, NINCollation) { BSONObj query = BSON("x" << BSON("$nin" << BSON_ARRAY("string"))); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, &collator); ASSERT_OK(result.getStatus()); ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); MatchExpression* child = result.getValue()->getChild(0); @@ -1179,8 +1183,12 @@ TEST(MatchExpressionParserLeafTest, NINConstantExprFails) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(BSON_ARRAY(1 << 2))); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), &collator, expCtx); + StatusWithMatchExpression result = + MatchExpressionParser::parse(query, + &collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_NOT_OK(result.getStatus()); ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); @@ -1190,8 +1198,11 @@ TEST(MatchExpressionParserLeafTest, NINConstantExprFails) { varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(123)); - result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), &collator, expCtx); + result = MatchExpressionParser::parse(query, + &collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr); ASSERT_NOT_OK(result.getStatus()); ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); } @@ -1201,8 +1212,7 @@ TEST(MatchExpressionParserLeafTest, Regex1) { b.appendRegex("x", "abc", "i"); BSONObj query = b.obj(); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -1219,8 +1229,7 @@ TEST(MatchExpressionParserLeafTest, Regex2) { << "$options" << "i")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -1237,8 +1246,7 @@ TEST(MatchExpressionParserLeafTest, Regex3) { << "$regex" << "abc")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -1256,27 +1264,26 @@ TEST(MatchExpressionParserLeafTest, RegexBad) { << "$optionas" << "i")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); // $regex does not with numbers query = BSON("x" << BSON("$regex" << 123)); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$regex" << BSON_ARRAY("abc"))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$optionas" << "i")); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); query = BSON("x" << BSON("$options" << "i")); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } @@ -1284,8 +1291,7 @@ TEST(MatchExpressionParserLeafTest, RegexEmbeddedNULByte) { BSONObj query = BSON("x" << BSON("$regex" << "^a\\x00b")); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); const auto value = "a\0b"_sd; @@ -1305,8 +1311,7 @@ TEST(MatchExpressionParserLeafTest, RegexWithConstantExprFails) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(std::string("i"))); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); @@ -1318,7 +1323,7 @@ TEST(MatchExpressionParserLeafTest, RegexWithConstantExprFails) { varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(std::string("abc"))); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } @@ -1327,8 +1332,7 @@ TEST(MatchExpressionParserLeafTest, ExistsYes1) { b.appendBool("$exists", true); BSONObj query = BSON("x" << b.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -1342,8 +1346,7 @@ TEST(MatchExpressionParserLeafTest, ExistsNO1) { b.appendBool("$exists", false); BSONObj query = BSON("x" << b.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -1355,8 +1358,7 @@ TEST(MatchExpressionParserLeafTest, ExistsNO1) { TEST(MatchExpressionParserLeafTest, Type1) { BSONObj query = BSON("x" << BSON("$type" << String)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -1367,8 +1369,7 @@ TEST(MatchExpressionParserLeafTest, Type1) { TEST(MatchExpressionParserLeafTest, Type2) { BSONObj query = BSON("x" << BSON("$type" << (double)NumberDouble)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -1378,8 +1379,7 @@ TEST(MatchExpressionParserLeafTest, Type2) { TEST(MatchExpressionParserLeafTest, TypeDoubleOperator) { BSONObj query = BSON("x" << BSON("$type" << 1.5)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -1389,8 +1389,7 @@ TEST(MatchExpressionParserLeafTest, TypeDoubleOperator) { TEST(MatchExpressionParserLeafTest, TypeDecimalOperator) { BSONObj query = BSON("x" << BSON("$type" << mongo::NumberDecimal)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT_FALSE(result.getValue()->matchesBSON(BSON("x" << 5.3))); @@ -1400,8 +1399,7 @@ TEST(MatchExpressionParserLeafTest, TypeDecimalOperator) { TEST(MatchExpressionParserLeafTest, TypeNull) { BSONObj query = BSON("x" << BSON("$type" << jstNULL)); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSONObj())); @@ -1416,48 +1414,35 @@ TEST(MatchExpressionParserLeafTest, TypeBadType) { b.append("$type", (JSTypeMax + 1)); BSONObj query = BSON("x" << b.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserLeafTest, TypeBadString) { const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: null}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: true}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: {}}}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(fromjson("{a: {$type: ObjectId('000000000000000000000000')}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: []}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + 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()); + ASSERT_NOT_OK(MatchExpressionParser::parse( + fromjson("{a: {$type: ObjectId('000000000000000000000000')}}"), collator) .getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$type: []}}"), collator).getStatus()); } TEST(MatchExpressionParserLeafTest, TypeStringnameDouble) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeNumberDouble = MatchExpressionParser::parse( - fromjson("{a: {$type: 'double'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeNumberDouble = + MatchExpressionParser::parse(fromjson("{a: {$type: 'double'}}"), collator); ASSERT_OK(typeNumberDouble.getStatus()); TypeMatchExpression* tmeNumberDouble = static_cast<TypeMatchExpression*>(typeNumberDouble.getValue().get()); @@ -1468,8 +1453,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameDouble) { TEST(MatchExpressionParserLeafTest, TypeStringNameNumberDecimal) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeNumberDecimal = MatchExpressionParser::parse( - fromjson("{a: {$type: 'decimal'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeNumberDecimal = + MatchExpressionParser::parse(fromjson("{a: {$type: 'decimal'}}"), collator); ASSERT_OK(typeNumberDecimal.getStatus()); TypeMatchExpression* tmeNumberDecimal = static_cast<TypeMatchExpression*>(typeNumberDecimal.getValue().get()); @@ -1480,8 +1465,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringNameNumberDecimal) { TEST(MatchExpressionParserLeafTest, TypeStringnameNumberInt) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeNumberInt = MatchExpressionParser::parse( - fromjson("{a: {$type: 'int'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeNumberInt = + MatchExpressionParser::parse(fromjson("{a: {$type: 'int'}}"), collator); ASSERT_OK(typeNumberInt.getStatus()); TypeMatchExpression* tmeNumberInt = static_cast<TypeMatchExpression*>(typeNumberInt.getValue().get()); @@ -1492,8 +1477,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumberInt) { TEST(MatchExpressionParserLeafTest, TypeStringnameNumberLong) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeNumberLong = MatchExpressionParser::parse( - fromjson("{a: {$type: 'long'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeNumberLong = + MatchExpressionParser::parse(fromjson("{a: {$type: 'long'}}"), collator); ASSERT_OK(typeNumberLong.getStatus()); TypeMatchExpression* tmeNumberLong = static_cast<TypeMatchExpression*>(typeNumberLong.getValue().get()); @@ -1504,8 +1489,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumberLong) { TEST(MatchExpressionParserLeafTest, TypeStringnameString) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeString = MatchExpressionParser::parse( - fromjson("{a: {$type: 'string'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeString = + MatchExpressionParser::parse(fromjson("{a: {$type: 'string'}}"), collator); ASSERT_OK(typeString.getStatus()); TypeMatchExpression* tmeString = static_cast<TypeMatchExpression*>(typeString.getValue().get()); ASSERT_EQ(tmeString->getBSONType(), BSONType::String); @@ -1515,8 +1500,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameString) { TEST(MatchExpressionParserLeafTest, TypeStringnamejstOID) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typejstOID = MatchExpressionParser::parse( - fromjson("{a: {$type: 'objectId'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typejstOID = + MatchExpressionParser::parse(fromjson("{a: {$type: 'objectId'}}"), collator); ASSERT_OK(typejstOID.getStatus()); TypeMatchExpression* tmejstOID = static_cast<TypeMatchExpression*>(typejstOID.getValue().get()); ASSERT_EQ(tmejstOID->getBSONType(), BSONType::jstOID); @@ -1526,8 +1511,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnamejstOID) { TEST(MatchExpressionParserLeafTest, TypeStringnamejstNULL) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typejstNULL = MatchExpressionParser::parse( - fromjson("{a: {$type: 'null'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typejstNULL = + MatchExpressionParser::parse(fromjson("{a: {$type: 'null'}}"), collator); ASSERT_OK(typejstNULL.getStatus()); TypeMatchExpression* tmejstNULL = static_cast<TypeMatchExpression*>(typejstNULL.getValue().get()); @@ -1538,8 +1523,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnamejstNULL) { TEST(MatchExpressionParserLeafTest, TypeStringnameBool) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeBool = MatchExpressionParser::parse( - fromjson("{a: {$type: 'bool'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeBool = + MatchExpressionParser::parse(fromjson("{a: {$type: 'bool'}}"), collator); ASSERT_OK(typeBool.getStatus()); TypeMatchExpression* tmeBool = static_cast<TypeMatchExpression*>(typeBool.getValue().get()); ASSERT_EQ(tmeBool->getBSONType(), BSONType::Bool); @@ -1549,8 +1534,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameBool) { TEST(MatchExpressionParserLeafTest, TypeStringnameObject) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeObject = MatchExpressionParser::parse( - fromjson("{a: {$type: 'object'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeObject = + MatchExpressionParser::parse(fromjson("{a: {$type: 'object'}}"), collator); ASSERT_OK(typeObject.getStatus()); TypeMatchExpression* tmeObject = static_cast<TypeMatchExpression*>(typeObject.getValue().get()); ASSERT_EQ(tmeObject->getBSONType(), BSONType::Object); @@ -1560,8 +1545,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameObject) { TEST(MatchExpressionParserLeafTest, TypeStringnameArray) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeArray = MatchExpressionParser::parse( - fromjson("{a: {$type: 'array'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeArray = + MatchExpressionParser::parse(fromjson("{a: {$type: 'array'}}"), collator); ASSERT_OK(typeArray.getStatus()); TypeMatchExpression* tmeArray = static_cast<TypeMatchExpression*>(typeArray.getValue().get()); ASSERT_EQ(tmeArray->getBSONType(), BSONType::Array); @@ -1571,8 +1556,8 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameArray) { TEST(MatchExpressionParserLeafTest, TypeStringnameNumber) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeNumber = MatchExpressionParser::parse( - fromjson("{a: {$type: 'number'}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeNumber = + MatchExpressionParser::parse(fromjson("{a: {$type: 'number'}}"), collator); ASSERT_OK(typeNumber.getStatus()); TypeMatchExpression* tmeNumber = static_cast<TypeMatchExpression*>(typeNumber.getValue().get()); ASSERT_TRUE(tmeNumber->matchesBSON(fromjson("{a: 5.4}"))); @@ -1583,22 +1568,22 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumber) { TEST(MatchExpressionParserLeafTest, InvalidTypeCodeLessThanMinKeyFailsToParse) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeNumber = MatchExpressionParser::parse( - fromjson("{a: {$type: -20}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeNumber = + MatchExpressionParser::parse(fromjson("{a: {$type: -20}}"), collator); ASSERT_NOT_OK(typeNumber.getStatus()); } TEST(MatchExpressionParserLeafTest, InvalidTypeCodeGreaterThanMaxKeyFailsToParse) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeNumber = MatchExpressionParser::parse( - fromjson("{a: {$type: 400}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeNumber = + MatchExpressionParser::parse(fromjson("{a: {$type: 400}}"), collator); ASSERT_NOT_OK(typeNumber.getStatus()); } TEST(MatchExpressionParserLeafTest, InvalidTypeCodeUnusedBetweenMinAndMaxFailsToParse) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression typeNumber = MatchExpressionParser::parse( - fromjson("{a: {$type: 62}}"), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression typeNumber = + MatchExpressionParser::parse(fromjson("{a: {$type: 62}}"), collator); ASSERT_NOT_OK(typeNumber.getStatus()); } @@ -1611,8 +1596,7 @@ TEST(MatchExpressionParserLeafTest, ValidTypeCodesParseSuccessfully) { for (auto type : validTypes) { BSONObj predicate = BSON("a" << BSON("$type" << type)); const CollatorInterface* collator = nullptr; - auto expression = MatchExpressionParser::parse( - predicate, ExtensionsCallbackDisallowExtensions(), collator); + auto expression = MatchExpressionParser::parse(predicate, collator); ASSERT_OK(expression.getStatus()); auto typeExpression = static_cast<TypeMatchExpression*>(expression.getValue().get()); ASSERT_EQ(type, typeExpression->getBSONType()); @@ -1628,8 +1612,7 @@ TEST(MatchExpressionParserLeafTest, TypeWithConstantExprFails) { auto varId = expCtx->variablesParseState.defineVariable("userVar"); expCtx->variables.setValue(varId, Value(static_cast<int>(BSONType::NumberDouble))); - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_NOT_OK(result.getStatus()); } @@ -1637,77 +1620,55 @@ TEST(MatchExpressionParserTest, BitTestMatchExpressionValidMask) { const double k2Power53 = scalbn(1, 32); const CollatorInterface* collator = nullptr; - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << 54)), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<long long>::max())), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53)), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53 - 1)), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << 54)), collator).getStatus()); + 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) .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << k2Power53 - 1)), collator) + .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << 54)), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<long long>::max())), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << k2Power53)), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << k2Power53 - 1)), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << 54)), collator) .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) + .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << 54)), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<long long>::max())), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53)), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53 - 1)), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << 54)), collator).getStatus()); + ASSERT_OK( + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<long long>::max())), collator) + .getStatus()); + ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53)), collator) .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << k2Power53 - 1)), collator) + .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << 54)), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<long long>::max())), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53)), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53 - 1)), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << 54)), collator) .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<long long>::max())), collator) + .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53)), collator) + .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << k2Power53 - 1)), collator) + .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionValidArray) { @@ -1718,79 +1679,59 @@ TEST(MatchExpressionParserTest, BitTestMatchExpressionValidArray) { ASSERT_EQ(BSONType::NumberLong, bsonArrayLongLong[3].type()); const CollatorInterface* collator = nullptr; - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0))), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0))), collator) + .getStatus()); ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0 << 1 << 2 << 3))), - ExtensionsCallbackDisallowExtensions(), - collator) + BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(0 << 1 << 2 << 3))), collator) .getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << bsonArrayLongLong)), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<int>::max()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0))), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0))), collator) + .getStatus()); ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0 << 1 << 2 << 3))), - ExtensionsCallbackDisallowExtensions(), - collator) + BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(0 << 1 << 2 << 3))), collator) .getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << bsonArrayLongLong)), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<int>::max()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0))), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0))), collator) + .getStatus()); ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0 << 1 << 2 << 3))), - ExtensionsCallbackDisallowExtensions(), - collator) + BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(0 << 1 << 2 << 3))), collator) .getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << bsonArrayLongLong)), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<int>::max()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0))), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + ASSERT_OK( + MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0))), collator) + .getStatus()); ASSERT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0 << 1 << 2 << 3))), - ExtensionsCallbackDisallowExtensions(), - collator) + BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(0 << 1 << 2 << 3))), collator) .getStatus()); ASSERT_OK(MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << bsonArrayLongLong)), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_OK(MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<int>::max()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); } @@ -1800,7 +1741,6 @@ TEST(MatchExpressionParserTest, BitTestMatchExpressionValidBinData) { ASSERT_OK( MatchExpressionParser::parse( fromjson("{a: {$bitsAllSet: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); @@ -1808,14 +1748,12 @@ TEST(MatchExpressionParserTest, BitTestMatchExpressionValidBinData) { MatchExpressionParser::parse( fromjson( "{a: {$bitsAllClear: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_OK( MatchExpressionParser::parse( fromjson("{a: {$bitsAnySet: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); @@ -1823,496 +1761,308 @@ TEST(MatchExpressionParserTest, BitTestMatchExpressionValidBinData) { MatchExpressionParser::parse( fromjson( "{a: {$bitsAnyClear: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}}}"), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidMaskType) { const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: null}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: true}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: {}}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ''}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: null}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: true}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: {}}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ''}}"), collator).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: null}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: true}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: {}}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ''}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse( - fromjson("{a: {$bitsAllClear: ObjectId('000000000000000000000000')}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .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()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ''}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse( + fromjson("{a: {$bitsAllClear: ObjectId('000000000000000000000000')}}"), collator) + .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: null}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: true}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: {}}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ''}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse( - fromjson("{a: {$bitsAnySet: ObjectId('000000000000000000000000')}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: null}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: true}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: {}}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ''}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse( + fromjson("{a: {$bitsAnySet: ObjectId('000000000000000000000000')}}"), collator) + .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: null}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: true}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: {}}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ''}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse( - fromjson("{a: {$bitsAnyClear: ObjectId('000000000000000000000000')}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .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()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ''}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse( + fromjson("{a: {$bitsAnyClear: ObjectId('000000000000000000000000')}}"), collator) + .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidMaskValue) { const double kLongLongMaxAsDouble = scalbn(1, std::numeric_limits<long long>::digits); const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: NaN}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: -54}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<double>::max())), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << kLongLongMaxAsDouble)), - ExtensionsCallbackDisallowExtensions(), - collator) + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: NaN}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: -54}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAllSet" << std::numeric_limits<double>::max())), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: 2.5}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAllSet" << kLongLongMaxAsDouble)), collator) .getStatus()); - ASSERT_NOT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllSet" << Decimal128("2.5"))), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: 2.5}}"), collator).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: NaN}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: -54}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<double>::max())), - ExtensionsCallbackDisallowExtensions(), - collator) + BSON("a" << BSON("$bitsAllSet" << Decimal128("2.5"))), collator) .getStatus()); + + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: NaN}}"), collator).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << kLongLongMaxAsDouble)), - ExtensionsCallbackDisallowExtensions(), - collator) + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: -54}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAllClear" << std::numeric_limits<double>::max())), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: 2.5}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAllClear" << kLongLongMaxAsDouble)), collator) .getStatus()); - ASSERT_NOT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAllClear" << Decimal128("2.5"))), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: 2.5}}"), collator).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: NaN}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: -54}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<double>::max())), - ExtensionsCallbackDisallowExtensions(), - collator) + BSON("a" << BSON("$bitsAllClear" << Decimal128("2.5"))), collator) .getStatus()); + + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: NaN}}"), collator).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << kLongLongMaxAsDouble)), - ExtensionsCallbackDisallowExtensions(), - collator) + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: -54}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnySet" << std::numeric_limits<double>::max())), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: 2.5}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnySet" << kLongLongMaxAsDouble)), collator) .getStatus()); - ASSERT_NOT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnySet" << Decimal128("2.5"))), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: 2.5}}"), collator).getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: NaN}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: -54}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse( - BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<double>::max())), - ExtensionsCallbackDisallowExtensions(), - collator) + BSON("a" << BSON("$bitsAnySet" << Decimal128("2.5"))), collator) .getStatus()); + + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: NaN}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: -54}}"), collator).getStatus()); ASSERT_NOT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << kLongLongMaxAsDouble)), - ExtensionsCallbackDisallowExtensions(), - collator) + MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnyClear" << std::numeric_limits<double>::max())), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: 2.5}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnyClear" << kLongLongMaxAsDouble)), collator) .getStatus()); - ASSERT_NOT_OK( - MatchExpressionParser::parse(BSON("a" << BSON("$bitsAnyClear" << Decimal128("2.5"))), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: 2.5}}"), collator).getStatus()); + + ASSERT_NOT_OK(MatchExpressionParser::parse( + BSON("a" << BSON("$bitsAnyClear" << Decimal128("2.5"))), collator) + .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidArray) { const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [null]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [true]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ['']}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [{}]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [[]]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [null]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [true]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: ['']}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [{}]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [[]]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAllSet: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [null]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [true]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ['']}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [{}]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [[]]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [null]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [true]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: ['']}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [{}]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [[]]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1]}}"), collator).getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAllClear: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [null]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [true]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ['']}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [{}]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [[]]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [null]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [true]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: ['']}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [{}]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [[]]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), collator).getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAnySet: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [null]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [true]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [null]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ['']}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [true]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [{}]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [[]]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: ['']}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [{}]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [[]]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1]}}"), collator).getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( fromjson( "{a: {$bitsAnyClear: [{$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA', $type: '00'}]}}"), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); } TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidArrayValue) { const CollatorInterface* collator = nullptr; - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-54]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [NaN]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [2.5]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [1e100]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-54]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [NaN]}}"), collator).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]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [-1e100]}}"), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllSet" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-54]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-54]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [NaN]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [NaN]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [2.5]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [1e100]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [1e100]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1e100]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: [-1e100]}}"), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAllClear" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-54]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [NaN]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [2.5]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) - .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [1e100]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-54]}}"), collator).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [NaN]}}"), collator).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]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: [-1e100]}}"), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnySet" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-54]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-54]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [NaN]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [NaN]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [2.5]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [1e100]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [1e100]}}"), collator) .getStatus()); - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1e100]}}"), - ExtensionsCallbackDisallowExtensions(), - collator) + ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: [-1e100]}}"), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<long long>::max()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); ASSERT_NOT_OK( MatchExpressionParser::parse( BSON("a" << BSON("$bitsAnyClear" << BSON_ARRAY(std::numeric_limits<long long>::min()))), - ExtensionsCallbackDisallowExtensions(), collator) .getStatus()); } @@ -2325,27 +2075,31 @@ TEST(MatchExpressionParserLeafTest, BitTestWithConstantExprFails) { expCtx->variables.setValue(varId, Value(BSON_ARRAY(1 << 5))); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [{$expr: 'userVar'}]}}"), - ExtensionsCallbackDisallowExtensions(), collator, - expCtx) + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr) .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: {$expr: 'userVar'}}}"), - ExtensionsCallbackDisallowExtensions(), collator, - expCtx) + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr) .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: {$expr: 'userVar'}}}"), - ExtensionsCallbackDisallowExtensions(), collator, - expCtx) + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr) .getStatus()); ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: {$expr: 'userVar'}}}"), - ExtensionsCallbackDisallowExtensions(), collator, - expCtx) + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kExpr) .getStatus()); } } // namespace mongo diff --git a/src/mongo/db/matcher/expression_parser_test.cpp b/src/mongo/db/matcher/expression_parser_test.cpp index 9026782ffdb..9f0276b7028 100644 --- a/src/mongo/db/matcher/expression_parser_test.cpp +++ b/src/mongo/db/matcher/expression_parser_test.cpp @@ -36,15 +36,15 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" +#include "mongo/db/matcher/extensions_callback_noop.h" +#include "mongo/db/pipeline/expression_context_for_test.h" namespace mongo { TEST(MatchExpressionParserTest, SimpleEQ1) { BSONObj query = BSON("x" << 2); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -54,8 +54,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 5 << "y" << 7))); @@ -68,24 +67,22 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); query = BSON("x" << 5 << "$isolated" << 1); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); query = BSON("x" << 5 << "y" << BSON("$isolated" << 1)); - result = MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } TEST(MatchExpressionParserTest, MinDistanceWithoutNearFailsToParse) { BSONObj query = fromjson("{loc: {$minDistance: 10}}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_FALSE(result.isOK()); } @@ -229,31 +226,26 @@ TEST(StatusWithTest, Fib1) { TEST(MatchExpressionParserTest, AlwaysFalseFailsToParseNonOneArguments) { auto queryIntArgument = BSON("$alwaysFalse" << 0); - auto expr = MatchExpressionParser::parse( - queryIntArgument, ExtensionsCallbackDisallowExtensions(), nullptr); + auto expr = MatchExpressionParser::parse(queryIntArgument, nullptr); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryStringArgument = BSON("$alwaysFalse" << ""); - expr = MatchExpressionParser::parse( - queryStringArgument, ExtensionsCallbackDisallowExtensions(), nullptr); + expr = MatchExpressionParser::parse(queryStringArgument, nullptr); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryDoubleArgument = BSON("$alwaysFalse" << 1.1); - expr = MatchExpressionParser::parse( - queryDoubleArgument, ExtensionsCallbackDisallowExtensions(), nullptr); + expr = MatchExpressionParser::parse(queryDoubleArgument, nullptr); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryFalseArgument = BSON("$alwaysFalse" << true); - expr = MatchExpressionParser::parse( - queryFalseArgument, ExtensionsCallbackDisallowExtensions(), nullptr); + expr = MatchExpressionParser::parse(queryFalseArgument, nullptr); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserTest, AlwaysFalseParsesIntegerArgument) { auto query = BSON("$alwaysFalse" << 1); - auto expr = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), nullptr); + auto expr = MatchExpressionParser::parse(query, nullptr); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{}"))); @@ -263,35 +255,138 @@ TEST(MatchExpressionParserTest, AlwaysFalseParsesIntegerArgument) { TEST(MatchExpressionParserTest, AlwaysTrueFailsToParseNonOneArguments) { auto queryIntArgument = BSON("$alwaysTrue" << 0); - auto expr = MatchExpressionParser::parse( - queryIntArgument, ExtensionsCallbackDisallowExtensions(), nullptr); + auto expr = MatchExpressionParser::parse(queryIntArgument, nullptr); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryStringArgument = BSON("$alwaysTrue" << ""); - expr = MatchExpressionParser::parse( - queryStringArgument, ExtensionsCallbackDisallowExtensions(), nullptr); + expr = MatchExpressionParser::parse(queryStringArgument, nullptr); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryDoubleArgument = BSON("$alwaysTrue" << 1.1); - expr = MatchExpressionParser::parse( - queryDoubleArgument, ExtensionsCallbackDisallowExtensions(), nullptr); + expr = MatchExpressionParser::parse(queryDoubleArgument, nullptr); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryFalseArgument = BSON("$alwaysTrue" << true); - expr = MatchExpressionParser::parse( - queryFalseArgument, ExtensionsCallbackDisallowExtensions(), nullptr); + expr = MatchExpressionParser::parse(queryFalseArgument, nullptr); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserTest, AlwaysTrueParsesIntegerArgument) { auto query = BSON("$alwaysTrue" << 1); - auto expr = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), nullptr); + auto expr = MatchExpressionParser::parse(query, nullptr); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{}"))); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{x: 1}"))); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{x: 'blah'}"))); } + +TEST(MatchExpressionParserTest, TextFailsToParseWhenDisallowed) { + auto query = fromjson("{$text: {$search: 'str'}}"); + const CollatorInterface* collator = nullptr; + ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).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()); +} + +TEST(MatchExpressionParserTest, WhereFailsToParseWhenDisallowed) { + auto query = fromjson("{$where: 'this.a == this.b'}"); + const CollatorInterface* collator = nullptr; + ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).getStatus()); +} + +TEST(MatchExpressionParserTest, WhereParsesSuccessfullyWhenAllowed) { + auto query = fromjson("{$where: 'this.a == this.b'}"); + const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + ASSERT_OK(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kJavascript) + .getStatus()); +} + +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()); +} + +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()); + ASSERT_OK(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kGeoNear) + .getStatus()); +} + +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()); +} + +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()); + ASSERT_OK(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kGeoNear) + .getStatus()); +} + +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()); +} + +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()); + ASSERT_OK(MatchExpressionParser::parse(query, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kGeoNear) + .getStatus()); +} + +TEST(MatchExpressionParserTest, ExprFailsToParseWhenDisallowed) { + auto query = fromjson("{a: {$expr: 5}}"); + const CollatorInterface* collator = nullptr; + ASSERT_NOT_OK(MatchExpressionParser::parse(query, collator).getStatus()); +} + +TEST(MatchExpressionParserTest, ExprParsesSuccessfullyWhenAllowed) { + auto query = fromjson("{a: {$expr: 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()); +} } diff --git a/src/mongo/db/matcher/expression_parser_tree.cpp b/src/mongo/db/matcher/expression_parser_tree.cpp index b7ba5964253..1e4290fcdc9 100644 --- a/src/mongo/db/matcher/expression_parser_tree.cpp +++ b/src/mongo/db/matcher/expression_parser_tree.cpp @@ -43,6 +43,7 @@ Status MatchExpressionParser::_parseTreeList(const BSONObj& arr, ListOfMatchExpression* out, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel) { if (arr.isEmpty()) return Status(ErrorCodes::BadValue, "$and/$or/$nor must be a nonempty array"); @@ -54,7 +55,8 @@ 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, topLevel); + StatusWithMatchExpression sub = + _parse(e.Obj(), collator, expCtx, allowedFeatures, topLevel); if (!sub.isOK()) return sub.getStatus(); @@ -68,6 +70,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseNot( const BSONElement& e, const CollatorInterface* collator, const boost::intrusive_ptr<ExpressionContext>& expCtx, + AllowedFeatureSet allowedFeatures, bool topLevel) { if (e.type() == RegEx) { StatusWithMatchExpression s = _parseRegexElement(name, e, expCtx); @@ -88,7 +91,8 @@ 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, topLevel); + Status s = + _parseSub(name, notObject, theAnd.get(), collator, 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 1fbed8b69a6..d223a672c95 100644 --- a/src/mongo/db/matcher/expression_parser_tree_test.cpp +++ b/src/mongo/db/matcher/expression_parser_tree_test.cpp @@ -36,15 +36,13 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -57,8 +55,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query2, collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 1))); @@ -71,8 +68,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -86,8 +82,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -99,8 +94,7 @@ TEST(MatchExpressionParserTreeTest, NOREmbedded) { TEST(MatchExpressionParserTreeTest, NOT1) { BSONObj query = BSON("x" << BSON("$not" << BSON("$gt" << 5))); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(result.getValue()->matchesBSON(BSON("x" << 2))); @@ -112,8 +106,7 @@ TEST(MatchExpressionParserLeafTest, NotRegex1) { b.appendRegex("$not", "abc", "i"); BSONObj query = BSON("x" << b.obj()); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" diff --git a/src/mongo/db/matcher/expression_serialization_test.cpp b/src/mongo/db/matcher/expression_serialization_test.cpp index 0f08fedebb7..6ab93f3e2dc 100644 --- a/src/mongo/db/matcher/expression_serialization_test.cpp +++ b/src/mongo/db/matcher/expression_serialization_test.cpp @@ -33,9 +33,9 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/matcher/matcher.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -54,9 +54,17 @@ BSONObj serialize(MatchExpression* match) { } TEST(SerializeBasic, AndExpressionWithOneChildSerializesCorrectly) { - Matcher original(fromjson("{$and: [{x: 0}]}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 0}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -68,10 +76,17 @@ TEST(SerializeBasic, AndExpressionWithOneChildSerializesCorrectly) { } TEST(SerializeBasic, AndExpressionWithTwoChildrenSerializesCorrectly) { - Matcher original( - fromjson("{$and: [{x: 1}, {x: 2}]}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 2}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -83,10 +98,17 @@ TEST(SerializeBasic, AndExpressionWithTwoChildrenSerializesCorrectly) { } TEST(SerializeBasic, AndExpressionWithTwoIdenticalChildrenSerializesCorrectly) { - Matcher original( - fromjson("{$and: [{x: 1}, {x: 1}]}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 1}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -98,10 +120,17 @@ TEST(SerializeBasic, AndExpressionWithTwoIdenticalChildrenSerializesCorrectly) { } TEST(SerializeBasic, ExpressionOr) { - Matcher original( - fromjson("{$or: [{x: 'A'}, {x: 'B'}]}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$or: [{x: {$eq: 'A'}}, {x: {$eq: 'B'}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -114,11 +143,17 @@ TEST(SerializeBasic, ExpressionOr) { } TEST(SerializeBasic, ExpressionElemMatchObjectSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$elemMatch: {a: {$gt: 0}, b: {$gt: 0}}}}"), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$elemMatch: {$and: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -131,11 +166,17 @@ 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(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{'': {$elemMatch: {$and: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -148,11 +189,17 @@ 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(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -167,13 +214,21 @@ TEST(SerializeBasic, ExpressionElemMatchValueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionElemMatchValueWithRegexSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); const auto match = BSON("x" << BSON("$elemMatch" << BSON("$regex" << "abc" << "$options" << "i"))); - Matcher original(match, ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + Matcher original(match, + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), match); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -188,11 +243,17 @@ 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(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$elemMatch: {$lt: 1, $gt: -1}}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -207,9 +268,17 @@ TEST(SerializeBasic, ExpressionElemMatchValueWithEmptyStringSerializesCorrectly) } TEST(SerializeBasic, ExpressionSizeSerializesCorrectly) { - Matcher original(fromjson("{x: {$size: 2}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$size: 2}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -221,9 +290,17 @@ TEST(SerializeBasic, ExpressionSizeSerializesCorrectly) { } TEST(SerializeBasic, ExpressionAllSerializesCorrectly) { - Matcher original(fromjson("{x: {$all: [1, 2]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$and: [{x: {$eq: 1}}, {x: {$eq: 2}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -235,9 +312,17 @@ TEST(SerializeBasic, ExpressionAllSerializesCorrectly) { } TEST(SerializeBasic, ExpressionAllWithEmptyArraySerializesCorrectly) { - Matcher original(fromjson("{x: {$all: []}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$alwaysFalse: 1}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -246,10 +331,17 @@ TEST(SerializeBasic, ExpressionAllWithEmptyArraySerializesCorrectly) { } TEST(SerializeBasic, ExpressionAllWithRegex) { - Matcher original( - fromjson("{x: {$all: [/a.b.c/, /.d.e./]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("$and" << BSON_ARRAY(BSON("x" << BSON("$regex" @@ -266,9 +358,17 @@ TEST(SerializeBasic, ExpressionAllWithRegex) { } TEST(SerializeBasic, ExpressionEqSerializesCorrectly) { - Matcher original(fromjson("{x: {$eq: {a: 1}}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$eq: {a: 1}}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -283,9 +383,17 @@ TEST(SerializeBasic, ExpressionEqSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNeSerializesCorrectly) { - Matcher original(fromjson("{x: {$ne: {a: 1}}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$eq: {a: 1}}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -297,12 +405,18 @@ TEST(SerializeBasic, ExpressionNeSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNeWithRegexObjectSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(BSON("x" << BSON("$ne" << BSON("$regex" << "abc"))), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("$nor" << BSON_ARRAY(BSON("x" << BSON("$eq" << BSON("$regex" << "abc")))))); @@ -316,9 +430,17 @@ TEST(SerializeBasic, ExpressionNeWithRegexObjectSerializesCorrectly) { } TEST(SerializeBasic, ExpressionLtSerializesCorrectly) { - Matcher original(fromjson("{x: {$lt: 3}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$lt: 3}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -330,9 +452,17 @@ TEST(SerializeBasic, ExpressionLtSerializesCorrectly) { } TEST(SerializeBasic, ExpressionGtSerializesCorrectly) { - Matcher original(fromjson("{x: {$gt: 3}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$gt: 3}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -344,9 +474,17 @@ TEST(SerializeBasic, ExpressionGtSerializesCorrectly) { } TEST(SerializeBasic, ExpressionGteSerializesCorrectly) { - Matcher original(fromjson("{x: {$gte: 3}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$gte: 3}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -358,9 +496,17 @@ TEST(SerializeBasic, ExpressionGteSerializesCorrectly) { } TEST(SerializeBasic, ExpressionLteSerializesCorrectly) { - Matcher original(fromjson("{x: {$lte: 3}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$lte: 3}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -372,9 +518,17 @@ TEST(SerializeBasic, ExpressionLteSerializesCorrectly) { } TEST(SerializeBasic, ExpressionRegexWithObjSerializesCorrectly) { - Matcher original(fromjson("{x: {$regex: 'a.b'}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("x" << BSON("$regex" << "a.b"))); @@ -388,9 +542,17 @@ TEST(SerializeBasic, ExpressionRegexWithObjSerializesCorrectly) { } TEST(SerializeBasic, ExpressionRegexWithValueAndOptionsSerializesCorrectly) { - Matcher original(fromjson("{x: /a.b/i}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("x" << BSON("$regex" << "a.b" @@ -406,9 +568,17 @@ TEST(SerializeBasic, ExpressionRegexWithValueAndOptionsSerializesCorrectly) { } TEST(SerializeBasic, ExpressionRegexWithValueSerializesCorrectly) { - Matcher original(fromjson("{x: /a.b/}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("x" << BSON("$regex" << "a.b"))); @@ -422,10 +592,17 @@ TEST(SerializeBasic, ExpressionRegexWithValueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionRegexWithEqObjSerializesCorrectly) { - Matcher original( - fromjson("{x: {$eq: {$regex: 'a.b'}}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$eq: {$regex: 'a.b'}}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -440,9 +617,17 @@ TEST(SerializeBasic, ExpressionRegexWithEqObjSerializesCorrectly) { } TEST(SerializeBasic, ExpressionModSerializesCorrectly) { - Matcher original(fromjson("{x: {$mod: [2, 1]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$mod: [2, 1]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -454,9 +639,17 @@ TEST(SerializeBasic, ExpressionModSerializesCorrectly) { } TEST(SerializeBasic, ExpressionExistsTrueSerializesCorrectly) { - Matcher original(fromjson("{x: {$exists: true}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$exists: true}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -468,9 +661,17 @@ TEST(SerializeBasic, ExpressionExistsTrueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionExistsFalseSerializesCorrectly) { - Matcher original(fromjson("{x: {$exists: false}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$exists: true}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -482,9 +683,17 @@ TEST(SerializeBasic, ExpressionExistsFalseSerializesCorrectly) { } TEST(SerializeBasic, ExpressionInSerializesCorrectly) { - Matcher original(fromjson("{x: {$in: [1, 2, 3]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$in: [1, 2, 3]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -499,9 +708,17 @@ TEST(SerializeBasic, ExpressionInSerializesCorrectly) { } TEST(SerializeBasic, ExpressionInWithEmptyArraySerializesCorrectly) { - Matcher original(fromjson("{x: {$in: []}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$in: []}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -510,10 +727,17 @@ TEST(SerializeBasic, ExpressionInWithEmptyArraySerializesCorrectly) { } TEST(SerializeBasic, ExpressionInWithRegexSerializesCorrectly) { - Matcher original( - fromjson("{x: {$in: [/\\d+/, /\\w+/]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$in: [/\\d+/, /\\w+/]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -528,9 +752,17 @@ TEST(SerializeBasic, ExpressionInWithRegexSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNinSerializesCorrectly) { - Matcher original(fromjson("{x: {$nin: [1, 2, 3]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$in: [1, 2, 3]}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -545,10 +777,17 @@ TEST(SerializeBasic, ExpressionNinSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNinWithRegexValueSerializesCorrectly) { - Matcher original( - fromjson("{x: {$nin: [/abc/, /def/, /xyz/]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$in: [/abc/, /def/, /xyz/]}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -563,10 +802,17 @@ TEST(SerializeBasic, ExpressionNinWithRegexValueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionBitsAllSetSerializesCorrectly) { - Matcher original( - fromjson("{x: {$bitsAllSet: [1, 3]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAllSet: [1, 3]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -578,10 +824,17 @@ TEST(SerializeBasic, ExpressionBitsAllSetSerializesCorrectly) { } TEST(SerializeBasic, ExpressionBitsAllClearSerializesCorrectly) { - Matcher original( - fromjson("{x: {$bitsAllClear: [1, 3]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAllClear: [1, 3]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -593,10 +846,17 @@ TEST(SerializeBasic, ExpressionBitsAllClearSerializesCorrectly) { } TEST(SerializeBasic, ExpressionBitsAnySetSerializesCorrectly) { - Matcher original( - fromjson("{x: {$bitsAnySet: [1, 3]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAnySet: [1, 3]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -608,10 +868,17 @@ TEST(SerializeBasic, ExpressionBitsAnySetSerializesCorrectly) { } TEST(SerializeBasic, ExpressionBitsAnyClearSerializesCorrectly) { - Matcher original( - fromjson("{x: {$bitsAnyClear: [1, 3]}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$bitsAnyClear: [1, 3]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -626,9 +893,17 @@ TEST(SerializeBasic, ExpressionBitsAnyClearSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: {$eq: 3}}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$eq: 3}}]}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -640,10 +915,17 @@ TEST(SerializeBasic, ExpressionNotSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithMultipleChildrenSerializesCorrectly) { - Matcher original( - fromjson("{x: {$not: {$lt: 1, $gt: 3}}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$lt: 1}}, {x: {$gt: 3}}]}]}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -656,10 +938,17 @@ TEST(SerializeBasic, ExpressionNotWithMultipleChildrenSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithBitTestSerializesCorrectly) { - Matcher original( - fromjson("{x: {$not: {$bitsAnySet: [1, 3]}}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$bitsAnySet: [1, 3]}}]}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -672,10 +961,17 @@ TEST(SerializeBasic, ExpressionNotWithBitTestSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithRegexObjSerializesCorrectly) { - Matcher original( - fromjson("{x: {$not: {$regex: 'a.b'}}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("$nor" << BSON_ARRAY(BSON("x" << BSON("$regex" << "a.b"))))); @@ -689,9 +985,17 @@ TEST(SerializeBasic, ExpressionNotWithRegexObjSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithRegexValueSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: /a.b/}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("$nor" << BSON_ARRAY(BSON("x" << BSON("$regex" << "a.b"))))); @@ -705,9 +1009,17 @@ TEST(SerializeBasic, ExpressionNotWithRegexValueSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithRegexValueAndOptionsSerializesCorrectly) { - Matcher original(fromjson("{x: {$not: /a.b/i}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("$nor" << BSON_ARRAY(BSON("x" << BSON("$regex" << "a.b" @@ -723,13 +1035,19 @@ TEST(SerializeBasic, ExpressionNotWithRegexValueAndOptionsSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNotWithGeoSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$not: {$geoIntersects: {$geometry: {type: 'Polygon', " "coordinates: [[[0,0], [5,0], " "[5, 5], [0, 5], [0, 0]]]}}}}}"), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ( *reserialized.getQuery(), fromjson("{$nor: [{$and: [{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: " @@ -752,10 +1070,17 @@ TEST(SerializeBasic, ExpressionNotWithGeoSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNorSerializesCorrectly) { - Matcher original( - fromjson("{$nor: [{x: 3}, {x: {$lt: 1}}]}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$nor: [{x: {$eq: 3}}, {x: {$lt: 1}}]}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -770,9 +1095,17 @@ TEST(SerializeBasic, ExpressionNorSerializesCorrectly) { } TEST(SerializeBasic, ExpressionTypeSerializesCorrectly) { - Matcher original(fromjson("{x: {$type: 2}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$type: 2}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -784,9 +1117,17 @@ TEST(SerializeBasic, ExpressionTypeSerializesCorrectly) { } TEST(SerializeBasic, ExpressionTypeWithNumberSerializesCorrectly) { - Matcher original(fromjson("{x: {$type: 'number'}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$type: 'number'}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -798,10 +1139,8 @@ TEST(SerializeBasic, ExpressionTypeWithNumberSerializesCorrectly) { } TEST(SerializeInternalSchema, InternalSchemaTypeExpressionSerializesCorrectly) { - Matcher original( - fromjson("{x: {$_internalSchemaType: 2}}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + Matcher original(fromjson("{x: {$_internalSchemaType: 2}}"), kSimpleCollator); + Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaType: 2}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -813,11 +1152,8 @@ TEST(SerializeInternalSchema, InternalSchemaTypeExpressionSerializesCorrectly) { } TEST(SerializeInternalSchema, InternalSchemaTypeExpressionWithNumberSerializesCorrectly) { - Matcher original(fromjson("{x: {$_internalSchemaType: 'number'}}"), - ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + Matcher original(fromjson("{x: {$_internalSchemaType: 'number'}}"), kSimpleCollator); + Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaType: 'number'}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -829,9 +1165,17 @@ TEST(SerializeInternalSchema, InternalSchemaTypeExpressionWithNumberSerializesCo } TEST(SerializeBasic, ExpressionEmptySerializesCorrectly) { - Matcher original(fromjson("{}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -840,10 +1184,17 @@ TEST(SerializeBasic, ExpressionEmptySerializesCorrectly) { } TEST(SerializeBasic, ExpressionWhereSerializesCorrectly) { - Matcher original( - fromjson("{$where: 'this.a == this.b'}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ( *reserialized.getQuery(), BSONObjBuilder().appendCodeWScope("$where", "this.a == this.b", BSONObj()).obj()); @@ -851,20 +1202,34 @@ 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(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON("$where" << BSONCodeWScope("this.a == this.b", BSON("x" << 3)))); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeBasic, ExpressionCommentSerializesCorrectly) { - Matcher original(fromjson("{$comment: 'Hello'}"), ExtensionsCallbackNoop(), kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + 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); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); @@ -876,14 +1241,20 @@ TEST(SerializeBasic, ExpressionCommentSerializesCorrectly) { } TEST(SerializeBasic, ExpressionGeoWithinSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original( fromjson( "{x: {$geoWithin: {$geometry: " "{type: 'Polygon', coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]]}}}}"), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ( *reserialized.getQuery(), fromjson("{x: {$geoWithin: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [10,0], " @@ -898,14 +1269,20 @@ TEST(SerializeBasic, ExpressionGeoWithinSerializesCorrectly) { } TEST(SerializeBasic, ExpressionGeoIntersectsSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original( fromjson( "{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [5,0], [5, " "5], [0, 5], [0, 0]]]}}}}"), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ( *reserialized.getQuery(), fromjson("{x: {$geoIntersects: {$geometry: {type: 'Polygon', coordinates: [[[0,0], [5,0], " @@ -927,13 +1304,19 @@ TEST(SerializeBasic, ExpressionGeoIntersectsSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNearSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original( fromjson("{x: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " "$minDistance: 1}}}"), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ( *reserialized.getQuery(), fromjson("{x: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " @@ -942,14 +1325,20 @@ TEST(SerializeBasic, ExpressionNearSerializesCorrectly) { } TEST(SerializeBasic, ExpressionNearSphereSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original( fromjson( "{x: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}, $maxDistance: 10, " "$minDistance: 1}}}"), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ( *reserialized.getQuery(), fromjson("{x: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}, " @@ -958,11 +1347,17 @@ 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(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$text: {$search: 'a', $language: 'en', $caseSensitive: true, " "$diacriticSensitive: false}}")); @@ -970,11 +1365,17 @@ TEST(SerializeBasic, ExpressionTextSerializesCorrectly) { } TEST(SerializeBasic, ExpressionTextWithDefaultLanguageSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$text: {$search: 'a', $caseSensitive: false}}"), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$text: {$search: 'a', $language: '', $caseSensitive: false, " "$diacriticSensitive: false}}")); @@ -982,110 +1383,162 @@ TEST(SerializeBasic, ExpressionTextWithDefaultLanguageSerializesCorrectly) { } TEST(SerializeBasic, ExpressionAlwaysTrueSerializesCorrectly) { - Matcher original( - fromjson("{$alwaysTrue: 1}"), ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher original(fromjson("{$alwaysTrue: 1}"), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$alwaysTrue: 1}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeBasic, ExpressionAlwaysFalseSerializesCorrectly) { - Matcher original( - fromjson("{$alwaysFalse: 1}"), ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + Matcher original(fromjson("{$alwaysFalse: 1}"), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$alwaysFalse: 1}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaAllElemMatchFromIndexSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaAllElemMatchFromIndex: [2, {y: 1}]}}"), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaAllElemMatchFromIndex: [2, {y: {$eq: 1}}]}}")); } TEST(SerializeInternalSchema, ExpressionInternalSchemaMinItemsSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaMinItems: 1}}"), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaMinItems: 1}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaMaxItemsSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaMaxItems: 1}}"), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaMaxItems: 1}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaUniqueItemsSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaUniqueItems: true}}"), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaUniqueItems: true}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaObjectMatchSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaObjectMatch: {y: 1}}}"), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaObjectMatch: {y: {$eq: 1}}}}")); } TEST(SerializeInternalSchema, ExpressionInternalSchemaMinLengthSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaMinLength: 1}}"), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaMinLength: 1}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaMaxLengthSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{x: {$_internalSchemaMaxLength: 1}}"), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{x: {$_internalSchemaMaxLength: 1}}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaCondSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original(fromjson("{$_internalSchemaCond: [{a: 1}, {b: 2}, {c: 3}]}}"), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); BSONObjBuilder builder; ASSERT_BSONOBJ_EQ( *reserialized.getQuery(), @@ -1094,34 +1547,52 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaCondSerializesCorrectly) { } TEST(SerializeInternalSchema, ExpressionInternalSchemaMinPropertiesSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); const CollatorInterface* collator = nullptr; Matcher original(fromjson("{$_internalSchemaMinProperties: 1}"), - ExtensionsCallbackDisallowExtensions(), - collator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackDisallowExtensions(), collator); + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$_internalSchemaMinProperties: 1}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaMaxPropertiesSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); const CollatorInterface* collator = nullptr; Matcher original(fromjson("{$_internalSchemaMaxProperties: 1}"), - ExtensionsCallbackDisallowExtensions(), - collator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackDisallowExtensions(), collator); + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$_internalSchemaMaxProperties: 1}")); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression())); } TEST(SerializeInternalSchema, ExpressionInternalSchemaFmodSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); Matcher original( fromjson("{a: {$_internalSchemaFmod: [NumberDecimal('2.3'), NumberDecimal('1.1')]}}"), + kSimpleCollator, + expCtx, ExtensionsCallbackNoop(), - kSimpleCollator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackNoop(), kSimpleCollator); + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + kSimpleCollator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ( *reserialized.getQuery(), @@ -1134,13 +1605,19 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaFmodSerializesCorrectly) { } TEST(SerializeInternalSchema, ExpressionInternalSchemaMatchArrayIndexSerializesCorrectly) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); constexpr CollatorInterface* collator = nullptr; Matcher original(fromjson("{a: {$_internalSchemaMatchArrayIndex:" "{index: 2, namePlaceholder: 'i', expression: {i: {$lt: 3}}}}}"), - ExtensionsCallbackDisallowExtensions(), - collator); - Matcher reserialized( - serialize(original.getMatchExpression()), ExtensionsCallbackDisallowExtensions(), collator); + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); + Matcher reserialized(serialize(original.getMatchExpression()), + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{a: {$_internalSchemaMatchArrayIndex:" "{index: 2, namePlaceholder: 'i', expression: {i: {$lt: 3}}}}}")); @@ -1154,11 +1631,8 @@ TEST(SerializeInternalSchema, ExpressionInternalSchemaAllowedPropertiesSerialize namePlaceholder: 'i', patternProperties: [{regex: /b/, expression: {i: {$type: 'number'}}}] }})"), - ExtensionsCallbackDisallowExtensions(), kSimpleCollator); - Matcher reserialized(serialize(original.getMatchExpression()), - ExtensionsCallbackDisallowExtensions(), - kSimpleCollator); + Matcher reserialized(serialize(original.getMatchExpression()), kSimpleCollator); ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson(R"({$_internalSchemaAllowedProperties: { properties: ['a'], namePlaceholder: 'i', diff --git a/src/mongo/db/matcher/expression_text.h b/src/mongo/db/matcher/expression_text.h index bb5dbfb77b1..2a3ac4a3c36 100644 --- a/src/mongo/db/matcher/expression_text.h +++ b/src/mongo/db/matcher/expression_text.h @@ -47,6 +47,21 @@ public: return _ftsQuery; } + bool matchesSingleElement(const BSONElement& e, MatchDetails* details = nullptr) const final { + // Text match expressions force the selection of the text index and always generate EXACT + // index bounds (which causes the MatchExpression node to be trimmed), so we don't currently + // implement any explicit text matching logic here. SERVER-17648 tracks the work to + // implement a real text matcher. + // + // TODO: simply returning 'true' here isn't quite correct. First, we should be overriding + // matches() instead of matchesSingleElement(), because the latter is only ever called if + // the matched document has an element with path "_fts". Second, there are scenarios where + // we will use the untrimmed expression tree for matching (for example, when deciding + // whether or not to retry an operation that throws WriteConflictException); in those cases, + // we won't be able to correctly determine whether or not the object matches the expression. + return true; + } + std::unique_ptr<MatchExpression> shallowClone() const final; private: diff --git a/src/mongo/db/matcher/expression_text_base.h b/src/mongo/db/matcher/expression_text_base.h index 65b38f90b43..045a9d88a32 100644 --- a/src/mongo/db/matcher/expression_text_base.h +++ b/src/mongo/db/matcher/expression_text_base.h @@ -63,21 +63,6 @@ public: // Methods inherited from MatchExpression. // - bool matchesSingleElement(const BSONElement& e, MatchDetails* details = nullptr) const final { - // Text match expressions force the selection of the text index and always generate EXACT - // index bounds (which causes the MatchExpression node to be trimmed), so we don't currently - // implement any explicit text matching logic here. SERVER-17648 tracks the work to - // implement a real text matcher. - // - // TODO: simply returning 'true' here isn't quite correct. First, we should be overriding - // matches() instead of matchesSingleElement(), because the latter is only ever called if - // the matched document has an element with path "_fts". Second, there are scenarios where - // we will use the untrimmed expression tree for matching (for example, when deciding - // whether or not to retry an operation that throws WriteConflictException); in those cases, - // we won't be able to correctly determine whether or not the object matches the expression. - return true; - } - void debugString(StringBuilder& debug, int level = 0) const final; void serialize(BSONObjBuilder* out) const final; diff --git a/src/mongo/db/matcher/expression_text_noop.h b/src/mongo/db/matcher/expression_text_noop.h index 8e01d40e70b..429fecff05d 100644 --- a/src/mongo/db/matcher/expression_text_noop.h +++ b/src/mongo/db/matcher/expression_text_noop.h @@ -41,6 +41,10 @@ public: return _ftsQuery; } + bool matchesSingleElement(const BSONElement& e, MatchDetails* details = nullptr) const final { + MONGO_UNREACHABLE; + } + std::unique_ptr<MatchExpression> shallowClone() const final; private: diff --git a/src/mongo/db/matcher/expression_where_noop.cpp b/src/mongo/db/matcher/expression_where_noop.cpp index 23bb7c287e5..c65bf70019c 100644 --- a/src/mongo/db/matcher/expression_where_noop.cpp +++ b/src/mongo/db/matcher/expression_where_noop.cpp @@ -40,7 +40,7 @@ WhereNoOpMatchExpression::WhereNoOpMatchExpression(WhereParams params) : WhereMatchExpressionBase(std::move(params)) {} bool WhereNoOpMatchExpression::matches(const MatchableDocument* doc, MatchDetails* details) const { - return false; + MONGO_UNREACHABLE; } std::unique_ptr<MatchExpression> WhereNoOpMatchExpression::shallowClone() const { diff --git a/src/mongo/db/matcher/expression_with_placeholder.cpp b/src/mongo/db/matcher/expression_with_placeholder.cpp index 34771d2cc8a..97158b6ab33 100644 --- a/src/mongo/db/matcher/expression_with_placeholder.cpp +++ b/src/mongo/db/matcher/expression_with_placeholder.cpp @@ -32,8 +32,6 @@ #include <regex> -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" - namespace mongo { namespace { @@ -105,8 +103,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithFilter = MatchExpressionParser::parse(rawFilter, collator); if (!statusWithFilter.isOK()) { return statusWithFilter.getStatus(); diff --git a/src/mongo/db/matcher/expression_with_placeholder_test.cpp b/src/mongo/db/matcher/expression_with_placeholder_test.cpp index 8fd5f4e456f..bb8abef57ef 100644 --- a/src/mongo/db/matcher/expression_with_placeholder_test.cpp +++ b/src/mongo/db/matcher/expression_with_placeholder_test.cpp @@ -30,7 +30,6 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_with_placeholder.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/unittest.h" @@ -178,6 +177,21 @@ TEST(ExpressionWithPlaceholderTest, WhereExpressionFailsToParse) { ASSERT_NOT_OK(status.getStatus()); } +TEST(ExpressionWithPlaceholderTest, GeoNearExpressionFailsToParse) { + const CollatorInterface* collator = nullptr; + auto rawFilter = + fromjson("{i: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}"); + auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + ASSERT_NOT_OK(status.getStatus()); +} + +TEST(ExpressionWithPlaceholderTest, ExprExpressionFailsToParse) { + const CollatorInterface* collator = nullptr; + auto rawFilter = fromjson("{i: {$expr: 5}}"); + auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); + ASSERT_NOT_OK(status.getStatus()); +} + TEST(ExpressionWithPlaceholderTest, EquivalentIfPlaceholderAndExpressionMatch) { constexpr auto collator = nullptr; auto rawFilter1 = fromjson("{i: 5}}"); diff --git a/src/mongo/db/matcher/extensions_callback_disallow_extensions.cpp b/src/mongo/db/matcher/extensions_callback_disallow_extensions.cpp deleted file mode 100644 index 2c68c97a23a..00000000000 --- a/src/mongo/db/matcher/extensions_callback_disallow_extensions.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (C) 2015 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" - -namespace mongo { - -StatusWithMatchExpression ExtensionsCallbackDisallowExtensions::parseWhere( - BSONElement where) const { - return {Status(ErrorCodes::NoMatchParseContext, "no context for parsing $where")}; -} - -StatusWithMatchExpression ExtensionsCallbackDisallowExtensions::parseText(BSONElement text) const { - return {Status(ErrorCodes::NoMatchParseContext, "no context for parsing $text")}; -} - -} // namespace mongo diff --git a/src/mongo/db/matcher/extensions_callback_disallow_extensions.h b/src/mongo/db/matcher/extensions_callback_disallow_extensions.h deleted file mode 100644 index c641aecd0d1..00000000000 --- a/src/mongo/db/matcher/extensions_callback_disallow_extensions.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (C) 2015 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/db/matcher/extensions_callback.h" - -namespace mongo { - -/** - * ExtensionsCallbackDisallowExtensions produces an error during parsing if expressions which - * require context are present. This implementation of ExtensionsCallback should be used if you wish - * to explicitly ban the use of query language "extensions" such as $text and $where. - */ -class ExtensionsCallbackDisallowExtensions : public ExtensionsCallback { -public: - /** - * Always returns an error status. - */ - StatusWithMatchExpression parseText(BSONElement text) const final; - - /** - * Always returns an error status. - */ - StatusWithMatchExpression parseWhere(BSONElement where) const final; -}; - -} // namespace mongo diff --git a/src/mongo/db/matcher/matcher.cpp b/src/mongo/db/matcher/matcher.cpp index faf0f6f1170..5648a4f15d5 100644 --- a/src/mongo/db/matcher/matcher.cpp +++ b/src/mongo/db/matcher/matcher.cpp @@ -42,11 +42,13 @@ namespace mongo { Matcher::Matcher(const BSONObj& pattern, + const CollatorInterface* collator, + const boost::intrusive_ptr<ExpressionContext>& expCtx, const ExtensionsCallback& extensionsCallback, - const CollatorInterface* collator) + const MatchExpressionParser::AllowedFeatureSet allowedFeatures) : _pattern(pattern) { - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(pattern, extensionsCallback, collator); + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( + pattern, collator, 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 e37a6a0a3b5..382b0dd4e0d 100644 --- a/src/mongo/db/matcher/matcher.h +++ b/src/mongo/db/matcher/matcher.h @@ -36,6 +36,7 @@ #include "mongo/bson/bsonobj.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/matcher/match_details.h" @@ -54,8 +55,11 @@ public: * 'collator' must outlive the returned Matcher and any MatchExpression cloned from it. */ explicit Matcher(const BSONObj& pattern, - const ExtensionsCallback& extensionsCallback, - const CollatorInterface* collator); + const CollatorInterface* collator, + const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr, + const ExtensionsCallback& extensionsCallback = ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatureSet allowedFeatures = + MatchExpressionParser::kBanAllSpecialFeatures); bool matches(const BSONObj& doc, MatchDetails* details = NULL) const; 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 a0e0d6573ba..87c0896193a 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 @@ -31,7 +31,6 @@ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index.h" #include "mongo/unittest/unittest.h" @@ -42,16 +41,14 @@ constexpr CollatorInterface* kSimpleCollator = nullptr; TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchesEmptyQuery) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {}]}}"); - auto expr = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); 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, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(BSON("a" << BSON_ARRAY(1 << 2 << 3 << 4)))); @@ -63,24 +60,21 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchesValidQueries) { TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, RejectsNonArrayElements) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto expr = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); 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, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); 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, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE( expr.getValue()->matchesBSON(BSON("a" << BSON_ARRAY(1 << 2 << BSON_ARRAY(3 << 4) << 4)))); @@ -92,8 +86,7 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, NestedArraysMatchSubexp TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, MatchedQueriesWithDottedPaths) { auto query = fromjson("{'a.b': {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); - auto expr = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE( expr.getValue()->matchesBSON(BSON("a" << BSON("b" << BSON_ARRAY(1 << 2 << 3 << 4))))); 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 b00d45d9172..e19a5bc2637 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 @@ -30,7 +30,6 @@ #include "mongo/bson/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/schema/expression_internal_schema_allowed_properties.h" #include "mongo/unittest/unittest.h" @@ -41,8 +40,7 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, MatchesObjectsWithListedPro auto filter = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['a', 'b']," "namePlaceholder: 'i', patternProperties: [], otherwise: {i: 0}}}"); - auto expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{a: 1, b: 1}"))); @@ -61,8 +59,7 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, MatchesObjectsWithMatchingP ], otherwise: {i: {$type: 'string'}} }})"); - auto expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{puppies: 2, kittens: 3, phoneNum: 1234}"))); @@ -75,8 +72,7 @@ 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, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{a: 6}"))); @@ -95,8 +91,7 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, OtherwiseEnforcedWhenApprop ], otherwise: {i: {$type: 'string'}} }})"); - auto expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{foo: 'bar'}"))); @@ -107,8 +102,7 @@ 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, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); auto clone = expr.getValue()->shallowClone(); ASSERT_TRUE(expr.getValue()->equivalent(clone.get())); 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 d8a1dc63871..b1cbb03d18a 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 @@ -30,7 +30,6 @@ #include "mongo/bson/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/schema/expression_internal_schema_cond.h" #include "mongo/db/matcher/schema/expression_internal_schema_object_match.h" #include "mongo/unittest/unittest.h" @@ -46,14 +45,11 @@ std::unique_ptr<InternalSchemaCondMatchExpression> createCondMatchExpression(BSO auto cond = stdx::make_unique<InternalSchemaCondMatchExpression>(); const CollatorInterface* kSimpleCollator = nullptr; - auto conditionExpr = MatchExpressionParser::parse( - condition, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto conditionExpr = MatchExpressionParser::parse(condition, kSimpleCollator); ASSERT_OK(conditionExpr.getStatus()); - auto thenBranchExpr = MatchExpressionParser::parse( - thenBranch, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto thenBranchExpr = MatchExpressionParser::parse(thenBranch, kSimpleCollator); ASSERT_OK(thenBranchExpr.getStatus()); - auto elseBranchExpr = MatchExpressionParser::parse( - elseBranch, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto elseBranchExpr = MatchExpressionParser::parse(elseBranch, kSimpleCollator); cond->init({{std::move(conditionExpr.getValue()), std::move(thenBranchExpr.getValue()), 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 0f6dc702287..87c1d847beb 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 @@ -31,7 +31,6 @@ #include "mongo/bson/json.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/expression_with_placeholder.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/schema/expression_internal_schema_match_array_index.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/unittest.h" @@ -44,8 +43,7 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, RejectsNonArrays) { auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$gt: 7}}}}}"); - auto expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{foo: 'blah'}"))); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{foo: 7}"))); @@ -56,8 +54,7 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, MatchesArraysWithMatchingElem auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$elemMatch: {'bar': 7}}}}}}"); - auto expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); 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}]]}"))); @@ -65,8 +62,7 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, MatchesArraysWithMatchingElem filter = fromjson( "{baz: {$_internalSchemaMatchArrayIndex:" "{index: 2, namePlaceholder: 'i', expression: {i: {$type: 'string'}}}}}"); - expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{baz: [0, 1, '2']}"))); } @@ -75,16 +71,14 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, DoesNotMatchArrayIfMatchingEl auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$lte: 7}}}}}"); - auto expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); 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, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{foo: [0, 99, 1, 2]}"))); } @@ -93,16 +87,14 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, MatchesIfNotEnoughArrayElemen auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: 1}}}}"); - auto expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); 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, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{foo: ['no', 'no', 'no', 'no']}"))); } @@ -111,8 +103,7 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, EquivalentToClone) { auto filter = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$type: 'number'}}}}}"); - auto expr = MatchExpressionParser::parse( - filter, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(filter, kSimpleCollator); ASSERT_OK(expr.getStatus()); auto clone = expr.getValue()->shallowClone(); ASSERT_TRUE(expr.getValue()->equivalent(clone.get())); 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 89a95e7eff3..d195b901af6 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 @@ -29,7 +29,6 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/matcher.h" #include "mongo/db/matcher/schema/expression_internal_schema_object_match.h" #include "mongo/db/query/collation/collator_interface_mock.h" @@ -40,8 +39,7 @@ namespace mongo { namespace { TEST(InternalSchemaObjectMatchExpression, RejectsNonObjectElements) { - auto subExpr = MatchExpressionParser::parse( - BSON("b" << 1), ExtensionsCallbackDisallowExtensions(), nullptr); + auto subExpr = MatchExpressionParser::parse(BSON("b" << 1), nullptr); ASSERT_OK(subExpr.getStatus()); InternalSchemaObjectMatchExpression objMatch; @@ -56,7 +54,6 @@ TEST(InternalSchemaObjectMatchExpression, RejectsNonObjectElements) { TEST(InternalSchemaObjectMatchExpression, RejectsObjectsThatDontMatch) { auto subExpr = MatchExpressionParser::parse(BSON("b" << BSON("$type" << "string")), - ExtensionsCallbackDisallowExtensions(), nullptr); ASSERT_OK(subExpr.getStatus()); @@ -70,7 +67,6 @@ TEST(InternalSchemaObjectMatchExpression, RejectsObjectsThatDontMatch) { TEST(InternalSchemaObjectMatchExpression, AcceptsObjectsThatMatch) { auto subExpr = MatchExpressionParser::parse(BSON("b" << BSON("$type" << "string")), - ExtensionsCallbackDisallowExtensions(), nullptr); ASSERT_OK(subExpr.getStatus()); @@ -92,7 +88,6 @@ TEST(InternalSchemaObjectMatchExpression, AcceptsObjectsThatMatch) { TEST(InternalSchemaObjectMatchExpression, DottedPathAcceptsObjectsThatMatch) { auto subExpr = MatchExpressionParser::parse(BSON("b.c.d" << BSON("$type" << "string")), - ExtensionsCallbackDisallowExtensions(), nullptr); ASSERT_OK(subExpr.getStatus()); @@ -107,8 +102,7 @@ TEST(InternalSchemaObjectMatchExpression, DottedPathAcceptsObjectsThatMatch) { } TEST(InternalSchemaObjectMatchExpression, EmptyMatchAcceptsAllObjects) { - auto subExpr = - MatchExpressionParser::parse(BSONObj(), ExtensionsCallbackDisallowExtensions(), nullptr); + auto subExpr = MatchExpressionParser::parse(BSONObj(), nullptr); ASSERT_OK(subExpr.getStatus()); InternalSchemaObjectMatchExpression objMatch; @@ -130,8 +124,7 @@ TEST(InternalSchemaObjectMatchExpression, NestedObjectMatchReturnsCorrectPath) { " $or: [{c: {$type: 'string'}}, {c: {$gt: 0}}]" " }}}" " }}}"); - auto objMatch = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), nullptr); + auto objMatch = MatchExpressionParser::parse(query, nullptr); ASSERT_OK(objMatch.getStatus()); ASSERT_EQ(objMatch.getValue()->path(), "a"); @@ -145,8 +138,7 @@ TEST(InternalSchemaObjectMatchExpression, MatchesNestedObjectMatch) { " c: 3" " }}}" " }}}"); - auto objMatch = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), nullptr); + auto objMatch = MatchExpressionParser::parse(query, nullptr); ASSERT_OK(objMatch.getStatus()); ASSERT_FALSE(objMatch.getValue()->matchesBSON(fromjson("{a: 1}"))); @@ -160,20 +152,20 @@ TEST(InternalSchemaObjectMatchExpression, EquivalentReturnsCorrectResults) { " {a: {$_internalSchemaObjectMatch: {" " b: 3" " }}}"); - Matcher objectMatch(query, ExtensionsCallbackDisallowExtensions(), nullptr); + Matcher objectMatch(query, nullptr); query = fromjson( " {a: {$_internalSchemaObjectMatch: {" " b: {$eq: 3}" " }}}"); - Matcher objectMatchEq(query, ExtensionsCallbackDisallowExtensions(), nullptr); + Matcher objectMatchEq(query, nullptr); ASSERT_TRUE(objectMatch.getMatchExpression()->equivalent(objectMatchEq.getMatchExpression())); query = fromjson( " {a: {$_internalSchemaObjectMatch: {" " c: {$eq: 3}" " }}}"); - Matcher objectMatchNotEq(query, ExtensionsCallbackDisallowExtensions(), nullptr); + Matcher objectMatchNotEq(query, nullptr); ASSERT_FALSE( objectMatch.getMatchExpression()->equivalent(objectMatchNotEq.getMatchExpression())); } @@ -184,8 +176,7 @@ TEST(InternalSchemaObjectMatchExpression, SubExpressionRespectsCollator) { "{a: {$_internalSchemaObjectMatch: {" " b: {$eq: 'FOO'}" "}}}"); - auto objectMatch = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), &collator); + auto objectMatch = MatchExpressionParser::parse(query, &collator); ASSERT_OK(objectMatch.getStatus()); ASSERT_TRUE(objectMatch.getValue()->matchesBSON(fromjson("{a: {b: 'FOO'}}"))); @@ -195,8 +186,7 @@ TEST(InternalSchemaObjectMatchExpression, SubExpressionRespectsCollator) { TEST(InternalSchemaObjectMatchExpression, RejectsArraysContainingMatchingSubObject) { auto query = fromjson("{a: {$_internalSchemaObjectMatch: {b: 1}}}"); - auto objMatch = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), nullptr); + auto objMatch = MatchExpressionParser::parse(query, nullptr); ASSERT_OK(objMatch.getStatus()); ASSERT_FALSE(objMatch.getValue()->matchesBSON(fromjson("{a: 1}"))); 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 2e2efe50327..37f6ff4f6c2 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 @@ -33,7 +33,6 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/schema/expression_internal_schema_xor.h" #include "mongo/unittest/unittest.h" @@ -50,8 +49,7 @@ TEST(InternalSchemaXorOp, MatchesNothingWhenHasNoClauses) { TEST(InternalSchemaXorOp, MatchesSingleClause) { BSONObj matchPredicate = fromjson("{$_internalSchemaXor: [{a: { $ne: 5 }}]}"); const CollatorInterface* collator = nullptr; - auto expr = MatchExpressionParser::parse( - matchPredicate, ExtensionsCallbackDisallowExtensions(), collator); + auto expr = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(BSON("a" << 4))); @@ -65,8 +63,7 @@ TEST(InternalSchemaXorOp, MatchesThreeClauses) { BSONObj matchPredicate = fromjson("{$_internalSchemaXor: [{a: { $gt: 10 }}, {a: { $lt: 0 }}, {b: 0}]}"); - auto expr = MatchExpressionParser::parse( - matchPredicate, ExtensionsCallbackDisallowExtensions(), collator); + auto expr = MatchExpressionParser::parse(matchPredicate, collator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(BSON("a" << -1))); @@ -84,8 +81,7 @@ TEST(InternalSchemaXorOp, DoesNotUseElemMatchKey) { BSONObj matchPredicate = fromjson("{$_internalSchemaXor: [{a: 1}, {b: 2}]}"); - auto expr = MatchExpressionParser::parse( - matchPredicate, ExtensionsCallbackDisallowExtensions(), collator); + auto expr = MatchExpressionParser::parse(matchPredicate, collator); 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 74bded78933..af86c2928eb 100644 --- a/src/mongo/db/matcher/schema/expression_parser_schema_test.cpp +++ b/src/mongo/db/matcher/schema/expression_parser_schema_test.cpp @@ -32,7 +32,6 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/expression_type.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/schema/expression_internal_schema_max_items.h" #include "mongo/db/matcher/schema/expression_internal_schema_max_length.h" #include "mongo/db/matcher/schema/expression_internal_schema_min_items.h" @@ -49,8 +48,7 @@ constexpr CollatorInterface* kSimpleCollator = nullptr; TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesIntegerArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinItems" << 2)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -61,8 +59,7 @@ TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesIntegerArgument) { TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesLongArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinItems" << 2LL)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -73,8 +70,7 @@ TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesLongArgument) { TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesDoubleArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinItems" << 2.0)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -85,8 +81,7 @@ TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesDoubleArgumentAsInt TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesDecimalArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinItems" << Decimal128("2"))); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -97,8 +92,7 @@ TEST(MatchExpressionParserSchemaTest, MinItemsCorrectlyParsesDecimalArgumentAsIn TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesIntegerArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxItems" << 2)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -109,8 +103,7 @@ TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesIntegerArgument) { TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesLongArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxItems" << 2LL)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -122,8 +115,7 @@ TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesLongArgument) { TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesDoubleArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxItems" << 2.0)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -134,8 +126,7 @@ TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesDoubleArgumentAsInt TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesDecimalArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxItems" << Decimal128("2"))); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT(!result.getValue()->matchesBSON(BSON("x" << 1))); @@ -146,31 +137,26 @@ TEST(MatchExpressionParserSchemaTest, MaxItemsCorrectlyParsesDecimalArgumentAsIn TEST(MatchExpressionParserSchemaTest, UniqueItemsFailsToParseNonTrueArguments) { auto queryIntArgument = BSON("x" << BSON("$_internalSchemaUniqueItems" << 0)); - auto expr = MatchExpressionParser::parse( - queryIntArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(queryIntArgument, kSimpleCollator); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryStringArgument = BSON("x" << BSON("$_internalSchemaUniqueItems" << "")); - expr = MatchExpressionParser::parse( - queryStringArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryStringArgument, kSimpleCollator); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryDoubleArgument = BSON("x" << BSON("$_internalSchemaUniqueItems" << 1.0)); - expr = MatchExpressionParser::parse( - queryDoubleArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryDoubleArgument, kSimpleCollator); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); auto queryFalseArgument = BSON("x" << BSON("$_internalSchemaUniqueItems" << false)); - expr = MatchExpressionParser::parse( - queryFalseArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryFalseArgument, kSimpleCollator); ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, UniqueItemsParsesTrueBooleanArgument) { auto query = BSON("x" << BSON("$_internalSchemaUniqueItems" << true)); - auto expr = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_FALSE(expr.getValue()->matchesBSON(fromjson("{x: 1}"))); @@ -184,20 +170,17 @@ TEST(MatchExpressionParserSchemaTest, UniqueItemsParsesTrueBooleanArgument) { TEST(MatchExpressionParserSchemaTest, ObjectMatchOnlyAcceptsAnObjectArgument) { auto query = BSON("a" << BSON("$_internalSchemaObjectMatch" << 1)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); query = BSON("a" << BSON("$_internalSchemaObjectMatch" << "string")); - result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); query = BSON( "a" << BSON("$_internalSchemaObjectMatch" << BSON_ARRAY(BSON("a" << 1) << BSON("b" << 1)))); - result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); } @@ -207,8 +190,7 @@ TEST(MatchExpressionParserSchemaTest, ObjectMatchCorrectlyParsesObjects) { " b: {$gte: 0}" " }}" "}"); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT_FALSE(result.getValue()->matchesBSON(fromjson("{a: 1}"))); @@ -225,8 +207,7 @@ TEST(MatchExpressionParserSchemaTest, ObjectMatchCorrectlyParsesNestedObjectMatc " $or: [{c: {$type: 'string'}}, {c: {$gt: 0}}]" " }}" "}}}"); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_TRUE(result.isOK()); ASSERT_FALSE(result.getValue()->matchesBSON(fromjson("{a: 1}"))); @@ -243,8 +224,7 @@ TEST(MatchExpressionParserSchemaTest, ObjectMatchSubExprRejectsTopLevelOperators "{a: {$_internalSchemaObjectMatch: {" " $isolated: 1" "}}}"); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_EQ(result.getStatus(), ErrorCodes::BadValue); } @@ -253,8 +233,7 @@ TEST(MatchExpressionParserSchemaTest, ObjectMatchSubExprRejectsTopLevelOperators // TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesIntegerArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinLength" << 2)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -267,8 +246,7 @@ TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesIntegerArgument) { TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesLongArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinLength" << 2LL)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -281,8 +259,7 @@ TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesLongArgument) { TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesDoubleArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinLength" << 2.0)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -295,8 +272,7 @@ TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesDoubleArgumentAsIn TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesDecimalArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMinLength" << Decimal128("2"))); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT(!result.getValue()->matchesBSON(BSON("x" @@ -310,29 +286,24 @@ TEST(MatchExpressionParserSchemaTest, MinLengthCorrectlyParsesDecimalArgumentAsI TEST(MatchExpressionParserSchemaTest, MinLengthFailsToParseNonIntegerArguments) { auto queryStringArgument = BSON("x" << BSON("$_internalSchemaMinLength" << "abc")); - auto expr = MatchExpressionParser::parse( - queryStringArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(queryStringArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); auto queryEmptyStringArgument = BSON("x" << BSON("$_internalSchemaMinLength" << "")); - expr = MatchExpressionParser::parse( - queryEmptyStringArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryEmptyStringArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); auto queryDoubleArgument = BSON("x" << BSON("$_internalSchemaMinLength" << 1.5)); - expr = MatchExpressionParser::parse( - queryDoubleArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryDoubleArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); auto queryFalseArgument = BSON("x" << BSON("$_internalSchemaMinLength" << false)); - expr = MatchExpressionParser::parse( - queryFalseArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryFalseArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); auto queryArrArgument = BSON("x" << BSON("$_internalSchemaMinLength" << BSON_ARRAY(1))); - expr = MatchExpressionParser::parse( - queryArrArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryArrArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); } @@ -341,8 +312,7 @@ TEST(MatchExpressionParserSchemaTest, MinLengthFailsToParseNonIntegerArguments) // TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesIntegerArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxLength" << 2)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -355,8 +325,7 @@ TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesIntegerArgument) { TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesLongArgument) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxLength" << 2LL)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -369,8 +338,7 @@ TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesLongArgument) { TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesDoubleArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxLength" << 2.0)); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -383,8 +351,7 @@ TEST(MatchExpressionParserSchemaTest, MaxLengthCorrectlyParsesDoubleArgumentAsIn TEST(MatchExpressionParserSchemaTest, MaxLengthorrectlyParsesDecimalArgumentAsInteger) { BSONObj query = BSON("x" << BSON("$_internalSchemaMaxLength" << Decimal128("2"))); - StatusWithMatchExpression result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + StatusWithMatchExpression result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT(result.getValue()->matchesBSON(BSON("x" @@ -398,80 +365,62 @@ TEST(MatchExpressionParserSchemaTest, MaxLengthorrectlyParsesDecimalArgumentAsIn TEST(MatchExpressionParserSchemaTest, MaxLengthFailsToParseNonIntegerArguments) { auto queryStringArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << "abc")); - auto expr = MatchExpressionParser::parse( - queryStringArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(queryStringArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); auto queryEmptyStringArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << "")); - expr = MatchExpressionParser::parse( - queryEmptyStringArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryEmptyStringArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); auto queryDoubleArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << 1.5)); - expr = MatchExpressionParser::parse( - queryDoubleArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryDoubleArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); auto queryFalseArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << false)); - expr = MatchExpressionParser::parse( - queryFalseArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryFalseArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); auto queryArrArgument = BSON("x" << BSON("$_internalSchemaMaxLength" << BSON_ARRAY(1))); - expr = MatchExpressionParser::parse( - queryArrArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + expr = MatchExpressionParser::parse(queryArrArgument, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); } TEST(MatchExpressionParserSchemaTest, CondFailsToParseNonObjectArguments) { auto queryWithInteger = fromjson("{$_internalSchemaCond: [1, {foo: 'bar'}, {baz: 7}]}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse( - queryWithInteger, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus()); + MatchExpressionParser::parse(queryWithInteger, kSimpleCollator).getStatus()); auto queryWithArray = fromjson("{$_internalSchemaCond: [{foo: 'bar'}, [{qux: 3}], {baz: 7}]}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse( - queryWithArray, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus()); + MatchExpressionParser::parse(queryWithArray, kSimpleCollator).getStatus()); auto queryWithString = fromjson("{$_internalSchemaCond: [{foo: 'bar'}, {baz: 7}, 'blah']}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse( - queryWithString, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus()); + MatchExpressionParser::parse(queryWithString, kSimpleCollator).getStatus()); } TEST(MatchExpressionParserSchemaTest, CondFailsToParseIfNotExactlyThreeArguments) { auto queryNoArguments = fromjson("{$_internalSchemaCond: []}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse( - queryNoArguments, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus()); + MatchExpressionParser::parse(queryNoArguments, kSimpleCollator).getStatus()); auto queryOneArgument = fromjson("{$_internalSchemaCond: [{height: 171}]}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse( - queryOneArgument, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus()); + MatchExpressionParser::parse(queryOneArgument, kSimpleCollator).getStatus()); auto queryFourArguments = fromjson( "{$_internalSchemaCond: [{make: 'lamborghini'}, {model: 'ghost'}, {color: 'celadon'}, " "{used: false}]}"); ASSERT_EQ(ErrorCodes::FailedToParse, - MatchExpressionParser::parse( - queryFourArguments, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus()); + MatchExpressionParser::parse(queryFourArguments, kSimpleCollator).getStatus()); } TEST(MatchExpressionParserSchemaTest, CondParsesThreeMatchExpresssions) { auto query = fromjson( "{$_internalSchemaCond: [{climate: 'rainy'}, {clothing: 'jacket'}, {clothing: 'shirt'}]}"); - auto expr = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON( @@ -485,102 +434,79 @@ TEST(MatchExpressionParserSchemaTest, CondParsesThreeMatchExpresssions) { TEST(MatchExpressionParserSchemaTest, MatchArrayIndexFailsToParseNonObjectArguments) { auto query = fromjson("{foo: {$_internalSchemaMatchArrayIndex: 7}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson("{foo: {$_internalSchemaMatchArrayIndex: []}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "[{index: 5, namePlaceholder: 'i', expression: {i: 1}}]}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, MatchArrayIndexFailsToParseIfPlaceholderNotValid) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 5, namePlaceholder: 7, expression: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 5, namePlaceholder: 'Z', expression: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, MatchArrayIndexFailsToParseIfIndexNotANonnegativeInteger) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 'blah', namePlaceholder: 'i', expression: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: -1, namePlaceholder: 'i', expression: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 3.14, namePlaceholder: 'i', expression: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, MatchArrayIndexFailsToParseIfExpressionNotValid) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: 'blah'}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {doesntMatchThePlaceholder: 7}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {$invalid: 'blah'}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::BadValue); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::BadValue); } TEST(MatchExpressionParserSchemaTest, MatchArrayIndexParsesSuccessfully) { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$lt: 0}}}}}"); - auto matchArrayIndex = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto matchArrayIndex = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(matchArrayIndex.getStatus()); ASSERT_TRUE(matchArrayIndex.getValue()->matchesBSON(fromjson("{foo: [-1, 0, 1]}"))); @@ -591,37 +517,32 @@ TEST(MatchExpressionParserSchemaTest, MatchArrayIndexParsesSuccessfully) { TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FailsToParseWithNegativeIndex) { BSONObj matchPredicate = fromjson("{$_internalSchemaAllElemMatchFromIndex: [-2, {a: { $lt: 0 }}]}"); - auto expr = MatchExpressionParser::parse( - matchPredicate, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(matchPredicate, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FailsToParseWithNonObjectExpression) { BSONObj matchPredicate = fromjson("{$_internalSchemaAllElemMatchFromIndex: [-2, 4]}"); - auto expr = MatchExpressionParser::parse( - matchPredicate, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(matchPredicate, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FailsToParseWithInvalidExpression) { BSONObj matchPredicate = fromjson("{$_internalSchemaAllElemMatchFromIndex: [-2, {$fakeExpression: 4}]}"); - auto expr = MatchExpressionParser::parse( - matchPredicate, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(matchPredicate, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FailsToParseWithEmptyArray) { BSONObj matchPredicate = fromjson("{$_internalSchemaAllElemMatchFromIndex: []}"); - auto expr = MatchExpressionParser::parse( - matchPredicate, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(matchPredicate, kSimpleCollator); ASSERT_NOT_OK(expr.getStatus()); } TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, ParsesCorreclyWithValidInput) { auto query = fromjson("{a: {$_internalSchemaAllElemMatchFromIndex: [2, {a: { $lt: 4 }}]}}"); - auto expr = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto expr = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(expr.getStatus()); ASSERT_TRUE(expr.getValue()->matchesBSON(fromjson("{a: [5, 3, 3, 3, 3, 3]}"))); @@ -630,16 +551,14 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, ParsesCorreclyWithValid TEST(MatchExpressionParserSchemaTest, InternalTypeFailsToParseOnTypeMismatch) { BSONObj query = BSON("x" << BSON("$_internalSchemaType" << BSONObj())); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_NOT_OK(result.getStatus()); } TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseNumberAlias) { BSONObj query = BSON("x" << BSON("$_internalSchemaType" << "number")); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT_EQ(result.getValue()->matchType(), MatchExpression::INTERNAL_SCHEMA_TYPE); @@ -650,8 +569,7 @@ TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseNumberAlias) { TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseLongAlias) { BSONObj query = BSON("x" << BSON("$_internalSchemaType" << "long")); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT_EQ(result.getValue()->matchType(), MatchExpression::INTERNAL_SCHEMA_TYPE); @@ -662,8 +580,7 @@ TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseLongAlias) { TEST(MatchExpressionParserSchemaTest, InternalTypeCanParseLongCode) { BSONObj query = BSON("x" << BSON("$_internalSchemaType" << 18)); - auto result = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto result = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(result.getStatus()); ASSERT_EQ(result.getValue()->matchType(), MatchExpression::INTERNAL_SCHEMA_TYPE); @@ -676,88 +593,68 @@ TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfAFieldIsMis auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{namePlaceholder: 'i', patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: []}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfNamePlaceholderNotAString) { auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 7, patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: /i/, patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfNamePlaceholderNotValid) { auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'Capital'," "patternProperties: [], otherwise: {Capital: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::BadValue); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::BadValue); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: '', patternProperties: [], otherwise: {'': 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::BadValue); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::BadValue); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfPropertiesNotAllStrings) { auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [7], namePlaceholder: 'i', patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['x', {}], namePlaceholder: 'i'," "patternProperties: [], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, @@ -765,18 +662,14 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: ['blah'], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 1}, patternProperties: [{regex: /a/, expression: {i: 0}}, 'blah']}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, @@ -784,18 +677,14 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [{foo: 1, bar: 1}], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [{regex: /a/, blah: 0}], otherwise: {i: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, @@ -803,26 +692,20 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{expression: {i: 0}}]}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: 7, expression: {i: 0}}]}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: 'notARegex', expression: {i: 0}}]}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, @@ -830,18 +713,14 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: /a/}]}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: /a/, expression: 'blah'}]}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, @@ -849,64 +728,50 @@ TEST(MatchExpressionParserSchemaTest, auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "otherwise: {i: 0}, patternProperties: [{regex: /a/i, expression: {i: 0}}]}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::BadValue); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::BadValue); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfMismatchingNamePlaceholders) { auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: {j: 1}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [{regex: /a/, expression: {w: 7}}], otherwise: {i: 'foo'}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfOtherwiseIncorrectType) { auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: false}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: [{i: 7}]}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::TypeMismatch); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::TypeMismatch); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesFailsParsingIfOtherwiseNotAValidExpression) { auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: [], namePlaceholder: 'i'," "patternProperties: [], otherwise: {i: {$invalid: 1}}}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::BadValue); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::BadValue); query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: {}}}}}"); - ASSERT_EQ( - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator) - .getStatus(), - ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(query, kSimpleCollator).getStatus(), + ErrorCodes::FailedToParse); } TEST(MatchExpressionParserSchemaTest, AllowedPropertiesParsesSuccessfully) { @@ -914,8 +779,7 @@ 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, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto allowedProperties = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(allowedProperties.getStatus()); ASSERT_TRUE(allowedProperties.getValue()->matchesBSON( @@ -932,8 +796,7 @@ TEST(MatchExpressionParserSchemaTest, AllowedPropertiesAcceptsEmptyPropertiesAnd auto query = fromjson( "{$_internalSchemaAllowedProperties:" "{properties: [], namePlaceholder: 'i', patternProperties: [], otherwise: {i: 1}}}}"); - auto allowedProperties = MatchExpressionParser::parse( - query, ExtensionsCallbackDisallowExtensions(), kSimpleCollator); + auto allowedProperties = MatchExpressionParser::parse(query, kSimpleCollator); ASSERT_OK(allowedProperties.getStatus()); ASSERT_TRUE(allowedProperties.getValue()->matchesBSON(BSONObj())); diff --git a/src/mongo/db/ops/modifier_pull.cpp b/src/mongo/db/ops/modifier_pull.cpp index f3adc0e3538..bb18a80b723 100644 --- a/src/mongo/db/ops/modifier_pull.cpp +++ b/src/mongo/db/ops/modifier_pull.cpp @@ -31,7 +31,6 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/algorithm.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface.h" #include "mongo/db/update/field_checker.h" #include "mongo/db/update/log_builder.h" @@ -123,9 +122,8 @@ Status ModifierPull::init(const BSONElement& modExpr, const Options& opts, bool* } // Build the matcher around the object we built above. Currently, we do not allow $pull - // operations to contain $text/$where clauses, so preserving this behaviour. - StatusWithMatchExpression parseResult = MatchExpressionParser::parse( - _exprObj, ExtensionsCallbackDisallowExtensions(), _collator); + // operations to contain $text/$where/$geoNear/$near/$nearSphere/$expr clauses. + StatusWithMatchExpression parseResult = MatchExpressionParser::parse(_exprObj, _collator); if (!parseResult.isOK()) { return parseResult.getStatus(); } diff --git a/src/mongo/db/ops/modifier_pull_test.cpp b/src/mongo/db/ops/modifier_pull_test.cpp index 6d465442dfe..afefb4349ed 100644 --- a/src/mongo/db/ops/modifier_pull_test.cpp +++ b/src/mongo/db/ops/modifier_pull_test.cpp @@ -40,17 +40,10 @@ #include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" +namespace mongo { + namespace { -using mongo::BSONObj; -using mongo::CollatorInterface; -using mongo::CollatorInterfaceMock; -using mongo::LogBuilder; -using mongo::ModifierInterface; -using mongo::ModifierPull; -using mongo::Status; -using mongo::StringData; -using mongo::fromjson; using mongo::mutablebson::Document; using mongo::mutablebson::Element; @@ -90,6 +83,62 @@ private: ModifierPull _mod; }; +TEST(SimpleMod, InitWithTextFails) { + auto update = fromjson("{$pull: {a: {$text: {$search: 'str'}}}}"); + const CollatorInterface* collator = nullptr; + ModifierPull node; + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + 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; + ModifierPull node; + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + +TEST(SimpleMod, InitWithGeoNearElemFails) { + auto update = + fromjson("{$pull: {a: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}"); + const CollatorInterface* collator = nullptr; + ModifierPull node; + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + +TEST(SimpleMod, InitWithGeoNearObjectFails) { + auto update = fromjson( + "{$pull: {a: {b: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}}"); + const CollatorInterface* collator = nullptr; + ModifierPull node; + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + +TEST(SimpleMod, InitWithExprElemFails) { + auto update = fromjson("{$pull: {a: {$expr: 5}}}"); + const CollatorInterface* collator = nullptr; + ModifierPull node; + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + +TEST(SimpleMod, InitWithExprObjectFails) { + auto update = fromjson("{$pull: {a: {b: {$expr: 5}}}}"); + const CollatorInterface* collator = nullptr; + ModifierPull node; + auto status = node.init(update["$pull"]["a"], ModifierInterface::Options::normal(collator)); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + TEST(SimpleMod, PrepareOKTargetNotFound) { Document doc(fromjson("{}")); Mod mod(fromjson("{ $pull : { a : { $lt : 1 } } }")); @@ -712,3 +761,4 @@ TEST(MatchingRegressions, SERVER_3988) { } } // namespace +} // namespace mongo diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp index 61c3fedf474..8e5d146562e 100644 --- a/src/mongo/db/ops/parsed_delete.cpp +++ b/src/mongo/db/ops/parsed_delete.cpp @@ -90,7 +90,14 @@ Status ParsedDelete::parseQueryToCQ() { qr->setLimit(1); } - auto statusWithCQ = CanonicalQuery::canonicalize(_opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(_opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (statusWithCQ.isOK()) { _canonicalQuery = std::move(statusWithCQ.getValue()); diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index a9bb5658d91..30a2ed15728 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -111,7 +111,14 @@ Status ParsedUpdate::parseQueryToCQ() { qr->setLimit(1); } - auto statusWithCQ = CanonicalQuery::canonicalize(_opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(_opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (statusWithCQ.isOK()) { _canonicalQuery = std::move(statusWithCQ.getValue()); } diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp index bac942e1f31..efac859eed0 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp @@ -33,7 +33,6 @@ #include "mongo/base/init.h" #include "mongo/db/bson/dotted_path_support.h" #include "mongo/db/jsobj.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/pipeline/document.h" #include "mongo/db/pipeline/document_comparator.h" #include "mongo/db/pipeline/document_path_support.h" @@ -544,9 +543,9 @@ intrusive_ptr<DocumentSource> DocumentSourceGraphLookUp::createFromBson( argument.type() == Object); // We don't need to keep ahold of the MatchExpression, but we do need to ensure that - // the specified object is parseable. - auto parsedMatchExpression = MatchExpressionParser::parse( - argument.embeddedObject(), ExtensionsCallbackDisallowExtensions(), nullptr); + // the specified object is parseable and does not contain extensions. + auto parsedMatchExpression = + MatchExpressionParser::parse(argument.embeddedObject(), nullptr); uassert(40186, str::stream() @@ -554,13 +553,6 @@ intrusive_ptr<DocumentSource> DocumentSourceGraphLookUp::createFromBson( << parsedMatchExpression.getStatus().reason(), parsedMatchExpression.isOK()); - uassert(40187, - str::stream() - << "Failed to parse 'restrictSearchWithMatch' option to $graphLookup: " - << "$near not supported.", - !QueryPlannerCommon::hasNode(parsedMatchExpression.getValue().get(), - MatchExpression::GEO_NEAR)); - additionalFilter = argument.embeddedObject().getOwned(); continue; } diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp index 56a51ecd594..5493d21ecd1 100644 --- a/src/mongo/db/pipeline/document_source_match.cpp +++ b/src/mongo/db/pipeline/document_source_match.cpp @@ -361,8 +361,13 @@ bool DocumentSourceMatch::isTextQuery(const BSONObj& query) { void DocumentSourceMatch::joinMatchWith(intrusive_ptr<DocumentSourceMatch> other) { _predicate = BSON("$and" << BSON_ARRAY(_predicate << other->getQuery())); - StatusWithMatchExpression status = uassertStatusOK(MatchExpressionParser::parse( - _predicate, ExtensionsCallbackNoop(), pExpCtx->getCollator(), pExpCtx)); + StatusWithMatchExpression status = uassertStatusOK( + MatchExpressionParser::parse(_predicate, + pExpCtx->getCollator(), + pExpCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kText | + MatchExpressionParser::AllowedFeatures::kExpr)); _expression = std::move(status.getValue()); _dependencies = DepsTracker(_dependencies.getMetadataAvailable()); getDependencies(&_dependencies); @@ -447,27 +452,8 @@ boost::intrusive_ptr<DocumentSourceMatch> DocumentSourceMatch::descendMatchOnPat return new DocumentSourceMatch(query.obj(), expCtx); } -static void uassertNoDisallowedClauses(BSONObj query) { - BSONForEach(e, query) { - // can't use the MatchExpression API because this would segfault the constructor - uassert(16395, - "$where is not allowed inside of a $match aggregation expression", - !str::equals(e.fieldName(), "$where")); - // geo breaks if it is not the first portion of the pipeline - uassert(16424, - "$near is not allowed inside of a $match aggregation expression", - !str::equals(e.fieldName(), "$near")); - uassert(16426, - "$nearSphere is not allowed inside of a $match aggregation expression", - !str::equals(e.fieldName(), "$nearSphere")); - if (e.isABSONObj()) - uassertNoDisallowedClauses(e.Obj()); - } -} - intrusive_ptr<DocumentSourceMatch> DocumentSourceMatch::create( BSONObj filter, const intrusive_ptr<ExpressionContext>& expCtx) { - uassertNoDisallowedClauses(filter); intrusive_ptr<DocumentSourceMatch> match(new DocumentSourceMatch(filter, expCtx)); return match; } @@ -508,8 +494,13 @@ void DocumentSourceMatch::addDependencies(DepsTracker* deps) const { DocumentSourceMatch::DocumentSourceMatch(const BSONObj& query, const intrusive_ptr<ExpressionContext>& pExpCtx) : DocumentSource(pExpCtx), _predicate(query.getOwned()), _isTextQuery(isTextQuery(query)) { - StatusWithMatchExpression status = uassertStatusOK(MatchExpressionParser::parse( - _predicate, ExtensionsCallbackNoop(), pExpCtx->getCollator(), pExpCtx)); + StatusWithMatchExpression status = uassertStatusOK( + MatchExpressionParser::parse(_predicate, + pExpCtx->getCollator(), + pExpCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatures::kText | + MatchExpressionParser::AllowedFeatures::kExpr)); _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 df8a38541aa..c01ae31db9a 100644 --- a/src/mongo/db/pipeline/document_source_match_test.cpp +++ b/src/mongo/db/pipeline/document_source_match_test.cpp @@ -33,8 +33,6 @@ #include "mongo/bson/bsonmisc.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/json.h" -#include "mongo/db/matcher/extensions_callback_noop.h" -#include "mongo/db/matcher/matcher.h" #include "mongo/db/pipeline/aggregation_context_fixture.h" #include "mongo/db/pipeline/document.h" #include "mongo/db/pipeline/document_source_match.h" @@ -381,8 +379,8 @@ DEATH_TEST_F(DocumentSourceMatchTest, "Invariant failure expression::isPathPrefixOf") { const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a.b" << 1 << "b.c" << 1); - const auto matchExpression = unittest::assertGet( - MatchExpressionParser::parse(matchSpec, ExtensionsCallbackNoop(), expCtx->getCollator())); + const auto matchExpression = + unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx->getCollator())); DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); } @@ -391,8 +389,8 @@ DEATH_TEST_F(DocumentSourceMatchTest, "Invariant failure node->matchType()") { const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a" << BSON("$elemMatch" << BSON("a.b" << 1))); - const auto matchExpression = unittest::assertGet( - MatchExpressionParser::parse(matchSpec, ExtensionsCallbackNoop(), expCtx->getCollator())); + const auto matchExpression = + unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx->getCollator())); BSONObjBuilder out; matchExpression->serialize(&out); DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); @@ -406,16 +404,16 @@ DEATH_TEST_F(DocumentSourceMatchTest, "Invariant failure") { const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a" << BSON("$elemMatch" << BSON("$gt" << 0))); - const auto matchExpression = unittest::assertGet( - MatchExpressionParser::parse(matchSpec, ExtensionsCallbackNoop(), expCtx->getCollator())); + const auto matchExpression = + unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx->getCollator())); DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); } 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, ExtensionsCallbackNoop(), expCtx->getCollator())); + const auto matchExpression = + unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx->getCollator())); const auto descendedMatch = DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index ce3fa915f75..2425978a9a0 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -426,7 +426,12 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> attemptToGetExe const ExtensionsCallbackReal extensionsCallback(pExpCtx->opCtx, &nss); - auto cq = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback, pExpCtx); + auto cq = CanonicalQuery::canonicalize(opCtx, + std::move(qr), + pExpCtx, + extensionsCallback, + MatchExpressionParser::AllowedFeatures::kText | + MatchExpressionParser::AllowedFeatures::kExpr); if (!cq.isOK()) { // Return an error instead of uasserting, since there are cases where the combination of diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index a8e512c22d9..17d18c6b798 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -98,14 +98,22 @@ bool matchExpressionLessThan(const MatchExpression* lhs, const MatchExpression* return matchExpressionComparator(lhs, rhs) < 0; } +bool parsingCanProduceNoopMatchNodes(const ExtensionsCallback& extensionsCallback, + MatchExpressionParser::AllowedFeatureSet allowedFeatures) { + return extensionsCallback.hasNoopExtensions() && + (allowedFeatures & MatchExpressionParser::AllowedFeatures::kText || + allowedFeatures & MatchExpressionParser::AllowedFeatures::kJavascript); +} + } // namespace // static StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( OperationContext* opCtx, const QueryMessage& qm, + const boost::intrusive_ptr<ExpressionContext>& expCtx, const ExtensionsCallback& extensionsCallback, - const boost::intrusive_ptr<ExpressionContext>& expCtx) { + MatchExpressionParser::AllowedFeatureSet allowedFeatures) { // Make QueryRequest. auto qrStatus = QueryRequest::fromLegacyQueryMessage(qm); if (!qrStatus.isOK()) { @@ -113,15 +121,16 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( } return CanonicalQuery::canonicalize( - opCtx, std::move(qrStatus.getValue()), extensionsCallback, expCtx); + opCtx, std::move(qrStatus.getValue()), expCtx, extensionsCallback, allowedFeatures); } // static StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( OperationContext* opCtx, std::unique_ptr<QueryRequest> qr, + const boost::intrusive_ptr<ExpressionContext>& expCtx, const ExtensionsCallback& extensionsCallback, - const boost::intrusive_ptr<ExpressionContext>& expCtx) { + MatchExpressionParser::AllowedFeatureSet allowedFeatures) { auto qrStatus = qr->validate(); if (!qrStatus.isOK()) { return qrStatus; @@ -138,8 +147,8 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( } // Make MatchExpression. - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(qr->getFilter(), extensionsCallback, collator.get(), expCtx); + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( + qr->getFilter(), collator.get(), expCtx, extensionsCallback, allowedFeatures); if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } @@ -149,7 +158,10 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery()); Status initStatus = - cq->init(std::move(qr), extensionsCallback, me.release(), std::move(collator)); + cq->init(std::move(qr), + parsingCanProduceNoopMatchNodes(extensionsCallback, allowedFeatures), + me.release(), + std::move(collator)); if (!initStatus.isOK()) { return initStatus; @@ -159,10 +171,7 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( // static StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - OperationContext* opCtx, - const CanonicalQuery& baseQuery, - MatchExpression* root, - const ExtensionsCallback& extensionsCallback) { + OperationContext* opCtx, const CanonicalQuery& baseQuery, MatchExpression* root) { // TODO: we should be passing the filter corresponding to 'root' to the QR rather than the base // query's filter, baseQuery.getQueryRequest().getFilter(). auto qr = stdx::make_unique<QueryRequest>(baseQuery.nss()); @@ -183,8 +192,10 @@ 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), extensionsCallback, root->shallowClone().release(), std::move(collator)); + Status initStatus = cq->init(std::move(qr), + baseQuery.canHaveNoopMatchNodes(), + root->shallowClone().release(), + std::move(collator)); if (!initStatus.isOK()) { return initStatus; @@ -193,13 +204,13 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( } Status CanonicalQuery::init(std::unique_ptr<QueryRequest> qr, - const ExtensionsCallback& extensionsCallback, + bool canHaveNoopMatchNodes, MatchExpression* root, std::unique_ptr<CollatorInterface> collator) { _qr = std::move(qr); _collator = std::move(collator); - _hasNoopExtensions = extensionsCallback.hasNoopExtensions(); + _canHaveNoopMatchNodes = canHaveNoopMatchNodes; _isIsolated = QueryRequest::isQueryIsolated(_qr->getFilter()); // Normalize, sort and validate tree. @@ -215,8 +226,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, extensionsCallback); + Status projStatus = ParsedProjection::make(_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 f2466fe0c66..54360808233 100644 --- a/src/mongo/db/query/canonical_query.h +++ b/src/mongo/db/query/canonical_query.h @@ -33,6 +33,7 @@ #include "mongo/db/dbmessage.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/query/collation/collator_interface.h" #include "mongo/db/query/parsed_projection.h" #include "mongo/db/query/query_request.h" @@ -55,8 +56,10 @@ public: static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( OperationContext* opCtx, const QueryMessage& qm, - const ExtensionsCallback& extensionsCallback, - const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr); + const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr, + const ExtensionsCallback& extensionsCallback = ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatureSet allowedFeatures = + MatchExpressionParser::kBanAllSpecialFeatures); /** * If parsing succeeds, returns a std::unique_ptr<CanonicalQuery> representing the parsed @@ -68,8 +71,10 @@ public: static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( OperationContext* opCtx, std::unique_ptr<QueryRequest> qr, - const ExtensionsCallback&, - const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr); + const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr, + const ExtensionsCallback& extensionsCallback = ExtensionsCallbackNoop(), + MatchExpressionParser::AllowedFeatureSet allowedFeatures = + MatchExpressionParser::kBanAllSpecialFeatures); /** * For testing or for internal clients to use. @@ -82,11 +87,9 @@ public: * * Does not take ownership of 'root'. */ - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - OperationContext* opCtx, - const CanonicalQuery& baseQuery, - MatchExpression* root, - const ExtensionsCallback& extensionsCallback); + static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(OperationContext* opCtx, + const CanonicalQuery& baseQuery, + MatchExpression* root); /** * Returns true if "query" describes an exact-match query on _id, possibly with @@ -163,14 +166,16 @@ public: static size_t countNodes(const MatchExpression* root, MatchExpression::MatchType type); /** - * Returns true if this canonical query converted extensions such as $where and $text into - * no-ops during parsing. + * Returns true if this canonical query may have converted extensions such as $where and $text + * into no-ops during parsing. This will be the case if it allowed $where and $text in parsing, + * but parsed using an ExtensionsCallbackNoop. This does not guarantee that a $where or $text + * existed in the query. * * Queries with a no-op extension context are special because they can be parsed and planned, * but they cannot be executed. */ - bool hasNoopExtensions() const { - return _hasNoopExtensions; + bool canHaveNoopMatchNodes() const { + return _canHaveNoopMatchNodes; } /** @@ -186,7 +191,7 @@ private: CanonicalQuery() {} Status init(std::unique_ptr<QueryRequest> qr, - const ExtensionsCallback& extensionsCallback, + bool canHaveNoopMatchNodes, MatchExpression* root, std::unique_ptr<CollatorInterface> collator); @@ -199,7 +204,7 @@ private: std::unique_ptr<CollatorInterface> _collator; - bool _hasNoopExtensions = false; + bool _canHaveNoopMatchNodes = false; bool _isIsolated; }; diff --git a/src/mongo/db/query/canonical_query_test.cpp b/src/mongo/db/query/canonical_query_test.cpp index 542f1ac2477..691079a9560 100644 --- a/src/mongo/db/query/canonical_query_test.cpp +++ b/src/mongo/db/query/canonical_query_test.cpp @@ -30,10 +30,10 @@ #include "mongo/client/dbclientinterface.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/index_tag.h" @@ -55,8 +55,13 @@ static const NamespaceString nss("testdb.testcoll"); */ MatchExpression* parseMatchExpression(const BSONObj& obj) { const CollatorInterface* collator = nullptr; + const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackNoop(), collator); + MatchExpressionParser::parse(obj, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); if (!status.isOK()) { mongoutils::str::stream ss; ss << "failed to parse query: " << obj.toString() @@ -329,8 +334,7 @@ TEST(CanonicalQueryTest, IsValidSortKeyMetaProjection) { const bool isExplain = false; auto qr = assertGet(QueryRequest::makeFromFindCommand( nss, fromjson("{find: 'testcoll', projection: {foo: {$meta: 'sortKey'}}}"), isExplain)); - auto cq = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto cq = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_NOT_OK(cq.getStatus()); } @@ -341,8 +345,7 @@ TEST(CanonicalQueryTest, IsValidSortKeyMetaProjection) { nss, fromjson("{find: 'testcoll', projection: {foo: {$meta: 'sortKey'}}, sort: {bar: 1}}"), isExplain)); - auto cq = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto cq = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(cq.getStatus()); } } @@ -439,8 +442,7 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson(queryStr)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } @@ -455,8 +457,7 @@ std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, qr->setFilter(fromjson(queryStr)); qr->setSort(fromjson(sortStr)); qr->setProj(fromjson(projStr)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } @@ -568,12 +569,10 @@ TEST(CanonicalQueryTest, CanonicalizeFromBaseQuery) { const std::string cmdStr = "{find:'bogusns', filter:{$or:[{a:1,b:1},{a:1,c:1}]}, projection:{a:1}, sort:{b:1}}"; auto qr = assertGet(QueryRequest::makeFromFindCommand(nss, fromjson(cmdStr), isExplain)); - auto baseCq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto baseCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr))); MatchExpression* firstClauseExpr = baseCq->root()->getChild(0); - auto childCq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), *baseCq, firstClauseExpr, ExtensionsCallbackDisallowExtensions())); + auto childCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), *baseCq, firstClauseExpr)); // Descriptive test. The childCq's filter should be the relevant $or clause, rather than the // entire query predicate. @@ -590,8 +589,7 @@ TEST(CanonicalQueryTest, CanonicalQueryFromQRWithNoCollation) { auto opCtx = serviceContext.makeOperationContext(); auto qr = stdx::make_unique<QueryRequest>(nss); - auto cq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr))); ASSERT_TRUE(cq->getCollator() == nullptr); } @@ -602,8 +600,7 @@ TEST(CanonicalQueryTest, CanonicalQueryFromQRWithCollation) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setCollation(BSON("locale" << "reverse")); - auto cq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr))); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); ASSERT_TRUE(CollatorInterface::collatorsMatch(cq->getCollator(), &collator)); } @@ -614,11 +611,9 @@ TEST(CanonicalQueryTest, CanonicalQueryFromBaseQueryWithNoCollation) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{$or:[{a:1,b:1},{a:1,c:1}]}")); - auto baseCq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto baseCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr))); MatchExpression* firstClauseExpr = baseCq->root()->getChild(0); - auto childCq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), *baseCq, firstClauseExpr, ExtensionsCallbackDisallowExtensions())); + auto childCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), *baseCq, firstClauseExpr)); ASSERT_TRUE(baseCq->getCollator() == nullptr); ASSERT_TRUE(childCq->getCollator() == nullptr); } @@ -631,11 +626,9 @@ TEST(CanonicalQueryTest, CanonicalQueryFromBaseQueryWithCollation) { qr->setFilter(fromjson("{$or:[{a:1,b:1},{a:1,c:1}]}")); qr->setCollation(BSON("locale" << "reverse")); - auto baseCq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto baseCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr))); MatchExpression* firstClauseExpr = baseCq->root()->getChild(0); - auto childCq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), *baseCq, firstClauseExpr, ExtensionsCallbackDisallowExtensions())); + auto childCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), *baseCq, firstClauseExpr)); ASSERT(baseCq->getCollator()); ASSERT(childCq->getCollator()); ASSERT_TRUE(*(childCq->getCollator()) == *(baseCq->getCollator())); @@ -647,8 +640,7 @@ TEST(CanonicalQueryTest, SettingCollatorUpdatesCollatorAndMatchExpression) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: 'foo', b: {$in: ['bar', 'baz']}}")); - auto cq = assertGet(CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr))); ASSERT_EQUALS(2U, cq->root()->numChildren()); auto firstChild = cq->root()->getChild(0); auto secondChild = cq->root()->getChild(1); diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index da2a71e2068..ca7fe029325 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -536,8 +536,14 @@ std::string runQuery(OperationContext* opCtx, beginQueryOp(opCtx, nss, q.query, q.ntoreturn, q.ntoskip); // Parse the qm into a CanonicalQuery. - - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, q, ExtensionsCallbackReal(opCtx, &nss)); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + q, + expCtx, + ExtensionsCallbackReal(opCtx, &nss), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { uasserted(17287, str::stream() << "Can't canonicalize query: " diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 3f89d4c0148..60d3b166d04 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -55,7 +55,6 @@ #include "mongo/db/exec/update.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/index_names.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/ops/update_lifecycle.h" @@ -295,7 +294,7 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, // document, so we don't support covered projections. However, we might use the // simple inclusion fast path. if (NULL != canonicalQuery->getProj()) { - ProjectionStageParams params(ExtensionsCallbackReal(opCtx, &collection->ns())); + ProjectionStageParams params; params.projObj = canonicalQuery->getProj()->getProjObj(); params.collator = canonicalQuery->getCollator(); @@ -657,8 +656,7 @@ StatusWith<unique_ptr<PlanStage>> applyProjection(OperationContext* opCtx, invariant(!proj.isEmpty()); ParsedProjection* rawParsedProj; - Status ppStatus = ParsedProjection::make( - proj.getOwned(), cq->root(), &rawParsedProj, ExtensionsCallbackDisallowExtensions()); + Status ppStatus = ParsedProjection::make(proj.getOwned(), cq->root(), &rawParsedProj); if (!ppStatus.isOK()) { return ppStatus; } @@ -678,7 +676,7 @@ StatusWith<unique_ptr<PlanStage>> applyProjection(OperationContext* opCtx, "Cannot use a $meta sortKey projection in findAndModify commands."}; } - ProjectionStageParams params(ExtensionsCallbackReal(opCtx, &nsString)); + ProjectionStageParams params; params.projObj = proj; params.collator = cq->getCollator(); params.fullExpression = cq->root(); @@ -998,7 +996,14 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorGroup( const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { return statusWithCQ.getStatus(); } @@ -1228,12 +1233,16 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCount( qr->setHint(request.getHint()); qr->setExplain(explain); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize( opCtx, std::move(qr), + expCtx, collection ? static_cast<const ExtensionsCallback&>( ExtensionsCallbackReal(opCtx, &collection->ns())) - : static_cast<const ExtensionsCallback&>(ExtensionsCallbackNoop())); + : static_cast<const ExtensionsCallback&>(ExtensionsCallbackNoop()), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { return statusWithCQ.getStatus(); @@ -1484,7 +1493,14 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDistinct( auto qr = stdx::make_unique<QueryRequest>(parsedDistinct->getQuery()->getQueryRequest()); qr->setProj(projection); - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { return statusWithCQ.getStatus(); } diff --git a/src/mongo/db/query/get_executor_test.cpp b/src/mongo/db/query/get_executor_test.cpp index a1dc1f88648..002d4a427b3 100644 --- a/src/mongo/db/query/get_executor_test.cpp +++ b/src/mongo/db/query/get_executor_test.cpp @@ -37,7 +37,6 @@ #include "mongo/bson/simple_bsonobj_comparator.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/query_settings.h" #include "mongo/db/query/query_test_service_context.h" #include "mongo/stdx/unordered_set.h" @@ -65,8 +64,7 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, qr->setFilter(fromjson(queryStr)); qr->setSort(fromjson(sortStr)); qr->setProj(fromjson(projStr)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } diff --git a/src/mongo/db/query/index_bounds_builder_test.cpp b/src/mongo/db/query/index_bounds_builder_test.cpp index 7b400b2c62c..f8bff9d6984 100644 --- a/src/mongo/db/query/index_bounds_builder_test.cpp +++ b/src/mongo/db/query/index_bounds_builder_test.cpp @@ -35,7 +35,6 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/expression_index.h" #include "mongo/unittest/unittest.h" @@ -60,8 +59,7 @@ double NaN = numeric_limits<double>::quiet_NaN(); */ MatchExpression* parseMatchExpression(const BSONObj& obj) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); ASSERT_TRUE(status.isOK()); MatchExpression* expr(status.getValue().release()); return expr; diff --git a/src/mongo/db/query/parsed_distinct.cpp b/src/mongo/db/query/parsed_distinct.cpp index 8b024533326..da071756726 100644 --- a/src/mongo/db/query/parsed_distinct.cpp +++ b/src/mongo/db/query/parsed_distinct.cpp @@ -201,7 +201,13 @@ StatusWith<ParsedDistinct> ParsedDistinct::parse(OperationContext* opCtx, qr->setExplain(isExplain); - auto cq = CanonicalQuery::canonicalize(opCtx, std::move(qr), extensionsCallback); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto cq = CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + extensionsCallback, + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!cq.isOK()) { return cq.getStatus(); } diff --git a/src/mongo/db/query/parsed_distinct_test.cpp b/src/mongo/db/query/parsed_distinct_test.cpp index 68554d2637c..f751534cca4 100644 --- a/src/mongo/db/query/parsed_distinct_test.cpp +++ b/src/mongo/db/query/parsed_distinct_test.cpp @@ -31,7 +31,7 @@ #include <algorithm> #include "mongo/bson/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/pipeline/aggregation_request.h" #include "mongo/db/query/parsed_distinct.h" #include "mongo/db/query/query_test_service_context.h" @@ -51,7 +51,7 @@ TEST(ParsedDistinctTest, ConvertToAggregationNoQuery) { auto pd = ParsedDistinct::parse(opCtx, testns, fromjson("{distinct: 'testcoll', key: 'x'}"), - ExtensionsCallbackDisallowExtensions(), + ExtensionsCallbackNoop(), !isExplain); ASSERT_OK(pd.getStatus()); @@ -109,7 +109,7 @@ TEST(ParsedDistinctTest, ConvertToAggregationWithAllOptions) { << "aComment" << "maxTimeMS" << 100), - ExtensionsCallbackDisallowExtensions(), + ExtensionsCallbackNoop(), !isExplain); ASSERT_OK(pd.getStatus()); @@ -155,7 +155,7 @@ TEST(ParsedDistinctTest, ConvertToAggregationWithQuery) { auto pd = ParsedDistinct::parse(opCtx, testns, fromjson("{distinct: 'testcoll', key: 'y', query: {z: 7}}"), - ExtensionsCallbackDisallowExtensions(), + ExtensionsCallbackNoop(), !isExplain); ASSERT_OK(pd.getStatus()); @@ -196,7 +196,7 @@ TEST(ParsedDistinctTest, ExplainNotIncludedWhenConvertingToAggregationCommand) { auto pd = ParsedDistinct::parse(opCtx, testns, fromjson("{distinct: 'testcoll', key: 'x'}"), - ExtensionsCallbackDisallowExtensions(), + ExtensionsCallbackNoop(), isExplain); ASSERT_OK(pd.getStatus()); diff --git a/src/mongo/db/query/parsed_projection.cpp b/src/mongo/db/query/parsed_projection.cpp index d83b9e786ee..575c5d5dff5 100644 --- a/src/mongo/db/query/parsed_projection.cpp +++ b/src/mongo/db/query/parsed_projection.cpp @@ -28,9 +28,8 @@ #include "mongo/db/query/parsed_projection.h" -#include "mongo/db/query/query_request.h" - #include "mongo/bson/simple_bsonobj_comparator.h" +#include "mongo/db/query/query_request.h" namespace mongo { @@ -49,8 +48,7 @@ using std::string; // static Status ParsedProjection::make(const BSONObj& spec, const MatchExpression* const query, - ParsedProjection** out, - const ExtensionsCallback& extensionsCallback) { + ParsedProjection** out) { // Whether we're including or excluding fields. enum class IncludeExclude { kUninitialized, kInclude, kExclude }; IncludeExclude includeExclude = IncludeExclude::kUninitialized; @@ -128,10 +126,11 @@ Status ParsedProjection::make(const BSONObj& spec, // is ok because the parsed MatchExpression is not used after being created. We are // only parsing here in order to ensure that the elemMatch projection is valid. // - // TODO: Is there a faster way of validating the elemMatchObj? + // Match expression extensions such as $text, $where, $geoNear, $near, $nearSphere, + // and $expr are not allowed in $elemMatch projections. const CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(elemMatchObj, extensionsCallback, collator); + MatchExpressionParser::parse(elemMatchObj, collator); 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 0730f39c18c..2f273c5d303 100644 --- a/src/mongo/db/query/parsed_projection.h +++ b/src/mongo/db/query/parsed_projection.h @@ -47,8 +47,7 @@ public: */ static Status make(const BSONObj& spec, const MatchExpression* const query, - ParsedProjection** out, - const ExtensionsCallback& extensionsCallback); + ParsedProjection** out); /** * Returns true if the projection requires match details from the query, diff --git a/src/mongo/db/query/parsed_projection_test.cpp b/src/mongo/db/query/parsed_projection_test.cpp index fa17165932d..22046f8b531 100644 --- a/src/mongo/db/query/parsed_projection_test.cpp +++ b/src/mongo/db/query/parsed_projection_test.cpp @@ -31,7 +31,6 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_always_boolean.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/unittest/unittest.h" #include <memory> @@ -49,13 +48,11 @@ using namespace mongo; unique_ptr<ParsedProjection> createParsedProjection(const BSONObj& query, const BSONObj& projObj) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(query, collator); ASSERT(statusWithMatcher.isOK()); std::unique_ptr<MatchExpression> queryMatchExpr = std::move(statusWithMatcher.getValue()); ParsedProjection* out = NULL; - Status status = ParsedProjection::make( - projObj, queryMatchExpr.get(), &out, ExtensionsCallbackDisallowExtensions()); + Status status = ParsedProjection::make(projObj, queryMatchExpr.get(), &out); if (!status.isOK()) { FAIL(mongoutils::str::stream() << "failed to parse projection " << projObj << " (query: " << query @@ -80,13 +77,11 @@ void assertInvalidProjection(const char* queryStr, const char* projStr) { BSONObj query = fromjson(queryStr); BSONObj projObj = fromjson(projStr); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(query, collator); ASSERT(statusWithMatcher.isOK()); std::unique_ptr<MatchExpression> queryMatchExpr = std::move(statusWithMatcher.getValue()); ParsedProjection* out = NULL; - Status status = ParsedProjection::make( - projObj, queryMatchExpr.get(), &out, ExtensionsCallbackDisallowExtensions()); + Status status = ParsedProjection::make(projObj, queryMatchExpr.get(), &out); std::unique_ptr<ParsedProjection> destroy(out); ASSERT(!status.isOK()); } @@ -163,6 +158,24 @@ TEST(ParsedProjectionTest, InvalidPositionalOperatorProjections) { assertInvalidProjection("{a: [1, 2, 3]}", "{'.$': 1}"); } +TEST(ParsedProjectionTest, InvalidElemMatchTextProjection) { + assertInvalidProjection("{}", "{a: {$elemMatch: {$text: {$search: 'str'}}}}"); +} + +TEST(ParsedProjectionTest, InvalidElemMatchWhereProjection) { + assertInvalidProjection("{}", "{a: {$elemMatch: {$where: 'this.a == this.b'}}}"); +} + +TEST(ParsedProjectionTest, InvalidElemMatchGeoNearProjection) { + assertInvalidProjection( + "{}", + "{a: {$elemMatch: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}"); +} + +TEST(ParsedProjectionTest, InvalidElemMatchExprProjection) { + assertInvalidProjection("{}", "{a: {$elemMatch: {$expr: 5}}}"); +} + TEST(ParsedProjectionTest, ValidPositionalOperatorProjections) { createParsedProjection("{a: 1}", "{'a.$': 1}"); createParsedProjection("{a: 1}", "{'a.foo.bar.$': 1}"); @@ -191,15 +204,13 @@ TEST(ParsedProjectionTest, InvalidPositionalProjectionDefaultPathMatchExpression ParsedProjection* out = NULL; BSONObj projObj = fromjson("{'a.$': 1}"); - Status status = ParsedProjection::make( - projObj, queryMatchExpr.get(), &out, ExtensionsCallbackDisallowExtensions()); + Status status = ParsedProjection::make(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, ExtensionsCallbackDisallowExtensions()); + status = ParsedProjection::make(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 3cc90e3429a..11635c4b665 100644 --- a/src/mongo/db/query/plan_cache_indexability_test.cpp +++ b/src/mongo/db/query/plan_cache_indexability_test.cpp @@ -30,7 +30,6 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.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" @@ -41,8 +40,7 @@ namespace { std::unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj, const CollatorInterface* collator = nullptr) { - StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); if (!status.isOK()) { FAIL(str::stream() << "failed to parse query: " << obj.toString() << ". Reason: " << status.getStatus().toString()); diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp index dd5eead802c..b94ab624fe1 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -38,7 +38,8 @@ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.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/db/query/plan_ranker.h" #include "mongo/db/query/query_knobs.h" @@ -72,8 +73,13 @@ unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(queryObj); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } @@ -95,8 +101,13 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, qr->setSort(fromjson(sortStr)); qr->setProj(fromjson(projStr)); qr->setCollation(fromjson(collationStr)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } @@ -125,8 +136,13 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, qr->setHint(fromjson(hintStr)); qr->setMin(fromjson(minStr)); qr->setMax(fromjson(maxStr)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } @@ -159,8 +175,13 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, qr->setMax(fromjson(maxStr)); qr->setSnapshot(snapshot); qr->setExplain(explain); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } @@ -170,8 +191,13 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); + MatchExpressionParser::parse(obj, + collator, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); if (!status.isOK()) { str::stream ss; ss << "failed to parse query: " << obj.toString() @@ -563,8 +589,13 @@ protected: qr->setMin(minObj); qr->setMax(maxObj); qr->setSnapshot(snapshot); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); Status s = QueryPlanner::plan(*statusWithCQ.getValue(), params, &solns); ASSERT_OK(s); @@ -585,8 +616,13 @@ protected: std::unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); Status s = QueryPlanner::plan(*statusWithCQ.getValue(), params, &solns); ASSERT_OK(s); @@ -666,8 +702,13 @@ protected: qr->setSort(sort); qr->setProj(proj); qr->setCollation(collation); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto statusWithCQ = + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue()); diff --git a/src/mongo/db/query/planner_ixselect_test.cpp b/src/mongo/db/query/planner_ixselect_test.cpp index 1c273db8716..bacd8990a56 100644 --- a/src/mongo/db/query/planner_ixselect_test.cpp +++ b/src/mongo/db/query/planner_ixselect_test.cpp @@ -34,7 +34,6 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/index_tag.h" #include "mongo/unittest/unittest.h" @@ -54,8 +53,7 @@ using std::vector; */ unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression status = - MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); ASSERT_TRUE(status.isOK()); return std::move(status.getValue()); } diff --git a/src/mongo/db/query/query_planner_test.cpp b/src/mongo/db/query/query_planner_test.cpp index 17e6bb09daa..1fcc20df418 100644 --- a/src/mongo/db/query/query_planner_test.cpp +++ b/src/mongo/db/query/query_planner_test.cpp @@ -35,7 +35,6 @@ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_always_boolean.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/query/query_planner_test_fixture.h" @@ -4268,8 +4267,7 @@ TEST_F(QueryPlannerTest, CacheDataFromTaggedTreeFailsOnBadInput) { auto qr = stdx::make_unique<QueryRequest>(NamespaceString("test.collection")); qr->setFilter(BSON("a" << 3)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue()); scopedCq->root()->setTag(new IndexTag(1)); @@ -4284,8 +4282,7 @@ TEST_F(QueryPlannerTest, TagAccordingToCacheFailsOnBadInput) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << 3)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue()); @@ -4314,8 +4311,7 @@ TEST_F(QueryPlannerTest, TagAccordingToCacheFailsOnBadInput) { // Regenerate canonical query in order to clear tags. auto newQR = stdx::make_unique<QueryRequest>(nss); newQR->setFilter(BSON("a" << 3)); - statusWithCQ = CanonicalQuery::canonicalize( - opCtx.get(), std::move(newQR), ExtensionsCallbackDisallowExtensions()); + statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(newQR)); ASSERT_OK(statusWithCQ.getStatus()); scopedCq = std::move(statusWithCQ.getValue()); diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp index 3376d24eb04..ae04eec22a4 100644 --- a/src/mongo/db/query/query_planner_test_fixture.cpp +++ b/src/mongo/db/query/query_planner_test_fixture.cpp @@ -35,9 +35,9 @@ #include <algorithm> #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/query_knobs.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/query/query_planner_test_lib.h" @@ -249,8 +249,13 @@ void QueryPlannerTest::runQueryFull(const BSONObj& query, qr->setMin(minObj); qr->setMax(maxObj); qr->setSnapshot(snapshot); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), ExtensionsCallbackNoop()); + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); cq = std::move(statusWithCQ.getValue()); @@ -328,8 +333,13 @@ void QueryPlannerTest::runInvalidQueryFull(const BSONObj& query, qr->setMin(minObj); qr->setMax(maxObj); qr->setSnapshot(snapshot); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), ExtensionsCallbackNoop()); + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); cq = std::move(statusWithCQ.getValue()); @@ -349,8 +359,13 @@ void QueryPlannerTest::runQueryAsCommand(const BSONObj& cmdObj) { std::unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), ExtensionsCallbackNoop()); + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); cq = std::move(statusWithCQ.getValue()); @@ -370,8 +385,13 @@ void QueryPlannerTest::runInvalidQueryAsCommand(const BSONObj& cmdObj) { std::unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), ExtensionsCallbackNoop()); + CanonicalQuery::canonicalize(opCtx.get(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); ASSERT_OK(statusWithCQ.getStatus()); cq = std::move(statusWithCQ.getValue()); @@ -452,8 +472,7 @@ 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, collator); if (!status.isOK()) { FAIL(str::stream() << "failed to parse query: " << obj.toString() << ". Reason: " << status.getStatus().toString()); diff --git a/src/mongo/db/query/query_planner_test_lib.cpp b/src/mongo/db/query/query_planner_test_lib.cpp index bd647280d3a..c1920f821d0 100644 --- a/src/mongo/db/query/query_planner_test_lib.cpp +++ b/src/mongo/db/query/query_planner_test_lib.cpp @@ -36,7 +36,6 @@ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_factory_mock.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/query/query_solution.h" @@ -67,8 +66,8 @@ bool filterMatches(const BSONObj& testFilter, testCollator = std::move(collator.getValue()); } - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - testFilter, ExtensionsCallbackDisallowExtensions(), testCollator.get()); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(testFilter, testCollator.get()); 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 a3a76deaa43..821b1efd4e9 100644 --- a/src/mongo/db/query/query_solution_test.cpp +++ b/src/mongo/db/query/query_solution_test.cpp @@ -30,7 +30,6 @@ #include "mongo/bson/bsontypes.h" #include "mongo/bson/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/index_entry.h" @@ -687,12 +686,10 @@ TEST(QuerySolutionTest, IndexScanNodeHasFieldExcludesSimpleBoundsStringFieldWhen std::unique_ptr<ParsedProjection> createParsedProjection(const BSONObj& query, const BSONObj& projObj) { const CollatorInterface* collator = nullptr; - StatusWithMatchExpression queryMatchExpr = - MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression queryMatchExpr = MatchExpressionParser::parse(query, collator); ASSERT(queryMatchExpr.isOK()); ParsedProjection* out = nullptr; - Status status = ParsedProjection::make( - projObj, queryMatchExpr.getValue().get(), &out, ExtensionsCallbackDisallowExtensions()); + Status status = ParsedProjection::make(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/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index 96fc04c3499..1319ac07f52 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -140,7 +140,7 @@ PlanStage* buildStages(OperationContext* opCtx, return nullptr; } - ProjectionStageParams params(ExtensionsCallbackReal(opCtx, &collection->ns())); + ProjectionStageParams params; params.projObj = pn->projection; params.collator = cq.getCollator(); @@ -390,7 +390,7 @@ bool StageBuilder::build(OperationContext* opCtx, // queries that disallow extensions, can be properly executed. If the query does not have // $text/$where context (and $text/$where are allowed), then no attempt should be made to // execute the query. - invariant(!cq.hasNoopExtensions()); + invariant(!cq.canHaveNoopMatchNodes()); if (nullptr == wsIn || nullptr == rootOut) { return false; diff --git a/src/mongo/db/repl/apply_ops.cpp b/src/mongo/db/repl/apply_ops.cpp index c4d05d660fd..b6d4e3a2c2a 100644 --- a/src/mongo/db/repl/apply_ops.cpp +++ b/src/mongo/db/repl/apply_ops.cpp @@ -43,7 +43,6 @@ #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/index/index_descriptor.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/matcher.h" #include "mongo/db/op_observer.h" #include "mongo/db/operation_context.h" @@ -269,10 +268,9 @@ Status _checkPrecondition(OperationContext* opCtx, } const CollatorInterface* collator = collection->getDefaultCollator(); - // Apply-ops would never have a $where/$text matcher. Using the "DisallowExtensions" - // callback ensures that parsing will throw an error if $where or $text are found. - Matcher matcher( - preCondition["res"].Obj(), ExtensionsCallbackDisallowExtensions(), collator); + // applyOps does not allow any extensions, such as $text, $where, $geoNear, $near, + // $nearSphere, or $expr. + Matcher matcher(preCondition["res"].Obj(), collator); if (!matcher.matches(realres)) { result->append("got", realres); result->append("whatFailed", preCondition); diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp index 24f00dfff4c..8f4bb4ae246 100644 --- a/src/mongo/db/ttl.cpp +++ b/src/mongo/db/ttl.cpp @@ -49,7 +49,6 @@ #include "mongo/db/db_raii.h" #include "mongo/db/exec/delete.h" #include "mongo/db/index/index_descriptor.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/ops/insert.h" #include "mongo/db/query/internal_plans.h" @@ -243,8 +242,7 @@ private: BSON(keyFieldName << BSON("$gte" << kDawnOfTime << "$lte" << expirationTime)); auto qr = stdx::make_unique<QueryRequest>(collectionNSS); qr->setFilter(query); - auto canonicalQuery = CanonicalQuery::canonicalize( - opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto canonicalQuery = CanonicalQuery::canonicalize(opCtx, std::move(qr)); invariantOK(canonicalQuery.getStatus()); DeleteStageParams params; diff --git a/src/mongo/db/update/path_support_test.cpp b/src/mongo/db/update/path_support_test.cpp index 339781699e1..3de5e8eff00 100644 --- a/src/mongo/db/update/path_support_test.cpp +++ b/src/mongo/db/update/path_support_test.cpp @@ -48,7 +48,6 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" #include "mongo/util/mongoutils/str.h" @@ -590,9 +589,7 @@ TEST_F(ArrayDoc, CreatePathAtFailsIfElemFoundIsArrayAndIdxFoundFieldIsNonNumeric static MatchExpression* makeExpr(const BSONObj& exprBSON) { const CollatorInterface* collator = nullptr; - return MatchExpressionParser::parse(exprBSON, ExtensionsCallbackDisallowExtensions(), collator) - .getValue() - .release(); + return MatchExpressionParser::parse(exprBSON, collator).getValue().release(); } static void assertContains(const EqualityMatches& equalities, const BSONObj& wrapped) { diff --git a/src/mongo/db/update/pull_node.cpp b/src/mongo/db/update/pull_node.cpp index 5842718c388..9ef4e02724b 100644 --- a/src/mongo/db/update/pull_node.cpp +++ b/src/mongo/db/update/pull_node.cpp @@ -31,7 +31,6 @@ #include "mongo/db/update/pull_node.h" #include "mongo/db/matcher/copyable_match_expression.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/collation/collator_interface.h" namespace mongo { @@ -43,9 +42,7 @@ namespace mongo { class PullNode::ObjectMatcher final : public PullNode::ElementMatcher { public: ObjectMatcher(BSONObj matchCondition, const CollatorInterface* collator) - : _matchExpr( - matchCondition, stdx::make_unique<ExtensionsCallbackDisallowExtensions>(), collator) { - } + : _matchExpr(matchCondition, collator) {} std::unique_ptr<ElementMatcher> clone() const final { return stdx::make_unique<ObjectMatcher>(*this); @@ -77,9 +74,7 @@ private: class PullNode::WrappedObjectMatcher final : public PullNode::ElementMatcher { public: WrappedObjectMatcher(BSONElement matchCondition, const CollatorInterface* collator) - : _matchExpr(matchCondition.wrap(""), - stdx::make_unique<ExtensionsCallbackDisallowExtensions>(), - collator) {} + : _matchExpr(matchCondition.wrap(""), collator) {} std::unique_ptr<ElementMatcher> clone() const final { return stdx::make_unique<WrappedObjectMatcher>(*this); diff --git a/src/mongo/db/update/pull_node_test.cpp b/src/mongo/db/update/pull_node_test.cpp index d54640c0d1a..0fa4c83dcc0 100644 --- a/src/mongo/db/update/pull_node_test.cpp +++ b/src/mongo/db/update/pull_node_test.cpp @@ -63,6 +63,62 @@ TEST(PullNodeTest, InitWithBadTopLevelOperatorFails) { ASSERT_EQUALS(ErrorCodes::BadValue, status); } +TEST(PullNodeTest, InitWithTextFails) { + auto update = fromjson("{$pull: {a: {$text: {$search: 'str'}}}}"); + const CollatorInterface* collator = nullptr; + PullNode node; + auto status = node.init(update["$pull"]["a"], collator); + 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; + PullNode node; + auto status = node.init(update["$pull"]["a"], collator); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + +TEST(PullNodeTest, InitWithGeoNearElemFails) { + auto update = + fromjson("{$pull: {a: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}"); + const CollatorInterface* collator = nullptr; + PullNode node; + auto status = node.init(update["$pull"]["a"], collator); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + +TEST(PullNodeTest, InitWithGeoNearObjectFails) { + auto update = fromjson( + "{$pull: {a: {b: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}}"); + const CollatorInterface* collator = nullptr; + PullNode node; + auto status = node.init(update["$pull"]["a"], collator); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + +TEST(PullNodeTest, InitWithExprElemFails) { + auto update = fromjson("{$pull: {a: {$expr: 5}}}"); + const CollatorInterface* collator = nullptr; + PullNode node; + auto status = node.init(update["$pull"]["a"], collator); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + +TEST(PullNodeTest, InitWithExprObjectFails) { + auto update = fromjson("{$pull: {a: {b: {$expr: 5}}}}"); + const CollatorInterface* collator = nullptr; + PullNode node; + auto status = node.init(update["$pull"]["a"], collator); + ASSERT_NOT_OK(status); + ASSERT_EQUALS(ErrorCodes::BadValue, status); +} + TEST_F(PullNodeTest, TargetNotFound) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); const CollatorInterface* collator = nullptr; @@ -361,6 +417,62 @@ TEST_F(PullNodeTest, ApplyStringMatchAfterSetCollator) { ASSERT_FALSE(doc2.isInPlaceModeEnabled()); } +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)); + + // First without a collator. + mutablebson::Document doc(fromjson("{ a : ['a', 'b', 'c', 'd'] }")); + setPathTaken("a"); + auto result = node.apply(getApplyParams(doc.root()["a"])); + ASSERT_FALSE(result.noop); + ASSERT_FALSE(result.indexesAffected); + ASSERT_EQUALS(fromjson("{a: ['a', 'b']}"), doc); + ASSERT_FALSE(doc.isInPlaceModeEnabled()); + + // Now with a collator. + CollatorInterfaceMock mockCollator(CollatorInterfaceMock::MockType::kAlwaysEqual); + node.setCollator(&mockCollator); + mutablebson::Document doc2(fromjson("{ a : ['a', 'b', 'c', 'd'] }")); + resetApplyParams(); + setPathTaken("a"); + result = node.apply(getApplyParams(doc2.root()["a"])); + ASSERT_FALSE(result.noop); + ASSERT_FALSE(result.indexesAffected); + ASSERT_EQUALS(fromjson("{a: []}"), doc2); + ASSERT_FALSE(doc2.isInPlaceModeEnabled()); +} + +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)); + + // First without a collator. + mutablebson::Document doc(fromjson("{a : [{b: 'w'}, {b: 'x'}, {b: 'y'}, {b: 'z'}]}")); + setPathTaken("a"); + auto result = node.apply(getApplyParams(doc.root()["a"])); + ASSERT_FALSE(result.noop); + ASSERT_FALSE(result.indexesAffected); + ASSERT_EQUALS(fromjson("{a : [{b: 'w'}, {b: 'x'}, {b: 'z'}]}"), doc); + ASSERT_FALSE(doc.isInPlaceModeEnabled()); + + // Now with a collator. + CollatorInterfaceMock mockCollator(CollatorInterfaceMock::MockType::kAlwaysEqual); + node.setCollator(&mockCollator); + mutablebson::Document doc2(fromjson("{a : [{b: 'w'}, {b: 'x'}, {b: 'y'}, {b: 'z'}]}")); + resetApplyParams(); + setPathTaken("a"); + result = node.apply(getApplyParams(doc2.root()["a"])); + ASSERT_FALSE(result.noop); + ASSERT_FALSE(result.indexesAffected); + ASSERT_EQUALS(fromjson("{a: []}"), doc2); + ASSERT_FALSE(doc2.isInPlaceModeEnabled()); +} + TEST_F(PullNodeTest, SetCollatorDoesNotAffectClone) { auto update = fromjson("{$pull : {a: 'c'}}"); PullNode node; diff --git a/src/mongo/db/update/update_driver.cpp b/src/mongo/db/update/update_driver.cpp index 6d1d89e7f77..52700a13f80 100644 --- a/src/mongo/db/update/update_driver.cpp +++ b/src/mongo/db/update/update_driver.cpp @@ -214,8 +214,14 @@ Status UpdateDriver::populateDocumentWithQueryFields(OperationContext* opCtx, // $where/$text clauses do not make sense, hence empty ExtensionsCallback. auto qr = stdx::make_unique<QueryRequest>(NamespaceString("")); qr->setFilter(query); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx, std::move(qr), ExtensionsCallbackNoop()); + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { return statusWithCQ.getStatus(); } diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp index 1db6048e282..4af64c6be73 100644 --- a/src/mongo/dbtests/documentsourcetests.cpp +++ b/src/mongo/dbtests/documentsourcetests.cpp @@ -36,7 +36,6 @@ #include "mongo/db/dbdirectclient.h" #include "mongo/db/exec/multi_plan.h" #include "mongo/db/exec/plan_stage.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/pipeline/dependencies.h" #include "mongo/db/pipeline/document_source.h" #include "mongo/db/pipeline/document_source_cursor.h" @@ -101,8 +100,7 @@ protected: if (hint) { qr->setHint(*hint); } - auto cq = uassertStatusOK(CanonicalQuery::canonicalize( - &_opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto cq = uassertStatusOK(CanonicalQuery::canonicalize(&_opCtx, std::move(qr))); auto exec = uassertStatusOK( getExecutor(&_opCtx, ctx.getCollection(), std::move(cq), PlanExecutor::NO_YIELD)); diff --git a/src/mongo/dbtests/executor_registry.cpp b/src/mongo/dbtests/executor_registry.cpp index 46ec9c1e3a0..8d961c51eff 100644 --- a/src/mongo/dbtests/executor_registry.cpp +++ b/src/mongo/dbtests/executor_registry.cpp @@ -43,7 +43,6 @@ #include "mongo/db/exec/plan_stage.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/plan_executor.h" #include "mongo/db/service_context.h" #include "mongo/dbtests/dbtests.h" @@ -78,8 +77,7 @@ public: // Create a plan executor to hold it auto qr = stdx::make_unique<QueryRequest>(nss); - auto statusWithCQ = CanonicalQuery::canonicalize( - &_opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); diff --git a/src/mongo/dbtests/matchertests.cpp b/src/mongo/dbtests/matchertests.cpp index 095df864a1e..3d20d60fde3 100644 --- a/src/mongo/dbtests/matchertests.cpp +++ b/src/mongo/dbtests/matchertests.cpp @@ -36,9 +36,9 @@ #include "mongo/db/client.h" #include "mongo/db/db_raii.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/matcher/matcher.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/dbtests/dbtests.h" #include "mongo/util/timer.h" @@ -62,7 +62,7 @@ public: void run() { BSONObj query = fromjson("{\"a\":\"b\"}"); const CollatorInterface* collator = nullptr; - M m(query, ExtensionsCallbackDisallowExtensions(), collator); + M m(query, collator); ASSERT(m.matches(fromjson("{\"a\":\"b\"}"))); } }; @@ -73,7 +73,7 @@ public: void run() { BSONObj query = fromjson("{\"a\":5}"); const CollatorInterface* collator = nullptr; - M m(query, ExtensionsCallbackDisallowExtensions(), collator); + M m(query, collator); ASSERT(m.matches(fromjson("{\"a\":5}"))); } }; @@ -85,7 +85,7 @@ public: BSONObjBuilder query; query.append("a", 5); const CollatorInterface* collator = nullptr; - M m(query.done(), ExtensionsCallbackDisallowExtensions(), collator); + M m(query.done(), collator); ASSERT(m.matches(fromjson("{\"a\":5}"))); } }; @@ -96,7 +96,7 @@ public: void run() { BSONObj query = fromjson("{\"a\":{\"$gt\":4}}"); const CollatorInterface* collator = nullptr; - M m(query, ExtensionsCallbackDisallowExtensions(), collator); + M m(query, collator); BSONObjBuilder b; b.append("a", 5); ASSERT(m.matches(b.done())); @@ -112,7 +112,7 @@ public: ASSERT_EQUALS(NumberInt, query["a"].embeddedObject()["$in"].embeddedObject()["0"].type()); const CollatorInterface* collator = nullptr; - M m(query, ExtensionsCallbackDisallowExtensions(), collator); + M m(query, collator); { BSONObjBuilder b; @@ -140,7 +140,7 @@ class MixedNumericEmbedded { public: void run() { const CollatorInterface* collator = nullptr; - M m(BSON("a" << BSON("x" << 1)), ExtensionsCallbackDisallowExtensions(), collator); + M m(BSON("a" << BSON("x" << 1)), collator); ASSERT(m.matches(BSON("a" << BSON("x" << 1)))); ASSERT(m.matches(BSON("a" << BSON("x" << 1.0)))); } @@ -151,7 +151,7 @@ class Size { public: void run() { const CollatorInterface* collator = nullptr; - M m(fromjson("{a:{$size:4}}"), ExtensionsCallbackDisallowExtensions(), collator); + M m(fromjson("{a:{$size:4}}"), collator); ASSERT(m.matches(fromjson("{a:[1,2,3,4]}"))); ASSERT(!m.matches(fromjson("{a:[1,2,3]}"))); ASSERT(!m.matches(fromjson("{a:[1,2,3,'a','b']}"))); @@ -164,9 +164,7 @@ class WithinBox { public: void run() { const CollatorInterface* collator = nullptr; - M m(fromjson("{loc:{$within:{$box:[{x: 4, y:4},[6,6]]}}}"), - ExtensionsCallbackDisallowExtensions(), - collator); + M m(fromjson("{loc:{$within:{$box:[{x: 4, y:4},[6,6]]}}}"), collator); ASSERT(!m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: [4,4]}"))); ASSERT(m.matches(fromjson("{loc: [5,5]}"))); @@ -180,9 +178,7 @@ 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]]}}}"), - ExtensionsCallbackDisallowExtensions(), - collator); + M m(fromjson("{loc:{$within:{$polygon:[{x:0,y:0},[0,5],[5,5],[5,0]]}}}"), collator); ASSERT(m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: [4,4]}"))); ASSERT(m.matches(fromjson("{loc: {x:5,y:5}}"))); @@ -196,9 +192,7 @@ class WithinCenter { public: void run() { const CollatorInterface* collator = nullptr; - M m(fromjson("{loc:{$within:{$center:[{x:30,y:30},10]}}}"), - ExtensionsCallbackDisallowExtensions(), - collator); + M m(fromjson("{loc:{$within:{$center:[{x:30,y:30},10]}}}"), collator); ASSERT(!m.matches(fromjson("{loc: [3,4]}"))); ASSERT(m.matches(fromjson("{loc: {x:30,y:30}}"))); ASSERT(m.matches(fromjson("{loc: [20,30]}"))); @@ -215,7 +209,7 @@ class ElemMatchKey { public: void run() { const CollatorInterface* collator = nullptr; - M matcher(BSON("a.b" << 1), ExtensionsCallbackDisallowExtensions(), collator); + M matcher(BSON("a.b" << 1), collator); MatchDetails details; details.requestElemMatchKey(); ASSERT(!details.hasElemMatchKey()); @@ -236,10 +230,13 @@ public: AutoGetCollectionForReadCommand ctx(&opCtx, nss); const CollatorInterface* collator = nullptr; + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); M m(BSON("$where" << "function(){ return this.a == 1; }"), + collator, + expCtx, ExtensionsCallbackReal(&opCtx, &nss), - collator); + MatchExpressionParser::AllowedFeatures::kJavascript); ASSERT(m.matches(BSON("a" << 1))); ASSERT(!m.matches(BSON("a" << 2))); } @@ -250,7 +247,7 @@ class TimingBase { public: long dotime(const BSONObj& patt, const BSONObj& obj) { const CollatorInterface* collator = nullptr; - M m(patt, ExtensionsCallbackDisallowExtensions(), collator); + M m(patt, collator); Timer t; for (int i = 0; i < 900000; i++) { if (!m.matches(obj)) { @@ -283,7 +280,6 @@ public: const CollatorInterface* collator = nullptr; M matcher(BSON("a" << "string"), - ExtensionsCallbackDisallowExtensions(), collator); ASSERT(!matcher.matches(BSON("a" << "string2"))); @@ -298,7 +294,6 @@ public: CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); M matcher(BSON("a" << "string"), - ExtensionsCallbackDisallowExtensions(), &collator); ASSERT(matcher.matches(BSON("a" << "string2"))); diff --git a/src/mongo/dbtests/oplogstarttests.cpp b/src/mongo/dbtests/oplogstarttests.cpp index 66e0a122875..5742271a6a7 100644 --- a/src/mongo/dbtests/oplogstarttests.cpp +++ b/src/mongo/dbtests/oplogstarttests.cpp @@ -30,7 +30,6 @@ #include "mongo/db/dbdirectclient.h" #include "mongo/db/exec/oplogstart.h" #include "mongo/db/exec/working_set.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/repl/repl_settings.h" #include "mongo/db/service_context.h" @@ -74,8 +73,7 @@ protected: void setupFromQuery(const BSONObj& query) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); - auto statusWithCQ = CanonicalQuery::canonicalize( - &_opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); _cq = std::move(statusWithCQ.getValue()); _oplogws.reset(new WorkingSet()); diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp index a1750c90154..80399f73b06 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -43,7 +43,6 @@ #include "mongo/db/exec/multi_plan.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/query_knobs.h" @@ -201,8 +200,7 @@ public: { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << 100 << "b" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); verify(statusWithCQ.isOK()); cq = std::move(statusWithCQ.getValue()); ASSERT(cq.get()); @@ -221,8 +219,7 @@ public: { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << 100 << "b" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); verify(statusWithCQ.isOK()); cq = std::move(statusWithCQ.getValue()); } @@ -257,8 +254,7 @@ public: // Run the query {a:1, b:{$gt:1}. auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << 1 << "b" << BSON("$gt" << 1))); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); verify(statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -299,8 +295,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << 27)); qr->setProj(BSON("_id" << 0 << "a" << 1 << "b" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -334,8 +329,7 @@ public: // There is no data that matches this query but we don't know that until EOF. auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << 1 << "b" << 1 << "c" << 99)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -374,8 +368,7 @@ public: qr->setFilter(BSON("a" << 2)); qr->setProj(BSON("_id" << 0 << "a" << 1 << "b" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -408,8 +401,7 @@ public: // Run the query {a:N+1, b:1}. (No such document.) auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << N + 1 << "b" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); verify(statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -445,8 +437,7 @@ public: // Run the query {a:N+1, b:1}. (No such document.) auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << BSON("$gte" << N + 1) << "b" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); verify(statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -476,8 +467,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("_id" << BSON("$gte" << 20 << "$lte" << 200))); qr->setSort(BSON("c" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -506,8 +496,7 @@ public: // Look for A Space Odyssey. auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("foo" << 2001)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); verify(statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -541,8 +530,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << 1)); qr->setSort(BSON("d" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -579,8 +567,7 @@ public: // than an index scan on 'a'. auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: 1, b: 1, c: {$gte: 5000}}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -612,8 +599,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: 9, b: {$ne: 10}, c: 9}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); diff --git a/src/mongo/dbtests/query_plan_executor.cpp b/src/mongo/dbtests/query_plan_executor.cpp index 839f69cff5d..4b1a1eef0e4 100644 --- a/src/mongo/dbtests/query_plan_executor.cpp +++ b/src/mongo/dbtests/query_plan_executor.cpp @@ -44,7 +44,6 @@ #include "mongo/db/exec/working_set_common.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/pipeline/document_source_cursor.h" #include "mongo/db/pipeline/expression_context_for_test.h" @@ -105,8 +104,7 @@ public: // Canonicalize the query. auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(filterObj); - auto statusWithCQ = CanonicalQuery::canonicalize( - &_opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr)); verify(statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); verify(NULL != cq.get()); @@ -157,8 +155,7 @@ public: unique_ptr<PlanStage> root(new FetchStage(&_opCtx, ws.get(), ix, NULL, coll)); auto qr = stdx::make_unique<QueryRequest>(nss); - auto statusWithCQ = CanonicalQuery::canonicalize( - &_opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr)); verify(statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); verify(NULL != cq.get()); diff --git a/src/mongo/dbtests/query_stage_cached_plan.cpp b/src/mongo/dbtests/query_stage_cached_plan.cpp index 196e21e2a7c..d020971fecd 100644 --- a/src/mongo/dbtests/query_stage_cached_plan.cpp +++ b/src/mongo/dbtests/query_stage_cached_plan.cpp @@ -38,7 +38,6 @@ #include "mongo/db/exec/queued_data_stage.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/get_executor.h" @@ -123,8 +122,7 @@ public: // Query can be answered by either index on "a" or index on "b". auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: {$gte: 8}, b: 1}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); const std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -191,8 +189,7 @@ public: // Query can be answered by either index on "a" or index on "b". auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{a: {$gte: 8}, b: 1}")); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); const std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp index d8e0088807c..d17dbdbbcfa 100644 --- a/src/mongo/dbtests/query_stage_collscan.cpp +++ b/src/mongo/dbtests/query_stage_collscan.cpp @@ -42,7 +42,6 @@ #include "mongo/db/exec/plan_stage.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/plan_executor.h" #include "mongo/db/storage/record_store.h" @@ -94,8 +93,8 @@ public: // Make the filter. const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filterObj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(filterObj, collator); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue()); diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp index a66c4d5ab38..130cd6e3e4b 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -42,7 +42,6 @@ #include "mongo/db/exec/working_set.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/dbtests/dbtests.h" namespace QueryStageCount { @@ -150,8 +149,8 @@ public: unique_ptr<WorkingSet> ws(new WorkingSet); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - request.getQuery(), ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(request.getQuery(), collator); ASSERT(statusWithMatcher.isOK()); unique_ptr<MatchExpression> expression = std::move(statusWithMatcher.getValue()); diff --git a/src/mongo/dbtests/query_stage_delete.cpp b/src/mongo/dbtests/query_stage_delete.cpp index b3892c41ffa..97e7166a478 100644 --- a/src/mongo/dbtests/query_stage_delete.cpp +++ b/src/mongo/dbtests/query_stage_delete.cpp @@ -41,7 +41,6 @@ #include "mongo/db/exec/collection_scan.h" #include "mongo/db/exec/delete.h" #include "mongo/db/exec/queued_data_stage.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/service_context.h" #include "mongo/dbtests/dbtests.h" @@ -106,8 +105,7 @@ public: unique_ptr<CanonicalQuery> canonicalize(const BSONObj& query) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); - auto statusWithCQ = CanonicalQuery::canonicalize( - &_opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } diff --git a/src/mongo/dbtests/query_stage_fetch.cpp b/src/mongo/dbtests/query_stage_fetch.cpp index ee8c5ec2b19..e866d2df9c9 100644 --- a/src/mongo/dbtests/query_stage_fetch.cpp +++ b/src/mongo/dbtests/query_stage_fetch.cpp @@ -43,7 +43,6 @@ #include "mongo/db/exec/queued_data_stage.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/dbtests/dbtests.h" #include "mongo/stdx/memory.h" @@ -195,8 +194,8 @@ public: // Make the filter. BSONObj filterObj = BSON("foo" << 6); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filterObj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(filterObj, collator); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue()); diff --git a/src/mongo/dbtests/query_stage_multiplan.cpp b/src/mongo/dbtests/query_stage_multiplan.cpp index c0043192e51..0f02e120110 100644 --- a/src/mongo/dbtests/query_stage_multiplan.cpp +++ b/src/mongo/dbtests/query_stage_multiplan.cpp @@ -42,7 +42,6 @@ #include "mongo/db/exec/queued_data_stage.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/plan_executor.h" @@ -165,8 +164,8 @@ public: // Make the filter. BSONObj filterObj = BSON("foo" << 7); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filterObj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(filterObj, collator); verify(statusWithMatcher.isOK()); unique_ptr<MatchExpression> filter = std::move(statusWithMatcher.getValue()); // Make the stage. @@ -176,8 +175,7 @@ public: // Hand the plans off to the MPS. auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("foo" << 7)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); verify(statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); verify(NULL != cq.get()); @@ -235,8 +233,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("a" << 1 << "b" << 1)); qr->setSort(BSON("b" << 1)); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); verify(statusWithCQ.isOK()); unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); ASSERT(NULL != cq.get()); @@ -340,8 +337,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("x" << 1)); - auto cq = uassertStatusOK(CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto cq = uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(qr))); unique_ptr<MultiPlanStage> mps = make_unique<MultiPlanStage>(&_opCtx, ctx.getCollection(), cq.get()); @@ -417,8 +413,7 @@ public: // Create the executor (Matching all documents). auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("foo" << BSON("$gte" << 0))); - auto cq = uassertStatusOK(CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto cq = uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(qr))); auto exec = uassertStatusOK(getExecutor(&_opCtx, coll, std::move(cq), PlanExecutor::NO_YIELD)); diff --git a/src/mongo/dbtests/query_stage_subplan.cpp b/src/mongo/dbtests/query_stage_subplan.cpp index 4450434b977..bca6559c25e 100644 --- a/src/mongo/dbtests/query_stage_subplan.cpp +++ b/src/mongo/dbtests/query_stage_subplan.cpp @@ -38,8 +38,8 @@ #include "mongo/db/exec/subplan.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/matcher/extensions_callback_noop.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/get_executor.h" #include "mongo/dbtests/dbtests.h" @@ -79,8 +79,13 @@ protected: bool isExplain = false; auto qr = unittest::assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain)); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto cq = unittest::assertGet( - CanonicalQuery::canonicalize(opCtx(), std::move(qr), ExtensionsCallbackNoop())); + CanonicalQuery::canonicalize(opCtx(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures)); return cq; } @@ -115,8 +120,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -161,8 +165,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -219,8 +222,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -278,8 +280,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); - auto statusWithCQ = CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -461,8 +462,7 @@ public: { BSONObj queryObj = fromjson("{$or:[{a:1}, {b:1}], e:1}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression expr = MatchExpressionParser::parse( - queryObj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, collator); ASSERT_OK(expr.getStatus()); std::unique_ptr<MatchExpression> rewrittenExpr = SubplanStage::rewriteToRootedOr(std::move(expr.getValue())); @@ -479,8 +479,7 @@ public: { BSONObj queryObj = fromjson("{$or:[{a:1}, {b:1}], e:1, f:1}"); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression expr = MatchExpressionParser::parse( - queryObj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, collator); ASSERT_OK(expr.getStatus()); std::unique_ptr<MatchExpression> rewrittenExpr = SubplanStage::rewriteToRootedOr(std::move(expr.getValue())); @@ -497,8 +496,7 @@ public: { 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, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression expr = MatchExpressionParser::parse(queryObj, collator); ASSERT_OK(expr.getStatus()); std::unique_ptr<MatchExpression> rewrittenExpr = SubplanStage::rewriteToRootedOr(std::move(expr.getValue())); @@ -534,8 +532,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); - auto cq = unittest::assertGet(CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto cq = unittest::assertGet(CanonicalQuery::canonicalize(opCtx(), std::move(qr))); Collection* collection = ctx.getCollection(); @@ -596,8 +593,7 @@ public: auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(fromjson("{$or: [{a: 1}, {a: {$ne:1}}]}")); qr->setSort(BSON("d" << 1)); - auto cq = unittest::assertGet(CanonicalQuery::canonicalize( - opCtx(), std::move(qr), ExtensionsCallbackDisallowExtensions())); + auto cq = unittest::assertGet(CanonicalQuery::canonicalize(opCtx(), std::move(qr))); Collection* collection = ctx.getCollection(); diff --git a/src/mongo/dbtests/query_stage_tests.cpp b/src/mongo/dbtests/query_stage_tests.cpp index 474dad6fb4d..6b7893798e5 100644 --- a/src/mongo/dbtests/query_stage_tests.cpp +++ b/src/mongo/dbtests/query_stage_tests.cpp @@ -39,7 +39,6 @@ #include "mongo/db/exec/plan_stage.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/plan_executor.h" #include "mongo/dbtests/dbtests.h" @@ -83,8 +82,8 @@ public: AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(ns())); const CollatorInterface* collator = nullptr; - StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( - filterObj, ExtensionsCallbackDisallowExtensions(), collator); + StatusWithMatchExpression statusWithMatcher = + MatchExpressionParser::parse(filterObj, collator); 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 4a066a33813..7ccd6058545 100644 --- a/src/mongo/dbtests/query_stage_update.cpp +++ b/src/mongo/dbtests/query_stage_update.cpp @@ -45,7 +45,6 @@ #include "mongo/db/exec/working_set.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/ops/update_lifecycle_impl.h" #include "mongo/db/ops/update_request.h" @@ -91,8 +90,7 @@ public: unique_ptr<CanonicalQuery> canonicalize(const BSONObj& query) { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); - auto statusWithCQ = CanonicalQuery::canonicalize( - &_opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); + auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr)); ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } diff --git a/src/mongo/s/chunk_manager.cpp b/src/mongo/s/chunk_manager.cpp index 1b09f52f577..3ec757bb218 100644 --- a/src/mongo/s/chunk_manager.cpp +++ b/src/mongo/s/chunk_manager.cpp @@ -113,8 +113,14 @@ void ChunkManager::getShardIdsForQuery(OperationContext* opCtx, qr->setCollation(_defaultCollator->getSpec().toBSON()); } - std::unique_ptr<CanonicalQuery> cq = uassertStatusOK( - CanonicalQuery::canonicalize(opCtx, std::move(qr), ExtensionsCallbackNoop())); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto cq = uassertStatusOK( + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr)); // Query validation if (QueryPlannerCommon::hasNode(cq->root(), MatchExpression::GEO_NEAR)) { diff --git a/src/mongo/s/chunk_manager_index_bounds_test.cpp b/src/mongo/s/chunk_manager_index_bounds_test.cpp index 5a6aa4ec7bf..9ffc73d0a1c 100644 --- a/src/mongo/s/chunk_manager_index_bounds_test.cpp +++ b/src/mongo/s/chunk_manager_index_bounds_test.cpp @@ -33,6 +33,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/canonical_query.h" #include "mongo/s/chunk_manager.h" #include "mongo/s/shard_key_pattern.h" @@ -56,8 +57,14 @@ protected: const NamespaceString nss("test.foo"); auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(queryObj); - auto statusWithCQ = CanonicalQuery::canonicalize( - operationContext(), std::move(qr), ExtensionsCallbackNoop()); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto statusWithCQ = + CanonicalQuery::canonicalize(operationContext(), + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures); + ASSERT_OK(statusWithCQ.getStatus()); return std::move(statusWithCQ.getValue()); } diff --git a/src/mongo/s/commands/chunk_manager_targeter.cpp b/src/mongo/s/commands/chunk_manager_targeter.cpp index f383c7de312..7b58421ebd3 100644 --- a/src/mongo/s/commands/chunk_manager_targeter.cpp +++ b/src/mongo/s/commands/chunk_manager_targeter.cpp @@ -413,7 +413,13 @@ Status ChunkManagerTargeter::targetUpdate( if (!collation.isEmpty()) { qr->setCollation(collation); } - auto cq = CanonicalQuery::canonicalize(opCtx, std::move(qr), ExtensionsCallbackNoop()); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto cq = CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!cq.isOK()) { return Status(cq.getStatus().code(), str::stream() << "Could not parse update query " << updateDoc.getQ() @@ -486,7 +492,13 @@ Status ChunkManagerTargeter::targetDelete( if (!collation.isEmpty()) { qr->setCollation(collation); } - auto cq = CanonicalQuery::canonicalize(opCtx, std::move(qr), ExtensionsCallbackNoop()); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto cq = CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!cq.isOK()) { return Status(cq.getStatus().code(), str::stream() << "Could not parse delete query " << deleteDoc.getQ() diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp index 381638eca5b..8dbef24be73 100644 --- a/src/mongo/s/commands/cluster_find_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_cmd.cpp @@ -164,8 +164,13 @@ public: return appendCommandStatus(result, qr.getStatus()); } - auto cq = - CanonicalQuery::canonicalize(opCtx, std::move(qr.getValue()), ExtensionsCallbackNoop()); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto cq = CanonicalQuery::canonicalize(opCtx, + std::move(qr.getValue()), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!cq.isOK()) { return appendCommandStatus(result, cq.getStatus()); } diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index 1e14c1cb99a..8c76c48b0d5 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -346,8 +346,14 @@ DbResponse Strategy::queryOp(OperationContext* opCtx, const NamespaceString& nss ReadPreferenceSetting::get(opCtx) = uassertStatusOK(ReadPreferenceSetting::fromContainingBSON(q.query, defaultReadPref)); - auto canonicalQuery = - uassertStatusOK(CanonicalQuery::canonicalize(opCtx, q, ExtensionsCallbackNoop())); + const boost::intrusive_ptr<ExpressionContext> expCtx; + auto canonicalQuery = uassertStatusOK( + CanonicalQuery::canonicalize(opCtx, + q, + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr)); // If the $explain flag was set, we must run the operation on the shards as an explain command // rather than a find command. diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp index cb9b0883ff9..baefac56f4f 100644 --- a/src/mongo/s/shard_key_pattern.cpp +++ b/src/mongo/s/shard_key_pattern.cpp @@ -283,8 +283,14 @@ StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(OperationContext* auto qr = stdx::make_unique<QueryRequest>(NamespaceString("")); qr->setFilter(basicQuery); + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = - CanonicalQuery::canonicalize(opCtx, std::move(qr), ExtensionsCallbackNoop()); + CanonicalQuery::canonicalize(opCtx, + std::move(qr), + expCtx, + ExtensionsCallbackNoop(), + MatchExpressionParser::kAllowAllSpecialFeatures & + ~MatchExpressionParser::AllowedFeatures::kExpr); if (!statusWithCQ.isOK()) { return StatusWith<BSONObj>(statusWithCQ.getStatus()); } |