--
-- MULTI_NULL_MINMAX_VALUE_PRUNING
--
-- This test checks that we can handle null min/max values in shard statistics
-- and that we don't partition or join prune shards that have null values.
CREATE SCHEMA multi_null_minmax_value_pruning;
SET search_path TO multi_null_minmax_value_pruning;
SET citus.explain_all_tasks TO on;
SET citus.log_multi_join_order to true;
SET citus.enable_repartition_joins to ON;
SET citus.next_shard_id = 290000;
CREATE TABLE lineitem (LIKE public.lineitem);
SELECT create_distributed_table('lineitem', 'l_orderkey', 'range');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT master_create_empty_shard('lineitem') as lineitem_shardid1 \gset
SELECT master_create_empty_shard('lineitem') as lineitem_shardid2 \gset
CREATE TABLE orders (LIKE public.orders);
SELECT create_distributed_table('orders', 'o_orderkey', 'range');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT master_create_empty_shard('orders') as orders_shardid1 \gset
SELECT master_create_empty_shard('orders') as orders_shardid2 \gset
SET client_min_messages TO DEBUG2;
UPDATE pg_dist_shard SET shardminvalue = '1', shardmaxvalue = '6000' WHERE shardid = :lineitem_shardid1 OR shardid = :orders_shardid1;
UPDATE pg_dist_shard SET shardminvalue = '6001', shardmaxvalue = '20000' WHERE shardid = :lineitem_shardid2 OR shardid = :orders_shardid2;
UPDATE pg_dist_partition SET colocationid = 87091 WHERE logicalrelid = 'orders'::regclass OR logicalrelid = 'lineitem'::regclass;
-- Check that partition and join pruning works when min/max values exist
-- Adding l_orderkey = 1 to make the query not router executable
SELECT public.coordinator_plan($Q$
EXPLAIN (COSTS FALSE)
SELECT l_orderkey, l_linenumber, l_shipdate FROM lineitem WHERE l_orderkey = 9030 or l_orderkey = 1;
$Q$);
DEBUG:  Router planner cannot handle multi-shard select queries
CONTEXT:  PL/pgSQL function public.coordinator_plan(text) line XX at FOR over EXECUTE statement
LOG:  join order: [ "lineitem" ]
CONTEXT:  PL/pgSQL function public.coordinator_plan(text) line XX at FOR over EXECUTE statement
       coordinator_plan
---------------------------------------------------------------------
 Custom Scan (Citus Adaptive)
   Task Count: 2
(2 rows)

EXPLAIN (COSTS FALSE)
SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
	WHERE l_orderkey = o_orderkey;
DEBUG:  Router planner cannot handle multi-shard select queries
LOG:  join order: [ "lineitem" ][ local partition join "orders" ]
DEBUG:  join prunable for intervals [1,6000] and [6001,20000]
DEBUG:  join prunable for intervals [6001,20000] and [1,6000]
                                   QUERY PLAN
---------------------------------------------------------------------
 Aggregate
   ->  Custom Scan (Citus Adaptive)
         Task Count: 2
         Tasks Shown: All
         ->  Task
               Node: host=localhost port=xxxxx dbname=regression
               ->  Aggregate
                     ->  Hash Join
                           Hash Cond: (orders.o_orderkey = lineitem.l_orderkey)
                           ->  Seq Scan on orders_290002 orders
                           ->  Hash
                                 ->  Seq Scan on lineitem_290000 lineitem
         ->  Task
               Node: host=localhost port=xxxxx dbname=regression
               ->  Aggregate
                     ->  Hash Join
                           Hash Cond: (orders.o_orderkey = lineitem.l_orderkey)
                           ->  Seq Scan on orders_290003 orders
                           ->  Hash
                                 ->  Seq Scan on lineitem_290001 lineitem
(20 rows)

-- Now set the minimum value for a shard to null. Then check that we don't apply
-- partition or join pruning for the shard with null min value. Since it is not
-- supported with single-repartition join, dual-repartition has been used.
UPDATE pg_dist_shard SET shardminvalue = NULL WHERE shardid = :lineitem_shardid1;
SELECT public.coordinator_plan($Q$
EXPLAIN (COSTS FALSE)
SELECT l_orderkey, l_linenumber, l_shipdate FROM lineitem WHERE l_orderkey = 9030;
$Q$);
DEBUG:  Router planner cannot handle multi-shard select queries
CONTEXT:  PL/pgSQL function public.coordinator_plan(text) line XX at FOR over EXECUTE statement
LOG:  join order: [ "lineitem" ]
CONTEXT:  PL/pgSQL function public.coordinator_plan(text) line XX at FOR over EXECUTE statement
       coordinator_plan
---------------------------------------------------------------------
 Custom Scan (Citus Adaptive)
   Task Count: 2
(2 rows)

EXPLAIN (COSTS FALSE)
SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
	WHERE l_partkey = o_custkey;
DEBUG:  Router planner cannot handle multi-shard select queries
LOG:  join order: [ "lineitem" ][ dual partition join "orders" ]
DEBUG:  join prunable for task partitionId 0 and 1
DEBUG:  join prunable for task partitionId 0 and 2
DEBUG:  join prunable for task partitionId 0 and 3
DEBUG:  join prunable for task partitionId 0 and 4
DEBUG:  join prunable for task partitionId 0 and 5
DEBUG:  join prunable for task partitionId 1 and 0
DEBUG:  join prunable for task partitionId 1 and 2
DEBUG:  join prunable for task partitionId 1 and 3
DEBUG:  join prunable for task partitionId 1 and 4
DEBUG:  join prunable for task partitionId 1 and 5
DEBUG:  join prunable for task partitionId 2 and 0
DEBUG:  join prunable for task partitionId 2 and 1
DEBUG:  join prunable for task partitionId 2 and 3
DEBUG:  join prunable for task partitionId 2 and 4
DEBUG:  join prunable for task partitionId 2 and 5
DEBUG:  join prunable for task partitionId 3 and 0
DEBUG:  join prunable for task partitionId 3 and 1
DEBUG:  join prunable for task partitionId 3 and 2
DEBUG:  join prunable for task partitionId 3 and 4
DEBUG:  join prunable for task partitionId 3 and 5
DEBUG:  join prunable for task partitionId 4 and 0
DEBUG:  join prunable for task partitionId 4 and 1
DEBUG:  join prunable for task partitionId 4 and 2
DEBUG:  join prunable for task partitionId 4 and 3
DEBUG:  join prunable for task partitionId 4 and 5
DEBUG:  join prunable for task partitionId 5 and 0
DEBUG:  join prunable for task partitionId 5 and 1
DEBUG:  join prunable for task partitionId 5 and 2
DEBUG:  join prunable for task partitionId 5 and 3
DEBUG:  join prunable for task partitionId 5 and 4
DEBUG:  pruning merge fetch taskId 1
DETAIL:  Creating dependency on merge taskId 3
DEBUG:  pruning merge fetch taskId 2
DETAIL:  Creating dependency on merge taskId 3
DEBUG:  pruning merge fetch taskId 4
DETAIL:  Creating dependency on merge taskId 6
DEBUG:  pruning merge fetch taskId 5
DETAIL:  Creating dependency on merge taskId 6
DEBUG:  pruning merge fetch taskId 7
DETAIL:  Creating dependency on merge taskId 9
DEBUG:  pruning merge fetch taskId 8
DETAIL:  Creating dependency on merge taskId 9
DEBUG:  pruning merge fetch taskId 10
DETAIL:  Creating dependency on merge taskId 12
DEBUG:  pruning merge fetch taskId 11
DETAIL:  Creating dependency on merge taskId 12
DEBUG:  pruning merge fetch taskId 13
DETAIL:  Creating dependency on merge taskId 15
DEBUG:  pruning merge fetch taskId 14
DETAIL:  Creating dependency on merge taskId 15
DEBUG:  pruning merge fetch taskId 16
DETAIL:  Creating dependency on merge taskId 18
DEBUG:  pruning merge fetch taskId 17
DETAIL:  Creating dependency on merge taskId 18
                            QUERY PLAN
---------------------------------------------------------------------
 Aggregate
   ->  Custom Scan (Citus Adaptive)
         Task Count: 6
         Tasks Shown: None, not supported for re-partition queries
         ->  MapMergeJob
               Map Task Count: 2
               Merge Task Count: 6
         ->  MapMergeJob
               Map Task Count: 2
               Merge Task Count: 6
(10 rows)

-- Next, set the maximum value for another shard to null. Then check that we
-- don't apply partition or join pruning for this other shard either. Since it
-- is not supported with single-repartition join, dual-repartition has been used.
UPDATE pg_dist_shard SET shardmaxvalue = NULL WHERE shardid = :lineitem_shardid2;
SELECT public.coordinator_plan($Q$
EXPLAIN (COSTS FALSE)
SELECT l_orderkey, l_linenumber, l_shipdate FROM lineitem WHERE l_orderkey = 9030;
$Q$);
DEBUG:  Router planner cannot handle multi-shard select queries
CONTEXT:  PL/pgSQL function public.coordinator_plan(text) line XX at FOR over EXECUTE statement
LOG:  join order: [ "lineitem" ]
CONTEXT:  PL/pgSQL function public.coordinator_plan(text) line XX at FOR over EXECUTE statement
       coordinator_plan
---------------------------------------------------------------------
 Custom Scan (Citus Adaptive)
   Task Count: 2
(2 rows)

EXPLAIN (COSTS FALSE)
SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
	WHERE l_partkey = o_custkey;
DEBUG:  Router planner cannot handle multi-shard select queries
LOG:  join order: [ "lineitem" ][ dual partition join "orders" ]
DEBUG:  join prunable for task partitionId 0 and 1
DEBUG:  join prunable for task partitionId 0 and 2
DEBUG:  join prunable for task partitionId 0 and 3
DEBUG:  join prunable for task partitionId 0 and 4
DEBUG:  join prunable for task partitionId 0 and 5
DEBUG:  join prunable for task partitionId 1 and 0
DEBUG:  join prunable for task partitionId 1 and 2
DEBUG:  join prunable for task partitionId 1 and 3
DEBUG:  join prunable for task partitionId 1 and 4
DEBUG:  join prunable for task partitionId 1 and 5
DEBUG:  join prunable for task partitionId 2 and 0
DEBUG:  join prunable for task partitionId 2 and 1
DEBUG:  join prunable for task partitionId 2 and 3
DEBUG:  join prunable for task partitionId 2 and 4
DEBUG:  join prunable for task partitionId 2 and 5
DEBUG:  join prunable for task partitionId 3 and 0
DEBUG:  join prunable for task partitionId 3 and 1
DEBUG:  join prunable for task partitionId 3 and 2
DEBUG:  join prunable for task partitionId 3 and 4
DEBUG:  join prunable for task partitionId 3 and 5
DEBUG:  join prunable for task partitionId 4 and 0
DEBUG:  join prunable for task partitionId 4 and 1
DEBUG:  join prunable for task partitionId 4 and 2
DEBUG:  join prunable for task partitionId 4 and 3
DEBUG:  join prunable for task partitionId 4 and 5
DEBUG:  join prunable for task partitionId 5 and 0
DEBUG:  join prunable for task partitionId 5 and 1
DEBUG:  join prunable for task partitionId 5 and 2
DEBUG:  join prunable for task partitionId 5 and 3
DEBUG:  join prunable for task partitionId 5 and 4
DEBUG:  pruning merge fetch taskId 1
DETAIL:  Creating dependency on merge taskId 3
DEBUG:  pruning merge fetch taskId 2
DETAIL:  Creating dependency on merge taskId 3
DEBUG:  pruning merge fetch taskId 4
DETAIL:  Creating dependency on merge taskId 6
DEBUG:  pruning merge fetch taskId 5
DETAIL:  Creating dependency on merge taskId 6
DEBUG:  pruning merge fetch taskId 7
DETAIL:  Creating dependency on merge taskId 9
DEBUG:  pruning merge fetch taskId 8
DETAIL:  Creating dependency on merge taskId 9
DEBUG:  pruning merge fetch taskId 10
DETAIL:  Creating dependency on merge taskId 12
DEBUG:  pruning merge fetch taskId 11
DETAIL:  Creating dependency on merge taskId 12
DEBUG:  pruning merge fetch taskId 13
DETAIL:  Creating dependency on merge taskId 15
DEBUG:  pruning merge fetch taskId 14
DETAIL:  Creating dependency on merge taskId 15
DEBUG:  pruning merge fetch taskId 16
DETAIL:  Creating dependency on merge taskId 18
DEBUG:  pruning merge fetch taskId 17
DETAIL:  Creating dependency on merge taskId 18
                            QUERY PLAN
---------------------------------------------------------------------
 Aggregate
   ->  Custom Scan (Citus Adaptive)
         Task Count: 6
         Tasks Shown: None, not supported for re-partition queries
         ->  MapMergeJob
               Map Task Count: 2
               Merge Task Count: 6
         ->  MapMergeJob
               Map Task Count: 2
               Merge Task Count: 6
(10 rows)

-- Last, set the minimum value to 0 and check that we don't treat it as null. We
-- should apply partition and join pruning for this shard now. Since it is not
-- supported with single-repartition join, dual-repartition has been used.
UPDATE pg_dist_shard SET shardminvalue = '0' WHERE shardid = :lineitem_shardid1;
SELECT public.coordinator_plan($Q$
EXPLAIN (COSTS FALSE)
SELECT l_orderkey, l_linenumber, l_shipdate FROM lineitem WHERE l_orderkey = 9030;
$Q$);
DEBUG:  Creating router plan
CONTEXT:  PL/pgSQL function public.coordinator_plan(text) line XX at FOR over EXECUTE statement
       coordinator_plan
---------------------------------------------------------------------
 Custom Scan (Citus Adaptive)
   Task Count: 1
(2 rows)

EXPLAIN (COSTS FALSE)
SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
	WHERE l_partkey = o_custkey;
DEBUG:  Router planner cannot handle multi-shard select queries
LOG:  join order: [ "lineitem" ][ dual partition join "orders" ]
DEBUG:  join prunable for task partitionId 0 and 1
DEBUG:  join prunable for task partitionId 0 and 2
DEBUG:  join prunable for task partitionId 0 and 3
DEBUG:  join prunable for task partitionId 0 and 4
DEBUG:  join prunable for task partitionId 0 and 5
DEBUG:  join prunable for task partitionId 1 and 0
DEBUG:  join prunable for task partitionId 1 and 2
DEBUG:  join prunable for task partitionId 1 and 3
DEBUG:  join prunable for task partitionId 1 and 4
DEBUG:  join prunable for task partitionId 1 and 5
DEBUG:  join prunable for task partitionId 2 and 0
DEBUG:  join prunable for task partitionId 2 and 1
DEBUG:  join prunable for task partitionId 2 and 3
DEBUG:  join prunable for task partitionId 2 and 4
DEBUG:  join prunable for task partitionId 2 and 5
DEBUG:  join prunable for task partitionId 3 and 0
DEBUG:  join prunable for task partitionId 3 and 1
DEBUG:  join prunable for task partitionId 3 and 2
DEBUG:  join prunable for task partitionId 3 and 4
DEBUG:  join prunable for task partitionId 3 and 5
DEBUG:  join prunable for task partitionId 4 and 0
DEBUG:  join prunable for task partitionId 4 and 1
DEBUG:  join prunable for task partitionId 4 and 2
DEBUG:  join prunable for task partitionId 4 and 3
DEBUG:  join prunable for task partitionId 4 and 5
DEBUG:  join prunable for task partitionId 5 and 0
DEBUG:  join prunable for task partitionId 5 and 1
DEBUG:  join prunable for task partitionId 5 and 2
DEBUG:  join prunable for task partitionId 5 and 3
DEBUG:  join prunable for task partitionId 5 and 4
DEBUG:  pruning merge fetch taskId 1
DETAIL:  Creating dependency on merge taskId 3
DEBUG:  pruning merge fetch taskId 2
DETAIL:  Creating dependency on merge taskId 3
DEBUG:  pruning merge fetch taskId 4
DETAIL:  Creating dependency on merge taskId 6
DEBUG:  pruning merge fetch taskId 5
DETAIL:  Creating dependency on merge taskId 6
DEBUG:  pruning merge fetch taskId 7
DETAIL:  Creating dependency on merge taskId 9
DEBUG:  pruning merge fetch taskId 8
DETAIL:  Creating dependency on merge taskId 9
DEBUG:  pruning merge fetch taskId 10
DETAIL:  Creating dependency on merge taskId 12
DEBUG:  pruning merge fetch taskId 11
DETAIL:  Creating dependency on merge taskId 12
DEBUG:  pruning merge fetch taskId 13
DETAIL:  Creating dependency on merge taskId 15
DEBUG:  pruning merge fetch taskId 14
DETAIL:  Creating dependency on merge taskId 15
DEBUG:  pruning merge fetch taskId 16
DETAIL:  Creating dependency on merge taskId 18
DEBUG:  pruning merge fetch taskId 17
DETAIL:  Creating dependency on merge taskId 18
                            QUERY PLAN
---------------------------------------------------------------------
 Aggregate
   ->  Custom Scan (Citus Adaptive)
         Task Count: 6
         Tasks Shown: None, not supported for re-partition queries
         ->  MapMergeJob
               Map Task Count: 2
               Merge Task Count: 6
         ->  MapMergeJob
               Map Task Count: 2
               Merge Task Count: 6
(10 rows)

RESET client_min_messages;
DROP SCHEMA multi_null_minmax_value_pruning CASCADE;
NOTICE:  drop cascades to 2 other objects
DETAIL:  drop cascades to table lineitem
drop cascades to table orders
