-- 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.
-- Connect as superuser to use SET ROLE later
\c :TEST_DBNAME :ROLE_SUPERUSER
SET timezone TO PST8PDT;
-- Run tests with default role
SET ROLE :ROLE_DEFAULT_PERM_USER;
-- Enable MERGE statements for continuous aggregate refresh
SET timescaledb.enable_merge_on_cagg_refresh TO ON;
\set TEST_BASE_NAME cagg_query_using_merge
\ir include/cagg_query_common.sql
-- 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.
SELECT
       format('%s/results/%s_results_view.out', :'TEST_OUTPUT_DIR', :'TEST_BASE_NAME') as "TEST_RESULTS_VIEW",
       format('%s/results/%s_results_view_hashagg.out', :'TEST_OUTPUT_DIR', :'TEST_BASE_NAME') as "TEST_RESULTS_VIEW_HASHAGG",
       format('%s/results/%s_results_table.out', :'TEST_OUTPUT_DIR', :'TEST_BASE_NAME') as "TEST_RESULTS_TABLE"
\gset
SELECT format('\! diff %s %s', :'TEST_RESULTS_VIEW', :'TEST_RESULTS_TABLE') as "DIFF_CMD",
      format('\! diff %s %s', :'TEST_RESULTS_VIEW_HASHAGG', :'TEST_RESULTS_TABLE') as "DIFF_CMD2"
\gset
\set EXPLAIN 'EXPLAIN (VERBOSE, BUFFERS OFF, COSTS OFF)'
SET client_min_messages TO NOTICE;
CREATE TABLE conditions (
      timec        TIMESTAMPTZ       NOT NULL,
      location    TEXT              NOT NULL,
      temperature DOUBLE PRECISION  NULL,
      humidity    DOUBLE PRECISION  NULL
    );
select table_name from create_hypertable( 'conditions', 'timec');
 table_name 
------------
 conditions

insert into conditions values ( '2018-01-01 09:20:00-08', 'SFO', 55, 45);
insert into conditions values ( '2018-01-02 09:30:00-08', 'por', 100, 100);
insert into conditions values ( '2018-01-02 09:20:00-08', 'SFO', 65, 45);
insert into conditions values ( '2018-01-02 09:10:00-08', 'NYC', 65, 45);
insert into conditions values ( '2018-11-01 09:20:00-08', 'NYC', 45, 30);
insert into conditions values ( '2018-11-01 10:40:00-08', 'NYC', 55, 35);
insert into conditions values ( '2018-11-01 11:50:00-08', 'NYC', 65, 40);
insert into conditions values ( '2018-11-01 12:10:00-08', 'NYC', 75, 45);
insert into conditions values ( '2018-11-01 13:10:00-08', 'NYC', 85, 50);
insert into conditions values ( '2018-11-02 09:20:00-08', 'NYC', 10, 10);
insert into conditions values ( '2018-11-02 10:30:00-08', 'NYC', 20, 15);
insert into conditions values ( '2018-11-02 11:40:00-08', 'NYC', null, null);
insert into conditions values ( '2018-11-03 09:50:00-08', 'NYC', null, null);
create table location_tab( locid integer, locname text );
insert into location_tab values( 1, 'SFO');
insert into location_tab values( 2, 'NYC');
insert into location_tab values( 3, 'por');
create materialized view mat_m1( location, timec, minl, sumt , sumh)
WITH (timescaledb.continuous, timescaledb.materialized_only=false)
as
select location, time_bucket('1day', timec), min(location), sum(temperature),sum(humidity)
from conditions
group by time_bucket('1day', timec), location WITH NO DATA;
--compute time_bucketted max+bucket_width for the materialized view
SELECT time_bucket('1day' , q.timeval+ '1day'::interval)
FROM ( select max(timec)as timeval from conditions ) as q;
         time_bucket          
------------------------------
 Sat Nov 03 17:00:00 2018 PDT

CALL refresh_continuous_aggregate('mat_m1', NULL, NULL);
--test first/last
create materialized view mat_m2(location, timec, firsth, lasth, maxtemp, mintemp)
WITH (timescaledb.continuous, timescaledb.materialized_only=false)
as
select location, time_bucket('1day', timec), first(humidity, timec), last(humidity, timec), max(temperature), min(temperature)
from conditions
group by time_bucket('1day', timec), location WITH NO DATA;
--time that refresh assumes as now() for repeatability
SELECT time_bucket('1day' , q.timeval+ '1day'::interval)
FROM ( select max(timec)as timeval from conditions ) as q;
         time_bucket          
------------------------------
 Sat Nov 03 17:00:00 2018 PDT

CALL refresh_continuous_aggregate('mat_m2', NULL, NULL);
--normal view --
create or replace view regview( location, timec, minl, sumt , sumh)
as
select location, time_bucket('1day', timec), min(location), sum(temperature),sum(humidity)
from conditions
group by location, time_bucket('1day', timec);
set enable_hashagg = false;
-- NO pushdown cases ---
--when we have addl. attrs in order by that are not in the
-- group by, we will still need a sort
:EXPLAIN
select * from mat_m1 order by sumh, sumt, minl, timec ;
--- QUERY PLAN ---
 Sort
   Output: _materialized_hypertable_2.location, _materialized_hypertable_2.timec, _materialized_hypertable_2.minl, _materialized_hypertable_2.sumt, _materialized_hypertable_2.sumh
   Sort Key: _materialized_hypertable_2.sumh, _materialized_hypertable_2.sumt, _materialized_hypertable_2.minl, _materialized_hypertable_2.timec
   ->  Append
         ->  Append
               ->  Seq Scan on _timescaledb_internal._hyper_2_3_chunk
                     Output: _hyper_2_3_chunk.location, _hyper_2_3_chunk.timec, _hyper_2_3_chunk.minl, _hyper_2_3_chunk.sumt, _hyper_2_3_chunk.sumh
               ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
                     Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
                     Index Cond: (_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)
         ->  GroupAggregate
               Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), min(_hyper_1_2_chunk.location), sum(_hyper_1_2_chunk.temperature), sum(_hyper_1_2_chunk.humidity)
               Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
               ->  Sort
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                     Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Result
                           Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                           ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                 Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                 Index Cond: (_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)

:EXPLAIN
select * from regview order by timec desc;
--- QUERY PLAN ---
 Sort
   Output: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec)), (min(conditions.location)), (sum(conditions.temperature)), (sum(conditions.humidity))
   Sort Key: (time_bucket('@ 1 day'::interval, conditions.timec)) DESC
   ->  Finalize GroupAggregate
         Output: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec)), min(conditions.location), sum(conditions.temperature), sum(conditions.humidity)
         Group Key: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec))
         ->  Sort
               Output: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec)), (PARTIAL min(conditions.location)), (PARTIAL sum(conditions.temperature)), (PARTIAL sum(conditions.humidity))
               Sort Key: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec))
               ->  Append
                     ->  Partial GroupAggregate
                           Output: _hyper_1_1_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec)), PARTIAL min(_hyper_1_1_chunk.location), PARTIAL sum(_hyper_1_1_chunk.temperature), PARTIAL sum(_hyper_1_1_chunk.humidity)
                           Group Key: _hyper_1_1_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec))
                           ->  Sort
                                 Output: _hyper_1_1_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec)), _hyper_1_1_chunk.temperature, _hyper_1_1_chunk.humidity
                                 Sort Key: _hyper_1_1_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec))
                                 ->  Seq Scan on _timescaledb_internal._hyper_1_1_chunk
                                       Output: _hyper_1_1_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec), _hyper_1_1_chunk.temperature, _hyper_1_1_chunk.humidity
                     ->  Partial GroupAggregate
                           Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), PARTIAL min(_hyper_1_2_chunk.location), PARTIAL sum(_hyper_1_2_chunk.temperature), PARTIAL sum(_hyper_1_2_chunk.humidity)
                           Group Key: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec))
                           ->  Sort
                                 Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                 Sort Key: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec))
                                 ->  Seq Scan on _timescaledb_internal._hyper_1_2_chunk
                                       Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity

-- PUSHDOWN cases --
-- all group by elts in order by , reorder group by elts to match
-- group by order
-- This should prevent an additional sort after GroupAggregate
:EXPLAIN
select * from mat_m1 order by timec desc, location;
--- QUERY PLAN ---
 Sort
   Output: _materialized_hypertable_2.location, _materialized_hypertable_2.timec, _materialized_hypertable_2.minl, _materialized_hypertable_2.sumt, _materialized_hypertable_2.sumh
   Sort Key: _materialized_hypertable_2.timec DESC, _materialized_hypertable_2.location
   ->  Append
         ->  Append
               ->  Seq Scan on _timescaledb_internal._hyper_2_3_chunk
                     Output: _hyper_2_3_chunk.location, _hyper_2_3_chunk.timec, _hyper_2_3_chunk.minl, _hyper_2_3_chunk.sumt, _hyper_2_3_chunk.sumh
               ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
                     Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
                     Index Cond: (_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)
         ->  GroupAggregate
               Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), min(_hyper_1_2_chunk.location), sum(_hyper_1_2_chunk.temperature), sum(_hyper_1_2_chunk.humidity)
               Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
               ->  Sort
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                     Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Result
                           Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                           ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                 Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                 Index Cond: (_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)

:EXPLAIN
select * from mat_m1 order by location, timec desc;
--- QUERY PLAN ---
 Sort
   Output: _materialized_hypertable_2.location, _materialized_hypertable_2.timec, _materialized_hypertable_2.minl, _materialized_hypertable_2.sumt, _materialized_hypertable_2.sumh
   Sort Key: _materialized_hypertable_2.location, _materialized_hypertable_2.timec DESC
   ->  Append
         ->  Append
               ->  Seq Scan on _timescaledb_internal._hyper_2_3_chunk
                     Output: _hyper_2_3_chunk.location, _hyper_2_3_chunk.timec, _hyper_2_3_chunk.minl, _hyper_2_3_chunk.sumt, _hyper_2_3_chunk.sumh
               ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
                     Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
                     Index Cond: (_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)
         ->  GroupAggregate
               Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), min(_hyper_1_2_chunk.location), sum(_hyper_1_2_chunk.temperature), sum(_hyper_1_2_chunk.humidity)
               Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
               ->  Sort
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                     Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Result
                           Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                           ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                 Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                 Index Cond: (_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)

:EXPLAIN
select * from mat_m1 order by location, timec asc;
--- QUERY PLAN ---
 Sort
   Output: _materialized_hypertable_2.location, _materialized_hypertable_2.timec, _materialized_hypertable_2.minl, _materialized_hypertable_2.sumt, _materialized_hypertable_2.sumh
   Sort Key: _materialized_hypertable_2.location, _materialized_hypertable_2.timec
   ->  Append
         ->  Append
               ->  Seq Scan on _timescaledb_internal._hyper_2_3_chunk
                     Output: _hyper_2_3_chunk.location, _hyper_2_3_chunk.timec, _hyper_2_3_chunk.minl, _hyper_2_3_chunk.sumt, _hyper_2_3_chunk.sumh
               ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
                     Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
                     Index Cond: (_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)
         ->  GroupAggregate
               Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), min(_hyper_1_2_chunk.location), sum(_hyper_1_2_chunk.temperature), sum(_hyper_1_2_chunk.humidity)
               Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
               ->  Sort
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                     Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Result
                           Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                           ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                 Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                 Index Cond: (_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)

:EXPLAIN
select * from mat_m1 where timec > '2018-10-01' order by timec desc;
--- QUERY PLAN ---
 Sort
   Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
   Sort Key: _hyper_2_4_chunk.timec DESC
   ->  Append
         ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
               Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
               Index Cond: ((_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_2_4_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
         ->  GroupAggregate
               Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), min(_hyper_1_2_chunk.location), sum(_hyper_1_2_chunk.temperature), sum(_hyper_1_2_chunk.humidity)
               Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
               ->  Sort
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                     Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Result
                           Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                           ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                 Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                 Index Cond: ((_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_1_2_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                                 Filter: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec) > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone)

-- outer sort is used by mat_m1 for grouping. But doesn't avoid a sort after the join ---
:EXPLAIN
select l.locid, mat_m1.* from mat_m1 , location_tab l where timec > '2018-10-01' and l.locname = mat_m1.location order by timec desc;
--- QUERY PLAN ---
 Sort
   Output: l.locid, _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
   Sort Key: _hyper_2_4_chunk.timec DESC
   ->  Hash Join
         Output: l.locid, _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
         Hash Cond: (l.locname = _hyper_2_4_chunk.location)
         ->  Seq Scan on public.location_tab l
               Output: l.locid, l.locname
         ->  Hash
               Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
               ->  Append
                     ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
                           Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
                           Index Cond: ((_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_2_4_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                     ->  GroupAggregate
                           Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), min(_hyper_1_2_chunk.location), sum(_hyper_1_2_chunk.temperature), sum(_hyper_1_2_chunk.humidity)
                           Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                           ->  Sort
                                 Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                 Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                                 ->  Result
                                       Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                       ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                             Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                             Index Cond: ((_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_1_2_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                                             Filter: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec) > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone)

:EXPLAIN
select * from mat_m2 where timec > '2018-10-01' order by timec desc;
--- QUERY PLAN ---
 Sort
   Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
   Sort Key: _hyper_3_6_chunk.timec DESC
   ->  Append
         ->  Index Scan using _hyper_3_6_chunk__materialized_hypertable_3_timec_idx on _timescaledb_internal._hyper_3_6_chunk
               Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
               Index Cond: ((_hyper_3_6_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_3_6_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
         ->  GroupAggregate
               Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), first(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), last(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), max(_hyper_1_2_chunk.temperature), min(_hyper_1_2_chunk.temperature)
               Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
               ->  Sort
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                     Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Result
                           Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                           ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                 Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.temperature
                                 Index Cond: ((_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_1_2_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                                 Filter: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec) > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone)

:EXPLAIN
select * from (select * from mat_m2 where timec > '2018-10-01' order by timec desc ) as q limit 1;
--- QUERY PLAN ---
 Limit
   Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
   ->  Sort
         Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
         Sort Key: _hyper_3_6_chunk.timec DESC
         ->  Append
               ->  Index Scan using _hyper_3_6_chunk__materialized_hypertable_3_timec_idx on _timescaledb_internal._hyper_3_6_chunk
                     Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
                     Index Cond: ((_hyper_3_6_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_3_6_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
               ->  GroupAggregate
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), first(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), last(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), max(_hyper_1_2_chunk.temperature), min(_hyper_1_2_chunk.temperature)
                     Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Sort
                           Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                           Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                           ->  Result
                                 Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                                 ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                       Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.temperature
                                       Index Cond: ((_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_1_2_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                                       Filter: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec) > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone)

:EXPLAIN
select * from (select * from mat_m2 where timec > '2018-10-01' order by timec desc , location asc nulls first) as q limit 1;
--- QUERY PLAN ---
 Limit
   Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
   ->  Sort
         Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
         Sort Key: _hyper_3_6_chunk.timec DESC, _hyper_3_6_chunk.location NULLS FIRST
         ->  Append
               ->  Index Scan using _hyper_3_6_chunk__materialized_hypertable_3_timec_idx on _timescaledb_internal._hyper_3_6_chunk
                     Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
                     Index Cond: ((_hyper_3_6_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_3_6_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
               ->  GroupAggregate
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), first(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), last(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), max(_hyper_1_2_chunk.temperature), min(_hyper_1_2_chunk.temperature)
                     Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Sort
                           Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                           Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                           ->  Result
                                 Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                                 ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                       Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.temperature
                                       Index Cond: ((_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_1_2_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                                       Filter: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec) > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone)

--plans with CTE
:EXPLAIN
with m1 as (
Select * from mat_m2 where timec > '2018-10-01' order by timec desc )
select * from m1;
--- QUERY PLAN ---
 Sort
   Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
   Sort Key: _hyper_3_6_chunk.timec DESC
   ->  Append
         ->  Index Scan using _hyper_3_6_chunk__materialized_hypertable_3_timec_idx on _timescaledb_internal._hyper_3_6_chunk
               Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
               Index Cond: ((_hyper_3_6_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_3_6_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
         ->  GroupAggregate
               Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), first(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), last(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), max(_hyper_1_2_chunk.temperature), min(_hyper_1_2_chunk.temperature)
               Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
               ->  Sort
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                     Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Result
                           Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                           ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                 Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.temperature
                                 Index Cond: ((_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_1_2_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                                 Filter: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec) > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone)

-- should reorder mat_m1 group by only based on mat_m1 order-by
:EXPLAIN
select * from mat_m1, mat_m2 where mat_m1.timec > '2018-10-01' and mat_m1.timec = mat_m2.timec order by mat_m1.timec desc;
--- QUERY PLAN ---
 Sort
   Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh, _materialized_hypertable_3.location, _materialized_hypertable_3.timec, _materialized_hypertable_3.firsth, _materialized_hypertable_3.lasth, _materialized_hypertable_3.maxtemp, _materialized_hypertable_3.mintemp
   Sort Key: _hyper_2_4_chunk.timec DESC
   ->  Hash Join
         Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh, _materialized_hypertable_3.location, _materialized_hypertable_3.timec, _materialized_hypertable_3.firsth, _materialized_hypertable_3.lasth, _materialized_hypertable_3.maxtemp, _materialized_hypertable_3.mintemp
         Hash Cond: (_materialized_hypertable_3.timec = _hyper_2_4_chunk.timec)
         ->  Append
               ->  Append
                     ->  Seq Scan on _timescaledb_internal._hyper_3_5_chunk
                           Output: _hyper_3_5_chunk.location, _hyper_3_5_chunk.timec, _hyper_3_5_chunk.firsth, _hyper_3_5_chunk.lasth, _hyper_3_5_chunk.maxtemp, _hyper_3_5_chunk.mintemp
                     ->  Index Scan using _hyper_3_6_chunk__materialized_hypertable_3_timec_idx on _timescaledb_internal._hyper_3_6_chunk
                           Output: _hyper_3_6_chunk.location, _hyper_3_6_chunk.timec, _hyper_3_6_chunk.firsth, _hyper_3_6_chunk.lasth, _hyper_3_6_chunk.maxtemp, _hyper_3_6_chunk.mintemp
                           Index Cond: (_hyper_3_6_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)
               ->  GroupAggregate
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), first(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), last(_hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec), max(_hyper_1_2_chunk.temperature), min(_hyper_1_2_chunk.temperature)
                     Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Sort
                           Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                           Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                           ->  Result
                                 Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature
                                 ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                       Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.humidity, _hyper_1_2_chunk.temperature
                                       Index Cond: (_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)
         ->  Hash
               Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
               ->  Append
                     ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
                           Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
                           Index Cond: ((_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_2_4_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                     ->  GroupAggregate
                           Output: _hyper_1_2_chunk_1.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec)), min(_hyper_1_2_chunk_1.location), sum(_hyper_1_2_chunk_1.temperature), sum(_hyper_1_2_chunk_1.humidity)
                           Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec)), _hyper_1_2_chunk_1.location
                           ->  Sort
                                 Output: _hyper_1_2_chunk_1.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec)), _hyper_1_2_chunk_1.temperature, _hyper_1_2_chunk_1.humidity
                                 Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec)), _hyper_1_2_chunk_1.location
                                 ->  Result
                                       Output: _hyper_1_2_chunk_1.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec), _hyper_1_2_chunk_1.temperature, _hyper_1_2_chunk_1.humidity
                                       ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk _hyper_1_2_chunk_1
                                             Output: _hyper_1_2_chunk_1.location, _hyper_1_2_chunk_1.timec, _hyper_1_2_chunk_1.temperature, _hyper_1_2_chunk_1.humidity
                                             Index Cond: ((_hyper_1_2_chunk_1.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_1_2_chunk_1.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                                             Filter: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec) > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone)

--should reorder only for mat_m1.
:EXPLAIN
select * from mat_m1, regview where mat_m1.timec > '2018-10-01' and mat_m1.timec = regview.timec order by mat_m1.timec desc;
--- QUERY PLAN ---
 Sort
   Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh, conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec)), (min(conditions.location)), (sum(conditions.temperature)), (sum(conditions.humidity))
   Sort Key: _hyper_2_4_chunk.timec DESC
   ->  Hash Join
         Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh, conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec)), (min(conditions.location)), (sum(conditions.temperature)), (sum(conditions.humidity))
         Hash Cond: ((time_bucket('@ 1 day'::interval, conditions.timec)) = _hyper_2_4_chunk.timec)
         ->  Finalize GroupAggregate
               Output: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec)), min(conditions.location), sum(conditions.temperature), sum(conditions.humidity)
               Group Key: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec))
               ->  Sort
                     Output: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec)), (PARTIAL min(conditions.location)), (PARTIAL sum(conditions.temperature)), (PARTIAL sum(conditions.humidity))
                     Sort Key: conditions.location, (time_bucket('@ 1 day'::interval, conditions.timec))
                     ->  Append
                           ->  Partial GroupAggregate
                                 Output: _hyper_1_1_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec)), PARTIAL min(_hyper_1_1_chunk.location), PARTIAL sum(_hyper_1_1_chunk.temperature), PARTIAL sum(_hyper_1_1_chunk.humidity)
                                 Group Key: _hyper_1_1_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec))
                                 ->  Sort
                                       Output: _hyper_1_1_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec)), _hyper_1_1_chunk.temperature, _hyper_1_1_chunk.humidity
                                       Sort Key: _hyper_1_1_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec))
                                       ->  Seq Scan on _timescaledb_internal._hyper_1_1_chunk
                                             Output: _hyper_1_1_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_1_chunk.timec), _hyper_1_1_chunk.temperature, _hyper_1_1_chunk.humidity
                           ->  Partial GroupAggregate
                                 Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), PARTIAL min(_hyper_1_2_chunk.location), PARTIAL sum(_hyper_1_2_chunk.temperature), PARTIAL sum(_hyper_1_2_chunk.humidity)
                                 Group Key: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec))
                                 ->  Sort
                                       Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                       Sort Key: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec))
                                       ->  Seq Scan on _timescaledb_internal._hyper_1_2_chunk
                                             Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
         ->  Hash
               Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
               ->  Append
                     ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
                           Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
                           Index Cond: ((_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_2_4_chunk.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                     ->  GroupAggregate
                           Output: _hyper_1_2_chunk_1.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec)), min(_hyper_1_2_chunk_1.location), sum(_hyper_1_2_chunk_1.temperature), sum(_hyper_1_2_chunk_1.humidity)
                           Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec)), _hyper_1_2_chunk_1.location
                           ->  Sort
                                 Output: _hyper_1_2_chunk_1.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec)), _hyper_1_2_chunk_1.temperature, _hyper_1_2_chunk_1.humidity
                                 Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec)), _hyper_1_2_chunk_1.location
                                 ->  Result
                                       Output: _hyper_1_2_chunk_1.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec), _hyper_1_2_chunk_1.temperature, _hyper_1_2_chunk_1.humidity
                                       ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk _hyper_1_2_chunk_1
                                             Output: _hyper_1_2_chunk_1.location, _hyper_1_2_chunk_1.timec, _hyper_1_2_chunk_1.temperature, _hyper_1_2_chunk_1.humidity
                                             Index Cond: ((_hyper_1_2_chunk_1.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone) AND (_hyper_1_2_chunk_1.timec > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone))
                                             Filter: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk_1.timec) > 'Mon Oct 01 00:00:00 2018 PDT'::timestamp with time zone)

select l.locid, mat_m1.* from mat_m1 , location_tab l where timec > '2018-10-01' and l.locname = mat_m1.location order by timec desc;
 locid | location |            timec             | minl | sumt | sumh 
-------+----------+------------------------------+------+------+------
     2 | NYC      | Fri Nov 02 17:00:00 2018 PDT | NYC  |      |     
     2 | NYC      | Thu Nov 01 17:00:00 2018 PDT | NYC  |   30 |   25
     2 | NYC      | Wed Oct 31 17:00:00 2018 PDT | NYC  |  325 |  200

\set ECHO none
---- Run the same queries with hash agg enabled now
set enable_hashagg = true;
\set ECHO none
--- Run the queries directly on the table now
set enable_hashagg = true;
\set ECHO none
-- diff results view select and table select
:DIFF_CMD
:DIFF_CMD2
--check if the guc works , reordering will not work
set timescaledb.enable_cagg_reorder_groupby = false;
set enable_hashagg = false;
:EXPLAIN
select * from mat_m1 order by timec desc, location;
--- QUERY PLAN ---
 Sort
   Output: _materialized_hypertable_2.location, _materialized_hypertable_2.timec, _materialized_hypertable_2.minl, _materialized_hypertable_2.sumt, _materialized_hypertable_2.sumh
   Sort Key: _materialized_hypertable_2.timec DESC, _materialized_hypertable_2.location
   ->  Append
         ->  Append
               ->  Seq Scan on _timescaledb_internal._hyper_2_3_chunk
                     Output: _hyper_2_3_chunk.location, _hyper_2_3_chunk.timec, _hyper_2_3_chunk.minl, _hyper_2_3_chunk.sumt, _hyper_2_3_chunk.sumh
               ->  Index Scan using _hyper_2_4_chunk__materialized_hypertable_2_timec_idx on _timescaledb_internal._hyper_2_4_chunk
                     Output: _hyper_2_4_chunk.location, _hyper_2_4_chunk.timec, _hyper_2_4_chunk.minl, _hyper_2_4_chunk.sumt, _hyper_2_4_chunk.sumh
                     Index Cond: (_hyper_2_4_chunk.timec < 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)
         ->  GroupAggregate
               Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), min(_hyper_1_2_chunk.location), sum(_hyper_1_2_chunk.temperature), sum(_hyper_1_2_chunk.humidity)
               Group Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
               ->  Sort
                     Output: _hyper_1_2_chunk.location, (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                     Sort Key: (time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec)), _hyper_1_2_chunk.location
                     ->  Result
                           Output: _hyper_1_2_chunk.location, time_bucket('@ 1 day'::interval, _hyper_1_2_chunk.timec), _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                           ->  Index Scan using _hyper_1_2_chunk_conditions_timec_idx on _timescaledb_internal._hyper_1_2_chunk
                                 Output: _hyper_1_2_chunk.location, _hyper_1_2_chunk.timec, _hyper_1_2_chunk.temperature, _hyper_1_2_chunk.humidity
                                 Index Cond: (_hyper_1_2_chunk.timec >= 'Sat Nov 03 17:00:00 2018 PDT'::timestamp with time zone)

-----------------------------------------------------------------------
-- Test the cagg_watermark function. The watermark gives the point
-- where to UNION raw and materialized data in real-time
-- aggregation. Specifically, test that the watermark caching works as
-- expected.
-----------------------------------------------------------------------
-- Insert some more data so that there is something to UNION in
-- real-time aggregation.
insert into conditions values ( '2018-12-02 20:10:00-08', 'SFO', 55, 45);
insert into conditions values ( '2018-12-02 21:20:00-08', 'SFO', 65, 45);
insert into conditions values ( '2018-12-02 20:30:00-08', 'NYC', 65, 45);
insert into conditions values ( '2018-12-02 21:50:00-08', 'NYC', 45, 30);
-- Test join of two caggs. Joining two caggs will force the cache to
-- reset every time the watermark function is invoked on a different
-- cagg in the same query.
SELECT mat_hypertable_id AS mat_id,
	   raw_hypertable_id AS raw_id,
	   schema_name AS mat_schema,
	   table_name AS mat_name,
	   format('%I.%I', schema_name, table_name) AS mat_table
FROM _timescaledb_catalog.continuous_agg ca, _timescaledb_catalog.hypertable h
WHERE user_view_name='mat_m1'
AND h.id = ca.mat_hypertable_id \gset
BEGIN;
-- Query without join
SELECT m1.location, m1.timec, sumt, sumh
FROM mat_m1 m1
ORDER BY m1.location COLLATE "C", m1.timec DESC
LIMIT 10;
 location |            timec             | sumt | sumh 
----------+------------------------------+------+------
 NYC      | Sun Dec 02 16:00:00 2018 PST |  110 |   75
 NYC      | Fri Nov 02 17:00:00 2018 PDT |      |     
 NYC      | Thu Nov 01 17:00:00 2018 PDT |   30 |   25
 NYC      | Wed Oct 31 17:00:00 2018 PDT |  325 |  200
 NYC      | Mon Jan 01 16:00:00 2018 PST |   65 |   45
 SFO      | Sun Dec 02 16:00:00 2018 PST |  120 |   90
 SFO      | Mon Jan 01 16:00:00 2018 PST |   65 |   45
 SFO      | Sun Dec 31 16:00:00 2017 PST |   55 |   45
 por      | Mon Jan 01 16:00:00 2018 PST |  100 |  100

-- Query that joins two caggs. This should force the watermark cache
-- to reset when the materialized hypertable ID changes. A hash join
-- could potentially read all values from mat_m1 then all values from
-- mat_m2. This would be the optimal situation for cagg_watermark
-- caching. We want to avoid it in tests to see that caching doesn't
-- do anything wrong in worse situations (e.g., a nested loop join).
SET enable_hashjoin=false;
SELECT m1.location, m1.timec, sumt, sumh, firsth, lasth, maxtemp, mintemp
FROM mat_m1 m1 RIGHT JOIN mat_m2 m2
ON (m1.location = m2.location
AND m1.timec = m2.timec)
ORDER BY m1.location COLLATE "C", m1.timec DESC
LIMIT 10;
 location |            timec             | sumt | sumh | firsth | lasth | maxtemp | mintemp 
----------+------------------------------+------+------+--------+-------+---------+---------
 NYC      | Sun Dec 02 16:00:00 2018 PST |  110 |   75 |     45 |    30 |      65 |      45
 NYC      | Fri Nov 02 17:00:00 2018 PDT |      |      |        |       |         |        
 NYC      | Thu Nov 01 17:00:00 2018 PDT |   30 |   25 |     10 |       |      20 |      10
 NYC      | Wed Oct 31 17:00:00 2018 PDT |  325 |  200 |     30 |    50 |      85 |      45
 NYC      | Mon Jan 01 16:00:00 2018 PST |   65 |   45 |     45 |    45 |      65 |      65
 SFO      | Sun Dec 02 16:00:00 2018 PST |  120 |   90 |     45 |    45 |      65 |      55
 SFO      | Mon Jan 01 16:00:00 2018 PST |   65 |   45 |     45 |    45 |      65 |      65
 SFO      | Sun Dec 31 16:00:00 2017 PST |   55 |   45 |     45 |    45 |      55 |      55
 por      | Mon Jan 01 16:00:00 2018 PST |  100 |  100 |    100 |   100 |     100 |     100

-- Show the current watermark
SELECT _timescaledb_functions.to_timestamp(_timescaledb_functions.cagg_watermark(:mat_id));
         to_timestamp         
------------------------------
 Sat Nov 03 17:00:00 2018 PDT

-- The watermark should, in this case, be the same as the invalidation
-- threshold
SELECT _timescaledb_functions.to_timestamp(watermark)
FROM _timescaledb_catalog.continuous_aggs_invalidation_threshold
WHERE hypertable_id = :raw_id;
         to_timestamp         
------------------------------
 Sat Nov 03 17:00:00 2018 PDT

-- The watermark is the end of materialization (end of last bucket)
-- while the MAX is the start of the last bucket
SELECT max(timec) FROM :mat_table;
             max              
------------------------------
 Fri Nov 02 17:00:00 2018 PDT

-- Drop the most recent chunk
SELECT chunk_name, range_start, range_end
FROM timescaledb_information.chunks
WHERE hypertable_name = :'mat_name';
    chunk_name    |         range_start          |          range_end           
------------------+------------------------------+------------------------------
 _hyper_2_3_chunk | Wed Nov 29 16:00:00 2017 PST | Wed Feb 07 16:00:00 2018 PST
 _hyper_2_4_chunk | Wed Sep 05 17:00:00 2018 PDT | Wed Nov 14 16:00:00 2018 PST

SELECT drop_chunks('mat_m1', newer_than=>'2018-01-01'::timestamptz);
              drop_chunks               
----------------------------------------
 _timescaledb_internal._hyper_2_4_chunk

SELECT chunk_name, range_start, range_end
FROM timescaledb_information.chunks
WHERE hypertable_name = :'mat_name';
    chunk_name    |         range_start          |          range_end           
------------------+------------------------------+------------------------------
 _hyper_2_3_chunk | Wed Nov 29 16:00:00 2017 PST | Wed Feb 07 16:00:00 2018 PST

-- The watermark should be updated to reflect the dropped data (i.e.,
-- the cache should be reset)
SELECT _timescaledb_functions.to_timestamp(_timescaledb_functions.cagg_watermark(:mat_id));
         to_timestamp         
------------------------------
 Tue Jan 02 16:00:00 2018 PST

-- Since we removed the last chunk, the invalidation threshold doesn't
-- move back, while the watermark does.
SELECT _timescaledb_functions.to_timestamp(watermark)
FROM _timescaledb_catalog.continuous_aggs_invalidation_threshold
WHERE hypertable_id = :raw_id;
         to_timestamp         
------------------------------
 Sat Nov 03 17:00:00 2018 PDT

-- Compare the new watermark to the MAX time in the table
SELECT max(timec) FROM :mat_table;
             max              
------------------------------
 Mon Jan 01 16:00:00 2018 PST

-- Try a subtransaction
SAVEPOINT clear_cagg;
SELECT m1.location, m1.timec, sumt, sumh, firsth, lasth, maxtemp, mintemp
FROM mat_m1 m1 RIGHT JOIN mat_m2 m2
ON (m1.location = m2.location
AND m1.timec = m2.timec)
ORDER BY m1.location COLLATE "C", m1.timec DESC
LIMIT 10;
 location |            timec             | sumt | sumh | firsth | lasth | maxtemp | mintemp 
----------+------------------------------+------+------+--------+-------+---------+---------
 NYC      | Sun Dec 02 16:00:00 2018 PST |  110 |   75 |     45 |    30 |      65 |      45
 NYC      | Fri Nov 02 17:00:00 2018 PDT |      |      |        |       |         |        
 NYC      | Thu Nov 01 17:00:00 2018 PDT |   30 |   25 |     10 |       |      20 |      10
 NYC      | Wed Oct 31 17:00:00 2018 PDT |  325 |  200 |     30 |    50 |      85 |      45
 NYC      | Mon Jan 01 16:00:00 2018 PST |   65 |   45 |     45 |    45 |      65 |      65
 SFO      | Sun Dec 02 16:00:00 2018 PST |  120 |   90 |     45 |    45 |      65 |      55
 SFO      | Mon Jan 01 16:00:00 2018 PST |   65 |   45 |     45 |    45 |      65 |      65
 SFO      | Sun Dec 31 16:00:00 2017 PST |   55 |   45 |     45 |    45 |      55 |      55
 por      | Mon Jan 01 16:00:00 2018 PST |  100 |  100 |    100 |   100 |     100 |     100

ALTER MATERIALIZED VIEW mat_m1 SET (timescaledb.materialized_only=true);
SELECT m1.location, m1.timec, sumt, sumh, firsth, lasth, maxtemp, mintemp
FROM mat_m1 m1 RIGHT JOIN mat_m2 m2
ON (m1.location = m2.location
AND m1.timec = m2.timec)
ORDER BY m1.location COLLATE "C" NULLS LAST, m1.timec DESC NULLS LAST, firsth NULLS LAST,
         lasth NULLS LAST, mintemp NULLS LAST, maxtemp NULLS LAST
LIMIT 10;
 location |            timec             | sumt | sumh | firsth | lasth | maxtemp | mintemp 
----------+------------------------------+------+------+--------+-------+---------+---------
 NYC      | Mon Jan 01 16:00:00 2018 PST |   65 |   45 |     45 |    45 |      65 |      65
 SFO      | Mon Jan 01 16:00:00 2018 PST |   65 |   45 |     45 |    45 |      65 |      65
 SFO      | Sun Dec 31 16:00:00 2017 PST |   55 |   45 |     45 |    45 |      55 |      55
 por      | Mon Jan 01 16:00:00 2018 PST |  100 |  100 |    100 |   100 |     100 |     100
          |                              |      |      |     10 |       |      20 |      10
          |                              |      |      |     30 |    50 |      85 |      45
          |                              |      |      |     45 |    30 |      65 |      45
          |                              |      |      |     45 |    45 |      65 |      55
          |                              |      |      |        |       |         |        

ROLLBACK;
-----
-- Tests with time_bucket and offset/origin
-----
CREATE TABLE temperature (
  time timestamptz NOT NULL,
  value float
);
SELECT create_hypertable('temperature', 'time');
    create_hypertable     
--------------------------
 (4,public,temperature,t)

INSERT INTO temperature VALUES ('2000-01-01 01:00:00'::timestamptz, 5);
CREATE TABLE temperature_wo_tz (
  time timestamp NOT NULL,
  value float
);
SELECT create_hypertable('temperature_wo_tz', 'time');
psql:include/cagg_query_common.sql:316: WARNING:  column type "timestamp without time zone" used for "time" does not follow best practices
       create_hypertable        
--------------------------------
 (5,public,temperature_wo_tz,t)

INSERT INTO temperature_wo_tz VALUES ('2000-01-01 01:00:00'::timestamp, 5);
CREATE TABLE temperature_date (
  time date NOT NULL,
  value float
);
SELECT create_hypertable('temperature_date', 'time');
       create_hypertable       
-------------------------------
 (6,public,temperature_date,t)

INSERT INTO temperature_date VALUES ('2000-01-01 01:00:00'::timestamp, 5);
-- Integer based tables
CREATE TABLE table_smallint (
  time smallint,
  data smallint
);
CREATE TABLE table_int (
  time int,
  data int
);
CREATE TABLE table_bigint (
  time bigint,
  data bigint
);
SELECT create_hypertable('table_smallint', 'time', chunk_time_interval => 10);
      create_hypertable      
-----------------------------
 (7,public,table_smallint,t)

SELECT create_hypertable('table_int', 'time', chunk_time_interval => 10);
   create_hypertable    
------------------------
 (8,public,table_int,t)

SELECT create_hypertable('table_bigint', 'time', chunk_time_interval => 10);
     create_hypertable     
---------------------------
 (9,public,table_bigint,t)

CREATE OR REPLACE FUNCTION integer_now_smallint() returns smallint LANGUAGE SQL STABLE as $$ SELECT coalesce(max(time), 0) FROM table_smallint $$;
CREATE OR REPLACE FUNCTION integer_now_int() returns int LANGUAGE SQL STABLE as $$ SELECT coalesce(max(time), 0) FROM table_int $$;
CREATE OR REPLACE FUNCTION integer_now_bigint() returns bigint LANGUAGE SQL STABLE as $$ SELECT coalesce(max(time), 0) FROM table_bigint $$;
SELECT set_integer_now_func('table_smallint', 'integer_now_smallint');
 set_integer_now_func 
----------------------
 

SELECT set_integer_now_func('table_int', 'integer_now_int');
 set_integer_now_func 
----------------------
 

SELECT set_integer_now_func('table_bigint', 'integer_now_bigint');
 set_integer_now_func 
----------------------
 

INSERT INTO table_smallint VALUES(1,2);
INSERT INTO table_int VALUES(1,2);
INSERT INTO table_bigint VALUES(1,2);
CREATE VIEW caggs_info AS
SELECT user_view_schema, user_view_name, bucket_func, bucket_width, bucket_origin, bucket_offset, bucket_timezone, bucket_fixed_width
FROM _timescaledb_catalog.continuous_aggs_bucket_function NATURAL JOIN _timescaledb_catalog.continuous_agg;
---
-- Tests with CAgg creation
---
CREATE MATERIALIZED VIEW cagg_4_hours
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:372: NOTICE:  refreshing continuous aggregate "cagg_4_hours"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours';
 user_view_schema | user_view_name |                      bucket_func                      | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+----------------+-------------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_4_hours   | public.time_bucket(interval,timestamp with time zone) | @ 4 hours    |               |               |                 | t

DROP MATERIALIZED VIEW cagg_4_hours;
psql:include/cagg_query_common.sql:374: NOTICE:  drop cascades to table _timescaledb_internal._hyper_10_14_chunk
CREATE MATERIALIZED VIEW cagg_4_hours_offset
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, '30m'::interval), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:380: NOTICE:  refreshing continuous aggregate "cagg_4_hours_offset"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_offset';
 user_view_schema |   user_view_name    |                          bucket_func                           | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+---------------------+----------------------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_offset | public.time_bucket(interval,timestamp with time zone,interval) | @ 4 hours    |               | @ 30 mins     |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_offset;
psql:include/cagg_query_common.sql:382: NOTICE:  drop cascades to table _timescaledb_internal._hyper_11_15_chunk
CREATE MATERIALIZED VIEW cagg_4_hours_offset2
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, "offset"=>'30m'::interval), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:388: NOTICE:  refreshing continuous aggregate "cagg_4_hours_offset2"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_offset2';
 user_view_schema |    user_view_name    |                          bucket_func                           | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+----------------------+----------------------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_offset2 | public.time_bucket(interval,timestamp with time zone,interval) | @ 4 hours    |               | @ 30 mins     |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_offset2;
psql:include/cagg_query_common.sql:390: NOTICE:  drop cascades to table _timescaledb_internal._hyper_12_16_chunk
-- Variable buckets (timezone is provided) with offset
CREATE MATERIALIZED VIEW cagg_4_hours_offset_ts
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, "offset"=>'30m'::interval, timezone=>'UTC'), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:397: NOTICE:  refreshing continuous aggregate "cagg_4_hours_offset_ts"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_offset_ts';
 user_view_schema |     user_view_name     |                                               bucket_func                                               | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+------------------------+---------------------------------------------------------------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_offset_ts | public.time_bucket(interval,timestamp with time zone,pg_catalog.text,timestamp with time zone,interval) | @ 4 hours    |               | @ 30 mins     | UTC             | f

DROP MATERIALIZED VIEW cagg_4_hours_offset_ts;
psql:include/cagg_query_common.sql:399: NOTICE:  drop cascades to table _timescaledb_internal._hyper_13_17_chunk
CREATE MATERIALIZED VIEW cagg_4_hours_origin
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, '2000-01-01 01:00:00 PST'::timestamptz), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:405: NOTICE:  refreshing continuous aggregate "cagg_4_hours_origin"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_origin';
 user_view_schema |   user_view_name    |                                  bucket_func                                   | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+---------------------+--------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_origin | public.time_bucket(interval,timestamp with time zone,timestamp with time zone) | @ 4 hours    | Sat Jan 01 01:00:00 2000 PST |               |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_origin;
psql:include/cagg_query_common.sql:407: NOTICE:  drop cascades to table _timescaledb_internal._hyper_14_18_chunk
-- Using named parameter
CREATE MATERIALIZED VIEW cagg_4_hours_origin2
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, origin=>'2000-01-01 01:00:00 PST'::timestamptz), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:414: NOTICE:  refreshing continuous aggregate "cagg_4_hours_origin2"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_origin2';
 user_view_schema |    user_view_name    |                                  bucket_func                                   | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+----------------------+--------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_origin2 | public.time_bucket(interval,timestamp with time zone,timestamp with time zone) | @ 4 hours    | Sat Jan 01 01:00:00 2000 PST |               |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_origin2;
psql:include/cagg_query_common.sql:416: NOTICE:  drop cascades to table _timescaledb_internal._hyper_15_19_chunk
-- Variable buckets (timezone is provided) with origin
CREATE MATERIALIZED VIEW cagg_4_hours_origin_ts
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, origin=>'2000-01-01 01:00:00 PST'::timestamptz, timezone=>'UTC'), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:423: NOTICE:  refreshing continuous aggregate "cagg_4_hours_origin_ts"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_origin_ts';
 user_view_schema |     user_view_name     |                                               bucket_func                                               | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+------------------------+---------------------------------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_origin_ts | public.time_bucket(interval,timestamp with time zone,pg_catalog.text,timestamp with time zone,interval) | @ 4 hours    | Sat Jan 01 01:00:00 2000 PST |               | UTC             | f

DROP MATERIALIZED VIEW cagg_4_hours_origin_ts;
psql:include/cagg_query_common.sql:425: NOTICE:  drop cascades to table _timescaledb_internal._hyper_16_20_chunk
-- Without named parameter
CREATE MATERIALIZED VIEW cagg_4_hours_origin_ts2
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, 'UTC', '2000-01-01 01:00:00 PST'::timestamptz), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:432: NOTICE:  refreshing continuous aggregate "cagg_4_hours_origin_ts2"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_origin_ts2';
 user_view_schema |     user_view_name      |                                               bucket_func                                               | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+-------------------------+---------------------------------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_origin_ts2 | public.time_bucket(interval,timestamp with time zone,pg_catalog.text,timestamp with time zone,interval) | @ 4 hours    | Sat Jan 01 01:00:00 2000 PST |               | UTC             | f

DROP MATERIALIZED VIEW cagg_4_hours_origin_ts2;
psql:include/cagg_query_common.sql:434: NOTICE:  drop cascades to table _timescaledb_internal._hyper_17_21_chunk
-- Timestamp based CAggs
CREATE MATERIALIZED VIEW cagg_4_hours_wo_tz
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time), max(value)
    FROM temperature_wo_tz
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:441: NOTICE:  refreshing continuous aggregate "cagg_4_hours_wo_tz"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_wo_tz';
 user_view_schema |   user_view_name   |                       bucket_func                        | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+--------------------+----------------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_wo_tz | public.time_bucket(interval,timestamp without time zone) | @ 4 hours    |               |               |                 | t

CREATE MATERIALIZED VIEW cagg_4_hours_origin_ts_wo_tz
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, '2000-01-01 01:00:00'::timestamp), max(value)
    FROM temperature_wo_tz
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:448: NOTICE:  refreshing continuous aggregate "cagg_4_hours_origin_ts_wo_tz"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_origin_ts_wo_tz';
 user_view_schema |        user_view_name        |                                     bucket_func                                      | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+------------------------------+--------------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_origin_ts_wo_tz | public.time_bucket(interval,timestamp without time zone,timestamp without time zone) | @ 4 hours    | Fri Dec 31 17:00:00 1999 PST |               |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_origin_ts_wo_tz;
psql:include/cagg_query_common.sql:450: NOTICE:  drop cascades to table _timescaledb_internal._hyper_19_23_chunk
-- Variable buckets (timezone is provided) with origin
CREATE MATERIALIZED VIEW cagg_4_hours_origin_ts_wo_tz2
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, origin=>'2000-01-01 01:00:00'::timestamp), max(value)
    FROM temperature_wo_tz
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:457: NOTICE:  refreshing continuous aggregate "cagg_4_hours_origin_ts_wo_tz2"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_origin_ts_wo_tz2';
 user_view_schema |        user_view_name         |                                     bucket_func                                      | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+-------------------------------+--------------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_origin_ts_wo_tz2 | public.time_bucket(interval,timestamp without time zone,timestamp without time zone) | @ 4 hours    | Fri Dec 31 17:00:00 1999 PST |               |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_origin_ts_wo_tz2;
psql:include/cagg_query_common.sql:459: NOTICE:  drop cascades to table _timescaledb_internal._hyper_20_24_chunk
CREATE MATERIALIZED VIEW cagg_4_hours_offset_wo_tz
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, "offset"=>'30m'::interval), max(value)
    FROM temperature_wo_tz
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:465: NOTICE:  refreshing continuous aggregate "cagg_4_hours_offset_wo_tz"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_offset_wo_tz';
 user_view_schema |      user_view_name       |                            bucket_func                            | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+---------------------------+-------------------------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_offset_wo_tz | public.time_bucket(interval,timestamp without time zone,interval) | @ 4 hours    |               | @ 30 mins     |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_offset_wo_tz;
psql:include/cagg_query_common.sql:467: NOTICE:  drop cascades to table _timescaledb_internal._hyper_21_25_chunk
DROP MATERIALIZED VIEW cagg_4_hours_wo_tz;
psql:include/cagg_query_common.sql:468: NOTICE:  drop cascades to table _timescaledb_internal._hyper_18_22_chunk
-- Date based CAggs
CREATE MATERIALIZED VIEW cagg_4_hours_date
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 days', time), max(value)
    FROM temperature_date
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:475: NOTICE:  refreshing continuous aggregate "cagg_4_hours_date"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_date';
 user_view_schema |  user_view_name   |                 bucket_func                  | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+-------------------+----------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_date | public.time_bucket(interval,pg_catalog.date) | @ 4 days     |               |               |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_date;
psql:include/cagg_query_common.sql:477: NOTICE:  drop cascades to table _timescaledb_internal._hyper_22_26_chunk
CREATE MATERIALIZED VIEW cagg_4_hours_date_origin
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 days', time, '2000-01-01'::date), max(value)
    FROM temperature_date
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:483: NOTICE:  refreshing continuous aggregate "cagg_4_hours_date_origin"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_date_origin';
 user_view_schema |      user_view_name      |                         bucket_func                          | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+--------------------------+--------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_date_origin | public.time_bucket(interval,pg_catalog.date,pg_catalog.date) | @ 4 days     | Sat Jan 01 00:00:00 2000 PST |               |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_date_origin;
psql:include/cagg_query_common.sql:485: NOTICE:  drop cascades to table _timescaledb_internal._hyper_23_27_chunk
CREATE MATERIALIZED VIEW cagg_4_hours_date_origin2
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 days', time, origin=>'2000-01-01'::date), max(value)
    FROM temperature_date
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:491: NOTICE:  refreshing continuous aggregate "cagg_4_hours_date_origin2"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_date_origin2';
 user_view_schema |      user_view_name       |                         bucket_func                          | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+---------------------------+--------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_date_origin2 | public.time_bucket(interval,pg_catalog.date,pg_catalog.date) | @ 4 days     | Sat Jan 01 00:00:00 2000 PST |               |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_date_origin2;
psql:include/cagg_query_common.sql:493: NOTICE:  drop cascades to table _timescaledb_internal._hyper_24_28_chunk
CREATE MATERIALIZED VIEW cagg_4_hours_date_offset
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 days', time, "offset"=>'30m'::interval), max(value)
    FROM temperature_date
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:499: NOTICE:  refreshing continuous aggregate "cagg_4_hours_date_offset"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_4_hours_date_offset';
 user_view_schema |      user_view_name      |                      bucket_func                      | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+--------------------------+-------------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_4_hours_date_offset | public.time_bucket(interval,pg_catalog.date,interval) | @ 4 days     |               | @ 30 mins     |                 | t

DROP MATERIALIZED VIEW cagg_4_hours_date_offset;
psql:include/cagg_query_common.sql:501: NOTICE:  drop cascades to table _timescaledb_internal._hyper_25_29_chunk
-- Integer based CAggs
CREATE MATERIALIZED VIEW cagg_smallint
    WITH (timescaledb.continuous, timescaledb.materialized_only=true)
    AS SELECT time_bucket('2', time), SUM(data) as value
        FROM table_smallint
        GROUP BY 1;
psql:include/cagg_query_common.sql:508: NOTICE:  refreshing continuous aggregate "cagg_smallint"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_smallint';
 user_view_schema | user_view_name |              bucket_func              | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+----------------+---------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_smallint  | public.time_bucket(smallint,smallint) | 2            |               |               |                 | t

DROP MATERIALIZED VIEW cagg_smallint;
psql:include/cagg_query_common.sql:510: NOTICE:  drop cascades to table _timescaledb_internal._hyper_26_30_chunk
CREATE MATERIALIZED VIEW cagg_smallint_offset
    WITH (timescaledb.continuous, timescaledb.materialized_only=true)
    AS SELECT time_bucket('2', time, "offset"=>1::smallint), SUM(data) as value
        FROM table_smallint
        GROUP BY 1;
psql:include/cagg_query_common.sql:516: NOTICE:  refreshing continuous aggregate "cagg_smallint_offset"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_smallint_offset';
 user_view_schema |    user_view_name    |                  bucket_func                   | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+----------------------+------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_smallint_offset | public.time_bucket(smallint,smallint,smallint) | 2            |               | 1             |                 | t

DROP MATERIALIZED VIEW cagg_smallint_offset;
psql:include/cagg_query_common.sql:518: NOTICE:  drop cascades to table _timescaledb_internal._hyper_27_31_chunk
CREATE MATERIALIZED VIEW cagg_int
    WITH (timescaledb.continuous, timescaledb.materialized_only=true)
    AS SELECT time_bucket('2', time), SUM(data) as value
        FROM table_int
        GROUP BY 1;
psql:include/cagg_query_common.sql:524: NOTICE:  refreshing continuous aggregate "cagg_int"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_int';
 user_view_schema | user_view_name |             bucket_func             | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+----------------+-------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_int       | public.time_bucket(integer,integer) | 2            |               |               |                 | t

DROP MATERIALIZED VIEW cagg_int;
psql:include/cagg_query_common.sql:526: NOTICE:  drop cascades to table _timescaledb_internal._hyper_28_32_chunk
CREATE MATERIALIZED VIEW cagg_int_offset
    WITH (timescaledb.continuous, timescaledb.materialized_only=true)
    AS SELECT time_bucket('2', time, "offset"=>1::int), SUM(data) as value
        FROM table_int
        GROUP BY 1;
psql:include/cagg_query_common.sql:532: NOTICE:  refreshing continuous aggregate "cagg_int_offset"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_int_offset';
 user_view_schema | user_view_name  |                 bucket_func                 | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+-----------------+---------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_int_offset | public.time_bucket(integer,integer,integer) | 2            |               | 1             |                 | t

DROP MATERIALIZED VIEW cagg_int_offset;
psql:include/cagg_query_common.sql:534: NOTICE:  drop cascades to table _timescaledb_internal._hyper_29_33_chunk
CREATE MATERIALIZED VIEW cagg_bigint
    WITH (timescaledb.continuous, timescaledb.materialized_only=true)
    AS SELECT time_bucket('2', time), SUM(data) as value
        FROM table_bigint
        GROUP BY 1 WITH NO DATA;
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_bigint';
 user_view_schema | user_view_name |            bucket_func            | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+----------------+-----------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_bigint    | public.time_bucket(bigint,bigint) | 2            |               |               |                 | t

DROP MATERIALIZED VIEW cagg_bigint;
CREATE MATERIALIZED VIEW cagg_bigint_offset
    WITH (timescaledb.continuous, timescaledb.materialized_only=true)
    AS SELECT time_bucket('2', time, "offset"=>1::bigint), SUM(data) as value
        FROM table_bigint
        GROUP BY 1 WITH NO DATA;
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_bigint_offset';
 user_view_schema |   user_view_name   |               bucket_func                | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+--------------------+------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_bigint_offset | public.time_bucket(bigint,bigint,bigint) | 2            |               | 1             |                 | t

DROP MATERIALIZED VIEW cagg_bigint_offset;
-- Without named parameter
CREATE MATERIALIZED VIEW cagg_bigint_offset2
    WITH (timescaledb.continuous, timescaledb.materialized_only=true)
    AS SELECT time_bucket('2', time, 1::bigint), SUM(data) as value
        FROM table_bigint
        GROUP BY 1 WITH NO DATA;
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_bigint_offset2';
 user_view_schema |   user_view_name    |               bucket_func                | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+---------------------+------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_bigint_offset2 | public.time_bucket(bigint,bigint,bigint) | 2            |               | 1             |                 | t

-- mess with the bucket_func signature to make sure it will raise an exception
SET ROLE :ROLE_SUPERUSER;
\set ON_ERROR_STOP 0
BEGIN;
UPDATE _timescaledb_catalog.continuous_aggs_bucket_function SET bucket_func = 'func_does_not_exist()';
-- should error because function does not exist
CALL refresh_continuous_aggregate('cagg_bigint_offset2', NULL, NULL);
psql:include/cagg_query_common.sql:566: ERROR:  function "func_does_not_exist()" does not exist
ROLLBACK;
\set ON_ERROR_STOP 1
SET ROLE :ROLE_DEFAULT_PERM_USER;
DROP MATERIALIZED VIEW cagg_bigint_offset2;
-- Test invalid bucket definitions
\set ON_ERROR_STOP 0
-- Offset and origin at the same time is not allowed (function does not exists)
CREATE MATERIALIZED VIEW cagg_4_hours_offset_and_origin
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, "offset"=>'30m'::interval, origin=>'2000-01-01 01:00:00 PST'::timestamptz), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:580: ERROR:  function time_bucket(unknown, timestamp with time zone, offset => interval, origin => timestamp with time zone) does not exist at character 140
-- Offset and origin at the same time is not allowed (function does exists but invalid parameter combination)
CREATE MATERIALIZED VIEW cagg_4_hours_offset_and_origin
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, "offset"=>'30m'::interval, origin=>'2000-01-01 01:00:00 PST'::timestamptz, timezone=>'UTC'), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:587: ERROR:  using offset and origin in a time_bucket function at the same time is not supported
\set ON_ERROR_STOP 1
---
-- Tests with CAgg processing
---
-- Check used timezone
SHOW timezone;
 TimeZone 
----------
 PST8PDT

-- Populate it
INSERT INTO temperature
  SELECT time, 5
    FROM generate_series('2000-01-01 01:00:00 PST'::timestamptz,
                         '2000-01-01 23:59:59 PST','1m') time;
INSERT INTO temperature
  SELECT time, 6
    FROM generate_series('2020-01-01 00:00:00 PST'::timestamptz,
                         '2020-01-01 23:59:59 PST','1m') time;
-- Create CAggs
CREATE MATERIALIZED VIEW cagg_4_hours
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:613: NOTICE:  refreshing continuous aggregate "cagg_4_hours"
CREATE MATERIALIZED VIEW cagg_4_hours_offset
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, '30m'::interval), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:619: NOTICE:  refreshing continuous aggregate "cagg_4_hours_offset"
-- Align origin with first value
CREATE MATERIALIZED VIEW cagg_4_hours_origin
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('4 hour', time, '2000-01-01 01:00:00 PST'::timestamptz), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:626: NOTICE:  refreshing continuous aggregate "cagg_4_hours_origin"
-- Query the CAggs and check that all buckets are materialized
SELECT time_bucket('4 hour', time), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 00:00:00 2000 PST |   5
 Sat Jan 01 04:00:00 2000 PST |   5
 Sat Jan 01 08:00:00 2000 PST |   5
 Sat Jan 01 12:00:00 2000 PST |   5
 Sat Jan 01 16:00:00 2000 PST |   5
 Sat Jan 01 20:00:00 2000 PST |   5
 Wed Jan 01 00:00:00 2020 PST |   6
 Wed Jan 01 04:00:00 2020 PST |   6
 Wed Jan 01 08:00:00 2020 PST |   6
 Wed Jan 01 12:00:00 2020 PST |   6
 Wed Jan 01 16:00:00 2020 PST |   6
 Wed Jan 01 20:00:00 2020 PST |   6

SELECT * FROM cagg_4_hours;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 00:00:00 2000 PST |   5
 Sat Jan 01 04:00:00 2000 PST |   5
 Sat Jan 01 08:00:00 2000 PST |   5
 Sat Jan 01 12:00:00 2000 PST |   5
 Sat Jan 01 16:00:00 2000 PST |   5
 Sat Jan 01 20:00:00 2000 PST |   5
 Wed Jan 01 00:00:00 2020 PST |   6
 Wed Jan 01 04:00:00 2020 PST |   6
 Wed Jan 01 08:00:00 2020 PST |   6
 Wed Jan 01 12:00:00 2020 PST |   6
 Wed Jan 01 16:00:00 2020 PST |   6
 Wed Jan 01 20:00:00 2020 PST |   6

ALTER MATERIALIZED VIEW cagg_4_hours SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 00:00:00 2000 PST |   5
 Sat Jan 01 04:00:00 2000 PST |   5
 Sat Jan 01 08:00:00 2000 PST |   5
 Sat Jan 01 12:00:00 2000 PST |   5
 Sat Jan 01 16:00:00 2000 PST |   5
 Sat Jan 01 20:00:00 2000 PST |   5
 Wed Jan 01 00:00:00 2020 PST |   6
 Wed Jan 01 04:00:00 2020 PST |   6
 Wed Jan 01 08:00:00 2020 PST |   6
 Wed Jan 01 12:00:00 2020 PST |   6
 Wed Jan 01 16:00:00 2020 PST |   6
 Wed Jan 01 20:00:00 2020 PST |   6

SELECT time_bucket('4 hour', time, '30m'::interval), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 00:30:00 2000 PST |   5
 Sat Jan 01 04:30:00 2000 PST |   5
 Sat Jan 01 08:30:00 2000 PST |   5
 Sat Jan 01 12:30:00 2000 PST |   5
 Sat Jan 01 16:30:00 2000 PST |   5
 Sat Jan 01 20:30:00 2000 PST |   5
 Tue Dec 31 20:30:00 2019 PST |   6
 Wed Jan 01 00:30:00 2020 PST |   6
 Wed Jan 01 04:30:00 2020 PST |   6
 Wed Jan 01 08:30:00 2020 PST |   6
 Wed Jan 01 12:30:00 2020 PST |   6
 Wed Jan 01 16:30:00 2020 PST |   6
 Wed Jan 01 20:30:00 2020 PST |   6

SELECT * FROM cagg_4_hours_offset;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 00:30:00 2000 PST |   5
 Sat Jan 01 04:30:00 2000 PST |   5
 Sat Jan 01 08:30:00 2000 PST |   5
 Sat Jan 01 12:30:00 2000 PST |   5
 Sat Jan 01 16:30:00 2000 PST |   5
 Sat Jan 01 20:30:00 2000 PST |   5
 Tue Dec 31 20:30:00 2019 PST |   6
 Wed Jan 01 00:30:00 2020 PST |   6
 Wed Jan 01 04:30:00 2020 PST |   6
 Wed Jan 01 08:30:00 2020 PST |   6
 Wed Jan 01 12:30:00 2020 PST |   6
 Wed Jan 01 16:30:00 2020 PST |   6
 Wed Jan 01 20:30:00 2020 PST |   6

ALTER MATERIALIZED VIEW cagg_4_hours_offset SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours_offset;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 00:30:00 2000 PST |   5
 Sat Jan 01 04:30:00 2000 PST |   5
 Sat Jan 01 08:30:00 2000 PST |   5
 Sat Jan 01 12:30:00 2000 PST |   5
 Sat Jan 01 16:30:00 2000 PST |   5
 Sat Jan 01 20:30:00 2000 PST |   5
 Tue Dec 31 20:30:00 2019 PST |   6
 Wed Jan 01 00:30:00 2020 PST |   6
 Wed Jan 01 04:30:00 2020 PST |   6
 Wed Jan 01 08:30:00 2020 PST |   6
 Wed Jan 01 12:30:00 2020 PST |   6
 Wed Jan 01 16:30:00 2020 PST |   6
 Wed Jan 01 20:30:00 2020 PST |   6

SELECT time_bucket('4 hour', time, '2000-01-01 01:00:00 PST'::timestamptz), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 01:00:00 2000 PST |   5
 Sat Jan 01 05:00:00 2000 PST |   5
 Sat Jan 01 09:00:00 2000 PST |   5
 Sat Jan 01 13:00:00 2000 PST |   5
 Sat Jan 01 17:00:00 2000 PST |   5
 Sat Jan 01 21:00:00 2000 PST |   5
 Tue Dec 31 21:00:00 2019 PST |   6
 Wed Jan 01 01:00:00 2020 PST |   6
 Wed Jan 01 05:00:00 2020 PST |   6
 Wed Jan 01 09:00:00 2020 PST |   6
 Wed Jan 01 13:00:00 2020 PST |   6
 Wed Jan 01 17:00:00 2020 PST |   6
 Wed Jan 01 21:00:00 2020 PST |   6

SELECT * FROM cagg_4_hours_origin;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 01:00:00 2000 PST |   5
 Sat Jan 01 05:00:00 2000 PST |   5
 Sat Jan 01 09:00:00 2000 PST |   5
 Sat Jan 01 13:00:00 2000 PST |   5
 Sat Jan 01 17:00:00 2000 PST |   5
 Sat Jan 01 21:00:00 2000 PST |   5
 Tue Dec 31 21:00:00 2019 PST |   6
 Wed Jan 01 01:00:00 2020 PST |   6
 Wed Jan 01 05:00:00 2020 PST |   6
 Wed Jan 01 09:00:00 2020 PST |   6
 Wed Jan 01 13:00:00 2020 PST |   6
 Wed Jan 01 17:00:00 2020 PST |   6
 Wed Jan 01 21:00:00 2020 PST |   6

ALTER MATERIALIZED VIEW cagg_4_hours_origin SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours_origin;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 01:00:00 2000 PST |   5
 Sat Jan 01 05:00:00 2000 PST |   5
 Sat Jan 01 09:00:00 2000 PST |   5
 Sat Jan 01 13:00:00 2000 PST |   5
 Sat Jan 01 17:00:00 2000 PST |   5
 Sat Jan 01 21:00:00 2000 PST |   5
 Tue Dec 31 21:00:00 2019 PST |   6
 Wed Jan 01 01:00:00 2020 PST |   6
 Wed Jan 01 05:00:00 2020 PST |   6
 Wed Jan 01 09:00:00 2020 PST |   6
 Wed Jan 01 13:00:00 2020 PST |   6
 Wed Jan 01 17:00:00 2020 PST |   6
 Wed Jan 01 21:00:00 2020 PST |   6

-- Update the last bucket and re-materialize
INSERT INTO temperature values('2020-01-01 23:55:00 PST', 10);
CALL refresh_continuous_aggregate('cagg_4_hours', NULL, NULL);
CALL refresh_continuous_aggregate('cagg_4_hours_offset', NULL, NULL);
CALL refresh_continuous_aggregate('cagg_4_hours_origin', NULL, NULL);
SELECT * FROM cagg_4_hours;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 00:00:00 2000 PST |   5
 Sat Jan 01 04:00:00 2000 PST |   5
 Sat Jan 01 08:00:00 2000 PST |   5
 Sat Jan 01 12:00:00 2000 PST |   5
 Sat Jan 01 16:00:00 2000 PST |   5
 Sat Jan 01 20:00:00 2000 PST |   5
 Wed Jan 01 00:00:00 2020 PST |   6
 Wed Jan 01 04:00:00 2020 PST |   6
 Wed Jan 01 08:00:00 2020 PST |   6
 Wed Jan 01 12:00:00 2020 PST |   6
 Wed Jan 01 16:00:00 2020 PST |   6
 Wed Jan 01 20:00:00 2020 PST |  10

SELECT * FROM cagg_4_hours_offset;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 00:30:00 2000 PST |   5
 Sat Jan 01 04:30:00 2000 PST |   5
 Sat Jan 01 08:30:00 2000 PST |   5
 Sat Jan 01 12:30:00 2000 PST |   5
 Sat Jan 01 16:30:00 2000 PST |   5
 Sat Jan 01 20:30:00 2000 PST |   5
 Tue Dec 31 20:30:00 2019 PST |   6
 Wed Jan 01 00:30:00 2020 PST |   6
 Wed Jan 01 04:30:00 2020 PST |   6
 Wed Jan 01 08:30:00 2020 PST |   6
 Wed Jan 01 12:30:00 2020 PST |   6
 Wed Jan 01 16:30:00 2020 PST |   6
 Wed Jan 01 20:30:00 2020 PST |  10

SELECT * FROM cagg_4_hours_origin;
         time_bucket          | max 
------------------------------+-----
 Sat Jan 01 01:00:00 2000 PST |   5
 Sat Jan 01 05:00:00 2000 PST |   5
 Sat Jan 01 09:00:00 2000 PST |   5
 Sat Jan 01 13:00:00 2000 PST |   5
 Sat Jan 01 17:00:00 2000 PST |   5
 Sat Jan 01 21:00:00 2000 PST |   5
 Tue Dec 31 21:00:00 2019 PST |   6
 Wed Jan 01 01:00:00 2020 PST |   6
 Wed Jan 01 05:00:00 2020 PST |   6
 Wed Jan 01 09:00:00 2020 PST |   6
 Wed Jan 01 13:00:00 2020 PST |   6
 Wed Jan 01 17:00:00 2020 PST |   6
 Wed Jan 01 21:00:00 2020 PST |  10

-- Check the real-time functionality
ALTER MATERIALIZED VIEW cagg_4_hours SET (timescaledb.materialized_only=false);
ALTER MATERIALIZED VIEW cagg_4_hours_offset SET (timescaledb.materialized_only=false);
ALTER MATERIALIZED VIEW cagg_4_hours_origin SET (timescaledb.materialized_only=false);
-- Check watermarks
SELECT continuous_agg.user_view_name, continuous_aggs_watermark.watermark, _timescaledb_functions.to_timestamp(watermark)
  FROM _timescaledb_catalog.continuous_aggs_watermark
  JOIN _timescaledb_catalog.continuous_agg USING (mat_hypertable_id)
WHERE user_view_name LIKE 'cagg_4_hours%'
ORDER BY mat_hypertable_id, watermark;
   user_view_name    |    watermark     |         to_timestamp         
---------------------+------------------+------------------------------
 cagg_4_hours        | 1577952000000000 | Thu Jan 02 00:00:00 2020 PST
 cagg_4_hours_offset | 1577953800000000 | Thu Jan 02 00:30:00 2020 PST
 cagg_4_hours_origin | 1577955600000000 | Thu Jan 02 01:00:00 2020 PST

-- Insert new data
INSERT INTO temperature values('2020-01-02 00:10:00 PST', 2222);
INSERT INTO temperature values('2020-01-02 05:35:00 PST', 5555);
INSERT INTO temperature values('2020-01-02 09:05:00 PST', 8888);
-- Watermark is at Thu Jan 02 00:00:00 2020 PST - all inserted tuples should be seen
SELECT * FROM cagg_4_hours;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:00:00 2000 PST |    5
 Sat Jan 01 04:00:00 2000 PST |    5
 Sat Jan 01 08:00:00 2000 PST |    5
 Sat Jan 01 12:00:00 2000 PST |    5
 Sat Jan 01 16:00:00 2000 PST |    5
 Sat Jan 01 20:00:00 2000 PST |    5
 Wed Jan 01 00:00:00 2020 PST |    6
 Wed Jan 01 04:00:00 2020 PST |    6
 Wed Jan 01 08:00:00 2020 PST |    6
 Wed Jan 01 12:00:00 2020 PST |    6
 Wed Jan 01 16:00:00 2020 PST |    6
 Wed Jan 01 20:00:00 2020 PST |   10
 Thu Jan 02 00:00:00 2020 PST | 2222
 Thu Jan 02 04:00:00 2020 PST | 5555
 Thu Jan 02 08:00:00 2020 PST | 8888

-- Watermark is at Thu Jan 02 00:30:00 2020 PST - only two inserted tuples should be seen
SELECT * FROM cagg_4_hours_offset;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:30:00 2000 PST |    5
 Sat Jan 01 04:30:00 2000 PST |    5
 Sat Jan 01 08:30:00 2000 PST |    5
 Sat Jan 01 12:30:00 2000 PST |    5
 Sat Jan 01 16:30:00 2000 PST |    5
 Sat Jan 01 20:30:00 2000 PST |    5
 Tue Dec 31 20:30:00 2019 PST |    6
 Wed Jan 01 00:30:00 2020 PST |    6
 Wed Jan 01 04:30:00 2020 PST |    6
 Wed Jan 01 08:30:00 2020 PST |    6
 Wed Jan 01 12:30:00 2020 PST |    6
 Wed Jan 01 16:30:00 2020 PST |    6
 Wed Jan 01 20:30:00 2020 PST |   10
 Thu Jan 02 04:30:00 2020 PST | 5555
 Thu Jan 02 08:30:00 2020 PST | 8888

-- Watermark is at Thu Jan 02 01:00:00 2020 PST - only two inserted tuples should be seen
SELECT * FROM cagg_4_hours_origin;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 01:00:00 2000 PST |    5
 Sat Jan 01 05:00:00 2000 PST |    5
 Sat Jan 01 09:00:00 2000 PST |    5
 Sat Jan 01 13:00:00 2000 PST |    5
 Sat Jan 01 17:00:00 2000 PST |    5
 Sat Jan 01 21:00:00 2000 PST |    5
 Tue Dec 31 21:00:00 2019 PST |    6
 Wed Jan 01 01:00:00 2020 PST |    6
 Wed Jan 01 05:00:00 2020 PST |    6
 Wed Jan 01 09:00:00 2020 PST |    6
 Wed Jan 01 13:00:00 2020 PST |    6
 Wed Jan 01 17:00:00 2020 PST |    6
 Wed Jan 01 21:00:00 2020 PST |   10
 Thu Jan 02 05:00:00 2020 PST | 5555
 Thu Jan 02 09:00:00 2020 PST | 8888

-- Update materialized data
SET client_min_messages TO DEBUG1;
CALL refresh_continuous_aggregate('cagg_4_hours', NULL, NULL);
psql:include/cagg_query_common.sql:683: LOG:  statement: CALL refresh_continuous_aggregate('cagg_4_hours', NULL, NULL);
psql:include/cagg_query_common.sql:683: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours" in window [ Thu Jan 02 00:00:00 2020 PST, Thu Jan 02 12:00:00 2020 PST ]
psql:include/cagg_query_common.sql:683: LOG:  inserted 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_33"
CALL refresh_continuous_aggregate('cagg_4_hours_offset', NULL, NULL);
psql:include/cagg_query_common.sql:684: LOG:  statement: CALL refresh_continuous_aggregate('cagg_4_hours_offset', NULL, NULL);
psql:include/cagg_query_common.sql:684: DEBUG:  hypertable 4 existing watermark >= new invalidation threshold 1577995200000000 1577995200000000
psql:include/cagg_query_common.sql:684: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours_offset" in window [ Wed Jan 01 20:30:00 2020 PST, Thu Jan 02 12:30:00 2020 PST ]
psql:include/cagg_query_common.sql:684: LOG:  merged 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_34"
psql:include/cagg_query_common.sql:684: LOG:  deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_34"
CALL refresh_continuous_aggregate('cagg_4_hours_origin', NULL, NULL);
psql:include/cagg_query_common.sql:685: LOG:  statement: CALL refresh_continuous_aggregate('cagg_4_hours_origin', NULL, NULL);
psql:include/cagg_query_common.sql:685: DEBUG:  hypertable 4 existing watermark >= new invalidation threshold 1577995200000000 1577995200000000
psql:include/cagg_query_common.sql:685: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours_origin" in window [ Wed Jan 01 21:00:00 2020 PST, Thu Jan 02 13:00:00 2020 PST ]
psql:include/cagg_query_common.sql:685: LOG:  merged 3 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_35"
psql:include/cagg_query_common.sql:685: LOG:  deleted 0 row(s) from materialization table "_timescaledb_internal._materialized_hypertable_35"
RESET client_min_messages;
psql:include/cagg_query_common.sql:686: LOG:  statement: RESET client_min_messages;
-- Query the CAggs and check that all buckets are materialized
SELECT * FROM cagg_4_hours;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:00:00 2000 PST |    5
 Sat Jan 01 04:00:00 2000 PST |    5
 Sat Jan 01 08:00:00 2000 PST |    5
 Sat Jan 01 12:00:00 2000 PST |    5
 Sat Jan 01 16:00:00 2000 PST |    5
 Sat Jan 01 20:00:00 2000 PST |    5
 Wed Jan 01 00:00:00 2020 PST |    6
 Wed Jan 01 04:00:00 2020 PST |    6
 Wed Jan 01 08:00:00 2020 PST |    6
 Wed Jan 01 12:00:00 2020 PST |    6
 Wed Jan 01 16:00:00 2020 PST |    6
 Wed Jan 01 20:00:00 2020 PST |   10
 Thu Jan 02 00:00:00 2020 PST | 2222
 Thu Jan 02 04:00:00 2020 PST | 5555
 Thu Jan 02 08:00:00 2020 PST | 8888

ALTER MATERIALIZED VIEW cagg_4_hours SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:00:00 2000 PST |    5
 Sat Jan 01 04:00:00 2000 PST |    5
 Sat Jan 01 08:00:00 2000 PST |    5
 Sat Jan 01 12:00:00 2000 PST |    5
 Sat Jan 01 16:00:00 2000 PST |    5
 Sat Jan 01 20:00:00 2000 PST |    5
 Wed Jan 01 00:00:00 2020 PST |    6
 Wed Jan 01 04:00:00 2020 PST |    6
 Wed Jan 01 08:00:00 2020 PST |    6
 Wed Jan 01 12:00:00 2020 PST |    6
 Wed Jan 01 16:00:00 2020 PST |    6
 Wed Jan 01 20:00:00 2020 PST |   10
 Thu Jan 02 00:00:00 2020 PST | 2222
 Thu Jan 02 04:00:00 2020 PST | 5555
 Thu Jan 02 08:00:00 2020 PST | 8888

SELECT time_bucket('4 hour', time), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:00:00 2000 PST |    5
 Sat Jan 01 04:00:00 2000 PST |    5
 Sat Jan 01 08:00:00 2000 PST |    5
 Sat Jan 01 12:00:00 2000 PST |    5
 Sat Jan 01 16:00:00 2000 PST |    5
 Sat Jan 01 20:00:00 2000 PST |    5
 Wed Jan 01 00:00:00 2020 PST |    6
 Wed Jan 01 04:00:00 2020 PST |    6
 Wed Jan 01 08:00:00 2020 PST |    6
 Wed Jan 01 12:00:00 2020 PST |    6
 Wed Jan 01 16:00:00 2020 PST |    6
 Wed Jan 01 20:00:00 2020 PST |   10
 Thu Jan 02 00:00:00 2020 PST | 2222
 Thu Jan 02 04:00:00 2020 PST | 5555
 Thu Jan 02 08:00:00 2020 PST | 8888

SELECT * FROM cagg_4_hours_offset;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:30:00 2000 PST |    5
 Sat Jan 01 04:30:00 2000 PST |    5
 Sat Jan 01 08:30:00 2000 PST |    5
 Sat Jan 01 12:30:00 2000 PST |    5
 Sat Jan 01 16:30:00 2000 PST |    5
 Sat Jan 01 20:30:00 2000 PST |    5
 Tue Dec 31 20:30:00 2019 PST |    6
 Wed Jan 01 00:30:00 2020 PST |    6
 Wed Jan 01 04:30:00 2020 PST |    6
 Wed Jan 01 08:30:00 2020 PST |    6
 Wed Jan 01 12:30:00 2020 PST |    6
 Wed Jan 01 16:30:00 2020 PST |    6
 Wed Jan 01 20:30:00 2020 PST | 2222
 Thu Jan 02 04:30:00 2020 PST | 5555
 Thu Jan 02 08:30:00 2020 PST | 8888

ALTER MATERIALIZED VIEW cagg_4_hours_offset SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours_offset;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:30:00 2000 PST |    5
 Sat Jan 01 04:30:00 2000 PST |    5
 Sat Jan 01 08:30:00 2000 PST |    5
 Sat Jan 01 12:30:00 2000 PST |    5
 Sat Jan 01 16:30:00 2000 PST |    5
 Sat Jan 01 20:30:00 2000 PST |    5
 Tue Dec 31 20:30:00 2019 PST |    6
 Wed Jan 01 00:30:00 2020 PST |    6
 Wed Jan 01 04:30:00 2020 PST |    6
 Wed Jan 01 08:30:00 2020 PST |    6
 Wed Jan 01 12:30:00 2020 PST |    6
 Wed Jan 01 16:30:00 2020 PST |    6
 Wed Jan 01 20:30:00 2020 PST | 2222
 Thu Jan 02 04:30:00 2020 PST | 5555
 Thu Jan 02 08:30:00 2020 PST | 8888

SELECT time_bucket('4 hour', time, '30m'::interval), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:30:00 2000 PST |    5
 Sat Jan 01 04:30:00 2000 PST |    5
 Sat Jan 01 08:30:00 2000 PST |    5
 Sat Jan 01 12:30:00 2000 PST |    5
 Sat Jan 01 16:30:00 2000 PST |    5
 Sat Jan 01 20:30:00 2000 PST |    5
 Tue Dec 31 20:30:00 2019 PST |    6
 Wed Jan 01 00:30:00 2020 PST |    6
 Wed Jan 01 04:30:00 2020 PST |    6
 Wed Jan 01 08:30:00 2020 PST |    6
 Wed Jan 01 12:30:00 2020 PST |    6
 Wed Jan 01 16:30:00 2020 PST |    6
 Wed Jan 01 20:30:00 2020 PST | 2222
 Thu Jan 02 04:30:00 2020 PST | 5555
 Thu Jan 02 08:30:00 2020 PST | 8888

SELECT * FROM cagg_4_hours_origin;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 01:00:00 2000 PST |    5
 Sat Jan 01 05:00:00 2000 PST |    5
 Sat Jan 01 09:00:00 2000 PST |    5
 Sat Jan 01 13:00:00 2000 PST |    5
 Sat Jan 01 17:00:00 2000 PST |    5
 Sat Jan 01 21:00:00 2000 PST |    5
 Tue Dec 31 21:00:00 2019 PST |    6
 Wed Jan 01 01:00:00 2020 PST |    6
 Wed Jan 01 05:00:00 2020 PST |    6
 Wed Jan 01 09:00:00 2020 PST |    6
 Wed Jan 01 13:00:00 2020 PST |    6
 Wed Jan 01 17:00:00 2020 PST |    6
 Wed Jan 01 21:00:00 2020 PST | 2222
 Thu Jan 02 05:00:00 2020 PST | 5555
 Thu Jan 02 09:00:00 2020 PST | 8888

ALTER MATERIALIZED VIEW cagg_4_hours_origin SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours_origin;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 01:00:00 2000 PST |    5
 Sat Jan 01 05:00:00 2000 PST |    5
 Sat Jan 01 09:00:00 2000 PST |    5
 Sat Jan 01 13:00:00 2000 PST |    5
 Sat Jan 01 17:00:00 2000 PST |    5
 Sat Jan 01 21:00:00 2000 PST |    5
 Tue Dec 31 21:00:00 2019 PST |    6
 Wed Jan 01 01:00:00 2020 PST |    6
 Wed Jan 01 05:00:00 2020 PST |    6
 Wed Jan 01 09:00:00 2020 PST |    6
 Wed Jan 01 13:00:00 2020 PST |    6
 Wed Jan 01 17:00:00 2020 PST |    6
 Wed Jan 01 21:00:00 2020 PST | 2222
 Thu Jan 02 05:00:00 2020 PST | 5555
 Thu Jan 02 09:00:00 2020 PST | 8888

SELECT time_bucket('4 hour', time, '2000-01-01 01:00:00 PST'::timestamptz), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 01:00:00 2000 PST |    5
 Sat Jan 01 05:00:00 2000 PST |    5
 Sat Jan 01 09:00:00 2000 PST |    5
 Sat Jan 01 13:00:00 2000 PST |    5
 Sat Jan 01 17:00:00 2000 PST |    5
 Sat Jan 01 21:00:00 2000 PST |    5
 Tue Dec 31 21:00:00 2019 PST |    6
 Wed Jan 01 01:00:00 2020 PST |    6
 Wed Jan 01 05:00:00 2020 PST |    6
 Wed Jan 01 09:00:00 2020 PST |    6
 Wed Jan 01 13:00:00 2020 PST |    6
 Wed Jan 01 17:00:00 2020 PST |    6
 Wed Jan 01 21:00:00 2020 PST | 2222
 Thu Jan 02 05:00:00 2020 PST | 5555
 Thu Jan 02 09:00:00 2020 PST | 8888

-- Test invalidations
TRUNCATE temperature;
CALL refresh_continuous_aggregate('cagg_4_hours', NULL, NULL);
CALL refresh_continuous_aggregate('cagg_4_hours_offset', NULL, NULL);
CALL refresh_continuous_aggregate('cagg_4_hours_origin', NULL, NULL);
INSERT INTO temperature
  SELECT time, 5
    FROM generate_series('2000-01-01 01:00:00 PST'::timestamptz,
                         '2000-01-01 23:59:59 PST','1m') time;
INSERT INTO temperature
  SELECT time, 6
    FROM generate_series('2020-01-01 00:00:00 PST'::timestamptz,
                         '2020-01-01 23:59:59 PST','1m') time;
INSERT INTO temperature values('2020-01-02 01:05:00+01', 2222);
INSERT INTO temperature values('2020-01-02 01:35:00+01', 5555);
INSERT INTO temperature values('2020-01-02 05:05:00+01', 8888);
SET client_min_messages TO DEBUG1;
CALL refresh_continuous_aggregate('cagg_4_hours', NULL, NULL);
psql:include/cagg_query_common.sql:725: LOG:  statement: CALL refresh_continuous_aggregate('cagg_4_hours', NULL, NULL);
psql:include/cagg_query_common.sql:725: DEBUG:  hypertable 4 existing watermark >= new invalidation threshold 1577995200000000 1577952000000000
psql:include/cagg_query_common.sql:725: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours" in window [ Sat Jan 01 00:00:00 2000 PST, Sun Jan 02 00:00:00 2000 PST ]
psql:include/cagg_query_common.sql:725: LOG:  inserted 6 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_33"
psql:include/cagg_query_common.sql:725: DEBUG:  hypertable 33 existing watermark >= new watermark 1577995200000000 946800000000000
psql:include/cagg_query_common.sql:725: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours" in window [ Wed Jan 01 00:00:00 2020 PST, Thu Jan 02 00:00:00 2020 PST ]
psql:include/cagg_query_common.sql:725: LOG:  inserted 6 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_33"
psql:include/cagg_query_common.sql:725: DEBUG:  hypertable 33 existing watermark >= new watermark 1577995200000000 1577952000000000
CALL refresh_continuous_aggregate('cagg_4_hours_offset', NULL, NULL);
psql:include/cagg_query_common.sql:726: LOG:  statement: CALL refresh_continuous_aggregate('cagg_4_hours_offset', NULL, NULL);
psql:include/cagg_query_common.sql:726: DEBUG:  hypertable 4 existing watermark >= new invalidation threshold 1577995200000000 1577952000000000
psql:include/cagg_query_common.sql:726: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours_offset" in window [ Fri Dec 31 20:30:00 1999 PST, Sun Jan 02 00:30:00 2000 PST ]
psql:include/cagg_query_common.sql:726: LOG:  inserted 6 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_34"
psql:include/cagg_query_common.sql:726: DEBUG:  hypertable 34 existing watermark >= new watermark 1577997000000000 946801800000000
psql:include/cagg_query_common.sql:726: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours_offset" in window [ Tue Dec 31 20:30:00 2019 PST, Thu Jan 02 00:30:00 2020 PST ]
psql:include/cagg_query_common.sql:726: LOG:  inserted 7 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_34"
psql:include/cagg_query_common.sql:726: DEBUG:  hypertable 34 existing watermark >= new watermark 1577997000000000 1577953800000000
CALL refresh_continuous_aggregate('cagg_4_hours_origin', NULL, NULL);
psql:include/cagg_query_common.sql:727: LOG:  statement: CALL refresh_continuous_aggregate('cagg_4_hours_origin', NULL, NULL);
psql:include/cagg_query_common.sql:727: DEBUG:  hypertable 4 existing watermark >= new invalidation threshold 1577995200000000 1577952000000000
psql:include/cagg_query_common.sql:727: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours_origin" in window [ Fri Dec 31 21:00:00 1999 PST, Sun Jan 02 01:00:00 2000 PST ]
psql:include/cagg_query_common.sql:727: LOG:  inserted 6 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_35"
psql:include/cagg_query_common.sql:727: DEBUG:  hypertable 35 existing watermark >= new watermark 1577998800000000 946803600000000
psql:include/cagg_query_common.sql:727: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_4_hours_origin" in window [ Tue Dec 31 21:00:00 2019 PST, Thu Jan 02 01:00:00 2020 PST ]
psql:include/cagg_query_common.sql:727: LOG:  inserted 7 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_35"
psql:include/cagg_query_common.sql:727: DEBUG:  hypertable 35 existing watermark >= new watermark 1577998800000000 1577955600000000
RESET client_min_messages;
psql:include/cagg_query_common.sql:728: LOG:  statement: RESET client_min_messages;
ALTER MATERIALIZED VIEW cagg_4_hours SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:00:00 2000 PST |    5
 Sat Jan 01 04:00:00 2000 PST |    5
 Sat Jan 01 08:00:00 2000 PST |    5
 Sat Jan 01 12:00:00 2000 PST |    5
 Sat Jan 01 16:00:00 2000 PST |    5
 Sat Jan 01 20:00:00 2000 PST |    5
 Wed Jan 01 00:00:00 2020 PST |    6
 Wed Jan 01 04:00:00 2020 PST |    6
 Wed Jan 01 08:00:00 2020 PST |    6
 Wed Jan 01 12:00:00 2020 PST |    6
 Wed Jan 01 16:00:00 2020 PST | 5555
 Wed Jan 01 20:00:00 2020 PST | 8888

ALTER MATERIALIZED VIEW cagg_4_hours SET (timescaledb.materialized_only=false);
SELECT * FROM cagg_4_hours;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:00:00 2000 PST |    5
 Sat Jan 01 04:00:00 2000 PST |    5
 Sat Jan 01 08:00:00 2000 PST |    5
 Sat Jan 01 12:00:00 2000 PST |    5
 Sat Jan 01 16:00:00 2000 PST |    5
 Sat Jan 01 20:00:00 2000 PST |    5
 Wed Jan 01 00:00:00 2020 PST |    6
 Wed Jan 01 04:00:00 2020 PST |    6
 Wed Jan 01 08:00:00 2020 PST |    6
 Wed Jan 01 12:00:00 2020 PST |    6
 Wed Jan 01 16:00:00 2020 PST | 5555
 Wed Jan 01 20:00:00 2020 PST | 8888

SELECT time_bucket('4 hour', time), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:00:00 2000 PST |    5
 Sat Jan 01 04:00:00 2000 PST |    5
 Sat Jan 01 08:00:00 2000 PST |    5
 Sat Jan 01 12:00:00 2000 PST |    5
 Sat Jan 01 16:00:00 2000 PST |    5
 Sat Jan 01 20:00:00 2000 PST |    5
 Wed Jan 01 00:00:00 2020 PST |    6
 Wed Jan 01 04:00:00 2020 PST |    6
 Wed Jan 01 08:00:00 2020 PST |    6
 Wed Jan 01 12:00:00 2020 PST |    6
 Wed Jan 01 16:00:00 2020 PST | 5555
 Wed Jan 01 20:00:00 2020 PST | 8888

ALTER MATERIALIZED VIEW cagg_4_hours_offset SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours_offset;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:30:00 2000 PST |    5
 Sat Jan 01 04:30:00 2000 PST |    5
 Sat Jan 01 08:30:00 2000 PST |    5
 Sat Jan 01 12:30:00 2000 PST |    5
 Sat Jan 01 16:30:00 2000 PST |    5
 Sat Jan 01 20:30:00 2000 PST |    5
 Tue Dec 31 20:30:00 2019 PST |    6
 Wed Jan 01 00:30:00 2020 PST |    6
 Wed Jan 01 04:30:00 2020 PST |    6
 Wed Jan 01 08:30:00 2020 PST |    6
 Wed Jan 01 12:30:00 2020 PST | 2222
 Wed Jan 01 16:30:00 2020 PST | 8888
 Wed Jan 01 20:30:00 2020 PST |    6

ALTER MATERIALIZED VIEW cagg_4_hours_offset SET (timescaledb.materialized_only=false);
SELECT * FROM cagg_4_hours_offset;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:30:00 2000 PST |    5
 Sat Jan 01 04:30:00 2000 PST |    5
 Sat Jan 01 08:30:00 2000 PST |    5
 Sat Jan 01 12:30:00 2000 PST |    5
 Sat Jan 01 16:30:00 2000 PST |    5
 Sat Jan 01 20:30:00 2000 PST |    5
 Tue Dec 31 20:30:00 2019 PST |    6
 Wed Jan 01 00:30:00 2020 PST |    6
 Wed Jan 01 04:30:00 2020 PST |    6
 Wed Jan 01 08:30:00 2020 PST |    6
 Wed Jan 01 12:30:00 2020 PST | 2222
 Wed Jan 01 16:30:00 2020 PST | 8888
 Wed Jan 01 20:30:00 2020 PST |    6

SELECT time_bucket('4 hour', time, '30m'::interval), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 00:30:00 2000 PST |    5
 Sat Jan 01 04:30:00 2000 PST |    5
 Sat Jan 01 08:30:00 2000 PST |    5
 Sat Jan 01 12:30:00 2000 PST |    5
 Sat Jan 01 16:30:00 2000 PST |    5
 Sat Jan 01 20:30:00 2000 PST |    5
 Tue Dec 31 20:30:00 2019 PST |    6
 Wed Jan 01 00:30:00 2020 PST |    6
 Wed Jan 01 04:30:00 2020 PST |    6
 Wed Jan 01 08:30:00 2020 PST |    6
 Wed Jan 01 12:30:00 2020 PST | 2222
 Wed Jan 01 16:30:00 2020 PST | 8888
 Wed Jan 01 20:30:00 2020 PST |    6

ALTER MATERIALIZED VIEW cagg_4_hours_origin SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_4_hours_origin;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 01:00:00 2000 PST |    5
 Sat Jan 01 05:00:00 2000 PST |    5
 Sat Jan 01 09:00:00 2000 PST |    5
 Sat Jan 01 13:00:00 2000 PST |    5
 Sat Jan 01 17:00:00 2000 PST |    5
 Sat Jan 01 21:00:00 2000 PST |    5
 Tue Dec 31 21:00:00 2019 PST |    6
 Wed Jan 01 01:00:00 2020 PST |    6
 Wed Jan 01 05:00:00 2020 PST |    6
 Wed Jan 01 09:00:00 2020 PST |    6
 Wed Jan 01 13:00:00 2020 PST | 5555
 Wed Jan 01 17:00:00 2020 PST | 8888
 Wed Jan 01 21:00:00 2020 PST |    6

ALTER MATERIALIZED VIEW cagg_4_hours_origin SET (timescaledb.materialized_only=false);
SELECT * FROM cagg_4_hours_origin;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 01:00:00 2000 PST |    5
 Sat Jan 01 05:00:00 2000 PST |    5
 Sat Jan 01 09:00:00 2000 PST |    5
 Sat Jan 01 13:00:00 2000 PST |    5
 Sat Jan 01 17:00:00 2000 PST |    5
 Sat Jan 01 21:00:00 2000 PST |    5
 Tue Dec 31 21:00:00 2019 PST |    6
 Wed Jan 01 01:00:00 2020 PST |    6
 Wed Jan 01 05:00:00 2020 PST |    6
 Wed Jan 01 09:00:00 2020 PST |    6
 Wed Jan 01 13:00:00 2020 PST | 5555
 Wed Jan 01 17:00:00 2020 PST | 8888
 Wed Jan 01 21:00:00 2020 PST |    6

SELECT time_bucket('4 hour', time, '2000-01-01 01:00:00 PST'::timestamptz), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max  
------------------------------+------
 Sat Jan 01 01:00:00 2000 PST |    5
 Sat Jan 01 05:00:00 2000 PST |    5
 Sat Jan 01 09:00:00 2000 PST |    5
 Sat Jan 01 13:00:00 2000 PST |    5
 Sat Jan 01 17:00:00 2000 PST |    5
 Sat Jan 01 21:00:00 2000 PST |    5
 Tue Dec 31 21:00:00 2019 PST |    6
 Wed Jan 01 01:00:00 2020 PST |    6
 Wed Jan 01 05:00:00 2020 PST |    6
 Wed Jan 01 09:00:00 2020 PST |    6
 Wed Jan 01 13:00:00 2020 PST | 5555
 Wed Jan 01 17:00:00 2020 PST | 8888
 Wed Jan 01 21:00:00 2020 PST |    6

--- Test with variable width buckets (use February, since hourly origins are not supported with variable sized buckets)
TRUNCATE temperature;
INSERT INTO temperature
  SELECT time, 5
    FROM generate_series('2000-02-01 01:00:00 PST'::timestamptz,
                         '2000-02-01 23:59:59 PST','1m') time;
INSERT INTO temperature
  SELECT time, 6
    FROM generate_series('2020-02-01 01:00:00 PST'::timestamptz,
                         '2020-02-01 23:59:59 PST','1m') time;
SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_invalidation_log ORDER BY 1, 2, 3;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------
                  2 |  -9223372036854775808 |     -210866803200000001
                  2 |      1541289600000000 |     9223372036854775807
                  3 |  -9223372036854775808 |     -210866803200000001
                  3 |      1541289600000000 |     9223372036854775807
                 33 |  -9223372036854775808 |     -210866803200000001
                 33 |      1577995200000000 |     9223372036854775807
                 34 |  -9223372036854775808 |     -210866803200000001
                 34 |      1577995200000000 |     9223372036854775807
                 35 |  -9223372036854775808 |     -210866803200000001
                 35 |      1577995200000000 |     9223372036854775807

CREATE MATERIALIZED VIEW cagg_1_year
  WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
  SELECT time_bucket('1 year', time), max(value)
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:766: NOTICE:  refreshing continuous aggregate "cagg_1_year"
SELECT * FROM _timescaledb_catalog.continuous_aggs_materialization_invalidation_log ORDER BY 1, 2, 3;
 materialization_id | lowest_modified_value | greatest_modified_value 
--------------------+-----------------------+-------------------------
                  2 |  -9223372036854775808 |     -210866803200000001
                  2 |      1541289600000000 |     9223372036854775807
                  3 |  -9223372036854775808 |     -210866803200000001
                  3 |      1541289600000000 |     9223372036854775807
                 33 |  -9223372036854775808 |     -210866803200000001
                 33 |  -9223372036854775808 |     9223372036854775807
                 33 |      1577995200000000 |     9223372036854775807
                 34 |  -9223372036854775808 |     -210866803200000001
                 34 |  -9223372036854775808 |     9223372036854775807
                 34 |      1577995200000000 |     9223372036854775807
                 35 |  -9223372036854775808 |     -210866803200000001
                 35 |  -9223372036854775808 |     9223372036854775807
                 35 |      1577995200000000 |     9223372036854775807
                 36 |      1609459200000000 |     9223372036854775807

---
-- Tests with integer based hypertables
---
TRUNCATE table_int;
INSERT INTO table_int
  SELECT time, 5
    FROM generate_series(-50, 50) time;
CREATE MATERIALIZED VIEW cagg_int
    WITH (timescaledb.continuous, timescaledb.materialized_only=false)
    AS SELECT time_bucket('10', time), SUM(data) as value
        FROM table_int
        GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:783: NOTICE:  refreshing continuous aggregate "cagg_int"
CREATE MATERIALIZED VIEW cagg_int_offset
    WITH (timescaledb.continuous, timescaledb.materialized_only=false)
    AS SELECT time_bucket('10', time, "offset"=>5), SUM(data) as value
        FROM table_int
        GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:789: NOTICE:  refreshing continuous aggregate "cagg_int_offset"
-- Compare bucketing results
SELECT time_bucket('10', time), SUM(data) FROM table_int GROUP BY 1 ORDER BY 1;
 time_bucket | sum 
-------------+-----
         -50 |  50
         -40 |  50
         -30 |  50
         -20 |  50
         -10 |  50
           0 |  50
          10 |  50
          20 |  50
          30 |  50
          40 |  50
          50 |   5

SELECT * FROM cagg_int;
 time_bucket | value 
-------------+-------
         -50 |    50
         -40 |    50
         -30 |    50
         -20 |    50
         -10 |    50
           0 |    50
          10 |    50
          20 |    50
          30 |    50
          40 |    50
          50 |     5

SELECT time_bucket('10', time, "offset"=>5), SUM(data) FROM table_int GROUP BY 1 ORDER BY 1;
 time_bucket | sum 
-------------+-----
         -55 |  25
         -45 |  50
         -35 |  50
         -25 |  50
         -15 |  50
          -5 |  50
           5 |  50
          15 |  50
          25 |  50
          35 |  50
          45 |  30

SELECT * FROM cagg_int_offset;
 time_bucket | value 
-------------+-------
         -55 |    25
         -45 |    50
         -35 |    50
         -25 |    50
         -15 |    50
          -5 |    50
           5 |    50
          15 |    50
          25 |    50
          35 |    50
          45 |    30

-- Update table
INSERT INTO table_int VALUES(51, 100);
INSERT INTO table_int VALUES(100, 555);
-- Compare bucketing results
SELECT time_bucket('10', time), SUM(data) FROM table_int GROUP BY 1 ORDER BY 1;
 time_bucket | sum 
-------------+-----
         -50 |  50
         -40 |  50
         -30 |  50
         -20 |  50
         -10 |  50
           0 |  50
          10 |  50
          20 |  50
          30 |  50
          40 |  50
          50 | 105
         100 | 555

SELECT * FROM cagg_int;
 time_bucket | value 
-------------+-------
         -50 |    50
         -40 |    50
         -30 |    50
         -20 |    50
         -10 |    50
           0 |    50
          10 |    50
          20 |    50
          30 |    50
          40 |    50
          50 |     5
         100 |   555

CALL refresh_continuous_aggregate('cagg_int', NULL, NULL);
SELECT * FROM cagg_int;
 time_bucket | value 
-------------+-------
         -50 |    50
         -40 |    50
         -30 |    50
         -20 |    50
         -10 |    50
           0 |    50
          10 |    50
          20 |    50
          30 |    50
          40 |    50
          50 |   105
         100 |   555

SELECT time_bucket('10', time, "offset"=>5), SUM(data) FROM table_int GROUP BY 1 ORDER BY 1;
 time_bucket | sum 
-------------+-----
         -55 |  25
         -45 |  50
         -35 |  50
         -25 |  50
         -15 |  50
          -5 |  50
           5 |  50
          15 |  50
          25 |  50
          35 |  50
          45 | 130
          95 | 555

SELECT * FROM cagg_int_offset;  -- the value 100 is part of the already serialized bucket, so it should not be visible
 time_bucket | value 
-------------+-------
         -55 |    25
         -45 |    50
         -35 |    50
         -25 |    50
         -15 |    50
          -5 |    50
           5 |    50
          15 |    50
          25 |    50
          35 |    50
          45 |    30
          95 |   555

CALL refresh_continuous_aggregate('cagg_int_offset', NULL, NULL);
SELECT * FROM cagg_int_offset;
 time_bucket | value 
-------------+-------
         -55 |    25
         -45 |    50
         -35 |    50
         -25 |    50
         -15 |    50
          -5 |    50
           5 |    50
          15 |    50
          25 |    50
          35 |    50
          45 |   130
          95 |   555

-- Ensure everything was materialized
ALTER MATERIALIZED VIEW cagg_int SET (timescaledb.materialized_only=true);
ALTER MATERIALIZED VIEW cagg_int_offset SET (timescaledb.materialized_only=true);
SELECT * FROM cagg_int;
 time_bucket | value 
-------------+-------
         -50 |    50
         -40 |    50
         -30 |    50
         -20 |    50
         -10 |    50
           0 |    50
          10 |    50
          20 |    50
          30 |    50
          40 |    50
          50 |   105
         100 |   555

SELECT * FROM cagg_int_offset;
 time_bucket | value 
-------------+-------
         -55 |    25
         -45 |    50
         -35 |    50
         -25 |    50
         -15 |    50
          -5 |    50
           5 |    50
          15 |    50
          25 |    50
          35 |    50
          45 |   130
          95 |   555

-- Check that the refresh is properly aligned
INSERT INTO table_int VALUES(114, 0);
SET client_min_messages TO DEBUG1;
CALL refresh_continuous_aggregate('cagg_int_offset', 110, 130);
psql:include/cagg_query_common.sql:824: LOG:  statement: CALL refresh_continuous_aggregate('cagg_int_offset', 110, 130);
psql:include/cagg_query_common.sql:824: DEBUG:  continuous aggregate refresh (individual invalidation) on "cagg_int_offset" in window [ 105, 135 ]
psql:include/cagg_query_common.sql:824: DEBUG:  building index "_hyper_38_67_chunk__materialized_hypertable_38_time_bucket_idx" on table "_hyper_38_67_chunk" serially
psql:include/cagg_query_common.sql:824: DEBUG:  index "_hyper_38_67_chunk__materialized_hypertable_38_time_bucket_idx" can safely use deduplication
psql:include/cagg_query_common.sql:824: LOG:  inserted 1 row(s) into materialization table "_timescaledb_internal._materialized_hypertable_38"
RESET client_min_messages;
psql:include/cagg_query_common.sql:825: LOG:  statement: RESET client_min_messages;
SELECT * FROM cagg_int_offset;
 time_bucket | value 
-------------+-------
         -55 |    25
         -45 |    50
         -35 |    50
         -25 |    50
         -15 |    50
          -5 |    50
           5 |    50
          15 |    50
          25 |    50
          35 |    50
          45 |   130
          95 |   555
         105 |     0

SELECT time_bucket('10', time, "offset"=>5), SUM(data) FROM table_int GROUP BY 1 ORDER BY 1;
 time_bucket | sum 
-------------+-----
         -55 |  25
         -45 |  50
         -35 |  50
         -25 |  50
         -15 |  50
          -5 |  50
           5 |  50
          15 |  50
          25 |  50
          35 |  50
          45 | 130
          95 | 555
         105 |   0

-- Variable sized buckets with origin
CREATE MATERIALIZED VIEW cagg_1_hour_variable_bucket_fixed_origin
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 year', time, origin=>'2000-01-01 01:05:00 UTC'::timestamptz, timezone=>'UTC') AS hour_bucket, max(value) AS max_value
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:835: NOTICE:  refreshing continuous aggregate "cagg_1_hour_variable_bucket_fixed_origin"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_1_hour_variable_bucket_fixed_origin';
 user_view_schema |              user_view_name              |                                               bucket_func                                               | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+------------------------------------------+---------------------------------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_1_hour_variable_bucket_fixed_origin | public.time_bucket(interval,timestamp with time zone,pg_catalog.text,timestamp with time zone,interval) | @ 1 year     | Fri Dec 31 17:05:00 1999 PST |               | UTC             | f

DROP MATERIALIZED VIEW cagg_1_hour_variable_bucket_fixed_origin;
psql:include/cagg_query_common.sql:837: NOTICE:  drop cascades to 2 other objects
-- Variable due to the used timezone
CREATE MATERIALIZED VIEW cagg_1_hour_variable_bucket_fixed_origin2
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 hour', time, origin=>'2000-01-01 01:05:00 UTC'::timestamptz, timezone=>'UTC') AS hour_bucket, max(value) AS max_value
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:844: NOTICE:  refreshing continuous aggregate "cagg_1_hour_variable_bucket_fixed_origin2"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_1_hour_variable_bucket_fixed_origin2';
 user_view_schema |              user_view_name               |                                               bucket_func                                               | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+-------------------------------------------+---------------------------------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_1_hour_variable_bucket_fixed_origin2 | public.time_bucket(interval,timestamp with time zone,pg_catalog.text,timestamp with time zone,interval) | @ 1 hour     | Fri Dec 31 17:05:00 1999 PST |               | UTC             | f

DROP MATERIALIZED VIEW cagg_1_hour_variable_bucket_fixed_origin2;
psql:include/cagg_query_common.sql:846: NOTICE:  drop cascades to 2 other objects
-- Variable with offset
CREATE MATERIALIZED VIEW cagg_1_hour_variable_bucket_fixed_origin3
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 year', time, "offset"=>'5 minutes'::interval) AS hour_bucket, max(value) AS max_value
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:853: NOTICE:  refreshing continuous aggregate "cagg_1_hour_variable_bucket_fixed_origin3"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_1_hour_variable_bucket_fixed_origin3';
 user_view_schema |              user_view_name               |                          bucket_func                           | bucket_width | bucket_origin | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+-------------------------------------------+----------------------------------------------------------------+--------------+---------------+---------------+-----------------+--------------------
 public           | cagg_1_hour_variable_bucket_fixed_origin3 | public.time_bucket(interval,timestamp with time zone,interval) | @ 1 year     |               | @ 5 mins      |                 | f

DROP MATERIALIZED VIEW cagg_1_hour_variable_bucket_fixed_origin3;
psql:include/cagg_query_common.sql:855: NOTICE:  drop cascades to 2 other objects
---
-- Test with blocking a few broken configurations
---
\set ON_ERROR_STOP 0
-- Unfortunately '\set VERBOSITY verbose' cannot be used here to check the error details
-- since it also prints the line number of the location, which is depended on the build
-- Different time origin
CREATE MATERIALIZED VIEW cagg_1_hour_origin
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 hour', time, origin=>'2000-01-02 01:00:00 PST'::timestamptz) AS hour_bucket, max(value) AS max_value
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:870: NOTICE:  refreshing continuous aggregate "cagg_1_hour_origin"
CREATE MATERIALIZED VIEW cagg_1_week_origin
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 week', hour_bucket, origin=>'2022-01-02 01:00:00 PST'::timestamptz) AS week_bucket, max(max_value) AS max_value
    FROM cagg_1_hour_origin
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:876: ERROR:  cannot create continuous aggregate with different bucket origin values
-- Different time offset
CREATE MATERIALIZED VIEW cagg_1_hour_offset
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 hour', time, "offset"=>'30m'::interval) AS hour_bucket, max(value) AS max_value
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:883: NOTICE:  refreshing continuous aggregate "cagg_1_hour_offset"
CREATE MATERIALIZED VIEW cagg_1_week_offset
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 week', hour_bucket, "offset"=>'35m'::interval) AS week_bucket, max(max_value) AS max_value
    FROM cagg_1_hour_offset
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:889: ERROR:  cannot create continuous aggregate with different bucket offset values
-- Cagg with NULL offset on top of cagg with non-NULL offset
\set VERBOSITY default
CREATE MATERIALIZED VIEW cagg_1_week_null_offset
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 week', hour_bucket, "offset"=>NULL::interval) AS week_bucket, max(max_value) AS max_value
    FROM cagg_1_hour_offset
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:897: ERROR:  cannot create continuous aggregate with different bucket offset values
DETAIL:  Time origin of "public.cagg_1_week_null_offset" [NULL] and "public.cagg_1_hour_offset" [@ 30 mins] should be the same.
-- Cagg with non-NULL offset on top of cagg with NULL offset
CREATE MATERIALIZED VIEW cagg_1_hour_null_offset
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 hour', time, "offset"=>NULL::interval) AS hour_bucket, max(value) AS max_value
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:904: NOTICE:  refreshing continuous aggregate "cagg_1_hour_null_offset"
HINT:  Use WITH NO DATA if you do not want to refresh the continuous aggregate on creation.
CREATE MATERIALIZED VIEW cagg_1_week_non_null_offset
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 week', hour_bucket, "offset"=>'35m'::interval) AS week_bucket, max(max_value) AS max_value
    FROM cagg_1_hour_null_offset
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:910: ERROR:  cannot create continuous aggregate with different bucket offset values
DETAIL:  Time origin of "public.cagg_1_week_non_null_offset" [@ 35 mins] and "public.cagg_1_hour_null_offset" [NULL] should be the same.
\set VERBOSITY terse
-- Different integer offset
CREATE MATERIALIZED VIEW cagg_int_offset_5
    WITH (timescaledb.continuous, timescaledb.materialized_only=false)
    AS SELECT time_bucket('10', time, "offset"=>5) AS time, SUM(data) AS value
        FROM table_int
        GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:918: NOTICE:  refreshing continuous aggregate "cagg_int_offset_5"
CREATE MATERIALIZED VIEW cagg_int_offset_10
    WITH (timescaledb.continuous, timescaledb.materialized_only=false)
    AS SELECT time_bucket('10', time, "offset"=>10) AS time, SUM(value) AS value
        FROM cagg_int_offset_5
        GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:924: ERROR:  cannot create continuous aggregate with different bucket offset values
\set ON_ERROR_STOP 1
DROP MATERIALIZED VIEW cagg_1_hour_origin;
psql:include/cagg_query_common.sql:928: NOTICE:  drop cascades to 2 other objects
DROP MATERIALIZED VIEW cagg_1_hour_offset;
psql:include/cagg_query_common.sql:929: NOTICE:  drop cascades to 2 other objects
DROP MATERIALIZED VIEW cagg_int_offset_5;
psql:include/cagg_query_common.sql:930: NOTICE:  drop cascades to 3 other objects
---
-- CAGGs on CAGGs tests
---
CREATE MATERIALIZED VIEW cagg_1_hour_offset
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 hour', time, origin=>'2000-01-02 01:00:00 PST'::timestamptz) AS hour_bucket, max(value) AS max_value
    FROM temperature
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:939: NOTICE:  refreshing continuous aggregate "cagg_1_hour_offset"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_1_hour_offset';
 user_view_schema |   user_view_name   |                                  bucket_func                                   | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+--------------------+--------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_1_hour_offset | public.time_bucket(interval,timestamp with time zone,timestamp with time zone) | @ 1 hour     | Sun Jan 02 01:00:00 2000 PST |               |                 | t

CREATE MATERIALIZED VIEW cagg_1_week_offset
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 week', hour_bucket, origin=>'2000-01-02 01:00:00 PST'::timestamptz) AS week_bucket, max(max_value) AS max_value
    FROM cagg_1_hour_offset
    GROUP BY 1 ORDER BY 1;
psql:include/cagg_query_common.sql:946: NOTICE:  refreshing continuous aggregate "cagg_1_week_offset"
SELECT * FROM caggs_info WHERE user_view_name = 'cagg_1_week_offset';
 user_view_schema |   user_view_name   |                                  bucket_func                                   | bucket_width |        bucket_origin         | bucket_offset | bucket_timezone | bucket_fixed_width 
------------------+--------------------+--------------------------------------------------------------------------------+--------------+------------------------------+---------------+-----------------+--------------------
 public           | cagg_1_week_offset | public.time_bucket(interval,timestamp with time zone,timestamp with time zone) | @ 7 days     | Sun Jan 02 01:00:00 2000 PST |               |                 | t

-- Compare output
SELECT * FROM cagg_1_week_offset;
         week_bucket          | max_value 
------------------------------+-----------
 Sun Jan 30 01:00:00 2000 PST |         5
 Sun Jan 26 01:00:00 2020 PST |         6

SELECT time_bucket('1 week', time, origin=>'2000-01-02 01:00:00 PST'::timestamptz), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          | max 
------------------------------+-----
 Sun Jan 30 01:00:00 2000 PST |   5
 Sun Jan 26 01:00:00 2020 PST |   6

INSERT INTO temperature values('2030-01-01 05:05:00 PST', 22222);
INSERT INTO temperature values('2030-01-03 05:05:00 PST', 55555);
-- Compare real-time functionality
ALTER MATERIALIZED VIEW cagg_1_hour_offset SET (timescaledb.materialized_only=false);
ALTER MATERIALIZED VIEW cagg_1_week_offset SET (timescaledb.materialized_only=false);
SELECT * FROM cagg_1_week_offset;
         week_bucket          | max_value 
------------------------------+-----------
 Sun Jan 30 01:00:00 2000 PST |         5
 Sun Jan 26 01:00:00 2020 PST |         6
 Sun Dec 30 01:00:00 2029 PST |     55555

SELECT time_bucket('1 week', time, origin=>'2000-01-02 01:00:00 PST'::timestamptz), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          |  max  
------------------------------+-------
 Sun Jan 30 01:00:00 2000 PST |     5
 Sun Jan 26 01:00:00 2020 PST |     6
 Sun Dec 30 01:00:00 2029 PST | 55555

-- Test refresh
CALL refresh_continuous_aggregate('cagg_1_hour_offset', NULL, NULL);
CALL refresh_continuous_aggregate('cagg_1_week_offset', NULL, NULL);
-- Everything should be now materailized
ALTER MATERIALIZED VIEW cagg_1_hour_offset SET (timescaledb.materialized_only=false);
ALTER MATERIALIZED VIEW cagg_1_week_offset SET (timescaledb.materialized_only=false);
SELECT * FROM cagg_1_week_offset;
         week_bucket          | max_value 
------------------------------+-----------
 Sun Jan 30 01:00:00 2000 PST |         5
 Sun Jan 26 01:00:00 2020 PST |         6
 Sun Dec 30 01:00:00 2029 PST |     55555

SELECT time_bucket('1 week', time, origin=>'2000-01-02 01:00:00 PST'::timestamptz), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
         time_bucket          |  max  
------------------------------+-------
 Sun Jan 30 01:00:00 2000 PST |     5
 Sun Jan 26 01:00:00 2020 PST |     6
 Sun Dec 30 01:00:00 2029 PST | 55555

TRUNCATE temperature;
SELECT * FROM cagg_1_week_offset;
         week_bucket          | max_value 
------------------------------+-----------
 Sun Jan 30 01:00:00 2000 PST |         5
 Sun Jan 26 01:00:00 2020 PST |         6
 Sun Dec 30 01:00:00 2029 PST |     55555

SELECT time_bucket('1 week', time, origin=>'2000-01-02 01:00:00 PST'::timestamptz), max(value) FROM temperature GROUP BY 1 ORDER BY 1;
 time_bucket | max 
-------------+-----

DROP VIEW caggs_info;
