--
-- Test chunk filtering in columnar using min/max values in stripe skip lists.
--
-- It has an alternative test output file
-- because PG16 changed the order of some Filters in EXPLAIN
-- Relevant PG commit:
-- https://github.com/postgres/postgres/commit/2489d76c4906f4461a364ca8ad7e0751ead8aa0d
--
-- filtered_row_count returns number of rows filtered by the WHERE clause.
-- If chunks get filtered by columnar, less rows are passed to WHERE
-- clause, so this function should return a lower number.
--
CREATE OR REPLACE FUNCTION filtered_row_count (query text) RETURNS bigint AS
$$
    DECLARE
        result bigint;
        rec text;
    BEGIN
        result := 0;

        FOR rec IN EXECUTE 'EXPLAIN ANALYZE ' || query LOOP
            IF rec ~ '^\s+Rows Removed by Filter' then
                result := regexp_replace(rec, '[^0-9]*', '', 'g');
            END IF;
        END LOOP;

        RETURN result;
    END;
$$ LANGUAGE PLPGSQL;
set columnar.qual_pushdown_correlation = 0.0;
-- Create and load data
-- chunk_group_row_limit '1000', stripe_row_limit '2000'
set columnar.stripe_row_limit = 2000;
set columnar.chunk_group_row_limit = 1000;
CREATE TABLE test_chunk_filtering (a int)
    USING columnar;
INSERT INTO test_chunk_filtering SELECT generate_series(1,10000);
-- Verify that filtered_row_count is less than 1000 for the following queries
SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering');
 filtered_row_count
---------------------------------------------------------------------
                  0
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a < 200');
 filtered_row_count
---------------------------------------------------------------------
                801
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a > 200');
 filtered_row_count
---------------------------------------------------------------------
                200
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a < 9900');
 filtered_row_count
---------------------------------------------------------------------
                101
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a > 9900');
 filtered_row_count
---------------------------------------------------------------------
                900
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a < 0');
 filtered_row_count
---------------------------------------------------------------------
                  0
(1 row)

-- Verify that filtered_row_count is less than 2000 for the following queries
SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a BETWEEN 1 AND 10');
 filtered_row_count
---------------------------------------------------------------------
                990
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a BETWEEN 990 AND 2010');
 filtered_row_count
---------------------------------------------------------------------
               1979
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a BETWEEN -10 AND 0');
 filtered_row_count
---------------------------------------------------------------------
                  0
(1 row)

-- Load data for second time and verify that filtered_row_count is exactly twice as before
INSERT INTO test_chunk_filtering SELECT generate_series(1,10000);
SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a < 200');
 filtered_row_count
---------------------------------------------------------------------
               1602
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a < 0');
 filtered_row_count
---------------------------------------------------------------------
                  0
(1 row)

SELECT filtered_row_count('SELECT count(*) FROM test_chunk_filtering WHERE a BETWEEN 990 AND 2010');
 filtered_row_count
---------------------------------------------------------------------
               3958
(1 row)

set columnar.stripe_row_limit to default;
set columnar.chunk_group_row_limit to default;
-- Verify that we are fine with collations which use a different alphabet order
CREATE TABLE collation_chunk_filtering_test(A text collate "da_DK")
    USING columnar;
COPY collation_chunk_filtering_test FROM STDIN;
SELECT * FROM collation_chunk_filtering_test WHERE A > 'B';
 a
---------------------------------------------------------------------
 Å
(1 row)

CREATE TABLE simple_chunk_filtering(i int) USING COLUMNAR;
INSERT INTO simple_chunk_filtering SELECT generate_series(0,234567);
EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT * FROM simple_chunk_filtering WHERE i > 123456;
                                    QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on simple_chunk_filtering (actual rows=111111 loops=1)
   Filter: (i > 123456)
   Rows Removed by Filter: 3457
   Columnar Projected Columns: i
   Columnar Chunk Group Filters: (i > 123456)
   Columnar Chunk Groups Removed by Filter: 12
(6 rows)

SET columnar.enable_qual_pushdown = false;
EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT * FROM simple_chunk_filtering WHERE i > 123456;
                                    QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on simple_chunk_filtering (actual rows=111111 loops=1)
   Filter: (i > 123456)
   Rows Removed by Filter: 123457
   Columnar Projected Columns: i
(4 rows)

SET columnar.enable_qual_pushdown TO DEFAULT;
-- https://github.com/citusdata/citus/issues/4555
TRUNCATE simple_chunk_filtering;
INSERT INTO simple_chunk_filtering SELECT generate_series(0,200000);
COPY (SELECT * FROM simple_chunk_filtering WHERE i > 180000) TO '/dev/null';
EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT * FROM simple_chunk_filtering WHERE i > 180000;
                                    QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on simple_chunk_filtering (actual rows=20000 loops=1)
   Filter: (i > 180000)
   Rows Removed by Filter: 1
   Columnar Projected Columns: i
   Columnar Chunk Group Filters: (i > 180000)
   Columnar Chunk Groups Removed by Filter: 18
(6 rows)

DROP TABLE simple_chunk_filtering;
CREATE TABLE multi_column_chunk_filtering(a int, b int) USING columnar;
INSERT INTO multi_column_chunk_filtering SELECT i,i+1 FROM generate_series(0,234567) i;
EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT count(*) FROM multi_column_chunk_filtering WHERE a > 50000;
                                          QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on multi_column_chunk_filtering (actual rows=184567 loops=1)
         Filter: (a > 50000)
         Rows Removed by Filter: 1
         Columnar Projected Columns: a
         Columnar Chunk Group Filters: (a > 50000)
         Columnar Chunk Groups Removed by Filter: 5
(7 rows)

EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT count(*) FROM multi_column_chunk_filtering WHERE a > 50000 AND b > 50000;
                                          QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on multi_column_chunk_filtering (actual rows=184567 loops=1)
         Filter: ((a > 50000) AND (b > 50000))
         Rows Removed by Filter: 1
         Columnar Projected Columns: a, b
         Columnar Chunk Group Filters: ((a > 50000) AND (b > 50000))
         Columnar Chunk Groups Removed by Filter: 5
(7 rows)

-- make next tests faster
TRUNCATE multi_column_chunk_filtering;
INSERT INTO multi_column_chunk_filtering SELECT generate_series(0,5);
EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT b FROM multi_column_chunk_filtering WHERE a > 50000 AND b > 50000;
                                     QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on multi_column_chunk_filtering (actual rows=0 loops=1)
   Filter: ((a > 50000) AND (b > 50000))
   Columnar Projected Columns: a, b
   Columnar Chunk Group Filters: ((a > 50000) AND (b > 50000))
   Columnar Chunk Groups Removed by Filter: 1
(5 rows)

EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT b, a FROM multi_column_chunk_filtering WHERE b > 50000;
                                     QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on multi_column_chunk_filtering (actual rows=0 loops=1)
   Filter: (b > 50000)
   Rows Removed by Filter: 6
   Columnar Projected Columns: a, b
   Columnar Chunk Group Filters: (b > 50000)
   Columnar Chunk Groups Removed by Filter: 0
(6 rows)

EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT FROM multi_column_chunk_filtering WHERE a > 50000;
                                     QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on multi_column_chunk_filtering (actual rows=0 loops=1)
   Filter: (a > 50000)
   Columnar Projected Columns: a
   Columnar Chunk Group Filters: (a > 50000)
   Columnar Chunk Groups Removed by Filter: 1
(5 rows)

EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT FROM multi_column_chunk_filtering;
                                     QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on multi_column_chunk_filtering (actual rows=6 loops=1)
   Columnar Projected Columns: <columnar optimized out all columns>
(2 rows)

BEGIN;
  ALTER TABLE multi_column_chunk_filtering DROP COLUMN a;
  ALTER TABLE multi_column_chunk_filtering DROP COLUMN b;
  EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT * FROM multi_column_chunk_filtering;
                                     QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on multi_column_chunk_filtering (actual rows=6 loops=1)
   Columnar Projected Columns: <columnar optimized out all columns>
(2 rows)

ROLLBACK;
CREATE TABLE another_columnar_table(x int, y int) USING columnar;
INSERT INTO another_columnar_table SELECT generate_series(0,5);
EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT a, y FROM multi_column_chunk_filtering, another_columnar_table WHERE x > 1;
                                        QUERY PLAN
---------------------------------------------------------------------
 Nested Loop (actual rows=24 loops=1)
   ->  Custom Scan (ColumnarScan) on another_columnar_table (actual rows=4 loops=1)
         Filter: (x > 1)
         Rows Removed by Filter: 2
         Columnar Projected Columns: x, y
         Columnar Chunk Group Filters: (x > 1)
         Columnar Chunk Groups Removed by Filter: 0
   ->  Custom Scan (ColumnarScan) on multi_column_chunk_filtering (actual rows=6 loops=4)
         Columnar Projected Columns: a
(9 rows)

EXPLAIN (costs off, timing off, summary off)
  SELECT y, * FROM another_columnar_table;
                      QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on another_columnar_table
   Columnar Projected Columns: x, y
(2 rows)

EXPLAIN (costs off, timing off, summary off)
  SELECT *, x FROM another_columnar_table;
                      QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on another_columnar_table
   Columnar Projected Columns: x, y
(2 rows)

EXPLAIN (costs off, timing off, summary off)
  SELECT y, another_columnar_table FROM another_columnar_table;
                      QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on another_columnar_table
   Columnar Projected Columns: x, y
(2 rows)

EXPLAIN (costs off, timing off, summary off)
  SELECT another_columnar_table, x FROM another_columnar_table;
                      QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on another_columnar_table
   Columnar Projected Columns: x, y
(2 rows)

DROP TABLE multi_column_chunk_filtering, another_columnar_table;
--
-- https://github.com/citusdata/citus/issues/4780
--
create table part_table (id int) partition by range (id);
create table part_1_row partition of part_table for values from (150000) to (160000);
create table part_2_columnar partition of part_table for values from (0) to (150000) using columnar;
insert into part_table select generate_series(1,159999);
select filtered_row_count('select count(*) from part_table where id > 75000');
 filtered_row_count
---------------------------------------------------------------------
               5000
(1 row)

drop table part_table;
-- test join parameterization
set columnar.stripe_row_limit = 2000;
set columnar.chunk_group_row_limit = 1000;
create table r1(id1 int, n1 int); -- row
create table r2(id2 int, n2 int); -- row
create table r3(id3 int, n3 int); -- row
create table r4(id4 int, n4 int); -- row
create table r5(id5 int, n5 int); -- row
create table r6(id6 int, n6 int); -- row
create table r7(id7 int, n7 int); -- row
create table coltest(id int, x1 int, x2 int, x3 int) using columnar;
create table coltest_part(id int, x1 int, x2 int, x3 int)
  partition by range (id);
create table coltest_part0
  partition of coltest_part for values from (0) to (10000)
  using columnar;
create table coltest_part1
  partition of coltest_part for values from (10000) to (20000); -- row
set columnar.stripe_row_limit to default;
set columnar.chunk_group_row_limit to default;
insert into r1 values(1234, 12350);
insert into r1 values(4567, 45000);
insert into r1 values(9101, 176000);
insert into r1 values(14202, 7);
insert into r1 values(18942, 189430);
insert into r2 values(1234, 123502);
insert into r2 values(4567, 450002);
insert into r2 values(9101, 1760002);
insert into r2 values(14202, 72);
insert into r2 values(18942, 1894302);
insert into r3 values(1234, 1235075);
insert into r3 values(4567, 4500075);
insert into r3 values(9101, 17600075);
insert into r3 values(14202, 775);
insert into r3 values(18942, 18943075);
insert into r4 values(1234, -1);
insert into r5 values(1234, -1);
insert into r6 values(1234, -1);
insert into r7 values(1234, -1);
insert into coltest
  select g, g*10, g*100, g*1000 from generate_series(0, 19999) g;
insert into coltest_part
  select g, g*10, g*100, g*1000 from generate_series(0, 19999) g;
ANALYZE r1, r2, r3, coltest, coltest_part;
-- force nested loop
set enable_mergejoin=false;
set enable_hashjoin=false;
set enable_material=false;
-- test different kinds of expressions
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT * FROM r1, coltest WHERE
  id1 = id AND x1 > 15000 AND x1::text > '000000' AND n1 % 10 = 0;
                                     QUERY PLAN
---------------------------------------------------------------------
 Nested Loop (actual rows=3 loops=1)
   ->  Seq Scan on r1 (actual rows=4 loops=1)
         Filter: ((n1 % 10) = 0)
         Rows Removed by Filter: 1
   ->  Custom Scan (ColumnarScan) on coltest (actual rows=1 loops=4)
         Filter: ((x1 > 15000) AND (r1.id1 = id) AND ((x1)::text > '000000'::text))
         Rows Removed by Filter: 999
         Columnar Projected Columns: id, x1, x2, x3
         Columnar Chunk Group Filters: ((x1 > 15000) AND (r1.id1 = id))
         Columnar Chunk Groups Removed by Filter: 19
(10 rows)

SELECT * FROM r1, coltest WHERE
  id1 = id AND x1 > 15000 AND x1::text > '000000' AND n1 % 10 = 0;
  id1  |   n1   |  id   |   x1   |   x2    |    x3
---------------------------------------------------------------------
  4567 |  45000 |  4567 |  45670 |  456700 |  4567000
  9101 | 176000 |  9101 |  91010 |  910100 |  9101000
 18942 | 189430 | 18942 | 189420 | 1894200 | 18942000
(3 rows)

-- test equivalence classes
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT * FROM r1, r2, r3, r4, r5, r6, r7, coltest WHERE
  id = id1 AND id1 = id2 AND id2 = id3 AND id3 = id4 AND
  id4 = id5 AND id5 = id6 AND id6 = id7;
                                         QUERY PLAN
---------------------------------------------------------------------
 Nested Loop (actual rows=1 loops=1)
   Join Filter: (coltest.id = r7.id7)
   ->  Nested Loop (actual rows=1 loops=1)
         Join Filter: (coltest.id = r6.id6)
         ->  Nested Loop (actual rows=1 loops=1)
               Join Filter: (coltest.id = r5.id5)
               ->  Nested Loop (actual rows=1 loops=1)
                     Join Filter: (coltest.id = r4.id4)
                     Rows Removed by Join Filter: 4
                     ->  Nested Loop (actual rows=5 loops=1)
                           ->  Nested Loop (actual rows=5 loops=1)
                                 Join Filter: (r1.id1 = r3.id3)
                                 Rows Removed by Join Filter: 20
                                 ->  Nested Loop (actual rows=5 loops=1)
                                       Join Filter: (r1.id1 = r2.id2)
                                       Rows Removed by Join Filter: 20
                                       ->  Seq Scan on r1 (actual rows=5 loops=1)
                                       ->  Seq Scan on r2 (actual rows=5 loops=5)
                                 ->  Seq Scan on r3 (actual rows=5 loops=5)
                           ->  Custom Scan (ColumnarScan) on coltest (actual rows=1 loops=5)
                                 Filter: (r1.id1 = id)
                                 Rows Removed by Filter: 999
                                 Columnar Projected Columns: id, x1, x2, x3
                                 Columnar Chunk Group Filters: (r1.id1 = id)
                                 Columnar Chunk Groups Removed by Filter: 19
                     ->  Seq Scan on r4 (actual rows=1 loops=5)
               ->  Seq Scan on r5 (actual rows=1 loops=1)
         ->  Seq Scan on r6 (actual rows=1 loops=1)
   ->  Seq Scan on r7 (actual rows=1 loops=1)
(29 rows)

SELECT * FROM r1, r2, r3, r4, r5, r6, r7, coltest WHERE
  id = id1 AND id1 = id2 AND id2 = id3 AND id3 = id4 AND
  id4 = id5 AND id5 = id6 AND id6 = id7;
 id1  |  n1   | id2  |   n2   | id3  |   n3    | id4  | n4 | id5  | n5 | id6  | n6 | id7  | n7 |  id  |  x1   |   x2   |   x3
---------------------------------------------------------------------
 1234 | 12350 | 1234 | 123502 | 1234 | 1235075 | 1234 | -1 | 1234 | -1 | 1234 | -1 | 1234 | -1 | 1234 | 12340 | 123400 | 1234000
(1 row)

-- test path generation with different thresholds
set columnar.planner_debug_level = 'notice';
set columnar.max_custom_scan_paths to 10;
EXPLAIN (costs off, timing off, summary off)
  SELECT * FROM coltest c1, coltest c2, coltest c3, coltest c4 WHERE
    c1.id = c2.id and c1.id = c3.id and c1.id = c4.id;
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  parameterized by rels {c2}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  parameterized by rels {c2, c3}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  parameterized by rels {c2, c3, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  parameterized by rels {c2, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  parameterized by rels {c3}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  parameterized by rels {c3, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  parameterized by rels {c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  parameterized by rels {c1}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  parameterized by rels {c1, c3}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  parameterized by rels {c1, c3, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  parameterized by rels {c1, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  parameterized by rels {c3}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  parameterized by rels {c3, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  parameterized by rels {c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  parameterized by rels {c1}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  parameterized by rels {c1, c2}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  parameterized by rels {c1, c2, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  parameterized by rels {c1, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  parameterized by rels {c2}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  parameterized by rels {c2, c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  parameterized by rels {c4}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  parameterized by rels {c1}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  parameterized by rels {c1, c2}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  parameterized by rels {c1, c2, c3}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  parameterized by rels {c1, c3}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  parameterized by rels {c2}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  parameterized by rels {c2, c3}; 1 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  parameterized by rels {c3}; 1 clauses pushed down
                           QUERY PLAN
---------------------------------------------------------------------
 Nested Loop
   ->  Nested Loop
         ->  Nested Loop
               ->  Custom Scan (ColumnarScan) on coltest c1
                     Columnar Projected Columns: id, x1, x2, x3
               ->  Custom Scan (ColumnarScan) on coltest c2
                     Filter: (c1.id = id)
                     Columnar Projected Columns: id, x1, x2, x3
                     Columnar Chunk Group Filters: (c1.id = id)
         ->  Custom Scan (ColumnarScan) on coltest c3
               Filter: (c1.id = id)
               Columnar Projected Columns: id, x1, x2, x3
               Columnar Chunk Group Filters: (c1.id = id)
   ->  Custom Scan (ColumnarScan) on coltest c4
         Filter: (c1.id = id)
         Columnar Projected Columns: id, x1, x2, x3
         Columnar Chunk Group Filters: (c1.id = id)
(17 rows)

set columnar.max_custom_scan_paths to 2;
EXPLAIN (costs off, timing off, summary off)
  SELECT * FROM coltest c1, coltest c2, coltest c3, coltest c4 WHERE
    c1.id = c2.id and c1.id = c3.id and c1.id = c4.id;
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c2
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c3
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for c4
DETAIL:  unparameterized; 0 clauses pushed down
                           QUERY PLAN
---------------------------------------------------------------------
 Nested Loop
   Join Filter: (c1.id = c4.id)
   ->  Nested Loop
         Join Filter: (c1.id = c3.id)
         ->  Nested Loop
               Join Filter: (c1.id = c2.id)
               ->  Custom Scan (ColumnarScan) on coltest c1
                     Columnar Projected Columns: id, x1, x2, x3
               ->  Custom Scan (ColumnarScan) on coltest c2
                     Columnar Projected Columns: id, x1, x2, x3
         ->  Custom Scan (ColumnarScan) on coltest c3
               Columnar Projected Columns: id, x1, x2, x3
   ->  Custom Scan (ColumnarScan) on coltest c4
         Columnar Projected Columns: id, x1, x2, x3
(14 rows)

set columnar.max_custom_scan_paths to default;
set columnar.planner_debug_level to default;
-- test more complex parameterization
set columnar.planner_debug_level = 'notice';
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT * FROM r1, r2, r3, coltest WHERE
  id1 = id2 AND id2 = id3 AND id3 = id AND
  n1 > x1 AND n2 > x2 AND n3 > x3;
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  parameterized by rels {r1}; 2 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  parameterized by rels {r1, r2}; 3 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  parameterized by rels {r1, r2, r3}; 4 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  parameterized by rels {r1, r3}; 3 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  parameterized by rels {r2}; 2 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  parameterized by rels {r2, r3}; 3 clauses pushed down
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  parameterized by rels {r3}; 2 clauses pushed down
                                     QUERY PLAN
---------------------------------------------------------------------
 Nested Loop (actual rows=3 loops=1)
   Join Filter: ((r3.n3 > coltest.x3) AND (r1.id1 = r3.id3))
   Rows Removed by Join Filter: 12
   ->  Nested Loop (actual rows=3 loops=1)
         Join Filter: ((r2.n2 > coltest.x2) AND (r1.id1 = r2.id2))
         Rows Removed by Join Filter: 12
         ->  Nested Loop (actual rows=3 loops=1)
               ->  Seq Scan on r1 (actual rows=5 loops=1)
               ->  Custom Scan (ColumnarScan) on coltest (actual rows=1 loops=5)
                     Filter: ((r1.n1 > x1) AND (r1.id1 = id))
                     Rows Removed by Filter: 799
                     Columnar Projected Columns: id, x1, x2, x3
                     Columnar Chunk Group Filters: ((r1.n1 > x1) AND (r1.id1 = id))
                     Columnar Chunk Groups Removed by Filter: 19
         ->  Seq Scan on r2 (actual rows=5 loops=3)
   ->  Seq Scan on r3 (actual rows=5 loops=3)
(16 rows)

set columnar.planner_debug_level to default;
SELECT * FROM r1, r2, r3, coltest WHERE
  id1 = id2 AND id2 = id3 AND id3 = id AND
  n1 > x1 AND n2 > x2 AND n3 > x3;
  id1  |   n1   |  id2  |   n2    |  id3  |    n3    |  id   |   x1   |   x2    |    x3
---------------------------------------------------------------------
  1234 |  12350 |  1234 |  123502 |  1234 |  1235075 |  1234 |  12340 |  123400 |  1234000
  9101 | 176000 |  9101 | 1760002 |  9101 | 17600075 |  9101 |  91010 |  910100 |  9101000
 18942 | 189430 | 18942 | 1894302 | 18942 | 18943075 | 18942 | 189420 | 1894200 | 18942000
(3 rows)

-- test partitioning parameterization
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT * FROM r1, coltest_part WHERE
  id1 = id AND n1 > x1;
                                           QUERY PLAN
---------------------------------------------------------------------
 Nested Loop (actual rows=3 loops=1)
   ->  Seq Scan on r1 (actual rows=5 loops=1)
   ->  Append (actual rows=1 loops=5)
         ->  Custom Scan (ColumnarScan) on coltest_part0 coltest_part_1 (actual rows=1 loops=3)
               Filter: ((r1.n1 > x1) AND (r1.id1 = id))
               Rows Removed by Filter: 999
               Columnar Projected Columns: id, x1, x2, x3
               Columnar Chunk Group Filters: ((r1.n1 > x1) AND (r1.id1 = id))
               Columnar Chunk Groups Removed by Filter: 9
         ->  Seq Scan on coltest_part1 coltest_part_2 (actual rows=0 loops=2)
               Filter: ((r1.n1 > x1) AND (r1.id1 = id))
               Rows Removed by Filter: 10000
(12 rows)

SELECT * FROM r1, coltest_part WHERE
  id1 = id AND n1 > x1;
  id1  |   n1   |  id   |   x1   |   x2    |    x3
---------------------------------------------------------------------
  1234 |  12350 |  1234 |  12340 |  123400 |  1234000
  9101 | 176000 |  9101 |  91010 |  910100 |  9101000
 18942 | 189430 | 18942 | 189420 | 1894200 | 18942000
(3 rows)

set enable_mergejoin to default;
set enable_hashjoin to default;
set enable_material to default;
set columnar.planner_debug_level = 'notice';
alter table coltest add column x5 int default (random()*20000)::int;
analyze coltest;
-- test that expressions on whole-row references are not pushed down
select * from coltest where coltest = (1,1,1,1);
NOTICE:  columnar planner: cannot push down clause: var is whole-row reference or system column
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  unparameterized; 0 clauses pushed down
 id | x1 | x2 | x3 | x5
---------------------------------------------------------------------
(0 rows)

-- test that expressions on uncorrelated attributes are not pushed down
set columnar.qual_pushdown_correlation to default;
select * from coltest where x5 = 23484;
NOTICE:  columnar planner: cannot push down clause: absolute correlation (X.YZ) of var attribute 5 is smaller than the value configured in "columnar.qual_pushdown_correlation_threshold" (0.900)
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  unparameterized; 0 clauses pushed down
 id | x1 | x2 | x3 | x5
---------------------------------------------------------------------
(0 rows)

-- test that expressions on volatile functions are not pushed down
create function vol() returns int language plpgsql as $$
BEGIN
  RETURN 1;
END;
$$;
select * from coltest where x3 = vol();
NOTICE:  columnar planner: cannot push down clause: expr contains volatile functions
NOTICE:  columnar planner: adding CustomScan path for coltest
DETAIL:  unparameterized; 0 clauses pushed down
 id | x1 | x2 | x3 | x5
---------------------------------------------------------------------
(0 rows)

EXPLAIN (analyze on, costs off, timing off, summary off)
  SELECT * FROM coltest c1 WHERE ceil(x1) > 4222;
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: adding CustomScan path for c1
DETAIL:  unparameterized; 0 clauses pushed down
                              QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on coltest c1 (actual rows=19577 loops=1)
   Filter: (ceil((x1)::double precision) > '4222'::double precision)
   Rows Removed by Filter: 423
   Columnar Projected Columns: id, x1, x2, x3, x5
(4 rows)

set columnar.planner_debug_level to default;
--
-- https://github.com/citusdata/citus/issues/4488
--
create table columnar_prepared_stmt (x int, y int) using columnar;
insert into columnar_prepared_stmt select s, s from generate_series(1,5000000) s;
prepare foo (int) as select x from columnar_prepared_stmt where x = $1;
execute foo(3);
 x
---------------------------------------------------------------------
 3
(1 row)

execute foo(3);
 x
---------------------------------------------------------------------
 3
(1 row)

execute foo(3);
 x
---------------------------------------------------------------------
 3
(1 row)

execute foo(3);
 x
---------------------------------------------------------------------
 3
(1 row)

select filtered_row_count('execute foo(3)');
 filtered_row_count
---------------------------------------------------------------------
               9999
(1 row)

select filtered_row_count('execute foo(3)');
 filtered_row_count
---------------------------------------------------------------------
               9999
(1 row)

select filtered_row_count('execute foo(3)');
 filtered_row_count
---------------------------------------------------------------------
               9999
(1 row)

select filtered_row_count('execute foo(3)');
 filtered_row_count
---------------------------------------------------------------------
               9999
(1 row)

drop table columnar_prepared_stmt;
--
-- https://github.com/citusdata/citus/issues/5258
--
set default_table_access_method to columnar;
CREATE TABLE atest1 ( a int, b text );
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
INSERT INTO atest1 VALUES (1, 'one');
SELECT * FROM atest1; -- ok
 a |  b
---------------------------------------------------------------------
 1 | one
(1 row)

SELECT * FROM atest2; -- ok
 col1 | col2
---------------------------------------------------------------------
(0 rows)

INSERT INTO atest1 VALUES (2, 'two'); -- ok
INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
 col1 | col2
---------------------------------------------------------------------
(0 rows)

CREATE TABLE t1 (name TEXT, n INTEGER);
CREATE TABLE t2 (name TEXT, n INTEGER);
CREATE TABLE t3 (name TEXT, n INTEGER);
INSERT INTO t1 VALUES ( 'bb', 11 );
INSERT INTO t2 VALUES ( 'bb', 12 );
INSERT INTO t2 VALUES ( 'cc', 22 );
INSERT INTO t2 VALUES ( 'ee', 42 );
INSERT INTO t3 VALUES ( 'bb', 13 );
INSERT INTO t3 VALUES ( 'cc', 23 );
INSERT INTO t3 VALUES ( 'dd', 33 );
SELECT * FROM
(SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1
NATURAL INNER JOIN
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL INNER JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
 name | s1_n | s1_1 | s2_n | s2_2 | s3_n | s3_2
---------------------------------------------------------------------
 bb   |   11 |    1 |   12 |    2 |   13 |    3
(1 row)

CREATE TABLE numrange_test (nr NUMRANGE);
INSERT INTO numrange_test VALUES('[,)');
INSERT INTO numrange_test VALUES('[3,]');
INSERT INTO numrange_test VALUES('[, 5)');
INSERT INTO numrange_test VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test VALUES('empty');
INSERT INTO numrange_test VALUES(numrange(1.7, 1.7, '[]'));
create table numrange_test2(nr numrange);
INSERT INTO numrange_test2 VALUES('[, 5)');
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2,'()'));
INSERT INTO numrange_test2 VALUES('empty');
set enable_nestloop=t;
set enable_hashjoin=f;
set enable_mergejoin=f;
select * from numrange_test natural join numrange_test2 order by nr;
    nr
---------------------------------------------------------------------
 empty
 (,5)
 [1.1,2.2)
 [1.1,2.2)
(4 rows)

DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2;
set default_table_access_method to default;
set columnar.planner_debug_level to notice;
BEGIN;
  SET LOCAL columnar.stripe_row_limit = 2000;
  SET LOCAL columnar.chunk_group_row_limit = 1000;
  create table pushdown_test (a int, b int) using columnar;
  insert into pushdown_test values (generate_series(1, 200000));
COMMIT;
SET columnar.max_custom_scan_paths TO 50;
SET columnar.qual_pushdown_correlation_threshold TO 0.0;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a = 104356 or a = 76556;
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
                                     QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on pushdown_test (actual rows=2 loops=1)
         Filter: ((a = 204356) OR (a = 104356) OR (a = 76556))
         Rows Removed by Filter: 1998
         Columnar Projected Columns: a
         Columnar Chunk Group Filters: ((a = 204356) OR (a = 104356) OR (a = 76556))
         Columnar Chunk Groups Removed by Filter: 198
(7 rows)

SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a = 104356 or a = 76556;
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
  sum
---------------------------------------------------------------------
 180912
(1 row)

EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 194356 or a = 104356 or a = 76556;
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
                                     QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on pushdown_test (actual rows=3 loops=1)
         Filter: ((a = 194356) OR (a = 104356) OR (a = 76556))
         Rows Removed by Filter: 2997
         Columnar Projected Columns: a
         Columnar Chunk Group Filters: ((a = 194356) OR (a = 104356) OR (a = 76556))
         Columnar Chunk Groups Removed by Filter: 197
(7 rows)

SELECT sum(a) FROM pushdown_test WHERE a = 194356 or a = 104356 or a = 76556;
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
  sum
---------------------------------------------------------------------
 375268
(1 row)

EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test WHERE a = 204356 or a > a*-1 + b;
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 0 clauses pushed down
                                QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on pushdown_test (actual rows=0 loops=1)
         Filter: ((a = 204356) OR (a > ((a * '-1'::integer) + b)))
         Rows Removed by Filter: 200000
         Columnar Projected Columns: a, b
(5 rows)

EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > 1000 and a < 10000) or (a > 20000 and a < 50000);
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
                                              QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on pushdown_test (actual rows=38998 loops=1)
         Filter: (((a > 1000) AND (a < 10000)) OR ((a > 20000) AND (a < 50000)))
         Rows Removed by Filter: 2
         Columnar Projected Columns: a
         Columnar Chunk Group Filters: (((a > 1000) AND (a < 10000)) OR ((a > 20000) AND (a < 50000)))
         Columnar Chunk Groups Removed by Filter: 161
(7 rows)

SELECT sum(a) FROM pushdown_test where (a > 1000 and a < 10000) or (a > 20000 and a < 50000);
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
    sum
---------------------------------------------------------------------
 1099459500
(1 row)

EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > random() and a < 2*a) or (a > 100);
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: cannot push down clause: none of the arguments were pushdownable, due to the reason(s) given above
NOTICE:  columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 0 clauses pushed down
                                      QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on pushdown_test (actual rows=200000 loops=1)
         Filter: ((((a)::double precision > random()) AND (a < (2 * a))) OR (a > 100))
         Columnar Projected Columns: a
(4 rows)

SELECT sum(a) FROM pushdown_test where (a > random() and a < 2*a) or (a > 100);
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: cannot push down clause: none of the arguments were pushdownable, due to the reason(s) given above
NOTICE:  columnar planner: cannot push down clause: all arguments of an OR expression must be pushdownable but one of them was not, due to the reason given above
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 0 clauses pushed down
     sum
---------------------------------------------------------------------
 20000100000
(1 row)

EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a > random() and a <= 2000) or (a > 200000-1010);
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
                                       QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on pushdown_test (actual rows=3010 loops=1)
         Filter: ((((a)::double precision > random()) AND (a <= 2000)) OR (a > 198990))
         Rows Removed by Filter: 990
         Columnar Projected Columns: a
         Columnar Chunk Group Filters: ((a <= 2000) OR (a > 198990))
         Columnar Chunk Groups Removed by Filter: 196
(7 rows)

SELECT sum(a) FROM pushdown_test where (a > random() and a <= 2000) or (a > 200000-1010);
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
    sum
---------------------------------------------------------------------
 203491455
(1 row)

SET hash_mem_multiplier = 1.0;
SELECT public.explain_with_pg16_subplan_format($Q$
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where
(
  a > random()
  and
  (
    (a < 200 and a not in (select a from pushdown_test)) or
    (a > 1000 and a < 2000)
  )
)
or
(a > 200000-2010);
$Q$) as "QUERY PLAN";
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 0 clauses pushed down
CONTEXT:  PL/pgSQL function explain_with_pg16_subplan_format(text) line XX at FOR over EXECUTE statement
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
CONTEXT:  PL/pgSQL function explain_with_pg16_subplan_format(text) line XX at FOR over EXECUTE statement
NOTICE:  columnar planner: cannot push down clause: must not contain a subplan
CONTEXT:  PL/pgSQL function explain_with_pg16_subplan_format(text) line XX at FOR over EXECUTE statement
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
CONTEXT:  PL/pgSQL function explain_with_pg16_subplan_format(text) line XX at FOR over EXECUTE statement
                                                                  QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on pushdown_test (actual rows=3009 loops=1)
         Filter: ((((a)::double precision > random()) AND (((a < 200) AND (NOT (SubPlan 1))) OR ((a > 1000) AND (a < 2000)))) OR (a > 197990))
         Rows Removed by Filter: 1991
         Columnar Projected Columns: a
         Columnar Chunk Group Filters: (((a < 200) OR ((a > 1000) AND (a < 2000))) OR (a > 197990))
         Columnar Chunk Groups Removed by Filter: 195
         SubPlan 1
           ->  Materialize (actual rows=100 loops=199)
                 ->  Custom Scan (ColumnarScan) on pushdown_test pushdown_test_1 (actual rows=199 loops=1)
                       Columnar Projected Columns: a
(11 rows)

RESET hash_mem_multiplier;
SELECT sum(a) FROM pushdown_test where
(
  a > random()
  and
  (
    (a < 200 and a not in (select a from pushdown_test)) or
    (a > 1000 and a < 2000)
  )
)
or
(a > 200000-2010);
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 0 clauses pushed down
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: cannot push down clause: must not contain a subplan
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
    sum
---------------------------------------------------------------------
 401479455
(1 row)

create function stable_1(arg int) returns int language plpgsql STRICT IMMUTABLE as
$$ BEGIN RETURN 1+arg; END; $$;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT sum(a) FROM pushdown_test where (a = random() and a < stable_1(a) and a < stable_1(6000));
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
                                        QUERY PLAN
---------------------------------------------------------------------
 Aggregate (actual rows=1 loops=1)
   ->  Custom Scan (ColumnarScan) on pushdown_test (actual rows=0 loops=1)
         Filter: ((a < 6001) AND ((a)::double precision = random()) AND (a < stable_1(a)))
         Rows Removed by Filter: 6000
         Columnar Projected Columns: a
         Columnar Chunk Group Filters: (a < 6001)
         Columnar Chunk Groups Removed by Filter: 194
(7 rows)

SELECT sum(a) FROM pushdown_test where (a = random() and a < stable_1(a) and a < stable_1(6000));
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: cannot push down clause: must match 'Var <op> Expr' or 'Expr <op> Var'
HINT:  Var must only reference this rel, and Expr must not reference this rel
NOTICE:  columnar planner: adding CustomScan path for pushdown_test
DETAIL:  unparameterized; 1 clauses pushed down
 sum
---------------------------------------------------------------------

(1 row)

RESET columnar.max_custom_scan_paths;
RESET columnar.qual_pushdown_correlation_threshold;
RESET columnar.planner_debug_level;
DROP TABLE pushdown_test;
-- https://github.com/citusdata/citus/issues/5803
CREATE TABLE pushdown_test(id int, country text) using columnar;
BEGIN;
    INSERT INTO pushdown_test VALUES(1, 'AL');
    INSERT INTO pushdown_test VALUES(2, 'AU');
END;
BEGIN;
    INSERT INTO pushdown_test VALUES(3, 'BR');
    INSERT INTO pushdown_test VALUES(4, 'BT');
END;
BEGIN;
    INSERT INTO pushdown_test VALUES(5, 'PK');
    INSERT INTO pushdown_test VALUES(6, 'PA');
END;
BEGIN;
    INSERT INTO pushdown_test VALUES(7, 'USA');
    INSERT INTO pushdown_test VALUES(8, 'ZW');
END;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT id FROM pushdown_test WHERE country IN ('USA', 'BR', 'ZW');
                                QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on pushdown_test (actual rows=3 loops=1)
    Filter: (country = ANY ('{USA,BR,ZW}'::text[]))
    Rows Removed by Filter: 1
    Columnar Projected Columns: id, country
    Columnar Chunk Group Filters: (country = ANY ('{USA,BR,ZW}'::text[]))
    Columnar Chunk Groups Removed by Filter: 2
(6 rows)

SELECT id FROM pushdown_test WHERE country IN ('USA', 'BR', 'ZW');
 id
---------------------------------------------------------------------
  3
  7
  8
(3 rows)

-- test for volatile functions with IN
CREATE FUNCTION volatileFunction() returns TEXT language plpgsql AS
$$
BEGIN
    return 'AL';
END;
$$;
EXPLAIN (analyze on, costs off, timing off, summary off)
SELECT * FROM pushdown_test WHERE country IN ('USA', 'ZW', volatileFunction());
                                   QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (ColumnarScan) on pushdown_test (actual rows=3 loops=1)
   Filter: (country = ANY (ARRAY['USA'::text, 'ZW'::text, volatilefunction()]))
   Rows Removed by Filter: 5
   Columnar Projected Columns: id, country
(4 rows)

SELECT * FROM pushdown_test WHERE country IN ('USA', 'ZW', volatileFunction());
 id | country
---------------------------------------------------------------------
  1 | AL
  7 | USA
  8 | ZW
(3 rows)

DROP TABLE pushdown_test;
