SET client_min_messages TO WARNING;
CREATE EXTENSION IF NOT EXISTS citus_columnar;
RESET client_min_messages;

CREATE SCHEMA drop_column_partitioned_table;
SET search_path TO drop_column_partitioned_table;

SET citus.shard_replication_factor TO 1;
SET citus.next_shard_id TO 2580000;

-- create a partitioned table with some columns that
-- are going to be dropped within the tests
CREATE TABLE sensors(
col_to_drop_0 text,
col_to_drop_1 text,
col_to_drop_2 date,
col_to_drop_3 inet,
col_to_drop_4 date,
measureid integer,
eventdatetime date,
measure_data jsonb,
PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);

-- drop column even before attaching any partitions
ALTER TABLE sensors DROP COLUMN col_to_drop_1;

-- now attach the first partition and create the distributed table
CREATE TABLE sensors_2000 PARTITION OF sensors FOR VALUES FROM ('2000-01-01') TO ('2001-01-01');
SELECT create_distributed_table('sensors', 'measureid');

-- prepared statements should work fine even after columns are dropped
PREPARE drop_col_prepare_insert(int, date, jsonb) AS INSERT INTO sensors (measureid, eventdatetime, measure_data) VALUES ($1, $2, $3);
PREPARE drop_col_prepare_select(int, date) AS SELECT count(*) FROM sensors WHERE measureid = $1 AND eventdatetime = $2;

-- execute 7 times to make sure it is cached
EXECUTE drop_col_prepare_insert(1, '2000-10-01', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(1, '2000-10-02', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(1, '2000-10-03', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(1, '2000-10-04', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(1, '2000-10-05', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(1, '2000-10-06', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(1, '2000-10-07', row_to_json(row(1)));
EXECUTE drop_col_prepare_select(1, '2000-10-01');
EXECUTE drop_col_prepare_select(1, '2000-10-02');
EXECUTE drop_col_prepare_select(1, '2000-10-03');
EXECUTE drop_col_prepare_select(1, '2000-10-04');
EXECUTE drop_col_prepare_select(1, '2000-10-05');
EXECUTE drop_col_prepare_select(1, '2000-10-06');
EXECUTE drop_col_prepare_select(1, '2000-10-07');

-- drop another column before attaching another partition
-- with .. PARTITION OF .. syntax
ALTER TABLE sensors DROP COLUMN col_to_drop_0;
CREATE TABLE sensors_2001 PARTITION OF sensors FOR VALUES FROM ('2001-01-01') TO ('2002-01-01');

-- drop another column before attaching another partition
-- with ALTER TABLE .. ATTACH PARTITION
ALTER TABLE sensors DROP COLUMN col_to_drop_2;

CREATE TABLE sensors_2002(
col_to_drop_4 date, col_to_drop_3 inet, measureid integer, eventdatetime date, measure_data jsonb,
PRIMARY KEY (measureid, eventdatetime, measure_data));
ALTER TABLE sensors ATTACH PARTITION sensors_2002 FOR VALUES FROM ('2002-01-01') TO ('2003-01-01');

-- drop another column before attaching another partition
-- that is already distributed
ALTER TABLE sensors DROP COLUMN col_to_drop_3;

CREATE TABLE sensors_2003(
col_to_drop_4 date, measureid integer, eventdatetime date, measure_data jsonb,
PRIMARY KEY (measureid, eventdatetime, measure_data));

SELECT create_distributed_table('sensors_2003', 'measureid');
ALTER TABLE sensors ATTACH PARTITION sensors_2003 FOR VALUES FROM ('2003-01-01') TO ('2004-01-01');

CREATE TABLE sensors_2004(
col_to_drop_4 date, measureid integer NOT NULL, eventdatetime date NOT NULL, measure_data jsonb NOT NULL);

ALTER TABLE sensors ATTACH PARTITION sensors_2004 FOR VALUES FROM ('2004-01-01') TO ('2005-01-01');
ALTER TABLE sensors DROP COLUMN col_to_drop_4;
SELECT alter_table_set_access_method('sensors_2004', 'columnar');

-- show that all partitions have the same distribution key
SELECT
	p.logicalrelid::regclass, column_to_column_name(p.logicalrelid, p.partkey)
FROM
	pg_dist_partition p
WHERE
	logicalrelid IN ('sensors'::regclass, 'sensors_2000'::regclass,
					 'sensors_2001'::regclass, 'sensors_2002'::regclass,
					 'sensors_2003'::regclass, 'sensors_2004'::regclass)
ORDER BY 1,2;

-- show that all the tables prune to the same shard for the same distribution key
WITH
	sensors_shardid AS (SELECT * FROM get_shard_id_for_distribution_column('sensors', 3)),
	sensors_2000_shardid AS (SELECT * FROM get_shard_id_for_distribution_column('sensors_2000', 3)),
	sensors_2001_shardid AS (SELECT * FROM get_shard_id_for_distribution_column('sensors_2001', 3)),
	sensors_2002_shardid AS (SELECT * FROM get_shard_id_for_distribution_column('sensors_2002', 3)),
	sensors_2003_shardid AS (SELECT * FROM get_shard_id_for_distribution_column('sensors_2003', 3)),
	sensors_2004_shardid AS (SELECT * FROM get_shard_id_for_distribution_column('sensors_2004', 3)),
	all_shardids AS (SELECT * FROM sensors_shardid UNION SELECT * FROM sensors_2000_shardid UNION
					 SELECT * FROM sensors_2001_shardid UNION SELECT * FROM sensors_2002_shardid
					 UNION SELECT * FROM sensors_2003_shardid UNION SELECT * FROM sensors_2004_shardid)
SELECT logicalrelid, shardid, shardminvalue, shardmaxvalue FROM pg_dist_shard WHERE shardid IN (SELECT * FROM all_shardids) ORDER BY 1,2,3,4;

VACUUM ANALYZE sensors, sensors_2000, sensors_2001, sensors_2002, sensors_2003;

-- show that both INSERT and SELECT can route to a single node when distribution
-- key is provided in the query
EXPLAIN (COSTS FALSE) INSERT INTO sensors VALUES (3, '2000-02-02', row_to_json(row(1)));
EXPLAIN (COSTS FALSE) INSERT INTO sensors_2000 VALUES (3, '2000-01-01', row_to_json(row(1)));
EXPLAIN (COSTS FALSE) INSERT INTO sensors_2001 VALUES (3, '2001-01-01', row_to_json(row(1)));
EXPLAIN (COSTS FALSE) INSERT INTO sensors_2002 VALUES (3, '2002-01-01', row_to_json(row(1)));
EXPLAIN (COSTS FALSE) INSERT INTO sensors_2003 VALUES (3, '2003-01-01', row_to_json(row(1)));

SELECT public.explain_has_single_task(
	$$
EXPLAIN (COSTS FALSE) SELECT count(*) FROM sensors WHERE measureid = 3 AND eventdatetime = '2000-02-02';
	$$
);

SELECT public.explain_has_single_task(
	$$
EXPLAIN (COSTS FALSE) SELECT count(*) FROM sensors_2003 WHERE measureid = 3;
	$$
);

SELECT public.explain_has_single_task(
	$$
EXPLAIN (COSTS FALSE) SELECT count(*) FROM sensors_2000 WHERE measureid = 3;
	$$
);

SELECT public.explain_has_single_task(
	$$
EXPLAIN (COSTS FALSE) SELECT count(*) FROM sensors_2001 WHERE measureid = 3;
	$$
);

SELECT public.explain_has_single_task(
	$$
EXPLAIN (COSTS FALSE) SELECT count(*) FROM sensors_2002 WHERE measureid = 3;
	$$
);


-- execute 7 times to make sure it is re-cached
EXECUTE drop_col_prepare_insert(3, '2000-10-01', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(3, '2001-10-01', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(3, '2002-10-01', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(3, '2003-10-01', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(3, '2003-10-02', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(4, '2003-10-03', row_to_json(row(1)));
EXECUTE drop_col_prepare_insert(5, '2003-10-04', row_to_json(row(1)));
EXECUTE drop_col_prepare_select(3, '2000-10-01');
EXECUTE drop_col_prepare_select(3, '2001-10-01');
EXECUTE drop_col_prepare_select(3, '2002-10-01');
EXECUTE drop_col_prepare_select(3, '2003-10-01');
EXECUTE drop_col_prepare_select(3, '2003-10-02');
EXECUTE drop_col_prepare_select(4, '2003-10-03');
EXECUTE drop_col_prepare_select(5, '2003-10-04');

-- non-fast router planner queries should also work
-- so we switched to DEBUG2 to show that dist. key
-- and the query is router
SET client_min_messages TO DEBUG2;
SELECT count(*) FROM (
SELECT * FROM sensors WHERE measureid = 3
	UNION
SELECT * FROM sensors_2000 WHERE measureid = 3
	UNION
SELECT * FROM sensors_2001 WHERE measureid = 3
	UNION
SELECT * FROM sensors_2002 WHERE measureid = 3
	UNION
SELECT * FROM sensors_2003 WHERE measureid = 3
	UNION
SELECT * FROM sensors_2004 WHERE measureid = 3
) as foo;

RESET client_min_messages;

-- show that all partitions have the same distribution key
-- even after alter_distributed_table changes the shard count

-- remove this comment once https://github.com/citusdata/citus/issues/5137 is fixed
--SELECT alter_distributed_table('sensors', shard_count:='3');

SELECT
	p.logicalrelid::regclass, column_to_column_name(p.logicalrelid, p.partkey)
FROM
	pg_dist_partition p
WHERE
	logicalrelid IN ('sensors'::regclass, 'sensors_2000'::regclass,
					 'sensors_2001'::regclass, 'sensors_2002'::regclass,
					 'sensors_2003'::regclass, 'sensors_2004'::regclass)
ORDER BY 1,2;

\c - - - :worker_1_port
SET search_path TO drop_column_partitioned_table;
SELECT
	p.logicalrelid::regclass, column_to_column_name(p.logicalrelid, p.partkey)
FROM
	pg_dist_partition p
WHERE
	logicalrelid IN ('sensors'::regclass, 'sensors_2000'::regclass,
					 'sensors_2001'::regclass, 'sensors_2002'::regclass,
					 'sensors_2003'::regclass, 'sensors_2004'::regclass)
ORDER BY 1,2;

\c - - - :master_port
SET client_min_messages TO WARNING;
DROP SCHEMA drop_column_partitioned_table CASCADE;

SET client_min_messages TO WARNING;
DROP EXTENSION citus_columnar CASCADE;
