summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernard Gorman <bernard.gorman@gmail.com>2021-03-10 12:16:34 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-03-10 19:59:19 +0000
commit3f601b592620eb2abd207e4c57cff5bf51b4e07e (patch)
treeec06061f80d13ebd75be93144db8475e784985ea
parent268847f5318cf1b5ef543317d7a96b5964981847 (diff)
downloadmongo-3f601b592620eb2abd207e4c57cff5bf51b4e07e.tar.gz
SERVER-54357 Avoid normalizing partialFilterExpression when creating a new index
-rw-r--r--jstests/core/index_partial_create_drop.js8
-rw-r--r--src/mongo/db/index_builds_coordinator.cpp22
-rw-r--r--src/mongo/db/index_builds_coordinator.h4
3 files changed, 13 insertions, 21 deletions
diff --git a/jstests/core/index_partial_create_drop.js b/jstests/core/index_partial_create_drop.js
index 706e787ee71..24a3d29fac4 100644
--- a/jstests/core/index_partial_create_drop.js
+++ b/jstests/core/index_partial_create_drop.js
@@ -42,11 +42,11 @@ assert.commandFailed(
assert.commandFailed(coll.createIndex(
{x: 1}, {partialFilterExpression: {$expr: {$eq: [{$trim: {input: "$x"}}, "hi"]}}}));
-// Only top-level $and is permitted, but by normalizing the input filter we absorb the child $and.
-assert.commandWorked(coll.createIndex({x: 1}, {
+// Only top-level $and is permitted in a partial filter expression.
+assert.commandFailedWithCode(coll.createIndex({x: 1}, {
partialFilterExpression: {$and: [{$and: [{x: {$lt: 2}}, {x: {$gt: 0}}]}, {x: {$exists: true}}]}
-}));
-assert.commandWorked(coll.dropIndexes());
+}),
+ ErrorCodes.CannotCreateIndex);
for (var i = 0; i < 10; i++) {
assert.commandWorked(coll.insert({x: i, a: i}));
diff --git a/src/mongo/db/index_builds_coordinator.cpp b/src/mongo/db/index_builds_coordinator.cpp
index 39dd76d54cd..59cf52abfcf 100644
--- a/src/mongo/db/index_builds_coordinator.cpp
+++ b/src/mongo/db/index_builds_coordinator.cpp
@@ -2757,7 +2757,7 @@ std::vector<BSONObj> IndexBuildsCoordinator::prepareSpecListForCreate(
return indexSpecs;
}
- // Normalize the specs' collations, wildcard projections, and partial filters as applicable.
+ // Normalize the specs' collations, wildcard projections, and any other fields as applicable.
auto normalSpecs = normalizeIndexSpecs(opCtx, collection, indexSpecs);
// Remove any index specifications which already exist in the catalog.
@@ -2791,20 +2791,12 @@ std::vector<BSONObj> IndexBuildsCoordinator::normalizeIndexSpecs(
auto normalSpecs =
uassertStatusOK(collection->addCollationDefaultsToIndexSpecsForCreate(opCtx, indexSpecs));
- // If the index spec has a partialFilterExpression, we normalize it by parsing to an optimized,
- // sorted MatchExpression tree, re-serialize it to BSON, and add it back into the index spec.
- const auto expCtx = make_intrusive<ExpressionContext>(opCtx, nullptr, collection->ns());
- std::transform(normalSpecs.begin(), normalSpecs.end(), normalSpecs.begin(), [&](auto& spec) {
- const auto kPartialFilterName = IndexDescriptor::kPartialFilterExprFieldName;
- auto partialFilterExpr = spec.getObjectField(kPartialFilterName);
- if (partialFilterExpr.isEmpty()) {
- return spec;
- }
- // Parse, optimize and sort the MatchExpression to reduce it to its normalized form.
- // Serialize the normalized filter back into the index spec before returning.
- auto partialFilter = MatchExpressionParser::parseAndNormalize(partialFilterExpr, expCtx);
- return spec.addField(BSON(kPartialFilterName << partialFilter->serialize()).firstElement());
- });
+ // We choose not to normalize the spec's partialFilterExpression at this point, if it exists.
+ // Doing so often reduces the legibility of the filter to the end-user, and makes it difficult
+ // for clients to validate (via the listIndexes output) whether a given partialFilterExpression
+ // is equivalent to the filter that they originally submitted. Omitting this normalization does
+ // not impact our internal index comparison semantics, since we compare based on the parsed
+ // MatchExpression trees rather than the serialized BSON specs. See SERVER-54357.
// If any of the specs describe wildcard indexes, normalize the wildcard projections if present.
// This will change all specs of the form {"a.b.c": 1} to normalized form {a: {b: {c : 1}}}.
diff --git a/src/mongo/db/index_builds_coordinator.h b/src/mongo/db/index_builds_coordinator.h
index 2fd4f1bb0d8..cf73da60d78 100644
--- a/src/mongo/db/index_builds_coordinator.h
+++ b/src/mongo/db/index_builds_coordinator.h
@@ -445,8 +445,8 @@ public:
* complete collation spec in cases where the index spec specifies a collation, and will add
* the collection-default collation, if present, in cases where collation is omitted. If the
* index spec omits the collation and the collection does not have a default, the collation
- * field is omitted from the spec. This function also converts 'wildcardProjection' and
- * 'partialFilterExpression' to canonical form in any cases where they exist.
+ * field is omitted from the spec. This function also converts the 'wildcardProjection' to
+ * canonical form in any cases where it exists.
*
* If 'collection' is null, no changes are made to the input specs.
*