-- 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
SET ROLE :ROLE_DEFAULT_PERM_USER;
SET client_min_messages TO NOTICE;
CREATE TABLE continuous_agg_test(timeval integer, col1 integer, col2 integer);
select create_hypertable('continuous_agg_test', 'timeval', chunk_time_interval=> 2);
        create_hypertable         
----------------------------------
 (1,public,continuous_agg_test,t)

CREATE OR REPLACE FUNCTION integer_now_test1() returns int LANGUAGE SQL STABLE as $$ SELECT coalesce(max(timeval), 0) FROM continuous_agg_test $$;
SELECT set_integer_now_func('continuous_agg_test', 'integer_now_test1');
 set_integer_now_func 
----------------------
 

INSERT INTO continuous_agg_test VALUES
    (10, - 4, 1), (11, - 3, 5), (12, - 3, 7), (13, - 3, 9), (14,-4, 11),
    (15, -4, 22), (16, -4, 23);
-- TEST for multiple continuous aggs
--- invalidations are picked up by both caggs
CREATE MATERIALIZED VIEW cagg_1( timed, cnt )
WITH (timescaledb.continuous,
      timescaledb.materialized_only=true)
AS
    SELECT time_bucket( 2, timeval), COUNT(col1)
    FROM continuous_agg_test
    GROUP BY 1 WITH NO DATA;
CREATE MATERIALIZED VIEW cagg_2( timed, grp, maxval)
WITH (timescaledb.continuous,
      timescaledb.materialized_only=true)
AS
    SELECT time_bucket(2, timeval), col1, max(col2)
    FROM continuous_agg_test
    GROUP BY 1, 2 WITH NO DATA;
select view_name, view_owner, materialization_hypertable_name
from timescaledb_information.continuous_aggregates ORDER BY 1;
 view_name |    view_owner     | materialization_hypertable_name 
-----------+-------------------+---------------------------------
 cagg_1    | default_perm_user | _materialized_hypertable_2
 cagg_2    | default_perm_user | _materialized_hypertable_3

--TEST1: cagg_1 is materialized, not cagg_2.
CALL refresh_continuous_aggregate('cagg_1', NULL, NULL);
select * from cagg_1 order by 1;
 timed | cnt 
-------+-----
    10 |   2
    12 |   2
    14 |   2
    16 |   1

SELECT time_bucket(2, timeval), COUNT(col1) as value
FROM continuous_agg_test
GROUP BY 1 order by 1;
 time_bucket | value 
-------------+-------
          10 |     2
          12 |     2
          14 |     2
          16 |     1

-- check that cagg_2 not materialized
select * from cagg_2 order by 1,2;
 timed | grp | maxval 
-------+-----+--------

CALL refresh_continuous_aggregate('cagg_2', NULL, NULL);
select * from cagg_2 order by 1,2;
 timed | grp | maxval 
-------+-----+--------
    10 |  -4 |      1
    10 |  -3 |      5
    12 |  -3 |      9
    14 |  -4 |     22
    16 |  -4 |     23

SELECT * FROM _timescaledb_catalog.continuous_aggs_invalidation_threshold;
 hypertable_id | watermark 
---------------+-----------
             1 |        18

--TEST2: cagg_2 gets invalidations after cagg_1's refresh
--will trigger invalidations
INSERT INTO continuous_agg_test VALUES
    (10, -4, 10), (11, - 3, 50), (11, - 3, 70), (10, - 4, 10);
SELECT * FROM _timescaledb_catalog.continuous_aggs_invalidation_threshold;
 hypertable_id | watermark 
---------------+-----------
             1 |        18

CALL refresh_continuous_aggregate('cagg_1', NULL, NULL);
select * from cagg_1 order by 1;
 timed | cnt 
-------+-----
    10 |   6
    12 |   2
    14 |   2
    16 |   1

SELECT time_bucket(2, timeval), COUNT(col1) as value
FROM continuous_agg_test
GROUP BY 1 order by 1;
 time_bucket | value 
-------------+-------
          10 |     6
          12 |     2
          14 |     2
          16 |     1

-- are the invalidations picked up here?
select * from cagg_2 order by 1, 2;
 timed | grp | maxval 
-------+-----+--------
    10 |  -4 |      1
    10 |  -3 |      5
    12 |  -3 |      9
    14 |  -4 |     22
    16 |  -4 |     23

SELECT time_bucket(2, timeval), col1, max(col2)
FROM continuous_agg_test
GROUP BY 1, 2
order by 1,2 ;
 time_bucket | col1 | max 
-------------+------+-----
          10 |   -4 |  10
          10 |   -3 |  70
          12 |   -3 |   9
          14 |   -4 |  22
          16 |   -4 |  23

CALL refresh_continuous_aggregate('cagg_2', NULL, NULL);
select * from cagg_2 order by 1, 2;
 timed | grp | maxval 
-------+-----+--------
    10 |  -4 |     10
    10 |  -3 |     70
    12 |  -3 |      9
    14 |  -4 |     22
    16 |  -4 |     23

--TEST3: invalidations left over by cagg_1 are dropped
--trigger another invalidation
INSERT INTO continuous_agg_test VALUES
    (10, -4, 1000);
select count(*) from _timescaledb_catalog.continuous_aggs_hypertable_invalidation_log;
 count 
-------
     1

select count(*) from _timescaledb_catalog.continuous_aggs_materialization_invalidation_log;
 count 
-------
     4

CALL refresh_continuous_aggregate('cagg_1', NULL, NULL);
select count(*) from _timescaledb_catalog.continuous_aggs_hypertable_invalidation_log;
 count 
-------
     0

select count(*) from _timescaledb_catalog.continuous_aggs_materialization_invalidation_log;
 count 
-------
     5

--now drop cagg_1, should still have materialization_invalidation_log
DROP MATERIALIZED VIEW cagg_1;
NOTICE:  drop cascades to table _timescaledb_internal._hyper_2_5_chunk
select count(*) from _timescaledb_catalog.continuous_aggs_materialization_invalidation_log;
 count 
-------
     3

--cagg_2 still exists
select view_name from timescaledb_information.continuous_aggregates;
 view_name 
-----------
 cagg_2

drop table continuous_agg_test cascade;
NOTICE:  drop cascades to 2 other objects
NOTICE:  drop cascades to table _timescaledb_internal._hyper_3_6_chunk
select count(*) from _timescaledb_catalog.continuous_aggs_materialization_invalidation_log;
 count 
-------
     0

select view_name from timescaledb_information.continuous_aggregates;
 view_name 
-----------

--TEST4: invalidations that are copied over by cagg1 are not deleted by cagg2 refresh if
-- they do not meet materialization invalidation threshold for cagg2.
CREATE TABLE continuous_agg_test(timeval integer, col1 integer, col2 integer);
select create_hypertable('continuous_agg_test', 'timeval', chunk_time_interval=> 2);
        create_hypertable         
----------------------------------
 (4,public,continuous_agg_test,t)

CREATE OR REPLACE FUNCTION integer_now_test1() returns int LANGUAGE SQL STABLE as $$ SELECT coalesce(max(timeval), 0) FROM continuous_agg_test $$;
SELECT set_integer_now_func('continuous_agg_test', 'integer_now_test1');
 set_integer_now_func 
----------------------
 

INSERT INTO continuous_agg_test VALUES
    (10, -4, 1), (11, -3, 5), (12, -3, 7), (13, -3, 9), (14, -4, 11),
    (15, -4, 22), (16, -4, 23);
CREATE MATERIALIZED VIEW cagg_1( timed, cnt )
WITH (timescaledb.continuous,
      timescaledb.materialized_only = true)
AS
    SELECT time_bucket( 2, timeval), COUNT(col1)
    FROM continuous_agg_test
    GROUP BY 1 WITH DATA;
NOTICE:  refreshing continuous aggregate "cagg_1"
CREATE MATERIALIZED VIEW cagg_2( timed, maxval)
WITH (timescaledb.continuous,
      timescaledb.materialized_only = true)
AS
    SELECT time_bucket(2, timeval), max(col2)
    FROM continuous_agg_test
    GROUP BY 1 WITH NO DATA;
--cagg_1 already refreshed on creation
select * from cagg_1 order by 1;
 timed | cnt 
-------+-----
    10 |   2
    12 |   2
    14 |   2
    16 |   1

--partially refresh cagg_2 to 14 to test inserts that won't be seen in
--one of the caggs
CALL refresh_continuous_aggregate('cagg_2', NULL, 14);
select * from cagg_2 order by 1;
 timed | maxval 
-------+--------
    10 |      5
    12 |      9

--this insert will be processed only by cagg_1 and copied over to cagg_2
insert into continuous_agg_test values( 14, -2, 100);
CALL refresh_continuous_aggregate('cagg_1', NULL, NULL);
select * from cagg_1 order by 1;
 timed | cnt 
-------+-----
    10 |   2
    12 |   2
    14 |   3
    16 |   1

CALL refresh_continuous_aggregate('cagg_2', NULL, 14);
NOTICE:  continuous aggregate "cagg_2" is already up-to-date
select * from cagg_2 order by 1;
 timed | maxval 
-------+--------
    10 |      5
    12 |      9

SET ROLE :ROLE_SUPERUSER;
select * from _timescaledb_catalog.continuous_aggs_invalidation_threshold order by 1;
 hypertable_id | watermark 
---------------+-----------
             4 |        18

select * from _timescaledb_catalog.continuous_aggs_materialization_invalidation_log order by 1;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------
                  5 |  -9223372036854775808 |             -2147483649
                  5 |                    18 |     9223372036854775807
                  6 |  -9223372036854775808 |             -2147483649
                  6 |                    14 |     9223372036854775807

SET ROLE :ROLE_DEFAULT_PERM_USER;
--this insert will be processed only by cagg_1 and cagg_2 will process the previous
--one
insert into continuous_agg_test values( 18, -2, 200);
CALL refresh_continuous_aggregate('cagg_1', NULL, NULL);
select * from cagg_1 order by 1;
 timed | cnt 
-------+-----
    10 |   2
    12 |   2
    14 |   3
    16 |   1
    18 |   1

-- Now make changes visible up to 16
CALL refresh_continuous_aggregate('cagg_2', NULL, 16);
select * from cagg_2 order by 1;
 timed | maxval 
-------+--------
    10 |      5
    12 |      9
    14 |    100

--TEST5 2 inserts with the same value can be copied over to materialization invalidation log
insert into continuous_agg_test values( 18, -2, 100);
insert into continuous_agg_test values( 18, -2, 100);
select * from _timescaledb_catalog.continuous_aggs_hypertable_invalidation_log order by 1;
 hypertable_id | lowest_modified_value | greatest_modified_value 
---------------+-----------------------+-------------------------
             4 |                    18 |                      18
             4 |                    18 |                      18

CALL refresh_continuous_aggregate('cagg_1', NULL, NULL);
select * from cagg_1 where timed = 18 ;
 timed | cnt 
-------+-----
    18 |   3

--copied over for cagg_2 to process later?
select * from _timescaledb_catalog.continuous_aggs_materialization_invalidation_log order by 1;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------
                  5 |  -9223372036854775808 |             -2147483649
                  5 |                    20 |     9223372036854775807
                  6 |  -9223372036854775808 |             -2147483649
                  6 |                    16 |     9223372036854775807
                  6 |                    18 |                      19

DROP MATERIALIZED VIEW cagg_1;
NOTICE:  drop cascades to table _timescaledb_internal._hyper_5_11_chunk
DROP MATERIALIZED VIEW cagg_2;
NOTICE:  drop cascades to table _timescaledb_internal._hyper_6_12_chunk
----TEST7 multiple continuous aggregates with real time aggregates test----
create table foo (a integer, b integer, c integer);
select table_name FROM create_hypertable('foo', 'a', chunk_time_interval=> 10);
 table_name 
------------
 foo

INSERT into foo values( 1 , 10 , 20);
INSERT into foo values( 1 , 11 , 20);
INSERT into foo values( 1 , 12 , 20);
INSERT into foo values( 1 , 13 , 20);
INSERT into foo values( 1 , 14 , 20);
INSERT into foo values( 5 , 14 , 20);
INSERT into foo values( 5 , 15 , 20);
INSERT into foo values( 5 , 16 , 20);
INSERT into foo values( 20 , 16 , 20);
INSERT into foo values( 20 , 26 , 20);
INSERT into foo values( 20 , 16 , 20);
INSERT into foo values( 21 , 15 , 30);
INSERT into foo values( 21 , 15 , 30);
INSERT into foo values( 21 , 15 , 30);
INSERT into foo values( 45 , 14 , 70);
CREATE OR REPLACE FUNCTION integer_now_foo() returns int LANGUAGE SQL STABLE as $$ SELECT coalesce(max(a), 0) FROM foo $$;
SELECT set_integer_now_func('foo', 'integer_now_foo');
 set_integer_now_func 
----------------------
 

CREATE MATERIALIZED VIEW mat_m1(a, countb)
WITH (timescaledb.continuous, timescaledb.materialized_only=false)
AS
SELECT time_bucket(10, a), count(*)
FROM foo
GROUP BY time_bucket(10, a) WITH NO DATA;
CREATE MATERIALIZED VIEW mat_m2(a, countb)
WITH (timescaledb.continuous, timescaledb.materialized_only=false)
AS
SELECT time_bucket(5, a), count(*)
FROM foo
GROUP BY time_bucket(5, a) WITH NO DATA;
select view_name, materialized_only from timescaledb_information.continuous_aggregates
WHERE view_name::text like 'mat_m%'
order by view_name;
 view_name | materialized_only 
-----------+-------------------
 mat_m1    | f
 mat_m2    | f

CALL refresh_continuous_aggregate('mat_m1', NULL, 35);
CALL refresh_continuous_aggregate('mat_m2', NULL, NULL);
-- the results from the view should match the direct query
SELECT * from mat_m1 order by 1;
 a  | countb 
----+--------
  0 |      8
 20 |      6
 40 |      1

SELECT time_bucket(5, a), count(*)
FROM foo
GROUP BY time_bucket(5, a)
ORDER BY 1;
 time_bucket | count 
-------------+-------
           0 |     5
           5 |     3
          20 |     6
          45 |     1

SELECT * from mat_m2 order by 1;
 a  | countb 
----+--------
  0 |      5
  5 |      3
 20 |      6
 45 |      1

SELECT time_bucket(10, a), count(*)
FROM foo
GROUP BY time_bucket(10, a)
ORDER BY 1;
 time_bucket | count 
-------------+-------
           0 |     8
          20 |     6
          40 |     1

