diff --git a/include/pgduckdb/pgduckdb_types.hpp b/include/pgduckdb/pgduckdb_types.hpp index ebc7622..09b2dca 100644 --- a/include/pgduckdb/pgduckdb_types.hpp +++ b/include/pgduckdb/pgduckdb_types.hpp @@ -15,6 +15,21 @@ constexpr int32_t PGDUCKDB_DUCK_DATE_OFFSET = 10957; constexpr int64_t PGDUCKDB_DUCK_TIMESTAMP_OFFSET = static_cast(PGDUCKDB_DUCK_DATE_OFFSET) * static_cast(86400000000) /* USECS_PER_DAY */; +// Check from regress/sql/date.sql +#define PG_MINYEAR (-4713) +#define PG_MINMONTH (11) +#define PG_MINDAY (24) +#define PG_MAXYEAR (5874897) +#define PG_MAXMONTH (12) +#define PG_MAXDAY (31) + +const duckdb::date_t PGDUCKDB_PG_MIN_DATE_VALUE = duckdb::Date::FromDate(PG_MINYEAR, PG_MINMONTH, PG_MINDAY); +const duckdb::date_t PGDUCKDB_PG_MAX_DATE_VALUE = duckdb::Date::FromDate(PG_MAXYEAR, PG_MAXMONTH, PG_MAXDAY); + +// Check ValidTimestampOrTimestampTz() for the logic, These values are counted from 1/1/1970 +constexpr int64_t PGDUCKDB_MAX_TIMESTAMP_VALUE = 9223371244800000000; +constexpr int64_t PGDUCKDB_MIN_TIMESTAMP_VALUE = -210866803200000000; + duckdb::LogicalType ConvertPostgresToDuckColumnType(Form_pg_attribute &attribute); Oid GetPostgresDuckDBType(const duckdb::LogicalType &type); int32_t GetPostgresDuckDBTypemod(const duckdb::LogicalType &type); diff --git a/src/pgduckdb_types.cpp b/src/pgduckdb_types.cpp index a5522ca..6a1a6dc 100644 --- a/src/pgduckdb_types.cpp +++ b/src/pgduckdb_types.cpp @@ -156,6 +156,25 @@ struct DecimalConversionDouble { } }; +static inline bool +ValidDate(duckdb::date_t dt) { + if ((dt < pgduckdb::PGDUCKDB_PG_MIN_DATE_VALUE || dt > pgduckdb::PGDUCKDB_PG_MAX_DATE_VALUE) && + !(dt == duckdb::date_t::infinity() || dt == duckdb::date_t::ninfinity())) + return false; + return true; +} + +static inline bool +ValidTimestampOrTimestampTz(int64_t timestamp) { + // PG TIMESTAMP RANGE = 4714-11-24 00:00:00 (BC) <-> 294276-12-31 23:59:59 + // DUCK TIMESTAMP RANGE = 290308-12-22 00:00:00 (BC) <-> 294247-01-10 04:00:54 + // Taking Intersection of the ranges + // MIN TIMESTAMP = 4714-11-24 00:00:00 (BC) + // MAX TIMESTAMP = 294246-12-31 23:59:59 , To keep it capped to a specific year.. also coincidently this is EXACTLY + // 30 years less than PG max value. + return timestamp >= pgduckdb::PGDUCKDB_MIN_TIMESTAMP_VALUE && timestamp < pgduckdb::PGDUCKDB_MAX_TIMESTAMP_VALUE; +} + static inline Datum ConvertBoolDatum(const duckdb::Value &value) { return value.GetValue(); @@ -216,6 +235,20 @@ ConvertBinaryDatum(const duckdb::Value &value) { inline Datum ConvertDateDatum(const duckdb::Value &value) { duckdb::date_t date = value.GetValue(); + if (!ValidDate(date)) + throw duckdb::OutOfRangeException("The value should be between min and max value (%s <-> %s)", + duckdb::Date::ToString(pgduckdb::PGDUCKDB_PG_MIN_DATE_VALUE), + duckdb::Date::ToString(pgduckdb::PGDUCKDB_PG_MAX_DATE_VALUE)); + + // Special Handling for +/-infinity date values + if (!duckdb::Date::IsFinite(date)) { + // -infinity value is different for PG date + if (date == duckdb::date_t::ninfinity()) + return date.days - 1; + else + return date.days; + } + return date.days - pgduckdb::PGDUCKDB_DUCK_DATE_OFFSET; } @@ -255,6 +288,14 @@ ConvertTimestampDatum(const duckdb::Value &value) { // Extract raw int64_t value of timestamp int64_t rawValue = value.GetValue(); + // Early Return for +/-Inf + if (!duckdb::Timestamp::IsFinite(static_cast(rawValue))) { + if (rawValue == static_cast(duckdb::timestamp_t::ninfinity())) + return Int64GetDatum(rawValue - 1); + else + return Int64GetDatum(rawValue); + } + // Handle specific Timestamp unit(sec, ms, ns) types switch (value.type().id()) { case duckdb::LogicalType::TIMESTAMP_MS: @@ -273,7 +314,36 @@ ConvertTimestampDatum(const duckdb::Value &value) { // Since we don't want to handle anything here break; } - return rawValue - pgduckdb::PGDUCKDB_DUCK_TIMESTAMP_OFFSET; + + if (!ValidTimestampOrTimestampTz(rawValue)) + throw duckdb::OutOfRangeException( + "The Timestamp value should be between min and max value (%s <-> %s)", + duckdb::Timestamp::ToString(static_cast(PGDUCKDB_MIN_TIMESTAMP_VALUE)), + duckdb::Timestamp::ToString(static_cast(PGDUCKDB_MAX_TIMESTAMP_VALUE))); + + return Int64GetDatum(rawValue - pgduckdb::PGDUCKDB_DUCK_TIMESTAMP_OFFSET); +} + +inline Datum +ConvertTimestampTzDatum(const duckdb::Value &value) { + duckdb::timestamp_tz_t timestamp = value.GetValue(); + int64_t rawValue = timestamp.value; + + // Early Return for +/-Inf + if (!duckdb::Timestamp::IsFinite(static_cast(rawValue))) { + if (rawValue == static_cast(duckdb::timestamp_t::ninfinity())) + return Int64GetDatum(rawValue - 1); + else + return Int64GetDatum(rawValue); + } + + if (!ValidTimestampOrTimestampTz(rawValue)) + throw duckdb::OutOfRangeException( + "The TimestampTz value should be between min and max value (%s <-> %s)", + duckdb::Timestamp::ToString(static_cast(PGDUCKDB_MIN_TIMESTAMP_VALUE)), + duckdb::Timestamp::ToString(static_cast(PGDUCKDB_MAX_TIMESTAMP_VALUE))); + + return Int64GetDatum(rawValue - pgduckdb::PGDUCKDB_DUCK_TIMESTAMP_OFFSET); } inline Datum @@ -876,8 +946,7 @@ ConvertDuckToPostgresValue(TupleTableSlot *slot, duckdb::Value &value, idx_t col break; } case TIMESTAMPTZOID: { - duckdb::timestamp_tz_t timestamp = value.GetValue(); - slot->tts_values[col] = timestamp.value - pgduckdb::PGDUCKDB_DUCK_TIMESTAMP_OFFSET; + slot->tts_values[col] = ConvertTimestampTzDatum(value); break; } case INTERVALOID: { @@ -1278,6 +1347,75 @@ AppendJsonb(duckdb::Vector &result, Datum value, idx_t offset) { data[offset] = duckdb::StringVector::AddString(result, str); } +static void +AppendDate(duckdb::Vector &result, Datum value, idx_t offset) { + auto date = DatumGetDateADT(value); + bool is_inf_val = false; + if (date == DATEVAL_NOBEGIN) { + is_inf_val = true; + // -infinity value is different between PG and duck + date += 1; + } + if (date == DATEVAL_NOEND) + is_inf_val = true; + + if (is_inf_val) { + Append(result, duckdb::date_t(static_cast(date)), offset); + } else + Append(result, duckdb::date_t(static_cast(date + PGDUCKDB_DUCK_DATE_OFFSET)), offset); +} + +static void +AppendTimestamp(duckdb::Vector &result, Datum value, idx_t offset) { + int64_t timestamp = static_cast(DatumGetTimestamp(value)); + bool is_inf_val = false; + if (timestamp == TIMESTAMP_MINUS_INFINITY) { + is_inf_val = true; + // -infinity value is different between PG and duck + timestamp += 1; + } + if (timestamp == TIMESTAMP_INFINITY) + is_inf_val = true; + + // Bounds Check + if (!is_inf_val && !ValidTimestampOrTimestampTz(timestamp + PGDUCKDB_DUCK_TIMESTAMP_OFFSET)) + throw duckdb::OutOfRangeException( + "The Timestamp value should be between min and max value (%s <-> %s)", + duckdb::Timestamp::ToString(static_cast(PGDUCKDB_MIN_TIMESTAMP_VALUE)), + duckdb::Timestamp::ToString(static_cast(PGDUCKDB_MAX_TIMESTAMP_VALUE))); + + if (is_inf_val) { + Append(result, duckdb::timestamp_t(timestamp), offset); + } else + Append(result, duckdb::timestamp_t(timestamp + PGDUCKDB_DUCK_TIMESTAMP_OFFSET), offset); +} + +static void +AppendTimestampTz(duckdb::Vector &result, Datum value, idx_t offset) { + int64_t timestamp = static_cast(DatumGetTimestamp(value)); + bool is_inf_val = false; + if (timestamp == TIMESTAMP_MINUS_INFINITY) { + is_inf_val = true; + // -infinity value is different between PG and duck + timestamp += 1; + } + if (timestamp == TIMESTAMP_INFINITY) + is_inf_val = true; + + // Bounds Check + if (!is_inf_val && !ValidTimestampOrTimestampTz(timestamp + PGDUCKDB_DUCK_TIMESTAMP_OFFSET)) + throw duckdb::OutOfRangeException( + "The TimestampTz value should be between min and max value (%s <-> %s)", + duckdb::Timestamp::ToString(static_cast(PGDUCKDB_MIN_TIMESTAMP_VALUE)), + duckdb::Timestamp::ToString(static_cast(PGDUCKDB_MAX_TIMESTAMP_VALUE))); + + if (is_inf_val) { + Append(result, duckdb::timestamp_tz_t(timestamp), offset); + } else + Append(result, duckdb::timestamp_tz_t(timestamp + PGDUCKDB_DUCK_TIMESTAMP_OFFSET), + offset); +} + template T ConvertDecimal(const NumericVar &numeric) { @@ -1434,19 +1572,17 @@ ConvertPostgresToDuckValue(Oid attr_type, Datum value, duckdb::Vector &result, i break; } case duckdb::LogicalTypeId::DATE: - Append(result, duckdb::date_t(static_cast(value + PGDUCKDB_DUCK_DATE_OFFSET)), offset); + AppendDate(result, value, offset); break; case duckdb::LogicalTypeId::TIMESTAMP_SEC: case duckdb::LogicalTypeId::TIMESTAMP_MS: case duckdb::LogicalTypeId::TIMESTAMP_NS: case duckdb::LogicalTypeId::TIMESTAMP: - Append( - result, duckdb::timestamp_t(static_cast(value + PGDUCKDB_DUCK_TIMESTAMP_OFFSET)), offset); + AppendTimestamp(result, value, offset); break; case duckdb::LogicalTypeId::TIMESTAMP_TZ: - Append( - result, duckdb::timestamp_tz_t(static_cast(value + PGDUCKDB_DUCK_TIMESTAMP_OFFSET)), offset); + AppendTimestampTz(result, value, offset); // Timestamp and Timestamptz are basically same in PG break; case duckdb::LogicalTypeId::INTERVAL: Append(result, DatumGetInterval(value), offset); @@ -1645,5 +1781,4 @@ FromNumeric(Numeric num) { dest.buf = NULL; /* digits array is not palloc'd */ return dest; } - } // namespace pgduckdb diff --git a/test/regression/expected/date.out b/test/regression/expected/date.out new file mode 100644 index 0000000..44e7600 --- /dev/null +++ b/test/regression/expected/date.out @@ -0,0 +1,54 @@ +-- Test +/- inf values +CREATE TABLE t(a DATE); +INSERT INTO t VALUES('Infinity'), ('-Infinity'); +-- PG Execution +SELECT * from t; + a +----------- + infinity + -infinity +(2 rows) + +SELECT isfinite(a) FROM t; + isfinite +---------- + f + f +(2 rows) + +set duckdb.force_execution = true; +-- DuckDB execution +SELECT * from t; + a +----------- + infinity + -infinity +(2 rows) + +SELECT isfinite(a) FROM t; + isfinite +---------- + f + f +(2 rows) + +-- Cleanup +set duckdb.force_execution = false; +DROP TABLE t; +-- Check upper and lower limits of date range +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC)'::date as date $$); + date +--------------- + 11-24-4714 BC +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC)'::date as date $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The value should be between min and max value (4714-11-24 (BC) <-> 5874897-12-31) +SELECT * FROM duckdb.query($$ SELECT '5874897-12-31'::date as date $$); + date +--------------- + 12-31-5874897 +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '5874898-01-01'::date as date $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The value should be between min and max value (4714-11-24 (BC) <-> 5874897-12-31) diff --git a/test/regression/expected/test_all_types.out b/test/regression/expected/test_all_types.out index 1fb26b2..42cfca1 100644 --- a/test/regression/expected/test_all_types.out +++ b/test/regression/expected/test_all_types.out @@ -23,6 +23,12 @@ SELECT * exclude( fixed_array_of_int_list, list_of_fixed_int_array, nested_int_array, -- The nested array has different lengths, which is not possible in PG + date, + timestamp, + timestamp_s, + timestamp_ms, + timestamp_ns, + timestamp_tz ) $$) -[ RECORD 1 ]---+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -37,14 +43,8 @@ usmallint | 0 uint | 0 ubigint | 0 varint | -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368 -date | 07-14-5881580 time | 00:00:00 -timestamp | Sun Jan 10 08:01:49.551616 294247 -timestamp_s | Sun Jan 10 08:01:49.551616 294247 -timestamp_ms | Sun Jan 10 08:01:49.551616 294247 -timestamp_ns | Wed Sep 22 00:00:00 1677 time_tz | 00:00:00+15:59:59 -timestamp_tz | Sun Jan 10 00:01:49.551616 294247 PST float | -3.4028235e+38 double | -1.7976931348623157e+308 dec_4_1 | -999.9 @@ -72,14 +72,8 @@ usmallint | 65535 uint | 4294967295 ubigint | 18446744073709551615 varint | 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368 -date | 07-10-5881580 time | 24:00:00 -timestamp | Sun Jan 10 04:00:54.775806 294247 -timestamp_s | Sun Jan 10 04:00:54 294247 -timestamp_ms | Sun Jan 10 04:00:54.775 294247 -timestamp_ns | Fri Apr 11 23:47:16.854775 2262 time_tz | 24:00:00-15:59:59 -timestamp_tz | Sat Jan 09 20:00:54.775806 294247 PST float | 3.4028235e+38 double | 1.7976931348623157e+308 dec_4_1 | 999.9 @@ -92,8 +86,8 @@ varchar | goo blob | \000\000\000a int_array | {42,999,NULL,NULL,-42} double_array | {42,NaN,Infinity,-Infinity,NULL,-42} -date_array | {01-01-1970,07-11-5881580,07-13-5881580,NULL,05-12-2022} -timestamp_array | {"Thu Jan 01 00:00:00 1970","Sun Jan 10 04:00:54.775807 294247","Sun Jan 10 04:00:54.775809 294247",NULL,"Thu May 12 16:23:45 2022"} +date_array | {01-01-1970,infinity,-infinity,NULL,05-12-2022} +timestamp_array | {"Thu Jan 01 00:00:00 1970",infinity,-infinity,NULL,"Thu May 12 16:23:45 2022"} varchar_array | {🦆🦆🦆🦆🦆🦆,goose,NULL,""} -[ RECORD 3 ]---+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bool | @@ -107,14 +101,8 @@ usmallint | uint | ubigint | varint | -date | time | -timestamp | -timestamp_s | -timestamp_ms | -timestamp_ns | time_tz | -timestamp_tz | float | double | dec_4_1 | diff --git a/test/regression/expected/timestamp_timestamptz.out b/test/regression/expected/timestamp_timestamptz.out new file mode 100644 index 0000000..822d865 --- /dev/null +++ b/test/regression/expected/timestamp_timestamptz.out @@ -0,0 +1,144 @@ +---------------------------------------- +-- Timestamp tests +---------------------------------------- +-- Test +/- inf values +CREATE TABLE t(a TIMESTAMP); +INSERT INTO t VALUES('Infinity'), ('-Infinity'); +-- PG Execution +SELECT * from t; + a +----------- + infinity + -infinity +(2 rows) + +SELECT isfinite(a) FROM t; + isfinite +---------- + f + f +(2 rows) + +set duckdb.force_execution = true; +-- DuckDB execution +SELECT * from t; + a +----------- + infinity + -infinity +(2 rows) + +SELECT isfinite(a) FROM t; + isfinite +---------- + f + f +(2 rows) + +-- Cleanup +set duckdb.force_execution = false; +DROP TABLE t; +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC) 00:00:00'::timestamp as timestamp $$); + timestamp +----------------------------- + Mon Nov 24 00:00:00 4714 BC +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC) 23:59:59'::timestamp as timestamp $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The Timestamp value should be between min and max value (4714-11-24 (BC) 00:00:00 <-> 294247-01-01 00:00:00) +SELECT * FROM duckdb.query($$ SELECT '294246-12-31 23:59:59'::timestamp as timestamp $$); + timestamp +---------------------------- + Thu Dec 31 23:59:59 294246 +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '294247-01-01 00:00:00'::timestamp as timestamp $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The Timestamp value should be between min and max value (4714-11-24 (BC) 00:00:00 <-> 294247-01-01 00:00:00) +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC) 00:00:00'::timestamp_s as timestamp_s $$); + timestamp_s +----------------------------- + Mon Nov 24 00:00:00 4714 BC +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC) 23:59:59'::timestamp_s as timestamp_s $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The Timestamp value should be between min and max value (4714-11-24 (BC) 00:00:00 <-> 294247-01-01 00:00:00) +SELECT * FROM duckdb.query($$ SELECT '294246-12-31 23:59:59'::timestamp_s as timestamp_s $$); + timestamp_s +---------------------------- + Thu Dec 31 23:59:59 294246 +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '294247-01-01 00:00:00'::timestamp_s as timestamp_s $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The Timestamp value should be between min and max value (4714-11-24 (BC) 00:00:00 <-> 294247-01-01 00:00:00) +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC) 00:00:00'::timestamp_ms as timestamp_ms $$); + timestamp_ms +----------------------------- + Mon Nov 24 00:00:00 4714 BC +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC) 23:59:59'::timestamp_ms as timestamp_ms $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The Timestamp value should be between min and max value (4714-11-24 (BC) 00:00:00 <-> 294247-01-01 00:00:00) +SELECT * FROM duckdb.query($$ SELECT '294246-12-31 23:59:59'::timestamp_ms as timestamp_ms $$); + timestamp_ms +---------------------------- + Thu Dec 31 23:59:59 294246 +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '294247-01-01 00:00:00'::timestamp_ms as timestamp_ms $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The Timestamp value should be between min and max value (4714-11-24 (BC) 00:00:00 <-> 294247-01-01 00:00:00) +---------------------------------------- +-- TimestampTz tests +---------------------------------------- +-- Test +/- inf valuestz +CREATE TABLE t(a TIMESTAMPTZ); +INSERT INTO t VALUES('Infinity'), ('-Infinity'); +-- PG Execution +SELECT * from t; + a +----------- + infinity + -infinity +(2 rows) + +SELECT isfinite(a) FROM t; + isfinite +---------- + f + f +(2 rows) + +set duckdb.force_execution = true; +-- DuckDB execution +SELECT * from t; + a +----------- + infinity + -infinity +(2 rows) + +SELECT isfinite(a) FROM t; + isfinite +---------- + f + f +(2 rows) + +-- Cleanup +set duckdb.force_execution = false; +DROP TABLE t; +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC) 00:00:00'::timestamptz as timestamptz $$); + timestamptz +--------------------------------- + Sun Nov 23 16:07:02 4714 LMT BC +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC) 23:59:59'::timestamptz as timestamptz $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The TimestampTz value should be between min and max value (4714-11-24 (BC) 00:00:00 <-> 294247-01-01 00:00:00) +SELECT * FROM duckdb.query($$ SELECT '294246-12-31 23:59:59'::timestamptz as timestamptz $$); + timestamptz +-------------------------------- + Thu Dec 31 15:59:59 294246 PST +(1 row) + +SELECT * FROM duckdb.query($$ SELECT '294247-01-01 00:00:00'::timestamptz as timestamptz $$); -- out of range +ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Out of Range Error: The TimestampTz value should be between min and max value (4714-11-24 (BC) 00:00:00 <-> 294247-01-01 00:00:00) diff --git a/test/regression/schedule b/test/regression/schedule index 4a26b96..4df9996 100644 --- a/test/regression/schedule +++ b/test/regression/schedule @@ -33,3 +33,5 @@ test: approx_count_distinct test: scan_postgres_tables test: unresolved_type test: json_functions_duckdb +test: date +test: timestamp_timestamptz diff --git a/test/regression/sql/date.sql b/test/regression/sql/date.sql new file mode 100644 index 0000000..15c6ef1 --- /dev/null +++ b/test/regression/sql/date.sql @@ -0,0 +1,22 @@ +-- Test +/- inf values +CREATE TABLE t(a DATE); +INSERT INTO t VALUES('Infinity'), ('-Infinity'); + +-- PG Execution +SELECT * from t; +SELECT isfinite(a) FROM t; + +set duckdb.force_execution = true; +-- DuckDB execution +SELECT * from t; +SELECT isfinite(a) FROM t; + +-- Cleanup +set duckdb.force_execution = false; +DROP TABLE t; + +-- Check upper and lower limits of date range +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC)'::date as date $$); +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC)'::date as date $$); -- out of range +SELECT * FROM duckdb.query($$ SELECT '5874897-12-31'::date as date $$); +SELECT * FROM duckdb.query($$ SELECT '5874898-01-01'::date as date $$); -- out of range diff --git a/test/regression/sql/test_all_types.sql b/test/regression/sql/test_all_types.sql index 7964794..f75e6a3 100644 --- a/test/regression/sql/test_all_types.sql +++ b/test/regression/sql/test_all_types.sql @@ -23,5 +23,11 @@ SELECT * exclude( fixed_array_of_int_list, list_of_fixed_int_array, nested_int_array, -- The nested array has different lengths, which is not possible in PG + date, + timestamp, + timestamp_s, + timestamp_ms, + timestamp_ns, + timestamp_tz ) $$) diff --git a/test/regression/sql/timestamp_timestamptz.sql b/test/regression/sql/timestamp_timestamptz.sql new file mode 100644 index 0000000..f35e6f7 --- /dev/null +++ b/test/regression/sql/timestamp_timestamptz.sql @@ -0,0 +1,59 @@ +---------------------------------------- +-- Timestamp tests +---------------------------------------- +-- Test +/- inf values +CREATE TABLE t(a TIMESTAMP); +INSERT INTO t VALUES('Infinity'), ('-Infinity'); + +-- PG Execution +SELECT * from t; +SELECT isfinite(a) FROM t; + +set duckdb.force_execution = true; +-- DuckDB execution +SELECT * from t; +SELECT isfinite(a) FROM t; + +-- Cleanup +set duckdb.force_execution = false; +DROP TABLE t; + +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC) 00:00:00'::timestamp as timestamp $$); +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC) 23:59:59'::timestamp as timestamp $$); -- out of range +SELECT * FROM duckdb.query($$ SELECT '294246-12-31 23:59:59'::timestamp as timestamp $$); +SELECT * FROM duckdb.query($$ SELECT '294247-01-01 00:00:00'::timestamp as timestamp $$); -- out of range + +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC) 00:00:00'::timestamp_s as timestamp_s $$); +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC) 23:59:59'::timestamp_s as timestamp_s $$); -- out of range +SELECT * FROM duckdb.query($$ SELECT '294246-12-31 23:59:59'::timestamp_s as timestamp_s $$); +SELECT * FROM duckdb.query($$ SELECT '294247-01-01 00:00:00'::timestamp_s as timestamp_s $$); -- out of range + +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC) 00:00:00'::timestamp_ms as timestamp_ms $$); +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC) 23:59:59'::timestamp_ms as timestamp_ms $$); -- out of range +SELECT * FROM duckdb.query($$ SELECT '294246-12-31 23:59:59'::timestamp_ms as timestamp_ms $$); +SELECT * FROM duckdb.query($$ SELECT '294247-01-01 00:00:00'::timestamp_ms as timestamp_ms $$); -- out of range + +---------------------------------------- +-- TimestampTz tests +---------------------------------------- +-- Test +/- inf valuestz +CREATE TABLE t(a TIMESTAMPTZ); +INSERT INTO t VALUES('Infinity'), ('-Infinity'); + +-- PG Execution +SELECT * from t; +SELECT isfinite(a) FROM t; + +set duckdb.force_execution = true; +-- DuckDB execution +SELECT * from t; +SELECT isfinite(a) FROM t; + +-- Cleanup +set duckdb.force_execution = false; +DROP TABLE t; + +SELECT * FROM duckdb.query($$ SELECT '4714-11-24 (BC) 00:00:00'::timestamptz as timestamptz $$); +SELECT * FROM duckdb.query($$ SELECT '4714-11-23 (BC) 23:59:59'::timestamptz as timestamptz $$); -- out of range +SELECT * FROM duckdb.query($$ SELECT '294246-12-31 23:59:59'::timestamptz as timestamptz $$); +SELECT * FROM duckdb.query($$ SELECT '294247-01-01 00:00:00'::timestamptz as timestamptz $$); -- out of range