-- 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. \set ON_ERROR_STOP 0 \set VERBOSITY default --table with special column names -- create table foo2 (a integer, "bacB toD" integer, c integer, d integer); select table_name from create_hypertable('foo2', 'a', chunk_time_interval=> 10); NOTICE: adding not-null constraint to column "a" DETAIL: Time dimensions cannot have NULL values. table_name ------------ foo2 (1 row) create table foo3 (a integer, "bacB toD" integer, c integer, d integer); select table_name from create_hypertable('foo3', 'a', chunk_time_interval=> 10); NOTICE: adding not-null constraint to column "a" DETAIL: Time dimensions cannot have NULL values. table_name ------------ foo3 (1 row) create table non_compressed (a integer, "bacB toD" integer, c integer, d integer); select table_name from create_hypertable('non_compressed', 'a', chunk_time_interval=> 10); NOTICE: adding not-null constraint to column "a" DETAIL: Time dimensions cannot have NULL values. table_name ---------------- non_compressed (1 row) insert into non_compressed values( 3 , 16 , 20, 4); ALTER TABLE foo2 set (timescaledb.compress_segmentby = '"bacB toD",c' , timescaledb.compress_orderby = 'c'); ERROR: the option timescaledb.compress must be set to true to enable compression ALTER TABLE foo2 set (timescaledb.compress, timescaledb.compress_segmentby = '"bacB toD",c' , timescaledb.compress_orderby = 'c'); ERROR: cannot use column "c" for both ordering and segmenting HINT: Use separate columns for the timescaledb.compress_orderby and timescaledb.compress_segmentby options. ALTER TABLE foo2 set (timescaledb.compress, timescaledb.compress_segmentby = '"bacB toD",c' , timescaledb.compress_orderby = 'd DESC'); ALTER TABLE foo2 set (timescaledb.compress, timescaledb.compress_segmentby = '"bacB toD",c' , timescaledb.compress_orderby = 'd'); -- this is acceptable: having previously set the default value for orderby -- and skipping orderby on a subsequent alter command create table default_skipped (a integer not null, b integer, c integer, d integer); select create_hypertable('default_skipped', 'a', chunk_time_interval=> 10); create_hypertable ------------------------------ (6,public,default_skipped,t) (1 row) alter table default_skipped set (timescaledb.compress, timescaledb.compress_segmentby = 'c'); alter table default_skipped set (timescaledb.compress, timescaledb.compress_segmentby = 'c'); create table with_rls (a integer, b integer); ALTER TABLE with_rls ENABLE ROW LEVEL SECURITY; select table_name from create_hypertable('with_rls', 'a', chunk_time_interval=> 10); NOTICE: adding not-null constraint to column "a" DETAIL: Time dimensions cannot have NULL values. table_name ------------ with_rls (1 row) ALTER TABLE with_rls set (timescaledb.compress, timescaledb.compress_orderby='a'); ERROR: compression cannot be used on table with row security --note that the time column "a" should be added to the end of the orderby list select * from _timescaledb_catalog.hypertable_compression order by attname; hypertable_id | attname | compression_algorithm_id | segmentby_column_index | orderby_column_index | orderby_asc | orderby_nullsfirst ---------------+----------+--------------------------+------------------------+----------------------+-------------+-------------------- 1 | a | 4 | | 2 | f | t 6 | a | 4 | | 1 | f | t 6 | b | 4 | | | | 1 | bacB toD | 0 | 1 | | | 1 | c | 0 | 2 | | | 6 | c | 0 | 1 | | | 1 | d | 4 | | 1 | t | f 6 | d | 4 | | | | (8 rows) ALTER TABLE foo3 set (timescaledb.compress, timescaledb.compress_orderby='d DeSc NullS lAsT'); --shold allow alter since segment by was empty ALTER TABLE foo3 set (timescaledb.compress, timescaledb.compress_orderby='d Asc NullS lAsT'); --this is ok too ALTER TABLE foo3 set (timescaledb.compress, timescaledb.compress_segmentby = '"bacB toD",c', timescaledb.compress_orderby = 'd DeSc NullS lAsT'); -- Negative test cases --- ALTER TABLE foo2 set (timescaledb.compress, timescaledb.compress_segmentby = '"bacB toD",c'); ERROR: must specify a column to order by DETAIL: The timescaledb.compress_orderby option was previously set and must also be specified in the updated configuration. alter table default_skipped set (timescaledb.compress, timescaledb.compress_orderby = 'a asc', timescaledb.compress_segmentby = 'c'); alter table default_skipped set (timescaledb.compress, timescaledb.compress_segmentby = 'c'); ERROR: must specify a column to order by DETAIL: The timescaledb.compress_orderby option was previously set and must also be specified in the updated configuration. create table reserved_column_prefix (a integer, _ts_meta_foo integer, "bacB toD" integer, c integer, d integer); select table_name from create_hypertable('reserved_column_prefix', 'a', chunk_time_interval=> 10); NOTICE: adding not-null constraint to column "a" DETAIL: Time dimensions cannot have NULL values. table_name ------------------------ reserved_column_prefix (1 row) ALTER TABLE reserved_column_prefix set (timescaledb.compress); ERROR: cannot compress tables with reserved column prefix '_ts_meta_' --basic test with count create table foo (a integer, b integer, c integer, t text, p point); ALTER TABLE foo ADD CONSTRAINT chk_existing CHECK(b > 0); select table_name from create_hypertable('foo', 'a', chunk_time_interval=> 10); NOTICE: adding not-null constraint to column "a" DETAIL: Time dimensions cannot have NULL values. table_name ------------ foo (1 row) insert into foo values( 3 , 16 , 20); insert into foo values( 10 , 10 , 20); insert into foo values( 20 , 11 , 20); insert into foo values( 30 , 12 , 20); -- should error out -- ALTER TABLE foo ALTER b SET NOT NULL, set (timescaledb.compress); ERROR: ALTER TABLE SET does not support multiple clauses ALTER TABLE foo ALTER b SET NOT NULL; select attname, attnotnull from pg_attribute where attrelid = (select oid from pg_class where relname like 'foo') and attname like 'b'; attname | attnotnull ---------+------------ b | t (1 row) ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_segmentby = 'd'); ERROR: column "d" does not exist HINT: The timescaledb.compress_segmentby option must reference a valid column. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'd'); ERROR: column "d" does not exist HINT: The timescaledb.compress_orderby option must reference a valid column. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c desc nulls'); ERROR: unable to parse ordering option "c desc nulls" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c desc nulls thirsty'); ERROR: unable to parse ordering option "c desc nulls thirsty" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c climb nulls first'); ERROR: unable to parse ordering option "c climb nulls first" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c nulls first asC'); ERROR: unable to parse ordering option "c nulls first asC" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c desc nulls first asc'); ERROR: unable to parse ordering option "c desc nulls first asc" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c desc hurry'); ERROR: unable to parse ordering option "c desc hurry" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c descend'); ERROR: unable to parse ordering option "c descend" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c; SELECT 1'); ERROR: unable to parse ordering option "c; SELECT 1" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = '1,2'); ERROR: unable to parse ordering option "1,2" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c + 1'); ERROR: unable to parse ordering option "c + 1" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'random()'); ERROR: unable to parse ordering option "random()" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c LIMIT 1'); ERROR: unable to parse ordering option "c LIMIT 1" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'c USING <'); ERROR: unable to parse ordering option "c USING <" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 't COLLATE "en_US"'); ERROR: unable to parse ordering option "t COLLATE "en_US"" HINT: The timescaledb.compress_orderby option must be a set of column names with sort options, separated by commas. It is the same format as an ORDER BY clause. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_segmentby = 'c asc' , timescaledb.compress_orderby = 'c'); ERROR: unable to parse segmenting option "c asc" HINT: The option timescaledb.compress_segmentby must be a set of columns separated by commas. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_segmentby = 'c nulls last'); ERROR: unable to parse segmenting option "c nulls last" HINT: The option timescaledb.compress_segmentby must be a set of columns separated by commas. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_segmentby = 'c + 1'); ERROR: unable to parse segmenting option "c + 1" HINT: The option timescaledb.compress_segmentby must be a set of columns separated by commas. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_segmentby = 'random()'); ERROR: unable to parse segmenting option "random()" HINT: The option timescaledb.compress_segmentby must be a set of columns separated by commas. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_segmentby = 'c LIMIT 1'); ERROR: unable to parse segmenting option "c LIMIT 1" HINT: The option timescaledb.compress_segmentby must be a set of columns separated by commas. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_segmentby = 'c + b'); ERROR: unable to parse segmenting option "c + b" HINT: The option timescaledb.compress_segmentby must be a set of columns separated by commas. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'a, p'); ERROR: invalid ordering column type point DETAIL: Could not identify a less-than operator for the type. --should succeed ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'a, b'); --ddl on ht with compression ALTER TABLE foo DROP COLUMN a; ERROR: cannot drop column named in partition key DETAIL: Cannot drop column that is a hypertable partitioning (space or time) dimension. ALTER TABLE foo DROP COLUMN b; ERROR: cannot drop orderby or segmentby column from a hypertable with compression enabled ALTER TABLE foo ALTER COLUMN t SET NOT NULL; ERROR: operation not supported on hypertables that have compression enabled ALTER TABLE foo RESET (timescaledb.compress); ERROR: compression options cannot be reset ALTER TABLE foo ADD CONSTRAINT chk CHECK(b > 0); ERROR: operation not supported on hypertables that have compression enabled ALTER TABLE foo ADD CONSTRAINT chk UNIQUE(b); ERROR: operation not supported on hypertables that have compression enabled ALTER TABLE foo DROP CONSTRAINT chk_existing; ERROR: operation not supported on hypertables that have compression enabled --can add index , but not unique index CREATE UNIQUE INDEX foo_idx ON foo ( a, c ); ERROR: operation not supported on hypertables that have compression enabled CREATE INDEX foo_idx ON foo ( a, c ); --note that the time column "a" should not be added to the end of the order by list again (should appear first) select hc.* from _timescaledb_catalog.hypertable_compression hc inner join _timescaledb_catalog.hypertable h on (h.id = hc.hypertable_id) where h.table_name = 'foo' order by attname; hypertable_id | attname | compression_algorithm_id | segmentby_column_index | orderby_column_index | orderby_asc | orderby_nullsfirst ---------------+---------+--------------------------+------------------------+----------------------+-------------+-------------------- 15 | a | 4 | | 1 | t | f 15 | b | 4 | | 2 | t | f 15 | c | 4 | | | | 15 | p | 1 | | | | 15 | t | 2 | | | | (5 rows) select decompress_chunk(ch1.schema_name|| '.' || ch1.table_name) FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'foo' ORDER BY ch1.id limit 1; ERROR: chunk "_hyper_15_2_chunk" is not compressed --test changing the segment by columns ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'a', timescaledb.compress_segmentby = 'b'); select ch1.schema_name|| '.' || ch1.table_name AS "CHUNK_NAME" FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'foo' ORDER BY ch1.id limit 1 \gset select decompress_chunk(:'CHUNK_NAME'); ERROR: chunk "_hyper_15_2_chunk" is not compressed select decompress_chunk(:'CHUNK_NAME', if_compressed=>true); NOTICE: chunk "_hyper_15_2_chunk" is not compressed decompress_chunk ------------------ (1 row) --should succeed select compress_chunk(:'CHUNK_NAME'); compress_chunk ----------------------------------------- _timescaledb_internal._hyper_15_2_chunk (1 row) select compress_chunk(:'CHUNK_NAME'); ERROR: chunk "_hyper_15_2_chunk" is already compressed select compress_chunk(:'CHUNK_NAME', if_not_compressed=>true); NOTICE: chunk "_hyper_15_2_chunk" is already compressed compress_chunk ----------------------------------------- _timescaledb_internal._hyper_15_2_chunk (1 row) select compress_chunk(ch1.schema_name|| '.' || ch1.table_name) FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'non_compressed' ORDER BY ch1.id limit 1; ERROR: compression not enabled on "non_compressed" DETAIL: It is not possible to compress chunks on a hypertable or continuous aggregate that does not have compression enabled. HINT: Enable compression using ALTER TABLE/MATERIALIZED VIEW with the timescaledb.compress option. ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'a', timescaledb.compress_segmentby = 'c'); ERROR: cannot change configuration on already compressed chunks DETAIL: There are compressed chunks that prevent changing the existing compression configuration. ALTER TABLE foo set (timescaledb.compress='f'); ERROR: cannot change configuration on already compressed chunks DETAIL: There are compressed chunks that prevent changing the existing compression configuration. ALTER TABLE foo reset (timescaledb.compress); ERROR: compression options cannot be reset select decompress_chunk(ch1.schema_name|| '.' || ch1.table_name) FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'non_compressed' ORDER BY ch1.id limit 1; ERROR: missing compressed hypertable --should succeed select decompress_chunk(ch1.schema_name|| '.' || ch1.table_name) FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'foo' and ch1.compressed_chunk_id IS NOT NULL; decompress_chunk ----------------------------------------- _timescaledb_internal._hyper_15_2_chunk (1 row) --should succeed ALTER TABLE foo set (timescaledb.compress, timescaledb.compress_orderby = 'a', timescaledb.compress_segmentby = 'b'); select hc.* from _timescaledb_catalog.hypertable_compression hc inner join _timescaledb_catalog.hypertable h on (h.id = hc.hypertable_id) where h.table_name = 'foo' order by attname; hypertable_id | attname | compression_algorithm_id | segmentby_column_index | orderby_column_index | orderby_asc | orderby_nullsfirst ---------------+---------+--------------------------+------------------------+----------------------+-------------+-------------------- 15 | a | 4 | | 1 | t | f 15 | b | 0 | 1 | | | 15 | c | 4 | | | | 15 | p | 1 | | | | 15 | t | 2 | | | | (5 rows) SELECT comp_hyper.schema_name|| '.' || comp_hyper.table_name as "COMPRESSED_HYPER_NAME" FROM _timescaledb_catalog.hypertable comp_hyper INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id) WHERE uncomp_hyper.table_name like 'foo' ORDER BY comp_hyper.id LIMIT 1 \gset select add_retention_policy(:'COMPRESSED_HYPER_NAME', INTERVAL '4 months', true); ERROR: cannot add retention policy to compressed hypertable "_compressed_hypertable_18" HINT: Please add the policy to the corresponding uncompressed hypertable instead. --Constraint checking for compression create table fortable(col integer primary key); create table table_constr( device_id integer, timec integer , location integer , c integer constraint valid_cval check (c > 20) , d integer, primary key ( device_id, timec) ); select table_name from create_hypertable('table_constr', 'timec', chunk_time_interval=> 10); table_name -------------- table_constr (1 row) ALTER TABLE table_constr set (timescaledb.compress, timescaledb.compress_segmentby = 'd'); ERROR: column "device_id" must be used for segmenting or ordering DETAIL: The constraint "table_constr_pkey" cannot be enforced with the given compression configuration. alter table table_constr add constraint table_constr_uk unique (location, timec, device_id); ALTER TABLE table_constr set (timescaledb.compress, timescaledb.compress_orderby = 'timec', timescaledb.compress_segmentby = 'device_id'); ERROR: column "location" must be used for segmenting or ordering DETAIL: The constraint "table_constr_uk" cannot be enforced with the given compression configuration. alter table table_constr add constraint table_constr_fk FOREIGN KEY(d) REFERENCES fortable(col) on delete cascade; ALTER TABLE table_constr set (timescaledb.compress, timescaledb.compress_orderby = 'timec', timescaledb.compress_segmentby = 'device_id, location'); ERROR: column "d" must be used for segmenting DETAIL: The foreign key constraint "table_constr_fk" cannot be enforced with the given compression configuration. --exclusion constraints not allowed alter table table_constr add constraint table_constr_exclu exclude using btree (timec with = ); ALTER TABLE table_constr set (timescaledb.compress, timescaledb.compress_orderby = 'timec', timescaledb.compress_segmentby = 'device_id, location, d'); ERROR: constraint table_constr_exclu is not supported for compression HINT: Exclusion constraints are not supported on hypertables that are compressed. alter table table_constr drop constraint table_constr_exclu ; --now it works ALTER TABLE table_constr set (timescaledb.compress, timescaledb.compress_orderby = 'timec', timescaledb.compress_segmentby = 'device_id, location, d'); --can't add fks after compression enabled alter table table_constr add constraint table_constr_fk_add_after FOREIGN KEY(d) REFERENCES fortable(col) on delete cascade; ERROR: operation not supported on hypertables that have compression enabled -- ddl ADD column variants that are not supported ALTER TABLE table_constr ADD COLUMN newcol integer CHECK ( newcol < 10 ); ERROR: cannot add column with constraints to a hypertable that has compression enabled ALTER TABLE table_constr ADD COLUMN newcol integer UNIQUE; ERROR: cannot add column with constraints to a hypertable that has compression enabled ALTER TABLE table_constr ADD COLUMN newcol integer PRIMARY KEY; ERROR: cannot add column with constraints to a hypertable that has compression enabled ALTER TABLE table_constr ADD COLUMN newcol integer NOT NULL; ERROR: cannot add column with NOT NULL constraint without default to a hypertable that has compression enabled ALTER TABLE table_constr ADD COLUMN newcol integer DEFAULT random() + random(); ERROR: cannot add column with non-constant default expression to a hypertable that has compression enabled ALTER TABLE table_constr ADD COLUMN IF NOT EXISTS newcol integer REFERENCES fortable(col); ERROR: cannot add column with constraints to a hypertable that has compression enabled ALTER TABLE table_constr ADD COLUMN IF NOT EXISTS newcol integer GENERATED ALWAYS AS IDENTITY; ERROR: cannot add column with constraints to a hypertable that has compression enabled ALTER TABLE table_constr ADD COLUMN IF NOT EXISTS newcol integer GENERATED BY DEFAULT AS IDENTITY; ERROR: cannot add column with constraints to a hypertable that has compression enabled ALTER TABLE table_constr ADD COLUMN newcol nonexistent_type; ERROR: type "nonexistent_type" does not exist LINE 1: ALTER TABLE table_constr ADD COLUMN newcol nonexistent_type; ^ --FK check should not error even with dropped columns (previously had a bug related to this) CREATE TABLE table_fk ( time timestamptz NOT NULL, id1 int8 NOT NULL, id2 int8 NOT NULL, value float8 NULL, CONSTRAINT fk1 FOREIGN KEY (id1) REFERENCES fortable(col), CONSTRAINT fk2 FOREIGN KEY (id2) REFERENCES fortable(col) ); SELECT create_hypertable('table_fk', 'time'); create_hypertable ------------------------ (21,public,table_fk,t) (1 row) ALTER TABLE table_fk DROP COLUMN id1; ALTER TABLE table_fk SET (timescaledb.compress,timescaledb.compress_segmentby = 'id2'); -- TEST fk cascade delete behavior on compressed chunk -- insert into fortable values(1); insert into fortable values(10); --we want 2 chunks here -- insert into table_constr values(1000, 1, 44, 44, 1); insert into table_constr values(1000, 10, 44, 44, 10); select ch1.schema_name|| '.' || ch1.table_name AS "CHUNK_NAME" FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht where ch1.hypertable_id = ht.id and ht.table_name like 'table_constr' ORDER BY ch1.id limit 1 \gset -- we have 1 compressed and 1 uncompressed chunk after this. select compress_chunk(:'CHUNK_NAME'); compress_chunk ----------------------------------------- _timescaledb_internal._hyper_19_7_chunk (1 row) SELECT total_chunks , number_compressed_chunks FROM hypertable_compression_stats('table_constr'); total_chunks | number_compressed_chunks --------------+-------------------------- 2 | 1 (1 row) --github issue 1661 --disable compression after enabling it on a table that has fk constraints CREATE TABLE table_constr2( device_id integer, timec integer , location integer , d integer references fortable(col), primary key ( device_id, timec) ); SELECT table_name from create_hypertable('table_constr2', 'timec', chunk_time_interval=> 10); table_name --------------- table_constr2 (1 row) INSERT INTO fortable VALUES( 99 ); INSERT INTO table_constr2 VALUES( 1000, 10, 5, 99); ALTER TABLE table_constr2 SET (timescaledb.compress, timescaledb.compress_segmentby = 'device_id'); ERROR: column "d" must be used for segmenting DETAIL: The foreign key constraint "table_constr2_d_fkey" cannot be enforced with the given compression configuration. ALTER TABLE table_constr2 SET (timescaledb.compress, timescaledb.compress_segmentby = 'device_id, d'); --compress a chunk and try to disable compression, it should fail -- SELECT ch1.schema_name|| '.' || ch1.table_name AS "CHUNK_NAME" FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht WHERE ch1.hypertable_id = ht.id and ht.table_name like 'table_constr2' \gset SELECT compress_chunk(:'CHUNK_NAME'); compress_chunk ------------------------------------------ _timescaledb_internal._hyper_23_10_chunk (1 row) ALTER TABLE table_constr2 set (timescaledb.compress=false); ERROR: cannot change configuration on already compressed chunks DETAIL: There are compressed chunks that prevent changing the existing compression configuration. --decompress all chunks and disable compression. SELECT decompress_chunk(:'CHUNK_NAME'); decompress_chunk ------------------------------------------ _timescaledb_internal._hyper_23_10_chunk (1 row) ALTER TABLE table_constr2 SET (timescaledb.compress=false); -- TEST compression policy -- modify the config to trigger errors at runtime CREATE TABLE test_table_int(time bigint, val int); SELECT create_hypertable('test_table_int', 'time', chunk_time_interval => 1); NOTICE: adding not-null constraint to column "time" DETAIL: Time dimensions cannot have NULL values. create_hypertable ------------------------------ (25,public,test_table_int,t) (1 row) CREATE OR REPLACE function dummy_now() returns BIGINT LANGUAGE SQL IMMUTABLE as 'SELECT 5::BIGINT'; SELECT set_integer_now_func('test_table_int', 'dummy_now'); set_integer_now_func ---------------------- (1 row) INSERT INTO test_table_int SELECT generate_series(1,5), 10; ALTER TABLE test_table_int set (timescaledb.compress); SELECT add_compression_policy('test_table_int', 2::int) AS compressjob_id \gset \c :TEST_DBNAME :ROLE_SUPERUSER UPDATE _timescaledb_config.bgw_job SET config = config - 'compress_after' WHERE id = :compressjob_id; SELECT config FROM _timescaledb_config.bgw_job WHERE id = :compressjob_id; config ----------------------- {"hypertable_id": 25} (1 row) --should fail CALL run_job(:compressjob_id); ERROR: job 1000 config must have compress_after CONTEXT: PL/pgSQL function _timescaledb_internal.policy_compression(integer,jsonb) line 35 at RAISE SELECT remove_compression_policy('test_table_int'); remove_compression_policy --------------------------- t (1 row) --again add a new policy that we'll tamper with SELECT add_compression_policy('test_table_int', 2::int) AS compressjob_id \gset UPDATE _timescaledb_config.bgw_job SET config = config - 'hypertable_id' WHERE id = :compressjob_id; SELECT config FROM _timescaledb_config.bgw_job WHERE id = :compressjob_id; config ----------------------- {"compress_after": 2} (1 row) --should fail CALL run_job(:compressjob_id); ERROR: job 1001 config must have hypertable_id CONTEXT: PL/pgSQL function _timescaledb_internal.policy_compression(integer,jsonb) line 26 at RAISE UPDATE _timescaledb_config.bgw_job SET config = NULL WHERE id = :compressjob_id; SELECT config FROM _timescaledb_config.bgw_job WHERE id = :compressjob_id; config -------- (1 row) --should fail CALL run_job(:compressjob_id); ERROR: job 1001 has null config CONTEXT: PL/pgSQL function _timescaledb_internal.policy_compression(integer,jsonb) line 21 at RAISE -- test ADD COLUMN IF NOT EXISTS CREATE TABLE metric (time TIMESTAMPTZ NOT NULL, val FLOAT8 NOT NULL, dev_id INT4 NOT NULL); SELECT create_hypertable('metric', 'time', 'dev_id', 10); create_hypertable ---------------------- (27,public,metric,t) (1 row) ALTER TABLE metric SET ( timescaledb.compress, timescaledb.compress_segmentby = 'dev_id', timescaledb.compress_orderby = 'time DESC' ); INSERT INTO metric(time, val, dev_id) SELECT s.*, 3.14+1, 1 FROM generate_series('2021-08-17 00:00:00'::timestamp, '2021-08-17 00:02:00'::timestamp, '1 s'::interval) s; SELECT compress_chunk(show_chunks('metric')); compress_chunk ------------------------------------------ _timescaledb_internal._hyper_27_17_chunk (1 row) -- column does not exist the first time ALTER TABLE metric ADD COLUMN IF NOT EXISTS "medium" VARCHAR ; -- column already exists the second time ALTER TABLE metric ADD COLUMN IF NOT EXISTS "medium" VARCHAR ; NOTICE: column "medium" of relation "metric" already exists, skipping -- also add one without IF NOT EXISTS ALTER TABLE metric ADD COLUMN "medium_1" VARCHAR ; ALTER TABLE metric ADD COLUMN "medium_1" VARCHAR ; ERROR: column "medium_1" of relation "metric" already exists --github issue 3481 --GROUP BY error when setting compress_segmentby with an enum column CREATE TYPE an_enum_type AS ENUM ('home', 'school'); CREATE TABLE test ( time timestamp NOT NULL, enum_col an_enum_type NOT NULL ); SELECT create_hypertable( 'test', 'time' ); WARNING: column type "timestamp without time zone" used for "time" does not follow best practices HINT: Use datatype TIMESTAMPTZ instead. create_hypertable -------------------- (29,public,test,t) (1 row) INSERT INTO test VALUES ('2001-01-01 00:00', 'home'), ('2001-01-01 01:00', 'school'), ('2001-01-01 02:00', 'home'); --enable compression on enum_col ALTER TABLE test SET ( timescaledb.compress, timescaledb.compress_segmentby = 'enum_col', timescaledb.compress_orderby = 'time' ); --below queries will pass before chunks are compressed SELECT 1 FROM test GROUP BY enum_col; ?column? ---------- 1 1 (2 rows) EXPLAIN SELECT DISTINCT 1 FROM test; QUERY PLAN ---------------------------------------------------------------------------------- Unique (cost=0.00..50.80 rows=1 width=4) -> Result (cost=0.00..50.80 rows=2040 width=4) -> Seq Scan on _hyper_29_19_chunk (cost=0.00..30.40 rows=2040 width=0) (3 rows) --compress chunks SELECT COMPRESS_CHUNK(X) FROM SHOW_CHUNKS('test') X; compress_chunk ------------------------------------------ _timescaledb_internal._hyper_29_19_chunk (1 row) --below query should pass after chunks are compressed SELECT 1 FROM test GROUP BY enum_col; ?column? ---------- 1 1 (2 rows) EXPLAIN SELECT DISTINCT 1 FROM test; QUERY PLAN ------------------------------------------------------------------------------------------------------ Unique (cost=0.51..21.02 rows=1 width=4) -> Result (cost=0.51..21.02 rows=2000 width=4) -> Custom Scan (DecompressChunk) on _hyper_29_19_chunk (cost=0.51..1.02 rows=2000 width=0) -> Seq Scan on compress_hyper_30_20_chunk (cost=0.00..1.02 rows=2 width=4) (4 rows)