-- 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.
CREATE OR REPLACE FUNCTION reorder_called(chunk_id INT) RETURNS BOOL AS $$
  SELECT indisclustered
  FROM _timescaledb_catalog.chunk ch
  JOIN pg_index i on indrelid = format('%I.%I',ch.schema_name,ch.table_name)::regclass
  WHERE ch.id = chunk_id;
$$ LANGUAGE SQL;
CREATE TABLE test_table(time timestamptz, chunk_id int);
SELECT create_hypertable('test_table', 'time');
    create_hypertable    
-------------------------
 (1,public,test_table,t)

-- These inserts should create 5 different chunks
INSERT INTO test_table VALUES (now() - INTERVAL '3 weeks', 1);
INSERT INTO test_table VALUES (now(), 2);
INSERT INTO test_table VALUES (now() - INTERVAL '5 months', 3);
INSERT INTO test_table VALUES (now() - INTERVAL '3 months', 4);
INSERT INTO test_table VALUES (now() - INTERVAL '8 months', 5);
SELECT COUNT(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table';
 count 
-------
     5

-- Make sure reorder correctly selects chunks to reorder
-- by starting with oldest chunks
select add_reorder_policy('test_table', 'test_table_time_idx') as reorder_job_id \gset
select * from _timescaledb_catalog.bgw_job WHERE id >= 1000 ORDER BY id;
  id  |   application_name    | schedule_interval | max_runtime | max_retries | retry_period |      proc_schema       |   proc_name    |       owner       | scheduled | fixed_schedule | initial_start | hypertable_id |                          config                           |      check_schema      |      check_name      | timezone 
------+-----------------------+-------------------+-------------+-------------+--------------+------------------------+----------------+-------------------+-----------+----------------+---------------+---------------+-----------------------------------------------------------+------------------------+----------------------+----------
 1000 | Reorder Policy [1000] | @ 84 hours        | @ 0         |          -1 | @ 5 mins     | _timescaledb_functions | policy_reorder | default_perm_user | t         | f              |               |             1 | {"index_name": "test_table_time_idx", "hypertable_id": 1} | _timescaledb_functions | policy_reorder_check | 

select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------

-- Make a manual calls to reorder: make sure the correct chunk is called
-- Chunk 5 should be first
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1000 |        5 |                 1

-- Confirm that reorder was called on the correct chunk Oid
SELECT reorder_called(5);
 reorder_called 
----------------
 t

-- Chunk 3 is next
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1000 |        5 |                 1
   1000 |        3 |                 1

SELECT reorder_called(3);
 reorder_called 
----------------
 t

-- Chunk 4 is next
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1000 |        5 |                 1
   1000 |        3 |                 1
   1000 |        4 |                 1

SELECT reorder_called(4);
 reorder_called 
----------------
 t

-- The following calls should not reorder any chunk, because they're all too new
CALL run_job(:reorder_job_id);
NOTICE:  no chunks need reordering for hypertable public.test_table
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1000 |        5 |                 1
   1000 |        3 |                 1
   1000 |        4 |                 1

CALL run_job(:reorder_job_id);
NOTICE:  no chunks need reordering for hypertable public.test_table
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1000 |        5 |                 1
   1000 |        3 |                 1
   1000 |        4 |                 1

INSERT INTO test_table VALUES (now() - INTERVAL '7 days', 6);
-- This call should reorder chunk 1
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1000 |        5 |                 1
   1000 |        3 |                 1
   1000 |        4 |                 1
   1000 |        1 |                 1

SELECT reorder_called(1);
 reorder_called 
----------------
 t

-- Should not reorder anything, because all chunks are too new
CALL run_job(:reorder_job_id);
NOTICE:  no chunks need reordering for hypertable public.test_table
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1000 |        5 |                 1
   1000 |        3 |                 1
   1000 |        4 |                 1
   1000 |        1 |                 1

select remove_reorder_policy('test_table');
 remove_reorder_policy 
-----------------------
 

-- Now do drop_chunks test
select add_retention_policy('test_table', INTERVAL '4 months', true) as drop_chunks_job_id \gset
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table';
 count 
-------
     6

-- Now simulate drop_chunks running automatically by calling it explicitly
CALL run_job(:drop_chunks_job_id);
-- Should have 4 chunks left
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table' \gset before_
select :before_count=4;
 ?column? 
----------
 t

-- Make sure this second call does nothing
CALL run_job(:drop_chunks_job_id);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table' \gset after_
-- Should be true
select :before_count=:after_count;
 ?column? 
----------
 t

INSERT INTO test_table VALUES (now() - INTERVAL '2 weeks', 1);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table' \gset before_
-- This call should also do nothing
CALL run_job(:drop_chunks_job_id);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table' \gset after_
-- Should be true
select :before_count=:after_count;
 ?column? 
----------
 t

select remove_retention_policy('test_table');
 remove_retention_policy 
-------------------------
 

-- Now test reorder chunk selection when there is space partitioning
TRUNCATE test_table;
SELECT add_dimension('public.test_table', 'chunk_id', 2);
          add_dimension           
----------------------------------
 (2,public,test_table,chunk_id,t)

INSERT INTO test_table VALUES (now() - INTERVAL '3 weeks', 1);
INSERT INTO test_table VALUES (now(), 2);
INSERT INTO test_table VALUES (now() - INTERVAL '5 months', 3);
INSERT INTO test_table VALUES (now() - INTERVAL '3 months', 4);
INSERT INTO test_table VALUES (now() - INTERVAL '3 months', -4);
INSERT INTO test_table VALUES (now() - INTERVAL '8 months', 5);
INSERT INTO test_table VALUES (now() - INTERVAL '8 months', -5);
select add_reorder_policy('test_table', 'test_table_time_idx') as reorder_job_id \gset
-- Should be nothing in the chunk_stats table
select count(*) from _timescaledb_internal.bgw_policy_chunk_stats where job_id=:reorder_job_id;
 count 
-------
     0

-- Make a manual calls to reorder: make sure the correct (oldest) chunk is called
select chunk_id from _timescaledb_catalog.dimension_slice as ds, _timescaledb_catalog.chunk_constraint as cc where ds.dimension_id=1 and ds.id=cc.dimension_slice_id ORDER BY ds.range_start LIMIT 1 \gset oldest_
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats where job_id=:reorder_job_id and chunk_id=:oldest_chunk_id;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1002 |       13 |                 1

-- Confirm that reorder was called on the correct chunk Oid
SELECT reorder_called(:oldest_chunk_id);
 reorder_called 
----------------
 t

-- Now run reorder again and pick the next oldest chunk
select cc.chunk_id from _timescaledb_catalog.dimension_slice as ds, _timescaledb_catalog.chunk_constraint as cc where ds.dimension_id=1 and ds.id=cc.dimension_slice_id and cc.chunk_id NOT IN (select chunk_id from _timescaledb_internal.bgw_policy_chunk_stats) ORDER BY ds.range_start LIMIT 1 \gset oldest_
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats where job_id=:reorder_job_id and chunk_id=:oldest_chunk_id;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1002 |       14 |                 1

-- Confirm that reorder was called on the correct chunk Oid
SELECT reorder_called(:oldest_chunk_id);
 reorder_called 
----------------
 t

-- Again
select cc.chunk_id from _timescaledb_catalog.dimension_slice as ds, _timescaledb_catalog.chunk_constraint as cc where ds.dimension_id=1 and ds.id=cc.dimension_slice_id and cc.chunk_id NOT IN (select chunk_id from _timescaledb_internal.bgw_policy_chunk_stats) ORDER BY ds.range_start LIMIT 1 \gset oldest_
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats where job_id=:reorder_job_id and chunk_id=:oldest_chunk_id;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1002 |       10 |                 1

SELECT reorder_called(:oldest_chunk_id);
 reorder_called 
----------------
 t

-- Again
select cc.chunk_id from _timescaledb_catalog.dimension_slice as ds, _timescaledb_catalog.chunk_constraint as cc where ds.dimension_id=1 and ds.id=cc.dimension_slice_id and cc.chunk_id NOT IN (select chunk_id from _timescaledb_internal.bgw_policy_chunk_stats) ORDER BY ds.range_start LIMIT 1 \gset oldest_
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats where job_id=:reorder_job_id and chunk_id=:oldest_chunk_id;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1002 |       11 |                 1

SELECT reorder_called(:oldest_chunk_id);
 reorder_called 
----------------
 t

-- Again
select cc.chunk_id from _timescaledb_catalog.dimension_slice as ds, _timescaledb_catalog.chunk_constraint as cc where ds.dimension_id=1 and ds.id=cc.dimension_slice_id and cc.chunk_id NOT IN (select chunk_id from _timescaledb_internal.bgw_policy_chunk_stats) ORDER BY ds.range_start LIMIT 1 \gset oldest_
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats where job_id=:reorder_job_id and chunk_id=:oldest_chunk_id;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1002 |       12 |                 1

SELECT reorder_called(:oldest_chunk_id);
 reorder_called 
----------------
 t

-- Ran out of chunks, so should be a noop
CALL run_job(:reorder_job_id);
NOTICE:  no chunks need reordering for hypertable public.test_table
-- Corner case: when there are no recent-enough chunks to reorder,
-- DO NOT reorder any new chunks created by space partitioning.
-- We only want to reorder when new dimension_slices on time are created.
INSERT INTO test_table VALUES (now() - INTERVAL '5 months', -5);
INSERT INTO test_table VALUES (now() - INTERVAL '3 weeks', -5);
INSERT INTO test_table VALUES (now(), -25);
-- Should be noop
CALL run_job(:reorder_job_id);
NOTICE:  no chunks need reordering for hypertable public.test_table
-- But if we create a new time dimension, reorder it
INSERT INTO test_table VALUES (now() - INTERVAL '1 year', 1);
select cc.chunk_id from _timescaledb_catalog.dimension_slice as ds, _timescaledb_catalog.chunk_constraint as cc where ds.dimension_id=1 and ds.id=cc.dimension_slice_id and cc.chunk_id NOT IN (select chunk_id from _timescaledb_internal.bgw_policy_chunk_stats) ORDER BY ds.range_start LIMIT 1 \gset oldest_
CALL run_job(:reorder_job_id);
select job_id, chunk_id, num_times_job_run from _timescaledb_internal.bgw_policy_chunk_stats where job_id=:reorder_job_id and chunk_id=:oldest_chunk_id;
 job_id | chunk_id | num_times_job_run 
--------+----------+-------------------
   1002 |       16 |                 1

SELECT reorder_called(:oldest_chunk_id);
 reorder_called 
----------------
 t

-- Should be noop again
CALL run_job(:reorder_job_id);
NOTICE:  no chunks need reordering for hypertable public.test_table
CREATE TABLE test_table_int(time bigint, junk int);
CREATE TABLE test_overflow_smallint(time smallint, junk int);
SELECT create_hypertable('test_table_int', 'time', chunk_time_interval => 1);
      create_hypertable      
-----------------------------
 (2,public,test_table_int,t)

SELECT create_hypertable('test_overflow_smallint', 'time', chunk_time_interval => 1);
          create_hypertable          
-------------------------------------
 (3,public,test_overflow_smallint,t)

create or replace function dummy_now() returns BIGINT LANGUAGE SQL IMMUTABLE as  'SELECT 1::BIGINT';
create or replace function dummy_now2() returns BIGINT LANGUAGE SQL IMMUTABLE as  'SELECT 2::BIGINT';
create or replace function overflow_now() returns SMALLINT LANGUAGE SQL IMMUTABLE as  'SELECT 32767::SMALLINT';
CREATE TABLE test_table_perm(time timestamp PRIMARY KEY);
SELECT create_hypertable('test_table_perm', 'time', chunk_time_interval => 1);
WARNING:  column type "timestamp without time zone" used for "time" does not follow best practices
WARNING:  unexpected interval: smaller than one second
      create_hypertable       
------------------------------
 (4,public,test_table_perm,t)

\set ON_ERROR_STOP 0
-- we cannot add a drop_chunks policy on a table whose open dimension is not time and no now_func is set
select add_retention_policy('test_table_int', INTERVAL '4 months', true);
ERROR:  invalid value for parameter drop_after
\set ON_ERROR_STOP 1
INSERT INTO test_table_int VALUES (-2, -2), (-1, -1), (0,0), (1, 1), (2, 2), (3, 3);
\c :TEST_DBNAME :ROLE_SUPERUSER;
CREATE USER unprivileged;
\c :TEST_DBNAME unprivileged
-- should fail as the user has no permissions on the table
\set ON_ERROR_STOP 0
select set_integer_now_func('test_table_int', 'dummy_now');
ERROR:  must be owner of hypertable "test_table_int"
\set ON_ERROR_STOP 1
\c :TEST_DBNAME :ROLE_SUPERUSER;
DROP USER unprivileged;
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
select set_integer_now_func('test_table_int', 'dummy_now');
 set_integer_now_func 
----------------------
 

select * from test_table_int;
 time | junk 
------+------
   -2 |   -2
   -1 |   -1
    0 |    0
    1 |    1
    2 |    2
    3 |    3

SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int';
 count 
-------
     6

select add_retention_policy('test_table_int', 1, true) as drop_chunks_job_id \gset
-- Now simulate drop_chunks running automatically by calling it explicitly
CALL run_job(:drop_chunks_job_id);
select * from test_table_int;
 time | junk 
------+------
    0 |    0
    1 |    1
    2 |    2
    3 |    3

-- Should have 4 chunks left
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int' \gset before_
select :before_count=4;
 ?column? 
----------
 t

-- Make sure this second call does nothing
CALL run_job(:drop_chunks_job_id);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int' \gset after_
-- Should be true
select :before_count=:after_count;
 ?column? 
----------
 t

INSERT INTO test_table_int VALUES (42, 42);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int' \gset before_
-- This call should also do nothing
CALL run_job(:drop_chunks_job_id);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int' \gset after_
-- Should be true
select :before_count=:after_count;
 ?column? 
----------
 t

INSERT INTO test_table_int VALUES (-1, -1);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int' \gset add_one_
select :before_count+1=:add_one_count;
 ?column? 
----------
 t

CALL run_job(:drop_chunks_job_id);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int' \gset after_
-- (-1,-1) was in droping range so it should be dropped by background job
select :before_count=:after_count;
 ?column? 
----------
 t

select set_integer_now_func('test_table_int', 'dummy_now2', replace_if_exists=>true);
 set_integer_now_func 
----------------------
 

select * from test_table_int;
 time | junk 
------+------
    0 |    0
    1 |    1
    2 |    2
    3 |    3
   42 |   42

CALL run_job(:drop_chunks_job_id);
-- added one to now() so time entry with value 0 should be dropped now
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int' \gset after_
select :before_count=:after_count+1;
 ?column? 
----------
 t

select * from test_table_int;
 time | junk 
------+------
    1 |    1
    2 |    2
    3 |    3
   42 |   42

-- make the now() function invalid -- returns INT and not BIGINT
drop function dummy_now2();
create or replace function dummy_now2() returns INT LANGUAGE SQL IMMUTABLE as  'SELECT 2::INT';
\set ON_ERROR_STOP 0
CALL run_job(:drop_chunks_job_id);
ERROR:  invalid integer_now function
\set ON_ERROR_STOP 1
-- test the expected use case of set_integer_now_func
 create function nowstamp() returns bigint language sql STABLE as 'SELECT extract(epoch from now())::BIGINT';
select set_integer_now_func('test_table_int', 'nowstamp', replace_if_exists=>true);
 set_integer_now_func 
----------------------
 

CALL run_job(:drop_chunks_job_id);
SELECT count(*) FROM _timescaledb_catalog.chunk as c, _timescaledb_catalog.hypertable as ht where c.hypertable_id = ht.id and ht.table_name='test_table_int' \gset after_
select :after_count=0;
 ?column? 
----------
 t

-- test the case when now()-interval overflows
select set_integer_now_func('test_overflow_smallint', 'overflow_now');
 set_integer_now_func 
----------------------
 

select add_retention_policy('test_overflow_smallint', -2) as drop_chunks_job_id \gset
\set ON_ERROR_STOP 0
CALL run_job(:drop_chunks_job_id);
ERROR:  integer time overflow
\set ON_ERROR_STOP 1
-- test the case when partitioning function and now function are set.
create table part_time_now_func(time float8, temp float8);
create or replace function time_partfunc(unixtime float8)
    returns bigint language plpgsql immutable as
$body$
declare
    retval bigint;
begin

    retval := unixtime::bigint;
    raise notice 'time value for % is %', unixtime, retval;
    return retval;
end
$body$;
create or replace function dummy_now() returns bigint language sql immutable as  'select 2::bigint';
select create_hypertable('part_time_now_func', 'time', time_partitioning_func => 'time_partfunc', chunk_time_interval=>1);
        create_hypertable        
---------------------------------
 (5,public,part_time_now_func,t)

insert into part_time_now_func values
(1.1, 23.4), (2.2, 22.3), (3.3, 42.3);
NOTICE:  time value for 1.1 is 1
NOTICE:  time value for 1.1 is 1
NOTICE:  time value for 1.1 is 1
NOTICE:  time value for 1.1 is 1
NOTICE:  time value for 2.2 is 2
NOTICE:  time value for 2.2 is 2
NOTICE:  time value for 2.2 is 2
NOTICE:  time value for 2.2 is 2
NOTICE:  time value for 3.3 is 3
NOTICE:  time value for 3.3 is 3
NOTICE:  time value for 3.3 is 3
NOTICE:  time value for 3.3 is 3
select * from part_time_now_func;
 time | temp 
------+------
  1.1 | 23.4
  2.2 | 22.3
  3.3 | 42.3

select set_integer_now_func('part_time_now_func', 'dummy_now');
 set_integer_now_func 
----------------------
 

select add_retention_policy('part_time_now_func', 0) as drop_chunks_job_id \gset
CALL run_job(:drop_chunks_job_id);
select * from part_time_now_func;
 time | temp 
------+------
  2.2 | 22.3
  3.3 | 42.3

select remove_retention_policy('part_time_now_func');
 remove_retention_policy 
-------------------------
 

\c :TEST_DBNAME :ROLE_SUPERUSER
alter function dummy_now() rename to dummy_now_renamed;
alter schema public rename to new_public;
select * from  _timescaledb_catalog.dimension;
 id | hypertable_id | column_name |         column_type         | aligned | num_slices | partitioning_func_schema | partitioning_func  | interval_length | compress_interval_length | integer_now_func_schema | integer_now_func 
----+---------------+-------------+-----------------------------+---------+------------+--------------------------+--------------------+-----------------+--------------------------+-------------------------+------------------
  1 |             1 | time        | timestamp with time zone    | t       |            |                          |                    |    604800000000 |                          |                         | 
  2 |             1 | chunk_id    | integer                     | f       |          2 | _timescaledb_functions   | get_partition_hash |                 |                          |                         | 
  5 |             4 | time        | timestamp without time zone | t       |            |                          |                    |               1 |                          |                         | 
  6 |             5 | time        | double precision            | t       |            | new_public               | time_partfunc      |               1 |                          | new_public              | dummy_now
  3 |             2 | time        | bigint                      | t       |            |                          |                    |               1 |                          | new_public              | nowstamp
  4 |             3 | time        | smallint                    | t       |            |                          |                    |               1 |                          | new_public              | overflow_now

alter schema new_public rename to public;
\c  :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
-- test that the behavior is strict when providing NULL required arguments
create table test_strict (time timestamptz not null, a int, b int);
select create_hypertable('test_strict', 'time');
    create_hypertable     
--------------------------
 (6,public,test_strict,t)

\set ON_ERROR_STOP 0
select add_reorder_policy('test_table_perm', 'test_table_perm_pkey');
ERROR:  must be owner of hypertable "test_table_perm"
select remove_reorder_policy('test_table');
ERROR:  must be owner of hypertable "test_table"
select add_retention_policy('test_table_perm', INTERVAL '4 months', true);
ERROR:  must be owner of hypertable "test_table_perm"
select remove_retention_policy('test_table');
ERROR:  must be owner of hypertable "test_table"
select add_retention_policy('test_strict', drop_after => NULL);
ERROR:  need to specify one of "drop_after" or "drop_created_before"
\set ON_ERROR_STOP 1
-- Check the number of non-internal policies
SELECT proc_name, count(*)
FROM _timescaledb_catalog.bgw_job
WHERE id >= 1000
GROUP BY proc_name;
    proc_name     | count 
------------------+-------
 policy_reorder   |     1
 policy_retention |     2

-- test retention with null arguments
select add_retention_policy(NULL, NULL);
 add_retention_policy 
----------------------
                     

select add_retention_policy(NULL, drop_after => interval '2 days');
 add_retention_policy 
----------------------
                     

-- this is an optional argument
select add_retention_policy('test_strict', drop_after => interval '2 days', if_not_exists => NULL);
 add_retention_policy 
----------------------
                     

select add_retention_policy('test_strict', interval '2 days', schedule_interval => NULL);
 add_retention_policy 
----------------------
                 1006

-- test compression with null arguments
alter table test_strict set (timescaledb.compress);
select add_compression_policy(NULL, compress_after => NULL);
 add_compression_policy 
------------------------
                       

select add_compression_policy('test_strict', INTERVAL '2 weeks', if_not_exists => NULL);
 add_compression_policy 
------------------------
                       

select add_compression_policy('test_strict', INTERVAL '2 weeks', schedule_interval => NULL);
 add_compression_policy 
------------------------
                   1007

-- test that we get the default schedule_interval if nothing is specified
create table test_missing_schedint (time timestamptz not null, a int, b int);
select create_hypertable('test_missing_schedint', 'time', chunk_time_interval=> '31days'::interval);
         create_hypertable          
------------------------------------
 (8,public,test_missing_schedint,t)

-- we expect shedule_interval to be 1 day
select add_retention_policy('test_missing_schedint', interval '2 weeks') as retenion_id_missing_schedint \gset
-- we expect schedule_interval to be chunk_time_interval/2 for timestamptz time
alter table test_missing_schedint set (timescaledb.compress);
select add_compression_policy('test_missing_schedint', interval '60 days') as compression_id_missing_schedint \gset
-- we expect schedule_interval to be 1 day for int time
create table test_missing_schedint_integer (time int not null, a int, b int);
-- 10 days interval
select create_hypertable('test_missing_schedint_integer', 'time', chunk_time_interval => 864000000);
              create_hypertable              
---------------------------------------------
 (10,public,test_missing_schedint_integer,t)

alter table test_missing_schedint_integer set (timescaledb.compress);
select add_compression_policy('test_missing_schedint_integer', BIGINT '600000') as compression_id_integer \gset
select * from _timescaledb_catalog.bgw_job where id in (:retenion_id_missing_schedint, :compression_id_missing_schedint, :compression_id_integer);
  id  |     application_name      | schedule_interval | max_runtime | max_retries | retry_period |      proc_schema       |     proc_name      |        owner        | scheduled | fixed_schedule | initial_start | hypertable_id |                       config                        |      check_schema      |        check_name        | timezone 
------+---------------------------+-------------------+-------------+-------------+--------------+------------------------+--------------------+---------------------+-----------+----------------+---------------+---------------+-----------------------------------------------------+------------------------+--------------------------+----------
 1008 | Retention Policy [1008]   | @ 1 day           | @ 5 mins    |          -1 | @ 5 mins     | _timescaledb_functions | policy_retention   | default_perm_user_2 | t         | f              |               |             8 | {"drop_after": "@ 14 days", "hypertable_id": 8}     | _timescaledb_functions | policy_retention_check   | 
 1009 | Columnstore Policy [1009] | @ 12 hours        | @ 0         |          -1 | @ 1 hour     | _timescaledb_functions | policy_compression | default_perm_user_2 | t         | f              |               |             8 | {"hypertable_id": 8, "compress_after": "@ 60 days"} | _timescaledb_functions | policy_compression_check | 
 1010 | Columnstore Policy [1010] | @ 1 day           | @ 0         |          -1 | @ 1 hour     | _timescaledb_functions | policy_compression | default_perm_user_2 | t         | f              |               |            10 | {"hypertable_id": 10, "compress_after": 600000}     | _timescaledb_functions | policy_compression_check | 

-- test policy check functions with NULL args
\set ON_ERROR_STOP 0
select add_compression_policy('test_strict', compress_after => NULL);
ERROR:  need to specify one of "compress_after" or "compress_created_before"
SELECT _timescaledb_functions.policy_compression_check(NULL);
ERROR:  config must not be NULL
SELECT _timescaledb_functions.policy_refresh_continuous_aggregate_check(NULL);
ERROR:  config must not be NULL
SELECT _timescaledb_functions.policy_reorder_check(NULL);
ERROR:  config must not be NULL
SELECT _timescaledb_functions.policy_retention_check(NULL);
ERROR:  config must not be NULL
\set ON_ERROR_STOP 1
--TEST check if alias for bgw_job table works
SELECT * from _timescaledb_config.bgw_job WHERE id = :retenion_id_missing_schedint ORDER BY id;
  id  |    application_name     | schedule_interval | max_runtime | max_retries | retry_period |      proc_schema       |    proc_name     |        owner        | scheduled | fixed_schedule | initial_start | hypertable_id |                     config                      |      check_schema      |       check_name       | timezone 
------+-------------------------+-------------------+-------------+-------------+--------------+------------------------+------------------+---------------------+-----------+----------------+---------------+---------------+-------------------------------------------------+------------------------+------------------------+----------
 1008 | Retention Policy [1008] | @ 1 day           | @ 5 mins    |          -1 | @ 5 mins     | _timescaledb_functions | policy_retention | default_perm_user_2 | t         | f              |               |             8 | {"drop_after": "@ 14 days", "hypertable_id": 8} | _timescaledb_functions | policy_retention_check | 

