summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMisha Ivkov <misha.ivkov@10gen.com>2019-07-31 18:00:15 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-08-14 19:00:24 +0000
commitd3470d48166e9897e9d9817340db9f11f70a55e4 (patch)
tree6f1fd2f866466df018961eda6b8603457fee8367
parentd5e2742489c6502f68324c5e40d4ea78c01a3dad (diff)
downloadmongo-d3470d48166e9897e9d9817340db9f11f70a55e4.tar.gz
SERVER-35921 Make IXSCAN use the proper MinKey/MaxKey bounds on LT and GT
(cherry picked from commit b1285a2acb60cbf7c268cb5499fbf5d674d490b2) (cherry picked from commit b315dcfc8145c6b898b21916bef4bec18e95ac54)
-rw-r--r--jstests/core/index_bounds_maxkey.js2
-rw-r--r--jstests/core/index_bounds_minkey.js2
-rw-r--r--jstests/core/min_max_key.js3
-rw-r--r--src/mongo/db/query/index_bounds_builder.cpp17
-rw-r--r--src/mongo/db/query/index_bounds_builder.h5
-rw-r--r--src/mongo/db/query/index_bounds_builder_test.cpp14
6 files changed, 28 insertions, 15 deletions
diff --git a/jstests/core/index_bounds_maxkey.js b/jstests/core/index_bounds_maxkey.js
index b22af082b13..ab152230904 100644
--- a/jstests/core/index_bounds_maxkey.js
+++ b/jstests/core/index_bounds_maxkey.js
@@ -18,7 +18,7 @@
assertCoveredQueryAndCount(
{collection: coll, query: {a: {$gte: MaxKey}}, project: proj, count: 1});
assertCoveredQueryAndCount(
- {collection: coll, query: {a: {$lt: MaxKey}}, project: proj, count: 1});
+ {collection: coll, query: {a: {$lt: MaxKey}}, project: proj, count: 0});
assertCoveredQueryAndCount(
{collection: coll, query: {a: {$lte: MaxKey}}, project: proj, count: 1});
diff --git a/jstests/core/index_bounds_minkey.js b/jstests/core/index_bounds_minkey.js
index 6fa9d4f0d1e..25fc4f56fc7 100644
--- a/jstests/core/index_bounds_minkey.js
+++ b/jstests/core/index_bounds_minkey.js
@@ -14,7 +14,7 @@
// Test that queries involving comparison operators with MinKey are covered.
const proj = {a: 1, _id: 0};
assertCoveredQueryAndCount(
- {collection: coll, query: {a: {$gt: MinKey}}, project: proj, count: 1});
+ {collection: coll, query: {a: {$gt: MinKey}}, project: proj, count: 0});
assertCoveredQueryAndCount(
{collection: coll, query: {a: {$gte: MinKey}}, project: proj, count: 1});
assertCoveredQueryAndCount(
diff --git a/jstests/core/min_max_key.js b/jstests/core/min_max_key.js
index d65d68292fa..744bdff2b49 100644
--- a/jstests/core/min_max_key.js
+++ b/jstests/core/min_max_key.js
@@ -89,9 +89,6 @@
testTypeBracketedQueries();
assert.commandWorked(coll.createIndex({a: 1}));
- // TODO: SERVER-35921 The results of the queries above should not change based on the
- // presence of an index
- assert.commandWorked(coll.dropIndexes());
testQueriesWithMinOrMaxKey();
testTypeBracketedQueries();
diff --git a/src/mongo/db/query/index_bounds_builder.cpp b/src/mongo/db/query/index_bounds_builder.cpp
index 503ee1f8b9d..48ee291b288 100644
--- a/src/mongo/db/query/index_bounds_builder.cpp
+++ b/src/mongo/db/query/index_bounds_builder.cpp
@@ -250,6 +250,13 @@ void IndexBoundsBuilder::allValuesForField(const BSONElement& elt, OrderedInterv
makeRangeInterval(bob.obj(), BoundInclusion::kIncludeBothStartAndEndKeys));
}
+Interval IndexBoundsBuilder::allValuesRespectingInclusion(BoundInclusion bi) {
+ BSONObjBuilder bob;
+ bob.appendMinKey("");
+ bob.appendMaxKey("");
+ return makeRangeInterval(bob.obj(), bi);
+}
+
Interval IndexBoundsBuilder::allValues() {
BSONObjBuilder bob;
bob.appendMinKey("");
@@ -479,9 +486,10 @@ void IndexBoundsBuilder::translate(const MatchExpression* expr,
const LTMatchExpression* node = static_cast<const LTMatchExpression*>(expr);
BSONElement dataElt = node->getData();
- // Everything is <= MaxKey.
+ // Everything is < MaxKey, except for MaxKey.
if (MaxKey == dataElt.type()) {
- oilOut->intervals.push_back(allValues());
+ oilOut->intervals.push_back(allValuesRespectingInclusion(
+ IndexBounds::makeBoundInclusionFromBoundBools(true, false)));
*tightnessOut =
index.collator ? IndexBoundsBuilder::INEXACT_FETCH : IndexBoundsBuilder::EXACT;
return;
@@ -517,9 +525,10 @@ void IndexBoundsBuilder::translate(const MatchExpression* expr,
const GTMatchExpression* node = static_cast<const GTMatchExpression*>(expr);
BSONElement dataElt = node->getData();
- // Everything is > MinKey.
+ // Everything is > MinKey, except MinKey.
if (MinKey == dataElt.type()) {
- oilOut->intervals.push_back(allValues());
+ oilOut->intervals.push_back(allValuesRespectingInclusion(
+ IndexBounds::makeBoundInclusionFromBoundBools(false, true)));
*tightnessOut =
index.collator ? IndexBoundsBuilder::INEXACT_FETCH : IndexBoundsBuilder::EXACT;
return;
diff --git a/src/mongo/db/query/index_bounds_builder.h b/src/mongo/db/query/index_bounds_builder.h
index 52e33853b8b..9f396bd144e 100644
--- a/src/mongo/db/query/index_bounds_builder.h
+++ b/src/mongo/db/query/index_bounds_builder.h
@@ -166,6 +166,11 @@ public:
*/
static Interval allValues();
+ /**
+ * Returns an Interval from minKey to maxKey, preserving the specified inclusion.
+ */
+ static Interval allValuesRespectingInclusion(BoundInclusion bi);
+
static void translateRegex(const RegexMatchExpression* rme,
const IndexEntry& index,
OrderedIntervalList* oil,
diff --git a/src/mongo/db/query/index_bounds_builder_test.cpp b/src/mongo/db/query/index_bounds_builder_test.cpp
index 392204f548c..75062d44c4f 100644
--- a/src/mongo/db/query/index_bounds_builder_test.cpp
+++ b/src/mongo/db/query/index_bounds_builder_test.cpp
@@ -439,9 +439,9 @@ TEST(IndexBoundsBuilderTest, TranslateLtMaxKey) {
IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
- ASSERT_EQUALS(oil.intervals[0].toString(), "[MinKey, MaxKey]");
+ ASSERT_EQUALS(oil.intervals[0].toString(), "[MinKey, MaxKey)");
ASSERT_TRUE(oil.intervals[0].startInclusive);
- ASSERT_TRUE(oil.intervals[0].endInclusive);
+ ASSERT_FALSE(oil.intervals[0].endInclusive);
ASSERT_EQUALS(tightness, IndexBoundsBuilder::EXACT);
}
@@ -583,8 +583,8 @@ TEST(IndexBoundsBuilderTest, TranslateGtMinKey) {
IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
- ASSERT_EQUALS(oil.intervals[0].toString(), "[MinKey, MaxKey]");
- ASSERT_TRUE(oil.intervals[0].startInclusive);
+ ASSERT_EQUALS(oil.intervals[0].toString(), "(MinKey, MaxKey]");
+ ASSERT_FALSE(oil.intervals[0].startInclusive);
ASSERT_TRUE(oil.intervals[0].endInclusive);
ASSERT_EQUALS(tightness, IndexBoundsBuilder::EXACT);
}
@@ -2485,7 +2485,8 @@ TEST(IndexBoundsBuilderTest, LTMaxKeyWithCollator) {
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS,
- oil.intervals[0].compare(IndexBoundsBuilder::allValues()));
+ oil.intervals[0].compare(IndexBoundsBuilder::allValuesRespectingInclusion(
+ BoundInclusion::kIncludeStartKeyOnly)));
ASSERT_EQUALS(tightness, IndexBoundsBuilder::INEXACT_FETCH);
}
@@ -2525,7 +2526,8 @@ TEST(IndexBoundsBuilderTest, GTMinKeyWithCollator) {
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS,
- oil.intervals[0].compare(IndexBoundsBuilder::allValues()));
+ oil.intervals[0].compare(IndexBoundsBuilder::allValuesRespectingInclusion(
+ BoundInclusion::kIncludeEndKeyOnly)));
ASSERT_EQUALS(tightness, IndexBoundsBuilder::INEXACT_FETCH);
}