diff options
21 files changed, 1046 insertions, 651 deletions
diff --git a/src/mongo/db/catalog/collection_info_cache_impl.cpp b/src/mongo/db/catalog/collection_info_cache_impl.cpp index 0b02a29896d..ecbca8a8509 100644 --- a/src/mongo/db/catalog/collection_info_cache_impl.cpp +++ b/src/mongo/db/catalog/collection_info_cache_impl.cpp @@ -188,7 +188,7 @@ QuerySettings* CollectionInfoCacheImpl::getQuerySettings() const { } void CollectionInfoCacheImpl::updatePlanCacheIndexEntries(OperationContext* opCtx) { - std::vector<IndexEntry> indexEntries; + std::vector<CoreIndexInfo> indexCores; // TODO We shouldn't need to include unfinished indexes, but we must here because the index // catalog may be in an inconsistent state. SERVER-18346. @@ -197,10 +197,10 @@ void CollectionInfoCacheImpl::updatePlanCacheIndexEntries(OperationContext* opCt _collection->getIndexCatalog()->getIndexIterator(opCtx, includeUnfinishedIndexes); while (ii->more()) { const IndexCatalogEntry* ice = ii->next(); - indexEntries.emplace_back(indexEntryFromIndexCatalogEntry(opCtx, *ice)); + indexCores.emplace_back(indexInfoFromIndexCatalogEntry(*ice)); } - _planCache->notifyOfIndexEntries(indexEntries); + _planCache->notifyOfIndexUpdates(indexCores); } void CollectionInfoCacheImpl::init(OperationContext* opCtx) { diff --git a/src/mongo/db/commands/index_filter_commands_test.cpp b/src/mongo/db/commands/index_filter_commands_test.cpp index 3427eb1b8f7..a2b6eec3080 100644 --- a/src/mongo/db/commands/index_filter_commands_test.cpp +++ b/src/mongo/db/commands/index_filter_commands_test.cpp @@ -428,13 +428,12 @@ TEST(IndexFilterCommandsTest, SetAndClearFiltersCollation) { // Create a plan cache. Add an index so that indexability is included in the plan cache keys. PlanCache planCache; - planCache.notifyOfIndexEntries({IndexEntry(fromjson("{a: 1}"), - false, - false, - false, - IndexEntry::Identifier{"index_name"}, - NULL, - BSONObj())}); + const auto keyPattern = fromjson("{a: 1}"); + planCache.notifyOfIndexUpdates( + {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + true, // sparse + IndexEntry::Identifier{"index_name"})}); // name // Inject query shapes with and without collation into plan cache. addQueryShapeToPlanCache( @@ -502,27 +501,23 @@ TEST(IndexFilterCommandsTest, SetAndClearFiltersCollation) { TEST(IndexFilterCommandsTest, SetFilterAcceptsIndexNames) { CollatorInterfaceMock reverseCollator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry collatedIndex(fromjson("{a: 1}"), - false, - false, - false, - IndexEntry::Identifier{"a_1:rev"}, - nullptr, - BSONObj()); + PlanCache planCache; + const auto keyPattern = fromjson("{a: 1}"); + CoreIndexInfo collatedIndex(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // sparse + IndexEntry::Identifier{"a_1:rev"}); // name collatedIndex.collator = &reverseCollator; QueryTestServiceContext serviceContext; auto opCtx = serviceContext.makeOperationContext(); QuerySettings querySettings; - PlanCache planCache; - planCache.notifyOfIndexEntries({IndexEntry(fromjson("{a: 1}"), - false, - false, - false, - IndexEntry::Identifier{"a_1"}, - nullptr, - BSONObj()), - collatedIndex}); + planCache.notifyOfIndexUpdates( + {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // sparse + IndexEntry::Identifier{"a_1"}), // name + collatedIndex}); addQueryShapeToPlanCache(opCtx.get(), &planCache, "{a: 2}", "{}", "{}", "{}"); ASSERT_TRUE(planCacheContains(opCtx.get(), planCache, "{a: 2}", "{}", "{}", "{}")); diff --git a/src/mongo/db/commands/plan_cache_commands_test.cpp b/src/mongo/db/commands/plan_cache_commands_test.cpp index b7dabbf3ea0..593909ac24f 100644 --- a/src/mongo/db/commands/plan_cache_commands_test.cpp +++ b/src/mongo/db/commands/plan_cache_commands_test.cpp @@ -390,13 +390,13 @@ TEST(PlanCacheCommandsTest, planCacheClearOneKeyCollation) { // Create plan cache with 2 entries. Add an index so that indexability is included in the plan // cache keys. PlanCache planCache; - planCache.notifyOfIndexEntries({IndexEntry(fromjson("{a: 1}"), - false, - false, - false, - IndexEntry::Identifier{"index_name"}, - NULL, - BSONObj())}); + const auto keyPattern = fromjson("{a: 1}"); + planCache.notifyOfIndexUpdates( + {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // sparse + IndexEntry::Identifier{"indexName"})}); // name + QuerySolution qs; qs.cacheData.reset(createSolutionCacheData()); std::vector<QuerySolution*> solns; @@ -640,13 +640,13 @@ TEST(PlanCacheCommandsTest, planCacheListPlansCollation) { // Create plan cache with 2 entries. Add an index so that indexability is included in the plan // cache keys. Give query with collation two solutions. PlanCache planCache; - planCache.notifyOfIndexEntries({IndexEntry(fromjson("{a: 1}"), - false, - false, - false, - IndexEntry::Identifier{"index_name"}, - NULL, - BSONObj())}); + const auto keyPattern = fromjson("{a: 1}"); + planCache.notifyOfIndexUpdates( + {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // sparse + IndexEntry::Identifier{"indexName"})}); // name + QuerySolution qs; qs.cacheData.reset(createSolutionCacheData()); std::vector<QuerySolution*> solns; diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index d56410ec580..0e24ef31472 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -181,6 +181,26 @@ IndexEntry indexEntryFromIndexCatalogEntry(OperationContext* opCtx, projExec}; } +CoreIndexInfo indexInfoFromIndexCatalogEntry(const IndexCatalogEntry& ice) { + auto desc = ice.descriptor(); + invariant(desc); + + auto accessMethod = ice.accessMethod(); + invariant(accessMethod); + + const ProjectionExecAgg* projExec = nullptr; + if (desc->getIndexType() == IndexType::INDEX_WILDCARD) + projExec = static_cast<const WildcardAccessMethod*>(accessMethod)->getProjectionExec(); + + return {desc->keyPattern(), + desc->getIndexType(), + desc->isSparse(), + IndexEntry::Identifier{desc->indexName()}, + ice.getFilterExpression(), + ice.getCollator(), + projExec}; +} + void fillOutPlannerParams(OperationContext* opCtx, Collection* collection, CanonicalQuery* canonicalQuery, diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h index ec5f010748f..8ad39d5091e 100644 --- a/src/mongo/db/query/get_executor.h +++ b/src/mongo/db/query/get_executor.h @@ -68,7 +68,8 @@ void fillOutPlannerParams(OperationContext* opCtx, /** * Converts the catalog metadata for an index into an IndexEntry, which is a format that is meant to - * be consumed by the query planner. + * be consumed by the query planner. This function can perform index reads and should not be called + * unless access to the storage engine is permitted. * * When 'canonicalQuery' is not null, only multikey metadata paths that intersect with the query * field set will be retrieved for a multikey wildcard index. Otherwise all multikey metadata paths @@ -79,6 +80,13 @@ IndexEntry indexEntryFromIndexCatalogEntry(OperationContext* opCtx, const CanonicalQuery* canonicalQuery = nullptr); /** + * Converts the catalog metadata for an index into a CoreIndexInfo, which is a format that is meant + * to be used to update the plan cache. This function has no side effects and is safe to call in + * all contexts. + */ +CoreIndexInfo indexInfoFromIndexCatalogEntry(const IndexCatalogEntry& ice); + +/** * Determines whether or not to wait for oplog visibility for a query. This is only used for * collection scans on the oplog. */ diff --git a/src/mongo/db/query/get_executor_test.cpp b/src/mongo/db/query/get_executor_test.cpp index 592cfaea3c9..da234b77150 100644 --- a/src/mongo/db/query/get_executor_test.cpp +++ b/src/mongo/db/query/get_executor_test.cpp @@ -116,12 +116,51 @@ void testAllowedIndices(std::vector<IndexEntry> indexes, } } +/** + * Make a minimal IndexEntry from just a key pattern and a name. + */ +IndexEntry buildSimpleIndexEntry(const BSONObj& kp, const std::string& indexName) { + return {kp, + IndexNames::nameToType(IndexNames::findPluginName(kp)), + false, + {}, + {}, + false, + false, + CoreIndexInfo::Identifier(indexName), + nullptr, + {}, + nullptr, + nullptr}; +} + +/** + * Make a minimal IndexEntry from just a key pattern and a name. Include a wildcardProjection which + * is neccesary for wildcard indicies. + */ +IndexEntry buildWildcardIndexEntry(const BSONObj& kp, + const ProjectionExecAgg* projExec, + const std::string& indexName) { + return {kp, + IndexNames::nameToType(IndexNames::findPluginName(kp)), + false, + {}, + {}, + false, + false, + CoreIndexInfo::Identifier(indexName), + nullptr, + {}, + nullptr, + projExec}; +} + // Use of index filters to select compound index over single key index. TEST(GetExecutorTest, GetAllowedIndices) { testAllowedIndices( - {IndexEntry(fromjson("{a: 1}"), "a_1"), - IndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), - IndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, + {buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), + buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, SimpleBSONObjComparator::kInstance.makeBSONObjSet({fromjson("{a: 1, b: 1}")}), stdx::unordered_set<std::string>{}, {"a_1_b_1"}); @@ -132,9 +171,9 @@ TEST(GetExecutorTest, GetAllowedIndices) { // result in the planner generating a collection scan. TEST(GetExecutorTest, GetAllowedIndicesNonExistentIndexKeyPatterns) { testAllowedIndices( - {IndexEntry(fromjson("{a: 1}"), "a_1"), - IndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), - IndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, + {buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), + buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, SimpleBSONObjComparator::kInstance.makeBSONObjSet({fromjson("{nosuchfield: 1}")}), stdx::unordered_set<std::string>{}, stdx::unordered_set<std::string>{}); @@ -143,16 +182,17 @@ TEST(GetExecutorTest, GetAllowedIndicesNonExistentIndexKeyPatterns) { // This test case shows how to force query execution to use // an index that orders items in descending order. TEST(GetExecutorTest, GetAllowedIndicesDescendingOrder) { - testAllowedIndices( - {IndexEntry(fromjson("{a: 1}"), "a_1"), IndexEntry(fromjson("{a: -1}"), "a_-1")}, - SimpleBSONObjComparator::kInstance.makeBSONObjSet({fromjson("{a: -1}")}), - stdx::unordered_set<std::string>{}, - {"a_-1"}); + testAllowedIndices({buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: -1}"), "a_-1")}, + SimpleBSONObjComparator::kInstance.makeBSONObjSet({fromjson("{a: -1}")}), + stdx::unordered_set<std::string>{}, + {"a_-1"}); } TEST(GetExecutorTest, GetAllowedIndicesMatchesByName) { testAllowedIndices( - {IndexEntry(fromjson("{a: 1}"), "a_1"), IndexEntry(fromjson("{a: 1}"), "a_1:en")}, + {buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1:en")}, // BSONObjSet default constructor is explicit, so we cannot copy-list-initialize until // C++14. SimpleBSONObjComparator::kInstance.makeBSONObjSet(), @@ -161,48 +201,64 @@ TEST(GetExecutorTest, GetAllowedIndicesMatchesByName) { } TEST(GetExecutorTest, GetAllowedIndicesMatchesMultipleIndexesByKey) { - testAllowedIndices( - {IndexEntry(fromjson("{a: 1}"), "a_1"), IndexEntry(fromjson("{a: 1}"), "a_1:en")}, - SimpleBSONObjComparator::kInstance.makeBSONObjSet({fromjson("{a: 1}")}), - stdx::unordered_set<std::string>{}, - {"a_1", "a_1:en"}); + testAllowedIndices({buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1:en")}, + SimpleBSONObjComparator::kInstance.makeBSONObjSet({fromjson("{a: 1}")}), + stdx::unordered_set<std::string>{}, + {"a_1", "a_1:en"}); } TEST(GetExecutorTest, GetAllowedWildcardIndicesByKey) { - testAllowedIndices({IndexEntry(BSON("$**" << 1), "$**_1"), - IndexEntry(fromjson("{a: 1}"), "a_1"), - IndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), - IndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, + auto projExec = ProjectionExecAgg::create( + fromjson("{_id: 0}"), + ProjectionExecAgg::DefaultIdPolicy::kExcludeId, + ProjectionExecAgg::ArrayRecursionPolicy::kDoNotRecurseNestedArrays); + testAllowedIndices({buildWildcardIndexEntry(BSON("$**" << 1), projExec.get(), "$**_1"), + buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), + buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, SimpleBSONObjComparator::kInstance.makeBSONObjSet({BSON("$**" << 1)}), stdx::unordered_set<std::string>{}, {"$**_1"}); } TEST(GetExecutorTest, GetAllowedWildcardIndicesByName) { - testAllowedIndices({IndexEntry(BSON("$**" << 1), "$**_1"), - IndexEntry(fromjson("{a: 1}"), "a_1"), - IndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), - IndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, + auto projExec = ProjectionExecAgg::create( + fromjson("{_id: 0}"), + ProjectionExecAgg::DefaultIdPolicy::kExcludeId, + ProjectionExecAgg::ArrayRecursionPolicy::kDoNotRecurseNestedArrays); + testAllowedIndices({buildWildcardIndexEntry(BSON("$**" << 1), projExec.get(), "$**_1"), + buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), + buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, SimpleBSONObjComparator::kInstance.makeBSONObjSet(), {"$**_1"}, {"$**_1"}); } TEST(GetExecutorTest, GetAllowedPathSpecifiedWildcardIndicesByKey) { - testAllowedIndices({IndexEntry(BSON("a.$**" << 1), "a.$**_1"), - IndexEntry(fromjson("{a: 1}"), "a_1"), - IndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), - IndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, + auto projExec = ProjectionExecAgg::create( + fromjson("{_id: 0}"), + ProjectionExecAgg::DefaultIdPolicy::kExcludeId, + ProjectionExecAgg::ArrayRecursionPolicy::kDoNotRecurseNestedArrays); + testAllowedIndices({buildWildcardIndexEntry(BSON("a.$**" << 1), projExec.get(), "a.$**_1"), + buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), + buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, SimpleBSONObjComparator::kInstance.makeBSONObjSet({BSON("a.$**" << 1)}), stdx::unordered_set<std::string>{}, {"a.$**_1"}); } TEST(GetExecutorTest, GetAllowedPathSpecifiedWildcardIndicesByName) { - testAllowedIndices({IndexEntry(BSON("a.$**" << 1), "a.$**_1"), - IndexEntry(fromjson("{a: 1}"), "a_1"), - IndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), - IndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, + auto projExec = ProjectionExecAgg::create( + fromjson("{_id: 0}"), + ProjectionExecAgg::DefaultIdPolicy::kExcludeId, + ProjectionExecAgg::ArrayRecursionPolicy::kDoNotRecurseNestedArrays); + testAllowedIndices({buildWildcardIndexEntry(BSON("a.$**" << 1), projExec.get(), "a.$**_1"), + buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"), + buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"), + buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")}, SimpleBSONObjComparator::kInstance.makeBSONObjSet(), {"a.$**_1"}, {"a.$**_1"}); diff --git a/src/mongo/db/query/index_bounds_builder_test.cpp b/src/mongo/db/query/index_bounds_builder_test.cpp index 0bb9f2638ee..25bc1c3f523 100644 --- a/src/mongo/db/query/index_bounds_builder_test.cpp +++ b/src/mongo/db/query/index_bounds_builder_test.cpp @@ -58,6 +58,25 @@ double positiveInfinity = numeric_limits<double>::infinity(); double NaN = numeric_limits<double>::quiet_NaN(); /** + * Make a minimal IndexEntry from just an optional key pattern. A dummy name will be added. An empty + * key pattern will be used if none is provided. + */ +IndexEntry buildSimpleIndexEntry(const BSONObj& kp = BSONObj()) { + return {kp, + IndexNames::nameToType(IndexNames::findPluginName(kp)), + false, + {}, + {}, + false, + false, + CoreIndexInfo::Identifier("test_foo"), + nullptr, + {}, + nullptr, + nullptr}; +} + +/** * Utility function to create MatchExpression */ MatchExpression* parseMatchExpression(const BSONObj& obj) { @@ -75,7 +94,7 @@ MatchExpression* parseMatchExpression(const BSONObj& obj) { void testTranslateAndUnion(const vector<BSONObj>& toUnion, OrderedIntervalList* oilOut, IndexBoundsBuilder::BoundsTightness* tightnessOut) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); for (vector<BSONObj>::const_iterator it = toUnion.begin(); it != toUnion.end(); ++it) { unique_ptr<MatchExpression> expr(parseMatchExpression(*it)); @@ -95,7 +114,7 @@ void testTranslateAndUnion(const vector<BSONObj>& toUnion, void testTranslateAndIntersect(const vector<BSONObj>& toIntersect, OrderedIntervalList* oilOut, IndexBoundsBuilder::BoundsTightness* tightnessOut) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); for (vector<BSONObj>::const_iterator it = toIntersect.begin(); it != toIntersect.end(); ++it) { unique_ptr<MatchExpression> expr(parseMatchExpression(*it)); @@ -119,7 +138,7 @@ void testTranslateAndIntersect(const vector<BSONObj>& toIntersect, void testTranslate(const vector<std::pair<BSONObj, bool>>& constraints, OrderedIntervalList* oilOut, IndexBoundsBuilder::BoundsTightness* tightnessOut) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); for (vector<std::pair<BSONObj, bool>>::const_iterator it = constraints.begin(); it != constraints.end(); @@ -156,7 +175,7 @@ bool testSingleInterval(IndexBounds bounds) { // TEST(IndexBoundsBuilderTest, TranslateElemMatchValue) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); // Bounds generated should be the same as the embedded expression // except for the tightness. BSONObj obj = fromjson("{a: {$elemMatch: {$gt: 2}}}"); @@ -178,7 +197,7 @@ TEST(IndexBoundsBuilderTest, TranslateElemMatchValue) { // TEST(IndexBoundsBuilderTest, TranslateLteNumber) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$lte: 1}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -194,7 +213,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteNumber) { } TEST(IndexBoundsBuilderTest, TranslateLteNumberMin) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lte" << numberMin)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -210,7 +229,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteNumberMin) { } TEST(IndexBoundsBuilderTest, TranslateLteNegativeInfinity) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$lte: -Infinity}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -226,7 +245,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteNegativeInfinity) { } TEST(IndexBoundsBuilderTest, TranslateLteObject) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$lte: {b: 1}}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -241,7 +260,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteObject) { } TEST(IndexBoundsBuilderTest, TranslateLteCode) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lte" << BSONCode("function(){ return 0; }"))); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -257,7 +276,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteCode) { } TEST(IndexBoundsBuilderTest, TranslateLteCodeWScope) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lte" << BSONCodeWScope("this.b == c", BSON("c" << 1)))); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -274,7 +293,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteCodeWScope) { } TEST(IndexBoundsBuilderTest, TranslateLteMinKey) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lte" << MINKEY)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -290,7 +309,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteMinKey) { } TEST(IndexBoundsBuilderTest, TranslateLteMaxKey) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lte" << MAXKEY)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -306,7 +325,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteMaxKey) { } TEST(IndexBoundsBuilderTest, TranslateLtNumber) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$lt: 1}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -322,7 +341,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtNumber) { } TEST(IndexBoundsBuilderTest, TranslateLtNumberMin) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lt" << numberMin)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -338,7 +357,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtNumberMin) { } TEST(IndexBoundsBuilderTest, TranslateLtNegativeInfinity) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$lt: -Infinity}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -351,7 +370,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtNegativeInfinity) { } TEST(IndexBoundsBuilderTest, TranslateLtDate) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << LT << Date_t::fromMillisSinceEpoch(5000)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -367,7 +386,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtDate) { } TEST(IndexBoundsBuilderTest, TranslateLtObject) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$lt: {b: 1}}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -383,7 +402,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtObject) { } TEST(IndexBoundsBuilderTest, TranslateLtCode) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lt" << BSONCode("function(){ return 0; }"))); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -399,7 +418,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtCode) { } TEST(IndexBoundsBuilderTest, TranslateLtCodeWScope) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lt" << BSONCodeWScope("this.b == c", BSON("c" << 1)))); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -417,7 +436,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtCodeWScope) { // Nothing can be less than MinKey so the resulting index bounds would be a useless empty range. TEST(IndexBoundsBuilderTest, TranslateLtMinKeyDoesNotGenerateBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lt" << MINKEY)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -430,7 +449,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtMinKeyDoesNotGenerateBounds) { } TEST(IndexBoundsBuilderTest, TranslateLtMaxKey) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$lt" << MAXKEY)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -446,7 +465,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtMaxKey) { } TEST(IndexBoundsBuilderTest, TranslateGtTimestamp) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << GT << Timestamp(2, 3)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -465,7 +484,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtTimestamp) { } TEST(IndexBoundsBuilderTest, TranslateGtNumber) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gt: 1}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -481,7 +500,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtNumber) { } TEST(IndexBoundsBuilderTest, TranslateGtNumberMax) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gt" << numberMax)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -497,7 +516,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtNumberMax) { } TEST(IndexBoundsBuilderTest, TranslateGtPositiveInfinity) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gt: Infinity}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -510,7 +529,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtPositiveInfinity) { } TEST(IndexBoundsBuilderTest, TranslateGtString) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gt: 'abc'}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -526,7 +545,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtString) { } TEST(IndexBoundsBuilderTest, TranslateGtObject) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gt: {b: 1}}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -542,7 +561,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtObject) { } TEST(IndexBoundsBuilderTest, TranslateGtCode) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gt" << BSONCode("function(){ return 0; }"))); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -558,7 +577,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtCode) { } TEST(IndexBoundsBuilderTest, TranslateGtCodeWScope) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gt" << BSONCodeWScope("this.b == c", BSON("c" << 1)))); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -574,7 +593,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtCodeWScope) { } TEST(IndexBoundsBuilderTest, TranslateGtMinKey) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gt" << MINKEY)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -591,7 +610,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtMinKey) { // Nothing can be greater than MaxKey so the resulting index bounds would be a useless empty range. TEST(IndexBoundsBuilderTest, TranslateGtMaxKeyDoesNotGenerateBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gt" << MAXKEY)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -604,7 +623,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtMaxKeyDoesNotGenerateBounds) { } TEST(IndexBoundsBuilderTest, TranslateGteNumber) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gte: 1}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -620,7 +639,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteNumber) { } TEST(IndexBoundsBuilderTest, TranslateGteNumberMax) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gte" << numberMax)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -636,7 +655,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteNumberMax) { } TEST(IndexBoundsBuilderTest, TranslateGtePositiveInfinity) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gte: Infinity}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -652,7 +671,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtePositiveInfinity) { } TEST(IndexBoundsBuilderTest, TranslateGteObject) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gte: {b: 1}}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -668,7 +687,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteObject) { } TEST(IndexBoundsBuilderTest, TranslateGteCode) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gte" << BSONCode("function(){ return 0; }"))); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -684,7 +703,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteCode) { } TEST(IndexBoundsBuilderTest, TranslateGteCodeWScope) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gte" << BSONCodeWScope("this.b == c", BSON("c" << 1)))); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -700,7 +719,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteCodeWScope) { } TEST(IndexBoundsBuilderTest, TranslateGteMinKey) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gte" << MINKEY)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -716,7 +735,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteMinKey) { } TEST(IndexBoundsBuilderTest, TranslateGteMaxKey) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$gte" << MAXKEY)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -732,7 +751,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteMaxKey) { } TEST(IndexBoundsBuilderTest, TranslateEqualNan) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: NaN}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -747,7 +766,7 @@ TEST(IndexBoundsBuilderTest, TranslateEqualNan) { } TEST(IndexBoundsBuilderTest, TranslateLtNan) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$lt: NaN}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -760,7 +779,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtNan) { } TEST(IndexBoundsBuilderTest, TranslateLteNan) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$lte: NaN}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -775,7 +794,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteNan) { } TEST(IndexBoundsBuilderTest, TranslateGtNan) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gt: NaN}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -788,7 +807,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtNan) { } TEST(IndexBoundsBuilderTest, TranslateGteNan) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$gte: NaN}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -803,7 +822,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteNan) { } TEST(IndexBoundsBuilderTest, TranslateEqual) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << 4); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -820,7 +839,7 @@ TEST(IndexBoundsBuilderTest, TranslateEqual) { TEST(IndexBoundsBuilderTest, TranslateExprEqual) { BSONObj keyPattern = BSON("a" << 1); BSONElement elt = keyPattern.firstElement(); - IndexEntry testIndex{keyPattern}; + auto testIndex = buildSimpleIndexEntry(keyPattern); BSONObj obj = BSON("a" << BSON("$_internalExprEq" << 4)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); OrderedIntervalList oil; @@ -837,7 +856,7 @@ TEST(IndexBoundsBuilderTest, TranslateExprEqualToStringRespectsCollation) { BSONObj keyPattern = BSON("a" << 1); BSONElement elt = keyPattern.firstElement(); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex{keyPattern}; + auto testIndex = buildSimpleIndexEntry(keyPattern); testIndex.collator = &collator; BSONObj obj = BSON("a" << BSON("$_internalExprEq" @@ -857,7 +876,7 @@ TEST(IndexBoundsBuilderTest, TranslateExprEqualToStringRespectsCollation) { TEST(IndexBoundsBuilderTest, TranslateExprEqualHashedIndex) { BSONObj keyPattern = fromjson("{a: 'hashed'}"); BSONElement elt = keyPattern.firstElement(); - IndexEntry testIndex{keyPattern}; + auto testIndex = buildSimpleIndexEntry(keyPattern); BSONObj obj = BSON("a" << BSON("$_internalExprEq" << 4)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); OrderedIntervalList oil; @@ -880,7 +899,7 @@ TEST(IndexBoundsBuilderTest, TranslateExprEqualHashedIndex) { TEST(IndexBoundsBuilderTest, TranslateExprEqualToNullIsInexactFetch) { BSONObj keyPattern = BSON("a" << 1); BSONElement elt = keyPattern.firstElement(); - IndexEntry testIndex{keyPattern}; + auto testIndex = buildSimpleIndexEntry(keyPattern); BSONObj obj = BSON("a" << BSON("$_internalExprEq" << BSONNULL)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); OrderedIntervalList oil; @@ -897,7 +916,7 @@ TEST(IndexBoundsBuilderTest, TranslateExprEqualToNullIsInexactFetch) { } TEST(IndexBoundsBuilderTest, TranslateArrayEqualBasic) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: [1, 2, 3]}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -915,7 +934,7 @@ TEST(IndexBoundsBuilderTest, TranslateArrayEqualBasic) { } TEST(IndexBoundsBuilderTest, TranslateIn) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$in: [8, 44, -1, -3]}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -936,7 +955,7 @@ TEST(IndexBoundsBuilderTest, TranslateIn) { } TEST(IndexBoundsBuilderTest, TranslateInArray) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$in: [[1], 2]}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -955,7 +974,7 @@ TEST(IndexBoundsBuilderTest, TranslateInArray) { } TEST(IndexBoundsBuilderTest, TranslateLteBinData) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson( "{a: {$lte: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA'," "$type: '00'}}}"); @@ -976,7 +995,7 @@ TEST(IndexBoundsBuilderTest, TranslateLteBinData) { } TEST(IndexBoundsBuilderTest, TranslateLtBinData) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson( "{a: {$lt: {$binary: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA'," "$type: '00'}}}"); @@ -997,7 +1016,7 @@ TEST(IndexBoundsBuilderTest, TranslateLtBinData) { } TEST(IndexBoundsBuilderTest, TranslateGtBinData) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson( "{a: {$gt: {$binary: '////////////////////////////'," "$type: '00'}}}"); @@ -1018,7 +1037,7 @@ TEST(IndexBoundsBuilderTest, TranslateGtBinData) { } TEST(IndexBoundsBuilderTest, TranslateGteBinData) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson( "{a: {$gte: {$binary: '////////////////////////////'," "$type: '00'}}}"); @@ -1043,7 +1062,7 @@ TEST(IndexBoundsBuilderTest, TranslateGteBinData) { // TEST(IndexBoundsBuilderTest, TypeNumber) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: 'number'}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1070,7 +1089,7 @@ TEST(IndexBoundsBuilderTest, TypeNumber) { // TEST(IndexBoundsBuilderTest, ExistsTrue) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$exists: true}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1085,7 +1104,7 @@ TEST(IndexBoundsBuilderTest, ExistsTrue) { } TEST(IndexBoundsBuilderTest, ExistsFalse) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$exists: false}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1100,13 +1119,20 @@ TEST(IndexBoundsBuilderTest, ExistsFalse) { } TEST(IndexBoundsBuilderTest, ExistsTrueSparse) { - IndexEntry testIndex = IndexEntry(BSONObj(), - false, // multikey - true, // sparse - false, // unique - IndexEntry::Identifier{"exists_true_sparse"}, - nullptr, // filterExpr - BSONObj()); + auto keyPattern = BSONObj(); + IndexEntry testIndex = + IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + true, // sparse + false, // unique + IndexEntry::Identifier{"exists_true_sparse"}, + nullptr, // filterExpr + BSONObj(), + nullptr, + nullptr); BSONObj obj = fromjson("{a: {$exists: true}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1125,7 +1151,7 @@ TEST(IndexBoundsBuilderTest, ExistsTrueSparse) { // TEST(IndexBoundsBuilderTest, UnionTwoLt) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toUnion; toUnion.push_back(fromjson("{a: {$lt: 1}}")); toUnion.push_back(fromjson("{a: {$lt: 5}}")); @@ -1141,7 +1167,7 @@ TEST(IndexBoundsBuilderTest, UnionTwoLt) { } TEST(IndexBoundsBuilderTest, UnionDupEq) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toUnion; toUnion.push_back(fromjson("{a: 1}")); toUnion.push_back(fromjson("{a: 5}")); @@ -1159,7 +1185,7 @@ TEST(IndexBoundsBuilderTest, UnionDupEq) { } TEST(IndexBoundsBuilderTest, UnionGtLt) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toUnion; toUnion.push_back(fromjson("{a: {$gt: 1}}")); toUnion.push_back(fromjson("{a: {$lt: 3}}")); @@ -1175,7 +1201,7 @@ TEST(IndexBoundsBuilderTest, UnionGtLt) { } TEST(IndexBoundsBuilderTest, UnionTwoEmptyRanges) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<std::pair<BSONObj, bool>> constraints; constraints.push_back(std::make_pair(fromjson("{a: {$gt: 1}}"), true)); constraints.push_back(std::make_pair(fromjson("{a: {$lte: 0}}"), true)); @@ -1192,7 +1218,7 @@ TEST(IndexBoundsBuilderTest, UnionTwoEmptyRanges) { // TEST(IndexBoundsBuilderTest, IntersectTwoLt) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toIntersect; toIntersect.push_back(fromjson("{a: {$lt: 1}}")); toIntersect.push_back(fromjson("{a: {$lt: 5}}")); @@ -1208,7 +1234,7 @@ TEST(IndexBoundsBuilderTest, IntersectTwoLt) { } TEST(IndexBoundsBuilderTest, IntersectEqGte) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toIntersect; toIntersect.push_back(fromjson("{a: 1}}")); toIntersect.push_back(fromjson("{a: {$gte: 1}}")); @@ -1223,7 +1249,7 @@ TEST(IndexBoundsBuilderTest, IntersectEqGte) { } TEST(IndexBoundsBuilderTest, IntersectGtLte) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toIntersect; toIntersect.push_back(fromjson("{a: {$gt: 0}}")); toIntersect.push_back(fromjson("{a: {$lte: 10}}")); @@ -1238,7 +1264,7 @@ TEST(IndexBoundsBuilderTest, IntersectGtLte) { } TEST(IndexBoundsBuilderTest, IntersectGtIn) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toIntersect; toIntersect.push_back(fromjson("{a: {$gt: 4}}")); toIntersect.push_back(fromjson("{a: {$in: [1,2,3,4,5,6]}}")); @@ -1255,7 +1281,7 @@ TEST(IndexBoundsBuilderTest, IntersectGtIn) { } TEST(IndexBoundsBuilderTest, IntersectionIsPointInterval) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toIntersect; toIntersect.push_back(fromjson("{a: {$gte: 1}}")); toIntersect.push_back(fromjson("{a: {$lte: 1}}")); @@ -1270,7 +1296,7 @@ TEST(IndexBoundsBuilderTest, IntersectionIsPointInterval) { } TEST(IndexBoundsBuilderTest, IntersectFullyContained) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toIntersect; toIntersect.push_back(fromjson("{a: {$gt: 5}}")); toIntersect.push_back(fromjson("{a: {$lt: 15}}")); @@ -1287,7 +1313,7 @@ TEST(IndexBoundsBuilderTest, IntersectFullyContained) { } TEST(IndexBoundsBuilderTest, EmptyIntersection) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toIntersect; toIntersect.push_back(fromjson("{a: 1}}")); toIntersect.push_back(fromjson("{a: {$gte: 2}}")); @@ -1303,7 +1329,7 @@ TEST(IndexBoundsBuilderTest, EmptyIntersection) { // TEST(IndexBoundsBuilderTest, TranslateMod) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$mod: [2, 0]}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1323,7 +1349,7 @@ TEST(IndexBoundsBuilderTest, TranslateMod) { // TEST(SimpleRegexTest, RootedLine) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^foo", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "foo"); @@ -1331,7 +1357,7 @@ TEST(SimpleRegexTest, RootedLine) { } TEST(SimpleRegexTest, RootedString) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("\\Afoo", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "foo"); @@ -1339,7 +1365,7 @@ TEST(SimpleRegexTest, RootedString) { } TEST(SimpleRegexTest, RootedOptionalFirstChar) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^f?oo", "", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1347,7 +1373,7 @@ TEST(SimpleRegexTest, RootedOptionalFirstChar) { } TEST(SimpleRegexTest, RootedOptionalSecondChar) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^fz?oo", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "f"); @@ -1355,7 +1381,7 @@ TEST(SimpleRegexTest, RootedOptionalSecondChar) { } TEST(SimpleRegexTest, RootedMultiline) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^foo", "m", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1363,7 +1389,7 @@ TEST(SimpleRegexTest, RootedMultiline) { } TEST(SimpleRegexTest, RootedStringMultiline) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("\\Afoo", "m", testIndex, &tightness); ASSERT_EQUALS(prefix, "foo"); @@ -1371,7 +1397,7 @@ TEST(SimpleRegexTest, RootedStringMultiline) { } TEST(SimpleRegexTest, RootedCaseInsensitiveMulti) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("\\Afoo", "mi", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1379,7 +1405,7 @@ TEST(SimpleRegexTest, RootedCaseInsensitiveMulti) { } TEST(SimpleRegexTest, RootedComplex) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex( "\\Af \t\vo\n\ro \\ \\# #comment", "mx", testIndex, &tightness); @@ -1388,7 +1414,7 @@ TEST(SimpleRegexTest, RootedComplex) { } TEST(SimpleRegexTest, RootedLiteral) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^\\Qasdf\\E", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "asdf"); @@ -1396,7 +1422,7 @@ TEST(SimpleRegexTest, RootedLiteral) { } TEST(SimpleRegexTest, RootedLiteralWithExtra) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^\\Qasdf\\E.*", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "asdf"); @@ -1404,7 +1430,7 @@ TEST(SimpleRegexTest, RootedLiteralWithExtra) { } TEST(SimpleRegexTest, RootedLiteralNoEnd) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^\\Qasdf", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "asdf"); @@ -1412,7 +1438,7 @@ TEST(SimpleRegexTest, RootedLiteralNoEnd) { } TEST(SimpleRegexTest, RootedLiteralBackslash) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^\\Qasdf\\\\E", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "asdf\\"); @@ -1420,7 +1446,7 @@ TEST(SimpleRegexTest, RootedLiteralBackslash) { } TEST(SimpleRegexTest, RootedLiteralDotStar) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^\\Qas.*df\\E", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "as.*df"); @@ -1428,7 +1454,7 @@ TEST(SimpleRegexTest, RootedLiteralDotStar) { } TEST(SimpleRegexTest, RootedLiteralNestedEscape) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^\\Qas\\Q[df\\E", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "as\\Q[df"); @@ -1436,7 +1462,7 @@ TEST(SimpleRegexTest, RootedLiteralNestedEscape) { } TEST(SimpleRegexTest, RootedLiteralNestedEscapeEnd) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^\\Qas\\E\\\\E\\Q$df\\E", "", testIndex, &tightness); @@ -1447,7 +1473,7 @@ TEST(SimpleRegexTest, RootedLiteralNestedEscapeEnd) { // An anchored regular expression that uses the "|" operator is not considered "simple" and has // non-tight index bounds. TEST(SimpleRegexTest, PipeCharacterUsesInexactBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^(a(a|$)|b", "", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1455,7 +1481,7 @@ TEST(SimpleRegexTest, PipeCharacterUsesInexactBounds) { } TEST(SimpleRegexTest, PipeCharacterUsesInexactBoundsWithTwoPrefixes) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^(a(a|$)|^b", "", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1463,7 +1489,7 @@ TEST(SimpleRegexTest, PipeCharacterUsesInexactBoundsWithTwoPrefixes) { } TEST(SimpleRegexTest, PipeCharacterPrecededByEscapedBackslashUsesInexactBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex(R"(^a\\|b)", "", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1477,7 +1503,7 @@ TEST(SimpleRegexTest, PipeCharacterPrecededByEscapedBackslashUsesInexactBounds) // However, a regular expression with an escaped pipe (that is, using no special meaning) can use // exact index bounds. TEST(SimpleRegexTest, PipeCharacterEscapedWithBackslashUsesExactBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex(R"(^a\|b)", "", testIndex, &tightness); ASSERT_EQUALS(prefix, "a|b"); @@ -1489,7 +1515,7 @@ TEST(SimpleRegexTest, PipeCharacterEscapedWithBackslashUsesExactBounds) { } TEST(SimpleRegexTest, FalsePositiveOnPipeInQEEscapeSequenceUsesInexactBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex(R"(^\Q|\E)", "", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1497,7 +1523,7 @@ TEST(SimpleRegexTest, FalsePositiveOnPipeInQEEscapeSequenceUsesInexactBounds) { } TEST(SimpleRegexTest, FalsePositiveOnPipeInCharacterClassUsesInexactBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex(R"(^[|])", "", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1506,7 +1532,7 @@ TEST(SimpleRegexTest, FalsePositiveOnPipeInCharacterClassUsesInexactBounds) { // SERVER-9035 TEST(SimpleRegexTest, RootedSingleLineMode) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("^foo", "s", testIndex, &tightness); ASSERT_EQUALS(prefix, "foo"); @@ -1515,7 +1541,7 @@ TEST(SimpleRegexTest, RootedSingleLineMode) { // SERVER-9035 TEST(SimpleRegexTest, NonRootedSingleLineMode) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex("foo", "s", testIndex, &tightness); ASSERT_EQUALS(prefix, ""); @@ -1524,7 +1550,7 @@ TEST(SimpleRegexTest, NonRootedSingleLineMode) { // SERVER-9035 TEST(SimpleRegexTest, RootedComplexSingleLineMode) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); IndexBoundsBuilder::BoundsTightness tightness; string prefix = IndexBoundsBuilder::simpleRegex( "\\Af \t\vo\n\ro \\ \\# #comment", "msx", testIndex, &tightness); @@ -1534,7 +1560,7 @@ TEST(SimpleRegexTest, RootedComplexSingleLineMode) { TEST(SimpleRegexTest, RootedRegexCantBeIndexedTightlyIfIndexHasCollation) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; IndexBoundsBuilder::BoundsTightness tightness; @@ -1548,7 +1574,7 @@ TEST(SimpleRegexTest, RootedRegexCantBeIndexedTightlyIfIndexHasCollation) { // TEST(IndexBoundsBuilderTest, SimpleNonPrefixRegex) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: /foo/}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1565,7 +1591,7 @@ TEST(IndexBoundsBuilderTest, SimpleNonPrefixRegex) { } TEST(IndexBoundsBuilderTest, NonSimpleRegexWithPipe) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: /^foo.*|bar/}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1582,7 +1608,7 @@ TEST(IndexBoundsBuilderTest, NonSimpleRegexWithPipe) { } TEST(IndexBoundsBuilderTest, SimpleRegexSingleLineMode) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: /^foo/s}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1600,7 +1626,7 @@ TEST(IndexBoundsBuilderTest, SimpleRegexSingleLineMode) { } TEST(IndexBoundsBuilderTest, SimplePrefixRegex) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: /^foo/}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1831,7 +1857,7 @@ BSONObj maxKeyIntObj(int start) { // Expected oil: [MinKey, 3), (3, MaxKey] TEST(IndexBoundsBuilderTest, SimpleNE) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = BSON("a" << BSON("$ne" << 3)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1848,7 +1874,7 @@ TEST(IndexBoundsBuilderTest, SimpleNE) { } TEST(IndexBoundsBuilderTest, IntersectWithNE) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toIntersect; toIntersect.push_back(fromjson("{a: {$gt: 1}}")); toIntersect.push_back(fromjson("{a: {$ne: 2}}}")); @@ -1866,7 +1892,7 @@ TEST(IndexBoundsBuilderTest, IntersectWithNE) { } TEST(IndexBoundsBuilderTest, UnionizeWithNE) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); vector<BSONObj> toUnionize; toUnionize.push_back(fromjson("{a: {$ne: 3}}")); toUnionize.push_back(fromjson("{a: {$ne: 4}}}")); @@ -1882,7 +1908,7 @@ TEST(IndexBoundsBuilderTest, UnionizeWithNE) { // Test $type bounds for Code BSON type. TEST(IndexBoundsBuilderTest, CodeTypeBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: 13}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1907,7 +1933,7 @@ TEST(IndexBoundsBuilderTest, CodeTypeBounds) { // Test $type bounds for Code With Scoped BSON type. TEST(IndexBoundsBuilderTest, CodeWithScopeTypeBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: 15}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1932,7 +1958,7 @@ TEST(IndexBoundsBuilderTest, CodeWithScopeTypeBounds) { // Test $type bounds for double BSON type. TEST(IndexBoundsBuilderTest, DoubleTypeBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: 1}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1956,7 +1982,7 @@ TEST(IndexBoundsBuilderTest, DoubleTypeBounds) { } TEST(IndexBoundsBuilderTest, TypeArrayBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: 'array'}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -1979,7 +2005,7 @@ TEST(IndexBoundsBuilderTest, TypeArrayBounds) { TEST(IndexBoundsBuilderTest, TranslateEqualityToStringWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = BSON("a" @@ -2001,7 +2027,7 @@ TEST(IndexBoundsBuilderTest, TranslateEqualityToStringWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateEqualityToNonStringWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = BSON("a" << 3); @@ -2033,7 +2059,7 @@ void assertBoundsRepresentEqualsNull(const OrderedIntervalList& oil) { TEST(IndexBoundsBuilderTest, TranslateEqualsToNullShouldBuildInexactBounds) { BSONObj indexPattern = BSON("a" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); BSONObj obj = BSON("a" << BSONNULL); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); @@ -2050,7 +2076,7 @@ TEST(IndexBoundsBuilderTest, TranslateEqualsToNullShouldBuildInexactBounds) { TEST(IndexBoundsBuilderTest, TranslateDottedEqualsToNullShouldBuildInexactBounds) { BSONObj indexPattern = BSON("a.b" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); BSONObj obj = BSON("a.b" << BSONNULL); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); @@ -2067,7 +2093,7 @@ TEST(IndexBoundsBuilderTest, TranslateDottedEqualsToNullShouldBuildInexactBounds TEST(IndexBoundsBuilderTest, TranslateEqualsToNullMultiKeyShouldBuildInexactBounds) { BSONObj indexPattern = BSON("a" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); testIndex.multikey = true; BSONObj obj = BSON("a" << BSONNULL); @@ -2086,7 +2112,7 @@ TEST(IndexBoundsBuilderTest, TranslateEqualsToNullMultiKeyShouldBuildInexactBoun TEST(IndexBoundsBuilderTest, TranslateEqualsToNullShouldBuildTwoIntervalsForHashedIndex) { BSONObj indexPattern = BSON("a" << "hashed"); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); testIndex.type = IndexType::INDEX_HASHED; BSONObj obj = BSON("a" << BSONNULL); @@ -2153,7 +2179,7 @@ void assertBoundsRepresentNotEqualsNull(const OrderedIntervalList& oil) { TEST(IndexBoundsBuilderTest, TranslateNotEqualToNullShouldBuildExactBoundsIfIndexIsNotMultiKey) { BSONObj indexPattern = BSON("a" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); BSONObj obj = BSON("a" << BSON("$ne" << BSONNULL)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); @@ -2172,7 +2198,7 @@ TEST(IndexBoundsBuilderTest, TranslateNotEqualToNullShouldBuildExactBoundsIfInde TEST(IndexBoundsBuilderTest, TranslateNotEqualToNullShouldBuildExactBoundsIfIndexIsNotMultiKeyOnRelevantPath) { BSONObj indexPattern = BSON("a" << 1 << "b" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); testIndex.multikeyPaths = {{}, {0}}; // "a" is not multi-key, but "b" is. BSONObj obj = BSON("a" << BSON("$ne" << BSONNULL)); @@ -2191,7 +2217,7 @@ TEST(IndexBoundsBuilderTest, TEST(IndexBoundsBuilderTest, TranslateNotEqualToNullShouldBuildExactBoundsOnReverseIndex) { BSONObj indexPattern = BSON("a" << -1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); BSONObj obj = BSON("a" << BSON("$ne" << BSONNULL)); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); @@ -2209,7 +2235,7 @@ TEST(IndexBoundsBuilderTest, TranslateNotEqualToNullShouldBuildExactBoundsOnReve TEST(IndexBoundsBuilderTest, TranslateNotEqualToNullShouldBuildInexactBoundsIfIndexIsMultiKey) { BSONObj indexPattern = BSON("a" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); testIndex.multikey = true; BSONObj matchObj = BSON("a" << BSON("$ne" << BSONNULL)); @@ -2228,7 +2254,7 @@ TEST(IndexBoundsBuilderTest, TranslateNotEqualToNullShouldBuildInexactBoundsIfIn TEST(IndexBoundsBuilderTest, TranslateDottedElemMatchValueNotEqualToNullShouldBuildExactBoundsIfIsMultiKeyOnThatPath) { BSONObj indexPattern = BSON("a.b" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); testIndex.multikeyPaths = {{1}}; // "a.b" is multikey. BSONObj matchObj = BSON("a.b" << BSON("$elemMatch" << BSON("$ne" << BSONNULL))); @@ -2247,7 +2273,7 @@ TEST(IndexBoundsBuilderTest, TEST(IndexBoundsBuilderTest, TranslateDottedFieldNotEqualToNullShouldBuildInexactBoundsIfIndexIsMultiKey) { BSONObj indexPattern = BSON("a.b" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); testIndex.multikey = true; BSONObj matchObj = BSON("a.b" << BSON("$ne" << BSONNULL)); @@ -2266,7 +2292,7 @@ TEST(IndexBoundsBuilderTest, TEST(IndexBoundsBuilderTest, TranslateElemMatchValueNotEqualToNullShouldBuildInexactBoundsIfIndexIsMultiKey) { BSONObj indexPattern = BSON("a" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); testIndex.multikey = true; BSONObj obj = BSON("a" << BSON("$elemMatch" << BSON("$ne" << BSONNULL))); @@ -2285,7 +2311,7 @@ TEST(IndexBoundsBuilderTest, TEST(IndexBoundsBuilderTest, TranslateElemMatchValueNotEqualToNullShouldBuildInExactBoundsIfIndexIsNotMultiKey) { BSONObj indexPattern = BSON("a" << 1); - IndexEntry testIndex(indexPattern); + auto testIndex = buildSimpleIndexEntry(indexPattern); BSONObj matchObj = BSON("a" << BSON("$elemMatch" << BSON("$ne" << BSONNULL))); unique_ptr<MatchExpression> expr(parseMatchExpression(matchObj)); @@ -2302,7 +2328,7 @@ TEST(IndexBoundsBuilderTest, TEST(IndexBoundsBuilderTest, TranslateNotEqualToStringWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = BSON("a" << BSON("$ne" @@ -2338,7 +2364,7 @@ TEST(IndexBoundsBuilderTest, TranslateNotEqualToStringWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateEqualToStringElemMatchValueWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$elemMatch: {$eq: 'baz'}}}"); @@ -2359,7 +2385,7 @@ TEST(IndexBoundsBuilderTest, TranslateEqualToStringElemMatchValueWithMockCollato TEST(IndexBoundsBuilderTest, TranslateLTEToStringWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$lte: 'foo'}}"); @@ -2379,7 +2405,7 @@ TEST(IndexBoundsBuilderTest, TranslateLTEToStringWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateLTEToNumberWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$lte: 3}}"); @@ -2400,7 +2426,7 @@ TEST(IndexBoundsBuilderTest, TranslateLTEToNumberWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateLTStringWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$lt: 'foo'}}"); @@ -2420,7 +2446,7 @@ TEST(IndexBoundsBuilderTest, TranslateLTStringWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateLTNumberWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$lt: 3}}"); @@ -2441,7 +2467,7 @@ TEST(IndexBoundsBuilderTest, TranslateLTNumberWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateGTStringWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$gt: 'foo'}}"); @@ -2462,7 +2488,7 @@ TEST(IndexBoundsBuilderTest, TranslateGTStringWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateGTNumberWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$gt: 3}}"); @@ -2483,7 +2509,7 @@ TEST(IndexBoundsBuilderTest, TranslateGTNumberWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateGTEToStringWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$gte: 'foo'}}"); @@ -2503,7 +2529,7 @@ TEST(IndexBoundsBuilderTest, TranslateGTEToStringWithMockCollator) { TEST(IndexBoundsBuilderTest, TranslateGTEToNumberWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$gte: 3}}"); @@ -2524,7 +2550,7 @@ TEST(IndexBoundsBuilderTest, TranslateGTEToNumberWithMockCollator) { TEST(IndexBoundsBuilderTest, SimplePrefixRegexWithMockCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: /^foo/}"); @@ -2546,7 +2572,7 @@ TEST(IndexBoundsBuilderTest, SimplePrefixRegexWithMockCollator) { TEST(IndexBoundsBuilderTest, NotWithMockCollatorIsExact) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$ne: 3}}"); @@ -2567,7 +2593,7 @@ TEST(IndexBoundsBuilderTest, NotWithMockCollatorIsExact) { TEST(IndexBoundsBuilderTest, ExistsTrueWithMockCollatorAndSparseIsExact) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; testIndex.sparse = true; @@ -2588,7 +2614,7 @@ TEST(IndexBoundsBuilderTest, ExistsTrueWithMockCollatorAndSparseIsExact) { TEST(IndexBoundsBuilderTest, ExistsFalseWithMockCollatorIsInexactFetch) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$exists: false}}"); @@ -2608,7 +2634,7 @@ TEST(IndexBoundsBuilderTest, ExistsFalseWithMockCollatorIsInexactFetch) { TEST(IndexBoundsBuilderTest, TypeStringIsInexactFetch) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$type: 'string'}}"); @@ -2628,7 +2654,7 @@ TEST(IndexBoundsBuilderTest, TypeStringIsInexactFetch) { TEST(IndexBoundsBuilderTest, InWithStringAndCollatorIsExact) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$in: ['foo']}}"); @@ -2649,7 +2675,7 @@ TEST(IndexBoundsBuilderTest, InWithStringAndCollatorIsExact) { TEST(IndexBoundsBuilderTest, InWithNumberAndStringAndCollatorIsExact) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$in: [2, 'foo']}}"); @@ -2672,7 +2698,7 @@ TEST(IndexBoundsBuilderTest, InWithNumberAndStringAndCollatorIsExact) { TEST(IndexBoundsBuilderTest, InWithRegexAndCollatorIsInexactFetch) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$in: [/^foo/]}}"); @@ -2694,7 +2720,7 @@ TEST(IndexBoundsBuilderTest, InWithRegexAndCollatorIsInexactFetch) { TEST(IndexBoundsBuilderTest, InWithNumberAndCollatorIsExact) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$in: [2]}}"); @@ -2713,7 +2739,7 @@ TEST(IndexBoundsBuilderTest, InWithNumberAndCollatorIsExact) { TEST(IndexBoundsBuilderTest, LTEMaxKeyWithCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$lte: {$maxKey: 1}}}"); @@ -2733,7 +2759,7 @@ TEST(IndexBoundsBuilderTest, LTEMaxKeyWithCollator) { TEST(IndexBoundsBuilderTest, LTMaxKeyWithCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$lt: {$maxKey: 1}}}"); @@ -2753,7 +2779,7 @@ TEST(IndexBoundsBuilderTest, LTMaxKeyWithCollator) { TEST(IndexBoundsBuilderTest, GTEMinKeyWithCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$gte: {$minKey: 1}}}"); @@ -2773,7 +2799,7 @@ TEST(IndexBoundsBuilderTest, GTEMinKeyWithCollator) { TEST(IndexBoundsBuilderTest, GTMinKeyWithCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$gt: {$minKey: 1}}}"); @@ -2795,7 +2821,7 @@ TEST(IndexBoundsBuilderTest, StringEqualityAgainstHashedIndexWithCollatorUsesHas BSONObj keyPattern = fromjson("{a: 'hashed'}"); BSONElement elt = keyPattern.firstElement(); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(keyPattern); + auto testIndex = buildSimpleIndexEntry(keyPattern); testIndex.collator = &collator; BSONObj obj = fromjson("{a: 'foo'}"); @@ -2824,7 +2850,7 @@ TEST(IndexBoundsBuilderTest, EqualityToNumberAgainstHashedIndexWithCollatorUsesH BSONObj keyPattern = fromjson("{a: 'hashed'}"); BSONElement elt = keyPattern.firstElement(); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(keyPattern); + auto testIndex = buildSimpleIndexEntry(keyPattern); testIndex.collator = &collator; BSONObj obj = fromjson("{a: 3}"); @@ -2851,7 +2877,7 @@ TEST(IndexBoundsBuilderTest, InWithStringAgainstHashedIndexWithCollatorUsesHashO BSONObj keyPattern = fromjson("{a: 'hashed'}"); BSONElement elt = keyPattern.firstElement(); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - IndexEntry testIndex = IndexEntry(keyPattern); + auto testIndex = buildSimpleIndexEntry(keyPattern); testIndex.collator = &collator; BSONObj obj = fromjson("{a: {$in: ['foo']}}"); @@ -2877,7 +2903,7 @@ TEST(IndexBoundsBuilderTest, InWithStringAgainstHashedIndexWithCollatorUsesHashO } TEST(IndexBoundsBuilderTest, TypeArrayWithAdditionalTypesHasOpenBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: ['array', 'long']}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -2894,7 +2920,7 @@ TEST(IndexBoundsBuilderTest, TypeArrayWithAdditionalTypesHasOpenBounds) { } TEST(IndexBoundsBuilderTest, TypeStringOrNumberHasCorrectBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: ['string', 'number']}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -2914,7 +2940,7 @@ TEST(IndexBoundsBuilderTest, TypeStringOrNumberHasCorrectBounds) { } TEST(IndexBoundsBuilderTest, RedundantTypeNumberHasCorrectBounds) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: ['number', 'int', 'long', 'double']}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); BSONElement elt = obj.firstElement(); @@ -2932,49 +2958,49 @@ TEST(IndexBoundsBuilderTest, RedundantTypeNumberHasCorrectBounds) { } TEST(IndexBoundsBuilderTest, CanUseCoveredMatchingForEqualityPredicate) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$eq: 3}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); ASSERT_TRUE(IndexBoundsBuilder::canUseCoveredMatching(expr.get(), testIndex)); } TEST(IndexBoundsBuilderTest, CannotUseCoveredMatchingForEqualityToArrayPredicate) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$eq: [1, 2, 3]}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); ASSERT_FALSE(IndexBoundsBuilder::canUseCoveredMatching(expr.get(), testIndex)); } TEST(IndexBoundsBuilderTest, CannotUseCoveredMatchingForEqualityToNullPredicate) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: null}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); ASSERT_FALSE(IndexBoundsBuilder::canUseCoveredMatching(expr.get(), testIndex)); } TEST(IndexBoundsBuilderTest, CannotUseCoveredMatchingForTypeArrayPredicate) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$type: 'array'}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); ASSERT_FALSE(IndexBoundsBuilder::canUseCoveredMatching(expr.get(), testIndex)); } TEST(IndexBoundsBuilderTest, CannotUseCoveredMatchingForExistsTruePredicate) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$exists: true}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); ASSERT_FALSE(IndexBoundsBuilder::canUseCoveredMatching(expr.get(), testIndex)); } TEST(IndexBoundsBuilderTest, CannotUseCoveredMatchingForExistsFalsePredicate) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); BSONObj obj = fromjson("{a: {$exists: false}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); ASSERT_FALSE(IndexBoundsBuilder::canUseCoveredMatching(expr.get(), testIndex)); } TEST(IndexBoundsBuilderTest, CanUseCoveredMatchingForExistsTrueWithSparseIndex) { - IndexEntry testIndex = IndexEntry(BSONObj()); + auto testIndex = buildSimpleIndexEntry(); testIndex.sparse = true; BSONObj obj = fromjson("{a: {$exists: true}}"); unique_ptr<MatchExpression> expr(parseMatchExpression(obj)); diff --git a/src/mongo/db/query/index_entry.h b/src/mongo/db/query/index_entry.h index a2c9bd555d1..9760fe97ae1 100644 --- a/src/mongo/db/query/index_entry.h +++ b/src/mongo/db/query/index_entry.h @@ -46,9 +46,31 @@ class CollatorInterface; class MatchExpression; /** - * This name sucks, but every name involving 'index' is used somewhere. + * A CoreIndexInfo is a representation of an index in the catalog with parsed information which is + * used for updating indexability discriminators. Its lifetime is not tied to the underlying + * collection. It is a subset of IndexEntry and is missing fields that are expensive or unavailable. */ -struct IndexEntry { +struct CoreIndexInfo { + + struct Identifier; + + CoreIndexInfo(const BSONObj& kp, + IndexType type, + bool sp, + Identifier ident, + const MatchExpression* fe = nullptr, + const CollatorInterface* ci = nullptr, + const ProjectionExecAgg* projExec = nullptr) + : identifier(std::move(ident)), + keyPattern(kp), + filterExpr(fe), + type(type), + sparse(sp), + collator(ci), + wildcardProjection(projExec) { + // We always expect a projection executor for $** indexes, and none otherwise. + invariant((type == IndexType::INDEX_WILDCARD) == (projExec != nullptr)); + } /** * This struct is used to uniquely identify an index. The index "Identifier" has two @@ -92,11 +114,35 @@ struct IndexEntry { // A string used for disambiguating multiple IndexEntries with the same catalogName (such // as in the case with a wildcard index). std::string disambiguator; - }; + } identifier; - /** - * Use this constructor if you're making an IndexEntry from the catalog. - */ + BSONObj keyPattern; + + const MatchExpression* filterExpr; + + // What type of index is this? (What access method can we use on the index described by the + // keyPattern?) + IndexType type; + + bool sparse; + + // Null if this index orders strings according to the simple binary compare. If non-null, + // represents the collator used to generate index keys for indexed strings. + const CollatorInterface* collator = nullptr; + + // For $** indexes, a pointer to the projection executor owned by the index access method. Null + // unless this IndexEntry represents a wildcard index, in which case this is always non-null. + const ProjectionExecAgg* wildcardProjection = nullptr; +}; + +/** + * An IndexEntry is a representation of an index in the catalog with parsed information which is + * helpful for query planning. Its lifetime is not tied to the underlying collection. In contrast + * to CoreIndexInfo, it includes information such as 'multikeyPaths' which can require resources to + * compute (i.e. for wildcard indexes, this requires reading the index) and so may not always be + * available. + */ +struct IndexEntry : CoreIndexInfo { IndexEntry(const BSONObj& kp, IndexType type, bool mk, @@ -109,58 +155,14 @@ struct IndexEntry { const BSONObj& io, const CollatorInterface* ci, const ProjectionExecAgg* projExec) - : keyPattern(kp), + : CoreIndexInfo(kp, type, sp, std::move(ident), fe, ci, projExec), multikey(mk), multikeyPaths(mkp), multikeyPathSet(std::move(multikeyPathSet)), - sparse(sp), unique(unq), - identifier(std::move(ident)), - filterExpr(fe), - infoObj(io), - type(type), - collator(ci), - wildcardProjection(projExec) { + infoObj(io) { // The caller must not supply multikey metadata in two different formats. invariant(multikeyPaths.empty() || multikeyPathSet.empty()); - // We always expect a projection executor for $** indexes, and none otherwise. - invariant((type == IndexType::INDEX_WILDCARD) == (projExec != nullptr)); - } - - /** - * For testing purposes only. - */ - IndexEntry(const BSONObj& kp, - bool mk, - bool sp, - bool unq, - Identifier ident, - const MatchExpression* fe, - const BSONObj& io, - const ProjectionExecAgg* projExec = nullptr) - : keyPattern(kp), - multikey(mk), - sparse(sp), - unique(unq), - identifier(std::move(ident)), - filterExpr(fe), - infoObj(io), - wildcardProjection(projExec) { - type = IndexNames::nameToType(IndexNames::findPluginName(keyPattern)); - } - - /** - * For testing purposes only. - */ - IndexEntry(const BSONObj& kp, const std::string& indexName = "test_foo") - : keyPattern(kp), - multikey(false), - sparse(false), - unique(false), - identifier(indexName), - filterExpr(nullptr), - infoObj(BSONObj()) { - type = IndexNames::nameToType(IndexNames::findPluginName(keyPattern)); } ~IndexEntry() { @@ -186,8 +188,6 @@ struct IndexEntry { std::string toString() const; - BSONObj keyPattern; - bool multikey; // If non-empty, 'multikeyPaths' is a vector with size equal to the number of elements in the @@ -208,28 +208,10 @@ struct IndexEntry { // 'multikeyPathSet' must be empty. std::set<FieldRef> multikeyPathSet; - bool sparse; - bool unique; - Identifier identifier; - - const MatchExpression* filterExpr; - // Geo indices have extra parameters. We need those available to plan correctly. BSONObj infoObj; - - // What type of index is this? (What access method can we use on the index described - // by the keyPattern?) - IndexType type; - - // Null if this index orders strings according to the simple binary compare. If non-null, - // represents the collator used to generate index keys for indexed strings. - const CollatorInterface* collator = nullptr; - - // For $** indexes, a pointer to the projection executor owned by the index access method. Null - // unless this IndexEntry represents a wildcard index, in which case this is always non-null. - const ProjectionExecAgg* wildcardProjection = nullptr; }; std::ostream& operator<<(std::ostream& stream, const IndexEntry::Identifier& ident); diff --git a/src/mongo/db/query/index_entry_test.cpp b/src/mongo/db/query/index_entry_test.cpp index 1e9c4c1cf3b..7626bf215a3 100644 --- a/src/mongo/db/query/index_entry_test.cpp +++ b/src/mongo/db/query/index_entry_test.cpp @@ -40,12 +40,22 @@ namespace mongo { namespace { IndexEntry makeIndexEntry(BSONObj keyPattern, MultikeyPaths multiKeyPaths) { - IndexEntry entry{std::move(keyPattern)}; - entry.multikeyPaths = std::move(multiKeyPaths); - entry.multikey = std::any_of(entry.multikeyPaths.cbegin(), - entry.multikeyPaths.cend(), - [](const auto& entry) { return !entry.empty(); }); - return entry; + bool multiKey = std::any_of(multiKeyPaths.cbegin(), + multiKeyPaths.cend(), + [](const auto& entry) { return !entry.empty(); }); + + return {keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + multiKey, + multiKeyPaths, + {}, + false, + false, + CoreIndexInfo::Identifier("test_foo"), + nullptr, + {}, + nullptr, + nullptr}; } TEST(QueryPlannerIXSelectTest, IndexedFieldHasMultikeyComponents) { diff --git a/src/mongo/db/query/plan_cache.cpp b/src/mongo/db/query/plan_cache.cpp index 0786f995c17..3ea3cf871d7 100644 --- a/src/mongo/db/query/plan_cache.cpp +++ b/src/mongo/db/query/plan_cache.cpp @@ -650,8 +650,8 @@ size_t PlanCache::size() const { return _cache.size(); } -void PlanCache::notifyOfIndexEntries(const std::vector<IndexEntry>& indexEntries) { - _indexabilityState.updateDiscriminators(indexEntries); +void PlanCache::notifyOfIndexUpdates(const std::vector<CoreIndexInfo>& indexCores) { + _indexabilityState.updateDiscriminators(indexCores); } std::vector<BSONObj> PlanCache::getMatchingStats( diff --git a/src/mongo/db/query/plan_cache.h b/src/mongo/db/query/plan_cache.h index 99f88ed23a9..2c8ca6c690c 100644 --- a/src/mongo/db/query/plan_cache.h +++ b/src/mongo/db/query/plan_cache.h @@ -517,7 +517,7 @@ public: * * Callers must hold the collection lock in exclusive mode when calling this method. */ - void notifyOfIndexEntries(const std::vector<IndexEntry>& indexEntries); + void notifyOfIndexUpdates(const std::vector<CoreIndexInfo>& indexCores); /** * Iterates over the plan cache. For each entry, serializes the PlanCacheEntry according to diff --git a/src/mongo/db/query/plan_cache_indexability.cpp b/src/mongo/db/query/plan_cache_indexability.cpp index 488e40d7cc1..f227f8aca20 100644 --- a/src/mongo/db/query/plan_cache_indexability.cpp +++ b/src/mongo/db/query/plan_cache_indexability.cpp @@ -114,11 +114,11 @@ void PlanCacheIndexabilityState::processPartialIndex(const std::string& indexNam } } -void PlanCacheIndexabilityState::processWildcardIndex(const IndexEntry& ie) { - invariant(ie.type == IndexType::INDEX_WILDCARD); +void PlanCacheIndexabilityState::processWildcardIndex(const CoreIndexInfo& cii) { + invariant(cii.type == IndexType::INDEX_WILDCARD); _wildcardIndexDiscriminators.emplace_back( - ie.wildcardProjection, ie.identifier.catalogName, ie.filterExpr, ie.collator); + cii.wildcardProjection, cii.identifier.catalogName, cii.filterExpr, cii.collator); } void PlanCacheIndexabilityState::processIndexCollation(const std::string& indexName, @@ -166,11 +166,12 @@ IndexToDiscriminatorMap PlanCacheIndexabilityState::buildWildcardDiscriminators( return ret; } -void PlanCacheIndexabilityState::updateDiscriminators(const std::vector<IndexEntry>& indexEntries) { +void PlanCacheIndexabilityState::updateDiscriminators( + const std::vector<CoreIndexInfo>& indexCores) { _pathDiscriminatorsMap = PathDiscriminatorsMap(); _wildcardIndexDiscriminators.clear(); - for (const IndexEntry& idx : indexEntries) { + for (const auto& idx : indexCores) { if (idx.type == IndexType::INDEX_WILDCARD) { processWildcardIndex(idx); continue; diff --git a/src/mongo/db/query/plan_cache_indexability.h b/src/mongo/db/query/plan_cache_indexability.h index 1c9991bd019..702dbd20e19 100644 --- a/src/mongo/db/query/plan_cache_indexability.h +++ b/src/mongo/db/query/plan_cache_indexability.h @@ -43,7 +43,7 @@ class BSONObj; class CollatorInterface; class CompositeIndexabilityDiscriminator; class MatchExpression; -struct IndexEntry; +struct CoreIndexInfo; using IndexabilityDiscriminator = stdx::function<bool(const MatchExpression* me)>; using IndexabilityDiscriminators = std::vector<IndexabilityDiscriminator>; @@ -104,9 +104,9 @@ public: IndexToDiscriminatorMap buildWildcardDiscriminators(StringData path) const; /** - * Clears discriminators for all paths, and regenerate them from 'indexEntries'. + * Clears discriminators for all paths, and regenerates them from 'indexCores'. */ - void updateDiscriminators(const std::vector<IndexEntry>& indexEntries); + void updateDiscriminators(const std::vector<CoreIndexInfo>& indexCores); private: using PathDiscriminatorsMap = StringMap<IndexToDiscriminatorMap>; @@ -174,7 +174,7 @@ private: * path, appropriate discriminators for the wildcard index will be included if it includes the * given path. */ - void processWildcardIndex(const IndexEntry& ie); + void processWildcardIndex(const CoreIndexInfo& cii); // PathDiscriminatorsMap is a map from field path to index name to IndexabilityDiscriminator. PathDiscriminatorsMap _pathDiscriminatorsMap; diff --git a/src/mongo/db/query/plan_cache_indexability_test.cpp b/src/mongo/db/query/plan_cache_indexability_test.cpp index dc67fd8c30a..fd13a2b39f1 100644 --- a/src/mongo/db/query/plan_cache_indexability_test.cpp +++ b/src/mongo/db/query/plan_cache_indexability_test.cpp @@ -58,30 +58,40 @@ std::unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj, // The latter simulates the ProjectionExecAgg which, during normal operation, is owned and // maintained by the $** index's IndexAccessMethod, and is required because the plan cache will // obtain unowned pointers to it. -std::pair<IndexEntry, std::unique_ptr<ProjectionExecAgg>> makeWildcardEntry( - BSONObj keyPattern, const MatchExpression* filterExpr = nullptr) { +auto makeWildcardEntry(BSONObj keyPattern, const MatchExpression* filterExpr = nullptr) { auto projExec = WildcardKeyGenerator::createProjectionExec(keyPattern, {}); - return {IndexEntry(keyPattern, - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"indexName"}, - filterExpr, - BSONObj(), - projExec.get()), - std::move(projExec)}; + return std::make_pair(IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"indexName"}, + filterExpr, + BSONObj(), + nullptr, + projExec.get()), + std::move(projExec)); } // Test sparse index discriminators for a simple sparse index. TEST(PlanCacheIndexabilityTest, SparseIndexSimple) { PlanCacheIndexabilityState state; - state.updateDiscriminators({IndexEntry(BSON("a" << 1), - false, // multikey - true, // sparse - false, // unique - IndexEntry::Identifier{"a_1"}, // name - nullptr, // filterExpr - BSONObj())}); + auto keyPattern = BSON("a" << 1); + state.updateDiscriminators( + {IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + true, // sparse + false, // unique + IndexEntry::Identifier{"a_1"}, // name + nullptr, // filterExpr + BSONObj(), + nullptr, + nullptr)}); auto discriminators = state.getDiscriminators("a"); ASSERT_EQ(1U, discriminators.size()); @@ -108,13 +118,20 @@ TEST(PlanCacheIndexabilityTest, SparseIndexSimple) { // Test sparse index discriminators for a compound sparse index. TEST(PlanCacheIndexabilityTest, SparseIndexCompound) { PlanCacheIndexabilityState state; - state.updateDiscriminators({IndexEntry(BSON("a" << 1 << "b" << 1), - false, // multikey - true, // sparse - false, // unique - IndexEntry::Identifier{"a_1_b_1"}, // name - nullptr, // filterExpr - BSONObj())}); + auto keyPattern = BSON("a" << 1 << "b" << 1); + state.updateDiscriminators( + {IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + true, // sparse + false, // unique + IndexEntry::Identifier{"a_1_b_1"}, // name + nullptr, // filterExpr + BSONObj(), + nullptr, + nullptr)}); { auto discriminators = state.getDiscriminators("a"); @@ -148,13 +165,20 @@ TEST(PlanCacheIndexabilityTest, PartialIndexSimple) { BSONObj filterObj = BSON("f" << BSON("$gt" << 0)); std::unique_ptr<MatchExpression> filterExpr(parseMatchExpression(filterObj)); PlanCacheIndexabilityState state; - state.updateDiscriminators({IndexEntry(BSON("a" << 1), - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"a_1"}, // name - filterExpr.get(), - BSONObj())}); + auto keyPattern = BSON("a" << 1); + state.updateDiscriminators( + {IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"a_1"}, // name + filterExpr.get(), + BSONObj(), + nullptr, + nullptr)}); { auto discriminators = state.getDiscriminators("f"); @@ -190,13 +214,20 @@ TEST(PlanCacheIndexabilityTest, PartialIndexAnd) { BSONObj filterObj = BSON("f" << 1 << "g" << 1); std::unique_ptr<MatchExpression> filterExpr(parseMatchExpression(filterObj)); PlanCacheIndexabilityState state; - state.updateDiscriminators({IndexEntry(BSON("a" << 1), - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"a_1"}, // name - filterExpr.get(), - BSONObj())}); + auto keyPattern = BSON("a" << 1); + state.updateDiscriminators( + {IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"a_1"}, // name + filterExpr.get(), + BSONObj(), + nullptr, + nullptr)}); { auto discriminators = state.getDiscriminators("f"); @@ -244,20 +275,33 @@ TEST(PlanCacheIndexabilityTest, MultiplePartialIndexes) { std::unique_ptr<MatchExpression> filterExpr2(parseMatchExpression(filterObj2)); PlanCacheIndexabilityState state; - state.updateDiscriminators({IndexEntry(BSON("a" << 1), - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"a_1"}, // name - filterExpr1.get(), - BSONObj()), - IndexEntry(BSON("b" << 1), - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"b_1"}, // name - filterExpr2.get(), - BSONObj())}); + auto keyPattern_a = BSON("a" << 1); + auto keyPattern_b = BSON("b" << 1); + state.updateDiscriminators( + {IndexEntry(keyPattern_a, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern_a)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"a_1"}, // name + filterExpr1.get(), + BSONObj(), + nullptr, + nullptr), + IndexEntry(keyPattern_b, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern_b)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"b_1"}, // name + filterExpr2.get(), + BSONObj(), + nullptr, + nullptr)}); { auto discriminators = state.getDiscriminators("f"); @@ -317,13 +361,20 @@ TEST(PlanCacheIndexabilityTest, MultiplePartialIndexes) { // collation indexability). TEST(PlanCacheIndexabilityTest, IndexNeitherSparseNorPartial) { PlanCacheIndexabilityState state; - state.updateDiscriminators({IndexEntry(BSON("a" << 1), - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"a_1"}, // name - nullptr, - BSONObj())}); + auto keyPattern = BSON("a" << 1); + state.updateDiscriminators( + {IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"a_1"}, // name + nullptr, + BSONObj(), + nullptr, + nullptr)}); auto discriminators = state.getDiscriminators("a"); ASSERT_EQ(1U, discriminators.size()); ASSERT(discriminators.find("a_1") != discriminators.end()); @@ -332,13 +383,19 @@ TEST(PlanCacheIndexabilityTest, IndexNeitherSparseNorPartial) { // Test discriminator for a simple index with a collation. TEST(PlanCacheIndexabilityTest, DiscriminatorForCollationIndicatesWhenCollationsAreCompatible) { PlanCacheIndexabilityState state; - IndexEntry entry(BSON("a" << 1), - false, // multikey + auto keyPattern = BSON("a" << 1); + IndexEntry entry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, false, // sparse false, // unique IndexEntry::Identifier{"a_1"}, // name nullptr, // filterExpr - BSONObj()); + BSONObj(), + nullptr, + nullptr); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); entry.collator = &collator; state.updateDiscriminators({entry}); @@ -413,13 +470,20 @@ TEST(PlanCacheIndexabilityTest, DiscriminatorForCollationIndicatesWhenCollations // only encode collation indexability). TEST(PlanCacheIndexabilityTest, CompoundIndexCollationDiscriminator) { PlanCacheIndexabilityState state; - state.updateDiscriminators({IndexEntry(BSON("a" << 1 << "b" << 1), - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"a_1_b_1"}, // name - nullptr, - BSONObj())}); + auto keyPattern = BSON("a" << 1 << "b" << 1); + state.updateDiscriminators( + {IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"a_1_b_1"}, // name + nullptr, + BSONObj(), + nullptr, + nullptr)}); auto discriminatorsA = state.getDiscriminators("a"); ASSERT_EQ(1U, discriminatorsA.size()); diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp index dbc5b13dec4..fde92088aa1 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -247,16 +247,34 @@ void assertEquivalent(const char* queryStr, std::pair<IndexEntry, std::unique_ptr<ProjectionExecAgg>> makeWildcardEntry(BSONObj keyPattern) { auto projExec = WildcardKeyGenerator::createProjectionExec(keyPattern, {}); return {IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), false, // multikey + {}, + {}, false, // sparse false, // unique IndexEntry::Identifier{"indexName"}, nullptr, BSONObj(), + nullptr, projExec.get()), std::move(projExec)}; } +// A version of the above for CoreIndexInfo, used for plan cache update tests. +std::pair<CoreIndexInfo, std::unique_ptr<ProjectionExecAgg>> makeWildcardUpdate( + BSONObj keyPattern) { + auto projExec = WildcardKeyGenerator::createProjectionExec(keyPattern, {}); + return {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // sparse + IndexEntry::Identifier{"indexName"}, // name + nullptr, // filterExpr + nullptr, // collation + projExec.get()), // wildcard + std::move(projExec)}; +} + // // Tests for CachedSolution // @@ -872,31 +890,50 @@ protected: } void addIndex(BSONObj keyPattern, const std::string& indexName, bool multikey = false) { - // The first false means not multikey. - // The second false means not sparse. - // The NULL means no filter expression. - params.indices.push_back(IndexEntry(keyPattern, - multikey, - false, - false, - IndexEntry::Identifier{indexName}, - NULL, - BSONObj())); + params.indices.push_back( + IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + multikey, + {}, + {}, + false, + false, + IndexEntry::Identifier{indexName}, + nullptr, + BSONObj(), + nullptr, + nullptr)); } void addIndex(BSONObj keyPattern, const std::string& indexName, bool multikey, bool sparse) { - params.indices.push_back(IndexEntry(keyPattern, - multikey, - sparse, - false, - IndexEntry::Identifier{indexName}, - NULL, - BSONObj())); + params.indices.push_back( + IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + multikey, + {}, + {}, + sparse, + false, + IndexEntry::Identifier{indexName}, + nullptr, + BSONObj(), + nullptr, + nullptr)); } void addIndex(BSONObj keyPattern, const std::string& indexName, CollatorInterface* collator) { - IndexEntry entry( - keyPattern, false, false, false, IndexEntry::Identifier{indexName}, NULL, BSONObj()); + IndexEntry entry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, + {}, + {}, + false, + false, + IndexEntry::Identifier{indexName}, + nullptr, + BSONObj(), + nullptr, + nullptr); entry.collator = collator; params.indices.push_back(entry); } @@ -1763,13 +1800,12 @@ TEST_F(CachePlanSelectionTest, ContainedOrAndIntersection) { // whether or not the predicates in the given query can use the index. TEST(PlanCacheTest, ComputeKeySparseIndex) { PlanCache planCache; - planCache.notifyOfIndexEntries({IndexEntry(BSON("a" << 1), - false, // multikey - true, // sparse - false, // unique - IndexEntry::Identifier{""}, // name - nullptr, // filterExpr - BSONObj())}); + const auto keyPattern = BSON("a" << 1); + planCache.notifyOfIndexUpdates( + {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + true, // sparse + IndexEntry::Identifier{""})}); // name unique_ptr<CanonicalQuery> cqEqNumber(canonicalize("{a: 0}}")); unique_ptr<CanonicalQuery> cqEqString(canonicalize("{a: 'x'}}")); @@ -1797,13 +1833,13 @@ TEST(PlanCacheTest, ComputeKeyPartialIndex) { unique_ptr<MatchExpression> filterExpr(parseMatchExpression(filterObj)); PlanCache planCache; - planCache.notifyOfIndexEntries({IndexEntry(BSON("a" << 1), - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{""}, // name - filterExpr.get(), - BSONObj())}); + const auto keyPattern = BSON("a" << 1); + planCache.notifyOfIndexUpdates( + {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // sparse + IndexEntry::Identifier{""}, // name + filterExpr.get())}); // filterExpr unique_ptr<CanonicalQuery> cqGtNegativeFive(canonicalize("{f: {$gt: -5}}")); unique_ptr<CanonicalQuery> cqGtZero(canonicalize("{f: {$gt: 0}}")); @@ -1822,15 +1858,14 @@ TEST(PlanCacheTest, ComputeKeyCollationIndex) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); PlanCache planCache; - IndexEntry entry(BSON("a" << 1), - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{""}, // name - nullptr, // filterExpr - BSONObj()); - entry.collator = &collator; - planCache.notifyOfIndexEntries({entry}); + const auto keyPattern = BSON("a" << 1); + planCache.notifyOfIndexUpdates( + {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // sparse + IndexEntry::Identifier{""}, // name + nullptr, // filterExpr + &collator)}); // collation unique_ptr<CanonicalQuery> containsString(canonicalize("{a: 'abc'}")); unique_ptr<CanonicalQuery> containsObject(canonicalize("{a: {b: 'abc'}}")); @@ -1887,10 +1922,10 @@ TEST(PlanCacheTest, ComputeKeyCollationIndex) { } TEST(PlanCacheTest, ComputeKeyWildcardIndex) { - auto entryProjExecPair = makeWildcardEntry(BSON("a.$**" << 1)); + auto entryProjUpdatePair = makeWildcardUpdate(BSON("a.$**" << 1)); PlanCache planCache; - planCache.notifyOfIndexEntries({entryProjExecPair.first}); + planCache.notifyOfIndexUpdates({entryProjUpdatePair.first}); // Used to check that two queries have the same shape when no indexes are present. PlanCache planCacheWithNoIndexes; @@ -1950,10 +1985,10 @@ TEST(PlanCacheTest, ComputeKeyWildcardIndex) { } TEST(PlanCacheTest, ComputeKeyWildcardIndexDiscriminatesEqualityToEmptyObj) { - auto entryProjExecPair = makeWildcardEntry(BSON("a.$**" << 1)); + auto entryProjUpdatePair = makeWildcardUpdate(BSON("a.$**" << 1)); PlanCache planCache; - planCache.notifyOfIndexEntries({entryProjExecPair.first}); + planCache.notifyOfIndexUpdates({entryProjUpdatePair.first}); // Equality to empty obj and equality to non-empty obj have different plan cache keys. std::unique_ptr<CanonicalQuery> equalsEmptyObj(canonicalize("{a: {}}")); @@ -1979,14 +2014,13 @@ TEST(PlanCacheTest, StableKeyDoesNotChangeAcrossIndexCreation) { const auto preIndexStableKey = preIndexKey.getStableKey(); ASSERT_EQ(preIndexKey.getUnstablePart(), ""); + const auto keyPattern = BSON("a" << 1); // Create a sparse index (which requires a discriminator). - planCache.notifyOfIndexEntries({IndexEntry(BSON("a" << 1), - false, // multikey - true, // sparse - false, // unique - IndexEntry::Identifier{""}, // name - nullptr, // filterExpr - BSONObj())}); + planCache.notifyOfIndexUpdates( + {CoreIndexInfo(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + true, // sparse + IndexEntry::Identifier{""})}); // name const PlanCacheKey postIndexKey = planCache.computeKey(*cq); const auto postIndexStableKey = postIndexKey.getStableKey(); diff --git a/src/mongo/db/query/planner_analysis_test.cpp b/src/mongo/db/query/planner_analysis_test.cpp index 11fee9f0bc0..1ad7de68ece 100644 --- a/src/mongo/db/query/planner_analysis_test.cpp +++ b/src/mongo/db/query/planner_analysis_test.cpp @@ -42,6 +42,24 @@ using namespace mongo; namespace { +/** + * Make a minimal IndexEntry from just a key pattern. A dummy name will be added. + */ +IndexEntry buildSimpleIndexEntry(const BSONObj& kp) { + return {kp, + IndexNames::nameToType(IndexNames::findPluginName(kp)), + false, + {}, + {}, + false, + false, + CoreIndexInfo::Identifier("test_foo"), + nullptr, + {}, + nullptr, + nullptr}; +} + TEST(QueryPlannerAnalysis, GetSortPatternBasic) { ASSERT_BSONOBJ_EQ(fromjson("{a: 1}"), QueryPlannerAnalysis::getSortPattern(fromjson("{a: 1}"))); ASSERT_BSONOBJ_EQ(fromjson("{a: -1}"), @@ -114,7 +132,7 @@ TEST(QueryPlannerAnalysis, GetSortPatternSpecialIndexTypes) { // Test the generation of sort orders provided by an index scan done by // IndexScanNode::computeProperties(). TEST(QueryPlannerAnalysis, IxscanSortOrdersBasic) { - IndexScanNode ixscan(IndexEntry(fromjson("{a: 1, b: 1, c: 1, d: 1, e: 1}"))); + IndexScanNode ixscan(buildSimpleIndexEntry(fromjson("{a: 1, b: 1, c: 1, d: 1, e: 1}"))); // Bounds are {a: [[1,1]], b: [[2,2]], c: [[3,3]], d: [[1,5]], e:[[1,1],[2,2]]}, // all inclusive. @@ -166,11 +184,11 @@ TEST(QueryPlannerAnalysis, GeoSkipValidation) { BSONObj unsupportedVersion = fromjson("{'2dsphereIndexVersion': 2}"); BSONObj supportedVersion = fromjson("{'2dsphereIndexVersion': 3}"); - IndexEntry relevantIndex(fromjson("{'geometry.field': '2dsphere'}")); - IndexEntry irrelevantIndex(fromjson("{'geometry.field': 1}")); - IndexEntry differentFieldIndex(fromjson("{'geometry.blah': '2dsphere'}")); - IndexEntry compoundIndex(fromjson("{'geometry.field': '2dsphere', 'a': -1}")); - IndexEntry unsupportedIndex(fromjson("{'geometry.field': '2dsphere'}")); + auto relevantIndex = buildSimpleIndexEntry(fromjson("{'geometry.field': '2dsphere'}")); + auto irrelevantIndex = buildSimpleIndexEntry(fromjson("{'geometry.field': 1}")); + auto differentFieldIndex = buildSimpleIndexEntry(fromjson("{'geometry.blah': '2dsphere'}")); + auto compoundIndex = buildSimpleIndexEntry(fromjson("{'geometry.field': '2dsphere', 'a': -1}")); + auto unsupportedIndex = buildSimpleIndexEntry(fromjson("{'geometry.field': '2dsphere'}")); relevantIndex.infoObj = irrelevantIndex.infoObj = differentFieldIndex.infoObj = compoundIndex.infoObj = supportedVersion; diff --git a/src/mongo/db/query/planner_ixselect_test.cpp b/src/mongo/db/query/planner_ixselect_test.cpp index d9acd0a2542..d2a3dc571e7 100644 --- a/src/mongo/db/query/planner_ixselect_test.cpp +++ b/src/mongo/db/query/planner_ixselect_test.cpp @@ -193,6 +193,24 @@ void findRelevantTaggedNodePathsAndIndices(MatchExpression* root, } /** + * Make a minimal IndexEntry from just a key pattern. A dummy name will be added. + */ +IndexEntry buildSimpleIndexEntry(const BSONObj& kp) { + return {kp, + IndexNames::nameToType(IndexNames::findPluginName(kp)), + false, + {}, + {}, + false, + false, + CoreIndexInfo::Identifier("test_foo"), + nullptr, + {}, + nullptr, + nullptr}; +} + +/** * Parses a MatchExpression from query string and passes that along with prefix, collator, and * indices to rateIndices. Verifies results against list of expected paths and expected indices. In * future, we may expand this test function to validate which indices are assigned to which node. @@ -314,7 +332,7 @@ TEST(QueryPlannerIXSelectTest, RateIndicesTaggedNodePathArrayNegation) { */ TEST(QueryPlannerIXSelectTest, ElemMatchNotExistsShouldNotUseSparseIndex) { std::vector<IndexEntry> indices; - auto idxEntry = IndexEntry(BSON("a" << 1)); + auto idxEntry = buildSimpleIndexEntry(BSON("a" << 1)); idxEntry.sparse = true; indices.push_back(idxEntry); std::set<size_t> expectedIndices; @@ -331,7 +349,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchNotExistsShouldNotUseSparseIndex) { */ TEST(QueryPlannerIXSelectTest, ElemMatchInNullValueShouldUseSparseIndex) { std::vector<IndexEntry> indices; - auto idxEntry = IndexEntry(BSON("a" << 1)); + auto idxEntry = buildSimpleIndexEntry(BSON("a" << 1)); idxEntry.sparse = true; indices.push_back(idxEntry); std::set<size_t> expectedIndices = {0}; @@ -344,7 +362,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchInNullValueShouldUseSparseIndex) { */ TEST(QueryPlannerIXSelectTest, ElemMatchGeoShouldNotUseBtreeIndex) { std::vector<IndexEntry> indices; - auto idxEntry = IndexEntry(BSON("a" << 1)); + auto idxEntry = buildSimpleIndexEntry(BSON("a" << 1)); indices.push_back(idxEntry); std::set<size_t> expectedIndices; testRateIndices(R"({a: {$elemMatch: {$geoWithin: {$geometry: {type: 'Polygon', @@ -361,7 +379,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchGeoShouldNotUseBtreeIndex) { */ TEST(QueryPlannerIXSelectTest, ElemMatchEqNullValueShouldUseSparseIndex) { std::vector<IndexEntry> indices; - auto idxEntry = IndexEntry(BSON("a" << 1)); + auto idxEntry = buildSimpleIndexEntry(BSON("a" << 1)); idxEntry.sparse = true; indices.push_back(idxEntry); std::set<size_t> expectedIndices = {0}; @@ -374,7 +392,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchEqNullValueShouldUseSparseIndex) { */ TEST(QueryPlannerIXSelectTest, ElemMatchMultipleChildrenShouldRequireAllToBeCompatible) { std::vector<IndexEntry> indices; - auto idxEntry = IndexEntry(BSON("a" << 1)); + auto idxEntry = buildSimpleIndexEntry(BSON("a" << 1)); idxEntry.sparse = true; indices.push_back(idxEntry); std::set<size_t> expectedIndices; @@ -391,7 +409,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchMultipleChildrenShouldRequireAllToBeComp */ TEST(QueryPlannerIXSelectTest, NullCollatorsMatch) { std::vector<IndexEntry> indices; - indices.push_back(IndexEntry(BSON("a" << 1))); + indices.push_back(buildSimpleIndexEntry(BSON("a" << 1))); std::set<size_t> expectedIndices = {0}; testRateIndices("{a: 'string'}", "", nullptr, indices, "a", expectedIndices); } @@ -402,7 +420,7 @@ TEST(QueryPlannerIXSelectTest, NullCollatorsMatch) { TEST(QueryPlannerIXSelectTest, NonNullCollatorDoesNotMatchIndexWithNullCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); std::vector<IndexEntry> indices; - indices.push_back(IndexEntry(BSON("a" << 1))); + indices.push_back(buildSimpleIndexEntry(BSON("a" << 1))); std::set<size_t> expectedIndices; testRateIndices("{a: 'string'}", "", &collator, indices, "a", expectedIndices); } @@ -411,7 +429,7 @@ TEST(QueryPlannerIXSelectTest, NonNullCollatorDoesNotMatchIndexWithNullCollator) * If the collator is null, we do not select the relevant index with a non-null collator. */ TEST(QueryPlannerIXSelectTest, NullCollatorDoesNotMatchIndexWithNonNullCollator) { - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kAlwaysEqual); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -425,7 +443,7 @@ TEST(QueryPlannerIXSelectTest, NullCollatorDoesNotMatchIndexWithNonNullCollator) */ TEST(QueryPlannerIXSelectTest, EqualCollatorsMatch) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kAlwaysEqual); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -439,7 +457,7 @@ TEST(QueryPlannerIXSelectTest, EqualCollatorsMatch) { */ TEST(QueryPlannerIXSelectTest, UnequalCollatorsDoNotMatch) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -453,7 +471,7 @@ TEST(QueryPlannerIXSelectTest, UnequalCollatorsDoNotMatch) { */ TEST(QueryPlannerIXSelectTest, NoStringComparison) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -464,7 +482,7 @@ TEST(QueryPlannerIXSelectTest, NoStringComparison) { TEST(QueryPlannerIXSelectTest, StringInternalExprEqUnequalCollatorsCannotUseIndex) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -476,7 +494,7 @@ TEST(QueryPlannerIXSelectTest, StringInternalExprEqUnequalCollatorsCannotUseInde TEST(QueryPlannerIXSelectTest, StringInternalExprEqEqualCollatorsCanUseIndex) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -487,7 +505,7 @@ TEST(QueryPlannerIXSelectTest, StringInternalExprEqEqualCollatorsCanUseIndex) { TEST(QueryPlannerIXSelectTest, NestedObjectInternalExprEqUnequalCollatorsCannotUseIndex) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -499,7 +517,7 @@ TEST(QueryPlannerIXSelectTest, NestedObjectInternalExprEqUnequalCollatorsCannotU TEST(QueryPlannerIXSelectTest, NestedObjectInternalExprEqEqualCollatorsCanUseIndex) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -513,7 +531,7 @@ TEST(QueryPlannerIXSelectTest, NestedObjectInternalExprEqEqualCollatorsCanUseInd */ TEST(QueryPlannerIXSelectTest, StringGTUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -527,7 +545,7 @@ TEST(QueryPlannerIXSelectTest, StringGTUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringGTEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -540,7 +558,7 @@ TEST(QueryPlannerIXSelectTest, StringGTEqualCollators) { */ TEST(QueryPlannerIXSelectTest, ArrayGTUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -554,7 +572,7 @@ TEST(QueryPlannerIXSelectTest, ArrayGTUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, ArrayGTEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -567,7 +585,7 @@ TEST(QueryPlannerIXSelectTest, ArrayGTEqualCollators) { */ TEST(QueryPlannerIXSelectTest, NestedObjectGTUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -581,7 +599,7 @@ TEST(QueryPlannerIXSelectTest, NestedObjectGTUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, NestedObjectGTEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -594,7 +612,7 @@ TEST(QueryPlannerIXSelectTest, NestedObjectGTEqualCollators) { */ TEST(QueryPlannerIXSelectTest, StringGTEUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -608,7 +626,7 @@ TEST(QueryPlannerIXSelectTest, StringGTEUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringGTEEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -621,7 +639,7 @@ TEST(QueryPlannerIXSelectTest, StringGTEEqualCollators) { */ TEST(QueryPlannerIXSelectTest, StringLTUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -635,7 +653,7 @@ TEST(QueryPlannerIXSelectTest, StringLTUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringLTEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -648,7 +666,7 @@ TEST(QueryPlannerIXSelectTest, StringLTEqualCollators) { */ TEST(QueryPlannerIXSelectTest, StringLTEUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -662,7 +680,7 @@ TEST(QueryPlannerIXSelectTest, StringLTEUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringLTEEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -675,7 +693,7 @@ TEST(QueryPlannerIXSelectTest, StringLTEEqualCollators) { */ TEST(QueryPlannerIXSelectTest, NoStringComparisonInExpression) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -689,7 +707,7 @@ TEST(QueryPlannerIXSelectTest, NoStringComparisonInExpression) { */ TEST(QueryPlannerIXSelectTest, StringComparisonInExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -703,7 +721,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonInExpressionUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonInExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -716,7 +734,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonInExpressionEqualCollators) { */ TEST(QueryPlannerIXSelectTest, NoStringComparisonNotExpression) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -730,7 +748,7 @@ TEST(QueryPlannerIXSelectTest, NoStringComparisonNotExpression) { */ TEST(QueryPlannerIXSelectTest, StringComparisonNotExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -744,7 +762,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonNotExpressionUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonNotExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -757,7 +775,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonNotExpressionEqualCollators) { */ TEST(QueryPlannerIXSelectTest, NoStringComparisonElemMatchValueExpression) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -771,7 +789,7 @@ TEST(QueryPlannerIXSelectTest, NoStringComparisonElemMatchValueExpression) { */ TEST(QueryPlannerIXSelectTest, StringComparisonElemMatchValueExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -786,7 +804,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonElemMatchValueExpressionUnequalCo */ TEST(QueryPlannerIXSelectTest, StringComparisonElemMatchValueExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -800,7 +818,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonElemMatchValueExpressionEqualColl */ TEST(QueryPlannerIXSelectTest, NoStringComparisonNotInExpression) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -814,7 +832,7 @@ TEST(QueryPlannerIXSelectTest, NoStringComparisonNotInExpression) { */ TEST(QueryPlannerIXSelectTest, StringComparisonNotInExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -828,7 +846,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonNotInExpressionUnequalCollators) */ TEST(QueryPlannerIXSelectTest, StringComparisonNotInExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -841,7 +859,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonNotInExpressionEqualCollators) { */ TEST(QueryPlannerIXSelectTest, NoStringComparisonNinExpression) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -855,7 +873,7 @@ TEST(QueryPlannerIXSelectTest, NoStringComparisonNinExpression) { */ TEST(QueryPlannerIXSelectTest, StringComparisonNinExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -869,7 +887,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonNinExpressionUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonNinExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -882,7 +900,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonNinExpressionEqualCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonOrExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -896,7 +914,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonOrExpressionUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonOrExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -909,7 +927,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonOrExpressionEqualCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonAndExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -923,7 +941,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonAndExpressionUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonAndExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -936,7 +954,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonAndExpressionEqualCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonAllExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -950,7 +968,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonAllExpressionUnequalCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonAllExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -963,7 +981,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonAllExpressionEqualCollators) { */ TEST(QueryPlannerIXSelectTest, StringComparisonElemMatchObjectExpressionUnequalCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a.b" << 1)); + auto index = buildSimpleIndexEntry(BSON("a.b" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -978,7 +996,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonElemMatchObjectExpressionUnequalC */ TEST(QueryPlannerIXSelectTest, StringComparisonElemMatchObjectExpressionEqualCollators) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a.b" << 1)); + auto index = buildSimpleIndexEntry(BSON("a.b" << 1)); index.collator = &collator; std::vector<IndexEntry> indices; indices.push_back(index); @@ -992,7 +1010,7 @@ TEST(QueryPlannerIXSelectTest, StringComparisonElemMatchObjectExpressionEqualCol */ TEST(QueryPlannerIXSelectTest, NoStringComparisonMod) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -1006,7 +1024,7 @@ TEST(QueryPlannerIXSelectTest, NoStringComparisonMod) { */ TEST(QueryPlannerIXSelectTest, NoStringComparisonExists) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -1020,7 +1038,7 @@ TEST(QueryPlannerIXSelectTest, NoStringComparisonExists) { */ TEST(QueryPlannerIXSelectTest, NoStringComparisonType) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); index.collator = &indexCollator; std::vector<IndexEntry> indices; @@ -1036,26 +1054,32 @@ TEST(QueryPlannerIXSelectTest, NoStringComparisonType) { // Helper which constructs an IndexEntry and returns it along with an owned ProjectionExecAgg, which // is non-null if the requested entry represents a wildcard index and null otherwise. When non-null, // it simulates the ProjectionExecAgg that is owned by the $** IndexAccessMethod. -std::pair<IndexEntry, std::unique_ptr<ProjectionExecAgg>> makeIndexEntry( - BSONObj keyPattern, - MultikeyPaths multiKeyPaths, - std::set<FieldRef> multikeyPathSet = {}, - BSONObj infoObj = BSONObj()) { +auto makeIndexEntry(BSONObj keyPattern, + MultikeyPaths multiKeyPaths, + std::set<FieldRef> multiKeyPathSet = {}, + BSONObj infoObj = BSONObj()) { auto projExec = (keyPattern.firstElement().fieldNameStringData().endsWith("$**"_sd) ? WildcardKeyGenerator::createProjectionExec( keyPattern, infoObj.getObjectField("wildcardProjection")) : nullptr); - IndexEntry entry{std::move(keyPattern)}; - entry.multikeyPaths = std::move(multiKeyPaths); - entry.multikey = - !multikeyPathSet.empty() || std::any_of(entry.multikeyPaths.cbegin(), - entry.multikeyPaths.cend(), - [](const auto& entry) { return !entry.empty(); }); - entry.multikeyPathSet = std::move(multikeyPathSet); - entry.wildcardProjection = projExec.get(); - entry.infoObj = infoObj; - return {entry, std::move(projExec)}; + auto multiKey = !multiKeyPathSet.empty() || + std::any_of(multiKeyPaths.cbegin(), multiKeyPaths.cend(), [](const auto& entry) { + return !entry.empty(); + }); + return std::make_pair(IndexEntry(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + multiKey, + multiKeyPaths, + multiKeyPathSet, + false, + false, + CoreIndexInfo::Identifier("test_foo"), + nullptr, + {}, + nullptr, + projExec.get()), + std::move(projExec)); } TEST(QueryPlannerIXSelectTest, InternalExprEqCannotUseMultiKeyIndex) { @@ -1077,7 +1101,7 @@ TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseNonMultikeyFieldOfMultikeyInd } TEST(QueryPlannerIXSelectTest, InternalExprEqCannotUseMultikeyIndexWithoutPathLevelMultikeyData) { - IndexEntry entry{BSON("a" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1)); entry.multikey = true; std::vector<IndexEntry> indices; indices.push_back(entry); @@ -1087,7 +1111,7 @@ TEST(QueryPlannerIXSelectTest, InternalExprEqCannotUseMultikeyIndexWithoutPathLe } TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseNonMultikeyIndexWithNoPathLevelMultikeyData) { - IndexEntry entry{BSON("a" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1)); std::vector<IndexEntry> indices; indices.push_back(entry); std::set<size_t> expectedIndices = {0}; @@ -1096,8 +1120,8 @@ TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseNonMultikeyIndexWithNoPathLev } TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseHashedIndex) { - IndexEntry entry{BSON("a" - << "hashed")}; + auto entry = buildSimpleIndexEntry(BSON("a" + << "hashed")); std::vector<IndexEntry> indices; indices.push_back(entry); std::set<size_t> expectedIndices = {0}; @@ -1106,10 +1130,10 @@ TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseHashedIndex) { } TEST(QueryPlannerIXSelectTest, InternalExprEqCannotUseTextIndexPrefix) { - IndexEntry entry{BSON("a" << 1 << "_fts" - << "text" - << "_ftsx" - << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1 << "_fts" + << "text" + << "_ftsx" + << 1)); std::vector<IndexEntry> indices; indices.push_back(entry); std::set<size_t> expectedIndices; @@ -1118,12 +1142,12 @@ TEST(QueryPlannerIXSelectTest, InternalExprEqCannotUseTextIndexPrefix) { } TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseTextIndexSuffix) { - IndexEntry entry{BSON("_fts" - << "text" - << "_ftsx" - << 1 - << "a" - << 1)}; + auto entry = buildSimpleIndexEntry(BSON("_fts" + << "text" + << "_ftsx" + << 1 + << "a" + << 1)); std::vector<IndexEntry> indices; indices.push_back(entry); std::set<size_t> expectedIndices = {0}; @@ -1132,7 +1156,7 @@ TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseTextIndexSuffix) { } TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseSparseIndexWithComparisonToNull) { - IndexEntry entry{BSON("a" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1)); entry.sparse = true; std::vector<IndexEntry> indices; indices.push_back(entry); @@ -1142,7 +1166,7 @@ TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseSparseIndexWithComparisonToNu } TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseSparseIndexWithComparisonToNonNull) { - IndexEntry entry{BSON("a" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1)); entry.sparse = true; std::vector<IndexEntry> indices; indices.push_back(entry); @@ -1151,20 +1175,20 @@ TEST(QueryPlannerIXSelectTest, InternalExprEqCanUseSparseIndexWithComparisonToNo "{a: {$_internalExprEq: 1}}", "", kSimpleCollator, indices, "a", expectedIndices); } TEST(QueryPlannerIXSelectTest, NotEqualsNullCanUseIndex) { - IndexEntry entry{BSON("a" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1)); std::set<size_t> expectedIndices = {0}; testRateIndices("{a: {$ne: null}}", "", kSimpleCollator, {entry}, "a,a", expectedIndices); } TEST(QueryPlannerIXSelectTest, NotEqualsNullCannotUseMultiKeyIndex) { - IndexEntry entry{BSON("a" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1)); entry.multikey = true; std::set<size_t> expectedIndices = {}; testRateIndices("{a: {$ne: null}}", "", kSimpleCollator, {entry}, "a,a", expectedIndices); } TEST(QueryPlannerIXSelectTest, NotEqualsNullCannotUseDottedMultiKeyIndex) { - IndexEntry entry{BSON("a.b" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a.b" << 1)); entry.multikeyPaths = {{0}}; std::set<size_t> expectedIndices = {}; testRateIndices( @@ -1172,21 +1196,21 @@ TEST(QueryPlannerIXSelectTest, NotEqualsNullCannotUseDottedMultiKeyIndex) { } TEST(QueryPlannerIXSelectTest, NotEqualsNullCanUseIndexWhichIsMultiKeyOnAnotherPath) { - IndexEntry entry{BSON("a" << 1 << "mk" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1 << "mk" << 1)); entry.multikeyPaths = {{}, {0}}; std::set<size_t> expectedIndices = {0}; testRateIndices("{a: {$ne: null}}", "", kSimpleCollator, {entry}, "a,a", expectedIndices); } TEST(QueryPlannerIXSelectTest, ElemMatchValueWithNotEqualsNullCanUseIndex) { - IndexEntry entry{BSON("a" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1)); std::set<size_t> expectedIndices = {0}; testRateIndices( "{a: {$elemMatch: {$ne: null}}}", "", kSimpleCollator, {entry}, "a", expectedIndices); } TEST(QueryPlannerIXSelectTest, ElemMatchValueWithNotEqualsNullCanUseMultiKeyIndex) { - IndexEntry entry{BSON("a" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a" << 1)); entry.multikey = true; std::set<size_t> expectedIndices = {0}; testRateIndices( @@ -1194,7 +1218,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchValueWithNotEqualsNullCanUseMultiKeyInde } TEST(QueryPlannerIXSelectTest, ElemMatchObjectWithNotEqualNullCanUseIndex) { - IndexEntry entry{BSON("a.b" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a.b" << 1)); std::set<size_t> expectedIndices = {0}; testRateIndices("{a: {$elemMatch: {b: {$ne: null}}}}", "", @@ -1205,7 +1229,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchObjectWithNotEqualNullCanUseIndex) { } TEST(QueryPlannerIXSelectTest, ElemMatchObjectWithNotEqualNullCannotUseOldMultiKeyIndex) { - IndexEntry entry{BSON("a.b" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a.b" << 1)); entry.multikey = true; std::set<size_t> expectedIndices = {}; testRateIndices("{a: {$elemMatch: {b: {$ne: null}}}}", @@ -1217,7 +1241,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchObjectWithNotEqualNullCannotUseOldMultiK } TEST(QueryPlannerIXSelectTest, ElemMatchObjectWithNotEqualNullCanUseIndexMultikeyOnPrefix) { - IndexEntry entry{BSON("a.b.c.d" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a.b.c.d" << 1)); entry.multikeyPaths = {{0U}}; std::set<size_t> expectedIndices = {0U}; const auto query = "{'a.b': {$elemMatch: {'c.d': {$ne: null}}}}"; @@ -1237,7 +1261,7 @@ TEST(QueryPlannerIXSelectTest, ElemMatchObjectWithNotEqualNullCanUseIndexMultike TEST(QueryPlannerIXSelectTest, NestedElemMatchObjectWithNotEqualNullCanUseIndexMultikeyOnAnyPrefix) { - IndexEntry entry{BSON("a.b.c.d" << 1)}; + auto entry = buildSimpleIndexEntry(BSON("a.b.c.d" << 1)); entry.multikeyPaths = {{0U}}; std::set<size_t> expectedIndices = {0U}; const auto query = "{a: {$elemMatch: {b: {$elemMatch: {'c.d': {$ne: null}}}}}}"; @@ -1256,16 +1280,16 @@ TEST(QueryPlannerIXSelectTest, } TEST(QueryPlannerIXSelectTest, HashedIndexShouldNotBeRelevantForNotPredicate) { - IndexEntry entry{BSON("a" - << "hashed")}; + auto entry = buildSimpleIndexEntry(BSON("a" + << "hashed")); entry.type = IndexType::INDEX_HASHED; std::set<size_t> expectedIndices = {}; testRateIndices("{a: {$ne: 4}}", "", kSimpleCollator, {entry}, "a,a", expectedIndices); } TEST(QueryPlannerIXSelectTest, HashedIndexShouldNotBeRelevantForNotEqualsNullPredicate) { - IndexEntry entry{BSON("a" - << "hashed")}; + auto entry = buildSimpleIndexEntry(BSON("a" + << "hashed")); entry.type = IndexType::INDEX_HASHED; std::set<size_t> expectedIndices = {}; testRateIndices("{a: {$ne: null}}", "", kSimpleCollator, {entry}, "a,a", expectedIndices); diff --git a/src/mongo/db/query/query_planner_test.cpp b/src/mongo/db/query/query_planner_test.cpp index b5d64fd6f0b..b983cfd2294 100644 --- a/src/mongo/db/query/query_planner_test.cpp +++ b/src/mongo/db/query/query_planner_test.cpp @@ -45,6 +45,24 @@ namespace { using namespace mongo; +/** + * Make a minimal IndexEntry from just a key pattern and a name. + */ +IndexEntry buildSimpleIndexEntry(const BSONObj& kp, const std::string& indexName) { + return {kp, + IndexNames::nameToType(IndexNames::findPluginName(kp)), + false, + {}, + {}, + false, + false, + CoreIndexInfo::Identifier(indexName), + nullptr, + {}, + nullptr, + nullptr}; +} + TEST_F(QueryPlannerTest, PlannerUsesCoveredIxscanForCountWhenIndexSatisfiesQuery) { params.options = QueryPlannerParams::IS_COUNT; addIndex(BSON("x" << 1)); @@ -341,13 +359,19 @@ TEST_F(QueryPlannerTest, NotEqualsNullInElemMatchValueSparseMultiKeyIndex) { } TEST_F(QueryPlannerTest, NotEqualsNullInElemMatchObjectSparseMultiKeyAboveElemMatch) { - IndexEntry ind(BSON("a.b.c.d" << 1), + auto keyPattern = BSON("a.b.c.d" << 1); + IndexEntry ind(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), true, + {}, + {}, true, false, IndexEntry::Identifier{"ind"}, - NULL, // filterExpr - BSONObj()); + nullptr, // filterExpr + BSONObj(), + nullptr, + nullptr); ind.multikeyPaths = {{0U, 1U}}; addIndex(ind); @@ -364,13 +388,19 @@ TEST_F(QueryPlannerTest, NotEqualsNullInElemMatchObjectSparseMultiKeyAboveElemMa TEST_F(QueryPlannerTest, NotEqualsNullInElemMatchObjectSparseMultiKeyBelowElemMatch) { // "a.b.c" being multikey will prevent us from using the index since $elemMatch doesn't do // implicit array traversal. - IndexEntry ind(BSON("a.b.c.d" << 1), + auto keyPattern = BSON("a.b.c.d" << 1); + IndexEntry ind(keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), true, + {}, + {}, true, false, IndexEntry::Identifier{"ind"}, - NULL, // filterExpr - BSONObj()); + nullptr, // filterExpr + BSONObj(), + nullptr, + nullptr); ind.multikeyPaths = {{2U}}; addIndex(ind); @@ -4417,7 +4447,7 @@ TEST_F(QueryPlannerTest, CacheDataFromTaggedTreeFailsOnBadInput) { ASSERT_NOT_OK(QueryPlanner::cacheDataFromTaggedTree(NULL, relevantIndices).getStatus()); // No relevant index matching the index tag. - relevantIndices.push_back(IndexEntry(BSON("a" << 1))); + relevantIndices.push_back(buildSimpleIndexEntry(BSON("a" << 1), "a_1")); auto qr = stdx::make_unique<QueryRequest>(NamespaceString("test.collection")); qr->setFilter(BSON("a" << 3)); @@ -4440,7 +4470,7 @@ TEST_F(QueryPlannerTest, TagAccordingToCacheFailsOnBadInput) { std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue()); std::unique_ptr<PlanCacheIndexTree> indexTree(new PlanCacheIndexTree()); - indexTree->setIndexEntry(IndexEntry(BSON("a" << 1), "a_1")); + indexTree->setIndexEntry(buildSimpleIndexEntry(BSON("a" << 1), "a_1")); std::map<IndexEntry::Identifier, size_t> indexMap; @@ -4470,7 +4500,7 @@ TEST_F(QueryPlannerTest, TagAccordingToCacheFailsOnBadInput) { // Mismatched tree topology. PlanCacheIndexTree* child = new PlanCacheIndexTree(); - child->setIndexEntry(IndexEntry(BSON("a" << 1))); + child->setIndexEntry(buildSimpleIndexEntry(BSON("a" << 1), "a_1")); indexTree->children.push_back(child); s = QueryPlanner::tagAccordingToCache(scopedCq->root(), indexTree.get(), indexMap); ASSERT_NOT_OK(s); diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp index 61367200a6b..01c0823809f 100644 --- a/src/mongo/db/query/query_planner_test_fixture.cpp +++ b/src/mongo/db/query/query_planner_test_fixture.cpp @@ -66,59 +66,85 @@ void QueryPlannerTest::clearState() { } void QueryPlannerTest::addIndex(BSONObj keyPattern, bool multikey) { - params.indices.push_back(IndexEntry(keyPattern, - multikey, - false, // sparse - false, // unique - IndexEntry::Identifier{"hari_king_of_the_stove"}, - NULL, // filterExpr - BSONObj())); + params.indices.push_back({keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + multikey, + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"hari_king_of_the_stove"}, + nullptr, // filterExpr + BSONObj(), + nullptr, + nullptr}); } void QueryPlannerTest::addIndex(BSONObj keyPattern, bool multikey, bool sparse) { - params.indices.push_back(IndexEntry(keyPattern, - multikey, - sparse, - false, // unique - IndexEntry::Identifier{"note_to_self_dont_break_build"}, - NULL, // filterExpr - BSONObj())); + params.indices.push_back({keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + multikey, + {}, + {}, + sparse, + false, // unique + IndexEntry::Identifier{"note_to_self_dont_break_build"}, + nullptr, // filterExpr + BSONObj(), + nullptr, + nullptr}); } void QueryPlannerTest::addIndex(BSONObj keyPattern, bool multikey, bool sparse, bool unique) { params.indices.push_back( - IndexEntry(keyPattern, - multikey, - sparse, - unique, - IndexEntry::Identifier{"sql_query_walks_into_bar_and_says_can_i_join_you?"}, - NULL, // filterExpr - BSONObj())); + {keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + multikey, + {}, + {}, + sparse, + unique, + IndexEntry::Identifier{"sql_query_walks_into_bar_and_says_can_i_join_you?"}, + nullptr, // filterExpr + BSONObj(), + nullptr, + nullptr}); } void QueryPlannerTest::addIndex(BSONObj keyPattern, BSONObj infoObj) { - params.indices.push_back(IndexEntry(keyPattern, - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"foo"}, - NULL, // filterExpr - infoObj)); + params.indices.push_back({keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"foo"}, + nullptr, // filterExpr + infoObj, + nullptr, + nullptr}); } void QueryPlannerTest::addIndex(BSONObj keyPattern, MatchExpression* filterExpr) { - params.indices.push_back(IndexEntry(keyPattern, - false, // multikey - false, // sparse - false, // unique - IndexEntry::Identifier{"foo"}, - filterExpr, - BSONObj())); + params.indices.push_back({keyPattern, + IndexNames::nameToType(IndexNames::findPluginName(keyPattern)), + false, // multikey + {}, + {}, + false, // sparse + false, // unique + IndexEntry::Identifier{"foo"}, + filterExpr, + BSONObj(), + nullptr, + nullptr}); } void QueryPlannerTest::addIndex(BSONObj keyPattern, const MultikeyPaths& multikeyPaths) { invariant(multikeyPaths.size() == static_cast<size_t>(keyPattern.nFields())); + const auto type = IndexNames::nameToType(IndexNames::findPluginName(keyPattern)); const bool multikey = std::any_of(multikeyPaths.cbegin(), multikeyPaths.cend(), @@ -128,21 +154,42 @@ void QueryPlannerTest::addIndex(BSONObj keyPattern, const MultikeyPaths& multike const char name[] = "my_index_with_path_level_multikey_info"; const MatchExpression* filterExpr = nullptr; const BSONObj infoObj; - IndexEntry entry( - keyPattern, multikey, sparse, unique, IndexEntry::Identifier{name}, filterExpr, infoObj); + IndexEntry entry(keyPattern, + type, + multikey, + {}, + {}, + sparse, + unique, + IndexEntry::Identifier{name}, + filterExpr, + infoObj, + nullptr, + nullptr); entry.multikeyPaths = multikeyPaths; params.indices.push_back(entry); } void QueryPlannerTest::addIndex(BSONObj keyPattern, const CollatorInterface* collator) { + const auto type = IndexNames::nameToType(IndexNames::findPluginName(keyPattern)); const bool sparse = false; const bool unique = false; const bool multikey = false; const char name[] = "my_index_with_collator"; const MatchExpression* filterExpr = nullptr; const BSONObj infoObj; - IndexEntry entry( - keyPattern, multikey, sparse, unique, IndexEntry::Identifier{name}, filterExpr, infoObj); + IndexEntry entry(keyPattern, + type, + multikey, + {}, + {}, + sparse, + unique, + IndexEntry::Identifier{name}, + filterExpr, + infoObj, + nullptr, + nullptr); entry.collator = collator; params.indices.push_back(entry); } @@ -150,14 +197,25 @@ void QueryPlannerTest::addIndex(BSONObj keyPattern, const CollatorInterface* col void QueryPlannerTest::addIndex(BSONObj keyPattern, const CollatorInterface* collator, StringData indexName) { + const auto type = IndexNames::nameToType(IndexNames::findPluginName(keyPattern)); const bool sparse = false; const bool unique = false; const bool multikey = false; const auto name = indexName.toString(); const MatchExpression* filterExpr = nullptr; const BSONObj infoObj; - IndexEntry entry( - keyPattern, multikey, sparse, unique, IndexEntry::Identifier{name}, filterExpr, infoObj); + IndexEntry entry(keyPattern, + type, + multikey, + {}, + {}, + sparse, + unique, + IndexEntry::Identifier{name}, + filterExpr, + infoObj, + nullptr, + nullptr); entry.collator = collator; params.indices.push_back(entry); } @@ -165,13 +223,24 @@ void QueryPlannerTest::addIndex(BSONObj keyPattern, void QueryPlannerTest::addIndex(BSONObj keyPattern, MatchExpression* filterExpr, const CollatorInterface* collator) { + const auto type = IndexNames::nameToType(IndexNames::findPluginName(keyPattern)); const bool sparse = false; const bool unique = false; const bool multikey = false; const char name[] = "my_partial_index_with_collator"; const BSONObj infoObj; - IndexEntry entry( - keyPattern, multikey, sparse, unique, IndexEntry::Identifier{name}, filterExpr, infoObj); + IndexEntry entry(keyPattern, + type, + multikey, + {}, + {}, + sparse, + unique, + IndexEntry::Identifier{name}, + filterExpr, + infoObj, + nullptr, + nullptr); entry.collator = collator; params.indices.push_back(entry); } diff --git a/src/mongo/db/query/query_settings_test.cpp b/src/mongo/db/query/query_settings_test.cpp index 9d3365d1f4a..23b5217d467 100644 --- a/src/mongo/db/query/query_settings_test.cpp +++ b/src/mongo/db/query/query_settings_test.cpp @@ -37,6 +37,7 @@ #include "mongo/bson/bsonobj.h" #include "mongo/bson/json.h" #include "mongo/bson/simple_bsonobj_comparator.h" +#include "mongo/db/index_names.h" #include "mongo/db/query/index_entry.h" #include "mongo/unittest/unittest.h" @@ -50,20 +51,31 @@ namespace { TEST(QuerySettingsTest, AllowedIndicesFilterAllowsIndexesByName) { SimpleBSONObjComparator bsonCmp; AllowedIndicesFilter filter(bsonCmp.makeBSONObjSet({fromjson("{a:1}")}), {"a_1"}); - IndexEntry a_idx(fromjson("{a:1, b:1}"), + auto keyPat = fromjson("{a:1, b:1}"); + IndexEntry a_idx(keyPat, + mongo::IndexNames::nameToType(mongo::IndexNames::findPluginName(keyPat)), false, + {}, + {}, false, false, IndexEntry::Identifier{"a_1"}, nullptr, - BSONObj()); - IndexEntry ab_idx(fromjson("{a:1, b:1}"), + BSONObj(), + nullptr, + nullptr); + IndexEntry ab_idx(keyPat, + mongo::IndexNames::nameToType(mongo::IndexNames::findPluginName(keyPat)), false, + {}, + {}, false, false, IndexEntry::Identifier{"a_1:2"}, nullptr, - BSONObj()); + BSONObj(), + nullptr, + nullptr); ASSERT_TRUE(filter.allows(a_idx)); ASSERT_FALSE(filter.allows(ab_idx)); @@ -72,15 +84,32 @@ TEST(QuerySettingsTest, AllowedIndicesFilterAllowsIndexesByName) { TEST(QuerySettingsTest, AllowedIndicesFilterAllowsIndexesByKeyPattern) { SimpleBSONObjComparator bsonCmp; AllowedIndicesFilter filter(bsonCmp.makeBSONObjSet({fromjson("{a:1}")}), {"a"}); - IndexEntry a_idx( - fromjson("{a:1}"), false, false, false, IndexEntry::Identifier{"foo"}, nullptr, BSONObj()); - IndexEntry ab_idx(fromjson("{a:1, b:1}"), + auto keyPat_a = fromjson("{a:1}"); + IndexEntry a_idx(keyPat_a, + mongo::IndexNames::nameToType(mongo::IndexNames::findPluginName(keyPat_a)), + false, + {}, + {}, + false, + false, + IndexEntry::Identifier{"foo"}, + nullptr, + BSONObj(), + nullptr, + nullptr); + auto keyPat_ab = fromjson("{a:1, b:1}"); + IndexEntry ab_idx(keyPat_ab, + mongo::IndexNames::nameToType(mongo::IndexNames::findPluginName(keyPat_ab)), false, + {}, + {}, false, false, IndexEntry::Identifier{"bar"}, nullptr, - BSONObj()); + BSONObj(), + nullptr, + nullptr); ASSERT_TRUE(filter.allows(a_idx)); ASSERT_FALSE(filter.allows(ab_idx)); diff --git a/src/mongo/db/query/query_solution_test.cpp b/src/mongo/db/query/query_solution_test.cpp index 0e05968f887..c8555503e7c 100644 --- a/src/mongo/db/query/query_solution_test.cpp +++ b/src/mongo/db/query/query_solution_test.cpp @@ -44,11 +44,30 @@ namespace { using namespace mongo; +/** + * Make a minimal IndexEntry from just a key pattern. A dummy name will be added. + */ +IndexEntry buildSimpleIndexEntry(const BSONObj& kp) { + return {kp, + IndexNames::nameToType(IndexNames::findPluginName(kp)), + false, + {}, + {}, + false, + false, + CoreIndexInfo::Identifier("test_foo"), + nullptr, + {}, + nullptr, + nullptr}; +} + // Index: {a: 1, b: 1, c: 1, d: 1, e: 1} // Min: {a: 1, b: 1, c: 1, d: 1, e: 1} // Max: {a: 1, b: 1, c: 1, d: 1, e: 1} TEST(QuerySolutionTest, SimpleRangeAllEqual) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; + IndexScanNode node{ + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; node.bounds.isSimpleRange = true; node.bounds.startKey = BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1); node.bounds.endKey = BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1); @@ -71,7 +90,8 @@ TEST(QuerySolutionTest, SimpleRangeAllEqual) { // Min: {a: 1, b: 1, c: 1, d: 1, e: 1} // Max: {a: 2, b: 2, c: 2, d: 2, e: 2} TEST(QuerySolutionTest, SimpleRangeNoneEqual) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; + IndexScanNode node{ + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; node.bounds.isSimpleRange = true; node.bounds.startKey = BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1); node.bounds.endKey = BSON("a" << 2 << "b" << 2 << "c" << 2 << "d" << 2 << "e" << 2); @@ -90,7 +110,8 @@ TEST(QuerySolutionTest, SimpleRangeNoneEqual) { // Min: {a: 1, b: 1, c: 1, d: 1, e: 1} // Max: {a: 1, b: 1, c: 2, d: 2, e: 2} TEST(QuerySolutionTest, SimpleRangeSomeEqual) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; + IndexScanNode node{ + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; node.bounds.isSimpleRange = true; node.bounds.startKey = BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1); node.bounds.endKey = BSON("a" << 1 << "b" << 1 << "c" << 2 << "d" << 2 << "e" << 2); @@ -112,7 +133,8 @@ TEST(QuerySolutionTest, SimpleRangeSomeEqual) { // Index: {a: 1, b: 1, c: 1, d: 1, e: 1} // Intervals: a: [1,1], b: [1,1], c: [1,1], d: [1,1], e: [1,1] TEST(QuerySolutionTest, IntervalListAllPoints) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; + IndexScanNode node{ + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; OrderedIntervalList a{}; a.name = "a"; @@ -158,7 +180,8 @@ TEST(QuerySolutionTest, IntervalListAllPoints) { // Index: {a: 1, b: 1, c: 1, d: 1, e: 1} // Intervals: a: [1,2], b: [1,2], c: [1,2], d: [1,2], e: [1,2] TEST(QuerySolutionTest, IntervalListNoPoints) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; + IndexScanNode node{ + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; OrderedIntervalList a{}; a.name = "a"; @@ -204,7 +227,8 @@ TEST(QuerySolutionTest, IntervalListNoPoints) { // Index: {a: 1, b: 1, c: 1, d: 1, e: 1} // Intervals: a: [1,1], b: [1,1], c: [1,2], d: [1,2], e: [1,2] TEST(QuerySolutionTest, IntervalListSomePoints) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; + IndexScanNode node{ + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; OrderedIntervalList a{}; a.name = "a"; @@ -420,7 +444,7 @@ TEST(QuerySolutionTest, GetFieldsWithStringBoundsIdentifiesStringsWithInclusiveB } TEST(QuerySolutionTest, IndexScanNodeRemovesNonMatchingCollatedFieldsFromSortsOnSimpleBounds) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))}; CollatorInterfaceMock queryCollator(CollatorInterfaceMock::MockType::kReverseString); node.queryCollator = &queryCollator; @@ -437,7 +461,7 @@ TEST(QuerySolutionTest, IndexScanNodeRemovesNonMatchingCollatedFieldsFromSortsOn } TEST(QuerySolutionTest, IndexScanNodeGetFieldsWithStringBoundsCorrectlyHandlesEndKeyInclusive) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))}; CollatorInterfaceMock queryCollator(CollatorInterfaceMock::MockType::kReverseString); node.queryCollator = &queryCollator; @@ -467,7 +491,7 @@ TEST(QuerySolutionTest, IndexScanNodeGetFieldsWithStringBoundsCorrectlyHandlesEn // Index: {a: 1} // Bounds: [MINKEY, MAXKEY] TEST(QuerySolutionTest, IndexScanNodeRemovesCollatedFieldsFromSortsIfCollationDifferent) { - IndexScanNode node{IndexEntry(BSON("a" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1))}; CollatorInterfaceMock queryCollator(CollatorInterfaceMock::MockType::kReverseString); node.queryCollator = &queryCollator; @@ -484,7 +508,7 @@ TEST(QuerySolutionTest, IndexScanNodeRemovesCollatedFieldsFromSortsIfCollationDi } TEST(QuerySolutionTest, IndexScanNodeDoesNotRemoveCollatedFieldsFromSortsIfCollationMatches) { - IndexScanNode node{IndexEntry(BSON("a" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1))}; CollatorInterfaceMock queryCollator(CollatorInterfaceMock::MockType::kReverseString); OrderedIntervalList oilA{}; @@ -503,11 +527,13 @@ TEST(QuerySolutionTest, IndexScanNodeDoesNotRemoveCollatedFieldsFromSortsIfColla // Index: {a: 1, b: 1, c: 1, d: 1, e: 1} // Intervals: a: [1,1], b: [1,1], c: [MinKey, MaxKey], d: [1,2], e: [1,2] TEST(QuerySolutionTest, CompoundIndexWithNonMatchingCollationFiltersAllSortsWithCollatedField) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; + IndexScanNode node{ + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1))}; CollatorInterfaceMock queryCollator(CollatorInterfaceMock::MockType::kReverseString); node.queryCollator = &queryCollator; - node.index = IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1)); + node.index = + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1 << "e" << 1)); OrderedIntervalList a{}; a.name = "a"; @@ -548,7 +574,7 @@ TEST(QuerySolutionTest, CompoundIndexWithNonMatchingCollationFiltersAllSortsWith // Index: {a : 1} // Bounds: [{}, {}] TEST(QuerySolutionTest, IndexScanNodeWithNonMatchingCollationFiltersObjectField) { - IndexScanNode node{IndexEntry(BSON("a" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1))}; CollatorInterfaceMock queryCollator(CollatorInterfaceMock::MockType::kReverseString); node.queryCollator = &queryCollator; @@ -568,7 +594,7 @@ TEST(QuerySolutionTest, IndexScanNodeWithNonMatchingCollationFiltersObjectField) // Index: {a : 1} // Bounds: [[], []] TEST(QuerySolutionTest, IndexScanNodeWithNonMatchingCollationFiltersArrayField) { - IndexScanNode node{IndexEntry(BSON("a" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1))}; CollatorInterfaceMock queryCollator(CollatorInterfaceMock::MockType::kReverseString); node.queryCollator = &queryCollator; @@ -586,7 +612,7 @@ TEST(QuerySolutionTest, IndexScanNodeWithNonMatchingCollationFiltersArrayField) } TEST(QuerySolutionTest, WithNonMatchingCollatorAndNoEqualityPrefixSortsAreNotDuplicated) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))}; CollatorInterfaceMock queryCollator(CollatorInterfaceMock::MockType::kReverseString); node.queryCollator = &queryCollator; @@ -614,7 +640,7 @@ TEST(QuerySolutionTest, WithNonMatchingCollatorAndNoEqualityPrefixSortsAreNotDup } TEST(QuerySolutionTest, IndexScanNodeHasFieldIncludesStringFieldWhenNoCollator) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))}; OrderedIntervalList oilA{}; oilA.name = "a"; @@ -636,7 +662,7 @@ TEST(QuerySolutionTest, IndexScanNodeHasFieldIncludesStringFieldWhenNoCollator) } TEST(QuerySolutionTest, IndexScanNodeHasFieldIncludesSimpleBoundsStringFieldWhenNoCollator) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))}; node.bounds.isSimpleRange = true; node.bounds.startKey = BSON("a" << 1 << "b" << 2); @@ -648,7 +674,7 @@ TEST(QuerySolutionTest, IndexScanNodeHasFieldIncludesSimpleBoundsStringFieldWhen } TEST(QuerySolutionTest, IndexScanNodeHasFieldExcludesStringFieldWhenIndexHasCollator) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))}; CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); node.index.collator = &indexCollator; @@ -673,7 +699,7 @@ TEST(QuerySolutionTest, IndexScanNodeHasFieldExcludesStringFieldWhenIndexHasColl } TEST(QuerySolutionTest, IndexScanNodeHasFieldExcludesSimpleBoundsStringFieldWhenIndexHasCollator) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))}; CollatorInterfaceMock indexCollator(CollatorInterfaceMock::MockType::kReverseString); node.index.collator = &indexCollator; @@ -710,7 +736,7 @@ std::unique_ptr<ParsedProjection> createParsedProjection(const BSONObj& query, } TEST(QuerySolutionTest, InclusionProjectionPreservesSort) { - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); auto node = stdx::make_unique<IndexScanNode>(index); BSONObj projection = BSON("a" << 1); @@ -727,7 +753,7 @@ TEST(QuerySolutionTest, InclusionProjectionPreservesSort) { } TEST(QuerySolutionTest, ExclusionProjectionDoesNotPreserveSort) { - IndexEntry index(BSON("a" << 1)); + auto index = buildSimpleIndexEntry(BSON("a" << 1)); auto node = stdx::make_unique<IndexScanNode>(index); BSONObj projection = BSON("a" << 0); @@ -743,7 +769,7 @@ TEST(QuerySolutionTest, ExclusionProjectionDoesNotPreserveSort) { } TEST(QuerySolutionTest, InclusionProjectionTruncatesSort) { - auto node = stdx::make_unique<IndexScanNode>(IndexEntry(BSON("a" << 1 << "b" << 1))); + auto node = stdx::make_unique<IndexScanNode>(buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))); BSONObj projection = BSON("a" << 1); BSONObj match; @@ -759,7 +785,7 @@ TEST(QuerySolutionTest, InclusionProjectionTruncatesSort) { } TEST(QuerySolutionTest, ExclusionProjectionTruncatesSort) { - auto node = stdx::make_unique<IndexScanNode>(IndexEntry(BSON("a" << 1 << "b" << 1))); + auto node = stdx::make_unique<IndexScanNode>(buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1))); BSONObj projection = BSON("b" << 0); BSONObj match; @@ -775,7 +801,8 @@ TEST(QuerySolutionTest, ExclusionProjectionTruncatesSort) { } TEST(QuerySolutionTest, NonMultikeyIndexWithoutPathLevelInfoCanCoverItsFields) { - auto node = stdx::make_unique<IndexScanNode>(IndexEntry(BSON("a" << 1 << "b.c.d" << 1))); + auto node = + stdx::make_unique<IndexScanNode>(buildSimpleIndexEntry(BSON("a" << 1 << "b.c.d" << 1))); node->index.multikey = false; node->index.multikeyPaths = MultikeyPaths{}; ASSERT_TRUE(node->hasField("a")); @@ -786,7 +813,8 @@ TEST(QuerySolutionTest, NonMultikeyIndexWithoutPathLevelInfoCanCoverItsFields) { } TEST(QuerySolutionTest, NonMultikeyIndexWithPathLevelInfoCanCoverItsFields) { - auto node = stdx::make_unique<IndexScanNode>(IndexEntry(BSON("a" << 1 << "b.c.d" << 1))); + auto node = + stdx::make_unique<IndexScanNode>(buildSimpleIndexEntry(BSON("a" << 1 << "b.c.d" << 1))); node->index.multikey = false; node->index.multikeyPaths = MultikeyPaths{{}, {}}; ASSERT_TRUE(node->hasField("a")); @@ -797,7 +825,8 @@ TEST(QuerySolutionTest, NonMultikeyIndexWithPathLevelInfoCanCoverItsFields) { } TEST(QuerySolutionTest, MultikeyIndexWithoutPathLevelInfoCannotCoverAnyFields) { - auto node = stdx::make_unique<IndexScanNode>(IndexEntry(BSON("a" << 1 << "b.c.d" << 1))); + auto node = + stdx::make_unique<IndexScanNode>(buildSimpleIndexEntry(BSON("a" << 1 << "b.c.d" << 1))); node->index.multikey = true; node->index.multikeyPaths = MultikeyPaths{}; ASSERT_FALSE(node->hasField("a")); @@ -808,8 +837,8 @@ TEST(QuerySolutionTest, MultikeyIndexWithoutPathLevelInfoCannotCoverAnyFields) { } TEST(QuerySolutionTest, MultikeyIndexWithPathLevelInfoCanCoverNonMultikeyFields) { - auto node = - stdx::make_unique<IndexScanNode>(IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1))); + auto node = stdx::make_unique<IndexScanNode>( + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1))); // Add metadata indicating that "b" is multikey. node->index.multikey = true; @@ -822,8 +851,8 @@ TEST(QuerySolutionTest, MultikeyIndexWithPathLevelInfoCanCoverNonMultikeyFields) } TEST(QuerySolutionTest, MultikeyIndexCannotCoverFieldWithAnyMultikeyPathComponent) { - auto node = - stdx::make_unique<IndexScanNode>(IndexEntry(BSON("a" << 1 << "b.c.d" << 1 << "e" << 1))); + auto node = stdx::make_unique<IndexScanNode>( + buildSimpleIndexEntry(BSON("a" << 1 << "b.c.d" << 1 << "e" << 1))); // Add metadata indicating that "b.c" is multikey. node->index.multikey = true; @@ -837,7 +866,7 @@ TEST(QuerySolutionTest, MultikeyIndexCannotCoverFieldWithAnyMultikeyPathComponen } TEST(QuerySolutionTest, MultikeyIndexWithoutPathLevelInfoCannotProvideAnySorts) { - IndexScanNode node{IndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c" << 1))}; node.index.multikey = true; { @@ -861,7 +890,7 @@ TEST(QuerySolutionTest, MultikeyIndexWithoutPathLevelInfoCannotProvideAnySorts) TEST(QuerySolutionTest, SimpleRangeAllEqualExcludesFieldWithMultikeyComponent) { IndexScanNode node{ - IndexEntry(BSON("a" << 1 << "b" << 1 << "c.z" << 1 << "d" << 1 << "e" << 1))}; + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c.z" << 1 << "d" << 1 << "e" << 1))}; node.bounds.isSimpleRange = true; node.bounds.startKey = BSON("a" << 1 << "b" << 1 << "c.z" << 1 << "d" << 1 << "e" << 1); node.bounds.endKey = BSON("a" << 1 << "b" << 1 << "c.z" << 1 << "d" << 1 << "e" << 1); @@ -880,7 +909,7 @@ TEST(QuerySolutionTest, SimpleRangeAllEqualExcludesFieldWithMultikeyComponent) { } TEST(QuerySolutionTest, MultikeyFieldsEmptyWhenIndexIsNotMultikey) { - IndexScanNode node{IndexEntry(BSON("a.b" << 1 << "c.d" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a.b" << 1 << "c.d" << 1))}; node.index.multikey = false; node.index.multikeyPaths = MultikeyPaths{}; node.computeProperties(); @@ -888,7 +917,7 @@ TEST(QuerySolutionTest, MultikeyFieldsEmptyWhenIndexIsNotMultikey) { } TEST(QuerySolutionTest, MultikeyFieldsEmptyWhenIndexHasNoMultikeynessMetadata) { - IndexScanNode node{IndexEntry(BSON("a.b" << 1 << "c.d" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a.b" << 1 << "c.d" << 1))}; node.index.multikey = true; node.index.multikeyPaths = MultikeyPaths{}; node.computeProperties(); @@ -896,7 +925,7 @@ TEST(QuerySolutionTest, MultikeyFieldsEmptyWhenIndexHasNoMultikeynessMetadata) { } TEST(QuerySolutionTest, MultikeyFieldsChosenCorrectlyWhenIndexHasPathLevelMultikeyMetadata) { - IndexScanNode node{IndexEntry(BSON("a.b" << 1 << "c.d" << 1 << "e.f" << 1))}; + IndexScanNode node{buildSimpleIndexEntry(BSON("a.b" << 1 << "c.d" << 1 << "e.f" << 1))}; node.index.multikey = true; node.index.multikeyPaths = MultikeyPaths{{0U}, {}, {0U, 1U}}; node.computeProperties(); @@ -907,7 +936,7 @@ TEST(QuerySolutionTest, MultikeyFieldsChosenCorrectlyWhenIndexHasPathLevelMultik TEST(QuerySolutionTest, NonSimpleRangeAllEqualExcludesFieldWithMultikeyComponent) { IndexScanNode node{ - IndexEntry(BSON("a" << 1 << "b" << 1 << "c.z" << 1 << "d" << 1 << "e" << 1))}; + buildSimpleIndexEntry(BSON("a" << 1 << "b" << 1 << "c.z" << 1 << "d" << 1 << "e" << 1))}; // Add metadata indicating that "c.z" is multikey. node.index.multikey = true; node.index.multikeyPaths = MultikeyPaths{{}, {}, {1U}, {}, {}}; |