-- 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.
\ir include/rand_generator.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.
--------------------------
-- cheap rand generator --
--------------------------
create table rand_minstd_state(i bigint);
create function rand_minstd_advance(bigint) returns bigint
language sql immutable as
$$
	select (16807 * $1) % 2147483647
$$;
create function gen_rand_minstd() returns bigint
language sql security definer as
$$
	update rand_minstd_state set i = rand_minstd_advance(i) returning i
$$;
-- seed the random num generator
insert into rand_minstd_state values (321);
\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;
--test hypertable with tables space
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
SET timezone TO 'America/Los_Angeles';
CREATE TABLE test1 ("Time" timestamptz, i integer not null, b bigint, t text);
SELECT table_name from create_hypertable('test1', 'Time', chunk_time_interval=> INTERVAL '1 day');
 table_name 
------------
 test1

INSERT INTO test1 SELECT t,  gen_rand_minstd(), gen_rand_minstd(), gen_rand_minstd()::text FROM generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-28 1:00', '1 hour') t;
ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = '"Time" DESC');
SELECT count(compress_chunk(ch)) FROM show_chunks('test1') ch;
 count 
-------
    27

VACUUM FULL ANALYZE test1;
--make sure allowed ddl still work
ALTER TABLE test1 CLUSTER ON "test1_Time_idx";
ALTER TABLE test1 SET WITHOUT CLUSTER;
CREATE INDEX new_index ON test1(b);
DROP INDEX new_index;
ALTER TABLE test1 SET (fillfactor=100);
ALTER TABLE test1 RESET (fillfactor);
ALTER TABLE test1 ALTER COLUMN b SET STATISTICS 10;
-- ensure that REPLICA IDENTITY works
SELECT relreplident, count(*) FROM show_chunks('test1') ch INNER JOIN pg_class c ON (ch = c.oid) GROUP BY 1 ORDER BY 1;
 relreplident | count 
--------------+-------
 d            |    27

SELECT relreplident FROM pg_class c WHERE c.relname = 'test1';
 relreplident 
--------------
 d

ALTER TABLE test1 REPLICA IDENTITY FULL;
SELECT relname, relreplident FROM pg_class WHERE relname = 'test1' ORDER BY relname;
 relname | relreplident 
---------+--------------
 test1   | f

-- the chunk's setting should also change to FULL
SELECT relreplident, count(*) FROM show_chunks('test1') ch INNER JOIN pg_class c ON (ch = c.oid) GROUP BY 1 ORDER BY 1;
 relreplident | count 
--------------+-------
 f            |    27

SELECT relreplident FROM pg_class c WHERE c.relname = 'test1';
 relreplident 
--------------
 f

ALTER TABLE test1 REPLICA IDENTITY DEFAULT;
--test adding boolean columns with default and not null
CREATE TABLE records (time timestamp NOT NULL);
SELECT create_hypertable('records', 'time');
WARNING:  column type "timestamp without time zone" used for "time" does not follow best practices
  create_hypertable   
----------------------
 (3,public,records,t)

ALTER TABLE records SET (timescaledb.compress = true, timescaledb.compress_orderby='"time" DESC');
ALTER TABLE records ADD COLUMN col1 boolean DEFAULT false NOT NULL;
-- NULL constraints are useless and it is safe allow adding this
-- column with NULL constraint to a compressed hypertable (Issue #5151)
ALTER TABLE records ADD COLUMN col2 BOOLEAN NULL;
DROP table records CASCADE;
-- TABLESPACES
-- For tablepaces with compressed chunks the semantics are the following:
--  - compressed chunks get put into the same tablespace as the
--    uncompressed chunk on compression.
-- - set tablespace on uncompressed hypertable cascades to compressed hypertable+chunks
-- - set tablespace on all chunks is blocked (same as w/o compression)
-- - move chunks on a uncompressed chunk errors
-- - move chunks on compressed chunk works
--In the future we will:
-- - add tablespace option to compress_chunk function and policy (this will override the setting
--   of the uncompressed chunk). This will allow changing tablespaces upon compression
-- - Note: The current plan is to never listen to the setting on compressed hypertable. In fact,
--   we will block setting tablespace on  compressed hypertables
SELECT count(*) as "COUNT_CHUNKS_UNCOMPRESSED"
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' \gset
SELECT count(*) as "COUNT_CHUNKS_COMPRESSED"
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
WHERE uncomp_hyper.table_name like 'test1' \gset
ALTER TABLE test1 SET TABLESPACE tablespace1;
--all chunks + both the compressed and uncompressed hypertable moved to new tablespace
SELECT count(*) = (:COUNT_CHUNKS_UNCOMPRESSED +:COUNT_CHUNKS_COMPRESSED + 2)
FROM pg_tables WHERE tablespace = 'tablespace1';
 ?column? 
----------
 t

ALTER TABLE test1 SET TABLESPACE tablespace2;
SELECT count(*) = (:COUNT_CHUNKS_UNCOMPRESSED +:COUNT_CHUNKS_COMPRESSED + 2)
FROM pg_tables WHERE tablespace = 'tablespace2';
 ?column? 
----------
 t

SELECT
    comp_chunk.schema_name|| '.' || comp_chunk.table_name as "COMPRESSED_CHUNK_NAME",
    uncomp_chunk.schema_name|| '.' || uncomp_chunk.table_name as "UNCOMPRESSED_CHUNK_NAME"
FROM _timescaledb_catalog.chunk comp_chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (comp_chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
INNER JOIN _timescaledb_catalog.chunk uncomp_chunk ON (uncomp_chunk.compressed_chunk_id = comp_chunk.id)
WHERE uncomp_hyper.table_name like 'test1' ORDER BY comp_chunk.id LIMIT 1\gset
-- ensure compression chunk cannot be moved directly
SELECT tablename
FROM pg_tables WHERE tablespace = 'tablespace1';
 tablename 
-----------

\set ON_ERROR_STOP 0
ALTER TABLE :COMPRESSED_CHUNK_NAME SET TABLESPACE tablespace1;
ERROR:  changing tablespace of columnstore chunk is not supported
\set ON_ERROR_STOP 1
SELECT tablename
FROM pg_tables WHERE tablespace = 'tablespace1';
 tablename 
-----------

-- ensure that both compressed and uncompressed chunks moved
ALTER TABLE :UNCOMPRESSED_CHUNK_NAME SET TABLESPACE tablespace1;
SELECT tablename
FROM pg_tables WHERE tablespace = 'tablespace1';
         tablename         
---------------------------
 compress_hyper_2_28_chunk
 _hyper_1_1_chunk

ALTER TABLE test1 SET TABLESPACE tablespace2;
SELECT tablename
FROM pg_tables WHERE tablespace = 'tablespace1';
 tablename 
-----------

\set ON_ERROR_STOP 0
SELECT move_chunk(chunk=>:'COMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1',  reorder_index=>'_timescaledb_internal."compress_hyper_2_28_chunk_b__ts_meta_min_1__ts_meta_max_1_idx"');
ERROR:  cannot directly move internal columnstore data
\set ON_ERROR_STOP 1
-- ensure that both compressed and uncompressed chunks moved
SELECT move_chunk(chunk=>:'UNCOMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1',  reorder_index=>'_timescaledb_internal."_hyper_1_1_chunk_test1_Time_idx"');
NOTICE:  ignoring index parameter
 move_chunk 
------------
 

SELECT tablename
FROM pg_tables WHERE tablespace = 'tablespace1';
         tablename         
---------------------------
 _hyper_1_1_chunk
 compress_hyper_2_28_chunk

-- the compressed chunk is in here now
SELECT count(*)
FROM pg_tables WHERE tablespace = 'tablespace1';
 count 
-------
     2

SELECT decompress_chunk(:'UNCOMPRESSED_CHUNK_NAME');
            decompress_chunk            
----------------------------------------
 _timescaledb_internal._hyper_1_1_chunk

--the compresse chunk was dropped by decompression
SELECT count(*)
FROM pg_tables WHERE tablespace = 'tablespace1';
 count 
-------
     1

SELECT move_chunk(chunk=>:'UNCOMPRESSED_CHUNK_NAME', destination_tablespace=>'tablespace1', index_destination_tablespace=>'tablespace1',  reorder_index=>'_timescaledb_internal."_hyper_1_1_chunk_test1_Time_idx"');
 move_chunk 
------------
 

--the uncompressed chunks has now been moved
SELECT count(*)
FROM pg_tables WHERE tablespace = 'tablespace1';
 count 
-------
     1

SELECT compress_chunk(:'UNCOMPRESSED_CHUNK_NAME');
             compress_chunk             
----------------------------------------
 _timescaledb_internal._hyper_1_1_chunk

--the compressed chunk is now in the same tablespace as the uncompressed one
SELECT count(*)
FROM pg_tables WHERE tablespace = 'tablespace1';
 count 
-------
     2

--
-- DROP CHUNKS
--
SELECT count(*) as count_chunks_uncompressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1';
 count_chunks_uncompressed 
---------------------------
                        27

SELECT count(*) as count_chunks_compressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
WHERE uncomp_hyper.table_name like 'test1';
 count_chunks_compressed 
-------------------------
                      27

SELECT chunk.schema_name|| '.' || chunk.table_name as "UNCOMPRESSED_CHUNK_NAME"
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' ORDER BY chunk.id LIMIT 1 \gset
DROP TABLE :UNCOMPRESSED_CHUNK_NAME;
--should decrease #chunks both compressed and decompressed
SELECT count(*) as count_chunks_uncompressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1';
 count_chunks_uncompressed 
---------------------------
                        26

--make sure there are no orphaned  _timescaledb_catalog.compression_chunk_size entries (should be 0)
SELECT count(*) as orphaned_compression_chunk_size
FROM _timescaledb_catalog.compression_chunk_size size
LEFT JOIN _timescaledb_catalog.chunk chunk ON (chunk.id = size.chunk_id)
WHERE chunk.id IS NULL;
 orphaned_compression_chunk_size 
---------------------------------
                               0

SELECT count(*) as count_chunks_compressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
WHERE uncomp_hyper.table_name like 'test1';
 count_chunks_compressed 
-------------------------
                      26

SELECT drop_chunks('test1', older_than => '2018-03-10'::TIMESTAMPTZ);
              drop_chunks               
----------------------------------------
 _timescaledb_internal._hyper_1_2_chunk
 _timescaledb_internal._hyper_1_3_chunk
 _timescaledb_internal._hyper_1_4_chunk
 _timescaledb_internal._hyper_1_5_chunk
 _timescaledb_internal._hyper_1_6_chunk
 _timescaledb_internal._hyper_1_7_chunk
 _timescaledb_internal._hyper_1_8_chunk

--should decrease #chunks both compressed and decompressed
SELECT count(*) as count_chunks_uncompressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1';
 count_chunks_uncompressed 
---------------------------
                        19

SELECT count(*) as count_chunks_compressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
WHERE uncomp_hyper.table_name like 'test1';
 count_chunks_compressed 
-------------------------
                      19

SELECT chunk.schema_name|| '.' || chunk.table_name as "UNCOMPRESSED_CHUNK_NAME"
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' ORDER BY chunk.id LIMIT 1 \gset
SELECT chunk.schema_name|| '.' || chunk.table_name as "COMPRESSED_CHUNK_NAME"
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
WHERE uncomp_hyper.table_name like 'test1' ORDER BY chunk.id LIMIT 1
\gset
\set ON_ERROR_STOP 0
DROP TABLE :COMPRESSED_CHUNK_NAME;
ERROR:  dropping columnstore chunks not supported
SELECT _timescaledb_functions.drop_chunk(:'COMPRESSED_CHUNK_NAME');
ERROR:  dropping compressed chunks not supported
\set ON_ERROR_STOP 1
SELECT
    chunk.schema_name|| '.' || chunk.table_name as "UNCOMPRESSED_CHUNK_NAME",
    comp_chunk.schema_name|| '.' || comp_chunk.table_name as "COMPRESSED_CHUNK_NAME"
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.chunk comp_chunk ON (chunk.compressed_chunk_id = comp_chunk.id)
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' ORDER BY chunk.id LIMIT 1 \gset
--create a dependent object on the compressed chunk to test cascade behaviour
CREATE VIEW dependent_1 AS SELECT * FROM :COMPRESSED_CHUNK_NAME;
\set ON_ERROR_STOP 0
--errors due to dependent objects
DROP TABLE :UNCOMPRESSED_CHUNK_NAME;
ERROR:  cannot drop table _timescaledb_internal.compress_hyper_2_36_chunk because other objects depend on it
\set ON_ERROR_STOP 1
DROP TABLE :UNCOMPRESSED_CHUNK_NAME CASCADE;
NOTICE:  drop cascades to view dependent_1
--should decrease #chunks both compressed and decompressed
SELECT count(*) as count_chunks_uncompressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1';
 count_chunks_uncompressed 
---------------------------
                        18

SELECT count(*) as count_chunks_compressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
WHERE uncomp_hyper.table_name like 'test1';
 count_chunks_compressed 
-------------------------
                      18

SELECT
    chunk.schema_name|| '.' || chunk.table_name as "UNCOMPRESSED_CHUNK_NAME",
    comp_chunk.schema_name|| '.' || comp_chunk.table_name as "COMPRESSED_CHUNK_NAME"
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.chunk comp_chunk ON (chunk.compressed_chunk_id = comp_chunk.id)
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1' ORDER BY chunk.id LIMIT 1 \gset
CREATE VIEW dependent_1 AS SELECT * FROM :COMPRESSED_CHUNK_NAME;
\set ON_ERROR_STOP 0
\set VERBOSITY default
--errors due to dependent objects
SELECT drop_chunks('test1', older_than => '2018-03-28'::TIMESTAMPTZ);
ERROR:  cannot drop table _timescaledb_internal.compress_hyper_2_37_chunk because other objects depend on it
DETAIL:  view dependent_1 depends on table _timescaledb_internal.compress_hyper_2_37_chunk
HINT:  Use DROP ... to drop the dependent objects.
\set VERBOSITY terse
\set ON_ERROR_STOP 1
DROP VIEW dependent_1;
SELECT drop_chunks('test1', older_than => '2018-03-28'::TIMESTAMPTZ);
               drop_chunks               
-----------------------------------------
 _timescaledb_internal._hyper_1_10_chunk
 _timescaledb_internal._hyper_1_11_chunk
 _timescaledb_internal._hyper_1_12_chunk
 _timescaledb_internal._hyper_1_13_chunk
 _timescaledb_internal._hyper_1_14_chunk
 _timescaledb_internal._hyper_1_15_chunk
 _timescaledb_internal._hyper_1_16_chunk
 _timescaledb_internal._hyper_1_17_chunk
 _timescaledb_internal._hyper_1_18_chunk
 _timescaledb_internal._hyper_1_19_chunk
 _timescaledb_internal._hyper_1_20_chunk
 _timescaledb_internal._hyper_1_21_chunk
 _timescaledb_internal._hyper_1_22_chunk
 _timescaledb_internal._hyper_1_23_chunk
 _timescaledb_internal._hyper_1_24_chunk
 _timescaledb_internal._hyper_1_25_chunk
 _timescaledb_internal._hyper_1_26_chunk

--should decrease #chunks both compressed and decompressed
SELECT count(*) as count_chunks_uncompressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
WHERE hypertable.table_name like 'test1';
 count_chunks_uncompressed 
---------------------------
                         1

SELECT count(*) as count_chunks_compressed
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
WHERE uncomp_hyper.table_name like 'test1';
 count_chunks_compressed 
-------------------------
                       1

--make sure there are no orphaned  _timescaledb_catalog.compression_chunk_size entries (should be 0)
SELECT count(*) as orphaned_compression_chunk_size
FROM _timescaledb_catalog.compression_chunk_size size
LEFT JOIN _timescaledb_catalog.chunk chunk ON (chunk.id = size.chunk_id)
WHERE chunk.id IS NULL;
 orphaned_compression_chunk_size 
---------------------------------
                               0

--
-- DROP HYPERTABLE
--
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 'test1' ORDER BY comp_hyper.id LIMIT 1 \gset
\set ON_ERROR_STOP 0
DROP TABLE :COMPRESSED_HYPER_NAME;
ERROR:  dropping columnstore hypertables not supported
\set ON_ERROR_STOP 1
BEGIN;
SELECT hypertable.schema_name|| '.' || hypertable.table_name as "UNCOMPRESSED_HYPER_NAME"
FROM _timescaledb_catalog.hypertable hypertable
WHERE hypertable.table_name like 'test1' ORDER BY hypertable.id LIMIT 1 \gset
--before the drop there are 2 hypertables: the compressed and uncompressed ones
SELECT count(*) FROM _timescaledb_catalog.hypertable hypertable;
 count 
-------
     2

--add policy to make sure it's dropped later
select add_compression_policy(:'UNCOMPRESSED_HYPER_NAME', interval '1 day');
 add_compression_policy 
------------------------
                   1000

SELECT count(*) FROM _timescaledb_catalog.bgw_job WHERE id >= 1000;
 count 
-------
     1

DROP TABLE :UNCOMPRESSED_HYPER_NAME;
--verify that there are no more hypertable remaining
SELECT count(*) FROM _timescaledb_catalog.hypertable hypertable;
 count 
-------
     0

--verify that the policy is gone
SELECT count(*) FROM _timescaledb_catalog.bgw_job WHERE id >= 1000;
 count 
-------
     0

ROLLBACK;
--create a dependent object on the compressed hypertable to test cascade behaviour
CREATE VIEW dependent_1 AS SELECT * FROM :COMPRESSED_HYPER_NAME;
\set ON_ERROR_STOP 0
DROP TABLE :UNCOMPRESSED_HYPER_NAME;
ERROR:  cannot drop table _timescaledb_internal._compressed_hypertable_2 because other objects depend on it
\set ON_ERROR_STOP 1
BEGIN;
DROP TABLE :UNCOMPRESSED_HYPER_NAME CASCADE;
NOTICE:  drop cascades to view dependent_1
SELECT count(*) FROM _timescaledb_catalog.hypertable hypertable;
 count 
-------
     0

ROLLBACK;
DROP VIEW dependent_1;
--create a cont agg view on the ht as well then the drop should nuke everything
CREATE MATERIALIZED VIEW test1_cont_view
WITH (timescaledb.continuous,
      timescaledb.materialized_only=true)
AS SELECT time_bucket('1 hour', "Time"), SUM(i)
   FROM test1
   GROUP BY 1 WITH NO DATA;
SELECT add_continuous_aggregate_policy('test1_cont_view', NULL, '1 hour'::interval, '1 day'::interval);
 add_continuous_aggregate_policy 
---------------------------------
                            1001

CALL refresh_continuous_aggregate('test1_cont_view', NULL, NULL);
SELECT count(*) FROM test1_cont_view;
 count 
-------
     9

\c :TEST_DBNAME :ROLE_SUPERUSER
SET timezone TO 'America/Los_Angeles';
SELECT chunk.schema_name|| '.' || chunk.table_name as "COMPRESSED_CHUNK_NAME"
FROM _timescaledb_catalog.chunk chunk
INNER JOIN _timescaledb_catalog.hypertable comp_hyper ON (chunk.hypertable_id = comp_hyper.id)
INNER JOIN _timescaledb_catalog.hypertable uncomp_hyper ON (comp_hyper.id = uncomp_hyper.compressed_hypertable_id)
WHERE uncomp_hyper.table_name like 'test1' ORDER BY chunk.id LIMIT 1
\gset
ALTER TABLE test1 OWNER TO :ROLE_DEFAULT_PERM_USER_2;
--make sure new owner is propagated down
SELECT a.rolname from pg_class c INNER JOIN pg_authid a ON(c.relowner = a.oid) WHERE c.oid = 'test1'::regclass;
       rolname       
---------------------
 default_perm_user_2

SELECT a.rolname from pg_class c INNER JOIN pg_authid a ON(c.relowner = a.oid) WHERE c.oid = :'COMPRESSED_HYPER_NAME'::regclass;
       rolname       
---------------------
 default_perm_user_2

SELECT a.rolname from pg_class c INNER JOIN pg_authid a ON(c.relowner = a.oid) WHERE c.oid = :'COMPRESSED_CHUNK_NAME'::regclass;
       rolname       
---------------------
 default_perm_user_2

--
-- turn off compression
--
SELECT count(decompress_chunk(ch)) FROM show_chunks('test1') ch;
 count 
-------
     1

VACUUM FULL ANALYZE test1;
select add_compression_policy('test1', interval '1 day');
 add_compression_policy 
------------------------
                   1002

\set ON_ERROR_STOP 0
ALTER table test1 set (timescaledb.compress='f');
\set ON_ERROR_STOP 1
select remove_compression_policy('test1');
 remove_compression_policy 
---------------------------
 t

ALTER table test1 set (timescaledb.compress='f');
--only one hypertable left
SELECT count(*) = 1 FROM _timescaledb_catalog.hypertable hypertable;
 ?column? 
----------
 f

SELECT compressed_hypertable_id IS NULL FROM _timescaledb_catalog.hypertable hypertable WHERE hypertable.table_name like 'test1' ;
 ?column? 
----------
 t

--make sure there are no orphaned  _timescaledb_catalog.compression_chunk_size entries (should be 0)
SELECT count(*) as orphaned_compression_chunk_size
FROM _timescaledb_catalog.compression_chunk_size size
LEFT JOIN _timescaledb_catalog.chunk chunk ON (chunk.id = size.chunk_id)
WHERE chunk.id IS NULL;
 orphaned_compression_chunk_size 
---------------------------------
                               0

--can turn compression back on
-- this will fail because current table owner does not have permission to create compressed hypertable
-- in the current tablespace, as they do not own it
\set ON_ERROR_STOP 0
ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = '"Time" DESC');
ERROR:  permission denied for tablespace "tablespace2" by table owner "default_perm_user_2"
-- now change the owner and repeat, should work
ALTER TABLESPACE tablespace2 OWNER TO :ROLE_DEFAULT_PERM_USER_2;
\set ON_ERROR_STOP 1
ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = '"Time" DESC');
SELECT count(compress_chunk(ch)) FROM show_chunks('test1') ch;
 count 
-------
     1

VACUUM FULL ANALYZE test1;
DROP TABLE test1 CASCADE;
NOTICE:  drop cascades to 2 other objects
NOTICE:  drop cascades to table _timescaledb_internal._hyper_5_56_chunk
DROP TABLESPACE tablespace1;
-- Triggers are NOT fired for compress/decompress
CREATE TABLE test1 ("Time" timestamptz, i integer);
SELECT table_name from create_hypertable('test1', 'Time', chunk_time_interval=> INTERVAL '1 day');
 table_name 
------------
 test1

CREATE OR REPLACE FUNCTION test1_print_func()
RETURNS TRIGGER LANGUAGE PLPGSQL AS
$BODY$
BEGIN
   RAISE NOTICE ' raise notice test1_print_trigger called ';
   RETURN OLD;
END;
$BODY$;
CREATE TRIGGER test1_trigger
BEFORE INSERT OR UPDATE OR DELETE OR TRUNCATE ON test1
FOR EACH STATEMENT EXECUTE FUNCTION test1_print_func();
INSERT INTO test1 SELECT generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-03 1:00', '1 hour') , 1 ;
NOTICE:   raise notice test1_print_trigger called 
-- add a row trigger too --
CREATE TRIGGER test1_trigger2
BEFORE INSERT OR UPDATE OR DELETE ON test1
FOR EACH ROW EXECUTE FUNCTION test1_print_func();
INSERT INTO test1 SELECT '2018-03-02 1:05'::TIMESTAMPTZ, 2;
NOTICE:   raise notice test1_print_trigger called 
NOTICE:   raise notice test1_print_trigger called 
ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_orderby = '"Time" DESC');
SELECT count(compress_chunk(ch)) FROM show_chunks('test1') ch;
 count 
-------
     2

SELECT count(decompress_chunk(ch)) FROM show_chunks('test1') ch;
 count 
-------
     2

DROP TABLE test1;
-- test disabling compression on hypertables with caggs and dropped chunks
-- github issue 2844
CREATE TABLE i2844 (created_at timestamptz NOT NULL,c1 float);
SELECT create_hypertable('i2844', 'created_at', chunk_time_interval => '6 hour'::interval);
  create_hypertable  
---------------------
 (10,public,i2844,t)

INSERT INTO i2844 SELECT generate_series('2000-01-01'::timestamptz, '2000-01-02'::timestamptz,'1h'::interval);
CREATE MATERIALIZED VIEW test_agg WITH (timescaledb.continuous) AS SELECT time_bucket('1 hour', created_at) AS bucket, AVG(c1) AS avg_c1 FROM i2844 GROUP BY bucket;
NOTICE:  refreshing continuous aggregate "test_agg"
ALTER TABLE i2844 SET (timescaledb.compress, timescaledb.compress_orderby = 'created_at DESC');
SELECT * FROM _timescaledb_catalog.compression_settings WHERE relid='i2844'::regclass;
 relid | compress_relid | segmentby |   orderby    | orderby_desc | orderby_nullsfirst | index 
-------+----------------+-----------+--------------+--------------+--------------------+-------
 i2844 |                |           | {created_at} | {t}          | {t}                | 

SELECT compress_chunk(show_chunks) AS compressed_chunk FROM show_chunks('i2844');
             compressed_chunk             
------------------------------------------
 _timescaledb_internal._hyper_10_62_chunk
 _timescaledb_internal._hyper_10_63_chunk
 _timescaledb_internal._hyper_10_64_chunk
 _timescaledb_internal._hyper_10_65_chunk
 _timescaledb_internal._hyper_10_66_chunk

SELECT drop_chunks('i2844', older_than => '2000-01-01 18:00'::timestamptz);
               drop_chunks                
------------------------------------------
 _timescaledb_internal._hyper_10_62_chunk
 _timescaledb_internal._hyper_10_63_chunk
 _timescaledb_internal._hyper_10_64_chunk

SELECT decompress_chunk(show_chunks, if_compressed => TRUE) AS decompressed_chunks FROM show_chunks('i2844');
           decompressed_chunks            
------------------------------------------
 _timescaledb_internal._hyper_10_65_chunk
 _timescaledb_internal._hyper_10_66_chunk

ALTER TABLE i2844 SET (timescaledb.compress = FALSE);
-- TEST compression alter schema tests
\ir include/compression_alter.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.
\ir compression_utils.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.
\set ECHO errors
\ir ../../../../test/sql/include/test_utils.sql
-- This file and its contents are licensed under the Apache License 2.0.
-- Please see the included NOTICE for copyright information and
-- LICENSE-APACHE for a copy of the license.
CREATE OR REPLACE FUNCTION assert_true(
    val boolean
)
 RETURNS VOID LANGUAGE PLPGSQL IMMUTABLE AS
$BODY$
BEGIN
    IF val IS NOT TRUE THEN
        RAISE 'Assert failed';
    END IF;
END
$BODY$;
CREATE OR REPLACE FUNCTION assert_equal(
    val1 anyelement,
    val2 anyelement
)
 RETURNS VOID LANGUAGE PLPGSQL IMMUTABLE AS
$BODY$
BEGIN
    IF (val1 = val2) IS NOT TRUE THEN
        RAISE 'Assert failed: % = %',val1,val2;
    END IF;
END
$BODY$;
CREATE TABLE test1 ("Time" timestamptz, intcol integer, bntcol bigint, txtcol text);
SELECT table_name from create_hypertable('test1', 'Time', chunk_time_interval=> INTERVAL '1 day');
 table_name 
------------
 test1

INSERT INTO test1
SELECT t,  gen_rand_minstd(), gen_rand_minstd(), gen_rand_minstd()::text
FROM generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-05 1:00', '1 hour') t;
INSERT INTO test1
SELECT '2018-03-04 2:00', 100, 200, 'hello' ;
ALTER TABLE test1 set (timescaledb.compress, timescaledb.compress_segmentby = 'bntcol', timescaledb.compress_orderby = '"Time" DESC');
SELECT count(compress_chunk(ch)) FROM show_chunks('test1') ch;
 count 
-------
     4

-- TEST: ALTER TABLE add column tests --
ALTER TABLE test1 ADD COLUMN new_coli integer;
ALTER TABLE test1 ADD COLUMN new_colv varchar(30);
SELECT count(*) from test1 where new_coli is not null;
 count 
-------
     0

SELECT count(*) from test1 where new_colv is null;
 count 
-------
    74

--decompress 1 chunk and query again
SELECT count(decompress_chunk(ch)) FROM show_chunks('test1') ch LIMIT 1;
 count 
-------
     4

SELECT count(*) from test1 where new_coli is not null;
 count 
-------
     0

SELECT count(*) from test1 where new_colv is null;
 count 
-------
    74

--compress all chunks and query ---
--create new chunk and fill in data --
INSERT INTO test1 SELECT t,  gen_rand_minstd(), gen_rand_minstd(), gen_rand_minstd()::text , 100, '101t'
FROM generate_series('2018-03-08 1:00'::TIMESTAMPTZ, '2018-03-09 1:00', '1 hour') t;
SELECT count(*) from test1 where new_coli  = 100;
 count 
-------
    25

SELECT count(*) from test1 where new_colv  = '101t';
 count 
-------
    25

SELECT count(compress_chunk(ch, true)) FROM show_chunks('test1') ch;
 count 
-------
     6

SELECT count(*) from test1 where new_coli  = 100;
 count 
-------
    25

SELECT count(*) from test1 where new_colv  = '101t';
 count 
-------
    25

CREATE INDEX new_index ON test1(new_colv);
-- TEST 2:  ALTER TABLE rename column
SELECT * from _timescaledb_catalog.hypertable WHERE table_name = 'test1';
 id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions | chunk_sizing_func_schema |  chunk_sizing_func_name  | chunk_target_size | compression_state | compressed_hypertable_id | status 
----+-------------+------------+------------------------+-------------------------+----------------+--------------------------+--------------------------+-------------------+-------------------+--------------------------+--------
 13 | public      | test1      | _timescaledb_internal  | _hyper_13               |              1 | _timescaledb_functions   | calculate_chunk_interval |                 0 |                 1 |                       14 |      0

SELECT * FROM _timescaledb_catalog.compression_settings WHERE relid='test1'::regclass;
 relid | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst | index 
-------+----------------+-----------+---------+--------------+--------------------+-------
 test1 |                | {bntcol}  | {Time}  | {t}          | {t}                | 

ALTER TABLE test1 RENAME new_coli TO coli;
SELECT * from _timescaledb_catalog.hypertable WHERE table_name = 'test1';
 id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions | chunk_sizing_func_schema |  chunk_sizing_func_name  | chunk_target_size | compression_state | compressed_hypertable_id | status 
----+-------------+------------+------------------------+-------------------------+----------------+--------------------------+--------------------------+-------------------+-------------------+--------------------------+--------
 13 | public      | test1      | _timescaledb_internal  | _hyper_13               |              1 | _timescaledb_functions   | calculate_chunk_interval |                 0 |                 1 |                       14 |      0

SELECT * FROM _timescaledb_catalog.compression_settings WHERE relid='test1'::regclass;
 relid | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst | index 
-------+----------------+-----------+---------+--------------+--------------------+-------
 test1 |                | {bntcol}  | {Time}  | {t}          | {t}                | 

SELECT count(*) from test1 where coli  = 100;
 count 
-------
    25

--rename segment by column name
ALTER TABLE test1 RENAME bntcol TO  bigintcol  ;
SELECT * FROM _timescaledb_catalog.compression_settings WHERE relid='test1'::regclass;
 relid | compress_relid |  segmentby  | orderby | orderby_desc | orderby_nullsfirst | index 
-------+----------------+-------------+---------+--------------+--------------------+-------
 test1 |                | {bigintcol} | {Time}  | {t}          | {t}                | 

--query by segment by column name
SELECT * from test1 WHERE bigintcol = 100;
 Time | intcol | bigintcol | txtcol | coli | new_colv 
------+--------+-----------+--------+------+----------

SELECT * from test1 WHERE bigintcol = 200;
             Time             | intcol | bigintcol | txtcol | coli | new_colv 
------------------------------+--------+-----------+--------+------+----------
 Sun Mar 04 02:00:00 2018 PST |    100 |       200 | hello  |      | 

-- add a new chunk and compress
INSERT INTO test1 SELECT '2019-03-04 2:00', 99, 800, 'newchunk' ;
SELECT count(compress_chunk(ch, true)) FROM show_chunks('test1') ch;
psql:include/compression_alter.sql:68: NOTICE:  chunk "_hyper_13_74_chunk" is already converted to columnstore
psql:include/compression_alter.sql:68: NOTICE:  chunk "_hyper_13_75_chunk" is already converted to columnstore
psql:include/compression_alter.sql:68: NOTICE:  chunk "_hyper_13_76_chunk" is already converted to columnstore
psql:include/compression_alter.sql:68: NOTICE:  chunk "_hyper_13_77_chunk" is already converted to columnstore
psql:include/compression_alter.sql:68: NOTICE:  chunk "_hyper_13_82_chunk" is already converted to columnstore
psql:include/compression_alter.sql:68: NOTICE:  chunk "_hyper_13_83_chunk" is already converted to columnstore
 count 
-------
     7

--check if all chunks have new column names
--both counts should be equal
SELECT count(*) FROM _timescaledb_catalog.chunk
WHERE hypertable_id =  ( SELECT id FROM _timescaledb_catalog.hypertable
                         WHERE table_name = 'test1' );
 count 
-------
     7

SELECT count(*) FROM pg_attribute att
INNER JOIN _timescaledb_catalog.chunk ch ON att.attrelid = format('%I.%I', ch.schema_name, ch.table_name)::regclass
INNER JOIN _timescaledb_catalog.hypertable ht ON ht.id = ch.hypertable_id AND ht.table_name = 'test1'
WHERE
  attname = 'bigintcol';
 count 
-------
     7

--check count on internal compression table too i.e. all the chunks have
--the correct column name
SELECT format('%I.%I', cht.schema_name, cht.table_name) AS "COMPRESSION_TBLNM"
FROM _timescaledb_catalog.hypertable ht, _timescaledb_catalog.hypertable cht
WHERE ht.table_name = 'test1' and cht.id = ht.compressed_hypertable_id \gset
SELECT count(*) FROM pg_attribute att
INNER JOIN _timescaledb_catalog.chunk ch ON att.attrelid = format('%I.%I', ch.schema_name, ch.table_name)::regclass
INNER JOIN _timescaledb_catalog.hypertable ht ON ht.compressed_hypertable_id = ch.hypertable_id AND ht.table_name = 'test1'
WHERE
  attname = 'bigintcol';
 count 
-------
     7

-- check column name truncation with renames
-- check if the name change is reflected for settings
ALTER TABLE test1 RENAME  bigintcol TO
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccabdeeeeeeccccccccccccc;
psql:include/compression_alter.sql:97: NOTICE:  identifier "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccabdeeeeeeccccccccccccc" will be truncated to "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccca"
SELECT * from _timescaledb_catalog.compression_settings WHERE relid = 'test1'::regclass;
 relid | compress_relid |                             segmentby                             | orderby | orderby_desc | orderby_nullsfirst | index 
-------+----------------+-------------------------------------------------------------------+---------+--------------+--------------------+-------
 test1 |                | {cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccca} | {Time}  | {t}          | {t}                | 

SELECT * from timescaledb_information.compression_settings
WHERE hypertable_name = 'test1' and attname like 'ccc%';
 hypertable_schema | hypertable_name |                             attname                             | segmentby_column_index | orderby_column_index | orderby_asc | orderby_nullsfirst 
-------------------+-----------------+-----------------------------------------------------------------+------------------------+----------------------+-------------+--------------------
 public            | test1           | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccca |                      1 |                      |             | 

SELECT count(*) FROM pg_attribute att
INNER JOIN _timescaledb_catalog.chunk ch ON att.attrelid = format('%I.%I', ch.schema_name, ch.table_name)::regclass
INNER JOIN _timescaledb_catalog.hypertable ht ON ht.compressed_hypertable_id = ch.hypertable_id AND ht.table_name = 'test1'
WHERE
  attname like 'ccc%a';
 count 
-------
     7

ALTER TABLE test1 RENAME
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccabdeeeeeeccccccccccccc
TO bigintcol;
psql:include/compression_alter.sql:111: NOTICE:  identifier "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccabdeeeeeeccccccccccccc" will be truncated to "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccca"
SELECT * from timescaledb_information.compression_settings
WHERE hypertable_name = 'test1' and attname = 'bigintcol' ;
 hypertable_schema | hypertable_name |  attname  | segmentby_column_index | orderby_column_index | orderby_asc | orderby_nullsfirst 
-------------------+-----------------+-----------+------------------------+----------------------+-------------+--------------------
 public            | test1           | bigintcol |                      1 |                      |             | 

-- test compression default handling
CREATE TABLE test_defaults(time timestamptz NOT NULL, device_id int);
SELECT create_hypertable('test_defaults','time');
      create_hypertable      
-----------------------------
 (15,public,test_defaults,t)

ALTER TABLE test_defaults SET (timescaledb.compress,timescaledb.compress_segmentby='device_id');
-- create 2 chunks
INSERT INTO test_defaults SELECT '2000-01-01', 1;
INSERT INTO test_defaults SELECT '2001-01-01', 1;
-- compress first chunk
SELECT compress_chunk(show_chunks) AS compressed_chunk FROM show_chunks('test_defaults') ORDER BY show_chunks::text LIMIT 1;
             compressed_chunk             
------------------------------------------
 _timescaledb_internal._hyper_15_92_chunk

SELECT * FROM test_defaults ORDER BY 1;
             time             | device_id 
------------------------------+-----------
 Sat Jan 01 00:00:00 2000 PST |         1
 Mon Jan 01 00:00:00 2001 PST |         1

ALTER TABLE test_defaults ADD COLUMN c1 int;
ALTER TABLE test_defaults ADD COLUMN c2 int NOT NULL DEFAULT 42;
SELECT * FROM test_defaults ORDER BY 1,2;
             time             | device_id | c1 | c2 
------------------------------+-----------+----+----
 Sat Jan 01 00:00:00 2000 PST |         1 |    | 42
 Mon Jan 01 00:00:00 2001 PST |         1 |    | 42

-- try insert into compressed and recompress
INSERT INTO test_defaults SELECT '2000-01-01', 2;
SELECT * FROM test_defaults ORDER BY 1,2;
             time             | device_id | c1 | c2 
------------------------------+-----------+----+----
 Sat Jan 01 00:00:00 2000 PST |         1 |    | 42
 Sat Jan 01 00:00:00 2000 PST |         2 |    | 42
 Mon Jan 01 00:00:00 2001 PST |         1 |    | 42

SELECT compress_chunk(ch) FROM show_chunks('test_defaults') ch LIMIT 1;
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_15_92_chunk

SELECT * FROM test_defaults ORDER BY 1,2;
             time             | device_id | c1 | c2 
------------------------------+-----------+----+----
 Sat Jan 01 00:00:00 2000 PST |         1 |    | 42
 Sat Jan 01 00:00:00 2000 PST |         2 |    | 42
 Mon Jan 01 00:00:00 2001 PST |         1 |    | 42

-- timescale/timescaledb#5412
ALTER TABLE test_defaults ADD COLUMN c3 int NOT NULL DEFAULT 43;
SELECT *,assert_equal(c3,43) FROM test_defaults ORDER BY 1,2;
             time             | device_id | c1 | c2 | c3 | assert_equal 
------------------------------+-----------+----+----+----+--------------
 Sat Jan 01 00:00:00 2000 PST |         1 |    | 42 | 43 | 
 Sat Jan 01 00:00:00 2000 PST |         2 |    | 42 | 43 | 
 Mon Jan 01 00:00:00 2001 PST |         1 |    | 42 | 43 | 

select decompress_chunk(show_chunks('test_defaults'),true);
psql:include/compression_alter.sql:142: NOTICE:  chunk "_hyper_15_93_chunk" is not converted to columnstore
             decompress_chunk             
------------------------------------------
 _timescaledb_internal._hyper_15_92_chunk
 

SELECT *,assert_equal(c3,43) FROM test_defaults ORDER BY 1,2;
             time             | device_id | c1 | c2 | c3 | assert_equal 
------------------------------+-----------+----+----+----+--------------
 Sat Jan 01 00:00:00 2000 PST |         1 |    | 42 | 43 | 
 Sat Jan 01 00:00:00 2000 PST |         2 |    | 42 | 43 | 
 Mon Jan 01 00:00:00 2001 PST |         1 |    | 42 | 43 | 

select compress_chunk(show_chunks('test_defaults'));
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_15_92_chunk
 _timescaledb_internal._hyper_15_93_chunk

SELECT *,assert_equal(c3,43) FROM test_defaults ORDER BY 1,2;
             time             | device_id | c1 | c2 | c3 | assert_equal 
------------------------------+-----------+----+----+----+--------------
 Sat Jan 01 00:00:00 2000 PST |         1 |    | 42 | 43 | 
 Sat Jan 01 00:00:00 2000 PST |         2 |    | 42 | 43 | 
 Mon Jan 01 00:00:00 2001 PST |         1 |    | 42 | 43 | 

-- test dropping columns from compressed
CREATE TABLE test_drop(f1 text, f2 text, f3 text, time timestamptz, device int, o1 text, o2 text);
SELECT create_hypertable('test_drop','time');
    create_hypertable    
-------------------------
 (17,public,test_drop,t)

ALTER TABLE test_drop SET (timescaledb.compress,timescaledb.compress_segmentby='device',timescaledb.compress_orderby='o1,o2');
-- dropping segmentby or orderby columns will fail
\set ON_ERROR_STOP 0
ALTER TABLE test_drop DROP COLUMN time;
psql:include/compression_alter.sql:154: ERROR:  cannot drop column named in partition key
ALTER TABLE test_drop DROP COLUMN o1;
psql:include/compression_alter.sql:155: ERROR:  cannot drop orderby or segmentby column from a hypertable with columnstore enabled
ALTER TABLE test_drop DROP COLUMN o2;
psql:include/compression_alter.sql:156: ERROR:  cannot drop orderby or segmentby column from a hypertable with columnstore enabled
ALTER TABLE test_drop DROP COLUMN device;
psql:include/compression_alter.sql:157: ERROR:  cannot drop orderby or segmentby column from a hypertable with columnstore enabled
\set ON_ERROR_STOP 1
-- switch to WARNING only to suppress compress_chunk NOTICEs
SET client_min_messages TO WARNING;
-- create some chunks each with different physical layout
ALTER TABLE test_drop DROP COLUMN f1;
INSERT INTO test_drop SELECT NULL,NULL,'2000-01-01',1,'o1','o2';
SELECT count(compress_chunk(chunk,true)) FROM show_chunks('test_drop') chunk;
 count 
-------
     1

ALTER TABLE test_drop DROP COLUMN f2;
-- test non-existant column
\set ON_ERROR_STOP 0
ALTER TABLE test_drop DROP COLUMN f10;
psql:include/compression_alter.sql:171: ERROR:  column "f10" of relation "test_drop" does not exist
\set ON_ERROR_STOP 1
ALTER TABLE test_drop DROP COLUMN IF EXISTS f10;
INSERT INTO test_drop SELECT NULL,'2001-01-01',2,'o1','o2';
SELECT count(compress_chunk(chunk,true)) FROM show_chunks('test_drop') chunk;
 count 
-------
     2

ALTER TABLE test_drop DROP COLUMN f3;
INSERT INTO test_drop SELECT '2003-01-01',3,'o1','o2';
SELECT count(compress_chunk(chunk,true)) FROM show_chunks('test_drop') chunk;
 count 
-------
     3

ALTER TABLE test_drop ADD COLUMN c1 TEXT;
ALTER TABLE test_drop ADD COLUMN c2 TEXT;
INSERT INTO test_drop SELECT '2004-01-01',4,'o1','o2','c1','c2-4';
SELECT count(compress_chunk(chunk,true)) FROM show_chunks('test_drop') chunk;
 count 
-------
     4

ALTER TABLE test_drop DROP COLUMN c1;
INSERT INTO test_drop SELECT '2005-01-01',5,'o1','o2','c2-5';
SELECT count(compress_chunk(chunk,true)) FROM show_chunks('test_drop') chunk;
 count 
-------
     5

RESET client_min_messages;
SELECT * FROM test_drop ORDER BY 1;
             time             | device | o1 | o2 |  c2  
------------------------------+--------+----+----+------
 Sat Jan 01 00:00:00 2000 PST |      1 | o1 | o2 | 
 Mon Jan 01 00:00:00 2001 PST |      2 | o1 | o2 | 
 Wed Jan 01 00:00:00 2003 PST |      3 | o1 | o2 | 
 Thu Jan 01 00:00:00 2004 PST |      4 | o1 | o2 | c2-4
 Sat Jan 01 00:00:00 2005 PST |      5 | o1 | o2 | c2-5

-- check dropped columns got removed from catalog
-- only segmentby and orderby are in catalog which we dont support removing
-- atm, so nothing to see here
SELECT * FROM _timescaledb_catalog.hypertable WHERE table_name = 'test_drop';
 id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions | chunk_sizing_func_schema |  chunk_sizing_func_name  | chunk_target_size | compression_state | compressed_hypertable_id | status 
----+-------------+------------+------------------------+-------------------------+----------------+--------------------------+--------------------------+-------------------+-------------------+--------------------------+--------
 17 | public      | test_drop  | _timescaledb_internal  | _hyper_17               |              1 | _timescaledb_functions   | calculate_chunk_interval |                 0 |                 1 |                       18 |      0

SELECT * FROM _timescaledb_catalog.compression_settings WHERE relid = 'test_drop'::regclass;
   relid   | compress_relid | segmentby |   orderby    | orderby_desc | orderby_nullsfirst | index 
-----------+----------------+-----------+--------------+--------------+--------------------+-------
 test_drop |                | {device}  | {o1,o2,time} | {f,f,t}      | {f,f,t}            | 

--TEST tablespaces for compressed chunks with attach_tablespace interface --
CREATE TABLE test2 (timec timestamptz, i integer, t integer);
SELECT table_name from create_hypertable('test2', 'timec', chunk_time_interval=> INTERVAL '1 day');
 table_name 
------------
 test2

SELECT attach_tablespace('tablespace2', 'test2');
 attach_tablespace 
-------------------
 

INSERT INTO test2 SELECT t,  gen_rand_minstd(), 22
FROM generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-02 13:00', '1 hour') t;
ALTER TABLE test2 set (timescaledb.compress, timescaledb.compress_segmentby = 'i', timescaledb.compress_orderby = 'timec');
-- the toast table and its index will have a different name depending on
-- the order the tests run, so anonymize it
SELECT regexp_replace(relname, 'pg_toast_[0-9]+', 'pg_toast_XXX') FROM pg_class
WHERE reltablespace in
  ( SELECT oid from pg_tablespace WHERE spcname = 'tablespace2') ORDER BY 1;
           regexp_replace            
-------------------------------------
 _compressed_hypertable_20
 _hyper_19_107_chunk
 _hyper_19_107_chunk_test2_timec_idx
 test2

-- test compress_chunk() with utility statement (SELECT ... INTO)
SELECT compress_chunk(ch) INTO compressed_chunks FROM show_chunks('test2') ch;
SELECT decompress_chunk(ch) INTO decompressed_chunks FROM show_chunks('test2') ch;
-- compress again
SELECT compress_chunk(ch) FROM show_chunks('test2') ch;
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_19_107_chunk

-- the chunk, compressed chunk + index + toast tables are in tablespace2 now .
-- toast table names differ across runs. So we use count to verify the results
-- instead of printing the table/index names
SELECT count(*) FROM (
SELECT relname FROM pg_class
WHERE reltablespace in
  ( SELECT oid from pg_tablespace WHERE spcname = 'tablespace2'))q;
 count 
-------
     8

DROP TABLE test2 CASCADE;
DROP TABLESPACE tablespace2;
-- Create a table with a compressed table and then delete the
-- compressed table and see that the drop of the hypertable does not
-- generate an error. This scenario can be triggered if an extension
-- is created with compressed hypertables since the tables are dropped
-- as part of the drop of the extension.
CREATE TABLE issue4140("time" timestamptz NOT NULL, device_id int);
SELECT create_hypertable('issue4140', 'time');
    create_hypertable    
-------------------------
 (21,public,issue4140,t)

ALTER TABLE issue4140 SET(timescaledb.compress);
SELECT format('%I.%I', schema_name, table_name)::regclass AS ctable
FROM _timescaledb_catalog.hypertable
WHERE id = (SELECT compressed_hypertable_id FROM _timescaledb_catalog.hypertable WHERE table_name = 'issue4140') \gset
SELECT timescaledb_pre_restore();
 timescaledb_pre_restore 
-------------------------
 t

DROP TABLE :ctable;
SELECT timescaledb_post_restore();
 timescaledb_post_restore 
--------------------------
 t

DROP TABLE issue4140;
-- github issue 5104
CREATE TABLE metric(
	time TIMESTAMPTZ NOT NULL,
	value DOUBLE PRECISION NOT NULL,
	series_id BIGINT NOT NULL);
SELECT create_hypertable('metric', 'time',
	chunk_time_interval => interval '1 h',
	create_default_indexes => false);
  create_hypertable   
----------------------
 (23,public,metric,t)

-- enable compression
ALTER TABLE metric set(timescaledb.compress,
    timescaledb.compress_segmentby = 'series_id, value',
    timescaledb.compress_orderby = 'time'
);
SELECT
      comp_hypertable.schema_name AS "COMP_SCHEMA_NAME",
      comp_hypertable.table_name AS "COMP_TABLE_NAME"
FROM _timescaledb_catalog.hypertable uc_hypertable
INNER JOIN _timescaledb_catalog.hypertable comp_hypertable ON (comp_hypertable.id = uc_hypertable.compressed_hypertable_id)
WHERE uc_hypertable.table_name like 'metric' \gset
-- get definition of compressed hypertable and notice the index
\d :COMP_SCHEMA_NAME.:COMP_TABLE_NAME
Table "_timescaledb_internal._compressed_hypertable_24"
 Column | Type | Collation | Nullable | Default 
--------+------+-----------+----------+---------

-- #5290 Compression can't be enabled on caggs
CREATE TABLE "tEst2" (
    "Id" uuid NOT NULL,
    "Time" timestamp with time zone NOT NULL,
    CONSTRAINT "test2_pkey" PRIMARY KEY ("Id", "Time")
);
SELECT create_hypertable(
  '"tEst2"',
  'Time',
  chunk_time_interval => INTERVAL '1 day'
);
  create_hypertable  
---------------------
 (25,public,tEst2,t)

alter table "tEst2" set (timescaledb.compress=true, timescaledb.compress_segmentby='"Id"');
CREATE MATERIALIZED VIEW "tEst2_mv"
WITH (timescaledb.continuous) AS
SELECT "Id" as "Idd",
   time_bucket(INTERVAL '1 day', "Time") AS "bUcket"
FROM public."tEst2"
GROUP BY "Idd", "bUcket";
NOTICE:  continuous aggregate "tEst2_mv" is already up-to-date
ALTER MATERIALIZED VIEW "tEst2_mv" SET (timescaledb.compress = true);
NOTICE:  defaulting compress_orderby to "bUcket","Idd"
-- #5161 segmentby param
CREATE MATERIALIZED VIEW test1_cont_view2
WITH (timescaledb.continuous,
      timescaledb.materialized_only=true
      )
AS SELECT time_bucket('1 hour', "Time") as t, SUM(intcol) as sum,txtcol as "iDeA"
   FROM test1
   GROUP BY 1,txtcol WITH NO DATA;
\set ON_ERROR_STOP 0
ALTER MATERIALIZED VIEW test1_cont_view2 SET (
  timescaledb.compress = true,
  timescaledb.compress_segmentby = 'invalid_column'
);
ERROR:  column "invalid_column" does not exist
\set ON_ERROR_STOP 1
ALTER MATERIALIZED VIEW test1_cont_view2 SET (
  timescaledb.compress = true
);
NOTICE:  defaulting compress_orderby to t,"iDeA"
ALTER MATERIALIZED VIEW test1_cont_view2 SET (
  timescaledb.compress = true,
  timescaledb.compress_segmentby = '"iDeA"'
);
NOTICE:  defaulting compress_orderby to t
\set ON_ERROR_STOP 0
ALTER MATERIALIZED VIEW test1_cont_view2 SET (
  timescaledb.compress = true,
  timescaledb.compress_orderby = '"iDeA"'
);
ERROR:  cannot use column "iDeA" for both ordering and segmenting
\set ON_ERROR_STOP 1
ALTER MATERIALIZED VIEW test1_cont_view2 SET (
  timescaledb.compress = false
);
DROP TABLE metric CASCADE;
-- inserting into compressed chunks with different physical layouts
CREATE TABLE compression_insert(filler_1 int, filler_2 int, filler_3 int, time timestamptz NOT NULL, device_id int, v0 int, v1 int, v2 float, v3 float);
CREATE INDEX ON compression_insert(time);
CREATE INDEX ON compression_insert(device_id,time);
SELECT create_hypertable('compression_insert','time',create_default_indexes:=false);
        create_hypertable         
----------------------------------
 (31,public,compression_insert,t)

ALTER TABLE compression_insert SET (timescaledb.compress, timescaledb.compress_orderby='time DESC', timescaledb.compress_segmentby='device_id');
-- test without altering physical layout
-- this is a baseline test to compare results with
-- next series of tests which should yield identical results
-- while changing the physical layouts of chunks
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1,  device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-01 0:00:00+0'::timestamptz,'2000-01-03 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
SELECT compress_chunk(ch, true) AS "CHUNK_NAME" FROM show_chunks('compression_insert') ch ORDER BY ch DESC \gset
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1,  device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-04 0:00:00+0'::timestamptz,'2000-01-05 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-01 0:00:00+0'
AND time <= '2000-01-05 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

VACUUM ANALYZE compression_insert;
-- force index scans to check index mapping
-- this verifies that we are actually using compressed chunk index scans
-- previously we could not use indexes on uncompressed chunks due to a bug:
-- https://github.com/timescale/timescaledb/issues/5432
--
-- this check basically makes sure that the indexes are built properly
-- and there are no issues in attribute mappings while building them
SET enable_seqscan = off;
EXPLAIN (buffers off, costs off) SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
--- QUERY PLAN ---
 Finalize GroupAggregate
   Group Key: compression_insert.device_id
   ->  Sort
         Sort Key: compression_insert.device_id
         ->  Append
               ->  Custom Scan (VectorAgg)
                     ->  Custom Scan (ColumnarScan) on _hyper_31_110_chunk
                           ->  Index Scan using compress_hyper_32_111_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_111_chunk
               ->  Partial GroupAggregate
                     Group Key: _hyper_31_110_chunk.device_id
                     ->  Index Only Scan using _hyper_31_110_chunk_compression_insert_device_id_time_idx on _hyper_31_110_chunk

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 |  3596
         2 |  3596
         3 |  3596
         4 |  3596
         5 |  3596

SELECT compress_chunk(:'CHUNK_NAME'::regclass);
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_31_110_chunk

SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-01 0:00:00+0'
AND time <= '2000-01-05 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 |  3596
         2 |  3596
         3 |  3596
         4 |  3596
         5 |  3596

SET enable_seqscan = default;
-- 1. drop column after first insert into chunk, before compressing
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1,  device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-07 0:00:00+0'::timestamptz,'2000-01-09 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
ALTER TABLE compression_insert DROP COLUMN filler_1;
SELECT compress_chunk(format('%I.%I',chunk_schema,chunk_name)) AS "CHUNK_NAME"
FROM timescaledb_information.chunks
WHERE hypertable_name = 'compression_insert' AND NOT is_compressed
ORDER BY chunk_name DESC \gset
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1,  device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-10 0:00:00+0'::timestamptz,'2000-01-11 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-07 0:00:00+0'
AND time <= '2000-01-11 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

VACUUM ANALYZE compression_insert;
-- force index scans to check index mapping
SET enable_seqscan = off;
EXPLAIN (buffers off, costs off) SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
--- QUERY PLAN ---
 Finalize GroupAggregate
   Group Key: compression_insert.device_id
   ->  Merge Append
         Sort Key: compression_insert.device_id
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_110_chunk
                     ->  Index Scan using compress_hyper_32_111_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_111_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_112_chunk
                     ->  Index Scan using compress_hyper_32_113_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_113_chunk
         ->  Partial GroupAggregate
               Group Key: _hyper_31_112_chunk.device_id
               ->  Index Only Scan using _hyper_31_112_chunk_compression_insert_device_id_time_idx on _hyper_31_112_chunk

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 |  7192
         2 |  7192
         3 |  7192
         4 |  7192
         5 |  7192

SELECT compress_chunk(:'CHUNK_NAME'::regclass);
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_31_112_chunk

SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-07 0:00:00+0'
AND time <= '2000-01-11 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 |  7192
         2 |  7192
         3 |  7192
         4 |  7192
         5 |  7192

SET enable_seqscan = default;
-- 2. drop column after compressing chunk
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1, device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-15 0:00:00+0'::timestamptz,'2000-01-17 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
SELECT compress_chunk(format('%I.%I',chunk_schema,chunk_name)) AS "CHUNK_NAME"
FROM timescaledb_information.chunks
WHERE hypertable_name = 'compression_insert' AND NOT is_compressed
ORDER BY chunk_name DESC \gset
ALTER TABLE compression_insert DROP COLUMN filler_2;
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1, device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-18 0:00:00+0'::timestamptz,'2000-01-19 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-15 0:00:00+0'
AND time <= '2000-01-19 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

VACUUM ANALYZE compression_insert;
-- force index scans to check index mapping
SET enable_seqscan = off;
EXPLAIN (buffers off, costs off) SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
--- QUERY PLAN ---
 Finalize GroupAggregate
   Group Key: compression_insert.device_id
   ->  Merge Append
         Sort Key: compression_insert.device_id
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_110_chunk
                     ->  Index Scan using compress_hyper_32_111_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_111_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_112_chunk
                     ->  Index Scan using compress_hyper_32_113_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_113_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_114_chunk
                     ->  Index Scan using compress_hyper_32_115_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_115_chunk
         ->  Partial GroupAggregate
               Group Key: _hyper_31_114_chunk.device_id
               ->  Index Only Scan using _hyper_31_114_chunk_compression_insert_device_id_time_idx on _hyper_31_114_chunk

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 | 10788
         2 | 10788
         3 | 10788
         4 | 10788
         5 | 10788

SELECT compress_chunk(:'CHUNK_NAME'::regclass);
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_31_114_chunk

SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-15 0:00:00+0'
AND time <= '2000-01-19 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 | 10788
         2 | 10788
         3 | 10788
         4 | 10788
         5 | 10788

SET enable_seqscan = default;
-- 3. add new column after first insert into chunk, before compressing
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1, device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-22 0:00:00+0'::timestamptz,'2000-01-24 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
ALTER TABLE compression_insert ADD COLUMN filler_4 int;
SELECT compress_chunk(format('%I.%I',chunk_schema,chunk_name)) AS "CHUNK_NAME"
FROM timescaledb_information.chunks
WHERE hypertable_name = 'compression_insert' AND NOT is_compressed
ORDER BY chunk_name DESC \gset
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1, device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-25 0:00:00+0'::timestamptz,'2000-01-26 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-22 0:00:00+0'
AND time <= '2000-01-26 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

VACUUM ANALYZE compression_insert;
-- force index scans to check index mapping
SET enable_seqscan = off;
EXPLAIN (buffers off, costs off) SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
--- QUERY PLAN ---
 Finalize GroupAggregate
   Group Key: compression_insert.device_id
   ->  Merge Append
         Sort Key: compression_insert.device_id
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_110_chunk
                     ->  Index Scan using compress_hyper_32_111_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_111_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_112_chunk
                     ->  Index Scan using compress_hyper_32_113_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_113_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_114_chunk
                     ->  Index Scan using compress_hyper_32_115_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_115_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_116_chunk
                     ->  Index Scan using compress_hyper_32_117_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_117_chunk
         ->  Partial GroupAggregate
               Group Key: _hyper_31_116_chunk.device_id
               ->  Index Only Scan using _hyper_31_116_chunk_compression_insert_device_id_time_idx on _hyper_31_116_chunk

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 | 14384
         2 | 14384
         3 | 14384
         4 | 14384
         5 | 14384

SELECT compress_chunk(:'CHUNK_NAME'::regclass);
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_31_116_chunk

SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-22 0:00:00+0'
AND time <= '2000-01-26 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 | 14384
         2 | 14384
         3 | 14384
         4 | 14384
         5 | 14384

SET enable_seqscan = default;
-- 4. add new column after compressing chunk
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1, device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-28 0:00:00+0'::timestamptz,'2000-01-30 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
SELECT compress_chunk(format('%I.%I',chunk_schema,chunk_name)) AS "CHUNK_NAME"
FROM timescaledb_information.chunks
WHERE hypertable_name = 'compression_insert' AND NOT is_compressed
ORDER BY chunk_name DESC \gset
ALTER TABLE compression_insert ADD COLUMN filler_5 int;
INSERT INTO compression_insert(time,device_id,v0,v1,v2,v3)
SELECT time, device_id, device_id+1, device_id + 2, device_id + 0.5, NULL
FROM generate_series('2000-01-31 0:00:00+0'::timestamptz,'2000-02-01 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gdevice(device_id);
SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-28 0:00:00+0'
AND time <= '2000-02-01 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

VACUUM ANALYZE compression_insert;
-- force index scans to check index mapping
SET enable_seqscan = off;
EXPLAIN (buffers off, costs off) SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
--- QUERY PLAN ---
 Finalize GroupAggregate
   Group Key: compression_insert.device_id
   ->  Merge Append
         Sort Key: compression_insert.device_id
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_110_chunk
                     ->  Index Scan using compress_hyper_32_111_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_111_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_112_chunk
                     ->  Index Scan using compress_hyper_32_113_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_113_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_114_chunk
                     ->  Index Scan using compress_hyper_32_115_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_115_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_116_chunk
                     ->  Index Scan using compress_hyper_32_117_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_117_chunk
         ->  Custom Scan (VectorAgg)
               ->  Custom Scan (ColumnarScan) on _hyper_31_118_chunk
                     ->  Index Scan using compress_hyper_32_119_chunk_device_id__ts_meta_min_1__ts_me_idx on compress_hyper_32_119_chunk
         ->  Partial GroupAggregate
               Group Key: _hyper_31_118_chunk.device_id
               ->  Index Only Scan using _hyper_31_118_chunk_compression_insert_device_id_time_idx on _hyper_31_118_chunk

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 | 17980
         2 | 17980
         3 | 17980
         4 | 17980
         5 | 17980

SELECT compress_chunk(:'CHUNK_NAME'::regclass);
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_31_118_chunk

SELECT count(*), sum(v0), sum(v1), sum(v2), sum(v3)
FROM compression_insert
WHERE time >= '2000-01-28 0:00:00+0'
AND time <= '2000-02-01 23:55:00+0';
 count |  sum  |  sum  |  sum  | sum 
-------+-------+-------+-------+-----
 17980 | 71920 | 89900 | 62930 |    

SELECT device_id, count(*)
FROM compression_insert
GROUP BY device_id
ORDER BY device_id;
 device_id | count 
-----------+-------
         1 | 17980
         2 | 17980
         3 | 17980
         4 | 17980
         5 | 17980

SET enable_seqscan = default;
DROP TABLE compression_insert;
-- check Chunk Append plans for partially compressed chunks
-- F: fully compressed, P : partially compressed, U: uncompressed
CREATE TABLE test_partials (time timestamptz NOT NULL, a int, b int);
SELECT create_hypertable('test_partials', 'time');
      create_hypertable      
-----------------------------
 (33,public,test_partials,t)

INSERT INTO test_partials
VALUES -- chunk1
  ('2020-01-01 00:00'::timestamptz, 1, 2),
  ('2020-01-01 00:01'::timestamptz, 2, 2),
  ('2020-01-01 00:04'::timestamptz, 1, 2),
  ('2020-01-01 00:05'::timestamptz, 3, 1),
  ('2020-01-01 00:06'::timestamptz, 3, 2),
  ('2020-01-01 00:07'::timestamptz, 3, 3),
  ('2020-01-01 00:08'::timestamptz, 4, 1),
  -- chunk2
  ('2021-01-01 00:00'::timestamptz, 1, 2),
  ('2021-01-01 00:04'::timestamptz, 1, 2),
  ('2021-01-01 00:05'::timestamptz, 3, 1),
  ('2021-01-01 00:06'::timestamptz, 3, 2),
  ('2021-01-01 00:07'::timestamptz, 3, 3),
  -- chunk3
  ('2022-01-01 00:00'::timestamptz, 1, 2),
  ('2022-01-01 00:04'::timestamptz, 1, 2),
  ('2022-01-01 00:05'::timestamptz, 3, 1);
-- enable compression, compress all chunks
ALTER TABLE test_partials SET (timescaledb.compress,
    timescaledb.compress_segmentby = 'a', timescaledb.compress_orderby = 'time desc');
SELECT compress_chunk(show_chunks('test_partials'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_33_120_chunk
 _timescaledb_internal._hyper_33_121_chunk
 _timescaledb_internal._hyper_33_122_chunk

VACUUM ANALYZE test_partials;
-- Chunks must be different size for plan stability
select count(*) from test_partials group by tableoid order by count(*) desc;
 count 
-------
     7
     5
     3

-- fully compressed
EXPLAIN (buffers off, costs off) SELECT * FROM test_partials ORDER BY time;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on test_partials
   Order: test_partials."time"
   ->  Sort
         Sort Key: _hyper_33_120_chunk."time"
         ->  Custom Scan (ColumnarScan) on _hyper_33_120_chunk
               ->  Seq Scan on compress_hyper_34_123_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_33_121_chunk
         ->  Sort
               Sort Key: compress_hyper_34_124_chunk._ts_meta_min_1
               ->  Seq Scan on compress_hyper_34_124_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_33_122_chunk
         ->  Sort
               Sort Key: compress_hyper_34_125_chunk._ts_meta_min_1
               ->  Seq Scan on compress_hyper_34_125_chunk

-- test P, F, F
INSERT INTO test_partials VALUES ('2020-01-01 00:03', 1, 2);
vacuum analyze test_partials;
-- Chunks must be different size for plan stability
select count(*) from test_partials group by tableoid order by count(*) desc;
 count 
-------
     8
     5
     3

EXPLAIN (buffers off, costs off) SELECT * FROM test_partials ORDER BY time;
--- QUERY PLAN ---
 Sort
   Sort Key: test_partials."time"
   ->  Append
         ->  Custom Scan (ColumnarScan) on _hyper_33_120_chunk
               ->  Seq Scan on compress_hyper_34_123_chunk
         ->  Seq Scan on _hyper_33_120_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_33_121_chunk
               ->  Seq Scan on compress_hyper_34_124_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_33_122_chunk
               ->  Seq Scan on compress_hyper_34_125_chunk

-- verify correct results
SELECT * FROM test_partials ORDER BY time;
             time             | a | b 
------------------------------+---+---
 Wed Jan 01 00:00:00 2020 PST | 1 | 2
 Wed Jan 01 00:01:00 2020 PST | 2 | 2
 Wed Jan 01 00:03:00 2020 PST | 1 | 2
 Wed Jan 01 00:04:00 2020 PST | 1 | 2
 Wed Jan 01 00:05:00 2020 PST | 3 | 1
 Wed Jan 01 00:06:00 2020 PST | 3 | 2
 Wed Jan 01 00:07:00 2020 PST | 3 | 3
 Wed Jan 01 00:08:00 2020 PST | 4 | 1
 Fri Jan 01 00:00:00 2021 PST | 1 | 2
 Fri Jan 01 00:04:00 2021 PST | 1 | 2
 Fri Jan 01 00:05:00 2021 PST | 3 | 1
 Fri Jan 01 00:06:00 2021 PST | 3 | 2
 Fri Jan 01 00:07:00 2021 PST | 3 | 3
 Sat Jan 01 00:00:00 2022 PST | 1 | 2
 Sat Jan 01 00:04:00 2022 PST | 1 | 2
 Sat Jan 01 00:05:00 2022 PST | 3 | 1

-- make second chunk partially compressed
-- P, P, F
INSERT INTO test_partials VALUES ('2021-01-01 00:03', 1, 2);
VACUUM ANALYZE test_partials;
-- Chunks must be different size for plan stability
select count(*) from test_partials group by tableoid order by count(*) desc;
 count 
-------
     8
     6
     3

EXPLAIN (buffers off, costs off) SELECT * FROM test_partials ORDER BY time;
--- QUERY PLAN ---
 Sort
   Sort Key: test_partials."time"
   ->  Append
         ->  Custom Scan (ColumnarScan) on _hyper_33_120_chunk
               ->  Seq Scan on compress_hyper_34_123_chunk
         ->  Seq Scan on _hyper_33_120_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_33_121_chunk
               ->  Seq Scan on compress_hyper_34_124_chunk
         ->  Seq Scan on _hyper_33_121_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_33_122_chunk
               ->  Seq Scan on compress_hyper_34_125_chunk

-- verify correct results
SELECT * FROM test_partials ORDER BY time;
             time             | a | b 
------------------------------+---+---
 Wed Jan 01 00:00:00 2020 PST | 1 | 2
 Wed Jan 01 00:01:00 2020 PST | 2 | 2
 Wed Jan 01 00:03:00 2020 PST | 1 | 2
 Wed Jan 01 00:04:00 2020 PST | 1 | 2
 Wed Jan 01 00:05:00 2020 PST | 3 | 1
 Wed Jan 01 00:06:00 2020 PST | 3 | 2
 Wed Jan 01 00:07:00 2020 PST | 3 | 3
 Wed Jan 01 00:08:00 2020 PST | 4 | 1
 Fri Jan 01 00:00:00 2021 PST | 1 | 2
 Fri Jan 01 00:03:00 2021 PST | 1 | 2
 Fri Jan 01 00:04:00 2021 PST | 1 | 2
 Fri Jan 01 00:05:00 2021 PST | 3 | 1
 Fri Jan 01 00:06:00 2021 PST | 3 | 2
 Fri Jan 01 00:07:00 2021 PST | 3 | 3
 Sat Jan 01 00:00:00 2022 PST | 1 | 2
 Sat Jan 01 00:04:00 2022 PST | 1 | 2
 Sat Jan 01 00:05:00 2022 PST | 3 | 1

-- third chunk partially compressed and add new chunk
-- P, P, P, U
INSERT INTO test_partials VALUES ('2022-01-01 00:03', 1, 2);
INSERT INTO test_partials VALUES ('2023-01-01 00:03', 1, 2);
INSERT INTO test_partials VALUES ('2023-01-01 00:05', 3, 1);
VACUUM ANALYZE test_partials;
-- Chunks must be different size for plan stability
select count(*) from test_partials group by tableoid order by count(*) desc;
 count 
-------
     8
     6
     4
     2

EXPLAIN (buffers off, costs off) SELECT * FROM test_partials ORDER BY time;
--- QUERY PLAN ---
 Sort
   Sort Key: test_partials."time"
   ->  Append
         ->  Custom Scan (ColumnarScan) on _hyper_33_120_chunk
               ->  Seq Scan on compress_hyper_34_123_chunk
         ->  Seq Scan on _hyper_33_120_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_33_121_chunk
               ->  Seq Scan on compress_hyper_34_124_chunk
         ->  Seq Scan on _hyper_33_121_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_33_122_chunk
               ->  Seq Scan on compress_hyper_34_125_chunk
         ->  Seq Scan on _hyper_33_122_chunk
         ->  Seq Scan on _hyper_33_126_chunk

-- F, F, P, U
-- recompress all chunks
DO $$
DECLARE
  chunk regclass;
BEGIN
  FOR chunk IN
  SELECT format('%I.%I', schema_name, table_name)::regclass
    FROM _timescaledb_catalog.chunk WHERE status = 9 and compressed_chunk_id IS NOT NULL AND NOT dropped
    ORDER BY id
  LOOP
    EXECUTE format('select decompress_chunk(''%s'');', chunk::text);
    EXECUTE format('select compress_chunk(''%s'');', chunk::text);
  END LOOP;
END
$$;
INSERT INTO test_partials VALUES ('2022-01-01 00:02', 1, 2);
VACUUM ANALYZE test_partials;
-- Chunks must be different size for plan stability
select count(*) from test_partials group by tableoid order by count(*) desc;
 count 
-------
     8
     6
     5
     2

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM test_partials ORDER BY time;
--- QUERY PLAN ---
 Sort
   Sort Key: test_partials."time"
   ->  Append
         ->  Custom Scan (ColumnarScan) on _hyper_33_120_chunk
               ->  Seq Scan on compress_hyper_34_127_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_33_121_chunk
               ->  Seq Scan on compress_hyper_34_128_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_33_122_chunk
               ->  Seq Scan on compress_hyper_34_129_chunk
         ->  Seq Scan on _hyper_33_122_chunk
         ->  Seq Scan on _hyper_33_126_chunk

-- F, F, P, F, F
INSERT INTO test_partials VALUES ('2024-01-01 00:02', 1, 2);
SELECT compress_chunk(c) FROM show_chunks('test_partials', newer_than => '2022-01-01') c;
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_33_126_chunk
 _timescaledb_internal._hyper_33_130_chunk

VACUUM ANALYZE test_partials;
-- Chunks must be different size for plan stability
select count(*) from test_partials group by tableoid order by count(*) desc;
 count 
-------
     8
     6
     5
     2
     1

EXPLAIN (buffers off, costs off) SELECT * FROM test_partials ORDER BY time;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on test_partials
   Order: test_partials."time"
   ->  Sort
         Sort Key: _hyper_33_120_chunk."time"
         ->  Custom Scan (ColumnarScan) on _hyper_33_120_chunk
               ->  Seq Scan on compress_hyper_34_127_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_33_121_chunk
         ->  Sort
               Sort Key: compress_hyper_34_128_chunk._ts_meta_min_1
               ->  Seq Scan on compress_hyper_34_128_chunk
   ->  Merge Append
         Sort Key: test_partials."time"
         ->  Custom Scan (ColumnarScan) on _hyper_33_122_chunk
               ->  Sort
                     Sort Key: compress_hyper_34_129_chunk._ts_meta_min_1
                     ->  Seq Scan on compress_hyper_34_129_chunk
         ->  Index Scan Backward using _hyper_33_122_chunk_test_partials_time_idx on _hyper_33_122_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_33_126_chunk
         ->  Sort
               Sort Key: compress_hyper_34_131_chunk._ts_meta_min_1
               ->  Seq Scan on compress_hyper_34_131_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_33_130_chunk
         ->  Sort
               Sort Key: compress_hyper_34_132_chunk._ts_meta_min_1
               ->  Seq Scan on compress_hyper_34_132_chunk

-- verify result correctness
SELECT * FROM test_partials ORDER BY time;
             time             | a | b 
------------------------------+---+---
 Wed Jan 01 00:00:00 2020 PST | 1 | 2
 Wed Jan 01 00:01:00 2020 PST | 2 | 2
 Wed Jan 01 00:03:00 2020 PST | 1 | 2
 Wed Jan 01 00:04:00 2020 PST | 1 | 2
 Wed Jan 01 00:05:00 2020 PST | 3 | 1
 Wed Jan 01 00:06:00 2020 PST | 3 | 2
 Wed Jan 01 00:07:00 2020 PST | 3 | 3
 Wed Jan 01 00:08:00 2020 PST | 4 | 1
 Fri Jan 01 00:00:00 2021 PST | 1 | 2
 Fri Jan 01 00:03:00 2021 PST | 1 | 2
 Fri Jan 01 00:04:00 2021 PST | 1 | 2
 Fri Jan 01 00:05:00 2021 PST | 3 | 1
 Fri Jan 01 00:06:00 2021 PST | 3 | 2
 Fri Jan 01 00:07:00 2021 PST | 3 | 3
 Sat Jan 01 00:00:00 2022 PST | 1 | 2
 Sat Jan 01 00:02:00 2022 PST | 1 | 2
 Sat Jan 01 00:03:00 2022 PST | 1 | 2
 Sat Jan 01 00:04:00 2022 PST | 1 | 2
 Sat Jan 01 00:05:00 2022 PST | 3 | 1
 Sun Jan 01 00:03:00 2023 PST | 1 | 2
 Sun Jan 01 00:05:00 2023 PST | 3 | 1
 Mon Jan 01 00:02:00 2024 PST | 1 | 2

-- Chunks must be different size for plan stability
select count(*) from test_partials group by tableoid order by count(*) desc;
 count 
-------
     8
     6
     5
     2
     1

-- add test for space partioning with partial chunks
CREATE TABLE space_part (time timestamptz, a int, b int, c int);
SELECT create_hypertable('space_part', 'time', chunk_time_interval => INTERVAL '1 day');
    create_hypertable     
--------------------------
 (35,public,space_part,t)

INSERT INTO space_part VALUES
-- chunk1
('2020-01-01 00:00', 1, 1, 1),
('2020-01-01 00:00', 2, 1, 1),
('2020-01-01 00:03', 1, 1, 1),
('2020-01-01 00:03', 2, 1, 1);
INSERT INTO space_part values
-- chunk2
('2021-01-01 00:00', 1, 1, 1),
('2021-01-01 00:00', 2, 1, 1),
('2021-01-01 00:03', 1, 1, 1),
('2021-01-01 00:03', 2, 1, 1);
-- compress them
ALTER TABLE space_part SET (timescaledb.compress, timescaledb.orderby='"time" desc');
SELECT compress_chunk(show_chunks('space_part'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_35_133_chunk
 _timescaledb_internal._hyper_35_134_chunk

-- make first chunk partial
INSERT INTO space_part VALUES
-- chunk1
('2020-01-01 00:01', 1, 1, 1),
('2020-01-01 00:01', 2, 1, 1);
VACUUM ANALYZE space_part;
-------- now enable the space partitioning, this will take effect for chunks created subsequently
SELECT add_dimension('space_part', 'a', number_partitions => 5);
       add_dimension        
----------------------------
 (19,public,space_part,a,t)

-- plan is still the same
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM space_part ORDER BY time;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on space_part
   Order: space_part."time"
   ->  Merge Append
         Sort Key: space_part."time"
         ->  Custom Scan (ColumnarScan) on _hyper_35_133_chunk
               ->  Sort
                     Sort Key: compress_hyper_36_135_chunk._ts_meta_min_1, compress_hyper_36_135_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_36_135_chunk
         ->  Index Scan Backward using _hyper_35_133_chunk_space_part_time_idx on _hyper_35_133_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_35_134_chunk
         ->  Sort
               Sort Key: compress_hyper_36_136_chunk._ts_meta_min_1, compress_hyper_36_136_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_36_136_chunk

-- now add more chunks that do adhere to the new space partitioning
-- chunks 3,4
INSERT INTO space_part VALUES
('2022-01-01 00:00', 1, 1, 1),
('2022-01-01 00:00', 2, 1, 1),
('2022-01-01 00:03', 1, 1, 1),
('2022-01-01 00:03', 2, 1, 1);
VACUUM ANALYZE space_part;
-- plan still ok
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM space_part ORDER BY time;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on space_part
   Order: space_part."time"
   ->  Merge Append
         Sort Key: space_part."time"
         ->  Custom Scan (ColumnarScan) on _hyper_35_133_chunk
               ->  Sort
                     Sort Key: compress_hyper_36_135_chunk._ts_meta_min_1, compress_hyper_36_135_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_36_135_chunk
         ->  Index Scan Backward using _hyper_35_133_chunk_space_part_time_idx on _hyper_35_133_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_35_134_chunk
         ->  Sort
               Sort Key: compress_hyper_36_136_chunk._ts_meta_min_1, compress_hyper_36_136_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_36_136_chunk
   ->  Merge Append
         Sort Key: space_part."time"
         ->  Index Scan Backward using _hyper_35_137_chunk_space_part_time_idx on _hyper_35_137_chunk
         ->  Index Scan Backward using _hyper_35_138_chunk_space_part_time_idx on _hyper_35_138_chunk

-- compress them
SELECT compress_chunk(c, if_not_compressed=>true) FROM show_chunks('space_part') c;
NOTICE:  chunk "_hyper_35_134_chunk" is already converted to columnstore
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_35_133_chunk
 _timescaledb_internal._hyper_35_134_chunk
 _timescaledb_internal._hyper_35_137_chunk
 _timescaledb_internal._hyper_35_138_chunk

VACUUM ANALYZE space_part;
-- plan still ok
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM space_part ORDER BY time;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on space_part
   Order: space_part."time"
   ->  Custom Scan (ColumnarScan) on _hyper_35_133_chunk
         ->  Sort
               Sort Key: compress_hyper_36_135_chunk._ts_meta_min_1, compress_hyper_36_135_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_36_135_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_35_134_chunk
         ->  Sort
               Sort Key: compress_hyper_36_136_chunk._ts_meta_min_1, compress_hyper_36_136_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_36_136_chunk
   ->  Merge Append
         Sort Key: space_part."time"
         ->  Custom Scan (ColumnarScan) on _hyper_35_137_chunk
               ->  Sort
                     Sort Key: compress_hyper_36_139_chunk._ts_meta_min_1, compress_hyper_36_139_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_36_139_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_35_138_chunk
               ->  Sort
                     Sort Key: compress_hyper_36_140_chunk._ts_meta_min_1, compress_hyper_36_140_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_36_140_chunk

-- make second one of them partial
insert into space_part values
('2022-01-01 00:02', 2, 1, 1),
('2022-01-01 00:02', 2, 1, 1);
VACUUM ANALYZE space_part;
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM space_part ORDER BY time;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on space_part
   Order: space_part."time"
   ->  Custom Scan (ColumnarScan) on _hyper_35_133_chunk
         ->  Sort
               Sort Key: compress_hyper_36_135_chunk._ts_meta_min_1, compress_hyper_36_135_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_36_135_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_35_134_chunk
         ->  Sort
               Sort Key: compress_hyper_36_136_chunk._ts_meta_min_1, compress_hyper_36_136_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_36_136_chunk
   ->  Merge Append
         Sort Key: space_part."time"
         ->  Custom Scan (ColumnarScan) on _hyper_35_137_chunk
               ->  Sort
                     Sort Key: compress_hyper_36_139_chunk._ts_meta_min_1, compress_hyper_36_139_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_36_139_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_35_138_chunk
               ->  Sort
                     Sort Key: compress_hyper_36_140_chunk._ts_meta_min_1, compress_hyper_36_140_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_36_140_chunk
         ->  Index Scan Backward using _hyper_35_138_chunk_space_part_time_idx on _hyper_35_138_chunk

-- make other one partial too
INSERT INTO space_part VALUES
('2022-01-01 00:02', 1, 1, 1);
VACUUM ANALYZE space_part;
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM space_part ORDER BY time;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on space_part
   Order: space_part."time"
   ->  Custom Scan (ColumnarScan) on _hyper_35_133_chunk
         ->  Sort
               Sort Key: compress_hyper_36_135_chunk._ts_meta_min_1, compress_hyper_36_135_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_36_135_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_35_134_chunk
         ->  Sort
               Sort Key: compress_hyper_36_136_chunk._ts_meta_min_1, compress_hyper_36_136_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_36_136_chunk
   ->  Merge Append
         Sort Key: space_part."time"
         ->  Custom Scan (ColumnarScan) on _hyper_35_137_chunk
               ->  Sort
                     Sort Key: compress_hyper_36_139_chunk._ts_meta_min_1, compress_hyper_36_139_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_36_139_chunk
         ->  Index Scan Backward using _hyper_35_137_chunk_space_part_time_idx on _hyper_35_137_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_35_138_chunk
               ->  Sort
                     Sort Key: compress_hyper_36_140_chunk._ts_meta_min_1, compress_hyper_36_140_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_36_140_chunk
         ->  Index Scan Backward using _hyper_35_138_chunk_space_part_time_idx on _hyper_35_138_chunk

-- test creation of unique expression index does not interfere with enabling compression
-- github issue 6205
create table mytab (col1 varchar(100) not null, col2 integer not null,
value double precision not null default 0, arrival_ts timestamptz not null, departure_ts timestamptz not null
default current_timestamp);
select create_hypertable('mytab', 'departure_ts');
WARNING:  column type "character varying" used for "col1" does not follow best practices
  create_hypertable  
---------------------
 (37,public,mytab,t)

create unique index myidx_unique ON
mytab (lower(col1::text), col2, departure_ts, arrival_ts);
alter table mytab set (timescaledb.compress);
-- github issue 6186
-- verify inserting into index works as expected during decompression
insert into mytab (col1, col2, value, arrival_ts, departure_ts)
values ('meter1', 1, 2.3, '2022-01-01'::timestamptz, '2022-01-01'::timestamptz),
('meTEr1', 2, 2.5, '2022-01-01'::timestamptz, '2022-01-01'::timestamptz),
('METEr1', 1, 2.9, '2022-01-01'::timestamptz, '2022-01-01 01:00'::timestamptz);
select compress_chunk(show_chunks('mytab'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_37_141_chunk

REINDEX TABLE mytab; -- should update index
select decompress_chunk(show_chunks('mytab'));
             decompress_chunk              
-------------------------------------------
 _timescaledb_internal._hyper_37_141_chunk

vacuum analyze mytab;
\set EXPLAIN 'EXPLAIN (buffers off, costs off,timing off,summary off)'
\set EXPLAIN_ANALYZE 'EXPLAIN (analyze,buffers off, costs off,timing off,summary off)'
-- do index scan on uncompressed, should give correct results
set enable_seqscan = off;
set enable_indexscan = on;
:EXPLAIN_ANALYZE select * from mytab where lower(col1::text) = 'meter1';
--- QUERY PLAN ---
 Index Scan using _hyper_37_141_chunk_myidx_unique on _hyper_37_141_chunk (actual rows=3.00 loops=1)
   Index Cond: (lower((col1)::text) = 'meter1'::text)

select * from mytab where lower(col1::text) = 'meter1';
  col1  | col2 | value |          arrival_ts          |         departure_ts         
--------+------+-------+------------------------------+------------------------------
 meter1 |    1 |   2.3 | Sat Jan 01 00:00:00 2022 PST | Sat Jan 01 00:00:00 2022 PST
 METEr1 |    1 |   2.9 | Sat Jan 01 00:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST
 meTEr1 |    2 |   2.5 | Sat Jan 01 00:00:00 2022 PST | Sat Jan 01 00:00:00 2022 PST

-- check predicate index
CREATE INDEX myidx_partial ON mytab (value)
WHERE (value > 2.4 AND value < 3);
select compress_chunk(show_chunks('mytab'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_37_141_chunk

select decompress_chunk(show_chunks('mytab'));
             decompress_chunk              
-------------------------------------------
 _timescaledb_internal._hyper_37_141_chunk

:EXPLAIN_ANALYZE SELECT * FROM mytab WHERE value BETWEEN 2.4 AND 2.8;
--- QUERY PLAN ---
 Seq Scan on _hyper_37_141_chunk (actual rows=1.00 loops=1)
   Filter: ((value >= '2.4'::double precision) AND (value <= '2.8'::double precision))
   Rows Removed by Filter: 2

-- check exclusion constraint with index - should not be supported
CREATE TABLE hyper_ex (
    time timestamptz,
    device_id TEXT NOT NULL,
    sensor_1 NUMERIC NULL DEFAULT 1,
    canceled boolean DEFAULT false,
    EXCLUDE USING btree (
        time WITH =, device_id WITH =
    ) WHERE (not canceled)
);
SELECT * FROM create_hypertable('hyper_ex', 'time', chunk_time_interval=> interval '1 month');
 hypertable_id | schema_name | table_name | created 
---------------+-------------+------------+---------
            39 | public      | hyper_ex   | t

INSERT INTO hyper_ex(time, device_id,sensor_1) VALUES
('2022-01-01', 'dev2', 11),
('2022-01-01 01:00', 'dev2', 12);
\set ON_ERROR_STOP 0
ALTER TABLE hyper_ex SET (timescaledb.compress, timescaledb.compress_segmentby='device_id');
ERROR:  constraint hyper_ex_time_device_id_excl is not supported for converting to columnstore
\set ON_ERROR_STOP 1
-- check deferred uniqueness
CREATE TABLE hyper_unique_deferred (
  time BIGINT UNIQUE DEFERRABLE INITIALLY DEFERRED,
  device_id TEXT NOT NULL,
  sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 10)
);
SELECT * FROM create_hypertable('hyper_unique_deferred', 'time', chunk_time_interval => 10);
 hypertable_id | schema_name |      table_name       | created 
---------------+-------------+-----------------------+---------
            40 | public      | hyper_unique_deferred | t

INSERT INTO hyper_unique_deferred(time, device_id,sensor_1) VALUES (1257987700000000000, 'dev2', 11);
alter table hyper_unique_deferred set (timescaledb.compress);
select compress_chunk(show_chunks('hyper_unique_deferred')); -- also worked fine before 2.11.0
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_40_145_chunk

select decompress_chunk(show_chunks('hyper_unique_deferred'));
             decompress_chunk              
-------------------------------------------
 _timescaledb_internal._hyper_40_145_chunk

\set ON_ERROR_STOP 0
begin; insert INTO hyper_unique_deferred values (1257987700000000000, 'dev1', 1); abort;
ERROR:  new row for relation "_hyper_40_145_chunk" violates check constraint "hyper_unique_deferred_sensor_1_check"
\set ON_ERROR_STOP 1
select compress_chunk(show_chunks('hyper_unique_deferred'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_40_145_chunk

\set ON_ERROR_STOP 0
begin; insert INTO hyper_unique_deferred values (1257987700000000000, 'dev1', 1); abort;
ERROR:  duplicate key value violates unique constraint "145_2_hyper_unique_deferred_time_key"
\set ON_ERROR_STOP 1
-- tests chunks being compressed using different segmentby settings
-- github issue #7102
CREATE TABLE compression_drop(time timestamptz NOT NULL, v0 int, v1 int);
CREATE INDEX ON compression_drop(time);
CREATE INDEX ON compression_drop(v0,time);
SELECT create_hypertable('compression_drop','time',create_default_indexes:=false);
       create_hypertable        
--------------------------------
 (42,public,compression_drop,t)

ALTER TABLE compression_drop SET (timescaledb.compress, timescaledb.compress_orderby='time DESC', timescaledb.compress_segmentby='v0');
-- insert data and compress chunk
INSERT INTO compression_drop(time, v0, v1)
SELECT time, v0, v0+1
FROM generate_series('2000-01-01 0:00:00+0'::timestamptz,'2000-01-03 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gv0(v0);
SELECT compress_chunk(ch, true) AS "CHUNK_NAME" FROM show_chunks('compression_drop') ch ORDER BY ch DESC \gset
-- change segmentby column
ALTER TABLE compression_drop SET (timescaledb.compress_segmentby='v1');
-- insert more data and compress next chunk
INSERT INTO compression_drop(time, v0, v1)
SELECT time, v0, v0+1
FROM generate_series('2000-01-07 0:00:00+0'::timestamptz,'2000-01-09 23:55:00+0','2m') gtime(time), generate_series(1,5,1) gv0(v0);
SELECT compress_chunk(format('%I.%I',chunk_schema,chunk_name)) AS "CHUNK_NAME"
FROM timescaledb_information.chunks
WHERE hypertable_name = 'compression_drop' AND NOT is_compressed;
                CHUNK_NAME                 
-------------------------------------------
 _timescaledb_internal._hyper_42_150_chunk

-- try dropping column v0, should fail
\set ON_ERROR_STOP 0
ALTER TABLE compression_drop DROP COLUMN v0;
ERROR:  cannot drop orderby or segmentby column from a chunk with columnstore enabled
\set ON_ERROR_STOP 1
DROP TABLE compression_drop;
SET client_min_messages = ERROR;
CREATE TABLE test2 (ts timestamptz, i integer not null, b bigint, t text);
SELECT table_name from create_hypertable('test2', 'ts', chunk_time_interval=> INTERVAL '1 day');
 table_name 
------------
 test2

INSERT INTO test2
SELECT t,
       gen_rand_minstd(),
       gen_rand_minstd(),
       gen_rand_minstd()::text
FROM   generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-28 1:00', '1 hour') t;
ALTER TABLE test2 SET (
      timescaledb.compress,
      timescaledb.compress_segmentby = 'b',
      timescaledb.compress_orderby = 'ts DESC'
);
\set ON_ERROR_STOP 0
INSERT INTO test2(ts,b,t) VALUES ('2024-11-18 18:04:51',99,'magic');
ERROR:  null value in column "i" of relation "_hyper_44_179_chunk" violates not-null constraint
\set ON_ERROR_STOP 1
ALTER TABLE test2 ALTER COLUMN i DROP NOT NULL;
INSERT INTO test2(ts,b,t) VALUES ('2024-11-18 18:04:51',99,'magic');
SELECT count(*) FROM test2 WHERE i IS NULL;
 count 
-------
     1

SELECT count(compress_chunk(ch)) FROM show_chunks('test2') ch;
 count 
-------
    28

SELECT count(*) FROM test2 WHERE i IS NULL;
 count 
-------
     1

SELECT count(decompress_chunk(ch)) FROM show_chunks('test2') ch;
 count 
-------
    28

SELECT count(*) FROM test2 WHERE i IS NULL;
 count 
-------
     1

SELECT count(compress_chunk(ch)) FROM show_chunks('test2') ch;
 count 
-------
    28

SELECT count(*) FROM test2 WHERE i IS NULL;
 count 
-------
     1

\set ON_ERROR_STOP 0
ALTER TABLE test2 ALTER COLUMN i SET NOT NULL;
ERROR:  column "i" of relation "_hyper_44_180_chunk" contains null values
DELETE FROM test2 WHERE i IS NULL;
SELECT count(*) FROM test2 WHERE i IS NULL;
 count 
-------
     0

ALTER TABLE test2 ALTER COLUMN i SET NOT NULL;
\set ON_ERROR_STOP 1
-- test set not null
CREATE TABLE test_notnull(time timestamptz, device text, value float);
SELECT create_hypertable('test_notnull','time');
     create_hypertable      
----------------------------
 (46,public,test_notnull,t)

ALTER TABLE test_notnull SET (timescaledb.compress, timescaledb.compress_segmentby='device');
INSERT INTO test_notnull VALUES ('2025-01-01','d1',NULL);
INSERT INTO test_notnull VALUES ('2025-01-01',NULL,NULL);
-- should fail since we have NULL value
\set ON_ERROR_STOP 0
ALTER TABLE test_notnull ALTER COLUMN value SET NOT NULL;
ERROR:  column "value" of relation "_hyper_46_237_chunk" contains null values
ALTER TABLE test_notnull ALTER COLUMN device SET NOT NULL;
ERROR:  column "device" of relation "_hyper_46_237_chunk" contains null values
\set ON_ERROR_STOP 1
SELECT compress_chunk(show_chunks('test_notnull'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_46_237_chunk

-- should fail since we have NULL value
\set ON_ERROR_STOP 0
ALTER TABLE test_notnull ALTER COLUMN value SET NOT NULL;
ERROR:  column "value" of relation "_hyper_46_237_chunk" contains null values
ALTER TABLE test_notnull ALTER COLUMN device SET NOT NULL;
ERROR:  column "device" of relation "_hyper_46_237_chunk" contains null values
\set ON_ERROR_STOP 1
UPDATE test_notnull SET value = 1;
ALTER TABLE test_notnull ALTER COLUMN value SET NOT NULL;
ALTER TABLE test_notnull ALTER COLUMN value DROP NOT NULL;
SELECT compress_chunk(show_chunks('test_notnull'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_46_237_chunk

ALTER TABLE test_notnull ALTER COLUMN value SET NOT NULL;
ALTER TABLE test_notnull ALTER COLUMN value DROP NOT NULL;
-- device still has NULL
\set ON_ERROR_STOP 0
ALTER TABLE test_notnull ALTER COLUMN device SET NOT NULL;
ERROR:  column "device" of relation "_hyper_46_237_chunk" contains null values
\set ON_ERROR_STOP 1
UPDATE test_notnull SET device = 'd1';
ALTER TABLE test_notnull ALTER COLUMN device SET NOT NULL;
ALTER TABLE test_notnull ALTER COLUMN device DROP NOT NULL;
SELECT compress_chunk(show_chunks('test_notnull'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_46_237_chunk

ALTER TABLE test_notnull ALTER COLUMN device SET NOT NULL;
ALTER TABLE test_notnull ALTER COLUMN device DROP NOT NULL;
-- test partial compressed chunks
-- NULL in uncompressed part only
INSERT INTO test_notnull VALUES ('2025-01-01',NULL,NULL);
\set ON_ERROR_STOP 0
ALTER TABLE test_notnull ALTER COLUMN device SET NOT NULL;
ERROR:  column "device" of relation "_hyper_46_237_chunk" contains null values
\set ON_ERROR_STOP 1
-- NULL in compressed part only
SELECT compress_chunk(show_chunks('test_notnull'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_46_237_chunk

INSERT INTO test_notnull VALUES ('2025-01-01','d1',2);
\set ON_ERROR_STOP 0
ALTER TABLE test_notnull ALTER COLUMN device SET NOT NULL;
ERROR:  column "device" of relation "_hyper_46_237_chunk" contains null values
\set ON_ERROR_STOP 1
-- test added columns and defaults
ALTER TABLE test_notnull ADD COLUMN c1 int;
\set ON_ERROR_STOP 0
ALTER TABLE test_notnull ALTER COLUMN c1 SET NOT NULL;
ERROR:  column "c1" of relation "_hyper_46_237_chunk" contains null values
\set ON_ERROR_STOP 1
ALTER TABLE test_notnull ADD COLUMN c2 int DEFAULT 42;
ALTER TABLE test_notnull ALTER COLUMN c2 SET NOT NULL;
ALTER TABLE test_notnull ALTER COLUMN c2 DROP NOT NULL;
-- test column with default and explicit NULL
UPDATE test_notnull SET c2 = NULL;
\set ON_ERROR_STOP 0
ALTER TABLE test_notnull ALTER COLUMN c2 SET NOT NULL;
ERROR:  column "c2" of relation "_hyper_46_237_chunk" contains null values
\set ON_ERROR_STOP 1
SELECT compress_chunk(show_chunks('test_notnull'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_46_237_chunk

\set ON_ERROR_STOP 0
ALTER TABLE test_notnull ALTER COLUMN c2 SET NOT NULL;
ERROR:  column "c2" of relation "_hyper_46_237_chunk" contains null values
\set ON_ERROR_STOP 1
-- test alias in parameter name
CREATE TABLE alias(time timestamptz NOT NULL);
SELECT create_hypertable('alias','time');
  create_hypertable  
---------------------
 (48,public,alias,t)

ALTER TABLE alias SET (tsdb.compress, tsdb.compress_orderby='time DESC',tsdb.compress_segmentby='');
INSERT INTO alias SELECT '2025-01-01';
SELECT count(compress_chunk(ch)) FROM show_chunks('alias') ch;
 count 
-------
     1

-- test mixing postgres and timescaledb options
CREATE TABLE mix_pg_ts(time timestamptz, device text) WITH (tsdb.hypertable,tsdb.partition_column='time',fillfactor=90);
SELECT reloptions FROM pg_class WHERE relname='mix_pg_ts';
   reloptions    
-----------------
 {fillfactor=90}

SELECT * FROM timescaledb_information.hypertable_compression_settings WHERE hypertable='mix_pg_ts'::regclass;
 hypertable | segmentby | orderby | compress_interval_length | index 
------------+-----------+---------+--------------------------+-------
 mix_pg_ts  |           |         |                          | 

ALTER TABLE mix_pg_ts SET (timescaledb.compress, fillfactor=70, tsdb.orderby='time', timescaledb.compress_segmentby='device', autovacuum_enabled=true);
SELECT reloptions FROM pg_class WHERE relname='mix_pg_ts';
               reloptions                
-----------------------------------------
 {fillfactor=70,autovacuum_enabled=true}

SELECT * FROM timescaledb_information.hypertable_compression_settings WHERE hypertable='mix_pg_ts'::regclass;
 hypertable | segmentby | orderby | compress_interval_length | index 
------------+-----------+---------+--------------------------+-------
 mix_pg_ts  | device    | "time"  |                          | 

-- test resetting options
ALTER TABLE mix_pg_ts RESET (fillfactor, tsdb.segmentby);
SELECT reloptions FROM pg_class WHERE relname='mix_pg_ts';
        reloptions         
---------------------------
 {autovacuum_enabled=true}

SELECT * FROM timescaledb_information.hypertable_compression_settings WHERE hypertable='mix_pg_ts'::regclass;
 hypertable | segmentby | orderby | compress_interval_length | index 
------------+-----------+---------+--------------------------+-------
 mix_pg_ts  |           | "time"  |                          | 

-- test with compression enabled but no compressed chunks
CREATE TABLE alter_col_type_test(time timestamptz NOT NULL, device_id int, value float);
SELECT create_hypertable('alter_col_type_test','time');
         create_hypertable         
-----------------------------------
 (52,public,alter_col_type_test,t)

INSERT INTO alter_col_type_test VALUES ('2025-01-01', 1, 10.5), ('2025-01-02', 2, 20.5);
-- alter column type should work on hypertable without compression
ALTER TABLE alter_col_type_test ALTER COLUMN device_id TYPE bigint;
SELECT * FROM alter_col_type_test ORDER BY time;
             time             | device_id | value 
------------------------------+-----------+-------
 Wed Jan 01 00:00:00 2025 PST |         1 |  10.5
 Thu Jan 02 00:00:00 2025 PST |         2 |  20.5

-- enable compression but don't compress any chunks yet
ALTER TABLE alter_col_type_test SET (timescaledb.compress, timescaledb.compress_segmentby='device_id');
-- alter column type should succeed when compression is enabled but no chunks are compressed
ALTER TABLE alter_col_type_test ALTER COLUMN device_id TYPE int;
ALTER TABLE alter_col_type_test ALTER COLUMN value TYPE double precision;
-- verify the changes worked
\d alter_col_type_test
                  Table "public.alter_col_type_test"
  Column   |           Type           | Collation | Nullable | Default 
-----------+--------------------------+-----------+----------+---------
 time      | timestamp with time zone |           | not null | 
 device_id | integer                  |           |          | 
 value     | double precision         |           |          | 
Indexes:
    "alter_col_type_test_time_idx" btree ("time" DESC)
Number of child tables: 2 (Use \d+ to list them.)

SELECT * FROM alter_col_type_test ORDER BY time;
             time             | device_id | value 
------------------------------+-----------+-------
 Wed Jan 01 00:00:00 2025 PST |         1 |  10.5
 Thu Jan 02 00:00:00 2025 PST |         2 |  20.5

-- now compress a chunk
SELECT compress_chunk(show_chunks('alter_col_type_test'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_52_241_chunk
 _timescaledb_internal._hyper_52_242_chunk

-- ALTER COLUMN TYPE should fail when chunks are compressed
\set ON_ERROR_STOP 0
ALTER TABLE alter_col_type_test ALTER COLUMN device_id TYPE text;
ERROR:  operation not supported on hypertables with compressed chunks
\set ON_ERROR_STOP 1
-- decompress and try again, should succeed
SELECT decompress_chunk(show_chunks('alter_col_type_test'));
             decompress_chunk              
-------------------------------------------
 _timescaledb_internal._hyper_52_241_chunk
 _timescaledb_internal._hyper_52_242_chunk

ALTER TABLE alter_col_type_test ALTER COLUMN device_id TYPE bigint;
\d alter_col_type_test
                  Table "public.alter_col_type_test"
  Column   |           Type           | Collation | Nullable | Default 
-----------+--------------------------+-----------+----------+---------
 time      | timestamp with time zone |           | not null | 
 device_id | bigint                   |           |          | 
 value     | double precision         |           |          | 
Indexes:
    "alter_col_type_test_time_idx" btree ("time" DESC)
Number of child tables: 2 (Use \d+ to list them.)

-- verify we can still work with the table after type change
SELECT * FROM alter_col_type_test ORDER BY time;
             time             | device_id | value 
------------------------------+-----------+-------
 Wed Jan 01 00:00:00 2025 PST |         1 |  10.5
 Thu Jan 02 00:00:00 2025 PST |         2 |  20.5

-- compress again to verify compression still works
SELECT compress_chunk(show_chunks('alter_col_type_test'));
              compress_chunk               
-------------------------------------------
 _timescaledb_internal._hyper_52_241_chunk
 _timescaledb_internal._hyper_52_242_chunk

-- ALTER TYPE should fail again when compressed
\set ON_ERROR_STOP 0
ALTER TABLE alter_col_type_test ALTER COLUMN device_id TYPE text;
ERROR:  operation not supported on hypertables with compressed chunks
\set ON_ERROR_STOP 1
DROP TABLE alter_col_type_test;
