-- This file and its contents are licensed under the Timescale License.
-- Please see the included NOTICE for copyright information and
-- LICENSE-TIMESCALE for a copy of the license.
\c :TEST_DBNAME :ROLE_SUPERUSER
CREATE OR REPLACE FUNCTION test.min_pg_timestamptz() RETURNS TIMESTAMPTZ
AS :MODULE_PATHNAME, 'ts_timestamptz_pg_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.end_pg_timestamptz() RETURNS TIMESTAMPTZ
AS :MODULE_PATHNAME, 'ts_timestamptz_pg_end' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.min_ts_timestamptz() RETURNS TIMESTAMPTZ
AS :MODULE_PATHNAME, 'ts_timestamptz_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.end_ts_timestamptz() RETURNS TIMESTAMPTZ
AS :MODULE_PATHNAME, 'ts_timestamptz_end' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.internal_min_ts_timestamptz() RETURNS BIGINT
AS :MODULE_PATHNAME, 'ts_timestamptz_internal_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.internal_end_ts_timestamptz() RETURNS BIGINT
AS :MODULE_PATHNAME, 'ts_timestamptz_internal_end' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.min_pg_timestamp() RETURNS TIMESTAMP
AS :MODULE_PATHNAME, 'ts_timestamp_pg_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.end_pg_timestamp() RETURNS TIMESTAMP
AS :MODULE_PATHNAME, 'ts_timestamp_pg_end' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.min_ts_timestamp() RETURNS TIMESTAMP
AS :MODULE_PATHNAME, 'ts_timestamp_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.end_ts_timestamp() RETURNS TIMESTAMP
AS :MODULE_PATHNAME, 'ts_timestamp_end' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.internal_min_ts_timestamp() RETURNS BIGINT
AS :MODULE_PATHNAME, 'ts_timestamp_internal_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.internal_end_ts_timestamp() RETURNS BIGINT
AS :MODULE_PATHNAME, 'ts_timestamp_internal_end' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.min_pg_date() RETURNS DATE
AS :MODULE_PATHNAME, 'ts_date_pg_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.end_pg_date() RETURNS DATE
AS :MODULE_PATHNAME, 'ts_date_pg_end' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.min_ts_date() RETURNS DATE
AS :MODULE_PATHNAME, 'ts_date_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.end_ts_date() RETURNS DATE
AS :MODULE_PATHNAME, 'ts_date_end' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.internal_min_ts_date() RETURNS BIGINT
AS :MODULE_PATHNAME, 'ts_date_internal_min' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION test.internal_end_ts_date() RETURNS BIGINT
AS :MODULE_PATHNAME, 'ts_date_internal_end' LANGUAGE C VOLATILE;
SET ROLE :ROLE_DEFAULT_PERM_USER;
--show PG and TimescaleDB-specific time boundaries. Note that we
--internally convert to UNIX epoch, which restricts the range of
--supported timestamps.
SET datestyle TO 'ISO,YMD';
\x
--To display end timestamps (which aren't valid timestamps), we need
--to be at UTC to avoid timezone conversion which would fail with
--out-of-range error. Being at UTC also makes it easier to compare
--TIMESTAMP and TIMESTAMP WITH TIME ZONE.
SET timezone TO 'UTC';
-- MIN values (PostgreSQL).
SELECT test.min_pg_timestamptz(),
       test.min_pg_timestamp(),
       test.min_pg_date();
-[ RECORD 1 ]------+--------------------------
min_pg_timestamptz | 4714-11-24 00:00:00+00 BC
min_pg_timestamp   | 4714-11-24 00:00:00 BC
min_pg_date        | 4714-11-24 BC

-- MIN values (TimescaleDB).
SELECT test.min_ts_timestamptz(),
       test.min_ts_timestamp(),
       test.min_ts_date(),
       _timescaledb_functions.to_timestamp(test.internal_min_ts_timestamptz()) AS min_ts_internal_timestamptz,
       _timescaledb_functions.to_timestamp_without_timezone(test.internal_min_ts_timestamp()) AS min_ts_internal_timestamp,
       _timescaledb_functions.to_date(test.internal_min_ts_date()) AS min_ts_internal_date;
-[ RECORD 1 ]---------------+--------------------------
min_ts_timestamptz          | 4714-11-24 00:00:00+00 BC
min_ts_timestamp            | 4714-11-24 00:00:00 BC
min_ts_date                 | 4714-11-24 BC
min_ts_internal_timestamptz | 4714-11-24 00:00:00+00 BC
min_ts_internal_timestamp   | 4714-11-24 00:00:00 BC
min_ts_internal_date        | 4714-11-24 BC

-- END values (PostgreSQL). Note that and values aren't valid
-- timestamps or dates (since, e.g., END_TIMESTAMP is exclusive). It
-- is possible to display them at UTC since no conversion is made.
SELECT test.end_pg_timestamptz(),
       test.end_pg_timestamp(),
       test.end_pg_date();
-[ RECORD 1 ]------+-------------------------
end_pg_timestamptz | 294277-01-01 00:00:00+00
end_pg_timestamp   | 294277-01-01 00:00:00
end_pg_date        | 5874898-01-01

-- END values (TimescaleDB). Note that we convert DATE to TIMESTAMP
-- internally, and that limits the end to that of timestamp.
SELECT test.end_ts_timestamptz(),
       test.end_ts_timestamp(),
       test.end_ts_date(),
       _timescaledb_functions.to_timestamp(test.internal_end_ts_timestamptz()) AS end_ts_internal_timestamptz,
       _timescaledb_functions.to_timestamp_without_timezone(test.internal_end_ts_timestamp()) AS end_ts_internal_timestamp,
       _timescaledb_functions.to_date(test.internal_end_ts_date()) AS end_ts_internal_date;
-[ RECORD 1 ]---------------+-------------------------
end_ts_timestamptz          | 294247-01-02 00:00:00+00
end_ts_timestamp            | 294247-01-02 00:00:00
end_ts_date                 | 294247-01-02
end_ts_internal_timestamptz | 294247-01-02 00:00:00+00
end_ts_internal_timestamp   | 294247-01-02 00:00:00
end_ts_internal_date        | 294247-01-02

--Test insert of time values close to or at limits
--Suitable constraints should be created on chunks
CREATE TABLE smallint_table(time smallint);
SELECT table_name FROM create_hypertable('smallint_table', 'time', chunk_time_interval=>10);
-[ RECORD 1 ]--------------
table_name | smallint_table

INSERT INTO smallint_table VALUES (-32768), (32767);
SELECT pg_get_constraintdef(c.oid)
FROM show_chunks('smallint_table') chunk, pg_constraint c
WHERE c.conrelid = chunk
AND c.contype = 'c' ORDER BY chunk;
-[ RECORD 1 ]--------+--------------------------------------
pg_get_constraintdef | CHECK (("time" < '-32760'::smallint))
-[ RECORD 2 ]--------+--------------------------------------
pg_get_constraintdef | CHECK (("time" >= '32760'::smallint))

CREATE TABLE int_table(time int);
SELECT table_name FROM create_hypertable('int_table', 'time', chunk_time_interval=>10);
-[ RECORD 1 ]---------
table_name | int_table

INSERT INTO int_table VALUES (-2147483648), (2147483647);
SELECT pg_get_constraintdef(c.oid)
FROM show_chunks('int_table') chunk, pg_constraint c
WHERE c.conrelid = chunk
AND c.contype = 'c' ORDER BY chunk;
-[ RECORD 1 ]--------+------------------------------------------
pg_get_constraintdef | CHECK (("time" < '-2147483640'::integer))
-[ RECORD 2 ]--------+------------------------------------------
pg_get_constraintdef | CHECK (("time" >= 2147483640))

CREATE TABLE bigint_table(time bigint);
SELECT table_name FROM create_hypertable('bigint_table', 'time', chunk_time_interval=>10);
-[ RECORD 1 ]------------
table_name | bigint_table

INSERT INTO bigint_table VALUES (-9223372036854775808), (9223372036854775807);
SELECT pg_get_constraintdef(c.oid)
FROM show_chunks('bigint_table') chunk, pg_constraint c
WHERE c.conrelid = chunk
AND c.contype = 'c' ORDER BY chunk;
-[ RECORD 1 ]--------+--------------------------------------------------
pg_get_constraintdef | CHECK (("time" < '-9223372036854775800'::bigint))
-[ RECORD 2 ]--------+--------------------------------------------------
pg_get_constraintdef | CHECK (("time" >= '9223372036854775800'::bigint))

CREATE TABLE date_table(time date);
SELECT table_name FROM create_hypertable('date_table', 'time');
-[ RECORD 1 ]----------
table_name | date_table

INSERT INTO date_table VALUES (test.min_ts_date()), (test.end_ts_date() - INTERVAL '1 day');
-- Test out-of-range dates
\set ON_ERROR_STOP 0
INSERT INTO date_table VALUES (test.min_ts_date() - INTERVAL '1 day');
ERROR:  timestamp out of range
INSERT INTO date_table VALUES (test.end_ts_date());
ERROR:  timestamp out of range
\set ON_ERROR_STOP 1
SELECT pg_get_constraintdef(c.oid)
FROM show_chunks('date_table') chunk, pg_constraint c
WHERE c.conrelid = chunk
AND c.contype = 'c' ORDER BY chunk;
-[ RECORD 1 ]--------+-----------------------------------------
pg_get_constraintdef | CHECK (("time" < '4714-11-27 BC'::date))
-[ RECORD 2 ]--------+-----------------------------------------
pg_get_constraintdef | CHECK (("time" >= '294246-12-31'::date))

CREATE TABLE timestamp_table(time timestamp);
SELECT table_name FROM create_hypertable('timestamp_table', 'time');
WARNING:  column type "timestamp without time zone" used for "time" does not follow best practices
-[ RECORD 1 ]---------------
table_name | timestamp_table

INSERT INTO timestamp_table VALUES (test.min_ts_timestamp());
INSERT INTO timestamp_table VALUES (test.end_ts_timestamp() - INTERVAL '1 microsecond');
-- Test out-of-range timestamps
\set ON_ERROR_STOP 0
INSERT INTO timestamp_table VALUES (test.min_ts_timestamp() - INTERVAL '1 microsecond');
ERROR:  timestamp out of range
INSERT INTO timestamp_table VALUES (test.end_ts_timestamp());
ERROR:  timestamp out of range
\set ON_ERROR_STOP 1
SELECT pg_get_constraintdef(c.oid)
FROM show_chunks('timestamp_table') chunk, pg_constraint c
WHERE c.conrelid = chunk
AND c.contype = 'c' ORDER BY chunk;
-[ RECORD 1 ]--------+-------------------------------------------------------------------------
pg_get_constraintdef | CHECK (("time" < '4714-11-27 00:00:00 BC'::timestamp without time zone))
-[ RECORD 2 ]--------+-------------------------------------------------------------------------
pg_get_constraintdef | CHECK (("time" >= '294246-12-31 00:00:00'::timestamp without time zone))

CREATE TABLE timestamptz_table(time timestamp);
SELECT table_name FROM create_hypertable('timestamptz_table', 'time');
WARNING:  column type "timestamp without time zone" used for "time" does not follow best practices
-[ RECORD 1 ]-----------------
table_name | timestamptz_table

-- Need to be at UTC for this to work for timestamp with time zone
INSERT INTO timestamptz_table VALUES (test.min_ts_timestamptz());
INSERT INTO timestamptz_table VALUES (test.end_ts_timestamptz() - INTERVAL '1 microsecond');
-- Test out-of-range timestamps
\set ON_ERROR_STOP 0
INSERT INTO timestamptz_table VALUES (test.min_ts_timestamptz() - INTERVAL '1 microsecond');
ERROR:  timestamp out of range
INSERT INTO timestamptz_table VALUES (test.end_ts_timestamptz());
ERROR:  timestamp out of range
\set ON_ERROR_STOP 1
SELECT pg_get_constraintdef(c.oid)
FROM show_chunks('timestamptz_table') chunk, pg_constraint c
WHERE c.conrelid = chunk
AND c.contype = 'c' ORDER BY chunk;
-[ RECORD 1 ]--------+-------------------------------------------------------------------------
pg_get_constraintdef | CHECK (("time" < '4714-11-27 00:00:00 BC'::timestamp without time zone))
-[ RECORD 2 ]--------+-------------------------------------------------------------------------
pg_get_constraintdef | CHECK (("time" >= '294246-12-31 00:00:00'::timestamp without time zone))

RESET datestyle;
RESET timezone;
