summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/plan_cache_indexability.cpp
diff options
context:
space:
mode:
authorIan Boros <ian.boros@10gen.com>2018-09-06 16:39:53 -0400
committerIan Boros <ian.boros@10gen.com>2018-09-20 16:26:20 -0400
commit5ed54bec92fc15009877e2d579fe59785bffdde7 (patch)
treef190e99159e98dde1d5f0d13f457c4ec2c1b12f1 /src/mongo/db/query/plan_cache_indexability.cpp
parent64672e68a25e1c4c53a9e1e974036b02fdda2cc5 (diff)
downloadmongo-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.cpp61
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(