mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-17 02:53:51 +08:00
Add support for infinite timestamps
The internal conversion functions for timestamps didn't account for timestamps that are infinite (`-Infinity` or `+Infinity`), and they would therefore generate an error if such timestamps were encountered. This change adds extra checks to the conversion functions to allow infinite timestamps.
This commit is contained in:
parent
418f283443
commit
e1c94484cf
25
src/utils.c
25
src/utils.c
@ -45,6 +45,12 @@ ts_pg_timestamp_to_unix_microseconds(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
|
||||
|
||||
if (TIMESTAMP_IS_NOBEGIN(timestamp))
|
||||
PG_RETURN_INT64(PG_INT64_MIN);
|
||||
|
||||
if (TIMESTAMP_IS_NOEND(timestamp))
|
||||
PG_RETURN_INT64(PG_INT64_MAX);
|
||||
|
||||
if (timestamp < MIN_TIMESTAMP)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range")));
|
||||
@ -68,10 +74,16 @@ ts_pg_unix_microseconds_to_timestamp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int64 microseconds = PG_GETARG_INT64(0);
|
||||
|
||||
if (microseconds == PG_INT64_MIN)
|
||||
PG_RETURN_TIMESTAMPTZ(DT_NOBEGIN);
|
||||
|
||||
if (microseconds == PG_INT64_MAX)
|
||||
PG_RETURN_TIMESTAMPTZ(DT_NOEND);
|
||||
|
||||
/*
|
||||
* Test that the UNIX us timestamp is within bounds. Note that an int64 at
|
||||
* UNIX epoch and microsecond precision cannot represent the upper limit
|
||||
* of the supported date range (Julian end date), so INT64_MAX is the
|
||||
* of the supported date range (Julian end date), so INT64_MAX-1 is the
|
||||
* natural upper bound for this function.
|
||||
*/
|
||||
if (microseconds < TS_INTERNAL_TIMESTAMP_MIN)
|
||||
@ -85,8 +97,15 @@ Datum
|
||||
ts_pg_unix_microseconds_to_date(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int64 microseconds = PG_GETARG_INT64(0);
|
||||
Datum res =
|
||||
DirectFunctionCall1(ts_pg_unix_microseconds_to_timestamp, Int64GetDatum(microseconds));
|
||||
Datum res;
|
||||
|
||||
if (microseconds == PG_INT64_MIN)
|
||||
PG_RETURN_DATEADT(DATEVAL_NOBEGIN);
|
||||
|
||||
if (microseconds == PG_INT64_MAX)
|
||||
PG_RETURN_DATEADT(DATEVAL_NOEND);
|
||||
|
||||
res = DirectFunctionCall1(ts_pg_unix_microseconds_to_timestamp, Int64GetDatum(microseconds));
|
||||
res = DirectFunctionCall1(timestamp_date, res);
|
||||
PG_RETURN_DATUM(res);
|
||||
}
|
||||
|
@ -157,15 +157,38 @@ SELECT _timescaledb_internal.to_unix_microseconds('2017-02-07 15:09:36.236538+00
|
||||
1486480176236538
|
||||
(1 row)
|
||||
|
||||
-- In UNIX microseconds, BIGINT MAX is smaller than internal date upper bound
|
||||
-- and should therefore be OK. Further, converting to the internal postgres
|
||||
-- epoch cannot overflow a 64-bit INTEGER since the postgres epoch is at a
|
||||
-- later date compared to the UNIX epoch, and is therefore represented by a
|
||||
-- smaller number
|
||||
-- For timestamps, BIGINT MAX represents +Infinity and BIGINT MIN
|
||||
-- -Infinity. We keep this notion for UNIX epoch time:
|
||||
SELECT _timescaledb_internal.to_unix_microseconds('+infinity');
|
||||
ERROR: invalid input syntax for type timestamp with time zone: "+infinity" at character 51
|
||||
SELECT _timescaledb_internal.to_timestamp(9223372036854775807);
|
||||
to_timestamp
|
||||
--------------
|
||||
infinity
|
||||
(1 row)
|
||||
|
||||
SELECT _timescaledb_internal.to_unix_microseconds('-infinity');
|
||||
to_unix_microseconds
|
||||
----------------------
|
||||
-9223372036854775808
|
||||
(1 row)
|
||||
|
||||
SELECT _timescaledb_internal.to_timestamp(-9223372036854775808);
|
||||
to_timestamp
|
||||
--------------
|
||||
-infinity
|
||||
(1 row)
|
||||
|
||||
-- In UNIX microseconds, the largest bigint value below infinity
|
||||
-- (BIGINT MAX) is smaller than internal date upper bound and should
|
||||
-- therefore be OK. Further, converting to the internal postgres epoch
|
||||
-- cannot overflow a 64-bit INTEGER since the postgres epoch is at a
|
||||
-- later date compared to the UNIX epoch, and is therefore represented
|
||||
-- by a smaller number
|
||||
SELECT _timescaledb_internal.to_timestamp(9223372036854775806);
|
||||
to_timestamp
|
||||
---------------------------------------
|
||||
Sun Jan 10 04:00:54.775807 294247 UTC
|
||||
Sun Jan 10 04:00:54.775806 294247 UTC
|
||||
(1 row)
|
||||
|
||||
-- Julian day zero is -210866803200000000 microseconds from UNIX epoch
|
||||
|
@ -100,12 +100,20 @@ SELECT _timescaledb_internal.to_timestamp(1486480176236538);
|
||||
-- Should be the inverse of the statement above.
|
||||
SELECT _timescaledb_internal.to_unix_microseconds('2017-02-07 15:09:36.236538+00');
|
||||
|
||||
-- In UNIX microseconds, BIGINT MAX is smaller than internal date upper bound
|
||||
-- and should therefore be OK. Further, converting to the internal postgres
|
||||
-- epoch cannot overflow a 64-bit INTEGER since the postgres epoch is at a
|
||||
-- later date compared to the UNIX epoch, and is therefore represented by a
|
||||
-- smaller number
|
||||
-- For timestamps, BIGINT MAX represents +Infinity and BIGINT MIN
|
||||
-- -Infinity. We keep this notion for UNIX epoch time:
|
||||
SELECT _timescaledb_internal.to_unix_microseconds('+infinity');
|
||||
SELECT _timescaledb_internal.to_timestamp(9223372036854775807);
|
||||
SELECT _timescaledb_internal.to_unix_microseconds('-infinity');
|
||||
SELECT _timescaledb_internal.to_timestamp(-9223372036854775808);
|
||||
|
||||
-- In UNIX microseconds, the largest bigint value below infinity
|
||||
-- (BIGINT MAX) is smaller than internal date upper bound and should
|
||||
-- therefore be OK. Further, converting to the internal postgres epoch
|
||||
-- cannot overflow a 64-bit INTEGER since the postgres epoch is at a
|
||||
-- later date compared to the UNIX epoch, and is therefore represented
|
||||
-- by a smaller number
|
||||
SELECT _timescaledb_internal.to_timestamp(9223372036854775806);
|
||||
|
||||
-- Julian day zero is -210866803200000000 microseconds from UNIX epoch
|
||||
SELECT _timescaledb_internal.to_timestamp(-210866803200000000);
|
||||
|
@ -111,7 +111,10 @@ ts_test_time_to_internal_conversion(PG_FUNCTION_ARGS)
|
||||
ts_time_value_to_internal(ts_internal_to_time_value(i64, TIMESTAMPOID),
|
||||
TIMESTAMPOID));
|
||||
|
||||
TestEnsureError(ts_internal_to_time_value(PG_INT64_MIN, TIMESTAMPOID));
|
||||
TestAssertInt64Eq(PG_INT64_MIN, ts_time_value_to_internal(DT_NOBEGIN, TIMESTAMPOID));
|
||||
TestAssertInt64Eq(PG_INT64_MAX, ts_time_value_to_internal(DT_NOEND, TIMESTAMPOID));
|
||||
|
||||
TestAssertInt64Eq(DT_NOBEGIN, ts_internal_to_time_value(PG_INT64_MIN, TIMESTAMPOID));
|
||||
TestEnsureError(ts_internal_to_time_value(TS_INTERNAL_TIMESTAMP_MIN - 1, TIMESTAMPOID));
|
||||
|
||||
TestAssertInt64Eq(TS_INTERNAL_TIMESTAMP_MIN,
|
||||
@ -119,10 +122,10 @@ ts_test_time_to_internal_conversion(PG_FUNCTION_ARGS)
|
||||
TIMESTAMPOID),
|
||||
TIMESTAMPOID));
|
||||
|
||||
TestAssertInt64Eq(PG_INT64_MAX - TS_EPOCH_DIFF_MICROSECONDS,
|
||||
DatumGetInt64(ts_internal_to_time_value(PG_INT64_MAX, TIMESTAMPOID)));
|
||||
TestEnsureError(ts_time_value_to_internal(ts_internal_to_time_value(PG_INT64_MAX, TIMESTAMPOID),
|
||||
TIMESTAMPOID));
|
||||
TestAssertInt64Eq(DT_NOEND,
|
||||
(ts_time_value_to_internal(ts_internal_to_time_value(PG_INT64_MAX,
|
||||
TIMESTAMPOID),
|
||||
TIMESTAMPOID)));
|
||||
|
||||
/* TIMESTAMPTZ */
|
||||
for (i64 = -100; i64 < 100; i64++)
|
||||
@ -140,7 +143,10 @@ ts_test_time_to_internal_conversion(PG_FUNCTION_ARGS)
|
||||
ts_time_value_to_internal(ts_internal_to_time_value(i64, TIMESTAMPTZOID),
|
||||
TIMESTAMPTZOID));
|
||||
|
||||
TestEnsureError(ts_internal_to_time_value(PG_INT64_MIN, TIMESTAMPTZOID));
|
||||
TestAssertInt64Eq(PG_INT64_MIN, ts_time_value_to_internal(DT_NOBEGIN, TIMESTAMPTZOID));
|
||||
TestAssertInt64Eq(PG_INT64_MAX, ts_time_value_to_internal(DT_NOEND, TIMESTAMPTZOID));
|
||||
|
||||
TestAssertInt64Eq(DT_NOBEGIN, ts_internal_to_time_value(PG_INT64_MIN, TIMESTAMPTZOID));
|
||||
TestEnsureError(ts_internal_to_time_value(TS_INTERNAL_TIMESTAMP_MIN - 1, TIMESTAMPTZOID));
|
||||
|
||||
TestAssertInt64Eq(TS_INTERNAL_TIMESTAMP_MIN,
|
||||
@ -148,21 +154,19 @@ ts_test_time_to_internal_conversion(PG_FUNCTION_ARGS)
|
||||
TIMESTAMPTZOID),
|
||||
TIMESTAMPTZOID));
|
||||
|
||||
TestAssertInt64Eq(PG_INT64_MAX - TS_EPOCH_DIFF_MICROSECONDS,
|
||||
DatumGetInt64(ts_internal_to_time_value(PG_INT64_MAX, TIMESTAMPTZOID)));
|
||||
TestEnsureError(
|
||||
ts_time_value_to_internal(ts_internal_to_time_value(PG_INT64_MAX, TIMESTAMPTZOID),
|
||||
TIMESTAMPTZOID));
|
||||
TestAssertInt64Eq(DT_NOEND,
|
||||
ts_time_value_to_internal(ts_internal_to_time_value(PG_INT64_MAX,
|
||||
TIMESTAMPTZOID),
|
||||
TIMESTAMPTZOID));
|
||||
|
||||
/* DATE */
|
||||
|
||||
for (i64 = -100 * USECS_PER_DAY; i64 < 100 * USECS_PER_DAY; i64 += USECS_PER_DAY)
|
||||
TestAssertInt64Eq(i64,
|
||||
ts_time_value_to_internal(ts_internal_to_time_value(i64, DATEOID),
|
||||
DATEOID));
|
||||
|
||||
TestEnsureError(ts_internal_to_time_value(PG_INT64_MIN, DATEOID));
|
||||
TestAssertInt64Eq(106741034, DatumGetDateADT(ts_internal_to_time_value(PG_INT64_MAX, DATEOID)));
|
||||
|
||||
TestAssertInt64Eq(DATEVAL_NOBEGIN, ts_internal_to_time_value(PG_INT64_MIN, DATEOID));
|
||||
TestAssertInt64Eq(DATEVAL_NOEND, ts_internal_to_time_value(PG_INT64_MAX, DATEOID));
|
||||
TestEnsureError(ts_time_value_to_internal((DATEVAL_NOBEGIN + 1), DATEOID));
|
||||
TestEnsureError(ts_time_value_to_internal((DATEVAL_NOEND - 1), DATEOID));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user