SERVER-105375 Rewrite obj elemMatch trivially false expressions as alwaysFalse (#36934)

GitOrigin-RevId: dbac78ce6307a45ebc873397486b9323838f6ede
This commit is contained in:
Carlos Alonso 2025-06-23 20:51:42 +02:00 committed by MongoDB Bot
parent a25a91f17a
commit 3369f76f50
3 changed files with 27 additions and 1 deletions

View File

@ -74,6 +74,7 @@ assertContainsIndexScan({x: {$in: [2]}}, {hint: {x: 1}});
// when an index on `x` is available. // when an index on `x` is available.
assertContainsEof({x: {$in: []}}); assertContainsEof({x: {$in: []}});
assertContainsEof({x: {$in: []}, y: {$gt: 9}}); assertContainsEof({x: {$in: []}, y: {$gt: 9}});
assertContainsEof({x: {$elemMatch: {y: {$in: []}}}});
// No relevant index should still produce an EOF plan. // No relevant index should still produce an EOF plan.
assertContainsEof({y: {$in: []}}); assertContainsEof({y: {$in: []}});
// Hinting an index should allow EOF plan generation. // Hinting an index should allow EOF plan generation.

View File

@ -115,13 +115,17 @@ void ElemMatchObjectMatchExpression::appendSerializedRightHandSide(BSONObjBuilde
} }
MatchExpression::ExpressionOptimizerFunc ElemMatchObjectMatchExpression::getOptimizer() const { MatchExpression::ExpressionOptimizerFunc ElemMatchObjectMatchExpression::getOptimizer() const {
return [](std::unique_ptr<MatchExpression> expression) { return [](std::unique_ptr<MatchExpression> expression) -> std::unique_ptr<MatchExpression> {
auto& elemExpression = static_cast<ElemMatchObjectMatchExpression&>(*expression); auto& elemExpression = static_cast<ElemMatchObjectMatchExpression&>(*expression);
// The Boolean simplifier is disabled since we don't want to simplify sub-expressions, but // The Boolean simplifier is disabled since we don't want to simplify sub-expressions, but
// simplify the whole expression instead. // simplify the whole expression instead.
elemExpression._sub = MatchExpression::optimize(std::move(elemExpression._sub), elemExpression._sub = MatchExpression::optimize(std::move(elemExpression._sub),
/* enableSimplification */ false); /* enableSimplification */ false);
if (elemExpression._sub->isTriviallyFalse()) {
return std::make_unique<AlwaysFalseMatchExpression>();
}
return expression; return expression;
}; };
} }

View File

@ -551,6 +551,27 @@ TEST(ExpressionOptimizeTest, EmptyInOptimizesToAlwaysFalse) {
ASSERT_BSONOBJ_EQ(optimizedMatchExpression->serialize(), fromjson("{$alwaysFalse: 1}")); ASSERT_BSONOBJ_EQ(optimizedMatchExpression->serialize(), fromjson("{$alwaysFalse: 1}"));
} }
TEST(ExpressionOptimizeTest, EmptyInWithinElemMatchExpressionOptimizesToAlwaysFalse) {
BSONObj obj = fromjson("{x: {$elemMatch: {y: {$in: []}}}}");
std::unique_ptr<MatchExpression> matchExpression(parseMatchExpression(obj));
auto optimizedMatchExpression = MatchExpression::optimize(std::move(matchExpression));
ASSERT_BSONOBJ_EQ(optimizedMatchExpression->serialize(), fromjson("{$alwaysFalse: 1}"));
}
TEST(ExpressionOptimizeTest, DoubleEmptyInWithinElemMatchExpressionOptimizesToAlwaysFalse) {
BSONObj obj = fromjson("{x: {$elemMatch: {y: {$in: []}, z: {$in: []}}}}");
std::unique_ptr<MatchExpression> matchExpression(parseMatchExpression(obj));
auto optimizedMatchExpression = MatchExpression::optimize(std::move(matchExpression));
ASSERT_BSONOBJ_EQ(optimizedMatchExpression->serialize(), fromjson("{$alwaysFalse: 1}"));
}
TEST(ExpressionOptimizeTest, EmptyInAndSmthElseWithinElemMatchExpressionOptimizesToAlwaysFalse) {
BSONObj obj = fromjson("{x: {$elemMatch: {y: {$in: []}, z: 1}}}");
std::unique_ptr<MatchExpression> matchExpression(parseMatchExpression(obj));
auto optimizedMatchExpression = MatchExpression::optimize(std::move(matchExpression));
ASSERT_BSONOBJ_EQ(optimizedMatchExpression->serialize(), fromjson("{$alwaysFalse: 1}"));
}
TEST(ExpressionOptimizeTest, InWithJustRegexesIsNotOptimizedToAlwaysFalse) { TEST(ExpressionOptimizeTest, InWithJustRegexesIsNotOptimizedToAlwaysFalse) {
BSONObj obj = fromjson("{x: {$in: [/foo/, /bar/]}}"); BSONObj obj = fromjson("{x: {$in: [/foo/, /bar/]}}");
std::unique_ptr<MatchExpression> matchExpression(parseMatchExpression(obj)); std::unique_ptr<MatchExpression> matchExpression(parseMatchExpression(obj));