-- 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. \c :TEST_DBNAME :ROLE_SUPERUSER create schema test_schema AUTHORIZATION :ROLE_DEFAULT_PERM_USER; create schema chunk_schema AUTHORIZATION :ROLE_DEFAULT_PERM_USER_2; SET ROLE :ROLE_DEFAULT_PERM_USER; create table test_schema.test_table(time BIGINT, temp float8, device_id text, device_type text, location text, id int, id2 int); \set ON_ERROR_STOP 0 -- get_create_command should fail since hypertable isn't made yet SELECT * FROM _timescaledb_internal.get_create_command('test_table'); ERROR: hypertable "test_table" not found \set ON_ERROR_STOP 1 \dt "test_schema".* List of relations Schema | Name | Type | Owner -------------+------------+-------+------------------- test_schema | test_table | table | default_perm_user (1 row) create table test_schema.test_table_no_not_null(time BIGINT, device_id text); \set ON_ERROR_STOP 0 -- Permission denied with unprivileged role SET ROLE :ROLE_DEFAULT_PERM_USER_2; select * from create_hypertable('test_schema.test_table_no_not_null', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month')); ERROR: permission denied for schema test_schema at character 33 -- CREATE on schema is not enough SET ROLE :ROLE_DEFAULT_PERM_USER; GRANT ALL ON SCHEMA test_schema TO :ROLE_DEFAULT_PERM_USER_2; SET ROLE :ROLE_DEFAULT_PERM_USER_2; select * from create_hypertable('test_schema.test_table_no_not_null', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month')); ERROR: must be owner of hypertable "test_table_no_not_null" \set ON_ERROR_STOP 1 -- Should work with when granted table owner role RESET ROLE; GRANT :ROLE_DEFAULT_PERM_USER TO :ROLE_DEFAULT_PERM_USER_2; SET ROLE :ROLE_DEFAULT_PERM_USER_2; select * from create_hypertable('test_schema.test_table_no_not_null', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month')); NOTICE: adding not-null constraint to column "time" hypertable_id | schema_name | table_name | created ---------------+-------------+------------------------+--------- 1 | test_schema | test_table_no_not_null | t (1 row) \set ON_ERROR_STOP 0 insert into test_schema.test_table_no_not_null (device_id) VALUES('foo'); ERROR: NULL value in column "time" violates not-null constraint \set ON_ERROR_STOP 1 insert into test_schema.test_table_no_not_null (time, device_id) VALUES(1, 'foo'); RESET ROLE; SET ROLE :ROLE_DEFAULT_PERM_USER; \set ON_ERROR_STOP 0 -- No permissions on associated schema should fail select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'), associated_schema_name => 'chunk_schema'); ERROR: permissions denied: cannot create chunks in schema "chunk_schema" \set ON_ERROR_STOP 1 -- Granting permissions on chunk_schema should make things work RESET ROLE; GRANT CREATE ON SCHEMA chunk_schema TO :ROLE_DEFAULT_PERM_USER; SET ROLE :ROLE_DEFAULT_PERM_USER; select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'), associated_schema_name => 'chunk_schema'); NOTICE: adding not-null constraint to column "time" hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 2 | test_schema | test_table | t (1 row) -- Check that the insert block trigger exists SELECT * FROM test.show_triggers('test_schema.test_table'); Trigger | Type | Function | Definition -------------------+------+--------------------------------------+---------------------------------------------------------------------------------------------------------------------------------- ts_insert_blocker | 7 | _timescaledb_internal.insert_blocker | ts_insert_blocker BEFORE INSERT ON test_schema.test_table FOR EACH ROW EXECUTE PROCEDURE _timescaledb_internal.insert_blocker() (1 row) SELECT * FROM _timescaledb_internal.get_create_command('test_table'); get_create_command -------------------------------------------------------------------------------------------------------------------------------------------------- SELECT create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval => 2592000000000, create_default_indexes=>FALSE); (1 row) --test adding one more closed dimension select add_dimension('test_schema.test_table', 'location', 4); add_dimension --------------------------------------- (5,test_schema,test_table,location,t) (1 row) select * from _timescaledb_catalog.hypertable where table_name = 'test_table'; id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions | chunk_sizing_func_schema | chunk_sizing_func_name | chunk_target_size | compressed | compressed_hypertable_id ----+-------------+------------+------------------------+-------------------------+----------------+--------------------------+--------------------------+-------------------+------------+-------------------------- 2 | test_schema | test_table | chunk_schema | _hyper_2 | 3 | _timescaledb_internal | calculate_chunk_interval | 0 | f | (1 row) select * from _timescaledb_catalog.dimension; id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length | integer_now_func_schema | integer_now_func ----+---------------+-------------+-------------+---------+------------+--------------------------+--------------------+-----------------+-------------------------+------------------ 1 | 1 | time | bigint | t | | | | 2592000000000 | | 2 | 1 | device_id | text | f | 2 | _timescaledb_internal | get_partition_hash | | | 3 | 2 | time | bigint | t | | | | 2592000000000 | | 4 | 2 | device_id | text | f | 2 | _timescaledb_internal | get_partition_hash | | | 5 | 2 | location | text | f | 4 | _timescaledb_internal | get_partition_hash | | | (5 rows) --test that we can change the number of partitions and that 1 is allowed SELECT set_number_partitions('test_schema.test_table', 1, 'location'); set_number_partitions ----------------------- (1 row) select * from _timescaledb_catalog.dimension WHERE column_name = 'location'; id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length | integer_now_func_schema | integer_now_func ----+---------------+-------------+-------------+---------+------------+--------------------------+--------------------+-----------------+-------------------------+------------------ 5 | 2 | location | text | f | 1 | _timescaledb_internal | get_partition_hash | | | (1 row) SELECT set_number_partitions('test_schema.test_table', 2, 'location'); set_number_partitions ----------------------- (1 row) select * from _timescaledb_catalog.dimension WHERE column_name = 'location'; id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length | integer_now_func_schema | integer_now_func ----+---------------+-------------+-------------+---------+------------+--------------------------+--------------------+-----------------+-------------------------+------------------ 5 | 2 | location | text | f | 2 | _timescaledb_internal | get_partition_hash | | | (1 row) \set ON_ERROR_STOP 0 --must give an explicit dimension when there are multiple space dimensions SELECT set_number_partitions('test_schema.test_table', 3); ERROR: hypertable "test_table" has multiple space dimensions --too few SELECT set_number_partitions('test_schema.test_table', 0, 'location'); ERROR: invalid number of partitions: must be between 1 and 32767 -- Too many SELECT set_number_partitions('test_schema.test_table', 32768, 'location'); ERROR: invalid number of partitions: must be between 1 and 32767 -- get_create_command only works on tables w/ 1 or 2 dimensions SELECT * FROM _timescaledb_internal.get_create_command('test_table'); ERROR: get_create_command only supports hypertables with up to 2 dimensions \set ON_ERROR_STOP 1 --test adding one more open dimension select add_dimension('test_schema.test_table', 'id', chunk_time_interval => 1000); NOTICE: adding not-null constraint to column "id" add_dimension --------------------------------- (6,test_schema,test_table,id,t) (1 row) select * from _timescaledb_catalog.hypertable where table_name = 'test_table'; id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions | chunk_sizing_func_schema | chunk_sizing_func_name | chunk_target_size | compressed | compressed_hypertable_id ----+-------------+------------+------------------------+-------------------------+----------------+--------------------------+--------------------------+-------------------+------------+-------------------------- 2 | test_schema | test_table | chunk_schema | _hyper_2 | 4 | _timescaledb_internal | calculate_chunk_interval | 0 | f | (1 row) select * from _timescaledb_catalog.dimension; id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length | integer_now_func_schema | integer_now_func ----+---------------+-------------+-------------+---------+------------+--------------------------+--------------------+-----------------+-------------------------+------------------ 1 | 1 | time | bigint | t | | | | 2592000000000 | | 2 | 1 | device_id | text | f | 2 | _timescaledb_internal | get_partition_hash | | | 3 | 2 | time | bigint | t | | | | 2592000000000 | | 4 | 2 | device_id | text | f | 2 | _timescaledb_internal | get_partition_hash | | | 5 | 2 | location | text | f | 2 | _timescaledb_internal | get_partition_hash | | | 6 | 2 | id | integer | t | | | | 1000 | | (6 rows) -- Test add_dimension: can use interval types for TIMESTAMPTZ columns CREATE TABLE dim_test_time(time TIMESTAMPTZ, time2 TIMESTAMPTZ, time3 BIGINT, temp float8, device int, location int); SELECT create_hypertable('dim_test_time', 'time'); NOTICE: adding not-null constraint to column "time" create_hypertable ---------------------------- (3,public,dim_test_time,t) (1 row) SELECT add_dimension('dim_test_time', 'time2', chunk_time_interval => INTERVAL '1 day'); NOTICE: adding not-null constraint to column "time2" add_dimension ---------------------------------- (8,public,dim_test_time,time2,t) (1 row) -- Test add_dimension: only integral should work on BIGINT columns \set ON_ERROR_STOP 0 SELECT add_dimension('dim_test_time', 'time3', chunk_time_interval => INTERVAL '1 day'); ERROR: invalid interval: must be an integer type for integer dimensions -- string is not a valid type SELECT add_dimension('dim_test_time', 'time3', chunk_time_interval => 'foo'::TEXT); ERROR: invalid interval: must be an interval or integer type \set ON_ERROR_STOP 1 SELECT add_dimension('dim_test_time', 'time3', chunk_time_interval => 500); NOTICE: adding not-null constraint to column "time3" add_dimension ---------------------------------- (9,public,dim_test_time,time3,t) (1 row) -- Test add_dimension: integrals should work on TIMESTAMPTZ columns CREATE TABLE dim_test_time2(time TIMESTAMPTZ, time2 TIMESTAMPTZ, temp float8, device int, location int); SELECT create_hypertable('dim_test_time2', 'time'); NOTICE: adding not-null constraint to column "time" create_hypertable ----------------------------- (4,public,dim_test_time2,t) (1 row) SELECT add_dimension('dim_test_time2', 'time2', chunk_time_interval => 500); WARNING: unexpected interval: smaller than one second NOTICE: adding not-null constraint to column "time2" add_dimension ------------------------------------ (11,public,dim_test_time2,time2,t) (1 row) --adding a dimension twice should not fail with 'if_not_exists' SELECT add_dimension('dim_test_time2', 'time2', chunk_time_interval => 500, if_not_exists => true); NOTICE: column "time2" is already a dimension, skipping add_dimension ------------------------------------ (11,public,dim_test_time2,time2,f) (1 row) \set ON_ERROR_STOP 0 --adding on a non-hypertable CREATE TABLE not_hypertable(time TIMESTAMPTZ, temp float8, device int, location int); SELECT add_dimension('not_hypertable', 'time', chunk_time_interval => 500); ERROR: table "not_hypertable" is not a hypertable --adding a non-exist column SELECT add_dimension('test_schema.test_table', 'nope', 2); ERROR: column "nope" does not exist --adding the same dimension twice should fail select add_dimension('test_schema.test_table', 'location', 2); ERROR: column "location" is already a dimension --adding dimension with both number_partitions and chunk_time_interval should fail select add_dimension('test_schema.test_table', 'id2', number_partitions => 2, chunk_time_interval => 1000); ERROR: cannot specify both the number of partitions and an interval --adding a new dimension on a non-empty table should also fail insert into test_schema.test_table values (123456789, 23.8, 'blue', 'type1', 'nyc', 1, 1); select add_dimension('test_schema.test_table', 'device_type', 2); ERROR: hypertable "test_table" has tuples or empty chunks -- should fail on non-empty table with 'if_not_exists' in case the dimension does not exists select add_dimension('test_schema.test_table', 'device_type', 2, if_not_exists => true); ERROR: hypertable "test_table" has tuples or empty chunks \set ON_ERROR_STOP 1 -- should not fail on non-empty table with 'if_not_exists' in case the dimension exists select add_dimension('test_schema.test_table', 'location', 2, if_not_exists => true); NOTICE: column "location" is already a dimension, skipping add_dimension --------------------------------------- (5,test_schema,test_table,location,f) (1 row) --should fail on empty table that still has chunks -- \set ON_ERROR_STOP 0 delete from test_schema.test_table where time is not null; select count(*) from test_schema.test_table; count ------- 0 (1 row) select add_dimension('test_schema.test_table', 'device_type', 2); ERROR: hypertable "test_table" has tuples or empty chunks \set ON_ERROR_STOP 1 --show chunks in the associated schema \dt "chunk_schema".* List of relations Schema | Name | Type | Owner --------------+------------------+-------+------------------- chunk_schema | _hyper_2_2_chunk | table | default_perm_user (1 row) --test partitioning in only time dimension create table test_schema.test_1dim(time timestamp, temp float); select create_hypertable('test_schema.test_1dim', 'time'); NOTICE: adding not-null constraint to column "time" create_hypertable ----------------------------- (5,test_schema,test_1dim,t) (1 row) SELECT * FROM _timescaledb_internal.get_create_command('test_1dim'); get_create_command -------------------------------------------------------------------------------------------------------------------------------- SELECT create_hypertable('test_schema.test_1dim', 'time', chunk_time_interval => 604800000000, create_default_indexes=>FALSE); (1 row) \dt "test_schema".* List of relations Schema | Name | Type | Owner -------------+------------------------+-------+------------------- test_schema | test_1dim | table | default_perm_user test_schema | test_table | table | default_perm_user test_schema | test_table_no_not_null | table | default_perm_user (3 rows) select create_hypertable('test_schema.test_1dim', 'time', if_not_exists => true); NOTICE: table "test_1dim" is already a hypertable, skipping create_hypertable ----------------------------- (5,test_schema,test_1dim,f) (1 row) -- Should error when creating again without if_not_exists set to true \set ON_ERROR_STOP 0 select create_hypertable('test_schema.test_1dim', 'time'); ERROR: table "test_1dim" is already a hypertable \set ON_ERROR_STOP 1 -- if_not_exist should also work with data in the hypertable insert into test_schema.test_1dim VALUES ('2004-10-19 10:23:54+02', 1.0); select create_hypertable('test_schema.test_1dim', 'time', if_not_exists => true); NOTICE: table "test_1dim" is already a hypertable, skipping create_hypertable ----------------------------- (5,test_schema,test_1dim,f) (1 row) -- Should error when creating again without if_not_exists set to true \set ON_ERROR_STOP 0 select create_hypertable('test_schema.test_1dim', 'time'); ERROR: table "test_1dim" is already a hypertable \set ON_ERROR_STOP 1 -- Test partitioning functions CREATE OR REPLACE FUNCTION invalid_partfunc(source integer) RETURNS INTEGER LANGUAGE PLPGSQL IMMUTABLE AS $BODY$ BEGIN RETURN NULL; END $BODY$; CREATE OR REPLACE FUNCTION time_partfunc(source text) RETURNS TIMESTAMPTZ LANGUAGE PLPGSQL IMMUTABLE AS $BODY$ BEGIN RETURN timezone('UTC', to_timestamp(source)); END $BODY$; CREATE TABLE test_schema.test_invalid_func(time timestamptz, temp float8, device text); \set ON_ERROR_STOP 0 -- should fail due to invalid signature SELECT create_hypertable('test_schema.test_invalid_func', 'time', 'device', 2, partitioning_func => 'invalid_partfunc'); ERROR: invalid partitioning function SELECT create_hypertable('test_schema.test_invalid_func', 'time'); NOTICE: adding not-null constraint to column "time" create_hypertable ------------------------------------- (6,test_schema,test_invalid_func,t) (1 row) -- should also fail due to invalid signature SELECT add_dimension('test_schema.test_invalid_func', 'device', 2, partitioning_func => 'invalid_partfunc'); ERROR: invalid partitioning function \set ON_ERROR_STOP 1 -- Test open-dimension function CREATE TABLE test_schema.open_dim_part_func(time text, temp float8, device text, event_time text); \set ON_ERROR_STOP 0 -- should fail due to invalid signature SELECT create_hypertable('test_schema.open_dim_part_func', 'time', time_partitioning_func => 'invalid_partfunc'); ERROR: invalid partitioning function \set ON_ERROR_STOP 1 SELECT create_hypertable('test_schema.open_dim_part_func', 'time', time_partitioning_func => 'time_partfunc'); NOTICE: adding not-null constraint to column "time" create_hypertable -------------------------------------- (7,test_schema,open_dim_part_func,t) (1 row) \set ON_ERROR_STOP 0 -- should fail due to invalid signature SELECT add_dimension('test_schema.open_dim_part_func', 'event_time', chunk_time_interval => interval '1 day', partitioning_func => 'invalid_partfunc'); ERROR: invalid partitioning function \set ON_ERROR_STOP 1 SELECT add_dimension('test_schema.open_dim_part_func', 'event_time', chunk_time_interval => interval '1 day', partitioning_func => 'time_partfunc'); NOTICE: adding not-null constraint to column "event_time" add_dimension -------------------------------------------------- (15,test_schema,open_dim_part_func,event_time,t) (1 row) --test data migration create table test_schema.test_migrate(time timestamp, temp float); insert into test_schema.test_migrate VALUES ('2004-10-19 10:23:54+02', 1.0), ('2004-12-19 10:23:54+02', 2.0); select * from only test_schema.test_migrate; time | temp --------------------------+------ Tue Oct 19 10:23:54 2004 | 1 Sun Dec 19 10:23:54 2004 | 2 (2 rows) \set ON_ERROR_STOP 0 --should fail without migrate_data => true select create_hypertable('test_schema.test_migrate', 'time'); ERROR: table "test_migrate" is not empty \set ON_ERROR_STOP 1 select create_hypertable('test_schema.test_migrate', 'time', migrate_data => true); NOTICE: adding not-null constraint to column "time" NOTICE: migrating data to chunks create_hypertable -------------------------------- (8,test_schema,test_migrate,t) (1 row) --there should be two new chunks select * from _timescaledb_catalog.hypertable where table_name = 'test_migrate'; id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions | chunk_sizing_func_schema | chunk_sizing_func_name | chunk_target_size | compressed | compressed_hypertable_id ----+-------------+--------------+------------------------+-------------------------+----------------+--------------------------+--------------------------+-------------------+------------+-------------------------- 8 | test_schema | test_migrate | _timescaledb_internal | _hyper_8 | 1 | _timescaledb_internal | calculate_chunk_interval | 0 | f | (1 row) select * from _timescaledb_catalog.chunk; id | hypertable_id | schema_name | table_name | compressed_chunk_id | dropped ----+---------------+-----------------------+------------------+---------------------+--------- 1 | 1 | _timescaledb_internal | _hyper_1_1_chunk | | f 2 | 2 | chunk_schema | _hyper_2_2_chunk | | f 3 | 5 | _timescaledb_internal | _hyper_5_3_chunk | | f 4 | 8 | _timescaledb_internal | _hyper_8_4_chunk | | f 5 | 8 | _timescaledb_internal | _hyper_8_5_chunk | | f (5 rows) select * from test_schema.test_migrate; time | temp --------------------------+------ Tue Oct 19 10:23:54 2004 | 1 Sun Dec 19 10:23:54 2004 | 2 (2 rows) --main table should now be empty select * from only test_schema.test_migrate; time | temp ------+------ (0 rows) select * from only _timescaledb_internal._hyper_8_4_chunk; time | temp --------------------------+------ Tue Oct 19 10:23:54 2004 | 1 (1 row) select * from only _timescaledb_internal._hyper_8_5_chunk; time | temp --------------------------+------ Sun Dec 19 10:23:54 2004 | 2 (1 row) create table test_schema.test_migrate_empty(time timestamp, temp float); select create_hypertable('test_schema.test_migrate_empty', 'time', migrate_data => true); NOTICE: adding not-null constraint to column "time" create_hypertable -------------------------------------- (9,test_schema,test_migrate_empty,t) (1 row) CREATE TYPE test_type AS (time timestamp, temp float); CREATE TABLE test_table_of_type OF test_type; SELECT create_hypertable('test_table_of_type', 'time'); NOTICE: adding not-null constraint to column "time" create_hypertable ---------------------------------- (10,public,test_table_of_type,t) (1 row) INSERT INTO test_table_of_type VALUES ('2004-10-19 10:23:54+02', 1.0), ('2004-12-19 10:23:54+02', 2.0); \set ON_ERROR_STOP 0 DROP TYPE test_type; ERROR: cannot drop type test_type because other objects depend on it \set ON_ERROR_STOP 1 DROP TYPE test_type CASCADE; NOTICE: drop cascades to 3 other objects CREATE TABLE test_table_of_type (time timestamp, temp float); SELECT create_hypertable('test_table_of_type', 'time'); NOTICE: adding not-null constraint to column "time" create_hypertable ---------------------------------- (11,public,test_table_of_type,t) (1 row) INSERT INTO test_table_of_type VALUES ('2004-10-19 10:23:54+02', 1.0), ('2004-12-19 10:23:54+02', 2.0); CREATE TYPE test_type AS (time timestamp, temp float); ALTER TABLE test_table_of_type OF test_type; \set ON_ERROR_STOP 0 DROP TYPE test_type; ERROR: cannot drop type test_type because other objects depend on it \set ON_ERROR_STOP 1 BEGIN; DROP TYPE test_type CASCADE; NOTICE: drop cascades to 3 other objects ROLLBACK; ALTER TABLE test_table_of_type NOT OF; DROP TYPE test_type; -- Reset GRANTS \c :TEST_DBNAME :ROLE_SUPERUSER REVOKE :ROLE_DEFAULT_PERM_USER FROM :ROLE_DEFAULT_PERM_USER_2; -- Test custom partitioning functions CREATE OR REPLACE FUNCTION partfunc_not_immutable(source anyelement) RETURNS INTEGER LANGUAGE PLPGSQL AS $BODY$ BEGIN RETURN _timescaledb_internal.get_partition_hash(source); END $BODY$; CREATE OR REPLACE FUNCTION partfunc_bad_return_type(source anyelement) RETURNS BIGINT LANGUAGE PLPGSQL IMMUTABLE AS $BODY$ BEGIN RETURN _timescaledb_internal.get_partition_hash(source); END $BODY$; CREATE OR REPLACE FUNCTION partfunc_bad_arg_type(source text) RETURNS INTEGER LANGUAGE PLPGSQL IMMUTABLE AS $BODY$ BEGIN RETURN _timescaledb_internal.get_partition_hash(source); END $BODY$; CREATE OR REPLACE FUNCTION partfunc_bad_multi_arg(source anyelement, extra_arg integer) RETURNS INTEGER LANGUAGE PLPGSQL IMMUTABLE AS $BODY$ BEGIN RETURN _timescaledb_internal.get_partition_hash(source); END $BODY$; CREATE OR REPLACE FUNCTION partfunc_valid(source anyelement) RETURNS INTEGER LANGUAGE PLPGSQL IMMUTABLE AS $BODY$ BEGIN RETURN _timescaledb_internal.get_partition_hash(source); END $BODY$; create table test_schema.test_partfunc(time timestamptz, temp float, device int); -- Test that create_hypertable fails due to invalid partitioning function \set ON_ERROR_STOP 0 select create_hypertable('test_schema.test_partfunc', 'time', 'device', 2, partitioning_func => 'partfunc_not_immutable'); ERROR: invalid partitioning function select create_hypertable('test_schema.test_partfunc', 'time', 'device', 2, partitioning_func => 'partfunc_bad_return_type'); ERROR: invalid partitioning function select create_hypertable('test_schema.test_partfunc', 'time', 'device', 2, partitioning_func => 'partfunc_bad_arg_type'); ERROR: invalid partitioning function select create_hypertable('test_schema.test_partfunc', 'time', 'device', 2, partitioning_func => 'partfunc_bad_multi_arg'); ERROR: invalid partitioning function \set ON_ERROR_STOP 1 -- Test that add_dimension fails due to invalid partitioning function select create_hypertable('test_schema.test_partfunc', 'time'); NOTICE: adding not-null constraint to column "time" create_hypertable ---------------------------------- (12,test_schema,test_partfunc,t) (1 row) \set ON_ERROR_STOP 0 select add_dimension('test_schema.test_partfunc', 'device', 2, partitioning_func => 'partfunc_not_immutable'); ERROR: invalid partitioning function select add_dimension('test_schema.test_partfunc', 'device', 2, partitioning_func => 'partfunc_bad_return_type'); ERROR: invalid partitioning function select add_dimension('test_schema.test_partfunc', 'device', 2, partitioning_func => 'partfunc_bad_arg_type'); ERROR: invalid partitioning function select add_dimension('test_schema.test_partfunc', 'device', 2, partitioning_func => 'partfunc_bad_multi_arg'); ERROR: invalid partitioning function \set ON_ERROR_STOP 1 -- A valid function should work: select add_dimension('test_schema.test_partfunc', 'device', 2, partitioning_func => 'partfunc_valid'); add_dimension ----------------------------------------- (21,test_schema,test_partfunc,device,t) (1 row) -- check get_create_command produces valid command CREATE TABLE test_schema.test_sql_cmd(time TIMESTAMPTZ, temp FLOAT8, device_id TEXT, device_type TEXT, location TEXT, id INT, id2 INT); SELECT create_hypertable('test_schema.test_sql_cmd','time'); NOTICE: adding not-null constraint to column "time" create_hypertable --------------------------------- (13,test_schema,test_sql_cmd,t) (1 row) SELECT * FROM _timescaledb_internal.get_create_command('test_sql_cmd'); get_create_command ----------------------------------------------------------------------------------------------------------------------------------- SELECT create_hypertable('test_schema.test_sql_cmd', 'time', chunk_time_interval => 604800000000, create_default_indexes=>FALSE); (1 row) SELECT _timescaledb_internal.get_create_command('test_sql_cmd') AS create_cmd; \gset create_cmd ----------------------------------------------------------------------------------------------------------------------------------- SELECT create_hypertable('test_schema.test_sql_cmd', 'time', chunk_time_interval => 604800000000, create_default_indexes=>FALSE); (1 row) DROP TABLE test_schema.test_sql_cmd CASCADE; CREATE TABLE test_schema.test_sql_cmd(time TIMESTAMPTZ, temp FLOAT8, device_id TEXT, device_type TEXT, location TEXT, id INT, id2 INT); SELECT test.execute_sql(:'create_cmd'); NOTICE: adding not-null constraint to column "time" execute_sql ----------------------------------------------------------------------------------------------------------------------------------- SELECT create_hypertable('test_schema.test_sql_cmd', 'time', chunk_time_interval => 604800000000, create_default_indexes=>FALSE); (1 row) \c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER CREATE TABLE test_table_int(time bigint, junk int); SELECT hypertable_id AS "TEST_TABLE_INT_HYPERTABLE_ID" FROM create_hypertable('test_table_int', 'time', chunk_time_interval => 1) \gset NOTICE: adding not-null constraint to column "time" \c :TEST_DBNAME :ROLE_SUPERUSER CREATE SCHEMA IF NOT EXISTS my_schema; create or replace function my_schema.dummy_now2() returns BIGINT LANGUAGE SQL IMMUTABLE as 'SELECT 1::BIGINT'; grant execute on ALL FUNCTIONS IN SCHEMA my_schema to public; create or replace function dummy_now3() returns BIGINT LANGUAGE SQL IMMUTABLE as 'SELECT 1::BIGINT'; grant execute on ALL FUNCTIONS IN SCHEMA my_schema to public; REVOKE execute ON function dummy_now3() FROM PUBLIC; CREATE SCHEMA IF NOT EXISTS my_user_schema; GRANT ALL ON SCHEMA my_user_schema to PUBLIC; \c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER create or replace function dummy_now() returns BIGINT LANGUAGE SQL IMMUTABLE as 'SELECT 1::BIGINT'; create or replace function my_user_schema.dummy_now4() returns BIGINT LANGUAGE SQL IMMUTABLE as 'SELECT 1::BIGINT'; select set_integer_now_func('test_table_int', 'dummy_now'); set_integer_now_func ---------------------- (1 row) select * from _timescaledb_catalog.dimension WHERE hypertable_id = :TEST_TABLE_INT_HYPERTABLE_ID; id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length | integer_now_func_schema | integer_now_func ----+---------------+-------------+-------------+---------+------------+--------------------------+-------------------+-----------------+-------------------------+------------------ 24 | 15 | time | bigint | t | | | | 1 | public | dummy_now (1 row) \set ON_ERROR_STOP 0 select set_integer_now_func('test_table_int', 'dummy_now'); ERROR: integer_now_func is already set for hypertable "test_table_int" select set_integer_now_func('test_table_int', 'my_schema.dummy_now2', replace_if_exists => TRUE); ERROR: permission denied for schema my_schema at character 47 select set_integer_now_func('test_table_int', 'dummy_now3', replace_if_exists => TRUE); ERROR: permission denied for function dummy_now3 \set ON_ERROR_STOP select set_integer_now_func('test_table_int', 'my_user_schema.dummy_now4', replace_if_exists => TRUE); set_integer_now_func ---------------------- (1 row) \c :TEST_DBNAME :ROLE_SUPERUSER ALTER SCHEMA my_user_schema RENAME TO my_new_schema; select * from _timescaledb_catalog.dimension WHERE hypertable_id = :TEST_TABLE_INT_HYPERTABLE_ID; id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length | integer_now_func_schema | integer_now_func ----+---------------+-------------+-------------+---------+------------+--------------------------+-------------------+-----------------+-------------------------+------------------ 24 | 15 | time | bigint | t | | | | 1 | my_new_schema | dummy_now4 (1 row)