diff options
author | James Wahlin <james@mongodb.com> | 2018-10-01 16:05:08 -0400 |
---|---|---|
committer | James Wahlin <james@mongodb.com> | 2018-10-02 09:56:37 -0400 |
commit | f7ddb89c8caf438781de9191d690d03f711b63fe (patch) | |
tree | 9244266869d8c17de23d5e0c817a2fddc2bc849a /src/mongo/db/query | |
parent | 5a6ee566f608c46654133de17a4e8bb3464d680d (diff) | |
download | mongo-f7ddb89c8caf438781de9191d690d03f711b63fe.tar.gz |
SERVER-37188 Rename "All Paths" index to "Wildcard" index
Diffstat (limited to 'src/mongo/db/query')
20 files changed, 344 insertions, 344 deletions
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index 3ce7ee94e67..64018a41388 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -24,7 +24,7 @@ env.Library( "plan_cache_indexability.cpp", "plan_enumerator.cpp", "planner_access.cpp", - "planner_allpaths_helpers.cpp", + "planner_wildcard_helpers.cpp", "planner_analysis.cpp", "planner_ixselect.cpp", "query_planner.cpp", @@ -341,12 +341,12 @@ env.CppUnitTest( env.CppUnitTest( target="query_planner_test", source=[ - "query_planner_all_paths_index_test.cpp", "query_planner_array_test.cpp", "query_planner_collation_test.cpp", "query_planner_geo_test.cpp", "query_planner_partialidx_test.cpp", "query_planner_test.cpp", + "query_planner_wildcard_index_test.cpp", ], LIBDEPS=[ "collation/collator_interface_mock", diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 958049fbdfd..161b73386dc 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -51,8 +51,8 @@ #include "mongo/db/exec/sort_key_generator.h" #include "mongo/db/exec/subplan.h" #include "mongo/db/exec/update.h" -#include "mongo/db/index/all_paths_access_method.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index/wildcard_access_method.h" #include "mongo/db/index_names.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/matcher/extensions_callback_real.h" diff --git a/src/mongo/db/query/index_bounds_builder.cpp b/src/mongo/db/query/index_bounds_builder.cpp index 13d45890e72..fdfcfc2096c 100644 --- a/src/mongo/db/query/index_bounds_builder.cpp +++ b/src/mongo/db/query/index_bounds_builder.cpp @@ -45,8 +45,8 @@ #include "mongo/db/query/expression_index.h" #include "mongo/db/query/expression_index_knobs.h" #include "mongo/db/query/indexability.h" -#include "mongo/db/query/planner_allpaths_helpers.h" #include "mongo/db/query/planner_ixselect.h" +#include "mongo/db/query/planner_wildcard_helpers.h" #include "mongo/db/query/query_knobs.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" @@ -57,7 +57,7 @@ namespace mongo { namespace { -namespace app = ::mongo::all_paths_planning; +namespace app = ::mongo::wildcard_planning; // Helper for checking that an OIL "appears" to be ascending given one interval. void assertOILIsAscendingLocally(const vector<Interval>& intervals, size_t idx) { @@ -344,8 +344,8 @@ void IndexBoundsBuilder::translate(const MatchExpression* expr, // Under certain circumstances, queries on a $** index require that the bounds' tightness be // adjusted regardless of the predicate. Having filled out the initial bounds, we apply any // necessary changes to the tightness here. - if (index.type == IndexType::INDEX_ALLPATHS) { - *tightnessOut = app::applyAllPathsIndexScanBoundsTightness(index, *tightnessOut); + if (index.type == IndexType::INDEX_WILDCARD) { + *tightnessOut = app::applyWildcardIndexScanBoundsTightness(index, *tightnessOut); } } diff --git a/src/mongo/db/query/index_entry.h b/src/mongo/db/query/index_entry.h index c032b47d785..c028618394e 100644 --- a/src/mongo/db/query/index_entry.h +++ b/src/mongo/db/query/index_entry.h @@ -87,7 +87,7 @@ struct IndexEntry { std::string catalogName; // A string used for disambiguating multiple IndexEntries with the same catalogName (such - // as in the case with an allPaths index). + // as in the case with a wildcard index). std::string disambiguator; }; diff --git a/src/mongo/db/query/plan_cache.cpp b/src/mongo/db/query/plan_cache.cpp index 49020044448..4fccc01a648 100644 --- a/src/mongo/db/query/plan_cache.cpp +++ b/src/mongo/db/query/plan_cache.cpp @@ -326,16 +326,16 @@ void encodeIndexability(const MatchExpression* tree, const IndexToDiscriminatorMap& discriminators = indexabilityState.getDiscriminators(tree->path()); - IndexToDiscriminatorMap allPathsDiscriminators = - indexabilityState.buildAllPathsDiscriminators(tree->path()); - if (discriminators.empty() && allPathsDiscriminators.empty()) { + IndexToDiscriminatorMap wildcardDiscriminators = + indexabilityState.buildWildcardDiscriminators(tree->path()); + if (discriminators.empty() && wildcardDiscriminators.empty()) { return; } *keyBuilder << kEncodeDiscriminatorsBegin; // For each discriminator on this path, append the character '0' or '1'. encodeIndexabilityForDiscriminators(tree, discriminators, keyBuilder); - encodeIndexabilityForDiscriminators(tree, allPathsDiscriminators, keyBuilder); + encodeIndexabilityForDiscriminators(tree, wildcardDiscriminators, keyBuilder); *keyBuilder << kEncodeDiscriminatorsEnd; } diff --git a/src/mongo/db/query/plan_cache_indexability.cpp b/src/mongo/db/query/plan_cache_indexability.cpp index 353c5c87fe3..462b4ecedc1 100644 --- a/src/mongo/db/query/plan_cache_indexability.cpp +++ b/src/mongo/db/query/plan_cache_indexability.cpp @@ -32,7 +32,7 @@ #include "mongo/base/init.h" #include "mongo/base/owned_pointer_vector.h" -#include "mongo/db/index/all_paths_key_generator.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_internal_expr_eq.h" @@ -112,11 +112,11 @@ void PlanCacheIndexabilityState::processPartialIndex(const std::string& indexNam } } -void PlanCacheIndexabilityState::processAllPathsIndex(const IndexEntry& ie) { - invariant(ie.type == IndexType::INDEX_ALLPATHS); +void PlanCacheIndexabilityState::processWildcardIndex(const IndexEntry& ie) { + invariant(ie.type == IndexType::INDEX_WILDCARD); - _allPathsIndexDiscriminators.emplace_back( - AllPathsKeyGenerator::createProjectionExec(ie.keyPattern, + _wildcardIndexDiscriminators.emplace_back( + WildcardKeyGenerator::createProjectionExec(ie.keyPattern, ie.infoObj.getObjectField("wildcardProjection")), ie.identifier.catalogName, ie.filterExpr, @@ -145,23 +145,23 @@ const IndexToDiscriminatorMap& PlanCacheIndexabilityState::getDiscriminators( return it->second; } -IndexToDiscriminatorMap PlanCacheIndexabilityState::buildAllPathsDiscriminators( +IndexToDiscriminatorMap PlanCacheIndexabilityState::buildWildcardDiscriminators( StringData path) const { IndexToDiscriminatorMap ret; - for (auto&& allPathsDiscriminator : _allPathsIndexDiscriminators) { - if (allPathsDiscriminator.projectionExec->applyProjectionToOneField(path)) { - CompositeIndexabilityDiscriminator& cid = ret[allPathsDiscriminator.catalogName]; + for (auto&& wildcardDiscriminator : _wildcardIndexDiscriminators) { + if (wildcardDiscriminator.projectionExec->applyProjectionToOneField(path)) { + CompositeIndexabilityDiscriminator& cid = ret[wildcardDiscriminator.catalogName]; // We can use these 'shallow' functions because the code building the plan cache key // will descend the match expression for us, and check the discriminator's return value // at each node. - cid.addDiscriminator(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex); + cid.addDiscriminator(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex); cid.addDiscriminator(nodeIsConservativelySupportedBySparseIndex); - cid.addDiscriminator(getCollatedIndexDiscriminator(allPathsDiscriminator.collator)); - if (allPathsDiscriminator.filterExpr) { + cid.addDiscriminator(getCollatedIndexDiscriminator(wildcardDiscriminator.collator)); + if (wildcardDiscriminator.filterExpr) { cid.addDiscriminator( - getPartialIndexDiscriminator(allPathsDiscriminator.filterExpr)); + getPartialIndexDiscriminator(wildcardDiscriminator.filterExpr)); } } } @@ -172,8 +172,8 @@ void PlanCacheIndexabilityState::updateDiscriminators(const std::vector<IndexEnt _pathDiscriminatorsMap = PathDiscriminatorsMap(); for (const IndexEntry& idx : indexEntries) { - if (idx.type == IndexType::INDEX_ALLPATHS) { - processAllPathsIndex(idx); + 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 7f43a60cace..a79aceaef3d 100644 --- a/src/mongo/db/query/plan_cache_indexability.h +++ b/src/mongo/db/query/plan_cache_indexability.h @@ -96,10 +96,10 @@ public: const IndexToDiscriminatorMap& getDiscriminators(StringData path) const; /** - * Construct an IndexToDiscriminator map for the given path, only for the allPaths indexes + * Construct an IndexToDiscriminator map for the given path, only for the wildcard indexes * which have been included in the indexability state. */ - IndexToDiscriminatorMap buildAllPathsDiscriminators(StringData path) const; + IndexToDiscriminatorMap buildWildcardDiscriminators(StringData path) const; /** * Clears discriminators for all paths, and regenerate them from 'indexEntries'. @@ -114,8 +114,8 @@ private: * every possible field that it indexes, so we have to maintain some special context about the * index. */ - struct AllPathsIndexDiscriminatorContext { - AllPathsIndexDiscriminatorContext(std::unique_ptr<ProjectionExecAgg> proj, + struct WildcardIndexDiscriminatorContext { + WildcardIndexDiscriminatorContext(std::unique_ptr<ProjectionExecAgg> proj, std::string name, const MatchExpression* filter, const CollatorInterface* coll) @@ -169,15 +169,15 @@ private: /** * Adds special state for a $** index. When the discriminators are retrieved for a certain - * path, appropriate discriminators for the allPaths index will be included if it includes the + * path, appropriate discriminators for the wildcard index will be included if it includes the * given path. */ - void processAllPathsIndex(const IndexEntry& ie); + void processWildcardIndex(const IndexEntry& ie); // PathDiscriminatorsMap is a map from field path to index name to IndexabilityDiscriminator. PathDiscriminatorsMap _pathDiscriminatorsMap; - std::vector<AllPathsIndexDiscriminatorContext> _allPathsIndexDiscriminators; + std::vector<WildcardIndexDiscriminatorContext> _wildcardIndexDiscriminators; }; } // namespace mongo diff --git a/src/mongo/db/query/plan_cache_indexability_test.cpp b/src/mongo/db/query/plan_cache_indexability_test.cpp index 6531b5cae30..f0775219d26 100644 --- a/src/mongo/db/query/plan_cache_indexability_test.cpp +++ b/src/mongo/db/query/plan_cache_indexability_test.cpp @@ -409,7 +409,7 @@ TEST(PlanCacheIndexabilityTest, CompoundIndexCollationDiscriminator) { ASSERT(discriminatorsB.find("a_1_b_1") != discriminatorsB.end()); } -TEST(PlanCacheIndexabilityTest, AllPathsDiscriminator) { +TEST(PlanCacheIndexabilityTest, WildcardDiscriminator) { PlanCacheIndexabilityState state; state.updateDiscriminators({IndexEntry(BSON("a.$**" << 1), false, // multikey @@ -419,10 +419,10 @@ TEST(PlanCacheIndexabilityTest, AllPathsDiscriminator) { nullptr, BSONObj())}); - const auto unindexedPathDiscriminators = state.buildAllPathsDiscriminators("notIndexed"); + const auto unindexedPathDiscriminators = state.buildWildcardDiscriminators("notIndexed"); ASSERT_EQ(0U, unindexedPathDiscriminators.size()); - auto discriminatorsA = state.buildAllPathsDiscriminators("a"); + auto discriminatorsA = state.buildWildcardDiscriminators("a"); ASSERT_EQ(1U, discriminatorsA.size()); ASSERT(discriminatorsA.find("indexName") != discriminatorsA.end()); @@ -431,16 +431,16 @@ TEST(PlanCacheIndexabilityTest, AllPathsDiscriminator) { ASSERT_TRUE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: 'abc'}")).get())); - // Querying for object values isn't support by allPaths indexes. + // Querying for object values isn't support by wildcard indexes. ASSERT_FALSE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: {b: 1}}")).get())); ASSERT_FALSE(disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: {}}")).get())); ASSERT_FALSE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: {$lt: {}}}")).get())); - // Querying for array values isn't supported by allPaths indexes. + // Querying for array values isn't supported by wildcard indexes. ASSERT_FALSE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: [1, 2, 3]}")).get())); - // Querying for null isn't supported by allPaths indexes. + // Querying for null isn't supported by wildcard indexes. ASSERT_FALSE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: null}")).get())); @@ -470,7 +470,7 @@ TEST(PlanCacheIndexabilityTest, AllPathsDiscriminator) { parseMatchExpression(fromjson("{a: {$in: [1, 2, null]}}")).get())); } -TEST(PlanCacheIndexabilityTest, AllPathsWithCollationDiscriminator) { +TEST(PlanCacheIndexabilityTest, WildcardWithCollationDiscriminator) { PlanCacheIndexabilityState state; IndexEntry entry(BSON("a.$**" << 1), false, // multikey @@ -483,10 +483,10 @@ TEST(PlanCacheIndexabilityTest, AllPathsWithCollationDiscriminator) { entry.collator = &collator; state.updateDiscriminators({entry}); - const auto unindexedPathDiscriminators = state.buildAllPathsDiscriminators("notIndexed"); + const auto unindexedPathDiscriminators = state.buildWildcardDiscriminators("notIndexed"); ASSERT_EQ(0U, unindexedPathDiscriminators.size()); - auto discriminatorsA = state.buildAllPathsDiscriminators("a"); + auto discriminatorsA = state.buildWildcardDiscriminators("a"); ASSERT_EQ(1U, discriminatorsA.size()); ASSERT(discriminatorsA.find("indexName") != discriminatorsA.end()); @@ -500,7 +500,7 @@ TEST(PlanCacheIndexabilityTest, AllPathsWithCollationDiscriminator) { parseMatchExpression(fromjson("{a: \"hello world\"}"), &collator).get())); } -TEST(PlanCacheIndexabilityTest, AllPathsPartialIndexDiscriminator) { +TEST(PlanCacheIndexabilityTest, WildcardPartialIndexDiscriminator) { PlanCacheIndexabilityState state; // Need to keep the filter BSON object around for the duration of the test since the match @@ -516,7 +516,7 @@ TEST(PlanCacheIndexabilityTest, AllPathsPartialIndexDiscriminator) { BSONObj()); state.updateDiscriminators({entry}); - auto discriminatorsA = state.buildAllPathsDiscriminators("a"); + auto discriminatorsA = state.buildWildcardDiscriminators("a"); ASSERT_EQ(1U, discriminatorsA.size()); ASSERT(discriminatorsA.find("indexName") != discriminatorsA.end()); diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp index f72c3ab15dc..f971200edbf 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -1271,9 +1271,9 @@ TEST_F(CachePlanSelectionTest, AndWithinPolygonWithinCenterSphere) { } // $** index -TEST_F(CachePlanSelectionTest, AllPathsIxScan) { +TEST_F(CachePlanSelectionTest, WildcardIxScan) { params.indices.push_back(IndexEntry(BSON("$**" << 1), - IndexType::INDEX_ALLPATHS, + IndexType::INDEX_WILDCARD, false, // multikey {}, // multikey paths {}, // multikeyPathSet @@ -1966,7 +1966,7 @@ TEST(PlanCacheTest, ComputeKeyCollationIndex) { planCache.computeKey(*inContainsStringHasCollation)); } -TEST(PlanCacheTest, ComputeKeyAllPathsIndex) { +TEST(PlanCacheTest, ComputeKeyWildcardIndex) { PlanCache planCache; IndexEntry entry(BSON("a.$**" << 1), false, // multikey @@ -2007,8 +2007,8 @@ TEST(PlanCacheTest, ComputeKeyAllPathsIndex) { ASSERT_EQ(planCache.computeKey(*usesPathWithObject), planCache.computeKey(*usesPathWithEmptyObject)); - // The query on 'b' should have a completely different plan cache key (both with and without an - // allPaths index). + // The query on 'b' should have a completely different plan cache key (both with and without a + // wildcard index). ASSERT_NE(planCacheWithNoIndexes.computeKey(*usesPathWithScalar), planCacheWithNoIndexes.computeKey(*doesNotUsePath)); ASSERT_NE(planCache.computeKey(*usesPathWithScalar), planCache.computeKey(*doesNotUsePath)); diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp index 2be774dafcf..026e994b301 100644 --- a/src/mongo/db/query/planner_access.cpp +++ b/src/mongo/db/query/planner_access.cpp @@ -45,7 +45,7 @@ #include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/index_tag.h" #include "mongo/db/query/indexability.h" -#include "mongo/db/query/planner_allpaths_helpers.h" +#include "mongo/db/query/planner_wildcard_helpers.h" #include "mongo/db/query/query_knobs.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/query/query_planner_common.h" @@ -57,7 +57,7 @@ namespace { using namespace mongo; -namespace app = ::mongo::all_paths_planning; +namespace app = ::mongo::wildcard_planning; namespace dps = ::mongo::dotted_path_support; /** @@ -530,10 +530,10 @@ void QueryPlannerAccess::finishTextNode(QuerySolutionNode* node, const IndexEntr tn->indexPrefix = prefixBob.obj(); } -void QueryPlannerAccess::finishAllPathsIndexScanNode(QuerySolutionNode* node, +void QueryPlannerAccess::finishWildcardIndexScanNode(QuerySolutionNode* node, const IndexEntry& plannerIndex) { // We should only ever reach this point if we are an IndexScanNode for a $** index. - invariant(plannerIndex.type == IndexType::INDEX_ALLPATHS); + invariant(plannerIndex.type == IndexType::INDEX_WILDCARD); invariant(node && node->getType() == STAGE_IXSCAN); // Sanity check the QuerySolutionNode's copy of the IndexEntry. @@ -676,8 +676,8 @@ void QueryPlannerAccess::finishLeafNode(QuerySolutionNode* node, const IndexEntr } // If this is a $** index, update and populate the keyPattern, bounds, and multikeyPaths. - if (index.type == IndexType::INDEX_ALLPATHS) { - finishAllPathsIndexScanNode(node, index); + if (index.type == IndexType::INDEX_WILDCARD) { + finishWildcardIndexScanNode(node, index); } // Find the first field in the scan's bounds that was not filled out. @@ -1068,12 +1068,12 @@ std::unique_ptr<QuerySolutionNode> QueryPlannerAccess::buildIndexedAnd( andResult = std::move(ixscanNodes[0]); } else { // $** indexes are prohibited from participating in either AND_SORTED or AND_HASH. - const bool allPathsIndexInvolvedInIntersection = + const bool wildcardIndexInvolvedInIntersection = std::any_of(ixscanNodes.begin(), ixscanNodes.end(), [](const auto& ixScan) { return ixScan->getType() == StageType::STAGE_IXSCAN && - static_cast<IndexScanNode*>(ixScan.get())->index.type == INDEX_ALLPATHS; + static_cast<IndexScanNode*>(ixScan.get())->index.type == INDEX_WILDCARD; }); - if (allPathsIndexInvolvedInIntersection) { + if (wildcardIndexInvolvedInIntersection) { return nullptr; } diff --git a/src/mongo/db/query/planner_access.h b/src/mongo/db/query/planner_access.h index cf559315f2b..fec5ef6b793 100644 --- a/src/mongo/db/query/planner_access.h +++ b/src/mongo/db/query/planner_access.h @@ -388,7 +388,7 @@ private: static void finishTextNode(QuerySolutionNode* node, const IndexEntry& index); - static void finishAllPathsIndexScanNode(QuerySolutionNode* node, const IndexEntry& index); + static void finishWildcardIndexScanNode(QuerySolutionNode* node, const IndexEntry& index); /** * Add the filter 'match' to the query solution node 'node'. Takes diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp index 8dd796ac18c..8a7f005d9c1 100644 --- a/src/mongo/db/query/planner_ixselect.cpp +++ b/src/mongo/db/query/planner_ixselect.cpp @@ -34,8 +34,8 @@ #include "mongo/base/simple_string_data_comparator.h" #include "mongo/db/geo/hash.h" -#include "mongo/db/index/all_paths_key_generator.h" #include "mongo/db/index/s2_common.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/index_names.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_geo.h" @@ -44,7 +44,7 @@ #include "mongo/db/query/collation/collator_interface.h" #include "mongo/db/query/index_tag.h" #include "mongo/db/query/indexability.h" -#include "mongo/db/query/planner_allpaths_helpers.h" +#include "mongo/db/query/planner_wildcard_helpers.h" #include "mongo/db/query/query_planner_common.h" #include "mongo/util/log.h" @@ -52,31 +52,31 @@ namespace mongo { namespace { -namespace app = ::mongo::all_paths_planning; +namespace app = ::mongo::wildcard_planning; std::size_t numPathComponents(StringData path) { return FieldRef{path}.numParts(); } /** - * Given a single allPaths index, and a set of fields which are being queried, create 'mock' + * Given a single wildcard index, and a set of fields which are being queried, create 'mock' * IndexEntry for each of the appropriate fields. */ -void expandIndex(const IndexEntry& allPathsIndex, +void expandIndex(const IndexEntry& wildcardIndex, const stdx::unordered_set<std::string>& fields, vector<IndexEntry>* out) { invariant(out); - invariant(allPathsIndex.type == INDEX_ALLPATHS); + invariant(wildcardIndex.type == INDEX_WILDCARD); // Should only have one field of the form {"path.$**" : 1}. - invariant(allPathsIndex.keyPattern.nFields() == 1); + invariant(wildcardIndex.keyPattern.nFields() == 1); // $** indexes do not keep the multikey metadata inside the index catalog entry, as the amount // of metadata is not bounded. We do not expect IndexEntry objects for $** indexes to have a // fixed-size vector of multikey metadata until after they are expanded. - invariant(allPathsIndex.multikeyPaths.empty()); + invariant(wildcardIndex.multikeyPaths.empty()); - const auto projExec = AllPathsKeyGenerator::createProjectionExec( - allPathsIndex.keyPattern, allPathsIndex.infoObj.getObjectField("wildcardProjection")); + const auto projExec = WildcardKeyGenerator::createProjectionExec( + wildcardIndex.keyPattern, wildcardIndex.infoObj.getObjectField("wildcardProjection")); const auto projectedFields = projExec->applyProjectionToFields(fields); @@ -91,8 +91,8 @@ void expandIndex(const IndexEntry& allPathsIndex, // in-memory. Here we convert this set of all multikey paths into a MultikeyPaths vector // which will indicate to the downstream planning code which components of 'fieldName' are // multikey. - auto multikeyPaths = app::buildMultiKeyPathsForExpandedAllPathsIndexEntry( - queryPath, allPathsIndex.multikeyPathSet); + auto multikeyPaths = app::buildMultiKeyPathsForExpandedWildcardIndexEntry( + queryPath, wildcardIndex.multikeyPathSet); // Check whether a query on the current fieldpath is answerable by the $** index, given any // numerical path components that may be present in the path string. @@ -109,8 +109,8 @@ void expandIndex(const IndexEntry& allPathsIndex, invariant(multikeyPaths.size() == 1u); const bool isMultikey = !multikeyPaths[0].empty(); - IndexEntry entry(BSON(fieldName << allPathsIndex.keyPattern.firstElement()), - IndexType::INDEX_ALLPATHS, + IndexEntry entry(BSON(fieldName << wildcardIndex.keyPattern.firstElement()), + IndexType::INDEX_WILDCARD, isMultikey, std::move(multikeyPaths), // Expanded index entries always use the fixed-size multikey paths @@ -118,17 +118,17 @@ void expandIndex(const IndexEntry& allPathsIndex, {}, true, // sparse false, // unique - {allPathsIndex.identifier.catalogName, fieldName}, - allPathsIndex.filterExpr, - allPathsIndex.infoObj, - allPathsIndex.collator); + {wildcardIndex.identifier.catalogName, fieldName}, + wildcardIndex.filterExpr, + wildcardIndex.infoObj, + wildcardIndex.collator); invariant("$_path"_sd != fieldName); out->push_back(std::move(entry)); } } -bool canUseAllPathsIndex(BSONElement elt, MatchExpression::MatchType matchType) { +bool canUseWildcardIndex(BSONElement elt, MatchExpression::MatchType matchType) { if (elt.type() == BSONType::Object) { return false; } @@ -370,7 +370,7 @@ std::vector<IndexEntry> QueryPlannerIXSelect::expandIndexes( const std::vector<IndexEntry>& relevantIndices) { std::vector<IndexEntry> out; for (auto&& entry : relevantIndices) { - if (entry.type == IndexType::INDEX_ALLPATHS) { + if (entry.type == IndexType::INDEX_WILDCARD) { expandIndex(entry, fields, &out); } else { out.push_back(entry); @@ -513,7 +513,7 @@ bool QueryPlannerIXSelect::_compatible(const BSONElement& keyPatternElt, } } - if (index.type == IndexType::INDEX_ALLPATHS && !nodeIsSupportedByAllPathsIndex(node)) { + if (index.type == IndexType::INDEX_WILDCARD && !nodeIsSupportedByWildcardIndex(node)) { return false; } @@ -652,8 +652,8 @@ bool QueryPlannerIXSelect::nodeIsSupportedBySparseIndex(const MatchExpression* q return true; } -bool QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex(const MatchExpression* queryExpr) { - // AllPaths indexes only store index keys for "leaf" nodes in an object. That is, they do not +bool QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex(const MatchExpression* queryExpr) { + // Wildcard indexes only store index keys for "leaf" nodes in an object. That is, they do not // store keys for nested objects, meaning that any kind of comparison to an object or array // cannot be answered by the index (including with a $in). @@ -661,14 +661,14 @@ bool QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex(const MatchExpression* const ComparisonMatchExpression* cmpExpr = static_cast<const ComparisonMatchExpression*>(queryExpr); - return canUseAllPathsIndex(cmpExpr->getData(), cmpExpr->matchType()); + return canUseWildcardIndex(cmpExpr->getData(), cmpExpr->matchType()); } else if (queryExpr->matchType() == MatchExpression::MATCH_IN) { const auto* queryExprIn = static_cast<const InMatchExpression*>(queryExpr); return std::all_of( queryExprIn->getEqualities().begin(), queryExprIn->getEqualities().end(), - [](const BSONElement& elt) { return canUseAllPathsIndex(elt, MatchExpression::EQ); }); + [](const BSONElement& elt) { return canUseWildcardIndex(elt, MatchExpression::EQ); }); } return true; @@ -766,7 +766,7 @@ void QueryPlannerIXSelect::_rateIndices(MatchExpression* node, // static void QueryPlannerIXSelect::stripInvalidAssignments(MatchExpression* node, const vector<IndexEntry>& indices) { - stripInvalidAssignmentsToAllPathsIndexes(node, indices); + stripInvalidAssignmentsToWildcardIndexes(node, indices); stripInvalidAssignmentsToTextIndexes(node, indices); if (MatchExpression::GEO != node->matchType() && @@ -955,13 +955,13 @@ void QueryPlannerIXSelect::stripInvalidAssignmentsToPartialIndices( } // -// AllPaths index invalid assignments. +// Wildcard index invalid assignments. // -void QueryPlannerIXSelect::stripInvalidAssignmentsToAllPathsIndexes( +void QueryPlannerIXSelect::stripInvalidAssignmentsToWildcardIndexes( MatchExpression* root, const vector<IndexEntry>& indices) { for (size_t idx = 0; idx < indices.size(); ++idx) { // Skip over all indexes except $**. - if (indices[idx].type != IndexType::INDEX_ALLPATHS) { + if (indices[idx].type != IndexType::INDEX_WILDCARD) { continue; } // If we have a $** index, check whether we have a TEXT node in the MatchExpression tree. diff --git a/src/mongo/db/query/planner_ixselect.h b/src/mongo/db/query/planner_ixselect.h index 01123e652b8..e2591ab3650 100644 --- a/src/mongo/db/query/planner_ixselect.h +++ b/src/mongo/db/query/planner_ixselect.h @@ -152,9 +152,9 @@ public: const std::vector<IndexEntry>& relevantIndices); /** - * Check if this match expression is a leaf and is supported by an allPaths index. + * Check if this match expression is a leaf and is supported by a wildcard index. */ - static bool nodeIsSupportedByAllPathsIndex(const MatchExpression* queryExpr); + static bool nodeIsSupportedByWildcardIndex(const MatchExpression* queryExpr); /* * Return true if the given match expression can use a sparse index, false otherwise. This will @@ -245,14 +245,14 @@ private: const std::vector<IndexEntry>& indices); /** - * This function strips RelevantTag assignments to expanded 'allPaths' indexes, in cases where + * This function strips RelevantTag assignments to expanded 'wildcard' indexes, in cases where * the assignment is incompatible with the query. * - * Specifically, if the query has a TEXT node with both 'text' and 'allPaths' indexes present, - * then the 'allPaths' index will mark itself as relevant to the '_fts' path reported by the - * TEXT node. We therefore remove any such misassigned 'allPaths' tags here. + * Specifically, if the query has a TEXT node with both 'text' and 'wildcard' indexes present, + * then the 'wildcard' index will mark itself as relevant to the '_fts' path reported by the + * TEXT node. We therefore remove any such misassigned 'wildcard' tags here. */ - static void stripInvalidAssignmentsToAllPathsIndexes(MatchExpression* root, + static void stripInvalidAssignmentsToWildcardIndexes(MatchExpression* root, const std::vector<IndexEntry>& indices); /** diff --git a/src/mongo/db/query/planner_ixselect_test.cpp b/src/mongo/db/query/planner_ixselect_test.cpp index 20bdf3f3d5a..bb51baa461a 100644 --- a/src/mongo/db/query/planner_ixselect_test.cpp +++ b/src/mongo/db/query/planner_ixselect_test.cpp @@ -1288,7 +1288,7 @@ bool indexEntryKeyPatternsMatch(vector<BSONObj>* keyPatterns, vector<IndexEntry> }); } -TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndices) { +TEST(QueryPlannerIXSelectTest, ExpandWildcardIndices) { const auto indexEntry = makeIndexEntry(BSON("$**" << 1), {}); // Case where no fields are specified. @@ -1302,15 +1302,15 @@ TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndices) { std::vector<BSONObj> expectedKeyPatterns = {BSON("fieldA" << 1), BSON("fieldB" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); - const auto allPathsIndexWithSubpath = makeIndexEntry(BSON("a.b.$**" << 1), {}); + const auto wildcardIndexWithSubpath = makeIndexEntry(BSON("a.b.$**" << 1), {}); fields = {"a.b", "a.b.c", "a.d"}; - result = QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexWithSubpath}); + result = QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexWithSubpath}); expectedKeyPatterns = {BSON("a.b" << 1), BSON("a.b.c" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndicesInPresenceOfOtherIndices) { - auto allPathsIndexEntry = makeIndexEntry(BSON("$**" << 1), {}); +TEST(QueryPlannerIXSelectTest, ExpandWildcardIndicesInPresenceOfOtherIndices) { + auto wildcardIndexEntry = makeIndexEntry(BSON("$**" << 1), {}); auto aIndexEntry = makeIndexEntry(BSON("fieldA" << 1), {}); auto bIndexEntry = makeIndexEntry(BSON("fieldB" << 1), {}); auto abIndexEntry = makeIndexEntry(BSON("fieldA" << 1 << "fieldB" << 1), {}); @@ -1319,18 +1319,18 @@ TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndicesInPresenceOfOtherIndices) { std::vector<BSONObj> expectedKeyPatterns = { BSON("fieldA" << 1), BSON("fieldA" << 1), BSON("fieldB" << 1), BSON("fieldC" << 1)}; - auto result = QueryPlannerIXSelect::expandIndexes(fields, {aIndexEntry, allPathsIndexEntry}); + auto result = QueryPlannerIXSelect::expandIndexes(fields, {aIndexEntry, wildcardIndexEntry}); ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); result.clear(); expectedKeyPatterns = { BSON("fieldB" << 1), BSON("fieldA" << 1), BSON("fieldB" << 1), BSON("fieldC" << 1)}; - result = QueryPlannerIXSelect::expandIndexes(fields, {bIndexEntry, allPathsIndexEntry}); + result = QueryPlannerIXSelect::expandIndexes(fields, {bIndexEntry, wildcardIndexEntry}); ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); result.clear(); result = - QueryPlannerIXSelect::expandIndexes(fields, {aIndexEntry, allPathsIndexEntry, bIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {aIndexEntry, wildcardIndexEntry, bIndexEntry}); expectedKeyPatterns = {BSON("fieldA" << 1), BSON("fieldA" << 1), BSON("fieldB" << 1), @@ -1339,7 +1339,7 @@ TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndicesInPresenceOfOtherIndices) { ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); result.clear(); - result = QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry, abIndexEntry}); + result = QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry, abIndexEntry}); expectedKeyPatterns = {BSON("fieldA" << 1), BSON("fieldB" << 1), BSON("fieldC" << 1), @@ -1349,11 +1349,11 @@ TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndicesInPresenceOfOtherIndices) { } TEST(QueryPlannerIXSelectTest, ExpandedIndexEntriesAreCorrectlyMarkedAsMultikeyOrNonMultikey) { - auto allPathsIndexEntry = makeIndexEntry(BSON("$**" << 1), {}, {FieldRef{"a"}}); + auto wildcardIndexEntry = makeIndexEntry(BSON("$**" << 1), {}, {FieldRef{"a"}}); const stdx::unordered_set<string> fields = {"a.b", "c.d"}; std::vector<BSONObj> expectedKeyPatterns = {BSON("a.b" << 1), BSON("c.d" << 1)}; - auto result = QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + auto result = QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); for (auto&& entry : result) { @@ -1371,7 +1371,7 @@ TEST(QueryPlannerIXSelectTest, ExpandedIndexEntriesAreCorrectlyMarkedAsMultikeyO } } -TEST(QueryPlannerIXSelectTest, AllPathsIndexExpansionExcludesIdField) { +TEST(QueryPlannerIXSelectTest, WildcardIndexExpansionExcludesIdField) { const auto indexEntry = makeIndexEntry(BSON("$**" << 1), {}); stdx::unordered_set<string> fields = {"_id", "abc", "def"}; @@ -1381,14 +1381,14 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndexExpansionExcludesIdField) { ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesExpandedEntryHasCorrectProperties) { - auto allPathsIndexEntry = makeIndexEntry(BSON("$**" << 1), {}); - allPathsIndexEntry.identifier = IndexEntry::Identifier("someIndex"); +TEST(QueryPlannerIXSelectTest, WildcardIndicesExpandedEntryHasCorrectProperties) { + auto wildcardIndexEntry = makeIndexEntry(BSON("$**" << 1), {}); + wildcardIndexEntry.identifier = IndexEntry::Identifier("someIndex"); stdx::unordered_set<string> fields = {"abc", "def"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = {BSON("abc" << 1), BSON("def" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); @@ -1400,57 +1400,57 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndicesExpandedEntryHasCorrectProperties) ASSERT_EQ(ie.multikeyPaths.size(), 1u); ASSERT_TRUE(ie.multikeyPaths[0].empty()); - // AllPaths indices are always sparse. + // Wildcard indices are always sparse. ASSERT_TRUE(ie.sparse); - // AllPaths indexes are never unique. + // Wildcard indexes are never unique. ASSERT_FALSE(ie.unique); ASSERT_EQ(ie.identifier, - IndexEntry::Identifier(allPathsIndexEntry.identifier.catalogName, + IndexEntry::Identifier(wildcardIndexEntry.identifier.catalogName, ie.keyPattern.firstElementFieldName())); } } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesExcludeNonMatchingKeySubpath) { - auto allPathsIndexEntry = makeIndexEntry(BSON("subpath.$**" << 1), {}); +TEST(QueryPlannerIXSelectTest, WildcardIndicesExcludeNonMatchingKeySubpath) { + auto wildcardIndexEntry = makeIndexEntry(BSON("subpath.$**" << 1), {}); stdx::unordered_set<string> fields = {"abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("subpath.abc" << 1), BSON("subpath.def" << 1), BSON("subpath" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesExcludeNonMatchingPathsWithInclusionProjection) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesExcludeNonMatchingPathsWithInclusionProjection) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("abc" << 1 << "subpath.abc" << 1))); stdx::unordered_set<string> fields = {"abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = {BSON("abc" << 1), BSON("subpath.abc" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesExcludeNonMatchingPathsWithExclusionProjection) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesExcludeNonMatchingPathsWithExclusionProjection) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("abc" << 0 << "subpath.abc" << 0))); stdx::unordered_set<string> fields = {"abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("def" << 1), BSON("subpath.def" << 1), BSON("subpath" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithInclusionProjectionAllowIdExclusion) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesWithInclusionProjectionAllowIdExclusion) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("_id" << 0 << "abc" << 1 << "subpath.abc" << 1))); @@ -1459,13 +1459,13 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithInclusionProjectionAllowIdExcl "_id", "abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = {BSON("abc" << 1), BSON("subpath.abc" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithInclusionProjectionAllowIdInclusion) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesWithInclusionProjectionAllowIdInclusion) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("_id" << 1 << "abc" << 1 << "subpath.abc" << 1))); @@ -1474,14 +1474,14 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithInclusionProjectionAllowIdIncl "_id", "abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("_id" << 1), BSON("abc" << 1), BSON("subpath.abc" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithExclusionProjectionAllowIdInclusion) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesWithExclusionProjectionAllowIdInclusion) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("_id" << 1 << "abc" << 0 << "subpath.abc" << 0))); @@ -1490,42 +1490,42 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithExclusionProjectionAllowIdIncl "_id", "abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("_id" << 1), BSON("def" << 1), BSON("subpath.def" << 1), BSON("subpath" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesIncludeMatchingInternalNodes) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesIncludeMatchingInternalNodes) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("_id" << 1 << "subpath" << 1))); stdx::unordered_set<string> fields = { "_id", "abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("_id" << 1), BSON("subpath.abc" << 1), BSON("subpath.def" << 1), BSON("subpath" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndexSupported) { - ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( +TEST(QueryPlannerIXSelectTest, WildcardIndexSupported) { + ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: {abc: 1}}")).get())); - ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: {$lt: {abc: 1}}}")).get())); - ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: {$in: [1, 2, 3, {abc: 1}]}}")).get())); } -TEST(QueryPlannerIXSelectTest, AllPathsIndexSupportedDoesNotTraverse) { +TEST(QueryPlannerIXSelectTest, WildcardIndexSupportedDoesNotTraverse) { // The function will not traverse a node's children. - ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{$or: [{z: {abc: 1}}]}")).get())); - ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: 5, y: {abc: 1}}")).get())); - ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: {$ne: {abc: 1}}}")).get())); } diff --git a/src/mongo/db/query/planner_allpaths_helpers.cpp b/src/mongo/db/query/planner_wildcard_helpers.cpp index b56de29e577..6f44f0eb50c 100644 --- a/src/mongo/db/query/planner_allpaths_helpers.cpp +++ b/src/mongo/db/query/planner_wildcard_helpers.cpp @@ -30,7 +30,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/query/planner_allpaths_helpers.h" +#include "mongo/db/query/planner_wildcard_helpers.h" #include <vector> @@ -38,7 +38,7 @@ #include "mongo/util/log.h" namespace mongo { -namespace all_paths_planning { +namespace wildcard_planning { namespace { /** * Compares the path 'fieldNameOrArrayIndexPath' to 'staticComparisonPath', ignoring any array @@ -136,7 +136,7 @@ FieldRef pathWithoutSpecifiedComponents(const FieldRef& path, } } // namespace -MultikeyPaths buildMultiKeyPathsForExpandedAllPathsIndexEntry( +MultikeyPaths buildMultiKeyPathsForExpandedWildcardIndexEntry( const FieldRef& indexedPath, const std::set<FieldRef>& multikeyPathSet) { FieldRef pathToLookup; std::set<std::size_t> multikeyPaths; @@ -155,7 +155,7 @@ std::set<FieldRef> generateFieldNameOrArrayIndexPathSet(const std::set<std::size // The algorithm is unavoidably O(n2^n), but we enforce that 'n' is never more than single // digits during the planner's index selection phase. const auto potentialArrayIndices = findArrayIndexPathComponents(multikeyPaths, queryPath); - invariant(potentialArrayIndices.size() <= kAllPathsMaxArrayIndexTraversalDepth); + invariant(potentialArrayIndices.size() <= kWildcardMaxArrayIndexTraversalDepth); invariant(potentialArrayIndices.size() < sizeof(size_t) * 8u); // We iterate over every value [0..2^n), where 'n' is the size of 'potentialArrayIndices', // treating each value as a 'bitMask' of 'n' bits. Each bit in 'bitMask' represents the @@ -178,13 +178,13 @@ std::set<FieldRef> generateFieldNameOrArrayIndexPathSet(const std::set<std::size return paths; } -BoundsTightness applyAllPathsIndexScanBoundsTightness(const IndexEntry& index, +BoundsTightness applyWildcardIndexScanBoundsTightness(const IndexEntry& index, BoundsTightness tightnessIn) { // This method should only ever be called for a $** IndexEntry. We expect to be called during - // planning, *before* finishAllPathsIndexScanNode has been invoked. The IndexEntry should thus + // planning, *before* finishWildcardIndexScanNode has been invoked. The IndexEntry should thus // only have a single keyPattern field and multikeyPath entry, but this is sufficient to // determine whether it will be necessary to adjust the tightness. - invariant(index.type == IndexType::INDEX_ALLPATHS); + invariant(index.type == IndexType::INDEX_WILDCARD); invariant(index.keyPattern.nFields() == 1); invariant(index.multikeyPaths.size() == 1); @@ -217,10 +217,10 @@ bool validateNumericPathComponents(const MultikeyPaths& multikeyPaths, // To support $** fieldname-or-array-index semantics, the planner must generate the power set of // all paths with and without array indices. Because this is O(2^n), we decline to answer // queries that traverse more than 8 levels of array indices. - if (arrayIndices.size() > kAllPathsMaxArrayIndexTraversalDepth) { + if (arrayIndices.size() > kWildcardMaxArrayIndexTraversalDepth) { LOG(2) << "Declining to answer query on field '" << queryPath.dottedField() << "' with $** index, as it traverses through more than " - << kAllPathsMaxArrayIndexTraversalDepth << " nested array indices."; + << kWildcardMaxArrayIndexTraversalDepth << " nested array indices."; return false; } // If 'includedPaths' is empty, then either the $** projection is an exclusion, or no explicit @@ -245,5 +245,5 @@ bool validateNumericPathComponents(const MultikeyPaths& multikeyPaths, return arrayIndices[0] >= includePath->numParts(); } -} // namespace all_paths_planning +} // namespace wildcard_planning } // namespace mongo diff --git a/src/mongo/db/query/planner_allpaths_helpers.h b/src/mongo/db/query/planner_wildcard_helpers.h index 4bbb333dead..7e56adb1ba0 100644 --- a/src/mongo/db/query/planner_allpaths_helpers.h +++ b/src/mongo/db/query/planner_wildcard_helpers.h @@ -36,7 +36,7 @@ #include "mongo/db/query/query_solution.h" namespace mongo { -namespace all_paths_planning { +namespace wildcard_planning { using BoundsTightness = IndexBoundsBuilder::BoundsTightness; @@ -44,13 +44,13 @@ using BoundsTightness = IndexBoundsBuilder::BoundsTightness; * Specifies the maximum depth of nested array indices through which a query may traverse before a * $** declines to answer it, due to the exponential complexity of the bounds required. */ -static constexpr size_t kAllPathsMaxArrayIndexTraversalDepth = 8u; +static constexpr size_t kWildcardMaxArrayIndexTraversalDepth = 8u; /** * Returns a MultikeyPaths which indicates which components of 'indexedPath' are multikey, by * looking up multikeyness in 'multikeyPathSet'. */ -MultikeyPaths buildMultiKeyPathsForExpandedAllPathsIndexEntry( +MultikeyPaths buildMultiKeyPathsForExpandedWildcardIndexEntry( const FieldRef& indexedPath, const std::set<FieldRef>& multikeyPathSet); /** @@ -71,7 +71,7 @@ std::set<FieldRef> generateFieldNameOrArrayIndexPathSet(const std::set<std::size * predicate. Given an IndexEntry representing an expanded $** index, we apply any necessary changes * to the tightness here. */ -BoundsTightness applyAllPathsIndexScanBoundsTightness(const IndexEntry& index, +BoundsTightness applyWildcardIndexScanBoundsTightness(const IndexEntry& index, BoundsTightness tightnessIn); /** @@ -79,7 +79,7 @@ BoundsTightness applyAllPathsIndexScanBoundsTightness(const IndexEntry& index, * by the $** index, true otherwise. Specifically, the $** index cannot answer the query if either * of the following scenarios occur: * - * - The query path traverses through more than 'kAllPathsMaxArrayIndexTraversalDepth' nested arrays + * - The query path traverses through more than 'kWildcardMaxArrayIndexTraversalDepth' nested arrays * via explicit array indices. * - The query path lies along a $** projection through an array index. * @@ -97,5 +97,5 @@ bool validateNumericPathComponents(const MultikeyPaths& multikeyPaths, const std::set<FieldRef>& includedPaths, const FieldRef& queryPath); -} // namespace all_paths_planning +} // namespace wildcard_planning } // namespace mongo diff --git a/src/mongo/db/query/query_planner.cpp b/src/mongo/db/query/query_planner.cpp index c7492757b20..c32d0343a1c 100644 --- a/src/mongo/db/query/query_planner.cpp +++ b/src/mongo/db/query/query_planner.cpp @@ -38,7 +38,7 @@ #include "mongo/base/string_data.h" #include "mongo/bson/simple_bsonelement_comparator.h" #include "mongo/db/bson/dotted_path_support.h" -#include "mongo/db/index/all_paths_key_generator.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/index_names.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_geo.h" @@ -150,7 +150,7 @@ static BSONObj getKeyFromQuery(const BSONObj& keyPattern, const BSONObj& query) static bool indexCompatibleMaxMin(const BSONObj& obj, const CollatorInterface* queryCollator, const IndexEntry& indexEntry) { - if (indexEntry.type == IndexType::INDEX_ALLPATHS) { + if (indexEntry.type == IndexType::INDEX_WILDCARD) { return false; } @@ -634,7 +634,7 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan( // $** index. if (relevantIndices.size() > 1) { for (auto&& entry : relevantIndices) { - invariant(entry.type == IndexType::INDEX_ALLPATHS); + invariant(entry.type == IndexType::INDEX_WILDCARD); } } } @@ -856,7 +856,7 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan( // desired behavior when an index is hinted that is not relevant to the query. In the case that // $** index is hinted, we do not want this behavior. if (!hintedIndex.isEmpty() && relevantIndices.size() == 1) { - if (0 == out.size() && relevantIndices.front().type != IndexType::INDEX_ALLPATHS) { + if (0 == out.size() && relevantIndices.front().type != IndexType::INDEX_WILDCARD) { // Push hinted index solution to output list if found. It is possible to end up without // a solution in the case where a filtering QueryPlannerParams argument, such as // NO_BLOCKING_SORT, leads to its exclusion. diff --git a/src/mongo/db/query/query_planner_collation_test.cpp b/src/mongo/db/query/query_planner_collation_test.cpp index e30d0bf6b59..bf6020f4df4 100644 --- a/src/mongo/db/query/query_planner_collation_test.cpp +++ b/src/mongo/db/query/query_planner_collation_test.cpp @@ -559,7 +559,7 @@ TEST_F(QueryPlannerTest, NoSortStageWhenMinMaxIndexCollationDoesNotMatchButBound assertSolutionExists("{fetch: {node: {ixscan: {pattern: {a: 1, b: 1, c: 1}}}}}"); } -TEST_F(QueryPlannerTest, StringComparisonWithUnequalCollatorsAndAllPathsIndexResultsInCollscan) { +TEST_F(QueryPlannerTest, StringComparisonWithUnequalCollatorsAndWildcardIndexResultsInCollscan) { CollatorInterfaceMock alwaysEqualCollator(CollatorInterfaceMock::MockType::kAlwaysEqual); addIndex(fromjson("{'$**': 1}"), &alwaysEqualCollator); @@ -570,7 +570,7 @@ TEST_F(QueryPlannerTest, StringComparisonWithUnequalCollatorsAndAllPathsIndexRes assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerTest, StringComparisonWithEqualCollatorsAndAllPathsIndexUsesIndex) { +TEST_F(QueryPlannerTest, StringComparisonWithEqualCollatorsAndWildcardIndexUsesIndex) { params.options &= ~QueryPlannerParams::INCLUDE_COLLSCAN; CollatorInterfaceMock reverseStringCollator(CollatorInterfaceMock::MockType::kReverseString); diff --git a/src/mongo/db/query/query_planner_all_paths_index_test.cpp b/src/mongo/db/query/query_planner_wildcard_index_test.cpp index 9685d312b63..0ca171bd08e 100644 --- a/src/mongo/db/query/query_planner_all_paths_index_test.cpp +++ b/src/mongo/db/query/query_planner_wildcard_index_test.cpp @@ -38,7 +38,7 @@ const std::string kIndexName = "indexName"; * A specialization of the QueryPlannerTest fixture which makes it easy to present the planner with * a view of the available $** indexes. */ -class QueryPlannerAllPathsTest : public QueryPlannerTest { +class QueryPlannerWildcardTest : public QueryPlannerTest { protected: void setUp() final { QueryPlannerTest::setUp(); @@ -48,7 +48,7 @@ protected: params.options &= ~QueryPlannerParams::INCLUDE_COLLSCAN; } - void addAllPathsIndex(BSONObj keyPattern, + void addWildcardIndex(BSONObj keyPattern, const std::set<std::string>& multikeyPathSet = {}, BSONObj wildcardProjection = BSONObj{}, MatchExpression* partialFilterExpr = nullptr) { @@ -63,7 +63,7 @@ protected: BSONObj infoObj = BSON("wildcardProjection" << wildcardProjection); params.indices.push_back(IndexEntry{std::move(keyPattern), - IndexType::INDEX_ALLPATHS, + IndexType::INDEX_WILDCARD, isMultikey, {}, // multikeyPaths std::move(multikeyFieldRefs), @@ -80,7 +80,7 @@ protected: // Null comparison and existence tests. // -TEST_F(QueryPlannerAllPathsTest, ExistsTrueQueriesUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, ExistsTrueQueriesUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$exists: true}}")); @@ -89,7 +89,7 @@ TEST_F(QueryPlannerAllPathsTest, ExistsTrueQueriesUseAllPathsIndexes) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExistsFalseQueriesDontUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, ExistsFalseQueriesDontUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$exists: false}}")); @@ -98,7 +98,7 @@ TEST_F(QueryPlannerAllPathsTest, ExistsFalseQueriesDontUseAllPathsIndexes) { assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualsNullQueriesDontUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, EqualsNullQueriesDontUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$eq: null}}")); @@ -107,7 +107,7 @@ TEST_F(QueryPlannerAllPathsTest, EqualsNullQueriesDontUseAllPathsIndexes) { assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, NotEqualsNullQueriesDontUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, NotEqualsNullQueriesDontUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$ne: null}}")); @@ -116,7 +116,7 @@ TEST_F(QueryPlannerAllPathsTest, NotEqualsNullQueriesDontUseAllPathsIndexes) { assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, NotEqualsNullAndExistsQueriesUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, NotEqualsNullAndExistsQueriesUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$ne: null, $exists: true}}")); @@ -125,7 +125,7 @@ TEST_F(QueryPlannerAllPathsTest, NotEqualsNullAndExistsQueriesUseAllPathsIndexes assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualsNullAndExistsQueriesUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, EqualsNullAndExistsQueriesUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$eq: null, $exists: true}}")); @@ -134,7 +134,7 @@ TEST_F(QueryPlannerAllPathsTest, EqualsNullAndExistsQueriesUseAllPathsIndexes) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EmptyBoundsWithAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, EmptyBoundsWithWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$lte: 5, $gte: 10}}")); @@ -147,8 +147,8 @@ TEST_F(QueryPlannerAllPathsTest, EmptyBoundsWithAllPathsIndexes) { // Multikey planning tests. // -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverMultikeyFieldNoElemMatch) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverMultikeyFieldNoElemMatch) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{a: {$gt: 0, $lt: 9}}")); assertNumSolutions(2U); @@ -162,8 +162,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverMultikeyFieldNoElemMatch) "bounds: {'$_path': [['a','a',true,true]], a: [[0,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverMultikeyFieldWithElemMatch) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverMultikeyFieldWithElemMatch) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{a: {$elemMatch: {$gt: 0, $lt: 9}}}")); assertNumSolutions(1U); @@ -173,8 +173,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverMultikeyFieldWithElemMatc "bounds: {'$_path': [['a','a',true,true]], a: [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNonMultikeyFieldWithMultikeyIndex) { - addAllPathsIndex(BSON("$**" << 1), {"b"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNonMultikeyFieldWithMultikeyIndex) { + addWildcardIndex(BSON("$**" << 1), {"b"}); runQuery(fromjson("{a: {$gt: 0, $lt: 9}}")); assertNumSolutions(1U); @@ -183,8 +183,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNonMultikeyFieldWithMulti "bounds: {'$_path': [['a','a',true,true]], a: [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithFirstComponentMultikey) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNestedFieldWithFirstComponentMultikey) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{'a.b': {$gt: 0, $lt: 9}}")); assertNumSolutions(2U); @@ -198,8 +198,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithFirstCompo "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithElemMatchObject) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNestedFieldWithElemMatchObject) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{a: {$elemMatch: {b: {$gt: 0, $lt: 9}}}}")); assertNumSolutions(1U); @@ -209,9 +209,9 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithElemMatchO "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNestedFieldWithElemMatchObjectBothComponentsMultikey) { - addAllPathsIndex(BSON("$**" << 1), {"a", "a.b"}); + addWildcardIndex(BSON("$**" << 1), {"a", "a.b"}); runQuery(fromjson("{a: {$elemMatch: {b: {$gt: 0, $lt: 9}}}}")); assertNumSolutions(2U); @@ -225,8 +225,8 @@ TEST_F(QueryPlannerAllPathsTest, "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithTwoElemMatches) { - addAllPathsIndex(BSON("$**" << 1), {"a", "a.b"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNestedFieldWithTwoElemMatches) { + addWildcardIndex(BSON("$**" << 1), {"a", "a.b"}); runQuery(fromjson("{a: {$elemMatch: {b: {$elemMatch: {$gt: 0, $lt: 9}}}}}")); assertNumSolutions(1U); @@ -236,8 +236,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithTwoElemMat "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ElemMatchOnInnermostMultikeyPathPermitsTightBounds) { - addAllPathsIndex(BSON("$**" << 1), {"a", "a.b", "a.b.c"}); +TEST_F(QueryPlannerWildcardTest, ElemMatchOnInnermostMultikeyPathPermitsTightBounds) { + addWildcardIndex(BSON("$**" << 1), {"a", "a.b", "a.b.c"}); runQuery(fromjson("{'a.b.c': {$elemMatch: {'d.e.f': {$gt: 0, $lt: 9}}}}")); assertNumSolutions(1U); @@ -248,8 +248,8 @@ TEST_F(QueryPlannerAllPathsTest, ElemMatchOnInnermostMultikeyPathPermitsTightBou "'a.b.c.d.e.f': [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPredsEligibleForIndexUseGenerateCandidatePlans) { - addAllPathsIndex(BSON("a.$**" << 1), {"a.b", "a.c"}); +TEST_F(QueryPlannerWildcardTest, AllPredsEligibleForIndexUseGenerateCandidatePlans) { + addWildcardIndex(BSON("a.$**" << 1), {"a.b", "a.c"}); runQuery( fromjson("{'a.b': {$gt: 0, $lt: 9}, 'a.c': {$gt: 11, $lt: 20}, d: {$gt: 31, $lt: 40}}")); @@ -272,8 +272,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPredsEligibleForIndexUseGenerateCandidatePla "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, RangeIndexScan) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, RangeIndexScan) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gt: 0, $lt: 9}}")); assertNumSolutions(1U); @@ -283,8 +283,8 @@ TEST_F(QueryPlannerAllPathsTest, RangeIndexScan) { "bounds: {'$_path': [['a','a',true,true]], a: [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, RangeIndexScanEmptyRange) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, RangeIndexScanEmptyRange) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gt: 9, $lt: 0}}")); assertNumSolutions(1U); @@ -294,8 +294,8 @@ TEST_F(QueryPlannerAllPathsTest, RangeIndexScanEmptyRange) { "bounds: {'$_path': [['a','a',true,true]], 'a': []}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, RangeIndexScanMinKeyMaxKey) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, RangeIndexScanMinKeyMaxKey) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gt: {$minKey: 1}, $lt: {$maxKey: 1}}}")); assertNumSolutions(1U); @@ -306,8 +306,8 @@ TEST_F(QueryPlannerAllPathsTest, RangeIndexScanMinKeyMaxKey) { "'MaxKey', true, true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, RangeIndexScanNestedField) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, RangeIndexScanNestedField) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{'a.b': {$gt: 0, $lt: 9}}")); assertNumSolutions(1U); @@ -317,8 +317,8 @@ TEST_F(QueryPlannerAllPathsTest, RangeIndexScanNestedField) { "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualityIndexScan) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualityIndexScan) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$eq: 5}}")); assertNumSolutions(1U); @@ -328,8 +328,8 @@ TEST_F(QueryPlannerAllPathsTest, EqualityIndexScan) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualityIndexScanOverNestedField) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualityIndexScanOverNestedField) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{'a.b': {$eq: 5}}")); assertNumSolutions(1U); @@ -339,8 +339,8 @@ TEST_F(QueryPlannerAllPathsTest, EqualityIndexScanOverNestedField) { "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[5,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExprEqCanUseIndex) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, ExprEqCanUseIndex) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$_internalExprEq: 1}}")); assertNumSolutions(1U); @@ -349,8 +349,8 @@ TEST_F(QueryPlannerAllPathsTest, ExprEqCanUseIndex) { "bounds: {'$_path': [['a','a',true,true]], a: [[1,1,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExprEqCanUseSparseIndexForEqualityToNull) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, ExprEqCanUseSparseIndexForEqualityToNull) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$_internalExprEq: null}}")); assertNumSolutions(1U); @@ -360,7 +360,7 @@ TEST_F(QueryPlannerAllPathsTest, ExprEqCanUseSparseIndexForEqualityToNull) { "[null,null,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, PrefixRegex) { +TEST_F(QueryPlannerWildcardTest, PrefixRegex) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{a: /^foo/}")); @@ -371,7 +371,7 @@ TEST_F(QueryPlannerAllPathsTest, PrefixRegex) { "a: [['foo','fop',true,false], [/^foo/,/^foo/,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, NonPrefixRegex) { +TEST_F(QueryPlannerWildcardTest, NonPrefixRegex) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{a: /foo/}")); @@ -382,8 +382,8 @@ TEST_F(QueryPlannerAllPathsTest, NonPrefixRegex) { "a: [['',{},true,false], [/foo/,/foo/,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, GreaterThan) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, GreaterThan) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gt: 5}}")); assertNumSolutions(1U); @@ -393,8 +393,8 @@ TEST_F(QueryPlannerAllPathsTest, GreaterThan) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, GreaterThanEqualTo) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, GreaterThanEqualTo) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gte: 5}}")); assertNumSolutions(1U); @@ -404,8 +404,8 @@ TEST_F(QueryPlannerAllPathsTest, GreaterThanEqualTo) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,Infinity,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, LessThan) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, LessThan) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$lt: 5}}")); assertNumSolutions(1U); @@ -415,8 +415,8 @@ TEST_F(QueryPlannerAllPathsTest, LessThan) { "bounds: {'$_path': [['a','a',true,true]], a: [[-Infinity,5,true,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, LessThanEqualTo) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, LessThanEqualTo) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$lte: 5}}")); assertNumSolutions(1U); @@ -426,8 +426,8 @@ TEST_F(QueryPlannerAllPathsTest, LessThanEqualTo) { "bounds: {'$_path': [['a','a',true,true]], a: [[-Infinity,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, Mod) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, Mod) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$mod: [2, 0]}}")); assertNumSolutions(1U); @@ -437,8 +437,8 @@ TEST_F(QueryPlannerAllPathsTest, Mod) { "bounds: {'$_path': [['a','a',true,true]], a: [[NaN,Infinity, true, true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExistsTrue) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, ExistsTrue) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$exists: true}}")); assertNumSolutions(1U); @@ -449,16 +449,16 @@ TEST_F(QueryPlannerAllPathsTest, ExistsTrue) { "[['MinKey','MaxKey',true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExistsFalseDoesNotUseIndex) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, ExistsFalseDoesNotUseIndex) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$exists: false}}")); assertNumSolutions(1U); assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, AndEqualityWithTwoPredicatesIndexesOnePath) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, AndEqualityWithTwoPredicatesIndexesOnePath) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: 5, b: 10}")); assertNumSolutions(2U); @@ -468,8 +468,8 @@ TEST_F(QueryPlannerAllPathsTest, AndEqualityWithTwoPredicatesIndexesOnePath) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, OrEqualityWithTwoPredicatesUsesTwoPaths) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, OrEqualityWithTwoPredicatesUsesTwoPaths) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{$or: [{a: 5}, {b: 10}]}")); assertNumSolutions(1U); @@ -482,8 +482,8 @@ TEST_F(QueryPlannerAllPathsTest, OrEqualityWithTwoPredicatesUsesTwoPaths) { ; } -TEST_F(QueryPlannerAllPathsTest, OrWithOneRegularAndOneAllPathsIndexPathUsesTwoIndexes) { - addAllPathsIndex(BSON("a.$**" << 1)); +TEST_F(QueryPlannerWildcardTest, OrWithOneRegularAndOneWildcardIndexPathUsesTwoIndexes) { + addWildcardIndex(BSON("a.$**" << 1)); addIndex(BSON("b" << 1)); runQuery(fromjson("{$or: [{a: 5}, {b: 10}]}")); @@ -497,8 +497,8 @@ TEST_F(QueryPlannerAllPathsTest, OrWithOneRegularAndOneAllPathsIndexPathUsesTwoI ; } -TEST_F(QueryPlannerAllPathsTest, BasicSkip) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, BasicSkip) { + addWildcardIndex(BSON("$**" << 1)); runQuerySkipNToReturn(BSON("a" << 5), 8, 0); assertNumSolutions(1U); @@ -508,8 +508,8 @@ TEST_F(QueryPlannerAllPathsTest, BasicSkip) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, CoveredSkip) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, CoveredSkip) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProjSkipNToReturn(fromjson("{a: 5}"), BSONObj(), fromjson("{_id: 0, a: 1}"), 8, 0); assertNumSolutions(1U); @@ -519,8 +519,8 @@ TEST_F(QueryPlannerAllPathsTest, CoveredSkip) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, BasicLimit) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, BasicLimit) { + addWildcardIndex(BSON("$**" << 1)); runQuerySkipNToReturn(BSON("a" << 5), 0, -5); assertNumSolutions(1U); @@ -530,8 +530,8 @@ TEST_F(QueryPlannerAllPathsTest, BasicLimit) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, BasicCovering) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, BasicCovering) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{ x : {$gt: 1}}"), BSONObj(), fromjson("{_id: 0, x: 1}")); assertNumSolutions(1U); @@ -540,8 +540,8 @@ TEST_F(QueryPlannerAllPathsTest, BasicCovering) { "bounds: {'$_path': [['x','x',true,true]], x: [[1,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, DottedFieldCovering) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, DottedFieldCovering) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{'a.b': 5}"), BSONObj(), fromjson("{_id: 0, 'a.b': 1}")); assertNumSolutions(1U); @@ -551,9 +551,9 @@ TEST_F(QueryPlannerAllPathsTest, DottedFieldCovering) { "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[5,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, CoveredIxscanForCountOnIndexedPath) { +TEST_F(QueryPlannerWildcardTest, CoveredIxscanForCountOnIndexedPath) { params.options = QueryPlannerParams::IS_COUNT; - addAllPathsIndex(BSON("$**" << 1)); + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: 5}")); assertNumSolutions(1U); @@ -562,8 +562,8 @@ TEST_F(QueryPlannerAllPathsTest, CoveredIxscanForCountOnIndexedPath) { "bounds: {'$_path': [['a','a',true,true]], 'a': [[5,5,true,true]]}}}"); } -TEST_F(QueryPlannerAllPathsTest, InBasic) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InBasic) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [1, 2]}}")); assertNumSolutions(1U); @@ -573,8 +573,8 @@ TEST_F(QueryPlannerAllPathsTest, InBasic) { "bounds: {'$_path': [['a','a',true,true]], a: [[1,1,true,true],[2,2,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualsEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualsEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: []}")); assertNumSolutions(1U); @@ -584,29 +584,29 @@ TEST_F(QueryPlannerAllPathsTest, EqualsEmptyArray) { "[[undefined,undefined,true,true],[[],[],true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualsNonEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualsNonEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: [1]}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, EqualsNestedEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualsNestedEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: [[]]}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, EqualsArrayWithValue) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualsArrayWithValue) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: [[1]]}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, InEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [[]]}}")); assertNumSolutions(1U); @@ -616,22 +616,22 @@ TEST_F(QueryPlannerAllPathsTest, InEmptyArray) { "[[undefined,undefined,true,true],[[],[],true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, InNonEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InNonEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [[1]]}}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, InNestedEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InNestedEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [[[]]]}}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, InArrayWithValue) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InArrayWithValue) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [[[1]]]}}")); assertHasOnlyCollscan(); @@ -639,8 +639,8 @@ TEST_F(QueryPlannerAllPathsTest, InArrayWithValue) { // Logically equivalent to the preceding $in query. // Indexed solution should be the same. -TEST_F(QueryPlannerAllPathsTest, InBasicOrEquivalent) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InBasicOrEquivalent) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{$or: [{a: 1}, {a: 2}]}")); assertNumSolutions(1U); @@ -650,10 +650,10 @@ TEST_F(QueryPlannerAllPathsTest, InBasicOrEquivalent) { "bounds: {'$_path': [['a','a',true,true]], a: [[1,1,true,true],[2,2,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, PartialIndexCanAnswerPredicateOnFilteredField) { +TEST_F(QueryPlannerWildcardTest, PartialIndexCanAnswerPredicateOnFilteredField) { auto filterObj = fromjson("{a: {$gt: 0}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); - addAllPathsIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); + addWildcardIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); runQuery(fromjson("{a: {$gte: 5}}")); assertNumSolutions(1U); @@ -677,12 +677,12 @@ TEST_F(QueryPlannerAllPathsTest, PartialIndexCanAnswerPredicateOnFilteredField) "bounds: {'$_path': [['a','a',true,true]], a: [[1,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, PartialIndexDoesNotAnswerPredicatesExcludedByFilter) { +TEST_F(QueryPlannerWildcardTest, PartialIndexDoesNotAnswerPredicatesExcludedByFilter) { // Must keep 'filterObj' around since match expressions will store pointers into the BSON they // were parsed from. auto filterObj = fromjson("{a: {$gt: 0}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); - addAllPathsIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); + addWildcardIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); runQuery(fromjson("{a: {$gte: -1}}")); assertHasOnlyCollscan(); @@ -694,10 +694,10 @@ TEST_F(QueryPlannerAllPathsTest, PartialIndexDoesNotAnswerPredicatesExcludedByFi assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, PartialIndexCanAnswerPredicateOnUnrelatedField) { +TEST_F(QueryPlannerWildcardTest, PartialIndexCanAnswerPredicateOnUnrelatedField) { auto filterObj = fromjson("{a: {$gt: 0}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); - addAllPathsIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); + addWildcardIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); // Test when the field query is not included by the partial filter expression. runQuery(fromjson("{b: {$gte: -1}, a: {$gte: 5}}")); @@ -712,10 +712,10 @@ TEST_F(QueryPlannerAllPathsTest, PartialIndexCanAnswerPredicateOnUnrelatedField) "bounds: {'$_path': [['a','a',true,true]], a: [[5,Infinity,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, PartialIndexWithExistsTrueFilterCanAnswerExistenceQuery) { +TEST_F(QueryPlannerWildcardTest, PartialIndexWithExistsTrueFilterCanAnswerExistenceQuery) { auto filterObj = fromjson("{x: {$exists: true}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); - addAllPathsIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); + addWildcardIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); runQuery(fromjson("{x: {$exists: true}}")); assertNumSolutions(1U); @@ -730,7 +730,7 @@ TEST_F(QueryPlannerAllPathsTest, PartialIndexWithExistsTrueFilterCanAnswerExiste // Index intersection tests. // -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotParticipateInIndexIntersection) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexDoesNotParticipateInIndexIntersection) { // Enable both AND_SORTED and AND_HASH index intersection for this test. params.options |= QueryPlannerParams::INDEX_INTERSECTION; internalQueryPlannerEnableHashIntersection.store(true); @@ -764,7 +764,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotParticipateInIndexIntersect "{filter: null, pattern: {a:1}}},{ixscan: {filter: null, pattern: {b:1}}}]}}}}"); // Now add a $** index and re-run the tests. - addAllPathsIndex(BSON("$**" << 1)); + addWildcardIndex(BSON("$**" << 1)); // First re-run the AND_SORTED test. runQuery(fromjson("{a:10, b:10}")); @@ -804,17 +804,17 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotParticipateInIndexIntersect } // -// AllPaths and $text index tests. +// Wildcard and $text index tests. // -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotSupplyCandidatePlanForTextSearch) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexDoesNotSupplyCandidatePlanForTextSearch) { + addWildcardIndex(BSON("$**" << 1)); addIndex(BSON("a" << 1 << "_fts" << "text" << "_ftsx" << 1)); - // Confirm that the allPaths index generates candidate plans for queries which do not include a + // Confirm that the wildcard index generates candidate plans for queries which do not include a // $text predicate. runQuery(fromjson("{a: 10, b: 10}")); assertNumSolutions(2U); @@ -823,7 +823,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotSupplyCandidatePlanForTextS assertSolutionExists( "{fetch: {filter: {a: 10}, node: {ixscan: {filter: null, pattern: {'$_path': 1, b: 1}}}}}"); - // Confirm that the allPaths index does not produce any candidate plans when a query includes a + // Confirm that the wildcard index does not produce any candidate plans when a query includes a // $text predicate, even for non-$text predicates which may be present in the query. runQuery(fromjson("{a: 10, b: 10, $text: {$search: 'banana'}}")); assertNumSolutions(1U); @@ -831,10 +831,10 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotSupplyCandidatePlanForTextS "{fetch: {filter: {b: 10}, node: {text: {prefix: {a: 10}, search: 'banana'}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsDoesNotSupportNegationPredicate) { - // AllPaths indexes can't support negation queries because they are sparse, and {a: {$ne: 5}} +TEST_F(QueryPlannerWildcardTest, WildcardDoesNotSupportNegationPredicate) { + // Wildcard indexes can't support negation queries because they are sparse, and {a: {$ne: 5}} // will match documents which don't have an "a" field. - addAllPathsIndex(BSON("$**" << 1)); + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$ne: 5}}")); assertHasOnlyCollscan(); @@ -842,11 +842,11 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsDoesNotSupportNegationPredicate) { assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, - AllPathsDoesNotSupportNegationPredicateInsideElemMatchMultiKeyPath) { - // Logically, there's no reason a (sparse) allPaths index could not support a negation inside a +TEST_F(QueryPlannerWildcardTest, + WildcardDoesNotSupportNegationPredicateInsideElemMatchMultiKeyPath) { + // Logically, there's no reason a (sparse) wildcard index could not support a negation inside a // "$elemMatch value", but it is not something we've implemented. - addAllPathsIndex(BSON("$**" << 1), {"a"}); + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{a: {$elemMatch: {$ne: 5}}}")); assertHasOnlyCollscan(); @@ -854,11 +854,11 @@ TEST_F(QueryPlannerAllPathsTest, assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, AllPathsDoesNotSupportNegationPredicateInsideElemMatch) { +TEST_F(QueryPlannerWildcardTest, WildcardDoesNotSupportNegationPredicateInsideElemMatch) { // Test the case where we use $elemMatch on a path which isn't even multikey. In this case, // we'd know up front that the results would be empty, but this is not an optimization we // support. - addAllPathsIndex(BSON("$**" << 1)); + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$elemMatch: {$ne: 5}}}")); assertHasOnlyCollscan(); @@ -870,7 +870,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsDoesNotSupportNegationPredicateInsideEl // Hinting with all paths index tests. // -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHint) { +TEST_F(QueryPlannerTest, ChooseWildcardIndexHint) { addIndex(BSON("$**" << 1)); addIndex(BSON("x" << 1)); @@ -880,21 +880,21 @@ TEST_F(QueryPlannerTest, ChooseAllPathsIndexHint) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintByName) { - StringData allPaths = "allPaths"; +TEST_F(QueryPlannerTest, ChooseWildcardIndexHintByName) { + StringData wildcard = "wildcard"; CollatorInterface* nullCollator = nullptr; - addIndex(BSON("$**" << 1), nullCollator, allPaths); + addIndex(BSON("$**" << 1), nullCollator, wildcard); addIndex(BSON("x" << 1)); runQueryHint(fromjson("{x: {$eq: 1}}"), BSON("$hint" - << "allPaths")); + << "wildcard")); assertNumSolutions(1U); assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithPath) { +TEST_F(QueryPlannerTest, ChooseWildcardIndexHintWithPath) { addIndex(BSON("x.$**" << 1)); addIndex(BSON("x" << 1)); @@ -904,7 +904,7 @@ TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithPath) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithOr) { +TEST_F(QueryPlannerTest, ChooseWildcardIndexHintWithOr) { addIndex(BSON("$**" << 1)); addIndex(BSON("x" << 1 << "y" << 1)); @@ -916,7 +916,7 @@ TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithOr) { " {ixscan: {pattern: {$_path: 1, y: 1}}}]}}}}"); } -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithCompoundIndex) { +TEST_F(QueryPlannerTest, ChooseWildcardIndexHintWithCompoundIndex) { addIndex(BSON("$**" << 1)); addIndex(BSON("x" << 1 << "y" << 1)); @@ -927,7 +927,7 @@ TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithCompoundIndex) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, y: 1}}}}}"); } -TEST_F(QueryPlannerTest, QueryNotInAllPathsIndexHint) { +TEST_F(QueryPlannerTest, QueryNotInWildcardIndexHint) { addIndex(BSON("a.$**" << 1)); addIndex(BSON("x" << 1)); @@ -935,13 +935,13 @@ TEST_F(QueryPlannerTest, QueryNotInAllPathsIndexHint) { assertNumSolutions(0U); } -TEST_F(QueryPlannerTest, AllPathsIndexDoesNotExist) { +TEST_F(QueryPlannerTest, WildcardIndexDoesNotExist) { addIndex(BSON("x" << 1)); runInvalidQueryHint(fromjson("{x: {$eq: 1}}"), BSON("$**" << 1)); } -TEST_F(QueryPlannerTest, AllPathsIndexHintWithPartialFilter) { +TEST_F(QueryPlannerTest, WildcardIndexHintWithPartialFilter) { auto filterObj = fromjson("{a: {$gt: 100}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); addIndex(BSON("$**" << 1), filterExpr.get()); @@ -950,7 +950,7 @@ TEST_F(QueryPlannerTest, AllPathsIndexHintWithPartialFilter) { assertNumSolutions(0U); } -TEST_F(QueryPlannerTest, MultipleAllPathsIndexesHintWithPartialFilter) { +TEST_F(QueryPlannerTest, MultipleWildcardIndexesHintWithPartialFilter) { auto filterObj = fromjson("{a: {$gt: 100}, b: {$gt: 100}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); addIndex(BSON("$**" << 1), filterExpr.get()); @@ -959,7 +959,7 @@ TEST_F(QueryPlannerTest, MultipleAllPathsIndexesHintWithPartialFilter) { assertNumSolutions(0U); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportObjectEquality) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportObjectEquality) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {abc: 1}}")); @@ -974,7 +974,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportObjectEquality) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportObjectInequality) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportObjectInequality) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$lt: {abc: 1}}}")); @@ -1007,7 +1007,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportObjectInequality) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportInWithUnsupportedValues) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportInWithUnsupportedValues) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$in: [1, 2, 3, {abc: 1}]}}")); @@ -1018,7 +1018,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportInWithUnsupportedVal assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesSupportElemMatchWithNull) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesSupportElemMatchWithNull) { addIndex(BSON("$**" << 1)); // Simple case. @@ -1026,14 +1026,14 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesSupportElemMatchWithNull) { assertNumSolutions(1U); assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); - // null inside an $in inside an $elemMatch is supported by the allPaths index, since it means + // null inside an $in inside an $elemMatch is supported by the wildcard index, since it means // we're searching for an explicit null value. runQuery(fromjson("{x: {$elemMatch: {$in: [1, 2, 3, null]}}}")); assertNumSolutions(1U); assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportElemMatchWithUnsupportedValues) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportElemMatchWithUnsupportedValues) { runQuery(fromjson("{x: {$elemMatch: {$eq: ['a', 'b', 'c']}}}")); assertHasOnlyCollscan(); @@ -1045,13 +1045,13 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportElemMatchWithUnsuppo assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportElemMatchObject) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportElemMatchObject) { runQuery(fromjson("{x: {$elemMatch: {a: 1}}}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexCanProvideNonBlockingSort) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexCanProvideNonBlockingSort) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{a: 1}"), BSON("a" << 1), BSONObj()); assertNumSolutions(1U); @@ -1060,9 +1060,9 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexCanProvideNonBlockingSort) { "bounds: {'$_path': [['a','a',true,true]], a: [[1,1,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, - AllPathsIndexCanProvideNonBlockingSortWhenFilterIncludesAdditionalFields) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, + WildcardIndexCanProvideNonBlockingSortWhenFilterIncludesAdditionalFields) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{a: {$gte: 3}, b: 1}"), BSON("a" << 1), BSONObj()); assertNumSolutions(2U); @@ -1079,8 +1079,8 @@ TEST_F(QueryPlannerAllPathsTest, "bounds: {'$_path': [['b','b',true,true]], b: [[1, 1, true, true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithElemMatch) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWithElemMatch) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuerySortProj(fromjson("{a: {$elemMatch: {$eq: 1}}}"), BSON("a" << 1), BSONObj()); assertNumSolutions(1U); @@ -1091,8 +1091,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithElemMatch) "bounds: {'$_path': [['a','a',true,true]], a: [[1, 1, true, true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithCompoundSort) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWithCompoundSort) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{a: {$lte: 3}}"), BSON("a" << 1 << "b" << 1), BSONObj()); assertNumSolutions(1U); @@ -1103,8 +1103,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithCompoundSor "bounds: {'$_path': [['a','a',true,true]], a: [[-Infinity, 3, true, true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithExistsQueries) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWithExistsQueries) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{a: {$exists: true}}"), BSON("a" << 1), BSONObj()); assertNumSolutions(1U); @@ -1116,7 +1116,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithExistsQueri "true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFilterNotPresent) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWhenFilterNotPresent) { // Since there's no filter on the field that we're sorting by, we cannot use an index scan to // answer the query as $** indexes are sparse. runQuerySortProj(BSONObj(), fromjson("{a: 1}"), BSONObj()); @@ -1125,8 +1125,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFilterNotPr "{cscan: {dir: 1}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFilterDoesNotIncludeSortKey) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWhenFilterDoesNotIncludeSortKey) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{b: 1, c: 1}"), fromjson("{a: 1}"), BSONObj()); assertNumSolutions(2U); @@ -1142,8 +1142,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFilterDoesN "bounds: {'$_path': [['c','c',true,true]], c: [[1, 1, true, true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFieldIsNotIncluded) { - addAllPathsIndex(BSON("$**" << 1), {}, BSON("b" << 0)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWhenFieldIsNotIncluded) { + addWildcardIndex(BSON("$**" << 1), {}, BSON("b" << 0)); runQuerySortProj(fromjson("{b: 1}"), fromjson("{b: 1}"), BSONObj()); assertNumSolutions(1U); @@ -1158,8 +1158,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFieldIsNotI // Field name or array index tests. // -TEST_F(QueryPlannerAllPathsTest, CannotAnswerQueryThroughArrayIndexProjection) { - addAllPathsIndex(BSON("$**" << 1), {"a"}, fromjson("{'a.0': 1, 'a.b': 1}")); +TEST_F(QueryPlannerWildcardTest, CannotAnswerQueryThroughArrayIndexProjection) { + addWildcardIndex(BSON("$**" << 1), {"a"}, fromjson("{'a.0': 1, 'a.b': 1}")); // Queries whose path lies along a projected array index cannot be answered. runQuery(fromjson("{'a.0': 10}")); @@ -1171,8 +1171,8 @@ TEST_F(QueryPlannerAllPathsTest, CannotAnswerQueryThroughArrayIndexProjection) { assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, CanAnswerQueryOnNonProjectedArrayIndex) { - addAllPathsIndex(BSON("$**" << 1), {"a", "c"}, fromjson("{'a.0': 1, b: 1, c: 1}")); +TEST_F(QueryPlannerWildcardTest, CanAnswerQueryOnNonProjectedArrayIndex) { + addWildcardIndex(BSON("$**" << 1), {"a", "c"}, fromjson("{'a.0': 1, b: 1, c: 1}")); // Queries on fields that are not projected array indices can be answered, even when such a // projection is present in the 'starPathsTempName' spec. @@ -1191,8 +1191,8 @@ TEST_F(QueryPlannerAllPathsTest, CanAnswerQueryOnNonProjectedArrayIndex) { "[[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldGenerateAllPotentialPathBoundsForArrayIndexQueries) { - addAllPathsIndex(BSON("a.$**" << 1), {"a", "a.b"}); +TEST_F(QueryPlannerWildcardTest, ShouldGenerateAllPotentialPathBoundsForArrayIndexQueries) { + addWildcardIndex(BSON("a.$**" << 1), {"a", "a.b"}); // A numeric path component immediately following a multikey path may represent an array index, // a fieldname, or both. The $** index does not record array indices explicitly, so for all such @@ -1221,8 +1221,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldGenerateAllPotentialPathBoundsForArrayInd "['a.b.c','a.b.c',true,true]], 'a.0.b.1.c': [[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldAddAllPredicatesToFetchFilterForArrayIndexQueries) { - addAllPathsIndex(BSON("$**" << 1), {"a", "a.b"}); +TEST_F(QueryPlannerWildcardTest, ShouldAddAllPredicatesToFetchFilterForArrayIndexQueries) { + addWildcardIndex(BSON("$**" << 1), {"a", "a.b"}); // Ordinarily, a query such as {'a': {$gt: 0, $lt: 5}} on a multikey field 'a' produces an EXACT // IXSCAN on one of the predicates and a FETCH filter on the other. For fieldname-or-array-index @@ -1302,8 +1302,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldAddAllPredicatesToFetchFilterForArrayInde "[[10,20,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldOnlyBuildSpecialBoundsForMultikeyPaths) { - addAllPathsIndex(BSON("a.$**" << 1), {"a.b", "a.b.c.d"}); +TEST_F(QueryPlannerWildcardTest, ShouldOnlyBuildSpecialBoundsForMultikeyPaths) { + addWildcardIndex(BSON("a.$**" << 1), {"a.b", "a.b.c.d"}); // 'a' is not multikey, so 'a.0' refers specifically to a fieldname rather than an array index, // and special bounds will not be generated. @@ -1350,8 +1350,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldOnlyBuildSpecialBoundsForMultikeyPaths) { "['a.b.c.d.e','a.b.c.d.e',true,true]], 'a.b.1.c.d.3.e':[[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldGenerateSpecialBoundsForNumericMultikeyPaths) { - addAllPathsIndex(BSON("a.$**" << 1), {"a.b", "a.b.0"}); +TEST_F(QueryPlannerWildcardTest, ShouldGenerateSpecialBoundsForNumericMultikeyPaths) { + addWildcardIndex(BSON("a.$**" << 1), {"a.b", "a.b.0"}); // 'a.b.0' is itself a multikey path, but since 'a.b' is multikey 'b.0' may refer to an array // element of 'b'. We generate special bounds for 'b.0'. @@ -1380,8 +1380,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldGenerateSpecialBoundsForNumericMultikeyPa "['a.b.1.c','a.b.1.c',true,true]], 'a.b.1.1.c': [[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldNotGenerateSpecialBoundsForFieldNamesWithLeadingZeroes) { - addAllPathsIndex(BSON("a.$**" << 1), {"a.b"}); +TEST_F(QueryPlannerWildcardTest, ShouldNotGenerateSpecialBoundsForFieldNamesWithLeadingZeroes) { + addWildcardIndex(BSON("a.$**" << 1), {"a.b"}); // 'a.b' is multikey, but '01' is not eligible for consideration as a numeric array index; it is // always strictly a field name. We therefore do not generate special bounds. @@ -1392,8 +1392,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldNotGenerateSpecialBoundsForFieldNamesWith "bounds: {'$_path': [['a.b.01','a.b.01',true,true]], 'a.b.01': [[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, InitialNumericPathComponentIsAlwaysFieldName) { - addAllPathsIndex(BSON("$**" << 1), {"0"}, fromjson("{'0': 1}")); +TEST_F(QueryPlannerWildcardTest, InitialNumericPathComponentIsAlwaysFieldName) { + addWildcardIndex(BSON("$**" << 1), {"0"}, fromjson("{'0': 1}")); // '0' is multikey, but the first component in a path can never be an array index since it must // always be a field name. We therefore do not generate special bounds for '0.b'. @@ -1412,8 +1412,8 @@ TEST_F(QueryPlannerAllPathsTest, InitialNumericPathComponentIsAlwaysFieldName) { "'0.1.b': [[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldGenerateSpecialBoundsForNullAndExistenceQueries) { - addAllPathsIndex(BSON("a.$**" << 1), {"a", "a.b", "a.b.2", "a.b.2.3", "a.b.2.3.4"}); +TEST_F(QueryPlannerWildcardTest, ShouldGenerateSpecialBoundsForNullAndExistenceQueries) { + addWildcardIndex(BSON("a.$**" << 1), {"a", "a.b", "a.b.2", "a.b.2.3", "a.b.2.3.4"}); runQuery(fromjson("{'a.0.b': {$exists: true}}")); assertNumSolutions(1U); @@ -1453,8 +1453,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldGenerateSpecialBoundsForNullAndExistenceQ "'a.0.b.2.3.4': [[{$minKey: 1},{$maxKey: 1},true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldDeclineToAnswerQueriesThatTraverseTooManyArrays) { - addAllPathsIndex(BSON("$**" << 1), +TEST_F(QueryPlannerWildcardTest, ShouldDeclineToAnswerQueriesThatTraverseTooManyArrays) { + addWildcardIndex(BSON("$**" << 1), {"a", "a.b", "a.b.c", diff --git a/src/mongo/db/query/query_solution.cpp b/src/mongo/db/query/query_solution.cpp index 142e9a061fd..567cb958e0a 100644 --- a/src/mongo/db/query/query_solution.cpp +++ b/src/mongo/db/query/query_solution.cpp @@ -561,7 +561,7 @@ bool IndexScanNode::hasField(const string& field) const { for (auto&& elt : index.keyPattern) { // For $** indexes, the keyPattern is prefixed by a virtual field, '$_path'. We therefore // skip the first keyPattern field when deciding whether we can provide the requested field. - if (index.type == IndexType::INDEX_ALLPATHS && !keyPatternFieldIndex) { + if (index.type == IndexType::INDEX_WILDCARD && !keyPatternFieldIndex) { invariant(elt.fieldNameStringData() == "$_path"_sd); ++keyPatternFieldIndex; continue; |