-- 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 VIEW settings AS SELECT * FROM _timescaledb_catalog.compression_settings ORDER BY upper(relid::text) COLLATE "C";
-- Test configurable sparse indexes settings
create table test_settings(x int, value text, u uuid, ts timestamp);
select create_hypertable('test_settings', 'x');
WARNING:  column type "timestamp without time zone" used for "ts" does not follow best practices
     create_hypertable      
----------------------------
 (1,public,test_settings,t)

-- defaults
alter table test_settings set (timescaledb.compress);
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst | index 
---------------+----------------+-----------+---------+--------------+--------------------+-------
 test_settings |                |           |         |              |                    | 

-- no custom sparse indexes
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst | index 
---------------+----------------+-----------+---------+--------------+--------------------+-------
 test_settings |                |           | {x}     | {f}          | {f}                | 

-- one sparse index
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u")');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                     index                                                      
---------------+----------------+-----------+---------+--------------+--------------------+----------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {x}     | {f}          | {f}                | [{"type": "bloom", "column": "u", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]

alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'minmax("ts")');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                      index                                                       
---------------+----------------+-----------+---------+--------------+--------------------+------------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {x}     | {f}          | {f}                | [{"type": "minmax", "column": "ts", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]

--multi column
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u"), bloom("ts")');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                                 index                                                                                 
---------------+----------------+-----------+---------+--------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {x}     | {f}          | {f}                | [{"type": "bloom", "column": "u", "source": "config"}, {"type": "bloom", "column": "ts", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]

alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom(u), bloom(ts)');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                                 index                                                                                 
---------------+----------------+-----------+---------+--------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {x}     | {f}          | {f}                | [{"type": "bloom", "column": "u", "source": "config"}, {"type": "bloom", "column": "ts", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]

--test errors
\set ON_ERROR_STOP 0
-- invalid syntax
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u"), bloom(count(u))');
ERROR:  sparse index bloom's first option must reference a valid column.
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = '"u", minmax("u")');
ERROR:  unable to parse sparse index option ""u", minmax("u")"
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'foo("u")');
ERROR:  unrecognized sparse index type "foo"
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom(public.u)');
ERROR:  invalid sparse index column reference syntax
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'select count(*)');
ERROR:  unable to parse sparse index option "select count(*)"
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom (ts); select count(*)');
ERROR:  unable to parse sparse index option "bloom (ts); select count(*)"
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = ';');
ERROR:  unable to parse sparse index option ";"
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = ' ');
ERROR:  unable to parse sparse index option " "
-- same column
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u"), minmax("u")');
ERROR:  duplicate column name "u"
-- multiple columns
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u,ts")');
ERROR:  column "u,ts" does not exist
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom(u,ts)');
ERROR:  sparse index "bloom" can only have one column
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom(u,abc)');
ERROR:  sparse index "bloom" can only have one column
-- duplicate column
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u"), bloom("u")');
ERROR:  duplicate column name "u"
-- invalid column
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u"), minmax("foo")');
ERROR:  column "foo" does not exist
-- no orderby
alter table test_settings reset (timescaledb.compress_orderby);
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_index = 'bloom("u"), minmax("x")');
ERROR:  cannot set sparse index option without orderby option
-- guc disabled
set timescaledb.enable_sparse_index_bloom to false;
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u")');
ERROR:  Creating bloom sparse index is disabled
reset timescaledb.enable_sparse_index_bloom;
\set ON_ERROR_STOP 1
-- empty sparse index
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'ts',
    timescaledb.compress_index = '');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                  index                                                                  
---------------+----------------+-----------+---------+--------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {ts,x}  | {f,t}        | {f,t}              | [{"source": "config"}, {"type": "minmax", "column": "ts", "source": "orderby"}, {"type": "minmax", "column": "x", "source": "orderby"}]

-- change orderby setting (sparse index changes)
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'u');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                 index                                                                  
---------------+----------------+-----------+---------+--------------+--------------------+----------------------------------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {u,x}   | {f,t}        | {f,t}              | [{"source": "config"}, {"type": "minmax", "column": "u", "source": "orderby"}, {"type": "minmax", "column": "x", "source": "orderby"}]

-- same column as orderby should succeed since minmax
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'ts',
    timescaledb.compress_index = 'bloom("value"), minmax("ts")');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                                   index                                                                                    
---------------+----------------+-----------+---------+--------------+--------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {ts,x}  | {f,t}        | {f,t}              | [{"type": "bloom", "column": "value", "source": "config"}, {"type": "minmax", "column": "ts", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]

-- change orderby setting (sparse index doesn't change)
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'u');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                                                               index                                                                                                                
---------------+----------------+-----------+---------+--------------+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {u,x}   | {f,t}        | {f,t}              | [{"type": "bloom", "column": "value", "source": "config"}, {"type": "minmax", "column": "ts", "source": "config"}, {"type": "minmax", "column": "u", "source": "orderby"}, {"type": "minmax", "column": "x", "source": "orderby"}]

alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'minmax("x")');
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'u');
select * from settings;
     relid     | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                      index                                                      
---------------+----------------+-----------+---------+--------------+--------------------+-----------------------------------------------------------------------------------------------------------------
 test_settings |                |           | {u,x}   | {f,t}        | {f,t}              | [{"type": "minmax", "column": "x", "source": "config"}, {"type": "minmax", "column": "u", "source": "orderby"}]

-- same column as orderby should fail since bloom
\set ON_ERROR_STOP 0
alter table test_settings set (timescaledb.compress,
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("x"), minmax("ts")');
ERROR:  the orderby column "x" cannot have a bloom sparse index 
\set ON_ERROR_STOP 1
drop table test_settings;
-- Test configurable sparse indexes functionality
create table test_sparse_index(x int, value text, u uuid, ts timestamp, data jsonb);
select create_hypertable('test_sparse_index', 'x');
WARNING:  column type "timestamp without time zone" used for "ts" does not follow best practices
       create_hypertable        
--------------------------------
 (3,public,test_sparse_index,t)

create index gin_jsonb_idx on test_sparse_index using gin (data);
insert into test_sparse_index
select x, md5(x::text),
    case when x = 7134 then '90ec9e8e-4501-4232-9d03-6d7cf6132815'
        else '6c1d0998-05f3-452c-abd3-45afe72bbcab'::uuid end,
    '2021-01-01'::timestamp + (interval '1 hour') * x,
    jsonb_build_object('id', x, 'tag', case when x % 2 = 0 then 'even' else 'odd' end, 'active', x % 10 = 0)
from generate_series(1, 10000) x;
alter table test_sparse_index set (timescaledb.compress,
    timescaledb.compress_segmentby = '',
    timescaledb.compress_orderby = 'x');
select count(compress_chunk(x)) from show_chunks('test_sparse_index') x;
 count 
-------
     1

alter table test_sparse_index set (timescaledb.compress,
    timescaledb.compress_segmentby = '',
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'bloom("u"),minmax("ts")');
select * from settings;
                 relid                  |                 compress_relid                 | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                                 index                                                                                  
----------------------------------------+------------------------------------------------+-----------+---------+--------------+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 test_sparse_index                      |                                                | {}        | {x}     | {f}          | {f}                | [{"type": "bloom", "column": "u", "source": "config"}, {"type": "minmax", "column": "ts", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]
 _timescaledb_internal._hyper_3_1_chunk | _timescaledb_internal.compress_hyper_4_2_chunk | {}        | {x}     | {f}          | {f}                | [{"type": "minmax", "column": "x", "source": "orderby"}]

select count(compress_chunk(x, recompress:=true)) from show_chunks('test_sparse_index') x;
 count 
-------
     1

vacuum full analyze test_sparse_index;
select schema_name || '.' || table_name chunk from _timescaledb_catalog.chunk
    where id = (select compressed_chunk_id from _timescaledb_catalog.chunk
        where hypertable_id = (select id from _timescaledb_catalog.hypertable
            where table_name = 'test_sparse_index') limit 1)
\gset
select * from test.show_columns_ext(:'chunk'::regclass);
        Column        |                 Type                  | Collation | Nullable | Default | Storage  | Stats target | Description 
----------------------+---------------------------------------+-----------+----------+---------+----------+--------------+-------------
 _ts_meta_count       | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_min_1       | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_max_1       | integer                               |           |          |         | plain    |         1000 | 
 x                    | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 value                | _timescaledb_internal.compressed_data |           |          |         | extended |            0 | 
 regress-test-bloom_u | _timescaledb_internal.bloom1          |           |          |         | external |         1000 | 
 u                    | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 _ts_meta_v2_min_ts   | timestamp without time zone           |           |          |         | plain    |         1000 | 
 _ts_meta_v2_max_ts   | timestamp without time zone           |           |          |         | plain    |         1000 | 
 ts                   | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 data                 | _timescaledb_internal.compressed_data |           |          |         | extended |            0 | 

-- UUID uses bloom
explain (analyze, verbose, buffers off, costs off, timing off, summary off)
select count(*) from test_sparse_index where u = '90ec9e8e-4501-4232-9d03-6d7cf6132815';
--- QUERY PLAN ---
 Aggregate (actual rows=1.00 loops=1)
   Output: count(*)
   ->  Custom Scan (ColumnarScan) on _timescaledb_internal._hyper_3_1_chunk (actual rows=1.00 loops=1)
         Vectorized Filter: (_hyper_3_1_chunk.u = '90ec9e8e-4501-4232-9d03-6d7cf6132815'::uuid)
         Rows Removed by Filter: 999
         Bulk Decompression: true
         ->  Seq Scan on _timescaledb_internal.compress_hyper_4_3_chunk (actual rows=1.00 loops=1)
               Output: compress_hyper_4_3_chunk._ts_meta_count, compress_hyper_4_3_chunk._ts_meta_min_1, compress_hyper_4_3_chunk._ts_meta_max_1, compress_hyper_4_3_chunk.x, compress_hyper_4_3_chunk.value, compress_hyper_4_3_chunk.regress-test-bloom_u, compress_hyper_4_3_chunk.u, compress_hyper_4_3_chunk._ts_meta_v2_min_ts, compress_hyper_4_3_chunk._ts_meta_v2_max_ts, compress_hyper_4_3_chunk.ts, compress_hyper_4_3_chunk.data
               Filter: _timescaledb_functions.bloom1_contains(compress_hyper_4_3_chunk.regress-test-bloom_u, '90ec9e8e-4501-4232-9d03-6d7cf6132815'::uuid)
               Rows Removed by Filter: 9

-- Timestamp uses minmax
explain (analyze, verbose, buffers off, costs off, timing off, summary off)
select count(*) from test_sparse_index where ts between '2021-01-07' and '2021-01-14';
--- QUERY PLAN ---
 Aggregate (actual rows=1.00 loops=1)
   Output: count(*)
   ->  Custom Scan (ColumnarScan) on _timescaledb_internal._hyper_3_1_chunk (actual rows=169.00 loops=1)
         Vectorized Filter: ((_hyper_3_1_chunk.ts >= 'Thu Jan 07 00:00:00 2021'::timestamp without time zone) AND (_hyper_3_1_chunk.ts <= 'Thu Jan 14 00:00:00 2021'::timestamp without time zone))
         Rows Removed by Filter: 831
         Bulk Decompression: true
         ->  Seq Scan on _timescaledb_internal.compress_hyper_4_3_chunk (actual rows=1.00 loops=1)
               Output: compress_hyper_4_3_chunk._ts_meta_count, compress_hyper_4_3_chunk._ts_meta_min_1, compress_hyper_4_3_chunk._ts_meta_max_1, compress_hyper_4_3_chunk.x, compress_hyper_4_3_chunk.value, compress_hyper_4_3_chunk.regress-test-bloom_u, compress_hyper_4_3_chunk.u, compress_hyper_4_3_chunk._ts_meta_v2_min_ts, compress_hyper_4_3_chunk._ts_meta_v2_max_ts, compress_hyper_4_3_chunk.ts, compress_hyper_4_3_chunk.data
               Filter: ((compress_hyper_4_3_chunk._ts_meta_v2_max_ts >= 'Thu Jan 07 00:00:00 2021'::timestamp without time zone) AND (compress_hyper_4_3_chunk._ts_meta_v2_min_ts <= 'Thu Jan 14 00:00:00 2021'::timestamp without time zone))
               Rows Removed by Filter: 9

drop table test_sparse_index;
-- Test configurable sparse index in CREATE TABLE .. WITH
create table test_sparse_index(x int, value text, u uuid, ts timestamp) with (
    tsdb.hypertable,
    tsdb.partition_column='x',
    tsdb.order_by='x',
    tsdb.index='bloom("u"),minmax("ts")');
select * from settings;
       relid       | compress_relid | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                                 index                                                                                  
-------------------+----------------+-----------+---------+--------------+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 test_sparse_index |                |           | {x}     | {f}          | {f}                | [{"type": "bloom", "column": "u", "source": "config"}, {"type": "minmax", "column": "ts", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]

insert into test_sparse_index
select x, md5(x::text),
    case when x = 7134 then '90ec9e8e-4501-4232-9d03-6d7cf6132815'
        else '6c1d0998-05f3-452c-abd3-45afe72bbcab'::uuid end,
    '2021-01-01'::timestamp + (interval '1 hour') * x
from generate_series(1, 10000) x;
select count(compress_chunk(x)) from show_chunks('test_sparse_index') x;
 count 
-------
     1

vacuum full analyze test_sparse_index;
select schema_name || '.' || table_name chunk from _timescaledb_catalog.chunk
    where id = (select compressed_chunk_id from _timescaledb_catalog.chunk
        where hypertable_id = (select id from _timescaledb_catalog.hypertable
            where table_name = 'test_sparse_index') limit 1)
\gset
select * from test.show_columns_ext(:'chunk'::regclass);
        Column        |                 Type                  | Collation | Nullable | Default | Storage  | Stats target | Description 
----------------------+---------------------------------------+-----------+----------+---------+----------+--------------+-------------
 _ts_meta_count       | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_min_1       | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_max_1       | integer                               |           |          |         | plain    |         1000 | 
 x                    | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 value                | _timescaledb_internal.compressed_data |           |          |         | extended |            0 | 
 regress-test-bloom_u | _timescaledb_internal.bloom1          |           |          |         | external |         1000 | 
 u                    | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 _ts_meta_v2_min_ts   | timestamp without time zone           |           |          |         | plain    |         1000 | 
 _ts_meta_v2_max_ts   | timestamp without time zone           |           |          |         | plain    |         1000 | 
 ts                   | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 

-- these tests show that despite column having multiple sparse indexes, the appropriate one is selected by the planner
-- UUID uses bloom
explain (analyze, verbose, buffers off, costs off, timing off, summary off)
select count(*) from test_sparse_index where u = '90ec9e8e-4501-4232-9d03-6d7cf6132815';
--- QUERY PLAN ---
 Aggregate (actual rows=1.00 loops=1)
   Output: count(*)
   ->  Custom Scan (ColumnarScan) on _timescaledb_internal._hyper_5_4_chunk (actual rows=1.00 loops=1)
         Vectorized Filter: (_hyper_5_4_chunk.u = '90ec9e8e-4501-4232-9d03-6d7cf6132815'::uuid)
         Rows Removed by Filter: 999
         Bulk Decompression: true
         ->  Seq Scan on _timescaledb_internal.compress_hyper_6_5_chunk (actual rows=1.00 loops=1)
               Output: compress_hyper_6_5_chunk._ts_meta_count, compress_hyper_6_5_chunk._ts_meta_min_1, compress_hyper_6_5_chunk._ts_meta_max_1, compress_hyper_6_5_chunk.x, compress_hyper_6_5_chunk.value, compress_hyper_6_5_chunk.regress-test-bloom_u, compress_hyper_6_5_chunk.u, compress_hyper_6_5_chunk._ts_meta_v2_min_ts, compress_hyper_6_5_chunk._ts_meta_v2_max_ts, compress_hyper_6_5_chunk.ts
               Filter: _timescaledb_functions.bloom1_contains(compress_hyper_6_5_chunk.regress-test-bloom_u, '90ec9e8e-4501-4232-9d03-6d7cf6132815'::uuid)
               Rows Removed by Filter: 9

-- Timestamp uses minmax
explain (analyze, verbose, buffers off, costs off, timing off, summary off)
select count(*) from test_sparse_index where ts between '2021-01-07' and '2021-01-14';
--- QUERY PLAN ---
 Aggregate (actual rows=1.00 loops=1)
   Output: count(*)
   ->  Custom Scan (ColumnarScan) on _timescaledb_internal._hyper_5_4_chunk (actual rows=169.00 loops=1)
         Vectorized Filter: ((_hyper_5_4_chunk.ts >= 'Thu Jan 07 00:00:00 2021'::timestamp without time zone) AND (_hyper_5_4_chunk.ts <= 'Thu Jan 14 00:00:00 2021'::timestamp without time zone))
         Rows Removed by Filter: 831
         Bulk Decompression: true
         ->  Seq Scan on _timescaledb_internal.compress_hyper_6_5_chunk (actual rows=1.00 loops=1)
               Output: compress_hyper_6_5_chunk._ts_meta_count, compress_hyper_6_5_chunk._ts_meta_min_1, compress_hyper_6_5_chunk._ts_meta_max_1, compress_hyper_6_5_chunk.x, compress_hyper_6_5_chunk.value, compress_hyper_6_5_chunk.regress-test-bloom_u, compress_hyper_6_5_chunk.u, compress_hyper_6_5_chunk._ts_meta_v2_min_ts, compress_hyper_6_5_chunk._ts_meta_v2_max_ts, compress_hyper_6_5_chunk.ts
               Filter: ((compress_hyper_6_5_chunk._ts_meta_v2_max_ts >= 'Thu Jan 07 00:00:00 2021'::timestamp without time zone) AND (compress_hyper_6_5_chunk._ts_meta_v2_min_ts <= 'Thu Jan 14 00:00:00 2021'::timestamp without time zone))
               Rows Removed by Filter: 9

-- Test recompression when the bloom filter index is disabled by a GUC
set timescaledb.enable_sparse_index_bloom to off;
select count(compress_chunk(decompress_chunk(x))) from show_chunks('test_sparse_index') x;
WARNING:  Creating bloom sparse index is disabled
 count 
-------
     1

reset timescaledb.enable_sparse_index_bloom;
-- Test rename column
-- change a non-sparse index column
alter table test_sparse_index rename value to value_new;
-- change sparse index column
alter table test_sparse_index rename ts to ts_new;
select * from settings;
                 relid                  |                 compress_relid                 | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                                                   index                                                                                    
----------------------------------------+------------------------------------------------+-----------+---------+--------------+--------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 test_sparse_index                      |                                                |           | {x}     | {f}          | {f}                | [{"type": "bloom", "column": "u", "source": "config"}, {"type": "minmax", "column": "ts_new", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]
 _timescaledb_internal._hyper_5_4_chunk | _timescaledb_internal.compress_hyper_6_6_chunk |           | {x}     | {f}          | {f}                | [{"type": "bloom", "column": "u", "source": "config"}, {"type": "minmax", "column": "ts_new", "source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]

select schema_name || '.' || table_name chunk from _timescaledb_catalog.chunk
    where id = (select compressed_chunk_id from _timescaledb_catalog.chunk
        where hypertable_id = (select id from _timescaledb_catalog.hypertable
            where table_name = 'test_sparse_index') limit 1)
\gset
select * from test.show_columns_ext(:'chunk'::regclass);
         Column         |                 Type                  | Collation | Nullable | Default | Storage  | Stats target | Description 
------------------------+---------------------------------------+-----------+----------+---------+----------+--------------+-------------
 _ts_meta_count         | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_min_1         | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_max_1         | integer                               |           |          |         | plain    |         1000 | 
 x                      | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 value_new              | _timescaledb_internal.compressed_data |           |          |         | extended |            0 | 
 regress-test-bloom_u   | _timescaledb_internal.bloom1          |           |          |         | external |         1000 | 
 u                      | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 _ts_meta_v2_min_ts_new | timestamp without time zone           |           |          |         | plain    |         1000 | 
 _ts_meta_v2_max_ts_new | timestamp without time zone           |           |          |         | plain    |         1000 | 
 ts_new                 | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 

-- Test same minmax and orderby column
alter table test_sparse_index set (timescaledb.compress,
    timescaledb.compress_segmentby = '',
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = 'minmax("x")');
select count(compress_chunk(x, recompress:=true)) from show_chunks('test_sparse_index') x;
 count 
-------
     1

select schema_name || '.' || table_name chunk from _timescaledb_catalog.chunk
    where id = (select compressed_chunk_id from _timescaledb_catalog.chunk
        where hypertable_id = (select id from _timescaledb_catalog.hypertable
            where table_name = 'test_sparse_index') limit 1)
\gset
select * from test.show_columns_ext(:'chunk'::regclass);
     Column     |                 Type                  | Collation | Nullable | Default | Storage  | Stats target | Description 
----------------+---------------------------------------+-----------+----------+---------+----------+--------------+-------------
 _ts_meta_count | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_min_1 | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_max_1 | integer                               |           |          |         | plain    |         1000 | 
 x              | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 value_new      | _timescaledb_internal.compressed_data |           |          |         | extended |            0 | 
 u              | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 ts_new         | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 

select * from settings;
                 relid                  |                 compress_relid                 | segmentby | orderby | orderby_desc | orderby_nullsfirst |                          index                          
----------------------------------------+------------------------------------------------+-----------+---------+--------------+--------------------+---------------------------------------------------------
 test_sparse_index                      |                                                | {}        | {x}     | {f}          | {f}                | [{"type": "minmax", "column": "x", "source": "config"}]
 _timescaledb_internal._hyper_5_4_chunk | _timescaledb_internal.compress_hyper_6_7_chunk | {}        | {x}     | {f}          | {f}                | [{"type": "minmax", "column": "x", "source": "config"}]

-- Test auto sparse index
create index ii on test_sparse_index(value_new);
alter table test_sparse_index reset (timescaledb.compress_index);
alter table test_sparse_index set (timescaledb.compress,
    timescaledb.compress_segmentby = '',
    timescaledb.compress_orderby = 'x');
select count(compress_chunk(x, recompress:=true)) from show_chunks('test_sparse_index') x;
 count 
-------
     1

select schema_name || '.' || table_name chunk from _timescaledb_catalog.chunk
    where id = (select compressed_chunk_id from _timescaledb_catalog.chunk
        where hypertable_id = (select id from _timescaledb_catalog.hypertable
            where table_name = 'test_sparse_index') limit 1)
\gset
select * from test.show_columns_ext(:'chunk'::regclass);
            Column            |                 Type                  | Collation | Nullable | Default | Storage  | Stats target | Description 
------------------------------+---------------------------------------+-----------+----------+---------+----------+--------------+-------------
 _ts_meta_count               | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_min_1               | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_max_1               | integer                               |           |          |         | plain    |         1000 | 
 x                            | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 regress-test-bloom_value_new | _timescaledb_internal.bloom1          |           |          |         | external |         1000 | 
 value_new                    | _timescaledb_internal.compressed_data |           |          |         | extended |            0 | 
 u                            | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 ts_new                       | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 

select * from settings;
                 relid                  |                 compress_relid                 | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                                          index                                                          
----------------------------------------+------------------------------------------------+-----------+---------+--------------+--------------------+-------------------------------------------------------------------------------------------------------------------------
 test_sparse_index                      |                                                | {}        | {x}     | {f}          | {f}                | 
 _timescaledb_internal._hyper_5_4_chunk | _timescaledb_internal.compress_hyper_6_8_chunk | {}        | {x}     | {f}          | {f}                | [{"type": "bloom", "column": "value_new", "source": "default"}, {"type": "minmax", "column": "x", "source": "orderby"}]

-- Test empty sparse index
alter table test_sparse_index set (timescaledb.compress,
    timescaledb.compress_segmentby = '',
    timescaledb.compress_orderby = 'x',
    timescaledb.compress_index = '');
select count(compress_chunk(x, recompress:=true)) from show_chunks('test_sparse_index') x;
 count 
-------
     1

vacuum full analyze test_sparse_index;
select schema_name || '.' || table_name chunk from _timescaledb_catalog.chunk
    where id = (select compressed_chunk_id from _timescaledb_catalog.chunk
        where hypertable_id = (select id from _timescaledb_catalog.hypertable
            where table_name = 'test_sparse_index') limit 1)
\gset
select * from test.show_columns_ext(:'chunk'::regclass);
     Column     |                 Type                  | Collation | Nullable | Default | Storage  | Stats target | Description 
----------------+---------------------------------------+-----------+----------+---------+----------+--------------+-------------
 _ts_meta_count | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_min_1 | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_max_1 | integer                               |           |          |         | plain    |         1000 | 
 x              | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 value_new      | _timescaledb_internal.compressed_data |           |          |         | extended |            0 | 
 u              | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 ts_new         | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 

select * from settings;
                 relid                  |                 compress_relid                 | segmentby | orderby | orderby_desc | orderby_nullsfirst |                                     index                                      
----------------------------------------+------------------------------------------------+-----------+---------+--------------+--------------------+--------------------------------------------------------------------------------
 test_sparse_index                      |                                                | {}        | {x}     | {f}          | {f}                | [{"source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]
 _timescaledb_internal._hyper_5_4_chunk | _timescaledb_internal.compress_hyper_6_9_chunk | {}        | {x}     | {f}          | {f}                | [{"source": "config"}, {"type": "minmax", "column": "x", "source": "orderby"}]

-- Test default orderby without sparse index
set timescaledb.enable_sparse_index_bloom to false;
alter table test_sparse_index reset (timescaledb.compress_segmentby,
    timescaledb.compress_orderby,
    timescaledb.compress_index);
select count(compress_chunk(x, recompress:=true)) from show_chunks('test_sparse_index') x;
 count 
-------
     1

vacuum full analyze test_sparse_index;
select schema_name || '.' || table_name chunk from _timescaledb_catalog.chunk
    where id = (select compressed_chunk_id from _timescaledb_catalog.chunk
        where hypertable_id = (select id from _timescaledb_catalog.hypertable
            where table_name = 'test_sparse_index') limit 1)
\gset
select * from test.show_columns_ext(:'chunk'::regclass);
     Column     |                 Type                  | Collation | Nullable | Default | Storage  | Stats target | Description 
----------------+---------------------------------------+-----------+----------+---------+----------+--------------+-------------
 _ts_meta_count | integer                               |           |          |         | plain    |         1000 | 
 value_new      | text                                  | default   |          |         | extended |         1000 | 
 _ts_meta_min_1 | integer                               |           |          |         | plain    |         1000 | 
 _ts_meta_max_1 | integer                               |           |          |         | plain    |         1000 | 
 x              | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 u              | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 
 ts_new         | _timescaledb_internal.compressed_data |           |          |         | external |            0 | 

select * from settings;
                 relid                  |                 compress_relid                  |  segmentby  | orderby | orderby_desc | orderby_nullsfirst |                          index                           
----------------------------------------+-------------------------------------------------+-------------+---------+--------------+--------------------+----------------------------------------------------------
 test_sparse_index                      |                                                 |             |         |              |                    | 
 _timescaledb_internal._hyper_5_4_chunk | _timescaledb_internal.compress_hyper_6_10_chunk | {value_new} | {x}     | {t}          | {t}                | [{"type": "minmax", "column": "x", "source": "orderby"}]

reset timescaledb.enable_sparse_index_bloom;
drop table test_sparse_index;
