Reject timestamps below the minimum in time_bucket, epoch_ms and to_timestamp

This commit is contained in:
Robinho-MR committed 2026-10-15 10:04:51 +00:00
1 parent 0d55d51113
commit 65cdf0fa07
4 files changed
+57 -1

No files matched your search

@@ -12,7 +12,9 @@ struct EpochSecOperator {
template <class INPUT_TYPE, class RESULT_TYPE>
static RESULT_TYPE Operation(INPUT_TYPE sec) {
int64_t result;
if (!TryCast::Operation(sec * Interval::MICROS_PER_SEC, result)) {
// the first midnight of Timestamp::MIN_YEAR - smaller values are not valid timestamps
constexpr int64_t min_timestamp_micros = -9223372022400000000LL;
if (!TryCast::Operation(sec * Interval::MICROS_PER_SEC, result) || result < min_timestamp_micros) {
throw ConversionException("Epoch seconds out of range for TIMESTAMP WITH TIME ZONE");
}
return timestamp_t(result);
@@ -97,6 +97,9 @@ struct TimeBucket {
return (Date::ExtractYear(ts_date) - 1970) * 12 + Date::ExtractMonth(ts_date) - 1;
}
//! The first midnight of Timestamp::MIN_YEAR - smaller values are not valid timestamps
static constexpr int64_t MIN_TIMESTAMP_MICROS = -9223372022400000000LL;
static inline timestamp_t WidthConvertibleToMicrosCommon(int64_t bucket_width_micros, int64_t ts_micros,
int64_t origin_micros) {
origin_micros %= bucket_width_micros;
@@ -108,6 +111,9 @@ struct TimeBucket {
SubtractOperatorOverflowCheck::Operation<int64_t, int64_t, int64_t>(result_micros, bucket_width_micros);
}
result_micros = AddOperatorOverflowCheck::Operation<int64_t, int64_t, int64_t>(result_micros, origin_micros);
if (result_micros < MIN_TIMESTAMP_MICROS) {
throw OutOfRangeException("Overflow in TIME_BUCKET: the result is below the minimum TIMESTAMP");
}
return Timestamp::FromEpochMicroSeconds(result_micros);
}
+4
View File
@@ -450,6 +450,10 @@ timestamp_t Timestamp::FromEpochMsPossiblyInfinite(int64_t ms) {
if (!TryMultiplyOperator::Operation(ms, Interval::MICROS_PER_MSEC, result)) {
throw ConversionException("Could not convert Timestamp(MS) to Timestamp(US)");
}
// the first midnight of Timestamp::MIN_YEAR - smaller values are not valid timestamps
if (result < -9223372022400000000LL) {
throw ConversionException("Could not convert Timestamp(MS) to Timestamp(US)");
}
return timestamp_t(result);
}
@@ -0,0 +1,44 @@
# name: test/sql/function/timestamp/test_timestamp_lower_bound.test
# description: Timestamp constructors reject values below the minimum timestamp
# group: [timestamp]
statement error
SELECT time_bucket(INTERVAL '1 hour', TIMESTAMP '290309-12-22 (BC) 00:00:00', TIMESTAMP '2000-01-01 00:00:01')
----
Overflow in TIME_BUCKET
statement error
SELECT epoch_ms(-9223372022400001)
----
<REGEX>:.*(Out of Range|Conversion) Error.*
statement error
SELECT make_timestamp_ms(-9223372022400001)
----
<REGEX>:.*(Out of Range|Conversion) Error.*
statement error
SELECT to_timestamp(-9223372022401)
----
<REGEX>:.*(Out of Range|Conversion) Error.*
statement error
SELECT to_timestamp(-9223372036854.775808)
----
<REGEX>:.*(Out of Range|Conversion) Error.*
# the minimum timestamp is still accepted
query I
SELECT epoch_ms(-9223372022400000)::VARCHAR
----
290309-12-22 (BC) 00:00:00
query I
SELECT to_timestamp(-9223372022400)::VARCHAR
----
290309-12-22 (BC) 00:00:00+00
query I
SELECT time_bucket(INTERVAL '1 hour', TIMESTAMP '2020-01-01 10:30:00', TIMESTAMP '2000-01-01 00:00:01')::VARCHAR
----
2020-01-01 10:00:01