diff options
author | Justin Seyster <justin.seyster@mongodb.com> | 2019-06-12 15:30:30 -0400 |
---|---|---|
committer | Justin Seyster <justin.seyster@mongodb.com> | 2019-07-01 14:49:54 -0400 |
commit | 52f4f202fee36d16873e3765f7b20ef5e798f711 (patch) | |
tree | 193f195a452ae95dbc15ce7a2cb8c2885c1b901b /src/mongo/db/pipeline/expression.cpp | |
parent | 6c5eea0e0757f912af7e43264bc1fbd581a480c0 (diff) | |
download | mongo-52f4f202fee36d16873e3765f7b20ef5e798f711.tar.gz |
SERVER-40383 Handle week, day edge cases in timelib_date_from_isodate
(cherry picked from commit d4843fc49931c7ce4332dc373623267c293eb518)
Diffstat (limited to 'src/mongo/db/pipeline/expression.cpp')
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index c1bf5957066..b965b86f244 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -1204,7 +1204,7 @@ Value ExpressionDateFromParts::serialize(bool explain) const { } bool ExpressionDateFromParts::evaluateNumberWithDefault(const Document& root, - intrusive_ptr<Expression> field, + const Expression* field, StringData fieldName, long long defaultValue, long long* returnValue, @@ -1232,14 +1232,39 @@ bool ExpressionDateFromParts::evaluateNumberWithDefault(const Document& root, return true; } +bool ExpressionDateFromParts::evaluateNumberWithDefaultAndBounds(const Document& root, + const Expression* field, + StringData fieldName, + long long defaultValue, + long long* returnValue, + Variables* variables) const { + bool result = + evaluateNumberWithDefault(root, field, fieldName, defaultValue, returnValue, variables); + + uassert(31034, + str::stream() << "'" << fieldName << "'" + << " must evaluate to a value in the range [" + << kMinValueForDatePart + << ", " + << kMaxValueForDatePart + << "]; value " + << *returnValue + << " is not in range", + !result || + (*returnValue >= kMinValueForDatePart && *returnValue <= kMaxValueForDatePart)); + + return result; +} + Value ExpressionDateFromParts::evaluate(const Document& root, Variables* variables) const { long long hour, minute, second, millisecond; - if (!evaluateNumberWithDefault(root, _hour, "hour"_sd, 0, &hour, variables) || - !evaluateNumberWithDefault(root, _minute, "minute"_sd, 0, &minute, variables) || - !evaluateNumberWithDefault(root, _second, "second"_sd, 0, &second, variables) || + if (!evaluateNumberWithDefaultAndBounds(root, _hour.get(), "hour"_sd, 0, &hour, variables) || + !evaluateNumberWithDefaultAndBounds( + root, _minute.get(), "minute"_sd, 0, &minute, variables) || + !evaluateNumberWithDefault(root, _second.get(), "second"_sd, 0, &second, variables) || !evaluateNumberWithDefault( - root, _millisecond, "millisecond"_sd, 0, &millisecond, variables)) { + root, _millisecond.get(), "millisecond"_sd, 0, &millisecond, variables)) { // One of the evaluated inputs in nullish. return Value(BSONNULL); } @@ -1254,9 +1279,10 @@ Value ExpressionDateFromParts::evaluate(const Document& root, Variables* variabl if (_year) { long long year, month, day; - if (!evaluateNumberWithDefault(root, _year, "year"_sd, 1970, &year, variables) || - !evaluateNumberWithDefault(root, _month, "month"_sd, 1, &month, variables) || - !evaluateNumberWithDefault(root, _day, "day"_sd, 1, &day, variables)) { + if (!evaluateNumberWithDefault(root, _year.get(), "year"_sd, 1970, &year, variables) || + !evaluateNumberWithDefaultAndBounds( + root, _month.get(), "month"_sd, 1, &month, variables) || + !evaluateNumberWithDefaultAndBounds(root, _day.get(), "day"_sd, 1, &day, variables)) { // One of the evaluated inputs in nullish. return Value(BSONNULL); } @@ -1276,14 +1302,23 @@ Value ExpressionDateFromParts::evaluate(const Document& root, Variables* variabl long long isoWeekYear, isoWeek, isoDayOfWeek; if (!evaluateNumberWithDefault( - root, _isoWeekYear, "isoWeekYear"_sd, 1970, &isoWeekYear, variables) || - !evaluateNumberWithDefault(root, _isoWeek, "isoWeek"_sd, 1, &isoWeek, variables) || - !evaluateNumberWithDefault( - root, _isoDayOfWeek, "isoDayOfWeek"_sd, 1, &isoDayOfWeek, variables)) { + root, _isoWeekYear.get(), "isoWeekYear"_sd, 1970, &isoWeekYear, variables) || + !evaluateNumberWithDefaultAndBounds( + root, _isoWeek.get(), "isoWeek"_sd, 1, &isoWeek, variables) || + !evaluateNumberWithDefaultAndBounds( + root, _isoDayOfWeek.get(), "isoDayOfWeek"_sd, 1, &isoDayOfWeek, variables)) { // One of the evaluated inputs in nullish. return Value(BSONNULL); } + uassert(31095, + str::stream() << "'isoWeekYear' must evaluate to an integer in the range " << 0 + << " to " + << 9999 + << ", found " + << isoWeekYear, + isoWeekYear >= 0 && isoWeekYear <= 9999); + return Value(timeZone->createFromIso8601DateParts( isoWeekYear, isoWeek, isoDayOfWeek, hour, minute, second, millisecond)); } |