mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-17 19:13:16 +08:00
Fix subtract_integer_from_now on 32-bit platforms
This patch fixes subtract_integer_from_now on 32-bit platforms, improves error handling and adds some basic tests. subtract_integer_from_now would trigger an assert when called on a hypertable without integer time dimension (found by sqlsmith). Additionally subtract_integer_from_now would segfault when called on a hypertable without partitioning dimensions.
This commit is contained in:
parent
a760887145
commit
39645d56da
@ -2391,6 +2391,11 @@ ts_hypertable_set_integer_now_func(PG_FUNCTION_ARGS)
|
||||
ts_hypertable_permissions_check(table_relid, GetUserId());
|
||||
hypertable = ts_hypertable_cache_get_cache_and_entry(table_relid, CACHE_FLAG_NONE, &hcache);
|
||||
|
||||
if (TS_HYPERTABLE_IS_INTERNAL_COMPRESSION_TABLE(hypertable))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("custom time function not supported on internal compression table")));
|
||||
|
||||
/* validate that the open dimension uses numeric type */
|
||||
open_dim = hyperspace_get_open_dimension(hypertable->space, 0);
|
||||
|
||||
|
28
src/utils.c
28
src/utils.c
@ -904,18 +904,24 @@ Datum
|
||||
ts_subtract_integer_from_now(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid ht_relid = PG_GETARG_OID(0);
|
||||
Datum lag = PG_GETARG_INT64(1);
|
||||
int64 lag = PG_GETARG_INT64(1);
|
||||
Cache *hcache;
|
||||
Hypertable *hypertable =
|
||||
ts_hypertable_cache_get_cache_and_entry(ht_relid, CACHE_FLAG_NONE, &hcache);
|
||||
|
||||
const Dimension *dim = hyperspace_get_open_dimension(hypertable->space, 0);
|
||||
Oid partitioning_type = ts_dimension_get_partition_type(dim);
|
||||
Oid now_func = ts_get_integer_now_func(dim);
|
||||
if (now_func == InvalidOid)
|
||||
elog(ERROR, "could not find valid integer_now function for hypertable");
|
||||
Assert(IS_INTEGER_TYPE(partitioning_type));
|
||||
int64 res = ts_sub_integer_from_now(lag, partitioning_type, now_func);
|
||||
Hypertable *ht = ts_hypertable_cache_get_cache_and_entry(ht_relid, CACHE_FLAG_NONE, &hcache);
|
||||
const Dimension *dim = hyperspace_get_open_dimension(ht->space, 0);
|
||||
ts_cache_release(hcache);
|
||||
|
||||
if (!dim)
|
||||
elog(ERROR, "hypertable has no open partitioning dimension");
|
||||
|
||||
Oid partitioning_type = ts_dimension_get_partition_type(dim);
|
||||
|
||||
if (!IS_INTEGER_TYPE(partitioning_type))
|
||||
elog(ERROR, "hypertable has no integer partitioning dimension");
|
||||
|
||||
Oid now_func = ts_get_integer_now_func(dim);
|
||||
if (!OidIsValid(now_func))
|
||||
elog(ERROR, "could not find valid integer_now function for hypertable");
|
||||
|
||||
int64 res = ts_sub_integer_from_now(lag, partitioning_type, now_func);
|
||||
return Int64GetDatum(res);
|
||||
}
|
||||
|
118
tsl/test/shared/expected/subtract_integer_from_now.out
Normal file
118
tsl/test/shared/expected/subtract_integer_from_now.out
Normal file
@ -0,0 +1,118 @@
|
||||
-- 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.
|
||||
-- test on normal table
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('pg_class', 1);
|
||||
ERROR: table "pg_class" is not a hypertable
|
||||
\set ON_ERROR_STOP 1
|
||||
-- test on hypertable with non-int time dimension
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('metrics', 1);
|
||||
ERROR: hypertable has no integer partitioning dimension
|
||||
\set ON_ERROR_STOP 1
|
||||
SELECT
|
||||
format('%I.%I', ht.schema_name, ht.table_name) AS "TABLENAME"
|
||||
FROM
|
||||
_timescaledb_catalog.hypertable ht
|
||||
INNER JOIN _timescaledb_catalog.hypertable uncompress ON (ht.id = uncompress.compressed_hypertable_id
|
||||
AND uncompress.table_name = 'metrics_compressed') \gset
|
||||
-- test on hypertable without dimensions
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now(:'TABLENAME', 1);
|
||||
ERROR: hypertable has no open partitioning dimension
|
||||
\set ON_ERROR_STOP 1
|
||||
-- test on hypertable without now function
|
||||
CREATE TABLE subtract_int_no_func(time int NOT NULL);
|
||||
SELECT table_name FROM create_hypertable('subtract_int_no_func','time',chunk_time_interval:=10);
|
||||
table_name
|
||||
----------------------
|
||||
subtract_int_no_func
|
||||
(1 row)
|
||||
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('subtract_int_no_func', 1);
|
||||
ERROR: integer_now function not set
|
||||
\set ON_ERROR_STOP 1
|
||||
CREATE OR REPLACE FUNCTION sub_int2_now() RETURNS int2 AS $$ SELECT 2::int2; $$ LANGUAGE SQL IMMUTABLE;
|
||||
CREATE OR REPLACE FUNCTION sub_int4_now() RETURNS int4 AS $$ SELECT 4::int4; $$ LANGUAGE SQL IMMUTABLE;
|
||||
CREATE OR REPLACE FUNCTION sub_int8_now() RETURNS int8 AS $$ SELECT 8::int8; $$ LANGUAGE SQL IMMUTABLE;
|
||||
CREATE TABLE subtract_int2(time int2 NOT NULL);
|
||||
CREATE TABLE subtract_int4(time int4 NOT NULL);
|
||||
CREATE TABLE subtract_int8(time int8 NOT NULL);
|
||||
SELECT table_name FROM create_hypertable('subtract_int2', 'time', chunk_time_interval:=10);
|
||||
table_name
|
||||
---------------
|
||||
subtract_int2
|
||||
(1 row)
|
||||
|
||||
SELECT table_name FROM create_hypertable('subtract_int4', 'time', chunk_time_interval:=10);
|
||||
table_name
|
||||
---------------
|
||||
subtract_int4
|
||||
(1 row)
|
||||
|
||||
SELECT table_name FROM create_hypertable('subtract_int8', 'time', chunk_time_interval:=10);
|
||||
table_name
|
||||
---------------
|
||||
subtract_int8
|
||||
(1 row)
|
||||
|
||||
SELECT set_integer_now_func('subtract_int2', 'sub_int2_now');
|
||||
set_integer_now_func
|
||||
----------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT set_integer_now_func('subtract_int4', 'sub_int4_now');
|
||||
set_integer_now_func
|
||||
----------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT set_integer_now_func('subtract_int8', 'sub_int8_now');
|
||||
set_integer_now_func
|
||||
----------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('subtract_int2', lag) AS sub FROM (VALUES (-10),(0),(2),(4),(8)) v(lag);
|
||||
sub
|
||||
-----
|
||||
12
|
||||
2
|
||||
0
|
||||
-2
|
||||
-6
|
||||
(5 rows)
|
||||
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('subtract_int4', lag) AS sub FROM (VALUES (-10),(0),(2),(4),(8)) v(lag);
|
||||
sub
|
||||
-----
|
||||
14
|
||||
4
|
||||
2
|
||||
0
|
||||
-4
|
||||
(5 rows)
|
||||
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('subtract_int8', lag) AS sub FROM (VALUES (-10),(0),(2),(4),(8)) v(lag);
|
||||
sub
|
||||
-----
|
||||
18
|
||||
8
|
||||
6
|
||||
4
|
||||
0
|
||||
(5 rows)
|
||||
|
||||
-- test set_integer_now_func on internal table
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT set_integer_now_func(:'TABLENAME', 'sub_int2_now');
|
||||
ERROR: custom time function not supported on internal compression table
|
||||
\set ON_ERROR_STOP 1
|
||||
-- cleanup
|
||||
DROP TABLE subtract_int_no_func;
|
||||
DROP TABLE subtract_int2;
|
||||
DROP TABLE subtract_int4;
|
||||
DROP TABLE subtract_int8;
|
@ -9,7 +9,8 @@ set(TEST_FILES_SHARED
|
||||
dist_fetcher_type.sql
|
||||
dist_gapfill.sql
|
||||
dist_insert.sql
|
||||
dist_queries.sql)
|
||||
dist_queries.sql
|
||||
subtract_integer_from_now.sql)
|
||||
|
||||
if((${PG_VERSION_MAJOR} GREATER_EQUAL "14"))
|
||||
list(APPEND TEST_FILES_SHARED memoize.sql)
|
||||
|
63
tsl/test/shared/sql/subtract_integer_from_now.sql
Normal file
63
tsl/test/shared/sql/subtract_integer_from_now.sql
Normal file
@ -0,0 +1,63 @@
|
||||
-- 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.
|
||||
|
||||
-- test on normal table
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('pg_class', 1);
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- test on hypertable with non-int time dimension
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('metrics', 1);
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
SELECT
|
||||
format('%I.%I', ht.schema_name, ht.table_name) AS "TABLENAME"
|
||||
FROM
|
||||
_timescaledb_catalog.hypertable ht
|
||||
INNER JOIN _timescaledb_catalog.hypertable uncompress ON (ht.id = uncompress.compressed_hypertable_id
|
||||
AND uncompress.table_name = 'metrics_compressed') \gset
|
||||
|
||||
-- test on hypertable without dimensions
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now(:'TABLENAME', 1);
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- test on hypertable without now function
|
||||
CREATE TABLE subtract_int_no_func(time int NOT NULL);
|
||||
SELECT table_name FROM create_hypertable('subtract_int_no_func','time',chunk_time_interval:=10);
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('subtract_int_no_func', 1);
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
CREATE OR REPLACE FUNCTION sub_int2_now() RETURNS int2 AS $$ SELECT 2::int2; $$ LANGUAGE SQL IMMUTABLE;
|
||||
CREATE OR REPLACE FUNCTION sub_int4_now() RETURNS int4 AS $$ SELECT 4::int4; $$ LANGUAGE SQL IMMUTABLE;
|
||||
CREATE OR REPLACE FUNCTION sub_int8_now() RETURNS int8 AS $$ SELECT 8::int8; $$ LANGUAGE SQL IMMUTABLE;
|
||||
|
||||
CREATE TABLE subtract_int2(time int2 NOT NULL);
|
||||
CREATE TABLE subtract_int4(time int4 NOT NULL);
|
||||
CREATE TABLE subtract_int8(time int8 NOT NULL);
|
||||
|
||||
SELECT table_name FROM create_hypertable('subtract_int2', 'time', chunk_time_interval:=10);
|
||||
SELECT table_name FROM create_hypertable('subtract_int4', 'time', chunk_time_interval:=10);
|
||||
SELECT table_name FROM create_hypertable('subtract_int8', 'time', chunk_time_interval:=10);
|
||||
|
||||
SELECT set_integer_now_func('subtract_int2', 'sub_int2_now');
|
||||
SELECT set_integer_now_func('subtract_int4', 'sub_int4_now');
|
||||
SELECT set_integer_now_func('subtract_int8', 'sub_int8_now');
|
||||
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('subtract_int2', lag) AS sub FROM (VALUES (-10),(0),(2),(4),(8)) v(lag);
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('subtract_int4', lag) AS sub FROM (VALUES (-10),(0),(2),(4),(8)) v(lag);
|
||||
SELECT _timescaledb_internal.subtract_integer_from_now('subtract_int8', lag) AS sub FROM (VALUES (-10),(0),(2),(4),(8)) v(lag);
|
||||
|
||||
-- test set_integer_now_func on internal table
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT set_integer_now_func(:'TABLENAME', 'sub_int2_now');
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- cleanup
|
||||
DROP TABLE subtract_int_no_func;
|
||||
DROP TABLE subtract_int2;
|
||||
DROP TABLE subtract_int4;
|
||||
DROP TABLE subtract_int8;
|
Loading…
x
Reference in New Issue
Block a user