mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-22 13:40:56 +08:00
The schema of base table on which hypertables are created, should define columns with proper data types. As per postgres best practices Wiki (https://wiki.postgresql.org/wiki/Don't_Do_This), one should not define columns with CHAR, VARCHAR, VARCHAR(N), instead use TEXT data type. Similarly instead of using timestamp, one should use timestamptz. This patch reports a WARNING to end user when creating hypertables, if underlying parent table, has columns of above mentioned data types. Fixes #4335
614 lines
33 KiB
Plaintext
614 lines
33 KiB
Plaintext
-- 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 <hypertable> 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)
|
|
|