-- 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 \set DN_DBNAME_1 :TEST_DBNAME _1 \set DN_DBNAME_2 :TEST_DBNAME _2 \ir include/remote_exec.sql -- 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. CREATE SCHEMA IF NOT EXISTS test; psql:include/remote_exec.sql:5: NOTICE: schema "test" already exists, skipping GRANT USAGE ON SCHEMA test TO PUBLIC; CREATE OR REPLACE FUNCTION test.remote_exec(srv_name name[], command text) RETURNS VOID AS :TSL_MODULE_PATHNAME, 'ts_remote_exec' LANGUAGE C; GRANT CREATE ON DATABASE :"TEST_DBNAME" TO :ROLE_DEFAULT_PERM_USER; SET ROLE :ROLE_DEFAULT_PERM_USER; CREATE SCHEMA "ChunkSchema"; CREATE TABLE chunkapi (time timestamptz, device int, temp float); SELECT * FROM create_hypertable('chunkapi', 'time', 'device', 2); NOTICE: adding not-null constraint to column "time" hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 1 | public | chunkapi | t (1 row) INSERT INTO chunkapi VALUES ('2018-01-01 05:00:00-8', 1, 23.4); SELECT (_timescaledb_internal.show_chunk(show_chunks)).* FROM show_chunks('chunkapi') ORDER BY chunk_id; chunk_id | hypertable_id | schema_name | table_name | relkind | slices ----------+---------------+-----------------------+------------------+---------+---------------------------------------------------------------------------------------------- 1 | 1 | _timescaledb_internal | _hyper_1_1_chunk | r | {"time": [1514419200000000, 1515024000000000], "device": [-9223372036854775808, 1073741823]} (1 row) -- Creating a chunk with the constraints of an existing chunk should -- return the existing chunk SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1514419200000000, 1515024000000000], "device": [-9223372036854775808, 1073741823]}'); chunk_id | hypertable_id | schema_name | table_name | relkind | slices | created ----------+---------------+-----------------------+------------------+---------+----------------------------------------------------------------------------------------------+--------- 1 | 1 | _timescaledb_internal | _hyper_1_1_chunk | r | {"time": [1514419200000000, 1515024000000000], "device": [-9223372036854775808, 1073741823]} | f (1 row) \set VERBOSITY default \set ON_ERROR_STOP 0 -- Modified time constraint should fail with collision SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1514419600000000, 1515024000000000], "device": [-9223372036854775808, 1073741823]}'); ERROR: chunk creation failed due to collision -- Missing dimension SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1514419600000000, 1515024000000000]}'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: invalid number of hypercube dimensions -- Extra dimension SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1514419600000000, 1515024000000000], "device": [-9223372036854775808, 1073741823], "time2": [1514419600000000, 1515024000000000]}'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: invalid number of hypercube dimensions -- Bad dimension name SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1514419600000000, 1515024000000000], "dev": [-9223372036854775808, 1073741823]}'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: dimension "dev" does not exist in hypertable -- Same dimension twice SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1514419600000000, 1515024000000000], "time": [1514419600000000, 1515024000000000]}'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: invalid number of hypercube dimensions -- Bad bounds format SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": ["1514419200000000", 1515024000000000], "device": [-9223372036854775808, 1073741823]}'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: constraint for dimension "time" is not numeric -- Bad slices format SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1515024000000000], "device": [-9223372036854775808, 1073741823]}'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: unexpected number of dimensional bounds for dimension "time" -- Bad slices json SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time: [1515024000000000] "device": [-9223372036854775808, 1073741823]}'); ERROR: invalid input syntax for type json LINE 1: ...ROM _timescaledb_internal.create_chunk('chunkapi',' {"time: ... ^ DETAIL: Token "device" is invalid. CONTEXT: JSON data, line 1: {"time: [1515024000000000] "device... -- Valid chunk, but no permissions SET ROLE :ROLE_DEFAULT_PERM_USER_2; SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1515024000000000, 1519024000000000], "device": [-9223372036854775808, 1073741823]}', 'ChunkSchema', 'My_chunk_Table_name'); ERROR: permission denied for table "chunkapi" DETAIL: Insert privileges required on "chunkapi" to create chunks. \set ON_ERROR_STOP 1 SET ROLE :ROLE_DEFAULT_PERM_USER; -- Test create_chunk_table for errors \set ON_ERROR_STOP 0 -- Test create_chunk_table for NULL input SELECT * FROM _timescaledb_internal.create_chunk_table(NULL,' {"time": [1515024000000000, 1519024000000000], "device": [-9223372036854775808, 1073741823]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: hypertable cannot be NULL SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi', NULL, '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: slices cannot be NULL SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1515024000000000, 1519024000000000], "device": [-9223372036854775808, 1073741823]}', NULL,'_hyper_1_1_chunk'); ERROR: chunk schema name cannot be NULL SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1515024000000000, 1519024000000000], "device": [-9223372036854775808, 1073741823]}', '_timescaledb_internal',NULL); ERROR: chunk table name cannot be NULL -- Modified time constraint should fail with collision SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1514419600000000, 1515024000000000], "device": [-9223372036854775808, 1073741823]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: chunk table creation failed due to dimension slice collision -- Missing dimension SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1514419600000000, 1515024000000000]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: invalid number of hypercube dimensions -- Extra dimension SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1514419600000000, 1515024000000000], "device": [-9223372036854775808, 1073741823], "time2": [1514419600000000, 1515024000000000]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: invalid number of hypercube dimensions -- Bad dimension name SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1514419600000000, 1515024000000000], "dev": [-9223372036854775808, 1073741823]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: dimension "dev" does not exist in hypertable -- Same dimension twice SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1514419600000000, 1515024000000000], "time": [1514419600000000, 1515024000000000]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: invalid number of hypercube dimensions -- Bad bounds format SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": ["1514419200000000", 1515024000000000], "device": [-9223372036854775808, 1073741823]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: constraint for dimension "time" is not numeric -- Bad slices format SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1515024000000000], "device": [-9223372036854775808, 1073741823]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: invalid hypercube for hypertable "chunkapi" DETAIL: unexpected number of dimensional bounds for dimension "time" -- Bad slices json SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time: [1515024000000000] "device": [-9223372036854775808, 1073741823]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: invalid input syntax for type json LINE 1: ...imescaledb_internal.create_chunk_table('chunkapi',' {"time: ... ^ DETAIL: Token "device" is invalid. CONTEXT: JSON data, line 1: {"time: [1515024000000000] "device... -- Valid chunk, but no permissions SET ROLE :ROLE_DEFAULT_PERM_USER_2; SELECT * FROM _timescaledb_internal.create_chunk_table('chunkapi',' {"time": [1515024000000000, 1519024000000000], "device": [-9223372036854775808, 1073741823]}', '_timescaledb_internal','_hyper_1_1_chunk'); ERROR: permission denied for table "chunkapi" DETAIL: Insert privileges required on "chunkapi" to create chunks. \set ON_ERROR_STOP 1 -- Test that granting insert on tables allow create_chunk to be -- called. This will also create a chunk that does not collide and has -- a custom schema and name. SET ROLE :ROLE_SUPERUSER; GRANT INSERT ON chunkapi TO :ROLE_DEFAULT_PERM_USER_2; SET ROLE :ROLE_DEFAULT_PERM_USER_2; SELECT * FROM _timescaledb_internal.create_chunk('chunkapi',' {"time": [1515024000000000, 1519024000000000], "device": [-9223372036854775808, 1073741823]}', 'ChunkSchema', 'My_chunk_Table_name'); chunk_id | hypertable_id | schema_name | table_name | relkind | slices | created ----------+---------------+-------------+---------------------+---------+----------------------------------------------------------------------------------------------+--------- 2 | 1 | ChunkSchema | My_chunk_Table_name | r | {"time": [1515024000000000, 1519024000000000], "device": [-9223372036854775808, 1073741823]} | t (1 row) SET ROLE :ROLE_DEFAULT_PERM_USER; \set VERBOSITY terse SELECT (_timescaledb_internal.show_chunk(show_chunks)).* FROM show_chunks('chunkapi') ORDER BY chunk_id; chunk_id | hypertable_id | schema_name | table_name | relkind | slices ----------+---------------+-----------------------+---------------------+---------+---------------------------------------------------------------------------------------------- 1 | 1 | _timescaledb_internal | _hyper_1_1_chunk | r | {"time": [1514419200000000, 1515024000000000], "device": [-9223372036854775808, 1073741823]} 2 | 1 | ChunkSchema | My_chunk_Table_name | r | {"time": [1515024000000000, 1519024000000000], "device": [-9223372036854775808, 1073741823]} (2 rows) -- Show the new chunks \dt public.* List of relations Schema | Name | Type | Owner --------+----------+-------+------------------- public | chunkapi | table | default_perm_user (1 row) \dt "ChunkSchema".* List of relations Schema | Name | Type | Owner -------------+---------------------+-------+------------------- ChunkSchema | My_chunk_Table_name | table | default_perm_user (1 row) -- Make ANALYZE deterministic SELECT setseed(1); setseed --------- (1 row) -- Test getting relation stats for chunks. First get stats -- chunk-by-chunk. Note that the table isn't ANALYZED, so no stats -- present yet. SELECT (_timescaledb_internal.get_chunk_relstats(show_chunks)).* FROM show_chunks('chunkapi') ORDER BY chunk_id; chunk_id | hypertable_id | num_pages | num_tuples | num_allvisible ----------+---------------+-----------+------------+---------------- 1 | 1 | 0 | 0 | 0 2 | 1 | 0 | 0 | 0 (2 rows) SELECT (_timescaledb_internal.get_chunk_colstats(show_chunks)).* FROM show_chunks('chunkapi') ORDER BY chunk_id; chunk_id | hypertable_id | att_num | nullfrac | width | distinctval | slotkind | slotopstrings | slotcollations | slot1numbers | slot2numbers | slot3numbers | slot4numbers | slot5numbers | slotvaluetypetrings | slot1values | slot2values | slot3values | slot4values | slot5values ----------+---------------+---------+----------+-------+-------------+----------+---------------+----------------+--------------+--------------+--------------+--------------+--------------+---------------------+-------------+-------------+-------------+-------------+------------- (0 rows) -- Get the same stats but by giving the hypertable as input SELECT * FROM _timescaledb_internal.get_chunk_relstats('chunkapi'); chunk_id | hypertable_id | num_pages | num_tuples | num_allvisible ----------+---------------+-----------+------------+---------------- 1 | 1 | 0 | 0 | 0 2 | 1 | 0 | 0 | 0 (2 rows) SELECT * FROM _timescaledb_internal.get_chunk_colstats('chunkapi'); chunk_id | hypertable_id | att_num | nullfrac | width | distinctval | slotkind | slotopstrings | slotcollations | slot1numbers | slot2numbers | slot3numbers | slot4numbers | slot5numbers | slotvaluetypetrings | slot1values | slot2values | slot3values | slot4values | slot5values ----------+---------------+---------+----------+-------+-------------+----------+---------------+----------------+--------------+--------------+--------------+--------------+--------------+---------------------+-------------+-------------+-------------+-------------+------------- (0 rows) -- reltuples is -1 on PG14 when no VACUUM/ANALYZE has run yet SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('chunkapi')) ORDER BY relname; relname | reltuples | relpages | relallvisible ---------------------+-----------+----------+--------------- My_chunk_Table_name | 0 | 0 | 0 _hyper_1_1_chunk | 0 | 0 | 0 (2 rows) SELECT tablename, attname, inherited, null_frac, avg_width, n_distinct FROM pg_stats WHERE tablename IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('chunkapi')) ORDER BY tablename, attname; tablename | attname | inherited | null_frac | avg_width | n_distinct -----------+---------+-----------+-----------+-----------+------------ (0 rows) -- Show stats after analyze ANALYZE chunkapi; SELECT * FROM _timescaledb_internal.get_chunk_relstats('chunkapi'); chunk_id | hypertable_id | num_pages | num_tuples | num_allvisible ----------+---------------+-----------+------------+---------------- 1 | 1 | 1 | 1 | 0 2 | 1 | 0 | 0 | 0 (2 rows) SELECT * FROM _timescaledb_internal.get_chunk_colstats('chunkapi'); chunk_id | hypertable_id | att_num | nullfrac | width | distinctval | slotkind | slotopstrings | slotcollations | slot1numbers | slot2numbers | slot3numbers | slot4numbers | slot5numbers | slotvaluetypetrings | slot1values | slot2values | slot3values | slot4values | slot5values ----------+---------------+---------+----------+-------+-------------+-------------+---------------+----------------+--------------+--------------+--------------+--------------+--------------+---------------------+-------------+-------------+-------------+-------------+------------- 1 | 1 | 1 | 0 | 8 | -1 | {0,0,0,0,0} | {} | {0,0,0,0,0} | | | | | | {} | | | | | 1 | 1 | 2 | 0 | 4 | -1 | {0,0,0,0,0} | {} | {0,0,0,0,0} | | | | | | {} | | | | | 1 | 1 | 3 | 0 | 8 | -1 | {0,0,0,0,0} | {} | {0,0,0,0,0} | | | | | | {} | | | | | (3 rows) SELECT relname, reltuples, relpages, relallvisible FROM pg_class WHERE relname IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('chunkapi')) ORDER BY relname; relname | reltuples | relpages | relallvisible ---------------------+-----------+----------+--------------- My_chunk_Table_name | 0 | 0 | 0 _hyper_1_1_chunk | 1 | 1 | 0 (2 rows) SELECT tablename, attname, inherited, null_frac, avg_width, n_distinct FROM pg_stats WHERE tablename IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('chunkapi')) ORDER BY tablename, attname; tablename | attname | inherited | null_frac | avg_width | n_distinct ------------------+---------+-----------+-----------+-----------+------------ _hyper_1_1_chunk | device | f | 0 | 4 | -1 _hyper_1_1_chunk | temp | f | 0 | 8 | -1 _hyper_1_1_chunk | time | f | 0 | 8 | -1 (3 rows) -- Test getting chunk stats on a distribute hypertable SET ROLE :ROLE_CLUSTER_SUPERUSER; SELECT * FROM add_data_node('data_node_1', host => 'localhost', database => :'DN_DBNAME_1'); node_name | host | port | database | node_created | database_created | extension_created -------------+-----------+-------+----------------+--------------+------------------+------------------- data_node_1 | localhost | 55432 | db_chunk_api_1 | t | t | t (1 row) SELECT * FROM add_data_node('data_node_2', host => 'localhost', database => :'DN_DBNAME_2'); node_name | host | port | database | node_created | database_created | extension_created -------------+-----------+-------+----------------+--------------+------------------+------------------- data_node_2 | localhost | 55432 | db_chunk_api_2 | t | t | t (1 row) GRANT USAGE ON FOREIGN SERVER data_node_1, data_node_2 TO :ROLE_1, :ROLE_DEFAULT_PERM_USER; SET ROLE :ROLE_1; CREATE TABLE disttable (time timestamptz, device int, temp float, color text); SELECT * FROM create_distributed_hypertable('disttable', 'time', 'device'); NOTICE: adding not-null constraint to column "time" hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 2 | public | disttable | t (1 row) INSERT INTO disttable VALUES ('2018-01-01 05:00:00-8', 1, 23.4, 'green'), ('2018-01-01 06:00:00-8', 4, 22.3, NULL), ('2018-01-01 06:00:00-8', 1, 21.1, 'green'); -- Make sure we get deterministic behavior across all nodes CALL distributed_exec($$ SELECT setseed(1); $$); -- No stats on the local table SELECT * FROM _timescaledb_internal.get_chunk_relstats('disttable'); chunk_id | hypertable_id | num_pages | num_tuples | num_allvisible ----------+---------------+-----------+------------+---------------- 3 | 2 | 0 | 0 | 0 4 | 2 | 0 | 0 | 0 (2 rows) SELECT * FROM _timescaledb_internal.get_chunk_colstats('disttable'); chunk_id | hypertable_id | att_num | nullfrac | width | distinctval | slotkind | slotopstrings | slotcollations | slot1numbers | slot2numbers | slot3numbers | slot4numbers | slot5numbers | slotvaluetypetrings | slot1values | slot2values | slot3values | slot4values | slot5values ----------+---------------+---------+----------+-------+-------------+----------+---------------+----------------+--------------+--------------+--------------+--------------+--------------+---------------------+-------------+-------------+-------------+-------------+------------- (0 rows) SELECT relname, reltuples, relpages, relallvisible FROM pg_class WHERE relname IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('disttable')) ORDER BY relname; relname | reltuples | relpages | relallvisible -----------------------+-----------+----------+--------------- _dist_hyper_2_3_chunk | 0 | 0 | 0 _dist_hyper_2_4_chunk | 0 | 0 | 0 (2 rows) SELECT * FROM pg_stats WHERE tablename IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('disttable')) ORDER BY 1,2,3; schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram ------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+---------------------- (0 rows) -- Run ANALYZE on data node 1 CALL distributed_exec('ANALYZE disttable', '{ "data_node_1" }'); -- Stats should now be refreshed after running get_chunk_{col,rel}stats SELECT relname, reltuples, relpages, relallvisible FROM pg_class WHERE relname IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('disttable')) ORDER BY relname; relname | reltuples | relpages | relallvisible -----------------------+-----------+----------+--------------- _dist_hyper_2_3_chunk | 0 | 0 | 0 _dist_hyper_2_4_chunk | 0 | 0 | 0 (2 rows) SELECT * FROM pg_stats WHERE tablename IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('disttable')) ORDER BY 1,2,3; schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram ------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+---------------------- (0 rows) SELECT * FROM _timescaledb_internal.get_chunk_relstats('disttable'); chunk_id | hypertable_id | num_pages | num_tuples | num_allvisible ----------+---------------+-----------+------------+---------------- 3 | 2 | 1 | 2 | 0 4 | 2 | 0 | 0 | 0 (2 rows) SELECT * FROM _timescaledb_internal.get_chunk_colstats('disttable'); chunk_id | hypertable_id | att_num | nullfrac | width | distinctval | slotkind | slotopstrings | slotcollations | slot1numbers | slot2numbers | slot3numbers | slot4numbers | slot5numbers | slotvaluetypetrings | slot1values | slot2values | slot3values | slot4values | slot5values ----------+---------------+---------+----------+-------+-------------+-------------+-------------------------------------------------------------------------------------------------------------------------+-----------------+--------------+--------------+--------------+--------------+--------------+--------------------------+-----------------------------------------------------------------+-------------+-------------+-------------+------------- 3 | 2 | 1 | 0 | 8 | -1 | {2,3,0,0,0} | {<,pg_catalog,timestamptz,pg_catalog,timestamptz,pg_catalog,<,pg_catalog,timestamptz,pg_catalog,timestamptz,pg_catalog} | {0,0,0,0,0} | | {1} | | | | {timestamptz,pg_catalog} | {"Mon Jan 01 05:00:00 2018 PST","Mon Jan 01 06:00:00 2018 PST"} | | | | 3 | 2 | 2 | 0 | 4 | -0.5 | {1,3,0,0,0} | {=,pg_catalog,int4,pg_catalog,int4,pg_catalog,<,pg_catalog,int4,pg_catalog,int4,pg_catalog} | {0,0,0,0,0} | {1} | {1} | | | | {int4,pg_catalog} | {1} | | | | 3 | 2 | 3 | 0 | 8 | -1 | {2,3,0,0,0} | {<,pg_catalog,float8,pg_catalog,float8,pg_catalog,<,pg_catalog,float8,pg_catalog,float8,pg_catalog} | {0,0,0,0,0} | | {-1} | | | | {float8,pg_catalog} | {21.1,23.4} | | | | 3 | 2 | 4 | 0 | 6 | -0.5 | {1,3,0,0,0} | {=,pg_catalog,text,pg_catalog,text,pg_catalog,<,pg_catalog,text,pg_catalog,text,pg_catalog} | {100,100,0,0,0} | {1} | {1} | | | | {text,pg_catalog} | {green} | | | | (4 rows) SELECT relname, reltuples, relpages, relallvisible FROM pg_class WHERE relname IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('disttable')) ORDER BY relname; relname | reltuples | relpages | relallvisible -----------------------+-----------+----------+--------------- _dist_hyper_2_3_chunk | 2 | 1 | 0 _dist_hyper_2_4_chunk | 0 | 0 | 0 (2 rows) SELECT * FROM pg_stats WHERE tablename IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('disttable')) ORDER BY 1,2,3; schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram -----------------------+-----------------------+---------+-----------+-----------+-----------+------------+------------------+-------------------+-----------------------------------------------------------------+-------------+-------------------+------------------------+---------------------- _timescaledb_internal | _dist_hyper_2_3_chunk | color | f | 0 | 6 | -0.5 | {green} | {1} | | 1 | | | _timescaledb_internal | _dist_hyper_2_3_chunk | device | f | 0 | 4 | -0.5 | {1} | {1} | | 1 | | | _timescaledb_internal | _dist_hyper_2_3_chunk | temp | f | 0 | 8 | -1 | | | {21.1,23.4} | -1 | | | _timescaledb_internal | _dist_hyper_2_3_chunk | time | f | 0 | 8 | -1 | | | {"Mon Jan 01 05:00:00 2018 PST","Mon Jan 01 06:00:00 2018 PST"} | 1 | | | (4 rows) -- Test that user without table permissions can't get column stats SET ROLE :ROLE_DEFAULT_PERM_USER; SELECT * FROM _timescaledb_internal.get_chunk_colstats('disttable'); chunk_id | hypertable_id | att_num | nullfrac | width | distinctval | slotkind | slotopstrings | slotcollations | slot1numbers | slot2numbers | slot3numbers | slot4numbers | slot5numbers | slotvaluetypetrings | slot1values | slot2values | slot3values | slot4values | slot5values ----------+---------------+---------+----------+-------+-------------+----------+---------------+----------------+--------------+--------------+--------------+--------------+--------------+---------------------+-------------+-------------+-------------+-------------+------------- (0 rows) SET ROLE :ROLE_1; -- Run ANALYZE again, but on both nodes. ANALYZE disttable; -- Now expect stats from all data node chunks SELECT * FROM _timescaledb_internal.get_chunk_relstats('disttable'); chunk_id | hypertable_id | num_pages | num_tuples | num_allvisible ----------+---------------+-----------+------------+---------------- 3 | 2 | 1 | 2 | 0 4 | 2 | 1 | 1 | 0 (2 rows) SELECT * FROM _timescaledb_internal.get_chunk_colstats('disttable'); chunk_id | hypertable_id | att_num | nullfrac | width | distinctval | slotkind | slotopstrings | slotcollations | slot1numbers | slot2numbers | slot3numbers | slot4numbers | slot5numbers | slotvaluetypetrings | slot1values | slot2values | slot3values | slot4values | slot5values ----------+---------------+---------+----------+-------+-------------+-------------+-------------------------------------------------------------------------------------------------------------------------+-----------------+--------------+--------------+--------------+--------------+--------------+--------------------------+-----------------------------------------------------------------+-------------+-------------+-------------+------------- 3 | 2 | 1 | 0 | 8 | -1 | {2,3,0,0,0} | {<,pg_catalog,timestamptz,pg_catalog,timestamptz,pg_catalog,<,pg_catalog,timestamptz,pg_catalog,timestamptz,pg_catalog} | {0,0,0,0,0} | | {1} | | | | {timestamptz,pg_catalog} | {"Mon Jan 01 05:00:00 2018 PST","Mon Jan 01 06:00:00 2018 PST"} | | | | 3 | 2 | 2 | 0 | 4 | -0.5 | {1,3,0,0,0} | {=,pg_catalog,int4,pg_catalog,int4,pg_catalog,<,pg_catalog,int4,pg_catalog,int4,pg_catalog} | {0,0,0,0,0} | {1} | {1} | | | | {int4,pg_catalog} | {1} | | | | 3 | 2 | 3 | 0 | 8 | -1 | {2,3,0,0,0} | {<,pg_catalog,float8,pg_catalog,float8,pg_catalog,<,pg_catalog,float8,pg_catalog,float8,pg_catalog} | {0,0,0,0,0} | | {-1} | | | | {float8,pg_catalog} | {21.1,23.4} | | | | 3 | 2 | 4 | 0 | 6 | -0.5 | {1,3,0,0,0} | {=,pg_catalog,text,pg_catalog,text,pg_catalog,<,pg_catalog,text,pg_catalog,text,pg_catalog} | {100,100,0,0,0} | {1} | {1} | | | | {text,pg_catalog} | {green} | | | | 4 | 2 | 1 | 0 | 8 | -1 | {0,0,0,0,0} | {} | {0,0,0,0,0} | | | | | | {} | | | | | 4 | 2 | 2 | 0 | 4 | -1 | {0,0,0,0,0} | {} | {0,0,0,0,0} | | | | | | {} | | | | | 4 | 2 | 3 | 0 | 8 | -1 | {0,0,0,0,0} | {} | {0,0,0,0,0} | | | | | | {} | | | | | 4 | 2 | 4 | 1 | 0 | 0 | {0,0,0,0,0} | {} | {0,0,0,0,0} | | | | | | {} | | | | | (8 rows) -- Test ANALYZE with a replica chunk. We'd like to ensure the -- stats-fetching functions handle duplicate stats from different (but -- identical) replica chunks. SELECT set_replication_factor('disttable', 2); WARNING: hypertable "disttable" is under-replicated set_replication_factor ------------------------ (1 row) INSERT INTO disttable VALUES ('2019-01-01 05:00:00-8', 1, 23.4, 'green'); -- Run twice to test that stats-fetching functions handle replica chunks. ANALYZE disttable; ANALYZE disttable; SELECT relname, reltuples, relpages, relallvisible FROM pg_class WHERE relname IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('disttable')) ORDER BY relname; relname | reltuples | relpages | relallvisible -----------------------+-----------+----------+--------------- _dist_hyper_2_3_chunk | 2 | 1 | 0 _dist_hyper_2_4_chunk | 1 | 1 | 0 _dist_hyper_2_5_chunk | 1 | 1 | 0 (3 rows) SELECT * FROM pg_stats WHERE tablename IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('disttable')) ORDER BY 1,2,3; schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram -----------------------+-----------------------+---------+-----------+-----------+-----------+------------+------------------+-------------------+-----------------------------------------------------------------+-------------+-------------------+------------------------+---------------------- _timescaledb_internal | _dist_hyper_2_3_chunk | color | f | 0 | 6 | -0.5 | {green} | {1} | | 1 | | | _timescaledb_internal | _dist_hyper_2_3_chunk | device | f | 0 | 4 | -0.5 | {1} | {1} | | 1 | | | _timescaledb_internal | _dist_hyper_2_3_chunk | temp | f | 0 | 8 | -1 | | | {21.1,23.4} | -1 | | | _timescaledb_internal | _dist_hyper_2_3_chunk | time | f | 0 | 8 | -1 | | | {"Mon Jan 01 05:00:00 2018 PST","Mon Jan 01 06:00:00 2018 PST"} | 1 | | | _timescaledb_internal | _dist_hyper_2_4_chunk | color | f | 1 | 0 | 0 | | | | | | | _timescaledb_internal | _dist_hyper_2_4_chunk | device | f | 0 | 4 | -1 | | | | | | | _timescaledb_internal | _dist_hyper_2_4_chunk | temp | f | 0 | 8 | -1 | | | | | | | _timescaledb_internal | _dist_hyper_2_4_chunk | time | f | 0 | 8 | -1 | | | | | | | _timescaledb_internal | _dist_hyper_2_5_chunk | color | f | 0 | 6 | -1 | | | | | | | _timescaledb_internal | _dist_hyper_2_5_chunk | device | f | 0 | 4 | -1 | | | | | | | _timescaledb_internal | _dist_hyper_2_5_chunk | temp | f | 0 | 8 | -1 | | | | | | | _timescaledb_internal | _dist_hyper_2_5_chunk | time | f | 0 | 8 | -1 | | | | | | | (12 rows) -- Check underlying pg_statistics table (looking at all columns except -- starelid, which changes depending on how many tests are run before -- this) RESET ROLE; SELECT ch, staattnum, stainherit, stanullfrac, stawidth, stadistinct, stakind1, stakind2, stakind3, stakind4, stakind5, staop1, staop2, staop3, staop4, staop5, stanumbers1, stanumbers2, stanumbers3, stanumbers4, stanumbers5, stavalues1, stavalues2, stavalues3, stavalues4, stavalues5 FROM pg_statistic st, show_chunks('disttable') ch WHERE st.starelid = ch ORDER BY ch, staattnum; ch | staattnum | stainherit | stanullfrac | stawidth | stadistinct | stakind1 | stakind2 | stakind3 | stakind4 | stakind5 | staop1 | staop2 | staop3 | staop4 | staop5 | stanumbers1 | stanumbers2 | stanumbers3 | stanumbers4 | stanumbers5 | stavalues1 | stavalues2 | stavalues3 | stavalues4 | stavalues5 ---------------------------------------------+-----------+------------+-------------+----------+-------------+----------+----------+----------+----------+----------+--------+--------+--------+--------+--------+-------------+-------------+-------------+-------------+-------------+-----------------------------------------------------------------+------------+------------+------------+------------ _timescaledb_internal._dist_hyper_2_3_chunk | 1 | f | 0 | 8 | -1 | 2 | 3 | 0 | 0 | 0 | 1322 | 1322 | 0 | 0 | 0 | | {1} | | | | {"Mon Jan 01 05:00:00 2018 PST","Mon Jan 01 06:00:00 2018 PST"} | | | | _timescaledb_internal._dist_hyper_2_3_chunk | 2 | f | 0 | 4 | -0.5 | 1 | 3 | 0 | 0 | 0 | 96 | 97 | 0 | 0 | 0 | {1} | {1} | | | | {1} | | | | _timescaledb_internal._dist_hyper_2_3_chunk | 3 | f | 0 | 8 | -1 | 2 | 3 | 0 | 0 | 0 | 672 | 672 | 0 | 0 | 0 | | {-1} | | | | {21.1,23.4} | | | | _timescaledb_internal._dist_hyper_2_3_chunk | 4 | f | 0 | 6 | -0.5 | 1 | 3 | 0 | 0 | 0 | 98 | 664 | 0 | 0 | 0 | {1} | {1} | | | | {green} | | | | _timescaledb_internal._dist_hyper_2_4_chunk | 1 | f | 0 | 8 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | _timescaledb_internal._dist_hyper_2_4_chunk | 2 | f | 0 | 4 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | _timescaledb_internal._dist_hyper_2_4_chunk | 3 | f | 0 | 8 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | _timescaledb_internal._dist_hyper_2_4_chunk | 4 | f | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk | 1 | f | 0 | 8 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk | 2 | f | 0 | 4 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk | 3 | f | 0 | 8 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk | 4 | f | 0 | 6 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | (12 rows) SELECT test.remote_exec(NULL, $$ SELECT ch, staattnum, stainherit, stanullfrac, stawidth, stadistinct, stakind1, stakind2, stakind3, stakind4, stakind5, staop1, staop2, staop3, staop4, staop5, stanumbers1, stanumbers2, stanumbers3, stanumbers4, stanumbers5, stavalues1, stavalues2, stavalues3, stavalues4, stavalues5 FROM pg_statistic st, show_chunks('disttable') ch WHERE st.starelid = ch ORDER BY ch, staattnum; $$); NOTICE: [data_node_1]: SELECT ch, staattnum, stainherit, stanullfrac, stawidth, stadistinct, stakind1, stakind2, stakind3, stakind4, stakind5, staop1, staop2, staop3, staop4, staop5, stanumbers1, stanumbers2, stanumbers3, stanumbers4, stanumbers5, stavalues1, stavalues2, stavalues3, stavalues4, stavalues5 FROM pg_statistic st, show_chunks('disttable') ch WHERE st.starelid = ch ORDER BY ch, staattnum NOTICE: [data_node_1]: ch |staattnum|stainherit|stanullfrac|stawidth|stadistinct|stakind1|stakind2|stakind3|stakind4|stakind5|staop1|staop2|staop3|staop4|staop5|stanumbers1|stanumbers2|stanumbers3|stanumbers4|stanumbers5|stavalues1 |stavalues2|stavalues3|stavalues4|stavalues5 -------------------------------------------+---------+----------+-----------+--------+-----------+--------+--------+--------+--------+--------+------+------+------+------+------+-----------+-----------+-----------+-----------+-----------+---------------------------------------------------------------+----------+----------+----------+---------- _timescaledb_internal._dist_hyper_2_3_chunk| 1|f | 0| 8| -1| 2| 3| 0| 0| 0| 1322| 1322| 0| 0| 0| |{1} | | | |{"Mon Jan 01 05:00:00 2018 PST","Mon Jan 01 06:00:00 2018 PST"}| | | | _timescaledb_internal._dist_hyper_2_3_chunk| 2|f | 0| 4| -0.5| 1| 3| 0| 0| 0| 96| 97| 0| 0| 0|{1} |{1} | | | |{1} | | | | _timescaledb_internal._dist_hyper_2_3_chunk| 3|f | 0| 8| -1| 2| 3| 0| 0| 0| 672| 672| 0| 0| 0| |{-1} | | | |{21.1,23.4} | | | | _timescaledb_internal._dist_hyper_2_3_chunk| 4|f | 0| 6| -0.5| 1| 3| 0| 0| 0| 98| 664| 0| 0| 0|{1} |{1} | | | |{green} | | | | _timescaledb_internal._dist_hyper_2_5_chunk| 1|f | 0| 8| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk| 2|f | 0| 4| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk| 3|f | 0| 8| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk| 4|f | 0| 6| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | (8 rows) NOTICE: [data_node_2]: SELECT ch, staattnum, stainherit, stanullfrac, stawidth, stadistinct, stakind1, stakind2, stakind3, stakind4, stakind5, staop1, staop2, staop3, staop4, staop5, stanumbers1, stanumbers2, stanumbers3, stanumbers4, stanumbers5, stavalues1, stavalues2, stavalues3, stavalues4, stavalues5 FROM pg_statistic st, show_chunks('disttable') ch WHERE st.starelid = ch ORDER BY ch, staattnum NOTICE: [data_node_2]: ch |staattnum|stainherit|stanullfrac|stawidth|stadistinct|stakind1|stakind2|stakind3|stakind4|stakind5|staop1|staop2|staop3|staop4|staop5|stanumbers1|stanumbers2|stanumbers3|stanumbers4|stanumbers5|stavalues1|stavalues2|stavalues3|stavalues4|stavalues5 -------------------------------------------+---------+----------+-----------+--------+-----------+--------+--------+--------+--------+--------+------+------+------+------+------+-----------+-----------+-----------+-----------+-----------+----------+----------+----------+----------+---------- _timescaledb_internal._dist_hyper_2_4_chunk| 1|f | 0| 8| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_4_chunk| 2|f | 0| 4| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_4_chunk| 3|f | 0| 8| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_4_chunk| 4|f | 1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk| 1|f | 0| 8| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk| 2|f | 0| 4| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk| 3|f | 0| 8| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | _timescaledb_internal._dist_hyper_2_5_chunk| 4|f | 0| 6| -1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| | | | | | | | | | (8 rows) remote_exec ------------- (1 row) -- Clean up RESET ROLE; TRUNCATE disttable; TRUNCATE costtable; SELECT * FROM delete_data_node('data_node_1', force => true); WARNING: insufficient number of data nodes for distributed hypertable "disttable" NOTICE: the number of partitions in dimension "device" was decreased to 1 delete_data_node ------------------ t (1 row) SELECT * FROM delete_data_node('data_node_2', force => true); WARNING: insufficient number of data nodes for distributed hypertable "disttable" delete_data_node ------------------ t (1 row) DROP DATABASE :DN_DBNAME_1; DROP DATABASE :DN_DBNAME_2; -- Test create_chunk_table to recreate the chunk table and show dimension slices SET ROLE :ROLE_DEFAULT_PERM_USER; SELECT * FROM chunkapi ORDER BY time; time | device | temp ------------------------------+--------+------ Mon Jan 01 05:00:00 2018 PST | 1 | 23.4 (1 row) SELECT chunk_schema AS "CHUNK_SCHEMA", chunk_name AS "CHUNK_NAME" FROM timescaledb_information.chunks c ORDER BY chunk_name DESC LIMIT 1 \gset SELECT slices AS "SLICES" FROM _timescaledb_internal.show_chunk(:'CHUNK_SCHEMA'||'.'||:'CHUNK_NAME') \gset SELECT relname FROM pg_catalog.pg_inherits, pg_class WHERE inhrelid = (:'CHUNK_SCHEMA'||'.'||:'CHUNK_NAME')::regclass AND inhparent = oid; relname ---------- chunkapi (1 row) SELECT * FROM _timescaledb_catalog.dimension_slice ORDER BY id; id | dimension_id | range_start | range_end ----+--------------+----------------------+------------------ 1 | 1 | 1514419200000000 | 1515024000000000 2 | 2 | -9223372036854775808 | 1073741823 3 | 1 | 1515024000000000 | 1519024000000000 (3 rows) DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; SELECT * FROM _timescaledb_catalog.dimension_slice ORDER BY id; id | dimension_id | range_start | range_end ----+--------------+----------------------+------------------ 2 | 2 | -9223372036854775808 | 1073741823 3 | 1 | 1515024000000000 | 1519024000000000 (2 rows) SELECT count(*) FROM _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); count ------- 1 (1 row) SELECT * FROM _timescaledb_catalog.dimension_slice ORDER BY id; id | dimension_id | range_start | range_end ----+--------------+----------------------+------------------ 2 | 2 | -9223372036854775808 | 1073741823 3 | 1 | 1515024000000000 | 1519024000000000 (2 rows) SELECT relname FROM pg_catalog.pg_inherits, pg_class WHERE inhrelid = (:'CHUNK_SCHEMA'||'.'||:'CHUNK_NAME')::regclass AND inhparent = oid; relname --------- (0 rows) -- Test that creat_chunk fails since chunk table already exists \set ON_ERROR_STOP 0 SELECT * FROM _timescaledb_internal.create_chunk('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); ERROR: relation "_hyper_1_1_chunk" already exists \set ON_ERROR_STOP 1 -- Test create_chunk_table on a hypertable where the chunk didn't exist before DROP TABLE chunkapi; DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; CREATE TABLE chunkapi (time timestamptz, device int, temp float); SELECT * FROM create_hypertable('chunkapi', 'time', 'device', 2); NOTICE: adding not-null constraint to column "time" hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 3 | public | chunkapi | t (1 row) SELECT count(*) FROM _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); count ------- 1 (1 row) -- Demonstrate that current settings for dimensions don't affect create_chunk_table DROP TABLE chunkapi; DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; CREATE TABLE chunkapi (time timestamptz not null, device int, temp float); SELECT * FROM create_hypertable('chunkapi', 'time', 'device', 2, '3d'); hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 4 | public | chunkapi | t (1 row) SELECT count(*) FROM _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); count ------- 1 (1 row) DROP TABLE chunkapi; DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; CREATE TABLE chunkapi (time timestamptz not null, device int, temp float); SELECT * FROM create_hypertable('chunkapi', 'time', 'device', 3); hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 5 | public | chunkapi | t (1 row) SELECT count(*) FROM _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); count ------- 1 (1 row) -- Test create_chunk_table if a colliding chunk exists DROP TABLE chunkapi; DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; CREATE TABLE chunkapi (time timestamptz not null, device int, temp float); SELECT * FROM create_hypertable('chunkapi', 'time', 'device', 3); hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 6 | public | chunkapi | t (1 row) INSERT INTO chunkapi VALUES ('2018-01-01 05:00:00-8', 1, 23.4); \set ON_ERROR_STOP 0 SELECT _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); ERROR: chunk table creation failed due to dimension slice collision \set ON_ERROR_STOP 1 -- Test create_chunk_table when a chunk exists in different space partition and thus doesn't collide DROP TABLE chunkapi; CREATE TABLE chunkapi (time timestamptz not null, device int, temp float); SELECT * FROM create_hypertable('chunkapi', 'time', 'device', 2); hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 7 | public | chunkapi | t (1 row) INSERT INTO chunkapi VALUES ('2018-01-01 05:00:00-8', 2, 23.4); SELECT _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); create_chunk_table -------------------- t (1 row) -- Test create_chunk_table when a chunk exists in different time partition and thus doesn't collide DROP TABLE chunkapi; DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; CREATE TABLE chunkapi (time timestamptz not null, device int, temp float); SELECT * FROM create_hypertable('chunkapi', 'time', 'device', 2); hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 8 | public | chunkapi | t (1 row) INSERT INTO chunkapi VALUES ('2018-02-01 05:00:00-8', 1, 23.4); SELECT _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); create_chunk_table -------------------- t (1 row) -- Test create_chunk_table with tablespaces \c :TEST_DBNAME :ROLE_SUPERUSER SET client_min_messages = ERROR; DROP TABLESPACE IF EXISTS tablespace1; DROP TABLESPACE IF EXISTS tablespace2; SET client_min_messages = NOTICE; CREATE TABLESPACE tablespace1 OWNER :ROLE_DEFAULT_PERM_USER LOCATION :TEST_TABLESPACE1_PATH; CREATE TABLESPACE tablespace2 OWNER :ROLE_DEFAULT_PERM_USER LOCATION :TEST_TABLESPACE2_PATH; \c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER -- Use the space partition to calculate the tablespace id to use DROP TABLE chunkapi; DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; CREATE TABLE chunkapi (time timestamptz not null, device int, temp float); SELECT * FROM create_hypertable('chunkapi', 'time', 'device', 3); hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 9 | public | chunkapi | t (1 row) SELECT attach_tablespace('tablespace1', 'chunkapi'); attach_tablespace ------------------- (1 row) SELECT attach_tablespace('tablespace2', 'chunkapi'); attach_tablespace ------------------- (1 row) SELECT count(*) FROM _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); count ------- 1 (1 row) SELECT tablespace FROM pg_tables WHERE tablename = :'CHUNK_NAME'; tablespace ------------- tablespace1 (1 row) -- Use the time partition to calculate the tablespace id to use DROP TABLE chunkapi; DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; CREATE TABLE devices (id int PRIMARY KEY); INSERT INTO devices VALUES (1); CREATE TABLE chunkapi (time timestamptz NOT NULL PRIMARY KEY, device int REFERENCES devices(id), temp float CHECK (temp > 0)); SELECT * FROM create_hypertable('chunkapi', 'time'); hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 10 | public | chunkapi | t (1 row) INSERT INTO chunkapi VALUES ('2018-01-01 05:00:00-8', 1, 23.4); SELECT chunk_schema AS "CHUNK_SCHEMA", chunk_name AS "CHUNK_NAME" FROM timescaledb_information.chunks c ORDER BY chunk_name DESC LIMIT 1 \gset SELECT slices AS "SLICES" FROM _timescaledb_internal.show_chunk(:'CHUNK_SCHEMA'||'.'||:'CHUNK_NAME') \gset -- Save the constraints info in a table for later comparison CREATE TABLE original_chunk_constraints AS SELECT "Constraint", "Type", "Columns", "Index"::text, "Expr", "Deferrable", "Deferred", "Validated" FROM test.show_constraints(format('%I.%I', :'CHUNK_SCHEMA', :'CHUNK_NAME')::regclass); -- Save contraints metadata CREATE TABLE original_chunk_constraints_metadata AS SELECT chunk_id, dimension_slice_id, constraint_name, hypertable_constraint_name FROM _timescaledb_catalog.chunk_constraint con INNER JOIN _timescaledb_catalog.chunk ch ON (con.chunk_id = ch.id) WHERE ch.schema_name = :'CHUNK_SCHEMA' AND ch.table_name = :'CHUNK_NAME'; DROP TABLE :CHUNK_SCHEMA.:CHUNK_NAME; SELECT attach_tablespace('tablespace1', 'chunkapi'); attach_tablespace ------------------- (1 row) SELECT attach_tablespace('tablespace2', 'chunkapi'); attach_tablespace ------------------- (1 row) SELECT count(*) FROM _timescaledb_internal.create_chunk_table('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME'); count ------- 1 (1 row) SELECT tablespace FROM pg_tables WHERE tablename = :'CHUNK_NAME'; tablespace ------------- tablespace1 (1 row) -- Now create the complete chunk from the chunk table SELECT _timescaledb_internal.create_chunk('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME', format('%I.%I', :'CHUNK_SCHEMA', :'CHUNK_NAME')::regclass); create_chunk --------------------------------------------------------------------------------------------------------- (11,10,_timescaledb_internal,_hyper_10_10_chunk,r,"{""time"": [1514419200000000, 1515024000000000]}",t) (1 row) -- Compare original and new constraints SELECT * FROM original_chunk_constraints; Constraint | Type | Columns | Index | Expr | Deferrable | Deferred | Validated ---------------------------+------+----------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+------------+----------+----------- 10_1_chunkapi_device_fkey | f | {device} | devices_pkey | | f | f | t 10_2_chunkapi_pkey | p | {time} | _timescaledb_internal."10_2_chunkapi_pkey" | | f | f | t chunkapi_temp_check | c | {temp} | - | (temp > (0)::double precision) | f | f | t constraint_15 | c | {time} | - | (("time" >= 'Wed Dec 27 16:00:00 2017 PST'::timestamp with time zone) AND ("time" < 'Wed Jan 03 16:00:00 2018 PST'::timestamp with time zone)) | f | f | t (4 rows) SELECT * FROM test.show_constraints(format('%I.%I', :'CHUNK_SCHEMA', :'CHUNK_NAME')::regclass); Constraint | Type | Columns | Index | Expr | Deferrable | Deferred | Validated ---------------------------+------+----------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+------------+----------+----------- 11_3_chunkapi_device_fkey | f | {device} | devices_pkey | | f | f | t 11_4_chunkapi_pkey | p | {time} | _timescaledb_internal."11_4_chunkapi_pkey" | | f | f | t chunkapi_temp_check | c | {temp} | - | (temp > (0)::double precision) | f | f | t constraint_16 | c | {time} | - | (("time" >= 'Wed Dec 27 16:00:00 2017 PST'::timestamp with time zone) AND ("time" < 'Wed Jan 03 16:00:00 2018 PST'::timestamp with time zone)) | f | f | t (4 rows) -- Compare original and new chunk constraints metadata SELECT * FROM original_chunk_constraints_metadata; chunk_id | dimension_slice_id | constraint_name | hypertable_constraint_name ----------+--------------------+---------------------------+---------------------------- 10 | 15 | constraint_15 | 10 | | 10_1_chunkapi_device_fkey | chunkapi_device_fkey 10 | | 10_2_chunkapi_pkey | chunkapi_pkey (3 rows) SELECT chunk_id, dimension_slice_id, constraint_name, hypertable_constraint_name FROM _timescaledb_catalog.chunk_constraint con INNER JOIN _timescaledb_catalog.chunk ch ON (con.chunk_id = ch.id) WHERE ch.schema_name = :'CHUNK_SCHEMA' AND ch.table_name = :'CHUNK_NAME'; chunk_id | dimension_slice_id | constraint_name | hypertable_constraint_name ----------+--------------------+---------------------------+---------------------------- 11 | 16 | constraint_16 | 11 | | 11_3_chunkapi_device_fkey | chunkapi_device_fkey 11 | | 11_4_chunkapi_pkey | chunkapi_pkey (3 rows) DROP TABLE original_chunk_constraints; DROP TABLE original_chunk_constraints_metadata; -- The chunk should inherit the hypertable SELECT relname FROM pg_catalog.pg_inherits, pg_class WHERE inhrelid = (:'CHUNK_SCHEMA'||'.'||:'CHUNK_NAME')::regclass AND inhparent = oid; relname ---------- chunkapi (1 row) -- Show chunk's attached to the table SELECT :'CHUNK_SCHEMA' AS expected_schema, :'CHUNK_NAME' AS expected_table_name, (_timescaledb_internal.show_chunk(ch)).* FROM show_chunks('chunkapi') ch; expected_schema | expected_table_name | chunk_id | hypertable_id | schema_name | table_name | relkind | slices -----------------------+---------------------+----------+---------------+-----------------------+--------------------+---------+------------------------------------------------ _timescaledb_internal | _hyper_10_10_chunk | 11 | 10 | _timescaledb_internal | _hyper_10_10_chunk | r | {"time": [1514419200000000, 1515024000000000]} (1 row) DROP TABLE chunkapi; DROP TABLE devices; -- Test creating a chunk from an existing chunk table which was not -- created via create_chunk_table and having a different name. CREATE TABLE devices (id int PRIMARY KEY); INSERT INTO devices VALUES (1); CREATE TABLE chunkapi (time timestamptz NOT NULL PRIMARY KEY, device int REFERENCES devices(id), temp float CHECK(temp > 0)); SELECT * FROM create_hypertable('chunkapi', 'time'); hypertable_id | schema_name | table_name | created ---------------+-------------+------------+--------- 11 | public | chunkapi | t (1 row) CREATE TABLE newchunk (time timestamptz NOT NULL, device int, temp float); SELECT * FROM test.show_constraints('newchunk'); Constraint | Type | Columns | Index | Expr | Deferrable | Deferred | Validated ------------+------+---------+-------+------+------------+----------+----------- (0 rows) INSERT INTO newchunk VALUES ('2018-01-01 05:00:00-8', 1, 23.4); \set ON_ERROR_STOP 0 -- Creating the chunk without required CHECK constraints on a table -- should fail. Currently, PostgreSQL only enforces presence of CHECK -- constraints, but not foreign key, unique, or primary key -- constraints. We should probably add checks to enforce the latter -- too or auto-create all constraints. SELECT * FROM _timescaledb_internal.create_chunk('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME', 'newchunk'); ERROR: child table is missing constraint "chunkapi_temp_check" \set ON_ERROR_STOP 1 -- Add the missing CHECK constraint. Note that the name must be the -- same as on the parent table. ALTER TABLE newchunk ADD CONSTRAINT chunkapi_temp_check CHECK (temp > 0); SELECT * FROM _timescaledb_internal.create_chunk('chunkapi', :'SLICES', :'CHUNK_SCHEMA', :'CHUNK_NAME', 'newchunk'); chunk_id | hypertable_id | schema_name | table_name | relkind | slices | created ----------+---------------+-----------------------+--------------------+---------+------------------------------------------------+--------- 13 | 11 | _timescaledb_internal | _hyper_10_10_chunk | r | {"time": [1514419200000000, 1515024000000000]} | t (1 row) -- Show the chunk and that names are what we'd expect SELECT :'CHUNK_SCHEMA' AS expected_schema, :'CHUNK_NAME' AS expected_table_name, (_timescaledb_internal.show_chunk(ch)).* FROM show_chunks('chunkapi') ch; expected_schema | expected_table_name | chunk_id | hypertable_id | schema_name | table_name | relkind | slices -----------------------+---------------------+----------+---------------+-----------------------+--------------------+---------+------------------------------------------------ _timescaledb_internal | _hyper_10_10_chunk | 13 | 11 | _timescaledb_internal | _hyper_10_10_chunk | r | {"time": [1514419200000000, 1515024000000000]} (1 row) -- The chunk should inherit the hypertable SELECT relname FROM pg_catalog.pg_inherits, pg_class WHERE inhrelid = (:'CHUNK_SCHEMA'||'.'||:'CHUNK_NAME')::regclass AND inhparent = oid; relname ---------- chunkapi (1 row) -- Test that it is possible to query the data via the hypertable SELECT * FROM chunkapi ORDER BY 1,2,3; time | device | temp ------------------------------+--------+------ Mon Jan 01 05:00:00 2018 PST | 1 | 23.4 (1 row) -- Show that the chunk has all the necessary constraints. These -- include inheritable constraints and dimensional constraints, which -- are specific to the chunk. Currently, foreign key, unique, and -- primary key constraints are not inherited or auto-created. SELECT * FROM test.show_constraints(format('%I.%I', :'CHUNK_SCHEMA', :'CHUNK_NAME')::regclass); Constraint | Type | Columns | Index | Expr | Deferrable | Deferred | Validated ---------------------------+------+----------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+------------+----------+----------- 13_7_chunkapi_device_fkey | f | {device} | devices_pkey | | f | f | t 13_8_chunkapi_pkey | p | {time} | _timescaledb_internal."13_8_chunkapi_pkey" | | f | f | t chunkapi_temp_check | c | {temp} | - | (temp > (0)::double precision) | f | f | t constraint_18 | c | {time} | - | (("time" >= 'Wed Dec 27 16:00:00 2017 PST'::timestamp with time zone) AND ("time" < 'Wed Jan 03 16:00:00 2018 PST'::timestamp with time zone)) | f | f | t (4 rows) DROP TABLE chunkapi; \c :TEST_DBNAME :ROLE_SUPERUSER SET client_min_messages = ERROR; DROP TABLESPACE tablespace1; DROP TABLESPACE tablespace2; SET client_min_messages = NOTICE; \c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER