summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/core/index_filter_commands.js27
-rw-r--r--src/mongo/db/query/explain.cpp16
2 files changed, 43 insertions, 0 deletions
diff --git a/jstests/core/index_filter_commands.js b/jstests/core/index_filter_commands.js
index dddc69a688d..048e1cd8178 100644
--- a/jstests/core/index_filter_commands.js
+++ b/jstests/core/index_filter_commands.js
@@ -145,3 +145,30 @@ assert(!planCacheContains(shape), 'plan cache for query shape not flushed after
print('Plan details before setting filter = ' + tojson(planBeforeSetFilter.details, '', true));
print('Plan details after setting filter = ' + tojson(planAfterSetFilter.details, '', true));
+
+//
+// Tests for the 'indexFilterSet' explain field.
+//
+
+// No filter.
+t.getPlanCache().clear();
+assert.eq(false, t.find({z: 1}).explain('queryPlanner').queryPlanner.indexFilterSet);
+assert.eq(false, t.find(queryA1, projectionA1).sort(sortA1)
+ .explain('queryPlanner').queryPlanner.indexFilterSet);
+
+// With one filter set.
+assert.commandWorked(t.runCommand('planCacheSetFilter', {query: {z: 1}, indexes: [{z: 1}]}));
+assert.eq(true, t.find({z: 1}).explain('queryPlanner').queryPlanner.indexFilterSet);
+assert.eq(false, t.find(queryA1, projectionA1).sort(sortA1)
+ .explain('queryPlanner').queryPlanner.indexFilterSet);
+
+// With two filters set.
+assert.commandWorked(t.runCommand('planCacheSetFilter', {
+ query: queryA1,
+ projection: projectionA1,
+ sort: sortA1,
+ indexes: [indexA1B1, indexA1C1]
+}));
+assert.eq(true, t.find({z: 1}).explain('queryPlanner').queryPlanner.indexFilterSet);
+assert.eq(true, t.find(queryA1, projectionA1).sort(sortA1)
+ .explain('queryPlanner').queryPlanner.indexFilterSet);
diff --git a/src/mongo/db/query/explain.cpp b/src/mongo/db/query/explain.cpp
index 7e25107e926..cbaaf0bb8e2 100644
--- a/src/mongo/db/query/explain.cpp
+++ b/src/mongo/db/query/explain.cpp
@@ -35,6 +35,7 @@
#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/plan_executor.h"
#include "mongo/db/query/query_planner.h"
+#include "mongo/db/query/query_settings.h"
#include "mongo/db/query/stage_builder.h"
#include "mongo/db/exec/working_set_common.h"
#include "mongo/db/server_options.h"
@@ -488,6 +489,21 @@ namespace mongo {
plannerBob.append("plannerVersion", QueryPlanner::kPlannerVersion);
plannerBob.append("namespace", exec->ns());
+ // Find whether there is an index filter set for the query shape. The 'indexFilterSet'
+ // field will always be false in the case of EOF or idhack plans.
+ bool indexFilterSet = false;
+ if (exec->collection() && exec->getCanonicalQuery()) {
+ const Collection* collection = exec->collection();
+ QuerySettings* querySettings = collection->infoCache()->getQuerySettings();
+ AllowedIndices* allowedIndicesRaw;
+ if (querySettings->getAllowedIndices(*exec->getCanonicalQuery(), &allowedIndicesRaw)) {
+ // Found an index filter set on the query shape.
+ boost::scoped_ptr<AllowedIndices> allowedIndices(allowedIndicesRaw);
+ indexFilterSet = true;
+ }
+ }
+ plannerBob.append("indexFilterSet", indexFilterSet);
+
// In general we should have a canonical query, but sometimes we may avoid
// creating a canonical query as an optimization (specifically, the update system
// does not canonicalize for idhack updates). In these cases, 'query' is NULL.