SERVER-127282: Handle open-ended date IXSCAN bounds in plan_stability reconstruction (#54145)

GitOrigin-RevId: 6337c3c5087a2f9f67d6728ccb7113205dcd1d61
This commit is contained in:
Naafiyan Ahmed 2026-05-22 13:22:53 -04:00 committed by MongoDB Bot
parent 989847bc89
commit dcefbaa865
2 changed files with 16 additions and 4 deletions

View File

@ -3104,7 +3104,7 @@ db.supplier.aggregate(EJSON.deserialize(
{"$match":{"$and":[{"o_clerk":{"$not":{"$eq":"Clerk#000000567"}}},{}]}}]}},
{"$unwind":"$orders"},{"$replaceRoot":{"newRoot":{"$mergeObjects":["$$ROOT","$orders"]}}},
{"$lookup":{"from":"lineitem","localField":"o_orderkey","foreignField":"l_orderkey","as":"lineitem","pipeline":[
{"$match":{"l_commitdate":{"$gte":null,"$lte":"1992-04-13T00:00:00.000Z"}}}]}},
{"$match":{"l_commitdate":{"$lte":"1992-04-13T00:00:00.000Z"}}}]}},
{"$unwind":"$lineitem"},{"$replaceRoot":{"newRoot":{"$mergeObjects":["$$ROOT","$lineitem"]}}}]
));
```

View File

@ -230,6 +230,11 @@ function getPredicateFromIxscan(stage) {
* we need to do a lot of heavy lifting to reconstruct the original predicate.
*/
function parseIndexBound(boundStr) {
// MongoDB's IXSCAN explain output renders "no lower/upper bound" on a date-typed index as
// new Date(INT64_MIN) / new Date(INT64_MAX).
const DATE_INT64_MIN_LITERAL = "new Date(-9223372036854775808)";
const DATE_INT64_MAX_LITERAL = "new Date(9223372036854775807)";
// Bounds look like this: '["abc", "abc"]', '(5.0, 10.0]', '[MinKey, MaxKey]'
const match = boundStr.match(/^([\[\(])\s*(.+?)\s*,\s*(.+?)\s*([\]\)])$/);
if (!match) {
@ -243,8 +248,15 @@ function parseIndexBound(boundStr) {
const lowerInclusive = match[1] === "[";
const upperInclusive = match[4] === "]";
const lowerVal = parseIndexBoundLiteral(match[2].trim());
const upperVal = parseIndexBoundLiteral(match[3].trim());
const lowerRaw = match[2].trim();
const upperRaw = match[3].trim();
// Only re-map on the side that semantically means "no bound": INT64_MIN as the lower bound,
// INT64_MAX as the upper bound. The inverse positions can appear as legitimate type-bracketing
// bounds, e.g. {$lt: null} on a date IXSCAN produces [MinKey, new Date(INT64_MIN)), and must
// stay intact.
const lowerVal = lowerRaw === DATE_INT64_MIN_LITERAL ? "MinKey" : parseIndexBoundLiteral(lowerRaw);
const upperVal = upperRaw === DATE_INT64_MAX_LITERAL ? "MaxKey" : parseIndexBoundLiteral(upperRaw);
const isEquality =
lowerInclusive &&
@ -264,7 +276,7 @@ function parseIndexBound(boundStr) {
}
/**
* Parse an individual literal as seen in an index bound
* Parse an individual literal as seen in an index bound.
*/
function parseIndexBoundLiteral(str) {
if (str === "MinKey") return "MinKey";