mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 02:23:49 +08:00
Time types, like date and timestamps, have limits that aren't the same as the underlying storage type. For instance, while a timestamp is stored as an `int64` internally, its max supported time value is not `INT64_MAX`. Instead, `INT64_MAX` represents `+Infinity` and the actual largest possible timestamp is close to `INT64_MAX` (but not `INT64_MAX-1` either). The same applies to min values. Unfortunately, time handling code does not check for these boundaries; in most cases, overflow handling when, e.g., bucketing, are checked against the max integer values instead of type-specific boundaries. In other cases, overflows simply throw errors instead of clamping to the boundary values, which makes more sense in many situations. Using integer time suffers from similar issues. To take one example, simply inserting a valid `smallint` value close to the max into a table with a `smallint` time column fails: ``` INSERT INTO smallint_table VALUES ('32765', 1, 2.0); ERROR: value "32770" is out of range for type smallint ``` This happens because the code that adds dimensional constraints always checks for overflow against `INT64_MAX` instead of the type-specific max value. Therefore, it tries to create a chunk constraint that ends at `32770`, which is outside the allowed range of `smallint`. The resolve these issues, several time-related utility functions have been implemented that, e.g., return type-specific range boundaries, and perform saturated addition and subtraction while clamping to supported boundaries. Fixes #2292
107 lines
6.3 KiB
SQL
107 lines
6.3 KiB
SQL
-- This file and its contents are licensed under the Apache License 2.0.
|
|
-- Please see the included NOTICE for copyright information and
|
|
-- LICENSE-APACHE for a copy of the license.
|
|
|
|
\unset ECHO
|
|
\o /dev/null
|
|
\ir include/test_utils.sql
|
|
\o
|
|
\set ECHO errors
|
|
\set VERBOSITY default
|
|
|
|
\o /dev/null
|
|
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.dimension_calculate_default_range_open(
|
|
dimension_value BIGINT,
|
|
interval_length BIGINT,
|
|
dimension_type CSTRING,
|
|
OUT range_start BIGINT,
|
|
OUT range_end BIGINT)
|
|
AS :MODULE_PATHNAME, 'ts_dimension_calculate_open_range_default' LANGUAGE C STABLE;
|
|
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.dimension_calculate_default_range_closed(
|
|
dimension_value BIGINT,
|
|
num_slices SMALLINT,
|
|
OUT range_start BIGINT,
|
|
OUT range_end BIGINT)
|
|
AS :MODULE_PATHNAME, 'ts_dimension_calculate_closed_range_default' LANGUAGE C STABLE;
|
|
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
|
|
--open
|
|
SELECT assert_equal(0::bigint, actual_range_start), assert_equal(10::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(0,10, 'int8') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(0::bigint, actual_range_start), assert_equal(10::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(9,10, 'int4') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(10::bigint, actual_range_start), assert_equal(20::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(10,10, 'int2') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(-10::bigint, actual_range_start), assert_equal(0::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-1,10, 'int8') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(-10::bigint, actual_range_start), assert_equal(0::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-10,10, 'int4') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(-20::bigint, actual_range_start), assert_equal(-10::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-11,10, 'int2') AS res(actual_range_start, actual_range_end);
|
|
|
|
--test that the ends are cut as needed to prevent overflow/undeflow.
|
|
|
|
---------------
|
|
-- BIGINT
|
|
---------------
|
|
SELECT assert_equal(-9223372036854775808, actual_range_start), assert_equal(-9223372036854775800::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-9223372036854775808,10, 'int8') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(-9223372036854775808, actual_range_start), assert_equal(-9223372036854775800::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-9223372036854775807,10, 'int8') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(9223372036854775800::bigint, actual_range_start), assert_equal(9223372036854775807::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(9223372036854775807,10, 'int8') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(9223372036854775800::bigint, actual_range_start), assert_equal(9223372036854775807::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(9223372036854775806,10, 'int8') AS res(actual_range_start, actual_range_end);
|
|
|
|
---------------
|
|
-- INT
|
|
---------------
|
|
SELECT assert_equal(-9223372036854775808, actual_range_start), assert_equal(-2147483640::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-2147483648,10, 'int4') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(-9223372036854775808, actual_range_start), assert_equal(-2147483640::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-2147483647,10, 'int4') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(2147483640::bigint, actual_range_start), assert_equal(9223372036854775807::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(2147483647,10, 'int4') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(2147483640::bigint, actual_range_start), assert_equal(9223372036854775807::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(2147483646,10, 'int4') AS res(actual_range_start, actual_range_end);
|
|
|
|
---------------
|
|
-- SMALLINT
|
|
---------------
|
|
SELECT assert_equal(-9223372036854775808, actual_range_start), assert_equal(-32760::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-32768,10, 'int2') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(-9223372036854775808, actual_range_start), assert_equal(-32760::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(-32767,10, 'int2') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(32760::bigint, actual_range_start), assert_equal(9223372036854775807::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(32767,10, 'int2') AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(32760::bigint, actual_range_start), assert_equal(9223372036854775807::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_open(32766,10, 'int2') AS res(actual_range_start, actual_range_end);
|
|
|
|
|
|
--closed
|
|
SELECT assert_equal((-9223372036854775808)::bigint, actual_range_start), assert_equal(1073741823::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_closed(0,2::smallint) AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal(1073741823::bigint, actual_range_start), assert_equal(9223372036854775807::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_closed(1073741824,2::smallint) AS res(actual_range_start, actual_range_end);
|
|
|
|
SELECT assert_equal((-9223372036854775808)::bigint, actual_range_start), assert_equal(9223372036854775807::bigint, actual_range_end)
|
|
FROM _timescaledb_internal.dimension_calculate_default_range_closed(1073741824,1::smallint) AS res(actual_range_start, actual_range_end);
|