diff options
author | Ian Boros <ian.boros@10gen.com> | 2018-09-06 16:39:53 -0400 |
---|---|---|
committer | Ian Boros <ian.boros@10gen.com> | 2018-09-20 16:26:20 -0400 |
commit | 5ed54bec92fc15009877e2d579fe59785bffdde7 (patch) | |
tree | f190e99159e98dde1d5f0d13f457c4ec2c1b12f1 /src/mongo/db/query/plan_cache_indexability.cpp | |
parent | 64672e68a25e1c4c53a9e1e974036b02fdda2cc5 (diff) | |
download | mongo-5ed54bec92fc15009877e2d579fe59785bffdde7.tar.gz |
SERVER-36731 Ban object inequality and $in with unsupported values when using allPaths indexes
Diffstat (limited to 'src/mongo/db/query/plan_cache_indexability.cpp')
-rw-r--r-- | src/mongo/db/query/plan_cache_indexability.cpp | 61 |
1 files changed, 15 insertions, 46 deletions
diff --git a/src/mongo/db/query/plan_cache_indexability.cpp b/src/mongo/db/query/plan_cache_indexability.cpp index c541a2fe4af..860381f8b93 100644 --- a/src/mongo/db/query/plan_cache_indexability.cpp +++ b/src/mongo/db/query/plan_cache_indexability.cpp @@ -40,6 +40,7 @@ #include "mongo/db/query/collation/collation_index_key.h" #include "mongo/db/query/collation/collator_interface.h" #include "mongo/db/query/index_entry.h" +#include "mongo/db/query/planner_ixselect.h" #include "mongo/stdx/memory.h" #include <memory> @@ -47,49 +48,6 @@ namespace mongo { namespace { -bool canUseAllPathsIndex(BSONElement elt, MatchExpression::MatchType matchType) { - if (elt.type() == BSONType::Object) { - return false; - } - - if (elt.type() == BSONType::Array) { - // We only support equality to empty array. - return elt.embeddedObject().isEmpty() && matchType == MatchExpression::EQ; - } - - return true; -} - -bool supportedByAllPathsIndex(const MatchExpression* queryExpr) { - if (ComparisonMatchExpression::isComparisonMatchExpression(queryExpr)) { - const ComparisonMatchExpression* cmpExpr = - static_cast<const ComparisonMatchExpression*>(queryExpr); - - return canUseAllPathsIndex(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); }); - } - - return true; -}; - -bool supportedBySparseIndex(const MatchExpression* queryExpr) { - if (queryExpr->matchType() == MatchExpression::EQ) { - const auto* queryExprEquality = static_cast<const EqualityMatchExpression*>(queryExpr); - return !queryExprEquality->getData().isNull(); - } else if (queryExpr->matchType() == MatchExpression::MATCH_IN) { - const auto* queryExprIn = static_cast<const InMatchExpression*>(queryExpr); - return !queryExprIn->hasNull(); - } else { - return true; - } -}; - IndexabilityDiscriminator getPartialIndexDiscriminator(const MatchExpression* filterExpr) { return [filterExpr](const MatchExpression* queryExpr) { return expression::isSubsetOf(queryExpr, filterExpr); @@ -124,13 +82,21 @@ IndexabilityDiscriminator getCollatedIndexDiscriminator(const CollatorInterface* return true; }; } + +bool nodeIsConservativelySupportedBySparseIndex(const MatchExpression* me) { + // When an expression is in an $elemMatch, a sparse index may be able to support an equality to + // null. We don't track whether or not a match expression is in an $elemMatch when generating + // the plan cache key, so we make the conservative assumption that it is not. + const bool inElemMatch = false; + return QueryPlannerIXSelect::nodeIsSupportedBySparseIndex(me, inElemMatch); +} } void PlanCacheIndexabilityState::processSparseIndex(const std::string& indexName, const BSONObj& keyPattern) { for (BSONElement elem : keyPattern) { _pathDiscriminatorsMap[elem.fieldNameStringData()][indexName].addDiscriminator( - supportedBySparseIndex); + nodeIsConservativelySupportedBySparseIndex); } } @@ -187,8 +153,11 @@ IndexToDiscriminatorMap PlanCacheIndexabilityState::buildAllPathsDiscriminators( if (allPathsDiscriminator.projectionExec->applyProjectionToOneField(path)) { CompositeIndexabilityDiscriminator& cid = ret[allPathsDiscriminator.catalogName]; - cid.addDiscriminator(supportedByAllPathsIndex); - cid.addDiscriminator(supportedBySparseIndex); + // 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(nodeIsConservativelySupportedBySparseIndex); cid.addDiscriminator(getCollatedIndexDiscriminator(allPathsDiscriminator.collator)); if (allPathsDiscriminator.filterExpr) { cid.addDiscriminator( |