-- This file and its contents are licensed under the Timescale License.
-- Please see the included NOTICE for copyright information and
-- LICENSE-TIMESCALE for a copy of the license.
\c :TEST_DBNAME :ROLE_SUPERUSER;
CREATE TABLE ht_metrics_compressed(time timestamptz, device int, value float, tag text);
ALTER TABLE ht_metrics_compressed SET (autovacuum_enabled = false);
SELECT create_hypertable('ht_metrics_compressed','time',create_default_indexes:=false, chunk_time_interval => interval '100 day');
         create_hypertable          
------------------------------------
 (1,public,ht_metrics_compressed,t)

ALTER TABLE ht_metrics_compressed SET (timescaledb.compress, timescaledb.compress_segmentby='device', timescaledb.compress_orderby='time');
-- helper function: float -> pseudorandom float [0..1].
CREATE OR REPLACE FUNCTION mix(x float4) RETURNS float4 AS $$ SELECT ((hashfloat4(x) / (pow(2., 31) - 1) + 1) / 2)::float4 $$ LANGUAGE SQL;
INSERT INTO ht_metrics_compressed
SELECT
    '2020-05-18'::timestamptz + interval '1 second' * (x + 0.1 * mix(device + x * 10)),
    device,
    100 * mix(device) * sin(x / 3600)
        + 100 * mix(device + 1) * sin(x / (3600 * 24))
        + 100 * mix(device + 2) * sin(x / (3600 * 24 * 7))
        + mix(device + x * 10 + 1),
     format('this-is-a-long-tag-#%s', x % 29)
FROM generate_series(1, 3600 * 24 * 90, 100) x, generate_series(1,2) device;
analyze ht_metrics_compressed;
select show_chunks('ht_metrics_compressed') as "CHUNK" limit 1 \gset
select count(*) from :CHUNK;
 count  
--------
 155520

select count(distinct tag) from :CHUNK;
 count 
-------
    29

select device, min(time), max(time) from :CHUNK group by 1 order by 1, 2, 3;
 device |                 min                 |                max                 
--------+-------------------------------------+------------------------------------
      1 | Mon May 18 00:00:01.037881 2020 PDT | Sat Aug 15 23:58:21.04471 2020 PDT
      2 | Mon May 18 00:00:01.013087 2020 PDT | Sat Aug 15 23:58:21.04471 2020 PDT

-- decompress with no indexes
select where compress_chunk(:'CHUNK') is null;
--

select where decompress_chunk(:'CHUNK') is null;
--

-- decompress with one index
select where compress_chunk(:'CHUNK') is null;
--

create index on :CHUNK(device, time);
select where decompress_chunk(:'CHUNK') is null;
--

-- decompress with two indexes
select where compress_chunk(:'CHUNK') is null;
--

create index on :CHUNK(tag);
select where decompress_chunk(:'CHUNK') is null;
--

-- check the data after decompression
set enable_seqscan to off;
select count(*) from :CHUNK;
 count  
--------
 155520

select count(distinct tag) from :CHUNK;
 count 
-------
    29

select distinct on (device) device, time from :CHUNK order by 1, 2;
 device |                time                 
--------+-------------------------------------
      1 | Mon May 18 00:00:01.037881 2020 PDT
      2 | Mon May 18 00:00:01.013087 2020 PDT

-- To avoid differences in PG15 output which doesn't support this feature
SET timescaledb.enable_skipscan_for_distinct_aggregates TO false;
-- check that the indexes are used
explain (buffers off, costs off) select count(distinct tag) from :CHUNK;
--- QUERY PLAN ---
 Aggregate
   ->  Index Only Scan using _hyper_1_1_chunk_tag_idx on _hyper_1_1_chunk

explain (buffers off, costs off) select distinct on (device) device, time from :CHUNK order by 1, 2;
--- QUERY PLAN ---
 Unique
   ->  Custom Scan (SkipScan) on _hyper_1_1_chunk
         ->  Index Only Scan using _hyper_1_1_chunk_device_time_idx on _hyper_1_1_chunk
               Index Cond: (device > NULL::integer)

RESET timescaledb.enable_skipscan_for_distinct_aggregates;
drop table ht_metrics_compressed;
-- Fix for issue #8681: IndexScan is not chosen for columnstore segmented on varchar column
-- We should chose IndexScan now, and use SkipScan as well
CREATE TABLE record (time timestamptz not null, data varchar);
SELECT table_name FROM create_hypertable('record','time');
WARNING:  column type "character varying" used for "data" does not follow best practices
 table_name 
------------
 record

ALTER TABLE record SET (timescaledb.compress,timescaledb.compress_orderby='time desc', timescaledb.compress_segmentby='data');
INSERT INTO record
SELECT time, (array['Yes', 'No', 'Maybe'])[floor(random() * 3 + 1)]
FROM generate_series('2000-01-01'::timestamptz,'2000-01-03'::timestamptz, '10 minute'::interval) AS g1(time);
analyze record;
SELECT compress_chunk(ch) FROM show_chunks('record') ch;
             compress_chunk             
----------------------------------------
 _timescaledb_internal._hyper_3_5_chunk

-- enable_seqscan is OFF, should see IndexScan
explain (buffers off, costs off) SELECT * FROM record ORDER BY data;
--- QUERY PLAN ---
 Custom Scan (ColumnarScan) on _hyper_3_5_chunk
   ->  Index Scan using compress_hyper_4_6_chunk_data__ts_meta_min_1__ts_meta_max_1_idx on compress_hyper_4_6_chunk

-- SkipScan is chosen because IndexScan is chosen
explain (buffers off, costs off) SELECT DISTINCT ON(data) * FROM record;
--- QUERY PLAN ---
 Unique
   ->  Custom Scan (SkipScan) on _hyper_3_5_chunk
         ->  Custom Scan (ColumnarScan) on _hyper_3_5_chunk
               ->  Index Scan using compress_hyper_4_6_chunk_data__ts_meta_min_1__ts_meta_max_1_idx on compress_hyper_4_6_chunk

-- (seg_col = const) condition is checked even when seg_col is coerced
explain (buffers off, costs off) SELECT * FROM record WHERE data='Yes' ORDER BY data;
--- QUERY PLAN ---
 Custom Scan (ColumnarScan) on _hyper_3_5_chunk
   ->  Index Scan using compress_hyper_4_6_chunk_data__ts_meta_min_1__ts_meta_max_1_idx on compress_hyper_4_6_chunk
         Index Cond: ((data)::text = 'Yes'::text)

explain (buffers off, costs off) SELECT * FROM record WHERE 'Yes' <= data ORDER BY data;
--- QUERY PLAN ---
 Custom Scan (ColumnarScan) on _hyper_3_5_chunk
   ->  Index Scan using compress_hyper_4_6_chunk_data__ts_meta_min_1__ts_meta_max_1_idx on compress_hyper_4_6_chunk
         Index Cond: ((data)::text >= 'Yes'::text)

drop table record cascade;
-- Fix for issue #9066: IndexScan is not chosen for columnstore segmented on several keys
-- for a query sorted on columnstore keys
-- but where one numeric key is pinned to a Const of different but compatible type.
-- We should chose IndexScan now, and use SkipScan as well.
CREATE TABLE log_numeric(
	"time"       timestamp with time zone NOT NULL,
	device_id    integer                  NOT NULL,
	parameter_id smallint                 NOT NULL,
	value        double precision
);
SELECT create_hypertable('log_numeric', 'time', chunk_time_interval => interval '1 days', create_default_indexes => false);
    create_hypertable     
--------------------------
 (5,public,log_numeric,t)

ALTER TABLE log_numeric SET (timescaledb.compress, timescaledb.compress_segmentby = 'device_id, parameter_id', timescaledb.compress_orderby='"time" DESC');
INSERT INTO log_numeric
SELECT time, device_id, parameter_id, device_id*parameter_id
FROM generate_series('2000-01-01'::timestamptz,'2000-01-03'::timestamptz, '10 minute'::interval) AS g1(time),
generate_series(1,4) device_id, generate_series(1,4) parameter_id;
select compress_chunk(ch) from show_chunks('log_numeric') ch;
             compress_chunk             
----------------------------------------
 _timescaledb_internal._hyper_5_7_chunk
 _timescaledb_internal._hyper_5_8_chunk
 _timescaledb_internal._hyper_5_9_chunk

-- enable_seqscan is OFF, should see IndexScan
explain (buffers off, costs off) SELECT * FROM log_numeric WHERE parameter_id = 1 ORDER BY device_id, parameter_id, time DESC;
--- QUERY PLAN ---
 Merge Append
   Sort Key: log_numeric.device_id, log_numeric."time" DESC
   ->  Custom Scan (ColumnarScan) on _hyper_5_7_chunk
         ->  Index Scan using compress_hyper_6_10_chunk_device_id_parameter_id__ts_meta_m_idx on compress_hyper_6_10_chunk
               Index Cond: (parameter_id = 1)
   ->  Custom Scan (ColumnarScan) on _hyper_5_8_chunk
         ->  Index Scan using compress_hyper_6_11_chunk_device_id_parameter_id__ts_meta_m_idx on compress_hyper_6_11_chunk
               Index Cond: (parameter_id = 1)
   ->  Custom Scan (ColumnarScan) on _hyper_5_9_chunk
         ->  Index Scan using compress_hyper_6_12_chunk_device_id_parameter_id__ts_meta_m_idx on compress_hyper_6_12_chunk
               Index Cond: (parameter_id = 1)

-- SkipScan is chosen because IndexScan is chosen
explain (buffers off, costs off) SELECT DISTINCT ON(device_id, parameter_id) * FROM log_numeric WHERE parameter_id = 1 ORDER BY device_id, parameter_id, time DESC;
--- QUERY PLAN ---
 Unique
   ->  Merge Append
         Sort Key: log_numeric.device_id, log_numeric."time" DESC
         ->  Custom Scan (SkipScan) on _hyper_5_7_chunk
               ->  Custom Scan (ColumnarScan) on _hyper_5_7_chunk
                     ->  Index Scan using compress_hyper_6_10_chunk_device_id_parameter_id__ts_meta_m_idx on compress_hyper_6_10_chunk
                           Index Cond: (parameter_id = 1)
         ->  Custom Scan (SkipScan) on _hyper_5_8_chunk
               ->  Custom Scan (ColumnarScan) on _hyper_5_8_chunk
                     ->  Index Scan using compress_hyper_6_11_chunk_device_id_parameter_id__ts_meta_m_idx on compress_hyper_6_11_chunk
                           Index Cond: (parameter_id = 1)
         ->  Custom Scan (SkipScan) on _hyper_5_9_chunk
               ->  Custom Scan (ColumnarScan) on _hyper_5_9_chunk
                     ->  Index Scan using compress_hyper_6_12_chunk_device_id_parameter_id__ts_meta_m_idx on compress_hyper_6_12_chunk
                           Index Cond: (parameter_id = 1)

drop table log_numeric cascade;
