summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Redman <joel.redman@mongodb.com>2022-09-27 16:19:20 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-03-15 22:28:04 +0000
commit21ee6003fe704534e63ea20d5aa0cf563da0df2f (patch)
tree0e08c4b7d8ff9311075babf73ef857de5b83fe87
parent3f23a831ecd8d03cc6ed73202bbfe238b5a21857 (diff)
downloadmongo-21ee6003fe704534e63ea20d5aa0cf563da0df2f.tar.gz
SERVER-66469 Fix correctness when filtering on dates before the epoch
(cherry picked from commit aedaf14d6dcc60253f3944252eb5cfc588e08ecb)
-rw-r--r--jstests/core/timeseries/timeseries_filter_extended_range.js190
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp243
2 files changed, 347 insertions, 86 deletions
diff --git a/jstests/core/timeseries/timeseries_filter_extended_range.js b/jstests/core/timeseries/timeseries_filter_extended_range.js
new file mode 100644
index 00000000000..5285a2ea47a
--- /dev/null
+++ b/jstests/core/timeseries/timeseries_filter_extended_range.js
@@ -0,0 +1,190 @@
+/**
+ * Test that find/match type queries work properly on dates ouside the 32 bit epoch range,
+ * [1970-01-01 00:00:00 UTC - 2038-01-29 03:13:07 UTC].
+ *
+ * @tags: [
+ * # We need a timeseries collection.
+ * requires_timeseries,
+ * # Timeseries collections require FCV 5.0.
+ * requires_fcv_50,
+ * # Cannot insert into a time-series collection in a multi-document transaction
+ * does_not_support_transactions,
+ * # TODO SERVER-73641 Re-enable this test once the bug is fixed in the sharded case.
+ * assumes_unsharded_collection,
+ * ]
+ */
+
+(function() {
+"use strict";
+const timeFieldName = "time";
+
+/*
+ * Creates a collection, populates it, runs the `query` and ensures that the result set
+ * is equal to `results`.
+ *
+ * If overflow is set we create a document with dates above the 32 bit range (year 2040)
+ * If underflow is set, we create a document with dates below the 32 bit range (year 1965)
+ */
+function runTest(underflow, overflow, query, results) {
+ // Setup our DB & our collections.
+ const tsColl = db.getCollection(jsTestName());
+ tsColl.drop();
+
+ assert.commandWorked(
+ db.createCollection(tsColl.getName(), {timeseries: {timeField: timeFieldName}}));
+
+ const dates = [
+ // If underflow, we want to insert a date that would fall below the epoch
+ // i.e. 1970-01-01 00:00:00 UTC. Otherwise we use a date within the epoch.
+ {[timeFieldName]: underflow ? new Date("1965-01-01") : new Date("1971-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ // If overflow, we want to insert a date that would use more than 32 bit milliseconds after
+ // the epoch. This overflow will occur 2038-01-29 03:13:07 UTC. Otherwise we go slightly
+ // before the end of the 32 bit epoch.
+ {[timeFieldName]: overflow ? new Date("2040-01-01") : new Date("2030-01-01")}
+ ];
+ assert.commandWorked(tsColl.insert(dates));
+
+ // Make sure the expected results are in the correct order for comparison below.
+ function cmpTimeFields(a, b) {
+ return (b[timeFieldName].getTime() - a[timeFieldName].getTime());
+ }
+ results.sort(cmpTimeFields);
+
+ const pipeline = [{$match: query}, {$project: {_id: 0, [timeFieldName]: 1}}];
+
+ // Verify agg pipeline. We don't want to go through a plan that encourages a sort order to
+ // avoid BUS and index selection, so we sort after gathering the results.
+ const aggActuals = tsColl.aggregate(pipeline).toArray();
+ aggActuals.sort(cmpTimeFields);
+ assert.docEq(aggActuals, results);
+
+ // Verify the equivalent find command. We again don't want to go through a plan that
+ // encourages a sort order to avoid BUS and index selection, so we sort after gathering the
+ // results.
+ let findActuals = tsColl.find(query, {_id: 0, [timeFieldName]: 1}).toArray();
+ findActuals.sort(cmpTimeFields);
+ assert.docEq(findActuals, results);
+}
+
+runTest(false,
+ false,
+ {[timeFieldName]: {$eq: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1980-01-01")}]);
+runTest(false,
+ true,
+ {[timeFieldName]: {$eq: new Date("2040-01-01")}},
+ [{[timeFieldName]: new Date("2040-01-01")}]);
+runTest(true,
+ false,
+ {[timeFieldName]: {$eq: new Date("1965-01-01")}},
+ [{[timeFieldName]: new Date("1965-01-01")}]);
+
+runTest(false,
+ false,
+ {[timeFieldName]: {$lt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1971-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
+runTest(false,
+ true,
+ {[timeFieldName]: {$lt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1971-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
+runTest(true,
+ false,
+ {[timeFieldName]: {$lt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1965-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
+runTest(true,
+ true,
+ {[timeFieldName]: {$lt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1965-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
+
+runTest(false,
+ false,
+ {[timeFieldName]: {$gt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2030-01-01")}]);
+runTest(false,
+ true,
+ {[timeFieldName]: {$gt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2040-01-01")}]);
+runTest(true,
+ false,
+ {[timeFieldName]: {$gt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2030-01-01")}]);
+runTest(true,
+ true,
+ {[timeFieldName]: {$gt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2040-01-01")}]);
+
+runTest(false, false, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1971-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")}
+]);
+runTest(false, true, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1971-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")}
+]);
+runTest(true, false, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1965-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")}
+]);
+runTest(true, true, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1965-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")}
+]);
+
+runTest(false, false, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2030-01-01")}
+]);
+runTest(false, true, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2040-01-01")}
+]);
+runTest(true, false, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2030-01-01")}
+]);
+runTest(true, true, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2040-01-01")}
+]);
+
+// Verify ranges that straddle the lower epoch work properly
+runTest(
+ true, false, {[timeFieldName]: {$gt: new Date("1920-01-01"), $lt: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1965-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ ]);
+
+runTest(
+ false, true, {[timeFieldName]: {$gt: new Date("1980-01-01"), $lt: new Date("2050-01-01")}}, [
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2040-01-01")},
+ ]);
+
+// TODO: SERVER-69952 Literals outside the epoch are currently compared to _id, generally,
+// so we cannot match against them. This will have to be fixed in a similar manner by determining
+// whether the compared dates can be outside the epoch range and not relying on _id in that case.
+//
+// The following scenarios fail:
+// runTest(
+// false, false, {[timeFieldName]: {$gt: new Date("1920-01-01"), $lt: new Date("1980-01-01")}}, [
+// {[timeFieldName]: new Date("1971-01-01")},
+// {[timeFieldName]: new Date("1975-01-01")},
+// ]);
+// runTest(
+// false, false, {[timeFieldName]: {$gt: new Date("1980-01-01"), $lt: new Date("2050-01-01")}},
+// [
+// {[timeFieldName]: new Date("1995-01-01")},
+// {[timeFieldName]: new Date("2030-01-01")},
+// ]);
+})();
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
index 9a333ca711f..16d0ec9517f 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
@@ -586,6 +586,27 @@ std::pair<BSONObj, bool> DocumentSourceInternalUnpackBucket::extractOrBuildProje
return {BSONObj{}, false};
}
+/**
+ * Makes a disjunction of the given predicates.
+ *
+ * - The result is non-null; it may be an OrMatchExpression with zero children.
+ * - Any trivially-false arguments are omitted.
+ * - If only one argument is nontrivial, returns that argument rather than adding an extra
+ * OrMatchExpression around it.
+ */
+std::unique_ptr<MatchExpression> makeOr(std::vector<std::unique_ptr<MatchExpression>> predicates) {
+ std::vector<std::unique_ptr<MatchExpression>> nontrivial;
+ for (auto&& p : predicates) {
+ if (!p->isTriviallyFalse())
+ nontrivial.push_back(std::move(p));
+ }
+
+ if (nontrivial.size() == 1)
+ return std::move(nontrivial[0]);
+
+ return std::make_unique<OrMatchExpression>(std::move(nontrivial));
+}
+
/*
* Creates a predicate that ensures that if there exists a subpath of matchExprPath such that the
* type of `control.min.subpath` is not the same as `control.max.subpath` then we will match that
@@ -700,120 +721,170 @@ std::unique_ptr<MatchExpression> createComparisonPredicate(
// For $eq, make both a $lte against 'control.min' and a $gte predicate against
// 'control.max'.
//
- // If the comparison is against the 'time' field, include a predicate against the _id
- // field which is converted to the maximum for the corresponding range of ObjectIds and
- // is adjusted by the max range for a bucket to approximate the max bucket value given
+ // If the comparison is against the 'time' field and we haven't stored a time outside of
+ // the 32 bit range, include a predicate against the _id field which is converted to
+ // the maximum for the corresponding range of ObjectIds and
// the min. Also include a predicate against the _id field which is converted to the
// minimum for the range of ObjectIds corresponding to the given date. In
- // addition, we include a {'control.min' : {$gte: 'time - bucketMaxSpanSeconds'}} and
- // a {'control.max' : {$lte: 'time + bucketMaxSpanSeconds'}} predicate which will be
- // helpful in reducing bounds for index scans on 'time' field and routing on mongos.
- return isTimeField
- ? makePredicate(
- MatchExprPredicate<InternalExprLTEMatchExpression>(minPath, matchExprData),
- MatchExprPredicate<InternalExprGTEMatchExpression>(minPath,
- minTime.firstElement()),
- MatchExprPredicate<InternalExprGTEMatchExpression>(maxPath, matchExprData),
- MatchExprPredicate<InternalExprLTEMatchExpression>(maxPath,
- maxTime.firstElement()),
- MatchExprPredicate<LTEMatchExpression, Value>(
- kBucketIdFieldName,
- constructObjectIdValue<LTEMatchExpression>(matchExprData,
- bucketMaxSpanSeconds)),
- MatchExprPredicate<GTEMatchExpression, Value>(
- kBucketIdFieldName,
- constructObjectIdValue<GTEMatchExpression>(matchExprData,
- bucketMaxSpanSeconds)))
- : std::make_unique<OrMatchExpression>(makeVector<std::unique_ptr<MatchExpression>>(
- makePredicate(MatchExprPredicate<InternalExprLTEMatchExpression>(
- minPath, matchExprData),
- MatchExprPredicate<InternalExprGTEMatchExpression>(
- maxPath, matchExprData)),
- createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ // addition, we include a {'control.min' : {$gte: 'time - bucketMaxSpanSeconds'}}
+ // predicate which will be helpful in reducing bounds for index scans on 'time' field
+ // and routing on mongos.
+ if (!isTimeField) {
+ return makeOr(makeVector<std::unique_ptr<MatchExpression>>(
+ makePredicate(
+ MatchExprPredicate<InternalExprLTEMatchExpression>(minPath, matchExprData),
+ MatchExprPredicate<InternalExprGTEMatchExpression>(maxPath, matchExprData)),
+ createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ } else if (bucketSpec.usesExtendedRange()) {
+ return makePredicate(
+ MatchExprPredicate<InternalExprLTEMatchExpression>(minPath, matchExprData),
+ MatchExprPredicate<InternalExprGTEMatchExpression>(minPath,
+ minTime.firstElement()),
+ MatchExprPredicate<InternalExprGTEMatchExpression>(maxPath, matchExprData),
+ MatchExprPredicate<InternalExprLTEMatchExpression>(maxPath,
+ maxTime.firstElement()));
+ } else {
+ return makePredicate(
+ MatchExprPredicate<InternalExprLTEMatchExpression>(minPath, matchExprData),
+ MatchExprPredicate<InternalExprGTEMatchExpression>(minPath,
+ minTime.firstElement()),
+ MatchExprPredicate<InternalExprGTEMatchExpression>(maxPath, matchExprData),
+ MatchExprPredicate<InternalExprLTEMatchExpression>(maxPath,
+ maxTime.firstElement()),
+ MatchExprPredicate<LTEMatchExpression, Value>(
+ kBucketIdFieldName,
+ constructObjectIdValue<LTEMatchExpression>(matchExprData,
+ bucketMaxSpanSeconds)),
+ MatchExprPredicate<GTEMatchExpression, Value>(
+ kBucketIdFieldName,
+ constructObjectIdValue<GTEMatchExpression>(matchExprData,
+ bucketMaxSpanSeconds)));
+ }
+ MONGO_UNREACHABLE_TASSERT(6646903);
case MatchExpression::GT:
// For $gt, make a $gt predicate against 'control.max'. In addition, if the comparison
- // is against the 'time' field, include a predicate against the _id field which is
- // converted to the maximum for the corresponding range of ObjectIds and is adjusted
- // by the max range for a bucket to approximate the max bucket value given the min. In
- // addition, we include a {'control.min' : {$gt: 'time - bucketMaxSpanSeconds'}}
+ // is against the 'time' field, and the collection doesn't contain times outside the
+ // 32 bit range, include a predicate against the _id field which is converted to the
+ // maximum for the corresponding range of ObjectIds and is adjusted by the max range
+ // for a bucket to approximate the max bucket value given the min.
+ //
+ // In addition, we include a {'control.min' : {$gt: 'time - bucketMaxSpanSeconds'}}
// predicate which will be helpful in reducing bounds for index scans on 'time' field
// and routing on mongos.
- return isTimeField
- ? makePredicate(
-
- MatchExprPredicate<InternalExprGTMatchExpression>(maxPath, matchExprData),
- MatchExprPredicate<InternalExprGTMatchExpression>(minPath,
- minTime.firstElement()),
- MatchExprPredicate<GTMatchExpression, Value>(
- kBucketIdFieldName,
- constructObjectIdValue<GTMatchExpression>(matchExprData,
- bucketMaxSpanSeconds)))
- : std::make_unique<OrMatchExpression>(makeVector<std::unique_ptr<MatchExpression>>(
- std::make_unique<InternalExprGTMatchExpression>(maxPath, matchExprData),
- createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ //
+ // The same procedure applies to aggregation expressions of the form
+ // {$expr: {$gt: [...]}} that can be rewritten to use $_internalExprGt.
+ if (!isTimeField) {
+ return makeOr(makeVector<std::unique_ptr<MatchExpression>>(
+ std::make_unique<InternalExprGTMatchExpression>(maxPath, matchExprData),
+ createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ } else if (bucketSpec.usesExtendedRange()) {
+ return makePredicate(
+ MatchExprPredicate<InternalExprGTMatchExpression>(maxPath, matchExprData),
+ MatchExprPredicate<InternalExprGTMatchExpression>(minPath,
+ minTime.firstElement()));
+ } else {
+ return makePredicate(
+ MatchExprPredicate<InternalExprGTMatchExpression>(maxPath, matchExprData),
+ MatchExprPredicate<InternalExprGTMatchExpression>(minPath,
+ minTime.firstElement()),
+ MatchExprPredicate<GTMatchExpression, Value>(
+ kBucketIdFieldName,
+ constructObjectIdValue<GTMatchExpression>(matchExprData,
+ bucketMaxSpanSeconds)));
+ }
+ MONGO_UNREACHABLE_TASSERT(6646904);
case MatchExpression::GTE:
// For $gte, make a $gte predicate against 'control.max'. In addition, if the comparison
- // is against the 'time' field, include a predicate against the _id field which is
+ // is against the 'time' field, and the collection doesn't contain times outside the
+ // 32 bit range, include a predicate against the _id field which is
// converted to the minimum for the corresponding range of ObjectIds and is adjusted
// by the max range for a bucket to approximate the max bucket value given the min. In
// addition, we include a {'control.min' : {$gte: 'time - bucketMaxSpanSeconds'}}
// predicate which will be helpful in reducing bounds for index scans on 'time' field
// and routing on mongos.
- return isTimeField
- ? makePredicate(
-
- MatchExprPredicate<InternalExprGTEMatchExpression>(maxPath, matchExprData),
- MatchExprPredicate<InternalExprGTEMatchExpression>(minPath,
- minTime.firstElement()),
- MatchExprPredicate<GTEMatchExpression, Value>(
- kBucketIdFieldName,
- constructObjectIdValue<GTEMatchExpression>(matchExprData,
- bucketMaxSpanSeconds)))
- : std::make_unique<OrMatchExpression>(makeVector<std::unique_ptr<MatchExpression>>(
- std::make_unique<InternalExprGTEMatchExpression>(maxPath, matchExprData),
- createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ if (!isTimeField) {
+ return makeOr(makeVector<std::unique_ptr<MatchExpression>>(
+ std::make_unique<InternalExprGTEMatchExpression>(maxPath, matchExprData),
+ createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ } else if (bucketSpec.usesExtendedRange()) {
+ return makePredicate(
+ MatchExprPredicate<InternalExprGTEMatchExpression>(maxPath, matchExprData),
+ MatchExprPredicate<InternalExprGTEMatchExpression>(minPath,
+ minTime.firstElement()));
+ } else {
+ return makePredicate(
+ MatchExprPredicate<InternalExprGTEMatchExpression>(maxPath, matchExprData),
+ MatchExprPredicate<InternalExprGTEMatchExpression>(minPath,
+ minTime.firstElement()),
+ MatchExprPredicate<GTEMatchExpression, Value>(
+ kBucketIdFieldName,
+ constructObjectIdValue<GTEMatchExpression>(matchExprData,
+ bucketMaxSpanSeconds)));
+ }
+ MONGO_UNREACHABLE_TASSERT(6646905);
case MatchExpression::LT:
// For $lt, make a $lt predicate against 'control.min'. In addition, if the comparison
// is against the 'time' field, include a predicate against the _id field which is
- // converted to the minimum for the corresponding range of ObjectIds. In
- // addition, we include a {'control.max' : {$lt: 'time + bucketMaxSpanSeconds'}}
+ // converted to the minimum for the corresponding range of ObjectIds, unless the
+ // collection contain extended range dates which won't fit int the 32 bits allocated
+ // for _id.
+ //
+ // In addition, we include a {'control.max' : {$lt: 'time + bucketMaxSpanSeconds'}}
// predicate which will be helpful in reducing bounds for index scans on 'time' field
// and routing on mongos.
- return isTimeField
- ? makePredicate(
- MatchExprPredicate<InternalExprLTMatchExpression>(minPath, matchExprData),
- MatchExprPredicate<InternalExprLTMatchExpression>(maxPath,
- maxTime.firstElement()),
- MatchExprPredicate<LTMatchExpression, Value>(
- kBucketIdFieldName,
- constructObjectIdValue<LTMatchExpression>(matchExprData,
- bucketMaxSpanSeconds)))
- : std::make_unique<OrMatchExpression>(makeVector<std::unique_ptr<MatchExpression>>(
- std::make_unique<InternalExprLTMatchExpression>(minPath, matchExprData),
- createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ if (!isTimeField) {
+ return makeOr(makeVector<std::unique_ptr<MatchExpression>>(
+ std::make_unique<InternalExprLTMatchExpression>(minPath, matchExprData),
+ createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ } else if (bucketSpec.usesExtendedRange()) {
+ return makePredicate(
+ MatchExprPredicate<InternalExprLTMatchExpression>(minPath, matchExprData),
+ MatchExprPredicate<InternalExprLTMatchExpression>(maxPath,
+ maxTime.firstElement()));
+ } else {
+ return makePredicate(
+ MatchExprPredicate<InternalExprLTMatchExpression>(minPath, matchExprData),
+ MatchExprPredicate<InternalExprLTMatchExpression>(maxPath,
+ maxTime.firstElement()),
+ MatchExprPredicate<LTMatchExpression, Value>(
+ kBucketIdFieldName,
+ constructObjectIdValue<LTMatchExpression>(matchExprData,
+ bucketMaxSpanSeconds)));
+ }
+ MONGO_UNREACHABLE_TASSERT(6646906);
case MatchExpression::LTE:
// For $lte, make a $lte predicate against 'control.min'. In addition, if the comparison
- // is against the 'time' field, include a predicate against the _id field which is
+ // is against the 'time' field, and the collection doesn't contain times outside the
+ // 32 bit range, include a predicate against the _id field which is
// converted to the maximum for the corresponding range of ObjectIds. In
// addition, we include a {'control.max' : {$lte: 'time + bucketMaxSpanSeconds'}}
// predicate which will be helpful in reducing bounds for index scans on 'time' field
// and routing on mongos.
- return isTimeField
- ? makePredicate(
- MatchExprPredicate<InternalExprLTEMatchExpression>(minPath, matchExprData),
- MatchExprPredicate<InternalExprLTEMatchExpression>(maxPath,
- maxTime.firstElement()),
- MatchExprPredicate<LTEMatchExpression, Value>(
- kBucketIdFieldName,
- constructObjectIdValue<LTEMatchExpression>(matchExprData,
- bucketMaxSpanSeconds)))
- : std::make_unique<OrMatchExpression>(makeVector<std::unique_ptr<MatchExpression>>(
- std::make_unique<InternalExprLTEMatchExpression>(minPath, matchExprData),
- createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ if (!isTimeField) {
+ return makeOr(makeVector<std::unique_ptr<MatchExpression>>(
+ std::make_unique<InternalExprLTEMatchExpression>(minPath, matchExprData),
+ createTypeEqualityPredicate(pExpCtx, matchExprPath)));
+ } else if (bucketSpec.usesExtendedRange()) {
+ return makePredicate(
+ MatchExprPredicate<InternalExprLTEMatchExpression>(minPath, matchExprData),
+ MatchExprPredicate<InternalExprLTEMatchExpression>(maxPath,
+ maxTime.firstElement()));
+ } else {
+ return makePredicate(
+ MatchExprPredicate<InternalExprLTEMatchExpression>(minPath, matchExprData),
+ MatchExprPredicate<InternalExprLTEMatchExpression>(maxPath,
+ maxTime.firstElement()),
+ MatchExprPredicate<LTEMatchExpression, Value>(
+ kBucketIdFieldName,
+ constructObjectIdValue<LTEMatchExpression>(matchExprData,
+ bucketMaxSpanSeconds)));
+ }
+ MONGO_UNREACHABLE_TASSERT(6646907);
default:
MONGO_UNREACHABLE_TASSERT(5348302);