-- 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.
SET timescaledb.enable_now_constify TO FALSE;
-- We disable index only scans to avoid some flakiness. It is not
-- needed for the tests and it is only important which index is
-- picked.
SET enable_indexonlyscan TO FALSE;
SELECT
       format('include/%s.sql', :'TEST_BASE_NAME') as "TEST_QUERY_NAME",
       format('%s/shared/results/%s_results_uncompressed.out', :'TEST_OUTPUT_DIR', :'TEST_BASE_NAME') as "TEST_RESULTS_UNCOMPRESSED",
       format('%s/shared/results/%s_results_compressed.out', :'TEST_OUTPUT_DIR', :'TEST_BASE_NAME') as "TEST_RESULTS_COMPRESSED"
\gset
SELECT format('\! diff -u --label "Uncompressed results" --label "Compressed results" %s %s', :'TEST_RESULTS_UNCOMPRESSED', :'TEST_RESULTS_COMPRESSED') as "DIFF_CMD"
\gset
-- get EXPLAIN output for all variations
\set PREFIX 'EXPLAIN (analyze, buffers off, costs off, timing off, summary off)'
\set PREFIX_VERBOSE 'EXPLAIN (analyze, buffers off, costs off, timing off, summary off, verbose)'
set work_mem to '64MB';
set max_parallel_workers_per_gather to 0;
set enable_nestloop to off;
\set TEST_TABLE 'metrics'
\ir :TEST_QUERY_NAME
-- 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.
-- In the following test cases, we test that certain indexes are used. By using the
-- timescaledb.enable_decompression_sorted_merge optimization, we are pushing a sort node
-- below the DecompressChunk node, which operates on the batches. This could lead to flaky
-- tests because the input data is small and PostgreSQL switches from IndexScans to
-- SequentialScans. Disable the optimization for the following tests to ensure we have
-- stable query plans in all CI environments.
SET timescaledb.enable_decompression_sorted_merge = 0;
SET enable_nestloop TO on;
-- test LATERAL with ordered append in the outer query
:PREFIX
SELECT time,
  pg_typeof(l)
FROM :TEST_TABLE,
  LATERAL (
    SELECT *
    FROM (
      VALUES (1),
        (2)) v) l
ORDER BY time DESC
LIMIT 2;
--- QUERY PLAN ---
 Limit (actual rows=2.00 loops=1)
   ->  Nested Loop (actual rows=2.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics (actual rows=1.00 loops=1)
               Order: metrics."time" DESC
               ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (never executed)
               ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=2.00 loops=1)
               ->  Values Scan on "*VALUES*" (actual rows=2.00 loops=1)

-- test LATERAL with ordered append in the lateral query
:PREFIX
SELECT time,
  pg_typeof(v)
FROM (
  VALUES (1),
    (2)) v,
  LATERAL (
    SELECT *
    FROM :TEST_TABLE
    ORDER BY time DESC
    LIMIT 2) l;
--- QUERY PLAN ---
 Nested Loop (actual rows=4.00 loops=1)
   ->  Values Scan on "*VALUES*" (actual rows=2.00 loops=1)
   ->  Materialize (actual rows=2.00 loops=2)
         ->  Subquery Scan on l (actual rows=2.00 loops=1)
               ->  Limit (actual rows=2.00 loops=1)
                     ->  Result (actual rows=2.00 loops=1)
                           ->  Custom Scan (ChunkAppend) on metrics (actual rows=2.00 loops=1)
                                 Order: metrics."time" DESC
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (actual rows=2.00 loops=1)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (never executed)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (never executed)

SET enable_nestloop TO off;
-- test plan with best index is chosen
-- this should use device_id, time index
:PREFIX
SELECT time,
  device_id
FROM :TEST_TABLE
WHERE device_id = 1
ORDER BY time DESC
LIMIT 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Custom Scan (ChunkAppend) on metrics (actual rows=1.00 loops=1)
         Order: metrics."time" DESC
         ->  Index Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               Index Cond: (device_id = 1)
         ->  Index Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk (never executed)
               Index Cond: (device_id = 1)
         ->  Index Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk (never executed)
               Index Cond: (device_id = 1)

-- test plan with best index is chosen
-- this should use time index
:PREFIX
SELECT time
FROM :TEST_TABLE
ORDER BY time DESC
LIMIT 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Custom Scan (ChunkAppend) on metrics (actual rows=1.00 loops=1)
         Order: metrics."time" DESC
         ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
         ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (never executed)
         ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (never executed)

SET enable_nestloop TO on;
-- test LATERAL with correlated query
-- only last chunk should be executed
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=1.00 loops=3)
         ->  Result (actual rows=1.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics o (actual rows=1.00 loops=3)
                     Order: o."time" DESC
                     Chunks excluded during startup: 0
                     Chunks excluded during runtime: 2
                     ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_1 (never executed)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                     ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_2 (never executed)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                     ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_3 (actual rows=1.00 loops=3)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))

-- test LATERAL with correlated query
-- only 2nd chunk should be executed
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-10'::timestamptz, '2000-01-11', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
  ORDER BY time
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=2.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=2.00 loops=1)
   ->  Limit (actual rows=1.00 loops=2)
         ->  Result (actual rows=1.00 loops=2)
               ->  Custom Scan (ChunkAppend) on metrics o (actual rows=1.00 loops=2)
                     Order: o."time"
                     Chunks excluded during startup: 0
                     Chunks excluded during runtime: 2
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_1 (never executed)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_2 (actual rows=1.00 loops=2)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_3 (never executed)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))

-- test startup and runtime exclusion together
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
    AND o.time < now()
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=1.00 loops=3)
         ->  Result (actual rows=1.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics o (actual rows=1.00 loops=3)
                     Order: o."time" DESC
                     Chunks excluded during startup: 0
                     Chunks excluded during runtime: 2
                     ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_1 (never executed)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                     ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_2 (never executed)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                     ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o_3 (actual rows=1.00 loops=3)
                           Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))

-- test startup and runtime exclusion together
-- all chunks should be filtered
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
    AND o.time > now()
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=0.00 loops=3)
         ->  Result (actual rows=0.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics o (actual rows=0.00 loops=3)
                     Order: o."time" DESC
                     Chunks excluded during startup: 3

-- test JOIN
-- no exclusion on joined table because quals are not propagated yet
-- With PG 14 on i368, this query uses a nested loop join. Disable the nested loop join to get the same query plan in all tests
SET enable_nestloop TO off;
:PREFIX
SELECT o1.time,
  o2.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.time < '2000-02-01'
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time;
--- QUERY PLAN ---
 Merge Join (actual rows=13674.00 loops=1)
   Merge Cond: (o1."time" = o2."time")
   ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=13674.00 loops=1)
         Order: o1."time"
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=3598.00 loops=1)
               Index Cond: (device_id = 1)
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (actual rows=5038.00 loops=1)
               Index Cond: (device_id = 1)
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (actual rows=5038.00 loops=1)
               Index Cond: (device_id = 1)
   ->  Materialize (actual rows=13674.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=13674.00 loops=1)
               Order: o2."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=3598.00 loops=1)
                     Index Cond: (device_id = 2)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (actual rows=5038.00 loops=1)
                     Index Cond: (device_id = 2)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (actual rows=5038.00 loops=1)
                     Index Cond: (device_id = 2)

-- test JOIN
-- last chunk of o2 should not be executed
:PREFIX
SELECT o1.time,
  o2.time
FROM :TEST_TABLE o1
  INNER JOIN (
    SELECT *
    FROM :TEST_TABLE o2
    ORDER BY time) o2 ON o1.time = o2.time
WHERE o1.time < '2000-01-08'
ORDER BY o1.time
LIMIT 10;
--- QUERY PLAN ---
 Limit (actual rows=10.00 loops=1)
   ->  Merge Join (actual rows=10.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=2.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o1_1 (actual rows=2.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
         ->  Materialize (actual rows=10.00 loops=1)
               ->  Result (actual rows=6.00 loops=1)
                     ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=6.00 loops=1)
                           Order: o2."time"
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o2_1 (actual rows=6.00 loops=1)
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o2_3 (never executed)

-- test join against max query
-- not ChunkAppend so no chunk exclusion
SET enable_hashjoin = FALSE;
SET enable_hashagg = FALSE;
:PREFIX
SELECT o1.time,
  o2.*
FROM :TEST_TABLE o1
  INNER JOIN (
    SELECT max(time) AS max_time
    FROM :TEST_TABLE) o2 ON o1.time = o2.max_time
WHERE o1.device_id = 1
ORDER BY time;
--- QUERY PLAN ---
 Merge Join (actual rows=1.00 loops=1)
   Merge Cond: (o1."time" = ($0))
   ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=13674.00 loops=1)
         Order: o1."time"
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=3598.00 loops=1)
               Index Cond: (device_id = 1)
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (actual rows=5038.00 loops=1)
               Index Cond: (device_id = 1)
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (actual rows=5038.00 loops=1)
               Index Cond: (device_id = 1)
   ->  Sort (actual rows=1.00 loops=1)
         Sort Key: ($0)
         Sort Method: quicksort 
         ->  Result (actual rows=1.00 loops=1)
               InitPlan 1 (returns $0)
                 ->  Limit (actual rows=1.00 loops=1)
                       ->  Custom Scan (ChunkAppend) on metrics (actual rows=1.00 loops=1)
                             Order: metrics."time" DESC
                             ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                                   Index Cond: ("time" IS NOT NULL)
                             ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (never executed)
                                   Index Cond: ("time" IS NOT NULL)
                             ->  Index Scan using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk (never executed)
                                   Index Cond: ("time" IS NOT NULL)

RESET enable_hashjoin;
RESET enable_hashagg;
SET enable_seqscan TO false;
-- test JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with USING
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 USING (time)
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test NATURAL JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  NATURAL INNER JOIN :TEST_TABLE o2
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=0.00 loops=1)
   ->  Sort (actual rows=0.00 loops=1)
         Sort Key: o1."time"
         Sort Method: quicksort 
         ->  Result (actual rows=0.00 loops=1)
               One-Time Filter: false

-- test LEFT JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  LEFT JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test RIGHT JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  RIGHT JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o2.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with ON clause expression order switched
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o2.time = o1.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with equality condition in WHERE clause
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON TRUE
WHERE o1.time = o2.time
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with ORDER BY 2nd hypertable
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o2.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column and device_id
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.device_id = o2.device_id
    AND o1.time = o2.time
  ORDER BY o1.time
  LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         Join Filter: (o1.device_id = o2.device_id)
         Rows Removed by Join Filter: 400
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o1_2 (never executed)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o1_3 (never executed)
         ->  Materialize (actual rows=500.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=101.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o2_1 (actual rows=101.00 loops=1)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_time_idx on _hyper_X_X_chunk o2_3 (never executed)

-- test JOIN on device_id
-- should not use ordered append for 2nd hypertable
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.device_id = o2.device_id
WHERE o1.device_id = 1
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Nested Loop (actual rows=100.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=1.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Append (actual rows=100.00 loops=1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 1)

-- test JOIN on time column with implicit join
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1,
  :TEST_TABLE o2
WHERE o1.time = o2.time
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Index Cond: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with 3 hypertables
-- should use 3 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
  INNER JOIN :TEST_TABLE o3 ON o1.time = o3.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
  AND o3.device_id = 3
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o3."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics o3 (actual rows=100.00 loops=1)
               Order: o3."time"
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o3_1 (actual rows=100.00 loops=1)
                     Index Cond: (device_id = 3)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o3_2 (never executed)
                     Index Cond: (device_id = 3)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o3_3 (never executed)
                     Index Cond: (device_id = 3)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Merge Join (actual rows=100.00 loops=1)
                     Merge Cond: (o1."time" = o2."time")
                     ->  Custom Scan (ChunkAppend) on metrics o1 (actual rows=100.00 loops=1)
                           Order: o1."time"
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Index Cond: (device_id = 1)
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                                 Index Cond: (device_id = 1)
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Materialize (actual rows=100.00 loops=1)
                           ->  Custom Scan (ChunkAppend) on metrics o2 (actual rows=100.00 loops=1)
                                 Order: o2."time"
                                 ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                                       Index Cond: (device_id = 2)
                                 ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                                       Index Cond: (device_id = 2)
                                 ->  Index Scan Backward using _hyper_X_X_chunk_metrics_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                                       Index Cond: (device_id = 2)

RESET enable_seqscan;
\set TEST_TABLE 'metrics_space'
\ir :TEST_QUERY_NAME
-- 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.
-- In the following test cases, we test that certain indexes are used. By using the
-- timescaledb.enable_decompression_sorted_merge optimization, we are pushing a sort node
-- below the DecompressChunk node, which operates on the batches. This could lead to flaky
-- tests because the input data is small and PostgreSQL switches from IndexScans to
-- SequentialScans. Disable the optimization for the following tests to ensure we have
-- stable query plans in all CI environments.
SET timescaledb.enable_decompression_sorted_merge = 0;
SET enable_nestloop TO on;
-- test LATERAL with ordered append in the outer query
:PREFIX
SELECT time,
  pg_typeof(l)
FROM :TEST_TABLE,
  LATERAL (
    SELECT *
    FROM (
      VALUES (1),
        (2)) v) l
ORDER BY time DESC
LIMIT 2;
--- QUERY PLAN ---
 Limit (actual rows=2.00 loops=1)
   ->  Nested Loop (actual rows=2.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_space (actual rows=1.00 loops=1)
               Order: metrics_space."time" DESC
               ->  Merge Append (actual rows=1.00 loops=1)
                     Sort Key: metrics_space."time" DESC
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Merge Append (never executed)
                     Sort Key: metrics_space."time" DESC
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
               ->  Merge Append (never executed)
                     Sort Key: metrics_space."time" DESC
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=2.00 loops=1)
               ->  Values Scan on "*VALUES*" (actual rows=2.00 loops=1)

-- test LATERAL with ordered append in the lateral query
:PREFIX
SELECT time,
  pg_typeof(v)
FROM (
  VALUES (1),
    (2)) v,
  LATERAL (
    SELECT *
    FROM :TEST_TABLE
    ORDER BY time DESC
    LIMIT 2) l;
--- QUERY PLAN ---
 Nested Loop (actual rows=4.00 loops=1)
   ->  Values Scan on "*VALUES*" (actual rows=2.00 loops=1)
   ->  Materialize (actual rows=2.00 loops=2)
         ->  Subquery Scan on l (actual rows=2.00 loops=1)
               ->  Limit (actual rows=2.00 loops=1)
                     ->  Result (actual rows=2.00 loops=1)
                           ->  Custom Scan (ChunkAppend) on metrics_space (actual rows=2.00 loops=1)
                                 Order: metrics_space."time" DESC
                                 ->  Merge Append (actual rows=2.00 loops=1)
                                       Sort Key: metrics_space."time" DESC
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=2.00 loops=1)
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 ->  Merge Append (never executed)
                                       Sort Key: metrics_space."time" DESC
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                 ->  Merge Append (never executed)
                                       Sort Key: metrics_space."time" DESC
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)

SET enable_nestloop TO off;
-- test plan with best index is chosen
-- this should use device_id, time index
:PREFIX
SELECT time,
  device_id
FROM :TEST_TABLE
WHERE device_id = 1
ORDER BY time DESC
LIMIT 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Custom Scan (ChunkAppend) on metrics_space (actual rows=1.00 loops=1)
         Order: metrics_space."time" DESC
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               Filter: (device_id = 1)
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
               Filter: (device_id = 1)
         ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
               Filter: (device_id = 1)

-- test plan with best index is chosen
-- this should use time index
:PREFIX
SELECT time
FROM :TEST_TABLE
ORDER BY time DESC
LIMIT 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Custom Scan (ChunkAppend) on metrics_space (actual rows=1.00 loops=1)
         Order: metrics_space."time" DESC
         ->  Merge Append (actual rows=1.00 loops=1)
               Sort Key: metrics_space."time" DESC
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
         ->  Merge Append (never executed)
               Sort Key: metrics_space."time" DESC
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
         ->  Merge Append (never executed)
               Sort Key: metrics_space."time" DESC
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)

SET enable_nestloop TO on;
-- test LATERAL with correlated query
-- only last chunk should be executed
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=1.00 loops=3)
         ->  Result (actual rows=1.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_space o (actual rows=1.00 loops=3)
                     Order: o."time" DESC
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_2 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_3 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_4 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_5 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_6 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                     ->  Merge Append (actual rows=1.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_7 (actual rows=1.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_8 (actual rows=1.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_9 (actual rows=1.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))

-- test LATERAL with correlated query
-- only 2nd chunk should be executed
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-10'::timestamptz, '2000-01-11', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
  ORDER BY time
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=2.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=2.00 loops=1)
   ->  Limit (actual rows=1.00 loops=2)
         ->  Result (actual rows=1.00 loops=2)
               ->  Custom Scan (ChunkAppend) on metrics_space o (actual rows=1.00 loops=2)
                     Order: o."time"
                     ->  Merge Append (actual rows=0.00 loops=2)
                           Sort Key: o."time"
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=2)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_2 (actual rows=0.00 loops=2)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_3 (actual rows=0.00 loops=2)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                     ->  Merge Append (actual rows=1.00 loops=2)
                           Sort Key: o."time"
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_4 (actual rows=1.00 loops=2)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_5 (actual rows=1.00 loops=2)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_6 (actual rows=1.00 loops=2)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                     ->  Merge Append (never executed)
                           Sort Key: o."time"
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_7 (never executed)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_8 (never executed)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_9 (never executed)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))

-- test startup and runtime exclusion together
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
    AND o.time < now()
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=1.00 loops=3)
         ->  Result (actual rows=1.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_space o (actual rows=1.00 loops=3)
                     Order: o."time" DESC
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_2 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_3 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_4 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_5 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_6 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                     ->  Merge Append (actual rows=1.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_7 (actual rows=1.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_8 (actual rows=1.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_9 (actual rows=1.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))

-- test startup and runtime exclusion together
-- all chunks should be filtered
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
    AND o.time > now()
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=0.00 loops=3)
         ->  Result (actual rows=0.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_space o (actual rows=0.00 loops=3)
                     Order: o."time" DESC
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_2 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_3 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_4 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_5 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_6 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_7 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_8 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o_9 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))

-- test JOIN
-- no exclusion on joined table because quals are not propagated yet
-- With PG 14 on i368, this query uses a nested loop join. Disable the nested loop join to get the same query plan in all tests
SET enable_nestloop TO off;
:PREFIX
SELECT o1.time,
  o2.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.time < '2000-02-01'
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time;
--- QUERY PLAN ---
 Merge Join (actual rows=13674.00 loops=1)
   Merge Cond: (o1."time" = o2."time")
   ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=13674.00 loops=1)
         Order: o1."time"
         ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=3598.00 loops=1)
               Index Cond: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
               Filter: (device_id = 1)
         ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (actual rows=5038.00 loops=1)
               Index Cond: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
               Filter: (device_id = 1)
         ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (actual rows=5038.00 loops=1)
               Index Cond: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
               Filter: (device_id = 1)
   ->  Materialize (actual rows=13674.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=13674.00 loops=1)
               Order: o2."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=3598.00 loops=1)
                     Index Cond: ((device_id = 2) AND ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (actual rows=5038.00 loops=1)
                     Index Cond: ((device_id = 2) AND ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (actual rows=5038.00 loops=1)
                     Index Cond: ((device_id = 2) AND ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))

-- test JOIN
-- last chunk of o2 should not be executed
:PREFIX
SELECT o1.time,
  o2.time
FROM :TEST_TABLE o1
  INNER JOIN (
    SELECT *
    FROM :TEST_TABLE o2
    ORDER BY time) o2 ON o1.time = o2.time
WHERE o1.time < '2000-01-08'
ORDER BY o1.time
LIMIT 10;
--- QUERY PLAN ---
 Limit (actual rows=10.00 loops=1)
   ->  Merge Join (actual rows=10.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=2.00 loops=1)
               Order: o1."time"
               ->  Merge Append (actual rows=2.00 loops=1)
                     Sort Key: o1."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=2.00 loops=1)
                           Index Cond: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (actual rows=1.00 loops=1)
                           Index Cond: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (actual rows=1.00 loops=1)
                           Index Cond: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
               ->  Merge Append (never executed)
                     Sort Key: o1."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_4 (never executed)
                           Index Cond: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_5 (never executed)
                           Index Cond: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_6 (never executed)
                           Index Cond: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
         ->  Materialize (actual rows=10.00 loops=1)
               ->  Result (actual rows=6.00 loops=1)
                     ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=6.00 loops=1)
                           Order: o2."time"
                           ->  Merge Append (actual rows=6.00 loops=1)
                                 Sort Key: o2."time"
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_1 (actual rows=2.00 loops=1)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_2 (actual rows=4.00 loops=1)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_3 (actual rows=2.00 loops=1)
                           ->  Merge Append (never executed)
                                 Sort Key: o2."time"
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_4 (never executed)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_5 (never executed)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_6 (never executed)
                           ->  Merge Append (never executed)
                                 Sort Key: o2."time"
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_7 (never executed)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_8 (never executed)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_9 (never executed)

-- test join against max query
-- not ChunkAppend so no chunk exclusion
SET enable_hashjoin = FALSE;
SET enable_hashagg = FALSE;
:PREFIX
SELECT o1.time,
  o2.*
FROM :TEST_TABLE o1
  INNER JOIN (
    SELECT max(time) AS max_time
    FROM :TEST_TABLE) o2 ON o1.time = o2.max_time
WHERE o1.device_id = 1
ORDER BY time;
--- QUERY PLAN ---
 Merge Join (actual rows=1.00 loops=1)
   Merge Cond: (o1."time" = ($0))
   ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=13674.00 loops=1)
         Order: o1."time"
         ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=3598.00 loops=1)
               Filter: (device_id = 1)
         ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (actual rows=5038.00 loops=1)
               Filter: (device_id = 1)
         ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (actual rows=5038.00 loops=1)
               Filter: (device_id = 1)
   ->  Sort (actual rows=1.00 loops=1)
         Sort Key: ($0)
         Sort Method: quicksort 
         ->  Result (actual rows=1.00 loops=1)
               InitPlan 1 (returns $0)
                 ->  Limit (actual rows=1.00 loops=1)
                       ->  Custom Scan (ChunkAppend) on metrics_space (actual rows=1.00 loops=1)
                             Order: metrics_space."time" DESC
                             ->  Merge Append (actual rows=1.00 loops=1)
                                   Sort Key: metrics_space."time" DESC
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                                         Index Cond: ("time" IS NOT NULL)
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                                         Index Cond: ("time" IS NOT NULL)
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                                         Index Cond: ("time" IS NOT NULL)
                             ->  Merge Append (never executed)
                                   Sort Key: metrics_space."time" DESC
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                         Index Cond: ("time" IS NOT NULL)
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                         Index Cond: ("time" IS NOT NULL)
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                         Index Cond: ("time" IS NOT NULL)
                             ->  Merge Append (never executed)
                                   Sort Key: metrics_space."time" DESC
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                         Index Cond: ("time" IS NOT NULL)
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                         Index Cond: ("time" IS NOT NULL)
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk (never executed)
                                         Index Cond: ("time" IS NOT NULL)

RESET enable_hashjoin;
RESET enable_hashagg;
SET enable_seqscan TO false;
-- test JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with USING
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 USING (time)
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test NATURAL JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  NATURAL INNER JOIN :TEST_TABLE o2
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=0.00 loops=1)
   ->  Sort (actual rows=0.00 loops=1)
         Sort Key: o1."time"
         Sort Method: quicksort 
         ->  Result (actual rows=0.00 loops=1)
               One-Time Filter: false

-- test LEFT JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  LEFT JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test RIGHT JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  RIGHT JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o2.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with ON clause expression order switched
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o2.time = o1.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with equality condition in WHERE clause
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON TRUE
WHERE o1.time = o2.time
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with ORDER BY 2nd hypertable
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o2.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column and device_id
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.device_id = o2.device_id
    AND o1.time = o2.time
  ORDER BY o1.time
  LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         Join Filter: (o1.device_id = o2.device_id)
         Rows Removed by Join Filter: 400
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o1."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=21.00 loops=1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (actual rows=60.00 loops=1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (actual rows=21.00 loops=1)
               ->  Merge Append (never executed)
                     Sort Key: o1."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_4 (never executed)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_5 (never executed)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_6 (never executed)
               ->  Merge Append (never executed)
                     Sort Key: o1."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_7 (never executed)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_8 (never executed)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_9 (never executed)
         ->  Materialize (actual rows=500.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=101.00 loops=1)
                     Order: o2."time"
                     ->  Merge Append (actual rows=101.00 loops=1)
                           Sort Key: o2."time"
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_1 (actual rows=21.00 loops=1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_2 (actual rows=61.00 loops=1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_3 (actual rows=21.00 loops=1)
                     ->  Merge Append (never executed)
                           Sort Key: o2."time"
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_4 (never executed)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_5 (never executed)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_6 (never executed)
                     ->  Merge Append (never executed)
                           Sort Key: o2."time"
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_7 (never executed)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_8 (never executed)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o2_9 (never executed)

-- test JOIN on device_id
-- should not use ordered append for 2nd hypertable
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.device_id = o2.device_id
WHERE o1.device_id = 1
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Nested Loop (actual rows=100.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=1.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Append (actual rows=100.00 loops=1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 1)

-- test JOIN on time column with implicit join
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1,
  :TEST_TABLE o2
WHERE o1.time = o2.time
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                     Filter: (device_id = 1)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                     Filter: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                           Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                           Index Cond: (device_id = 2)

-- test JOIN on time column with 3 hypertables
-- should use 3 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
  INNER JOIN :TEST_TABLE o3 ON o1.time = o3.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
  AND o3.device_id = 3
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o3."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_space o3 (actual rows=100.00 loops=1)
               Order: o3."time"
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o3_1 (actual rows=100.00 loops=1)
                     Filter: (device_id = 3)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o3_2 (never executed)
                     Filter: (device_id = 3)
               ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o3_3 (never executed)
                     Filter: (device_id = 3)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Merge Join (actual rows=100.00 loops=1)
                     Merge Cond: (o1."time" = o2."time")
                     ->  Custom Scan (ChunkAppend) on metrics_space o1 (actual rows=100.00 loops=1)
                           Order: o1."time"
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_2 (never executed)
                                 Filter: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_space_time_idx on _hyper_X_X_chunk o1_3 (never executed)
                                 Filter: (device_id = 1)
                     ->  Materialize (actual rows=100.00 loops=1)
                           ->  Custom Scan (ChunkAppend) on metrics_space o2 (actual rows=100.00 loops=1)
                                 Order: o2."time"
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                                       Index Cond: (device_id = 2)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_2 (never executed)
                                       Index Cond: (device_id = 2)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_space_device_id_time_idx on _hyper_X_X_chunk o2_3 (never executed)
                                       Index Cond: (device_id = 2)

RESET enable_seqscan;
\set TEST_TABLE 'metrics_compressed'
\ir :TEST_QUERY_NAME
-- 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.
-- In the following test cases, we test that certain indexes are used. By using the
-- timescaledb.enable_decompression_sorted_merge optimization, we are pushing a sort node
-- below the DecompressChunk node, which operates on the batches. This could lead to flaky
-- tests because the input data is small and PostgreSQL switches from IndexScans to
-- SequentialScans. Disable the optimization for the following tests to ensure we have
-- stable query plans in all CI environments.
SET timescaledb.enable_decompression_sorted_merge = 0;
SET enable_nestloop TO on;
-- test LATERAL with ordered append in the outer query
:PREFIX
SELECT time,
  pg_typeof(l)
FROM :TEST_TABLE,
  LATERAL (
    SELECT *
    FROM (
      VALUES (1),
        (2)) v) l
ORDER BY time DESC
LIMIT 2;
--- QUERY PLAN ---
 Limit (actual rows=2.00 loops=1)
   ->  Nested Loop (actual rows=2.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_compressed (actual rows=1.00 loops=1)
               Order: metrics_compressed."time" DESC
               ->  Sort (actual rows=1.00 loops=1)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     Sort Method: quicksort 
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=25190.00 loops=1)
                           ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=30.00 loops=1)
               ->  Sort (never executed)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
               ->  Merge Append (never executed)
                     Sort Key: metrics_compressed."time" DESC
                     ->  Sort (never executed)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                     ->  Index Scan Backward using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=2.00 loops=1)
               ->  Values Scan on "*VALUES*" (actual rows=2.00 loops=1)

-- test LATERAL with ordered append in the lateral query
:PREFIX
SELECT time,
  pg_typeof(v)
FROM (
  VALUES (1),
    (2)) v,
  LATERAL (
    SELECT *
    FROM :TEST_TABLE
    ORDER BY time DESC
    LIMIT 2) l;
--- QUERY PLAN ---
 Nested Loop (actual rows=4.00 loops=1)
   ->  Values Scan on "*VALUES*" (actual rows=2.00 loops=1)
   ->  Materialize (actual rows=2.00 loops=2)
         ->  Subquery Scan on l (actual rows=2.00 loops=1)
               ->  Limit (actual rows=2.00 loops=1)
                     ->  Result (actual rows=2.00 loops=1)
                           ->  Custom Scan (ChunkAppend) on metrics_compressed (actual rows=2.00 loops=1)
                                 Order: metrics_compressed."time" DESC
                                 ->  Sort (actual rows=2.00 loops=1)
                                       Sort Key: _hyper_X_X_chunk."time" DESC
                                       Sort Method: top-N heapsort 
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=25190.00 loops=1)
                                             ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=30.00 loops=1)
                                 ->  Sort (never executed)
                                       Sort Key: _hyper_X_X_chunk."time" DESC
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                             ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                 ->  Merge Append (never executed)
                                       Sort Key: metrics_compressed."time" DESC
                                       ->  Sort (never executed)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       ->  Index Scan Backward using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk (never executed)

SET enable_nestloop TO off;
-- test plan with best index is chosen
-- this should use device_id, time index
:PREFIX
SELECT time,
  device_id
FROM :TEST_TABLE
WHERE device_id = 1
ORDER BY time DESC
LIMIT 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Custom Scan (ChunkAppend) on metrics_compressed (actual rows=1.00 loops=1)
         Order: metrics_compressed."time" DESC
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                     Index Cond: (device_id = 1)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
               ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                     Index Cond: (device_id = 1)
         ->  Merge Append (never executed)
               Sort Key: metrics_compressed."time" DESC
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                     Filter: (device_id = 1)
                     ->  Sort (never executed)
                           Sort Key: compress_hyper_X_X_chunk._ts_meta_min_1 DESC, compress_hyper_X_X_chunk._ts_meta_max_1 DESC
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                 Filter: (device_id = 1)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk (never executed)
                     Filter: (device_id = 1)

-- test plan with best index is chosen
-- this should use time index
:PREFIX
SELECT time
FROM :TEST_TABLE
ORDER BY time DESC
LIMIT 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Custom Scan (ChunkAppend) on metrics_compressed (actual rows=1.00 loops=1)
         Order: metrics_compressed."time" DESC
         ->  Sort (actual rows=1.00 loops=1)
               Sort Key: _hyper_X_X_chunk."time" DESC
               Sort Method: top-N heapsort 
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=25190.00 loops=1)
                     ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=30.00 loops=1)
         ->  Sort (never executed)
               Sort Key: _hyper_X_X_chunk."time" DESC
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                     ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
         ->  Merge Append (never executed)
               Sort Key: metrics_compressed."time" DESC
               ->  Sort (never executed)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
               ->  Index Scan Backward using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk (never executed)

SET enable_nestloop TO on;
-- test LATERAL with correlated query
-- only last chunk should be executed
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=1.00 loops=3)
         ->  Result (actual rows=1.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o (actual rows=1.00 loops=3)
                     Order: o."time" DESC
                     Chunks excluded during startup: 0
                     Chunks excluded during runtime: 2
                     ->  Sort (never executed)
                           Sort Key: o_1."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_1 (never executed)
                                 Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)))
                     ->  Sort (never executed)
                           Sort Key: o_2."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_2 (never executed)
                                 Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)))
                     ->  Merge Append (actual rows=1.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=1.00 loops=3)
                                 Sort Key: o_3."time" DESC
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_3 (actual rows=3147.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 3650
                                       ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=7.00 loops=3)
                                             Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)))
                                             Rows Removed by Filter: 11
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o_3 (actual rows=1.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))

-- test LATERAL with correlated query
-- only 2nd chunk should be executed
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-10'::timestamptz, '2000-01-11', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
  ORDER BY time
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=2.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=2.00 loops=1)
   ->  Limit (actual rows=1.00 loops=2)
         ->  Sort (actual rows=1.00 loops=2)
               Sort Key: o."time"
               Sort Method: top-N heapsort 
               ->  Result (actual rows=3600.00 loops=2)
                     ->  Custom Scan (ChunkAppend) on metrics_compressed o (actual rows=3600.00 loops=2)
                           Chunks excluded during startup: 0
                           Chunks excluded during runtime: 1
                           ->  Merge Append (actual rows=0.00 loops=2)
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=2)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=0.00 loops=2)
                                             Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)))
                                             Rows Removed by Filter: 18
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=2)
                                       Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_2 (actual rows=3600.00 loops=2)
                                 Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                 Rows Removed by Filter: 3900
                                 ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=8.00 loops=2)
                                       Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 22
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_3 (never executed)
                                 Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)))

-- test startup and runtime exclusion together
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
    AND o.time < now()
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=1.00 loops=3)
         ->  Result (actual rows=1.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o (actual rows=1.00 loops=3)
                     Order: o."time" DESC
                     Chunks excluded during startup: 0
                     Chunks excluded during runtime: 2
                     ->  Sort (never executed)
                           Sort Key: o_1."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_1 (never executed)
                                 Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                 Vectorized Filter: ("time" < now())
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()))
                     ->  Sort (never executed)
                           Sort Key: o_2."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_2 (never executed)
                                 Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                 Vectorized Filter: ("time" < now())
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()))
                     ->  Merge Append (actual rows=1.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=1.00 loops=3)
                                 Sort Key: o_3."time" DESC
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_3 (actual rows=3147.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 3650
                                       Vectorized Filter: ("time" < now())
                                       ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=7.00 loops=3)
                                             Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()))
                                             Rows Removed by Filter: 11
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o_3 (actual rows=1.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" < now()))

-- test startup and runtime exclusion together
-- all chunks should be filtered
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
    AND o.time > now()
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=0.00 loops=3)
         ->  Result (actual rows=0.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o (actual rows=0.00 loops=3)
                     Order: o."time" DESC
                     Chunks excluded during startup: 2
                     Chunks excluded during runtime: 0
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_1."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Filter: ((_ts_meta_max_1 >= g."time") AND (_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 > now()))
                                             Rows Removed by Filter: 18
                           ->  Index Scan Backward using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=3)
                                 Index Cond: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)) AND ("time" > now()))

-- test JOIN
-- no exclusion on joined table because quals are not propagated yet
-- With PG 14 on i368, this query uses a nested loop join. Disable the nested loop join to get the same query plan in all tests
SET enable_nestloop TO off;
:PREFIX
SELECT o1.time,
  o2.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.time < '2000-02-01'
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time;
--- QUERY PLAN ---
 Merge Join (actual rows=13674.00 loops=1)
   Merge Cond: (o2."time" = o1."time")
   ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=13674.00 loops=1)
         Order: o2."time"
         ->  Merge Append (actual rows=3598.00 loops=1)
               Sort Key: o2."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=3598.00 loops=1)
                     Filter: (device_id = 2)
                     ->  Sort (actual rows=4.00 loops=1)
                           Sort Key: compress_hyper_X_X_chunk_1._ts_meta_min_1, compress_hyper_X_X_chunk_1._ts_meta_max_1
                           Sort Method: quicksort 
                           ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=4.00 loops=1)
                                 Filter: (device_id = 2)
                                 Rows Removed by Filter: 14
               ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                     Index Cond: (device_id = 2)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (actual rows=5038.00 loops=1)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=6.00 loops=1)
                     Index Cond: (device_id = 2)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (actual rows=5038.00 loops=1)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=6.00 loops=1)
                     Index Cond: (device_id = 2)
   ->  Materialize (actual rows=13674.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=13674.00 loops=1)
               Order: o1."time"
               ->  Merge Append (actual rows=3598.00 loops=1)
                     Sort Key: o1."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=2000.00 loops=1)
                           Filter: (device_id = 1)
                           ->  Sort (actual rows=2.00 loops=1)
                                 Sort Key: compress_hyper_X_X_chunk._ts_meta_min_1, compress_hyper_X_X_chunk._ts_meta_max_1
                                 Sort Method: quicksort 
                                 ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=2.00 loops=1)
                                       Filter: (device_id = 1)
                                       Rows Removed by Filter: 16
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=1598.00 loops=1)
                           Filter: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (actual rows=5038.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (actual rows=5038.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                           Index Cond: (device_id = 1)

-- test JOIN
-- last chunk of o2 should not be executed
:PREFIX
SELECT o1.time,
  o2.time
FROM :TEST_TABLE o1
  INNER JOIN (
    SELECT *
    FROM :TEST_TABLE o2
    ORDER BY time) o2 ON o1.time = o2.time
WHERE o1.time < '2000-01-08'
ORDER BY o1.time
LIMIT 10;
--- QUERY PLAN ---
 Limit (actual rows=10.00 loops=1)
   ->  Merge Join (actual rows=10.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Result (actual rows=2.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=2.00 loops=1)
                     Order: o2."time"
                     ->  Merge Append (actual rows=2.00 loops=1)
                           Sort Key: o2."time"
                           ->  Sort (actual rows=2.00 loops=1)
                                 Sort Key: o2_1."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=16392.00 loops=1)
                                       ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=18.00 loops=1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o2_1 (actual rows=1.00 loops=1)
                     ->  Sort (never executed)
                           Sort Key: o2_2."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                     ->  Sort (never executed)
                           Sort Key: o2_3."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=10.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=6.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=6.00 loops=1)
                           Sort Key: o1."time"
                           ->  Sort (actual rows=5.00 loops=1)
                                 Sort Key: o1_1."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=16392.00 loops=1)
                                       ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=18.00 loops=1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=2.00 loops=1)
                     ->  Sort (never executed)
                           Sort Key: o1_2."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                                 Vectorized Filter: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: (_ts_meta_min_1 < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)

-- test join against max query
-- not ChunkAppend so no chunk exclusion
SET enable_hashjoin = FALSE;
SET enable_hashagg = FALSE;
:PREFIX
SELECT o1.time,
  o2.*
FROM :TEST_TABLE o1
  INNER JOIN (
    SELECT max(time) AS max_time
    FROM :TEST_TABLE) o2 ON o1.time = o2.max_time
WHERE o1.device_id = 1
ORDER BY time;
--- QUERY PLAN ---
 Merge Join (actual rows=1.00 loops=1)
   Merge Cond: (o1."time" = ($0))
   ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=13674.00 loops=1)
         Order: o1."time"
         ->  Merge Append (actual rows=3598.00 loops=1)
               Sort Key: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=2000.00 loops=1)
                     Filter: (device_id = 1)
                     ->  Sort (actual rows=2.00 loops=1)
                           Sort Key: compress_hyper_X_X_chunk._ts_meta_min_1, compress_hyper_X_X_chunk._ts_meta_max_1
                           Sort Method: quicksort 
                           ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=2.00 loops=1)
                                 Filter: (device_id = 1)
                                 Rows Removed by Filter: 16
               ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=1598.00 loops=1)
                     Filter: (device_id = 1)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (actual rows=5038.00 loops=1)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                     Index Cond: (device_id = 1)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (actual rows=5038.00 loops=1)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                     Index Cond: (device_id = 1)
   ->  Sort (actual rows=1.00 loops=1)
         Sort Key: ($0)
         Sort Method: quicksort 
         ->  Result (actual rows=1.00 loops=1)
               InitPlan 1 (returns $0)
                 ->  Limit (actual rows=1.00 loops=1)
                       ->  Custom Scan (ChunkAppend) on metrics_compressed (actual rows=1.00 loops=1)
                             Order: metrics_compressed."time" DESC
                             ->  Sort (actual rows=1.00 loops=1)
                                   Sort Key: _hyper_X_X_chunk."time" DESC
                                   Sort Method: top-N heapsort 
                                   ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=25190.00 loops=1)
                                         Vectorized Filter: ("time" IS NOT NULL)
                                         ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=30.00 loops=1)
                             ->  Sort (never executed)
                                   Sort Key: _hyper_X_X_chunk."time" DESC
                                   ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                         Vectorized Filter: ("time" IS NOT NULL)
                                         ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                             ->  Merge Append (never executed)
                                   Sort Key: metrics_compressed."time" DESC
                                   ->  Sort (never executed)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                   ->  Index Scan Backward using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk (never executed)
                                         Index Cond: ("time" IS NOT NULL)

RESET enable_hashjoin;
RESET enable_hashagg;
SET enable_seqscan TO false;
-- test JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
               Order: o2."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 2)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=100.00 loops=1)
                           Sort Key: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                 Filter: (device_id = 1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)

-- test JOIN on time column with USING
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 USING (time)
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
               Order: o2."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 2)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=100.00 loops=1)
                           Sort Key: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                 Filter: (device_id = 1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)

-- test NATURAL JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  NATURAL INNER JOIN :TEST_TABLE o2
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=0.00 loops=1)
   ->  Sort (actual rows=0.00 loops=1)
         Sort Key: o1."time"
         Sort Method: quicksort 
         ->  Result (actual rows=0.00 loops=1)
               One-Time Filter: false

-- test LEFT JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  LEFT JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
               Order: o2."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 2)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=100.00 loops=1)
                           Sort Key: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                 Filter: (device_id = 1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)

-- test RIGHT JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  RIGHT JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o2.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
               Order: o2."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 2)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=100.00 loops=1)
                           Sort Key: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                 Filter: (device_id = 1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)

-- test JOIN on time column with ON clause expression order switched
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o2.time = o1.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
               Order: o2."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 2)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=100.00 loops=1)
                           Sort Key: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                 Filter: (device_id = 1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)

-- test JOIN on time column with equality condition in WHERE clause
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON TRUE
WHERE o1.time = o2.time
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
               Order: o2."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 2)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=100.00 loops=1)
                           Sort Key: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                 Filter: (device_id = 1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)

-- test JOIN on time column with ORDER BY 2nd hypertable
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o2.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
               Order: o2."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 2)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=100.00 loops=1)
                           Sort Key: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                 Filter: (device_id = 1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)

-- test JOIN on time column and device_id
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.device_id = o2.device_id
    AND o1.time = o2.time
  ORDER BY o1.time
  LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         Join Filter: (o1.device_id = o2.device_id)
         Rows Removed by Join Filter: 400
         ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o1."time"
                     ->  Sort (actual rows=80.00 loops=1)
                           Sort Key: o1_1."time"
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=16392.00 loops=1)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=18.00 loops=1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=21.00 loops=1)
               ->  Sort (never executed)
                     Sort Key: o1_2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
               ->  Sort (never executed)
                     Sort Key: o1_3."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=500.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=101.00 loops=1)
                     Order: o2."time"
                     ->  Merge Append (actual rows=101.00 loops=1)
                           Sort Key: o2."time"
                           ->  Sort (actual rows=81.00 loops=1)
                                 Sort Key: o2_1."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=16392.00 loops=1)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=18.00 loops=1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o2_1 (actual rows=21.00 loops=1)
                     ->  Sort (never executed)
                           Sort Key: o2_2."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                     ->  Sort (never executed)
                           Sort Key: o2_3."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)

-- test JOIN on device_id
-- should not use ordered append for 2nd hypertable
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.device_id = o2.device_id
WHERE o1.device_id = 1
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Nested Loop (actual rows=100.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=1.00 loops=1)
               Order: o1."time"
               ->  Merge Append (actual rows=1.00 loops=1)
                     Sort Key: o1."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                           Filter: (device_id = 1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                           Filter: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Append (actual rows=100.00 loops=1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 1)
                           ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 1)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (never executed)
                           Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                 Index Cond: (device_id = 1)

-- test JOIN on time column with implicit join
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1,
  :TEST_TABLE o2
WHERE o1.time = o2.time
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o2."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
               Order: o2."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 2)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           Index Cond: (device_id = 2)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                     Order: o1."time"
                     ->  Merge Append (actual rows=100.00 loops=1)
                           Sort Key: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                 Filter: (device_id = 1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 Filter: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 1)

-- test JOIN on time column with 3 hypertables
-- should use 3 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
  INNER JOIN :TEST_TABLE o3 ON o1.time = o3.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
  AND o3.device_id = 3
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o3."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_compressed o3 (actual rows=100.00 loops=1)
               Order: o3."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o3."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o3_1 (actual rows=100.00 loops=1)
                           Filter: (device_id = 3)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_2 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 3)
                     ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o3_1 (actual rows=0.00 loops=1)
                           Index Cond: (device_id = 3)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o3_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_2 (never executed)
                           Index Cond: (device_id = 3)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o3_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_2 (never executed)
                           Index Cond: (device_id = 3)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Merge Join (actual rows=100.00 loops=1)
                     Merge Cond: (o2."time" = o1."time")
                     ->  Custom Scan (ChunkAppend) on metrics_compressed o2 (actual rows=100.00 loops=1)
                           Order: o2."time"
                           ->  Merge Append (actual rows=100.00 loops=1)
                                 Sort Key: o2."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                                       Filter: (device_id = 2)
                                       ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                             Index Cond: (device_id = 2)
                                 ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_device_id_time_idx on _hyper_X_X_chunk o2_1 (actual rows=0.00 loops=1)
                                       Index Cond: (device_id = 2)
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                       Index Cond: (device_id = 2)
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                       Index Cond: (device_id = 2)
                     ->  Materialize (actual rows=100.00 loops=1)
                           ->  Custom Scan (ChunkAppend) on metrics_compressed o1 (actual rows=100.00 loops=1)
                                 Order: o1."time"
                                 ->  Merge Append (actual rows=100.00 loops=1)
                                       Sort Key: o1."time"
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                                             Filter: (device_id = 1)
                                             ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                                   Index Cond: (device_id = 1)
                                       ->  Index Scan using _hyper_X_X_chunk_metrics_compressed_time_idx on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                             Filter: (device_id = 1)
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                                       ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                             Index Cond: (device_id = 1)
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                                       ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                             Index Cond: (device_id = 1)

RESET enable_seqscan;
\set TEST_TABLE 'metrics_space_compressed'
\ir :TEST_QUERY_NAME
-- 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.
-- In the following test cases, we test that certain indexes are used. By using the
-- timescaledb.enable_decompression_sorted_merge optimization, we are pushing a sort node
-- below the DecompressChunk node, which operates on the batches. This could lead to flaky
-- tests because the input data is small and PostgreSQL switches from IndexScans to
-- SequentialScans. Disable the optimization for the following tests to ensure we have
-- stable query plans in all CI environments.
SET timescaledb.enable_decompression_sorted_merge = 0;
SET enable_nestloop TO on;
-- test LATERAL with ordered append in the outer query
:PREFIX
SELECT time,
  pg_typeof(l)
FROM :TEST_TABLE,
  LATERAL (
    SELECT *
    FROM (
      VALUES (1),
        (2)) v) l
ORDER BY time DESC
LIMIT 2;
--- QUERY PLAN ---
 Limit (actual rows=2.00 loops=1)
   ->  Nested Loop (actual rows=2.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed (actual rows=1.00 loops=1)
               Order: metrics_space_compressed."time" DESC
               ->  Merge Append (actual rows=1.00 loops=1)
                     Sort Key: metrics_space_compressed."time" DESC
                     ->  Sort (actual rows=1.00 loops=1)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=5038.00 loops=1)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                     ->  Sort (actual rows=1.00 loops=1)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=15114.00 loops=1)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=18.00 loops=1)
                     ->  Sort (actual rows=1.00 loops=1)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=5038.00 loops=1)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
               ->  Merge Append (never executed)
                     Sort Key: metrics_space_compressed."time" DESC
                     ->  Sort (never executed)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                     ->  Sort (never executed)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                     ->  Sort (never executed)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
               ->  Merge Append (never executed)
                     Sort Key: metrics_space_compressed."time" DESC
                     ->  Sort (never executed)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                     ->  Sort (never executed)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                     ->  Sort (never executed)
                           Sort Key: _hyper_X_X_chunk."time" DESC
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=2.00 loops=1)
               ->  Values Scan on "*VALUES*" (actual rows=2.00 loops=1)

-- test LATERAL with ordered append in the lateral query
:PREFIX
SELECT time,
  pg_typeof(v)
FROM (
  VALUES (1),
    (2)) v,
  LATERAL (
    SELECT *
    FROM :TEST_TABLE
    ORDER BY time DESC
    LIMIT 2) l;
--- QUERY PLAN ---
 Nested Loop (actual rows=4.00 loops=1)
   ->  Values Scan on "*VALUES*" (actual rows=2.00 loops=1)
   ->  Materialize (actual rows=2.00 loops=2)
         ->  Subquery Scan on l (actual rows=2.00 loops=1)
               ->  Limit (actual rows=2.00 loops=1)
                     ->  Result (actual rows=2.00 loops=1)
                           ->  Custom Scan (ChunkAppend) on metrics_space_compressed (actual rows=2.00 loops=1)
                                 Order: metrics_space_compressed."time" DESC
                                 ->  Merge Append (actual rows=2.00 loops=1)
                                       Sort Key: metrics_space_compressed."time" DESC
                                       ->  Sort (actual rows=2.00 loops=1)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             Sort Method: top-N heapsort 
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=5038.00 loops=1)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                                       ->  Sort (actual rows=1.00 loops=1)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             Sort Method: top-N heapsort 
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=15114.00 loops=1)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=18.00 loops=1)
                                       ->  Sort (actual rows=1.00 loops=1)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             Sort Method: top-N heapsort 
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=5038.00 loops=1)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                                 ->  Merge Append (never executed)
                                       Sort Key: metrics_space_compressed."time" DESC
                                       ->  Sort (never executed)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       ->  Sort (never executed)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       ->  Sort (never executed)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                 ->  Merge Append (never executed)
                                       Sort Key: metrics_space_compressed."time" DESC
                                       ->  Sort (never executed)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       ->  Sort (never executed)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       ->  Sort (never executed)
                                             Sort Key: _hyper_X_X_chunk."time" DESC
                                             ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                                   ->  Seq Scan on compress_hyper_X_X_chunk (never executed)

SET enable_nestloop TO off;
-- test plan with best index is chosen
-- this should use device_id, time index
:PREFIX
SELECT time,
  device_id
FROM :TEST_TABLE
WHERE device_id = 1
ORDER BY time DESC
LIMIT 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Custom Scan (ChunkAppend) on metrics_space_compressed (actual rows=1.00 loops=1)
         Order: metrics_space_compressed."time" DESC
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                     Index Cond: (device_id = 1)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
               ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                     Index Cond: (device_id = 1)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
               ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                     Index Cond: (device_id = 1)

-- test plan with best index is chosen
-- this should use time index
:PREFIX
SELECT time
FROM :TEST_TABLE
ORDER BY time DESC
LIMIT 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Custom Scan (ChunkAppend) on metrics_space_compressed (actual rows=1.00 loops=1)
         Order: metrics_space_compressed."time" DESC
         ->  Merge Append (actual rows=1.00 loops=1)
               Sort Key: metrics_space_compressed."time" DESC
               ->  Sort (actual rows=1.00 loops=1)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     Sort Method: top-N heapsort 
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=5038.00 loops=1)
                           ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
               ->  Sort (actual rows=1.00 loops=1)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     Sort Method: top-N heapsort 
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=15114.00 loops=1)
                           ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=18.00 loops=1)
               ->  Sort (actual rows=1.00 loops=1)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     Sort Method: top-N heapsort 
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=5038.00 loops=1)
                           ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
         ->  Merge Append (never executed)
               Sort Key: metrics_space_compressed."time" DESC
               ->  Sort (never executed)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
               ->  Sort (never executed)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
               ->  Sort (never executed)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
         ->  Merge Append (never executed)
               Sort Key: metrics_space_compressed."time" DESC
               ->  Sort (never executed)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
               ->  Sort (never executed)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
               ->  Sort (never executed)
                     Sort Key: _hyper_X_X_chunk."time" DESC
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                           ->  Seq Scan on compress_hyper_X_X_chunk (never executed)

SET enable_nestloop TO on;
-- test LATERAL with correlated query
-- only last chunk should be executed
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=1.00 loops=3)
         ->  Result (actual rows=1.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o (actual rows=1.00 loops=3)
                     Order: o."time" DESC
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_1."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_2."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_2 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_3."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_3 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_4."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_4 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_5."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_5 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_6."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_6 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                     ->  Merge Append (actual rows=1.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=1.00 loops=3)
                                 Sort Key: o_7."time" DESC
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_7 (actual rows=720.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 813
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=2.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=1.00 loops=3)
                                 Sort Key: o_8."time" DESC
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_8 (actual rows=2160.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 2438
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=5.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=1.00 loops=3)
                                 Sort Key: o_9."time" DESC
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_9 (actual rows=720.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 813
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=2.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))

-- test LATERAL with correlated query
-- only 2nd chunk should be executed
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-10'::timestamptz, '2000-01-11', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
  ORDER BY time
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=2.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=2.00 loops=1)
   ->  Limit (actual rows=1.00 loops=2)
         ->  Result (actual rows=1.00 loops=2)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o (actual rows=1.00 loops=2)
                     Order: o."time"
                     ->  Merge Append (actual rows=0.00 loops=2)
                           Sort Key: o."time"
                           ->  Sort (actual rows=0.00 loops=2)
                                 Sort Key: o_1."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=2)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=2)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=2)
                                 Sort Key: o_2."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_2 (actual rows=0.00 loops=2)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=2)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=2)
                                 Sort Key: o_3."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_3 (actual rows=0.00 loops=2)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=2)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                     ->  Merge Append (actual rows=1.00 loops=2)
                           Sort Key: o."time"
                           ->  Sort (actual rows=1.00 loops=2)
                                 Sort Key: o_4."time"
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_4 (actual rows=720.00 loops=2)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 780
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=2.00 loops=2)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=1.00 loops=2)
                                 Sort Key: o_5."time"
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_5 (actual rows=2160.00 loops=2)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 2340
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=4.00 loops=2)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=1.00 loops=2)
                                 Sort Key: o_6."time"
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_6 (actual rows=720.00 loops=2)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 780
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=2.00 loops=2)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                     ->  Merge Append (never executed)
                           Sort Key: o."time"
                           ->  Sort (never executed)
                                 Sort Key: o_7."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_7 (never executed)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (never executed)
                                 Sort Key: o_8."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_8 (never executed)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (never executed)
                                 Sort Key: o_9."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_9 (never executed)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time"))

-- test startup and runtime exclusion together
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
    AND o.time < now()
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=1.00 loops=3)
         ->  Result (actual rows=1.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o (actual rows=1.00 loops=3)
                     Order: o."time" DESC
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_1."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_2."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_2 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_3."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_3 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_4."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_4 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_5."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_5 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_6."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_6 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))
                     ->  Merge Append (actual rows=1.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=1.00 loops=3)
                                 Sort Key: o_7."time" DESC
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_7 (actual rows=720.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 813
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=2.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=1.00 loops=3)
                                 Sort Key: o_8."time" DESC
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_8 (actual rows=2160.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 2438
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=5.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))
                           ->  Sort (actual rows=1.00 loops=3)
                                 Sort Key: o_9."time" DESC
                                 Sort Method: top-N heapsort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_9 (actual rows=720.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Rows Removed by Filter: 813
                                       Vectorized Filter: ("time" < now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=2.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_min_1 < now()) AND (_ts_meta_max_1 >= g."time"))

-- test startup and runtime exclusion together
-- all chunks should be filtered
:PREFIX
SELECT g.time,
  l.time
FROM generate_series('2000-01-01'::timestamptz, '2000-01-03', '1d') AS g (time)
  LEFT OUTER JOIN LATERAL (
  SELECT *
  FROM :TEST_TABLE o
  WHERE o.time >= g.time
    AND o.time < g.time + '1d'::interval
    AND o.time > now()
  ORDER BY time DESC
  LIMIT 1) l ON TRUE;
--- QUERY PLAN ---
 Nested Loop Left Join (actual rows=3.00 loops=1)
   ->  Function Scan on generate_series g (actual rows=3.00 loops=1)
   ->  Limit (actual rows=0.00 loops=3)
         ->  Result (actual rows=0.00 loops=3)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o (actual rows=0.00 loops=3)
                     Order: o."time" DESC
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_1."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_1 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_2."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_2 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_3."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_3 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_4."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_4 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_5."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_5 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_6."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_6 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))
                     ->  Merge Append (actual rows=0.00 loops=3)
                           Sort Key: o."time" DESC
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_7."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_7 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_8."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_8 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))
                           ->  Sort (actual rows=0.00 loops=3)
                                 Sort Key: o_9."time" DESC
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o_9 (actual rows=0.00 loops=3)
                                       Filter: (("time" >= g."time") AND ("time" < (g."time" + '@ 1 day'::interval)))
                                       Vectorized Filter: ("time" > now())
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=0.00 loops=3)
                                             Index Cond: ((_ts_meta_min_1 < (g."time" + '@ 1 day'::interval)) AND (_ts_meta_max_1 >= g."time") AND (_ts_meta_max_1 > now()))

-- test JOIN
-- no exclusion on joined table because quals are not propagated yet
-- With PG 14 on i368, this query uses a nested loop join. Disable the nested loop join to get the same query plan in all tests
SET enable_nestloop TO off;
:PREFIX
SELECT o1.time,
  o2.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.time < '2000-02-01'
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time;
--- QUERY PLAN ---
 Merge Join (actual rows=13674.00 loops=1)
   Merge Cond: (o1."time" = o2."time")
   ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=13674.00 loops=1)
         Order: o1."time"
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=3598.00 loops=1)
               Vectorized Filter: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=4.00 loops=1)
                     Index Cond: ((device_id = 1) AND (_ts_meta_min_1 < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (actual rows=5038.00 loops=1)
               Vectorized Filter: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                     Index Cond: ((device_id = 1) AND (_ts_meta_min_1 < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (actual rows=5038.00 loops=1)
               Vectorized Filter: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                     Index Cond: ((device_id = 1) AND (_ts_meta_min_1 < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))
   ->  Materialize (actual rows=13674.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=13674.00 loops=1)
               Order: o2."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=3598.00 loops=1)
                     Vectorized Filter: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=4.00 loops=1)
                           Index Cond: ((device_id = 2) AND (_ts_meta_min_1 < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (actual rows=5038.00 loops=1)
                     Vectorized Filter: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                           Index Cond: ((device_id = 2) AND (_ts_meta_min_1 < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (actual rows=5038.00 loops=1)
                     Vectorized Filter: ("time" < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                           Index Cond: ((device_id = 2) AND (_ts_meta_min_1 < 'Tue Feb 01 00:00:00 2000 PST'::timestamp with time zone))

-- test JOIN
-- last chunk of o2 should not be executed
:PREFIX
SELECT o1.time,
  o2.time
FROM :TEST_TABLE o1
  INNER JOIN (
    SELECT *
    FROM :TEST_TABLE o2
    ORDER BY time) o2 ON o1.time = o2.time
WHERE o1.time < '2000-01-08'
ORDER BY o1.time
LIMIT 10;
--- QUERY PLAN ---
 Limit (actual rows=10.00 loops=1)
   ->  Merge Join (actual rows=10.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=2.00 loops=1)
               Order: o1."time"
               ->  Merge Append (actual rows=2.00 loops=1)
                     Sort Key: o1."time"
                     ->  Sort (actual rows=2.00 loops=1)
                           Sort Key: o1_1."time"
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=3598.00 loops=1)
                                 Vectorized Filter: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=4.00 loops=1)
                                       Filter: (_ts_meta_min_1 < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Sort (actual rows=1.00 loops=1)
                           Sort Key: o1_2."time"
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (actual rows=10794.00 loops=1)
                                 Vectorized Filter: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=12.00 loops=1)
                                       Filter: (_ts_meta_min_1 < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Sort (actual rows=1.00 loops=1)
                           Sort Key: o1_3."time"
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (actual rows=3598.00 loops=1)
                                 Vectorized Filter: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=4.00 loops=1)
                                       Filter: (_ts_meta_min_1 < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
               ->  Merge Append (never executed)
                     Sort Key: o1."time"
                     ->  Sort (never executed)
                           Sort Key: o1_4."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_4 (never executed)
                                 Vectorized Filter: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: (_ts_meta_min_1 < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Sort (never executed)
                           Sort Key: o1_5."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_5 (never executed)
                                 Vectorized Filter: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: (_ts_meta_min_1 < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                     ->  Sort (never executed)
                           Sort Key: o1_6."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_6 (never executed)
                                 Vectorized Filter: ("time" < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
                                 ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                       Filter: (_ts_meta_min_1 < 'Sat Jan 08 00:00:00 2000 PST'::timestamp with time zone)
         ->  Materialize (actual rows=10.00 loops=1)
               ->  Result (actual rows=6.00 loops=1)
                     ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=6.00 loops=1)
                           Order: o2."time"
                           ->  Merge Append (actual rows=6.00 loops=1)
                                 Sort Key: o2."time"
                                 ->  Sort (actual rows=2.00 loops=1)
                                       Sort Key: o2_1."time"
                                       Sort Method: quicksort 
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=3598.00 loops=1)
                                             ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=4.00 loops=1)
                                 ->  Sort (actual rows=4.00 loops=1)
                                       Sort Key: o2_2."time"
                                       Sort Method: quicksort 
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (actual rows=10794.00 loops=1)
                                             ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=12.00 loops=1)
                                 ->  Sort (actual rows=2.00 loops=1)
                                       Sort Key: o2_3."time"
                                       Sort Method: quicksort 
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (actual rows=3598.00 loops=1)
                                             ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=4.00 loops=1)
                           ->  Merge Append (never executed)
                                 Sort Key: o2."time"
                                 ->  Sort (never executed)
                                       Sort Key: o2_4."time"
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_4 (never executed)
                                             ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                 ->  Sort (never executed)
                                       Sort Key: o2_5."time"
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_5 (never executed)
                                             ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                 ->  Sort (never executed)
                                       Sort Key: o2_6."time"
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_6 (never executed)
                                             ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           ->  Merge Append (never executed)
                                 Sort Key: o2."time"
                                 ->  Sort (never executed)
                                       Sort Key: o2_7."time"
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_7 (never executed)
                                             ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                 ->  Sort (never executed)
                                       Sort Key: o2_8."time"
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_8 (never executed)
                                             ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                 ->  Sort (never executed)
                                       Sort Key: o2_9."time"
                                       ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_9 (never executed)
                                             ->  Seq Scan on compress_hyper_X_X_chunk (never executed)

-- test join against max query
-- not ChunkAppend so no chunk exclusion
SET enable_hashjoin = FALSE;
SET enable_hashagg = FALSE;
:PREFIX
SELECT o1.time,
  o2.*
FROM :TEST_TABLE o1
  INNER JOIN (
    SELECT max(time) AS max_time
    FROM :TEST_TABLE) o2 ON o1.time = o2.max_time
WHERE o1.device_id = 1
ORDER BY time;
--- QUERY PLAN ---
 Merge Join (actual rows=1.00 loops=1)
   Merge Cond: (o1."time" = ($0))
   ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=13674.00 loops=1)
         Order: o1."time"
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=3598.00 loops=1)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=4.00 loops=1)
                     Index Cond: (device_id = 1)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (actual rows=5038.00 loops=1)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                     Index Cond: (device_id = 1)
         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (actual rows=5038.00 loops=1)
               ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                     Index Cond: (device_id = 1)
   ->  Sort (actual rows=1.00 loops=1)
         Sort Key: ($0)
         Sort Method: quicksort 
         ->  Result (actual rows=1.00 loops=1)
               InitPlan 1 (returns $0)
                 ->  Limit (actual rows=1.00 loops=1)
                       ->  Custom Scan (ChunkAppend) on metrics_space_compressed (actual rows=1.00 loops=1)
                             Order: metrics_space_compressed."time" DESC
                             ->  Merge Append (actual rows=1.00 loops=1)
                                   Sort Key: metrics_space_compressed."time" DESC
                                   ->  Sort (actual rows=1.00 loops=1)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         Sort Method: top-N heapsort 
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=5038.00 loops=1)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=6.00 loops=1)
                                   ->  Sort (actual rows=1.00 loops=1)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         Sort Method: top-N heapsort 
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=15114.00 loops=1)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk (actual rows=18.00 loops=1)
                                   ->  Sort (actual rows=1.00 loops=1)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         Sort Method: top-N heapsort 
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (actual rows=5038.00 loops=1)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=6.00 loops=1)
                             ->  Merge Append (never executed)
                                   Sort Key: metrics_space_compressed."time" DESC
                                   ->  Sort (never executed)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                   ->  Sort (never executed)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                   ->  Sort (never executed)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                             ->  Merge Append (never executed)
                                   Sort Key: metrics_space_compressed."time" DESC
                                   ->  Sort (never executed)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                   ->  Sort (never executed)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk (never executed)
                                   ->  Sort (never executed)
                                         Sort Key: _hyper_X_X_chunk."time" DESC
                                         ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk (never executed)
                                               Vectorized Filter: ("time" IS NOT NULL)
                                               ->  Seq Scan on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)

RESET enable_hashjoin;
RESET enable_hashagg;
SET enable_seqscan TO false;
-- test JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)

-- test JOIN on time column with USING
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 USING (time)
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)

-- test NATURAL JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  NATURAL INNER JOIN :TEST_TABLE o2
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=0.00 loops=1)
   ->  Sort (actual rows=0.00 loops=1)
         Sort Key: o1."time"
         Sort Method: quicksort 
         ->  Result (actual rows=0.00 loops=1)
               One-Time Filter: false

-- test LEFT JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  LEFT JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)

-- test RIGHT JOIN on time column
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  RIGHT JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o2.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)

-- test JOIN on time column with ON clause expression order switched
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o2.time = o1.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)

-- test JOIN on time column with equality condition in WHERE clause
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON TRUE
WHERE o1.time = o2.time
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)

-- test JOIN on time column with ORDER BY 2nd hypertable
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o2.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)

-- test JOIN on time column and device_id
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.device_id = o2.device_id
    AND o1.time = o2.time
  ORDER BY o1.time
  LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         Join Filter: (o1.device_id = o2.device_id)
         Rows Removed by Join Filter: 400
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Merge Append (actual rows=100.00 loops=1)
                     Sort Key: o1."time"
                     ->  Sort (actual rows=21.00 loops=1)
                           Sort Key: o1_1."time"
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=3598.00 loops=1)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=4.00 loops=1)
                     ->  Sort (actual rows=60.00 loops=1)
                           Sort Key: o1_2."time"
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (actual rows=10794.00 loops=1)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=12.00 loops=1)
                     ->  Sort (actual rows=21.00 loops=1)
                           Sort Key: o1_3."time"
                           Sort Method: quicksort 
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (actual rows=3598.00 loops=1)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=4.00 loops=1)
               ->  Merge Append (never executed)
                     Sort Key: o1."time"
                     ->  Sort (never executed)
                           Sort Key: o1_4."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_4 (never executed)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                     ->  Sort (never executed)
                           Sort Key: o1_5."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_5 (never executed)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                     ->  Sort (never executed)
                           Sort Key: o1_6."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_6 (never executed)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
               ->  Merge Append (never executed)
                     Sort Key: o1."time"
                     ->  Sort (never executed)
                           Sort Key: o1_7."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_7 (never executed)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                     ->  Sort (never executed)
                           Sort Key: o1_8."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_8 (never executed)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                     ->  Sort (never executed)
                           Sort Key: o1_9."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_9 (never executed)
                                 ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=500.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=101.00 loops=1)
                     Order: o2."time"
                     ->  Merge Append (actual rows=101.00 loops=1)
                           Sort Key: o2."time"
                           ->  Sort (actual rows=21.00 loops=1)
                                 Sort Key: o2_1."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=3598.00 loops=1)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=4.00 loops=1)
                           ->  Sort (actual rows=61.00 loops=1)
                                 Sort Key: o2_2."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (actual rows=10794.00 loops=1)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=12.00 loops=1)
                           ->  Sort (actual rows=21.00 loops=1)
                                 Sort Key: o2_3."time"
                                 Sort Method: quicksort 
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (actual rows=3598.00 loops=1)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=4.00 loops=1)
                     ->  Merge Append (never executed)
                           Sort Key: o2."time"
                           ->  Sort (never executed)
                                 Sort Key: o2_4."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_4 (never executed)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           ->  Sort (never executed)
                                 Sort Key: o2_5."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_5 (never executed)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           ->  Sort (never executed)
                                 Sort Key: o2_6."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_6 (never executed)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                     ->  Merge Append (never executed)
                           Sort Key: o2."time"
                           ->  Sort (never executed)
                                 Sort Key: o2_7."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_7 (never executed)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           ->  Sort (never executed)
                                 Sort Key: o2_8."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_8 (never executed)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                           ->  Sort (never executed)
                                 Sort Key: o2_9."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_9 (never executed)
                                       ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)

-- test JOIN on device_id
-- should not use ordered append for 2nd hypertable
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.device_id = o2.device_id
WHERE o1.device_id = 1
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Nested Loop (actual rows=100.00 loops=1)
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=1.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=1.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Append (actual rows=100.00 loops=1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                 Index Cond: (device_id = 1)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk compress_hyper_X_X_chunk_1 (never executed)
                                 Index Cond: (device_id = 1)

-- test JOIN on time column with implicit join
-- should use 2 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1,
  :TEST_TABLE o2
WHERE o1.time = o2.time
  AND o1.device_id = 1
  AND o2.device_id = 2
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o1."time" = o2."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
               Order: o1."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 1)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                     Order: o2."time"
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)
                     ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                           ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                 Index Cond: (device_id = 2)

-- test JOIN on time column with 3 hypertables
-- should use 3 ChunkAppend
:PREFIX
SELECT o1.time
FROM :TEST_TABLE o1
  INNER JOIN :TEST_TABLE o2 ON o1.time = o2.time
  INNER JOIN :TEST_TABLE o3 ON o1.time = o3.time
WHERE o1.device_id = 1
  AND o2.device_id = 2
  AND o3.device_id = 3
ORDER BY o1.time
LIMIT 100;
--- QUERY PLAN ---
 Limit (actual rows=100.00 loops=1)
   ->  Merge Join (actual rows=100.00 loops=1)
         Merge Cond: (o3."time" = o1."time")
         ->  Custom Scan (ChunkAppend) on metrics_space_compressed o3 (actual rows=100.00 loops=1)
               Order: o3."time"
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o3_1 (actual rows=100.00 loops=1)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                           Index Cond: (device_id = 3)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o3_2 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 3)
               ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o3_3 (never executed)
                     ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                           Index Cond: (device_id = 3)
         ->  Materialize (actual rows=100.00 loops=1)
               ->  Merge Join (actual rows=100.00 loops=1)
                     Merge Cond: (o1."time" = o2."time")
                     ->  Custom Scan (ChunkAppend) on metrics_space_compressed o1 (actual rows=100.00 loops=1)
                           Order: o1."time"
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_1 (actual rows=100.00 loops=1)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                       Index Cond: (device_id = 1)
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_2 (never executed)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                       Index Cond: (device_id = 1)
                           ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o1_3 (never executed)
                                 ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                       Index Cond: (device_id = 1)
                     ->  Materialize (actual rows=100.00 loops=1)
                           ->  Custom Scan (ChunkAppend) on metrics_space_compressed o2 (actual rows=100.00 loops=1)
                                 Order: o2."time"
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_1 (actual rows=100.00 loops=1)
                                       ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (actual rows=1.00 loops=1)
                                             Index Cond: (device_id = 2)
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_2 (never executed)
                                       ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                             Index Cond: (device_id = 2)
                                 ->  Custom Scan (ColumnarScan) on _hyper_X_X_chunk o2_3 (never executed)
                                       ->  Index Scan Backward using compress_hyper_X_X_chunk_device_id__ts_meta_min_1__ts_meta_idx on compress_hyper_X_X_chunk (never executed)
                                             Index Cond: (device_id = 2)

RESET enable_seqscan;
-- Disable plain/sorted aggregation to get a deterministic test output
SET timescaledb.enable_chunkwise_aggregation = OFF;
-- get results for all the queries
-- run queries on uncompressed hypertable and store result
\set PREFIX ''
\set PREFIX_VERBOSE ''
\set ECHO none
-- #4418
-- test ordered append planning when inner join 2 hypertables on time column
CREATE table i4418_1(time timestamptz, device text);
CREATE table i4418_2(time timestamptz, device text);
SELECT table_name FROM create_hypertable('i4418_1','time');
 table_name 
------------
 i4418_1

SELECT table_name FROM create_hypertable('i4418_2','time');
 table_name 
------------
 i4418_2

INSERT INTO i4418_1 SELECT time, 'device 1' FROM generate_series('2022-08-01'::timestamptz, '2022-08-20'::timestamptz,'3min'::interval) g(time);
INSERT INTO i4418_2 SELECT * FROM i4418_1;
EXPLAIN (analyze,buffers off, costs off,timing off,summary off) SELECT time_bucket('1d', tbl1.time), count(*)
FROM i4418_1 tbl1
INNER JOIN i4418_2 tbl2
ON tbl1.device = tbl2.device AND tbl1.time = tbl2.time
GROUP BY 1 ORDER BY 1;
--- QUERY PLAN ---
 Sort (actual rows=20.00 loops=1)
   Sort Key: (time_bucket('@ 1 day'::interval, tbl1."time"))
   Sort Method: quicksort 
   ->  HashAggregate (actual rows=20.00 loops=1)
         Group Key: time_bucket('@ 1 day'::interval, tbl1."time")
         ->  Merge Join (actual rows=9121.00 loops=1)
               Merge Cond: ((tbl1.device = tbl2.device) AND (tbl1."time" = tbl2."time"))
               ->  Sort (actual rows=9121.00 loops=1)
                     Sort Key: tbl1.device, tbl1."time"
                     Sort Method: quicksort 
                     ->  Append (actual rows=9121.00 loops=1)
                           ->  Seq Scan on _hyper_X_X_chunk tbl1_1 (actual rows=1300.00 loops=1)
                           ->  Seq Scan on _hyper_X_X_chunk tbl1_2 (actual rows=3360.00 loops=1)
                           ->  Seq Scan on _hyper_X_X_chunk tbl1_3 (actual rows=3360.00 loops=1)
                           ->  Seq Scan on _hyper_X_X_chunk tbl1_4 (actual rows=1101.00 loops=1)
               ->  Sort (actual rows=9121.00 loops=1)
                     Sort Key: tbl2.device, tbl2."time"
                     Sort Method: quicksort 
                     ->  Append (actual rows=9121.00 loops=1)
                           ->  Seq Scan on _hyper_X_X_chunk tbl2_1 (actual rows=1300.00 loops=1)
                           ->  Seq Scan on _hyper_X_X_chunk tbl2_2 (actual rows=3360.00 loops=1)
                           ->  Seq Scan on _hyper_X_X_chunk tbl2_3 (actual rows=3360.00 loops=1)
                           ->  Seq Scan on _hyper_X_X_chunk tbl2_4 (actual rows=1101.00 loops=1)

DROP TABLE i4418_1;
DROP TABLE i4418_2;
reset enable_nestloop;
-- Ordered append with cross-type mergejoinable equality operator.
create table dates(ts date) with (timescaledb.hypertable, timescaledb.partition_column = ts);
insert into dates values ('2021-01-01'), ('2022-02-02'), ('2023-03-03');
create table times(ts timestamp) with (timescaledb.hypertable, timescaledb.partition_column = ts);
insert into times values ('2021-01-01 00:00:01'), ('2022-02-02 00:00:00'), ('2023-03-03 00:00:00');
explain (analyze, costs off, buffers off, summary off, timing off)
select * from dates natural join times where ts > '2021-01-01';
--- QUERY PLAN ---
 Merge Join (actual rows=2.00 loops=1)
   Merge Cond: (times.ts = dates.ts)
   ->  Merge Append (actual rows=3.00 loops=1)
         Sort Key: times.ts
         ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               Index Cond: (ts > 'Fri Jan 01 00:00:00 2021'::timestamp without time zone)
         ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
         ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
   ->  Materialize (actual rows=3.00 loops=1)
         ->  Merge Append (actual rows=3.00 loops=1)
               Sort Key: dates.ts
               ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)

explain (analyze, costs off, buffers off, summary off, timing off)
select * from dates natural join times where ts > '2021-01-01' order by ts;
--- QUERY PLAN ---
 Merge Join (actual rows=2.00 loops=1)
   Merge Cond: (times.ts = dates.ts)
   ->  Custom Scan (ChunkAppend) on times (actual rows=3.00 loops=1)
         Order: times.ts
         ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               Index Cond: (ts > 'Fri Jan 01 00:00:00 2021'::timestamp without time zone)
         ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
         ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
   ->  Materialize (actual rows=3.00 loops=1)
         ->  Custom Scan (ChunkAppend) on dates (actual rows=3.00 loops=1)
               Order: dates.ts
               ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)

explain (analyze, costs off, buffers off, summary off, timing off)
select * from dates natural join times where ts > '2021-01-01' order by ts limit 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Merge Join (actual rows=1.00 loops=1)
         Merge Cond: (times.ts = dates.ts)
         ->  Custom Scan (ChunkAppend) on times (actual rows=2.00 loops=1)
               Order: times.ts
               ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     Index Cond: (ts > 'Fri Jan 01 00:00:00 2021'::timestamp without time zone)
               ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=2.00 loops=1)
               ->  Custom Scan (ChunkAppend) on dates (actual rows=2.00 loops=1)
                     Order: dates.ts
                     ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (never executed)

explain (analyze, costs off, buffers off, summary off, timing off)
select * from dates natural join times where ts > '2021-01-01' order by ts desc limit 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Merge Join (actual rows=1.00 loops=1)
         Merge Cond: (times.ts = dates.ts)
         ->  Custom Scan (ChunkAppend) on times (actual rows=1.00 loops=1)
               Order: times.ts DESC
               ->  Index Scan using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (never executed)
               ->  Index Scan using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (never executed)
                     Index Cond: (ts > 'Fri Jan 01 00:00:00 2021'::timestamp without time zone)
         ->  Materialize (actual rows=1.00 loops=1)
               ->  Custom Scan (ChunkAppend) on dates (actual rows=1.00 loops=1)
                     Order: dates.ts DESC
                     ->  Index Scan using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     ->  Index Scan using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (never executed)
                     ->  Index Scan using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (never executed)

explain (analyze, costs off, buffers off, summary off, timing off)
select * from dates join times on times.ts = dates.ts where times.ts > '2021-01-01' order by times.ts desc limit 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Merge Join (actual rows=1.00 loops=1)
         Merge Cond: (times.ts = dates.ts)
         ->  Custom Scan (ChunkAppend) on times (actual rows=1.00 loops=1)
               Order: times.ts DESC
               ->  Index Scan using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (never executed)
               ->  Index Scan using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (never executed)
                     Index Cond: (ts > 'Fri Jan 01 00:00:00 2021'::timestamp without time zone)
         ->  Materialize (actual rows=1.00 loops=1)
               ->  Custom Scan (ChunkAppend) on dates (actual rows=1.00 loops=1)
                     Order: dates.ts DESC
                     ->  Index Scan using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     ->  Index Scan using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (never executed)
                     ->  Index Scan using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (never executed)

explain (analyze, costs off, buffers off, summary off, timing off)
select * from dates join times on times.ts = dates.ts where times.ts > '2021-01-01' order by dates.ts limit 1;
--- QUERY PLAN ---
 Limit (actual rows=1.00 loops=1)
   ->  Merge Join (actual rows=1.00 loops=1)
         Merge Cond: (times.ts = dates.ts)
         ->  Custom Scan (ChunkAppend) on times (actual rows=2.00 loops=1)
               Order: times.ts
               ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     Index Cond: (ts > 'Fri Jan 01 00:00:00 2021'::timestamp without time zone)
               ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
               ->  Index Scan Backward using _hyper_X_X_chunk_times_ts_idx on _hyper_X_X_chunk (never executed)
         ->  Materialize (actual rows=2.00 loops=1)
               ->  Custom Scan (ChunkAppend) on dates (actual rows=2.00 loops=1)
                     Order: dates.ts
                     ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (actual rows=1.00 loops=1)
                     ->  Index Scan Backward using _hyper_X_X_chunk_dates_ts_idx on _hyper_X_X_chunk (never executed)

drop table dates;
drop table times;
