summaryrefslogtreecommitdiff
path: root/jstests/core
diff options
context:
space:
mode:
authorAnton Korshunov <anton.korshunov@mongodb.com>2021-03-02 13:03:45 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-03-13 07:52:14 +0000
commitd362ea53d66d85750b0cb63b69168e1b3a4a330e (patch)
treead4a34c4c31ba25b252d52ddf854fd3f23550bbc /jstests/core
parenta90fee27ae85894ae6e4522251fe0ea35ef473c7 (diff)
downloadmongo-d362ea53d66d85750b0cb63b69168e1b3a4a330e.tar.gz
SERVER-54322 Text query plans are not shown properly in SBE explain
Diffstat (limited to 'jstests/core')
-rw-r--r--jstests/core/fts_explain.js6
-rw-r--r--jstests/core/fts_index3.js1
-rw-r--r--jstests/core/fts_projection.js4
-rw-r--r--jstests/core/hidden_index.js1
-rw-r--r--jstests/core/index_bounds_pipe.js3
-rw-r--r--jstests/core/index_filter_commands.js9
-rw-r--r--jstests/core/profile_mapreduce.js1
-rw-r--r--jstests/core/projection_dotted_paths.js44
-rw-r--r--jstests/core/stages_text.js24
-rw-r--r--jstests/core/text_covered_matching.js3
-rw-r--r--jstests/core/wildcard_and_text_indexes.js9
-rw-r--r--jstests/core/wildcard_index_cached_plans.js8
12 files changed, 43 insertions, 70 deletions
diff --git a/jstests/core/fts_explain.js b/jstests/core/fts_explain.js
index 8e18393d15a..c5a56039b1e 100644
--- a/jstests/core/fts_explain.js
+++ b/jstests/core/fts_explain.js
@@ -2,6 +2,7 @@
// collection.
// @tags: [
// assumes_no_implicit_index_creation,
+// requires_fcv_49,
// ]
// Test $text explain. SERVER-12037.
@@ -30,10 +31,9 @@ if ("SINGLE_SHARD" === stage.stage) {
assert.eq(stage.stage, "PROJECTION_DEFAULT");
let textStage = stage.inputStage;
-assert.eq(textStage.stage, "TEXT");
+assert.eq(textStage.stage, "TEXT_MATCH");
assert.gte(textStage.textIndexVersion, 1, "textIndexVersion incorrect or missing.");
-assert.eq(textStage.inputStage.stage, "TEXT_MATCH");
-assert.eq(textStage.inputStage.inputStage.stage, "TEXT_OR");
+assert.eq(textStage.inputStage.stage, "TEXT_OR");
assert.eq(textStage.parsedTextQuery.terms, ["a"]);
assert.eq(textStage.parsedTextQuery.negatedTerms, ["b"]);
assert.eq(textStage.parsedTextQuery.phrases, ["a"]);
diff --git a/jstests/core/fts_index3.js b/jstests/core/fts_index3.js
index 0f57c7a9d80..c255b645d90 100644
--- a/jstests/core/fts_index3.js
+++ b/jstests/core/fts_index3.js
@@ -3,7 +3,6 @@
// key.
// @tags: [
// assumes_unsharded_collection,
-// sbe_incompatible,
// ]
// Test that updates to fields in a text-indexed document are correctly reflected in the text index.
diff --git a/jstests/core/fts_projection.js b/jstests/core/fts_projection.js
index 3d08cb953f0..a850f440195 100644
--- a/jstests/core/fts_projection.js
+++ b/jstests/core/fts_projection.js
@@ -107,10 +107,10 @@ assert.neq(-1,
let explainOutput = t.find({$text: {$search: "textual content -irrelevant"}}, {
score: {$meta: "textScore"}
}).explain();
-assert(planHasStage(db, explainOutput.queryPlanner.winningPlan, "TEXT_OR"));
+assert(planHasStage(db, getWinningPlan(explainOutput.queryPlanner), "TEXT_OR"), explainOutput);
explainOutput = t.find({$text: {$search: "textual content -irrelevant"}}).explain();
-assert(!planHasStage(db, explainOutput.queryPlanner.winningPlan, "TEXT_OR"));
+assert(!planHasStage(db, getWinningPlan(explainOutput.queryPlanner), "TEXT_OR"), explainOutput);
// Scores should exist.
assert.eq(results.length, 2);
diff --git a/jstests/core/hidden_index.js b/jstests/core/hidden_index.js
index 344a808fab6..287c7cc5d0a 100644
--- a/jstests/core/hidden_index.js
+++ b/jstests/core/hidden_index.js
@@ -5,7 +5,6 @@
* @tags: [
* # CollMod is not retryable.
* requires_non_retryable_commands,
- * sbe_incompatible,
* ]
*/
diff --git a/jstests/core/index_bounds_pipe.js b/jstests/core/index_bounds_pipe.js
index 88c9f9a9a7f..6edbfe824db 100644
--- a/jstests/core/index_bounds_pipe.js
+++ b/jstests/core/index_bounds_pipe.js
@@ -1,9 +1,6 @@
/**
* Tests the tightness of index bounds when attempting to match a regex that contains escaped and
* non-escaped pipe '|' characters.
- * @tags: [
- * sbe_incompatible,
- * ]
*/
(function() {
'use strict';
diff --git a/jstests/core/index_filter_commands.js b/jstests/core/index_filter_commands.js
index 2369ac7e4fe..c87b3cfc2d7 100644
--- a/jstests/core/index_filter_commands.js
+++ b/jstests/core/index_filter_commands.js
@@ -230,10 +230,12 @@ assert.commandWorked(coll.runCommand('planCacheSetFilter',
// pattern.
explain = coll.find(queryAA).explain();
-assert(isIxscan(db, explain.queryPlanner.winningPlan), "Expected index scan: " + tojson(explain));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)),
+ "Expected index scan: " + tojson(explain));
explain = coll.find(queryAA).collation(collationEN).explain();
-assert(isIxscan(db, explain.queryPlanner.winningPlan), "Expected index scan: " + tojson(explain));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)),
+ "Expected index scan: " + tojson(explain));
// Ensure that index names in planCacheSetFilter only select matching names.
@@ -241,7 +243,8 @@ assert.commandWorked(coll.runCommand('planCacheSetFilter',
{query: queryAA, collation: collationEN, indexes: ["a_1"]}));
explain = coll.find(queryAA).collation(collationEN).explain();
-assert(isCollscan(db, explain.queryPlanner.winningPlan), "Expected collscan: " + tojson(explain));
+assert(isCollscan(db, getWinningPlan(explain.queryPlanner)),
+ "Expected collscan: " + tojson(explain));
//
// Test that planCacheSetFilter and planCacheClearFilters allow queries containing $expr.
diff --git a/jstests/core/profile_mapreduce.js b/jstests/core/profile_mapreduce.js
index 7f9b581acc1..608971f8684 100644
--- a/jstests/core/profile_mapreduce.js
+++ b/jstests/core/profile_mapreduce.js
@@ -3,7 +3,6 @@
// does_not_support_causal_consistency,
// does_not_support_stepdowns,
// requires_profiling,
-// sbe_incompatible,
// uses_map_reduce_with_temp_collections,
// ]
diff --git a/jstests/core/projection_dotted_paths.js b/jstests/core/projection_dotted_paths.js
index 340189facdc..5fc12cdcac3 100644
--- a/jstests/core/projection_dotted_paths.js
+++ b/jstests/core/projection_dotted_paths.js
@@ -28,16 +28,16 @@ assert.commandWorked(coll.insert({_id: 1, a: 1, b: {c: 1, d: 1, e: 1}, c: 1, e:
let resultDoc = coll.findOne({a: 1}, {_id: 0, a: 1, "b.c": 1, "b.d": 1, c: 1});
assert.eq(resultDoc, {a: 1, b: {c: 1, d: 1}, c: 1});
let explain = coll.find({a: 1}, {_id: 0, a: 1, "b.c": 1, "b.d": 1, c: 1}).explain("queryPlanner");
-assert(isIxscan(db, explain.queryPlanner.winningPlan), explain);
-assert(isIndexOnly(db, explain.queryPlanner.winningPlan), explain);
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)), explain);
+assert(isIndexOnly(db, getWinningPlan(explain.queryPlanner)), explain);
// Project a subset of the indexed fields. Verify that the projection is computed correctly and
// that the plan is covered.
resultDoc = coll.findOne({a: 1}, {_id: 0, "b.c": 1, c: 1});
assert.eq(resultDoc, {b: {c: 1}, c: 1});
explain = coll.find({a: 1}, {_id: 0, "b.c": 1, c: 1}).explain("queryPlanner");
-assert(isIxscan(db, explain.queryPlanner.winningPlan));
-assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
+assert(isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
// Project exactly the set of fields in the index but also include _id. Verify that the
// projection is computed correctly and that the plan cannot be covered.
@@ -45,32 +45,32 @@ resultDoc = coll.findOne({a: 1}, {_id: 1, a: 1, "b.c": 1, "b.d": 1, c: 1});
assert.eq(resultDoc, {_id: 1, a: 1, b: {c: 1, d: 1}, c: 1});
explain = coll.find({a: 1}, {_id: 0, "b.c": 1, c: 1}).explain("queryPlanner");
explain = coll.find({a: 1}, {_id: 1, a: 1, "b.c": 1, "b.d": 1, c: 1}).explain("queryPlanner");
-assert(isIxscan(db, explain.queryPlanner.winningPlan));
-assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
+assert(!isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
// Project a not-indexed field that exists in the collection. The plan should not be covered.
resultDoc = coll.findOne({a: 1}, {_id: 0, "b.c": 1, "b.e": 1, c: 1});
assert.eq(resultDoc, {b: {c: 1, e: 1}, c: 1});
explain = coll.find({a: 1}, {_id: 0, "b.c": 1, "b.e": 1, c: 1}).explain("queryPlanner");
-assert(isIxscan(db, explain.queryPlanner.winningPlan));
-assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
+assert(!isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
// Project a not-indexed field that does not exist in the collection. The plan should not be
// covered.
resultDoc = coll.findOne({a: 1}, {_id: 0, "b.c": 1, "b.z": 1, c: 1});
assert.eq(resultDoc, {b: {c: 1}, c: 1});
explain = coll.find({a: 1}, {_id: 0, "b.c": 1, "b.z": 1, c: 1}).explain("queryPlanner");
-assert(isIxscan(db, explain.queryPlanner.winningPlan));
-assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
+assert(!isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
// Verify that the correct projection is computed with an idhack query.
resultDoc = coll.findOne({_id: 1}, {_id: 0, "b.c": 1, "b.e": 1, c: 1});
assert.eq(resultDoc, {b: {c: 1, e: 1}, c: 1});
explain = coll.find({_id: 1}, {_id: 0, "b.c": 1, "b.e": 1, c: 1}).explain("queryPlanner");
if (isSBEEnabled) {
- assert(isIxscan(db, explain.queryPlanner.winningPlan), explain);
+ assert(isIxscan(db, getWinningPlan(explain.queryPlanner)), explain);
} else {
- assert(isIdhack(db, explain.queryPlanner.winningPlan), explain);
+ assert(isIdhack(db, getWinningPlan(explain.queryPlanner)), explain);
}
// If we make a dotted path multikey, projections using that path cannot be covered. But
@@ -80,15 +80,15 @@ assert.commandWorked(coll.insert({a: 2, b: {c: 1, d: [1, 2, 3]}}));
resultDoc = coll.findOne({a: 2}, {_id: 0, "b.c": 1, "b.d": 1});
assert.eq(resultDoc, {b: {c: 1, d: [1, 2, 3]}});
explain = coll.find({a: 2}, {_id: 0, "b.c": 1, "b.d": 1}).explain("queryPlanner");
-assert(isIxscan(db, explain.queryPlanner.winningPlan));
-assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
+assert(!isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
resultDoc = coll.findOne({a: 2}, {_id: 0, "b.c": 1});
assert.eq(resultDoc, {b: {c: 1}});
explain = coll.find({a: 2}, {_id: 0, "b.c": 1}).explain("queryPlanner");
-assert(isIxscan(db, explain.queryPlanner.winningPlan));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
// Path-level multikey info allows for generating a covered plan.
-assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
+assert(isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
// Verify that dotted projections work for multiple levels of nesting.
assert.commandWorked(coll.createIndex({a: 1, "x.y.y": 1, "x.y.z": 1, "x.z": 1}));
@@ -96,8 +96,8 @@ assert.commandWorked(coll.insert({a: 3, x: {y: {y: 1, f: 1, z: 1}, f: 1, z: 1}})
resultDoc = coll.findOne({a: 3}, {_id: 0, "x.y.y": 1, "x.y.z": 1, "x.z": 1});
assert.eq(resultDoc, {x: {y: {y: 1, z: 1}, z: 1}});
explain = coll.find({a: 3}, {_id: 0, "x.y.y": 1, "x.y.z": 1, "x.z": 1}).explain("queryPlanner");
-assert(isIxscan(db, explain.queryPlanner.winningPlan));
-assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
+assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
+assert(isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
// If projected nested paths do not exist in the indexed document, then they will get filled in
// with nulls. This is a bug tracked by SERVER-23229.
@@ -109,8 +109,8 @@ assert.eq(resultDoc, {x: {y: {y: null, z: null}, z: null}});
assert.commandWorked(coll.createIndex({"a.b.c": 1, "a.b": 1}));
assert.commandWorked(coll.insert({a: {b: {c: 1, d: 1}}}));
explain = coll.find({"a.b.c": 1}, {_id: 0, "a.b": 1}).explain();
- assert(isIxscan(db, explain.queryPlanner.winningPlan));
- assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
+ assert(isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
assert.eq(coll.findOne({"a.b.c": 1}, {_id: 0, "a.b": 1}), {a: {b: {c: 1, d: 1}}});
}
@@ -122,8 +122,8 @@ assert.eq(resultDoc, {x: {y: {y: null, z: null}, z: null}});
const filter = {"a.b": {c: 1, d: 1}};
explain = coll.find(filter, {_id: 0, "a.b": 1}).explain();
- assert(isIxscan(db, explain.queryPlanner.winningPlan));
- assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, getWinningPlan(explain.queryPlanner)));
+ assert(isIndexOnly(db, getWinningPlan(explain.queryPlanner)));
assert.eq(coll.findOne(filter, {_id: 0, "a.b": 1}), {a: {b: {c: 1, d: 1}}});
}
}());
diff --git a/jstests/core/stages_text.js b/jstests/core/stages_text.js
deleted file mode 100644
index 4b5379a0e4c..00000000000
--- a/jstests/core/stages_text.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// @tags: [
-// does_not_support_stepdowns,
-// uses_testing_only_commands,
-// ]
-
-// Test very basic functionality of text stage
-
-t = db.stages_text;
-t.drop();
-var collname = "stages_text";
-
-t.save({x: "az b x"});
-
-t.createIndex({x: "text"});
-
-// We expect to retrieve 'b'
-res = db.runCommand({stageDebug: {collection: collname, plan: {text: {args: {search: "b"}}}}});
-assert.eq(res.ok, 1);
-assert.eq(res.results.length, 1);
-
-// I have not been indexed yet.
-res = db.runCommand({stageDebug: {collection: collname, plan: {text: {args: {search: "hari"}}}}});
-assert.eq(res.ok, 1);
-assert.eq(res.results.length, 0);
diff --git a/jstests/core/text_covered_matching.js b/jstests/core/text_covered_matching.js
index 92366237047..0fd75306fa9 100644
--- a/jstests/core/text_covered_matching.js
+++ b/jstests/core/text_covered_matching.js
@@ -10,7 +10,6 @@
// @tags: [
// assumes_balancer_off,
// requires_fcv_49,
-// sbe_incompatible,
// ]
load("jstests/libs/analyze_plan.js");
@@ -80,7 +79,7 @@ assert.docEq(filteringStage.filter, {"b": {"$eq": 1}}, "Incorrect filter on TEXT
// underlying IXSCANs, but we should get an equivalent result.
explainResult = coll.find({$text: {$search: "hello world"}, b: 1}).explain("executionStats");
assert.commandWorked(explainResult);
-assert(planHasStage(db, explainResult.queryPlanner.winningPlan, "OR"));
+assert(planHasStage(db, getWinningPlan(explainResult.queryPlanner), "OR"));
assert.eq(explainResult.executionStats.totalKeysExamined,
4,
"Unexpected number of keys examined: " + tojson(explainResult));
diff --git a/jstests/core/wildcard_and_text_indexes.js b/jstests/core/wildcard_and_text_indexes.js
index 5fa3d0520a2..0835bd51b26 100644
--- a/jstests/core/wildcard_and_text_indexes.js
+++ b/jstests/core/wildcard_and_text_indexes.js
@@ -2,6 +2,7 @@
* Tests that a {$**: 1} index can coexist with a {$**: 'text'} index in the same collection.
* @tags: [
* assumes_balancer_off,
+ * requires_fcv_49,
* ]
*/
(function() {
@@ -52,7 +53,7 @@ for (let textIndex of [{'$**': 'text'}, {a: 1, '$**': 'text'}]) {
// when the query filter contains a compound field in the $text index.
const textQuery = Object.assign(textIndex.a ? {a: 1} : {}, {$text: {$search: 'banana'}});
let explainOut = assert.commandWorked(coll.find(textQuery).explain("executionStats"));
- assert(planHasStage(coll.getDB(), getWinningPlan(explainOut.queryPlanner), "TEXT"));
+ assert(planHasStage(coll.getDB(), getWinningPlan(explainOut.queryPlanner), "TEXT_MATCH"));
assert.eq(getRejectedPlans(explainOut).length, 0);
assert.eq(explainOut.executionStats.nReturned, 2);
@@ -60,7 +61,7 @@ for (let textIndex of [{'$**': 'text'}, {a: 1, '$**': 'text'}]) {
// where the query filter contains a field which is not present in the text index.
explainOut = assert.commandWorked(
coll.find(Object.assign({_fts: {$gt: 0, $lt: 4}}, textQuery)).explain("executionStats"));
- assert(planHasStage(coll.getDB(), getWinningPlan(explainOut.queryPlanner), "TEXT"));
+ assert(planHasStage(coll.getDB(), getWinningPlan(explainOut.queryPlanner), "TEXT_MATCH"));
assert.eq(getRejectedPlans(explainOut).length, 0);
assert.eq(explainOut.executionStats.nReturned, 2);
@@ -72,9 +73,9 @@ for (let textIndex of [{'$**': 'text'}, {a: 1, '$**': 'text'}]) {
const textOrWildcard = getPlanStages(getWinningPlan(explainOut.queryPlanner), "OR").shift();
assert.eq(textOrWildcard.inputStages.length, 2);
- const textBranch = (textOrWildcard.inputStages[0].stage === "TEXT" ? 0 : 1);
+ const textBranch = (textOrWildcard.inputStages[0].stage === "TEXT_MATCH" ? 0 : 1);
const wildcardBranch = (textBranch + 1) % 2;
- assert.eq(textOrWildcard.inputStages[textBranch].stage, "TEXT");
+ assert.eq(textOrWildcard.inputStages[textBranch].stage, "TEXT_MATCH");
assert.eq(textOrWildcard.inputStages[wildcardBranch].stage, "IXSCAN");
assert.eq(textOrWildcard.inputStages[wildcardBranch].keyPattern, {$_path: 1, _fts: 1});
diff --git a/jstests/core/wildcard_index_cached_plans.js b/jstests/core/wildcard_index_cached_plans.js
index 796686370bb..e124e2ad1e8 100644
--- a/jstests/core/wildcard_index_cached_plans.js
+++ b/jstests/core/wildcard_index_cached_plans.js
@@ -127,7 +127,7 @@ assert.commandWorked(coll.createIndex({"b.$**": 1}));
// string bounds.
const queryWithoutStringExplain =
coll.explain().find({a: 5, b: 5}).collation({locale: "fr"}).finish();
-let ixScans = getPlanStages(queryWithoutStringExplain.queryPlanner.winningPlan, "IXSCAN");
+let ixScans = getPlanStages(getWinningPlan(queryWithoutStringExplain.queryPlanner), "IXSCAN");
assert.eq(ixScans.length, FixtureHelpers.numberOfShardsForCollection(coll));
assert.eq(ixScans[0].keyPattern, {$_path: 1, b: 1});
@@ -135,7 +135,7 @@ assert.eq(ixScans[0].keyPattern, {$_path: 1, b: 1});
// bounds.
const queryWithStringExplain =
coll.explain().find({a: 5, b: "a string"}).collation({locale: "fr"}).finish();
-ixScans = getPlanStages(queryWithStringExplain.queryPlanner.winningPlan, "IXSCAN");
+ixScans = getPlanStages(getWinningPlan(queryWithStringExplain.queryPlanner), "IXSCAN");
assert.eq(ixScans.length, 0);
// Check that the shapes are different since the query which matches on a string will not
@@ -151,13 +151,13 @@ assert.commandWorked(coll.createIndex({"$**": 1}, {partialFilterExpression: {a:
// Run a query for a value included by the partial filter expression.
const queryIndexedExplain = coll.find({a: 4}).explain();
-let ixScans = getPlanStages(queryIndexedExplain.queryPlanner.winningPlan, "IXSCAN");
+let ixScans = getPlanStages(getWinningPlan(queryIndexedExplain.queryPlanner), "IXSCAN");
assert.eq(ixScans.length, FixtureHelpers.numberOfShardsForCollection(coll));
assert.eq(ixScans[0].keyPattern, {$_path: 1, a: 1});
// Run a query which tries to get a value not included by the partial filter expression.
const queryUnindexedExplain = coll.find({a: 100}).explain();
-ixScans = getPlanStages(queryUnindexedExplain.queryPlanner.winningPlan, "IXSCAN");
+ixScans = getPlanStages(getWinningPlan(queryUnindexedExplain.queryPlanner), "IXSCAN");
assert.eq(ixScans.length, 0);
// Check that the shapes are different since the query which searches for a value not