-- 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 OR REPLACE FUNCTION ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(timeout INT = -1, mock_start_time INT = 0) RETURNS VOID
AS :MODULE_PATHNAME LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION ts_bgw_params_create() RETURNS VOID
AS :MODULE_PATHNAME LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION ts_bgw_params_destroy() RETURNS VOID
AS :MODULE_PATHNAME LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION ts_bgw_params_reset_time(set_time BIGINT = 0, wait BOOLEAN = false) RETURNS VOID
AS :MODULE_PATHNAME LANGUAGE C VOLATILE;
-- Create a user with specific timezone and mock time
CREATE ROLE test_cagg_refresh_policy_user WITH LOGIN;
ALTER ROLE test_cagg_refresh_policy_user SET timezone TO 'UTC';
ALTER ROLE test_cagg_refresh_policy_user SET timescaledb.current_timestamp_mock TO '2025-03-11 00:00:00+00';
GRANT ALL ON SCHEMA public TO test_cagg_refresh_policy_user;
\c :TEST_DBNAME test_cagg_refresh_policy_user
CREATE TABLE public.bgw_log(
    msg_no INT,
    mock_time BIGINT,
    application_name TEXT,
    msg TEXT
);
CREATE VIEW sorted_bgw_log AS
SELECT
    msg_no,
    mock_time,
    application_name,
    regexp_replace(regexp_replace(msg, '(Wait until|started at|execution time) [0-9]+(\.[0-9]+)?', '\1 (RANDOM)', 'g'), 'background worker "[^"]+"','connection') AS msg
FROM
    bgw_log
ORDER BY
    mock_time,
    application_name COLLATE "C",
    msg_no;
CREATE TABLE public.bgw_dsm_handle_store(
    handle BIGINT
);
INSERT INTO public.bgw_dsm_handle_store VALUES (0);
SELECT ts_bgw_params_create();
 ts_bgw_params_create 
----------------------
 

CREATE TABLE conditions (
    time         TIMESTAMP WITH TIME ZONE NOT NULL,
    device_id    INTEGER,
    temperature  NUMERIC
);
SELECT FROM create_hypertable('conditions', by_range('time'));
--

INSERT INTO conditions
SELECT
    t, d, 10
FROM
    generate_series(
        '2025-02-05 00:00:00+00',
        '2025-03-05 00:00:00+00',
        '1 hour'::interval) AS t,
    generate_series(1,5) AS d;
CREATE MATERIALIZED VIEW conditions_by_day
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
SELECT
    time_bucket('1 day', time),
    device_id,
    count(*),
    min(temperature),
    max(temperature),
    avg(temperature),
    sum(temperature)
FROM
    conditions
GROUP BY
    1, 2
WITH NO DATA;
SELECT
    add_continuous_aggregate_policy(
        'conditions_by_day',
        start_offset => NULL,
        end_offset => NULL,
        schedule_interval => INTERVAL '1 h',
        buckets_per_batch => 10
    ) AS job_id \gset
SELECT
    config
FROM
    timescaledb_information.jobs
WHERE
    job_id = :'job_id' \gset
SELECT ts_bgw_params_reset_time(0, true);
 ts_bgw_params_reset_time 
--------------------------
 

SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no | mock_time |              application_name              |                                                                                   msg                                                                                    
--------+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
      0 |         0 | DB Scheduler                               | [TESTING] Registered new background worker
      1 |         0 | DB Scheduler                               | [TESTING] Registered new background worker
      2 |         0 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 |         0 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sat Mar 01 00:00:00 2025 UTC, Thu Mar 06 00:00:00 2025 UTC ] (batch 1 of 4)
      1 |         0 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 |         0 | Refresh Continuous Aggregate Policy [1000] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      3 |         0 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Wed Feb 19 00:00:00 2025 UTC, Sat Mar 01 00:00:00 2025 UTC ] (batch 2 of 4)
      4 |         0 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      5 |         0 | Refresh Continuous Aggregate Policy [1000] | inserted 50 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      6 |         0 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sun Feb 09 00:00:00 2025 UTC, Wed Feb 19 00:00:00 2025 UTC ] (batch 3 of 4)
      7 |         0 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      8 |         0 | Refresh Continuous Aggregate Policy [1000] | inserted 50 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      9 |         0 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Mon Nov 24 00:00:00 4714 UTC BC, Sun Feb 09 00:00:00 2025 UTC ] (batch 4 of 4)
     10 |         0 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
     11 |         0 | Refresh Continuous Aggregate Policy [1000] | inserted 20 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

CREATE MATERIALIZED VIEW conditions_by_day_manual_refresh
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
SELECT
    time_bucket('1 day', time),
    device_id,
    count(*),
    min(temperature),
    max(temperature),
    avg(temperature),
    sum(temperature)
FROM
    conditions
GROUP BY
    1, 2
WITH NO DATA;
CALL refresh_continuous_aggregate('conditions_by_day_manual_refresh', NULL, NULL);
SELECT count(*) FROM conditions_by_day;
 count 
-------
   145

SELECT count(*) FROM conditions_by_day_manual_refresh;
 count 
-------
   145

-- Should have no differences
SELECT
    count(*) > 0 AS has_diff
FROM
    ((SELECT * FROM conditions_by_day_manual_refresh ORDER BY 1, 2)
    EXCEPT
    (SELECT * FROM conditions_by_day ORDER BY 1, 2)) AS diff;
 has_diff 
----------
 f

TRUNCATE bgw_log, conditions_by_day;
SELECT
    config
FROM
    alter_job(
        :'job_id',
        config => jsonb_set(:'config', '{max_batches_per_execution}', '2')
    );
                                                           config                                                            
-----------------------------------------------------------------------------------------------------------------------------
 {"end_offset": null, "start_offset": null, "buckets_per_batch": 10, "mat_hypertable_id": 2, "max_batches_per_execution": 2}

-- advance time by 1h so that job runs one more time
SELECT ts_bgw_params_reset_time(extract(epoch from interval '1 hour')::bigint * 1000000, true);
 ts_bgw_params_reset_time 
--------------------------
 

SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no | mock_time  |              application_name              |                                                                                  msg                                                                                  
--------+------------+--------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
      0 | 3600000000 | DB Scheduler                               | [TESTING] Registered new background worker
      1 | 3600000000 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sat Mar 01 00:00:00 2025 UTC, Thu Mar 06 00:00:00 2025 UTC ] (batch 1 of 4)
      1 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      3 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Wed Feb 19 00:00:00 2025 UTC, Sat Mar 01 00:00:00 2025 UTC ] (batch 2 of 4)
      4 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      5 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | inserted 50 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      6 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | reached maximum number of batches per execution (2), batches not processed (2)

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

SELECT count(*) FROM conditions_by_day;
 count 
-------
    75

SELECT count(*) FROM conditions_by_day_manual_refresh;
 count 
-------
   145

-- Should have differences
SELECT
    count(*) > 0 AS has_diff
FROM
    ((SELECT * FROM conditions_by_day_manual_refresh ORDER BY 1, 2)
    EXCEPT
    (SELECT * FROM conditions_by_day ORDER BY 1, 2)) AS diff;
 has_diff 
----------
 t

-- advance time by 2h so that job runs one more time
SELECT ts_bgw_params_reset_time(extract(epoch from interval '2 hour')::bigint * 1000000, true);
 ts_bgw_params_reset_time 
--------------------------
 

SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no | mock_time  |              application_name              |                                                                                   msg                                                                                    
--------+------------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
      0 | 3600000000 | DB Scheduler                               | [TESTING] Registered new background worker
      1 | 3600000000 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sat Mar 01 00:00:00 2025 UTC, Thu Mar 06 00:00:00 2025 UTC ] (batch 1 of 4)
      1 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      3 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Wed Feb 19 00:00:00 2025 UTC, Sat Mar 01 00:00:00 2025 UTC ] (batch 2 of 4)
      4 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      5 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | inserted 50 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      6 | 3600000000 | Refresh Continuous Aggregate Policy [1000] | reached maximum number of batches per execution (2), batches not processed (2)
      0 | 7200000000 | DB Scheduler                               | [TESTING] Registered new background worker
      1 | 7200000000 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 | 7200000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sun Feb 09 00:00:00 2025 UTC, Wed Feb 19 00:00:00 2025 UTC ] (batch 1 of 2)
      1 | 7200000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 | 7200000000 | Refresh Continuous Aggregate Policy [1000] | inserted 50 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      3 | 7200000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Mon Nov 24 00:00:00 4714 UTC BC, Sun Feb 09 00:00:00 2025 UTC ] (batch 2 of 2)
      4 | 7200000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      5 | 7200000000 | Refresh Continuous Aggregate Policy [1000] | inserted 20 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

-- Should have no differences
SELECT
    count(*) > 0 AS has_diff
FROM
    ((SELECT * FROM conditions_by_day_manual_refresh ORDER BY 1, 2)
    EXCEPT
    (SELECT * FROM conditions_by_day ORDER BY 1, 2)) AS diff;
 has_diff 
----------
 f

-- Set max_batches_per_execution to 10
SELECT
    config
FROM
    alter_job(
        :'job_id',
        config => jsonb_set(:'config', '{max_batches_per_execution}', '10')
    );
                                                            config                                                            
------------------------------------------------------------------------------------------------------------------------------
 {"end_offset": null, "start_offset": null, "buckets_per_batch": 10, "mat_hypertable_id": 2, "max_batches_per_execution": 10}

TRUNCATE bgw_log;
-- Insert data into the past
INSERT INTO conditions
SELECT
    t, d, 10
FROM
    generate_series(
        '2020-02-05 00:00:00+00',
        '2020-03-05 00:00:00+00',
        '1 hour'::interval) AS t,
    generate_series(1,5) AS d;
-- advance time by 3h so that job runs one more time
SELECT ts_bgw_params_reset_time(extract(epoch from interval '3 hour')::bigint * 1000000, true);
 ts_bgw_params_reset_time 
--------------------------
 

-- Should process all four batches in the past
SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no |  mock_time  |              application_name              |                                                                                  msg                                                                                  
--------+-------------+--------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
      0 | 10800000000 | DB Scheduler                               | [TESTING] Registered new background worker
      1 | 10800000000 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sat Feb 29 00:00:00 2020 UTC, Fri Mar 06 00:00:00 2020 UTC ] (batch 1 of 4)
      1 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | inserted 30 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      3 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Wed Feb 19 00:00:00 2020 UTC, Sat Feb 29 00:00:00 2020 UTC ] (batch 2 of 4)
      4 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      5 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | inserted 50 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      6 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sun Feb 09 00:00:00 2020 UTC, Wed Feb 19 00:00:00 2020 UTC ] (batch 3 of 4)
      7 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      8 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | inserted 50 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      9 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Wed Feb 05 00:00:00 2020 UTC, Sun Feb 09 00:00:00 2020 UTC ] (batch 4 of 4)
     10 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
     11 | 10800000000 | Refresh Continuous Aggregate Policy [1000] | inserted 20 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

SELECT count(*) FROM conditions_by_day;
 count 
-------
   295

SELECT count(*) FROM conditions_by_day_manual_refresh;
 count 
-------
   145

CALL refresh_continuous_aggregate('conditions_by_day_manual_refresh', NULL, NULL);
SELECT count(*) FROM conditions_by_day;
 count 
-------
   295

SELECT count(*) FROM conditions_by_day_manual_refresh;
 count 
-------
   295

-- Should have no differences
SELECT
    count(*) > 0 AS has_diff
FROM
    ((SELECT * FROM conditions_by_day_manual_refresh ORDER BY 1, 2)
    EXCEPT
    (SELECT * FROM conditions_by_day ORDER BY 1, 2)) AS diff;
 has_diff 
----------
 f

-- Check invalid configurations
\set ON_ERROR_STOP 0
\set VERBOSITY default
SELECT
    config
FROM
    alter_job(
        :'job_id',
        config => jsonb_set(:'config', '{max_batches_per_execution}', '-1')
    );
ERROR:  invalid max batches per execution
DETAIL:  max_batches_per_execution: -1
HINT:  The max batches per execution should be greater than or equal to zero.
SELECT
    config
FROM
    alter_job(
        :'job_id',
        config => jsonb_set(:'config', '{buckets_per_batch}', '-1')
    );
ERROR:  invalid buckets per batch
DETAIL:  buckets_per_batch: -1
HINT:  The buckets per batch should be greater than or equal to zero.
\set VERBOSITY terse
\set ON_ERROR_STOP 1
-- Truncate all data from the original hypertable
TRUNCATE bgw_log, conditions;
-- advance time by 4h so that job runs one more time
SELECT ts_bgw_params_reset_time(extract(epoch from interval '4 hour')::bigint * 1000000, true);
 ts_bgw_params_reset_time 
--------------------------
 

-- Should fallback to single batch processing because there's no data to be refreshed on the original hypertable
SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no |  mock_time  |              application_name              |                                                                            msg                                                                            
--------+-------------+--------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------
      0 | 14400000000 | DB Scheduler                               | [TESTING] Registered new background worker
      1 | 14400000000 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 | 14400000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Mon Nov 24 00:00:00 4714 UTC BC, Thu Mar 06 00:00:00 2025 UTC ]
      1 | 14400000000 | Refresh Continuous Aggregate Policy [1000] | deleted 295 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 | 14400000000 | Refresh Continuous Aggregate Policy [1000] | inserted 0 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

-- Should return zero rows
SELECT count(*) FROM conditions_by_day;
 count 
-------
     0

-- 1 day of data
INSERT INTO conditions
SELECT
    t, d, 10
FROM
    generate_series(
        '2020-02-05 00:00:00+00',
        '2020-02-06 00:00:00+00',
        '1 hour'::interval) AS t,
    generate_series(1,5) AS d;
TRUNCATE bgw_log;
-- advance time by 5h so that job runs one more time
SELECT ts_bgw_params_reset_time(extract(epoch from interval '5 hour')::bigint * 1000000, true);
 ts_bgw_params_reset_time 
--------------------------
 

-- Should fallback to single batch processing because the refresh size is too small
SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no |  mock_time  |              application_name              |                                                                          msg                                                                           
--------+-------------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------
      0 | 18000000000 | DB Scheduler                               | [TESTING] Registered new background worker
      1 | 18000000000 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 | 18000000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Wed Feb 05 00:00:00 2020 UTC, Fri Feb 07 00:00:00 2020 UTC ]
      1 | 18000000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 | 18000000000 | Refresh Continuous Aggregate Policy [1000] | inserted 10 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

-- Should return 10 rows because the bucket width is `1 day` and buckets per batch is `10`
SELECT count(*) FROM conditions_by_day;
 count 
-------
    10

TRUNCATE conditions_by_day, conditions, bgw_log;
-- Less than 1 day of data (smaller than the bucket width)
INSERT INTO conditions
VALUES ('2020-02-05 00:00:00+00', 1, 10);
-- advance time by 6h so that job runs one more time
SELECT ts_bgw_params_reset_time(extract(epoch from interval '6 hour')::bigint * 1000000, true);
 ts_bgw_params_reset_time 
--------------------------
 

-- Should fallback to single batch processing because the refresh size is too small
SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no |  mock_time  |              application_name              |                                                                            msg                                                                            
--------+-------------+--------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------
      0 | 21600000000 | DB Scheduler                               | [TESTING] Registered new background worker
      1 | 21600000000 | DB Scheduler                               | [TESTING] Registered new background worker
      2 | 21600000000 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 | 21600000000 | Refresh Continuous Aggregate Policy [1000] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Mon Nov 24 00:00:00 4714 UTC BC, Thu Mar 06 00:00:00 2025 UTC ]
      1 | 21600000000 | Refresh Continuous Aggregate Policy [1000] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 | 21600000000 | Refresh Continuous Aggregate Policy [1000] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

-- Should return 1 row
SELECT count(*) FROM conditions_by_day;
 count 
-------
     1

SELECT delete_job(:job_id);
 delete_job 
------------
 

SELECT
    add_continuous_aggregate_policy(
        'conditions_by_day',
        start_offset => INTERVAL '15 days',
        end_offset => NULL,
        schedule_interval => INTERVAL '1 h',
        buckets_per_batch => 5,
        refresh_newest_first => true -- explicitly set to true to test the default behavior
    ) AS job_id \gset
SELECT
    add_continuous_aggregate_policy(
        'conditions_by_day_manual_refresh',
        start_offset => INTERVAL '15 days',
        end_offset => NULL,
        schedule_interval => INTERVAL '1 h',
        buckets_per_batch => 0 -- 0 means no batching, so it will refresh all buckets in one go
    ) AS job_id_manual \gset
TRUNCATE bgw_log, conditions_by_day, conditions_by_day_manual_refresh, conditions;
INSERT INTO conditions
SELECT
    t, d, 10
FROM
    generate_series(
        '2025-03-11 00:00:00+00'::timestamptz - INTERVAL '30 days',
        '2025-03-11 00:00:00+00'::timestamptz,
        '1 hour'::interval) AS t,
    generate_series(1,5) AS d;
SELECT ts_bgw_params_reset_time(0, true);
 ts_bgw_params_reset_time 
--------------------------
 

SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no | mock_time |              application_name              |                                                                                  msg                                                                                  
--------+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
      0 |         0 | DB Scheduler                               | [TESTING] Registered new background worker
      1 |         0 | DB Scheduler                               | [TESTING] Registered new background worker
      2 |         0 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 |         0 | Refresh Continuous Aggregate Policy [1001] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Tue Mar 11 00:00:00 2025 UTC, Wed Mar 12 00:00:00 2025 UTC ] (batch 1 of 4)
      1 |         0 | Refresh Continuous Aggregate Policy [1001] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 |         0 | Refresh Continuous Aggregate Policy [1001] | inserted 5 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      3 |         0 | Refresh Continuous Aggregate Policy [1001] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Thu Mar 06 00:00:00 2025 UTC, Tue Mar 11 00:00:00 2025 UTC ] (batch 2 of 4)
      4 |         0 | Refresh Continuous Aggregate Policy [1001] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      5 |         0 | Refresh Continuous Aggregate Policy [1001] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      6 |         0 | Refresh Continuous Aggregate Policy [1001] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sat Mar 01 00:00:00 2025 UTC, Thu Mar 06 00:00:00 2025 UTC ] (batch 3 of 4)
      7 |         0 | Refresh Continuous Aggregate Policy [1001] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      8 |         0 | Refresh Continuous Aggregate Policy [1001] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      9 |         0 | Refresh Continuous Aggregate Policy [1001] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Mon Feb 24 00:00:00 2025 UTC, Sat Mar 01 00:00:00 2025 UTC ] (batch 4 of 4)
     10 |         0 | Refresh Continuous Aggregate Policy [1001] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
     11 |         0 | Refresh Continuous Aggregate Policy [1001] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      0 |         0 | Refresh Continuous Aggregate Policy [1002] | continuous aggregate refresh (individual invalidation) on "conditions_by_day_manual_refresh" in window [ Mon Feb 24 00:00:00 2025 UTC, Wed Mar 12 00:00:00 2025 UTC ]
      1 |         0 | Refresh Continuous Aggregate Policy [1002] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_3"
      2 |         0 | Refresh Continuous Aggregate Policy [1002] | inserted 80 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_3"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

-- Both continuous aggregates should have the same data
SELECT count(*) FROM conditions_by_day;
 count 
-------
    80

SELECT count(*) FROM conditions_by_day_manual_refresh;
 count 
-------
    80

-- Should have no differences
SELECT
    count(*) > 0 AS has_diff
FROM
    ((SELECT * FROM conditions_by_day_manual_refresh ORDER BY 1, 2)
    EXCEPT
    (SELECT * FROM conditions_by_day ORDER BY 1, 2)) AS diff;
 has_diff 
----------
 f

-- Testing with explicit refresh_newest_first = false (from oldest to newest)
SELECT delete_job(:job_id);
 delete_job 
------------
 

SELECT delete_job(:job_id_manual);
 delete_job 
------------
 

SELECT
    add_continuous_aggregate_policy(
        'conditions_by_day',
        start_offset => INTERVAL '15 days',
        end_offset => NULL,
        schedule_interval => INTERVAL '1 h',
        buckets_per_batch => 5,
        refresh_newest_first => false
    ) AS job_id \gset
SELECT
    config
FROM
    timescaledb_information.jobs
WHERE
    job_id = :'job_id';
                                                              config                                                              
----------------------------------------------------------------------------------------------------------------------------------
 {"end_offset": null, "start_offset": "@ 15 days", "buckets_per_batch": 5, "mat_hypertable_id": 2, "refresh_newest_first": false}

TRUNCATE bgw_log, conditions_by_day;
SELECT ts_bgw_params_reset_time(0, true);
 ts_bgw_params_reset_time 
--------------------------
 

SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no | mock_time |              application_name              |                                                                                  msg                                                                                  
--------+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
      0 |         0 | DB Scheduler                               | [TESTING] Registered new background worker
      1 |         0 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 |         0 | Refresh Continuous Aggregate Policy [1003] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Mon Feb 24 00:00:00 2025 UTC, Sat Mar 01 00:00:00 2025 UTC ] (batch 1 of 4)
      1 |         0 | Refresh Continuous Aggregate Policy [1003] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      2 |         0 | Refresh Continuous Aggregate Policy [1003] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      3 |         0 | Refresh Continuous Aggregate Policy [1003] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Sat Mar 01 00:00:00 2025 UTC, Thu Mar 06 00:00:00 2025 UTC ] (batch 2 of 4)
      4 |         0 | Refresh Continuous Aggregate Policy [1003] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      5 |         0 | Refresh Continuous Aggregate Policy [1003] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      6 |         0 | Refresh Continuous Aggregate Policy [1003] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Thu Mar 06 00:00:00 2025 UTC, Tue Mar 11 00:00:00 2025 UTC ] (batch 3 of 4)
      7 |         0 | Refresh Continuous Aggregate Policy [1003] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
      8 |         0 | Refresh Continuous Aggregate Policy [1003] | inserted 25 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"
      9 |         0 | Refresh Continuous Aggregate Policy [1003] | continuous aggregate refresh (individual invalidation) on "conditions_by_day" in window [ Tue Mar 11 00:00:00 2025 UTC, Wed Mar 12 00:00:00 2025 UTC ] (batch 4 of 4)
     10 |         0 | Refresh Continuous Aggregate Policy [1003] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_2"
     11 |         0 | Refresh Continuous Aggregate Policy [1003] | inserted 5 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_2"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

-- Both continuous aggregates should have the same data
SELECT count(*) FROM conditions_by_day;
 count 
-------
    80

SELECT count(*) FROM conditions_by_day_manual_refresh;
 count 
-------
    80

-- Should have no differences
SELECT
    count(*) > 0 AS has_diff
FROM
    ((SELECT * FROM conditions_by_day_manual_refresh ORDER BY 1, 2)
    EXCEPT
    (SELECT * FROM conditions_by_day ORDER BY 1, 2)) AS diff;
 has_diff 
----------
 f

-- Tests with Variable sized bucket
SELECT delete_job(:job_id);
 delete_job 
------------
 

TRUNCATE conditions;
INSERT INTO conditions
SELECT
    t, d, 10
FROM
    generate_series(
        '2025-01-01 00:00:00+00',
        '2025-10-08 00:00:00+00',
        '1 hour'::interval) AS t,
    generate_series(1,5) AS d;
CREATE MATERIALIZED VIEW conditions_by_month
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
SELECT
    time_bucket('1 month', time),
    device_id,
    count(*),
    min(temperature),
    max(temperature),
    avg(temperature),
    sum(temperature)
FROM
    conditions
GROUP BY
    1, 2
WITH NO DATA;
SELECT
    add_continuous_aggregate_policy(
        'conditions_by_month',
        start_offset => INTERVAL '600 days',
        end_offset => INTERVAL '7 days',
        schedule_interval => INTERVAL '1 day',
        refresh_newest_first => false
    ) AS job_id \gset
SELECT
    config
FROM
    timescaledb_information.jobs
WHERE
    job_id = :'job_id';
                                                     config                                                      
-----------------------------------------------------------------------------------------------------------------
 {"end_offset": "@ 7 days", "start_offset": "@ 600 days", "mat_hypertable_id": 4, "refresh_newest_first": false}

TRUNCATE bgw_log, conditions_by_day;
SELECT ts_bgw_params_reset_time(0, true);
 ts_bgw_params_reset_time 
--------------------------
 

SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no | mock_time |              application_name              |                                                                           msg                                                                            
--------+-----------+--------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------
      0 |         0 | DB Scheduler                               | [TESTING] Registered new background worker
      1 |         0 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 |         0 | Refresh Continuous Aggregate Policy [1004] | continuous aggregate refresh (individual invalidation) on "conditions_by_month" in window [ Tue Aug 01 00:00:00 2023 UTC, Sat Mar 01 00:00:00 2025 UTC ]
      1 |         0 | Refresh Continuous Aggregate Policy [1004] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_4"
      2 |         0 | Refresh Continuous Aggregate Policy [1004] | inserted 10 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_4"

SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_ranges;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------

SELECT delete_job(:job_id);
 delete_job 
------------
 

------------------------------------------------------------------------------------------
--Test that batched refresh with variable-length buckets doesn't leave remainders
-------------------------------------------------------------------------------------------
CREATE TABLE test_data (
    time TIMESTAMPTZ NOT NULL,
    value INT
);
SELECT public.create_hypertable(
        relation => 'test_data',
        time_column_name => 'time',
        chunk_time_interval => interval '1 months'
);
   create_hypertable    
------------------------
 (5,public,test_data,t)

-- Insert initial data
INSERT INTO test_data
SELECT time, 1
FROM generate_series('2024-01-01'::timestamptz, '2024-12-31'::timestamptz, '1 day'::interval) time;
-- Create continuous aggregate with monthly buckets and timezone (variable-length buckets)
CREATE MATERIALIZED VIEW batch_test_cagg
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('1 month'::interval, time) AS bucket,
    count(*) as count
FROM test_data
GROUP BY bucket
WITH NO DATA;
-- Add a policy to enable batched refresh (batch size is 30 days by default for monthly buckets)
SELECT add_continuous_aggregate_policy('batch_test_cagg',
    start_offset =>null,
    end_offset => INTERVAL '1 month',
    schedule_interval => INTERVAL '1 hour',
    buckets_per_batch => 1
) AS job_id \gset
-- Run the policy job - this uses batched processing, 1 bucket per batch
TRUNCATE bgw_log;
SELECT ts_bgw_params_reset_time(0, true);
 ts_bgw_params_reset_time 
--------------------------
 

SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

-- Verify that invalidation log has no entries other than the left and right ends with -/+ infinity
SELECT materialization_id,
       _timescaledb_functions.to_timestamp(lowest_modified_value) as low,
       _timescaledb_functions.to_timestamp(greatest_modified_value) as high
FROM _timescaledb_catalog.continuous_aggs_materialization_invalidation_log
WHERE materialization_id IN
      (SELECT mat_hypertable_id FROM _timescaledb_catalog.continuous_agg
       WHERE user_view_name = 'batch_test_cagg')
  AND lowest_modified_value != -9223372036854775808 --  -infinity
  AND greatest_modified_value != 9223372036854775807 -- +infinity
ORDER BY low;
 materialization_id | low | high 
--------------------+-----+------

--verify that there is no duplicate/overlapping refreshes.
--Note that batch 1 and batch 12 contains 2 buckets instead of 1 bucket as set in the policy.
--This is due to the fact that we currently cut a batch of 30 days for monthly cagg,
--so first batch and batch containing February can have 2 buckets. After we have a cleaner solution to
--cut an exact batch size for variable-length buckets, this should be fixed.
SELECT * FROM sorted_bgw_log;
 msg_no | mock_time |              application_name              |                                                                                  msg                                                                                  
--------+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
      0 |         0 | DB Scheduler                               | [TESTING] Registered new background worker
      1 |         0 | DB Scheduler                               | [TESTING] Wait until (RANDOM), started at (RANDOM)
      0 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Sun Dec 01 00:00:00 2024 UTC, Sat Feb 01 00:00:00 2025 UTC ] (batch 1 of 13)
      1 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
      2 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
      3 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Fri Nov 01 00:00:00 2024 UTC, Sun Dec 01 00:00:00 2024 UTC ] (batch 2 of 13)
      4 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
      5 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
      6 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Tue Oct 01 00:00:00 2024 UTC, Fri Nov 01 00:00:00 2024 UTC ] (batch 3 of 13)
      7 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
      8 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
      9 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Sun Sep 01 00:00:00 2024 UTC, Tue Oct 01 00:00:00 2024 UTC ] (batch 4 of 13)
     10 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     11 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
     12 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Thu Aug 01 00:00:00 2024 UTC, Sun Sep 01 00:00:00 2024 UTC ] (batch 5 of 13)
     13 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     14 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
     15 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Mon Jul 01 00:00:00 2024 UTC, Thu Aug 01 00:00:00 2024 UTC ] (batch 6 of 13)
     16 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     17 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
     18 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Sat Jun 01 00:00:00 2024 UTC, Mon Jul 01 00:00:00 2024 UTC ] (batch 7 of 13)
     19 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     20 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
     21 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Wed May 01 00:00:00 2024 UTC, Sat Jun 01 00:00:00 2024 UTC ] (batch 8 of 13)
     22 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     23 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
     24 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Mon Apr 01 00:00:00 2024 UTC, Wed May 01 00:00:00 2024 UTC ] (batch 9 of 13)
     25 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     26 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
     27 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Fri Mar 01 00:00:00 2024 UTC, Mon Apr 01 00:00:00 2024 UTC ] (batch 10 of 13)
     28 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     29 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
     30 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ Mon Jan 01 00:00:00 2024 UTC, Fri Mar 01 00:00:00 2024 UTC ] (batch 12 of 13)
     31 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     32 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 2 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"
     33 |         0 | Refresh Continuous Aggregate Policy [1005] | continuous aggregate refresh (individual invalidation) on "batch_test_cagg" in window [ -infinity, Mon Jan 01 00:00:00 2024 UTC ] (batch 13 of 13)
     34 |         0 | Refresh Continuous Aggregate Policy [1005] | deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_6"
     35 |         0 | Refresh Continuous Aggregate Policy [1005] | inserted 0 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_6"

--now run the refresh again, should not do anything
TRUNCATE bgw_log;
SELECT ts_bgw_params_reset_time(extract(epoch from interval '1 hour')::bigint * 1000000, true);
 ts_bgw_params_reset_time 
--------------------------
 

SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(25);
 ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish 
------------------------------------------------------------
 

SELECT * FROM sorted_bgw_log;
 msg_no | mock_time  | application_name |                        msg                         
--------+------------+------------------+----------------------------------------------------
      0 | 3600000000 | DB Scheduler     | [TESTING] Registered new background worker
      1 | 3600000000 | DB Scheduler     | [TESTING] Wait until (RANDOM), started at (RANDOM)

--clean up
DROP TABLE test_data CASCADE;
NOTICE:  drop cascades to 2 other objects
NOTICE:  drop cascades to 2 other objects
\c :TEST_DBNAME :ROLE_SUPERUSER
REASSIGN OWNED BY test_cagg_refresh_policy_user TO :ROLE_SUPERUSER;
REVOKE ALL ON SCHEMA public FROM test_cagg_refresh_policy_user;
DROP ROLE test_cagg_refresh_policy_user;
