--
-- Distributed Partitioned Table Tests
--
SET citus.next_shard_id TO 1660000;
SET citus.shard_count TO 4;
SET citus.shard_replication_factor TO 1;
SET citus.enable_repartition_joins to ON;
--
-- Distributed Partitioned Table Creation Tests
--
-- 1-) Distributing partitioned table
-- create partitioned table
CREATE TABLE partitioning_test(id int, time date) PARTITION BY RANGE (time);
CREATE TABLE partitioning_hash_test(id int, subid int) PARTITION BY HASH(subid);
-- create its partitions
CREATE TABLE partitioning_test_2009 PARTITION OF partitioning_test FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
CREATE TABLE partitioning_test_2010 PARTITION OF partitioning_test FOR VALUES FROM ('2010-01-01') TO ('2011-01-01');
CREATE TABLE partitioning_hash_test_0 PARTITION OF partitioning_hash_test FOR VALUES WITH (MODULUS 3, REMAINDER 0);
CREATE TABLE partitioning_hash_test_1 PARTITION OF partitioning_hash_test FOR VALUES WITH (MODULUS 3, REMAINDER 1);
-- load some data and distribute tables
INSERT INTO partitioning_test VALUES (1, '2009-06-06');
INSERT INTO partitioning_test VALUES (2, '2010-07-07');
INSERT INTO partitioning_test_2009 VALUES (3, '2009-09-09');
INSERT INTO partitioning_test_2010 VALUES (4, '2010-03-03');
INSERT INTO partitioning_hash_test VALUES (1, 2);
INSERT INTO partitioning_hash_test VALUES (2, 13);
INSERT INTO partitioning_hash_test VALUES (3, 7);
INSERT INTO partitioning_hash_test VALUES (4, 4);
-- distribute partitioned table
SELECT create_distributed_table('partitioning_test', 'id');
NOTICE:  Copying data from local table...
NOTICE:  copying the data has completed
DETAIL:  The local data in the table is no longer visible, but is still on disk.
HINT:  To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2009$$)
NOTICE:  Copying data from local table...
NOTICE:  copying the data has completed
DETAIL:  The local data in the table is no longer visible, but is still on disk.
HINT:  To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2010$$)
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT create_distributed_table('partitioning_hash_test', 'id');
NOTICE:  Copying data from local table...
NOTICE:  copying the data has completed
DETAIL:  The local data in the table is no longer visible, but is still on disk.
HINT:  To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_hash_test_0$$)
NOTICE:  Copying data from local table...
NOTICE:  copying the data has completed
DETAIL:  The local data in the table is no longer visible, but is still on disk.
HINT:  To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_hash_test_1$$)
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- see the data is loaded to shards
SELECT * FROM partitioning_test ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  1 | 06-06-2009
  2 | 07-07-2010
  3 | 09-09-2009
  4 | 03-03-2010
(4 rows)

SELECT * FROM partitioning_hash_test ORDER BY 1;
 id | subid
---------------------------------------------------------------------
  1 |     2
  2 |    13
  3 |     7
  4 |     4
(4 rows)

-- should not return results when only querying parent
SELECT * FROM ONLY partitioning_test ORDER BY 1;
 id | time
---------------------------------------------------------------------
(0 rows)

SELECT * FROM ONLY partitioning_test WHERE id = 1;
 id | time
---------------------------------------------------------------------
(0 rows)

SELECT * FROM ONLY partitioning_test a JOIN partitioning_hash_test b ON (a.id = b.subid) ORDER BY 1;
 id | time | id | subid
---------------------------------------------------------------------
(0 rows)

-- see partitioned table and its partitions are distributed
SELECT
	logicalrelid
FROM
	pg_dist_partition
WHERE
	logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010')
ORDER BY 1;
      logicalrelid
---------------------------------------------------------------------
 partitioning_test
 partitioning_test_2009
 partitioning_test_2010
(3 rows)

SELECT
	logicalrelid, count(*)
FROM pg_dist_shard
	WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010')
GROUP BY
	logicalrelid
ORDER BY
	1,2;
      logicalrelid      | count
---------------------------------------------------------------------
 partitioning_test      |     4
 partitioning_test_2009 |     4
 partitioning_test_2010 |     4
(3 rows)

SELECT
	logicalrelid
FROM
	pg_dist_partition
WHERE
	logicalrelid IN ('partitioning_hash_test', 'partitioning_hash_test_0', 'partitioning_hash_test_1')
ORDER BY 1;
       logicalrelid
---------------------------------------------------------------------
 partitioning_hash_test
 partitioning_hash_test_0
 partitioning_hash_test_1
(3 rows)

SELECT
	logicalrelid, count(*)
FROM pg_dist_shard
	WHERE logicalrelid IN ('partitioning_hash_test', 'partitioning_hash_test_0', 'partitioning_hash_test_1')
GROUP BY
	logicalrelid
ORDER BY
	1,2;
       logicalrelid       | count
---------------------------------------------------------------------
 partitioning_hash_test   |     4
 partitioning_hash_test_0 |     4
 partitioning_hash_test_1 |     4
(3 rows)

-- 2-) Creating partition of a distributed table
CREATE TABLE partitioning_test_2011 PARTITION OF partitioning_test FOR VALUES FROM ('2011-01-01') TO ('2012-01-01');
-- new partition is automatically distributed as well
SELECT
	logicalrelid
FROM
	pg_dist_partition
WHERE
	logicalrelid IN ('partitioning_test', 'partitioning_test_2011')
ORDER BY 1;
      logicalrelid
---------------------------------------------------------------------
 partitioning_test
 partitioning_test_2011
(2 rows)

SELECT
	logicalrelid, count(*)
FROM pg_dist_shard
	WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2011')
GROUP BY
	logicalrelid
ORDER BY
	1,2;
      logicalrelid      | count
---------------------------------------------------------------------
 partitioning_test      |     4
 partitioning_test_2011 |     4
(2 rows)

-- 3-) Attaching non distributed table to a distributed table
CREATE TABLE partitioning_test_2012(id int, time date);
-- load some data
INSERT INTO partitioning_test_2012 VALUES (5, '2012-06-06');
INSERT INTO partitioning_test_2012 VALUES (6, '2012-07-07');
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2012 FOR VALUES FROM ('2012-01-01') TO ('2013-01-01');
NOTICE:  Copying data from local table...
NOTICE:  copying the data has completed
DETAIL:  The local data in the table is no longer visible, but is still on disk.
HINT:  To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_2012$$)
-- attached partition is distributed as well
SELECT
	logicalrelid
FROM
	pg_dist_partition
WHERE
	logicalrelid IN ('partitioning_test', 'partitioning_test_2012')
ORDER BY 1;
      logicalrelid
---------------------------------------------------------------------
 partitioning_test
 partitioning_test_2012
(2 rows)

SELECT
	logicalrelid, count(*)
FROM pg_dist_shard
	WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2012')
GROUP BY
	logicalrelid
ORDER BY
	1,2;
      logicalrelid      | count
---------------------------------------------------------------------
 partitioning_test      |     4
 partitioning_test_2012 |     4
(2 rows)

-- try to insert a new data to hash partitioned table
-- no partition is defined for value 5
INSERT INTO partitioning_hash_test VALUES (8, 5);
ERROR:  no partition of relation "partitioning_hash_test_1660012" found for row
DETAIL:  Partition key of the failing row contains (subid) = (5).
CONTEXT:  while executing command on localhost:xxxxx
INSERT INTO partitioning_hash_test VALUES (9, 12);
ERROR:  no partition of relation "partitioning_hash_test_1660015" found for row
DETAIL:  Partition key of the failing row contains (subid) = (12).
CONTEXT:  while executing command on localhost:xxxxx
CREATE TABLE partitioning_hash_test_2 (id int, subid int);
INSERT INTO partitioning_hash_test_2 VALUES (8, 5);
ALTER TABLE partitioning_hash_test ATTACH PARTITION partitioning_hash_test_2 FOR VALUES WITH (MODULUS 3, REMAINDER 2);
NOTICE:  Copying data from local table...
NOTICE:  copying the data has completed
DETAIL:  The local data in the table is no longer visible, but is still on disk.
HINT:  To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_hash_test_2$$)
INSERT INTO partitioning_hash_test VALUES (9, 12);
-- see the data is loaded to shards
SELECT * FROM partitioning_test ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  1 | 06-06-2009
  2 | 07-07-2010
  3 | 09-09-2009
  4 | 03-03-2010
  5 | 06-06-2012
  6 | 07-07-2012
(6 rows)

SELECT * FROM partitioning_hash_test ORDER BY 1;
 id | subid
---------------------------------------------------------------------
  1 |     2
  2 |    13
  3 |     7
  4 |     4
  8 |     5
  9 |    12
(6 rows)

-- 4-) Attaching distributed table to distributed table
CREATE TABLE partitioning_test_2013(id int, time date);
SELECT create_distributed_table('partitioning_test_2013', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- load some data
INSERT INTO partitioning_test_2013 VALUES (7, '2013-06-06');
INSERT INTO partitioning_test_2013 VALUES (8, '2013-07-07');
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2013 FOR VALUES FROM ('2013-01-01') TO ('2014-01-01');
-- see the data is loaded to shards
SELECT * FROM partitioning_test ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  1 | 06-06-2009
  2 | 07-07-2010
  3 | 09-09-2009
  4 | 03-03-2010
  5 | 06-06-2012
  6 | 07-07-2012
  7 | 06-06-2013
  8 | 07-07-2013
(8 rows)

-- 5-) Failure cases while creating distributed partitioned tables
-- cannot distribute a partition if its parent is not distributed
CREATE TABLE partitioning_test_failure(id int, time date) PARTITION BY RANGE (time);
CREATE TABLE partitioning_test_failure_2009 PARTITION OF partitioning_test_failure FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
SELECT create_distributed_table('partitioning_test_failure_2009', 'id');
ERROR:  cannot distribute relation "partitioning_test_failure_2009" which is partition of "partitioning_test_failure"
DETAIL:  Citus does not support distributing partitions if their parent is not distributed table.
HINT:  Distribute the partitioned table "partitioning_test_failure" instead.
-- only hash distributed tables can have partitions
SELECT create_distributed_table('partitioning_test_failure', 'id', 'append');
ERROR:  distributing partitioned tables in only supported for hash-distributed tables
SELECT create_distributed_table('partitioning_test_failure', 'id', 'range');
ERROR:  distributing partitioned tables in only supported for hash-distributed tables
SELECT create_reference_table('partitioning_test_failure');
ERROR:  distributing partitioned tables in only supported for hash-distributed tables
SET citus.shard_replication_factor TO 1;
-- non-distributed tables cannot have distributed partitions;
DROP TABLE partitioning_test_failure_2009;
CREATE TABLE partitioning_test_failure_2009(id int, time date);
SELECT create_distributed_table('partitioning_test_failure_2009', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

ALTER TABLE partitioning_test_failure ATTACH PARTITION partitioning_test_failure_2009 FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
ERROR:  non-citus partitioned tables cannot have citus table partitions
HINT:  Distribute the partitioned table "partitioning_test_failure" instead, or add it to metadata
-- multi-level partitioning is not allowed
DROP TABLE partitioning_test_failure_2009;
CREATE TABLE partitioning_test_failure_2009 PARTITION OF partitioning_test_failure FOR VALUES FROM ('2009-01-01') TO ('2010-01-01') PARTITION BY RANGE (time);
SELECT create_distributed_table('partitioning_test_failure', 'id');
ERROR:  distributing multi-level partitioned tables is not supported
DETAIL:  Relation "partitioning_test_failure_2009" is partitioned table itself and it is also partition of relation "partitioning_test_failure".
-- multi-level partitioning is not allowed in different order
DROP TABLE partitioning_test_failure_2009;
SELECT create_distributed_table('partitioning_test_failure', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE partitioning_test_failure_2009 PARTITION OF partitioning_test_failure FOR VALUES FROM ('2009-01-01') TO ('2010-01-01') PARTITION BY RANGE (time);
ERROR:  distributing multi-level partitioned tables is not supported
DETAIL:  Relation "partitioning_test_failure_2009" is partitioned table itself and it is also partition of relation "partitioning_test_failure".
--
-- DMLs in distributed partitioned tables
--
-- test COPY
-- COPY data to partitioned table
COPY partitioning_test FROM STDIN WITH CSV;
-- COPY data to partition directly
COPY partitioning_test_2009 FROM STDIN WITH CSV;
-- see the data is loaded to shards
SELECT * FROM partitioning_test WHERE id >= 9 ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  9 | 01-01-2009
 10 | 01-01-2010
 11 | 01-01-2011
 12 | 01-01-2012
 13 | 01-02-2009
 14 | 01-03-2009
(6 rows)

-- test INSERT
-- INSERT INTO the partitioned table
INSERT INTO partitioning_test VALUES(15, '2009-02-01');
INSERT INTO partitioning_test VALUES(16, '2010-02-01');
INSERT INTO partitioning_test VALUES(17, '2011-02-01');
INSERT INTO partitioning_test VALUES(18, '2012-02-01');
-- INSERT INTO the partitions directly table
INSERT INTO partitioning_test VALUES(19, '2009-02-02');
INSERT INTO partitioning_test VALUES(20, '2010-02-02');
-- see the data is loaded to shards
SELECT * FROM partitioning_test WHERE id >= 15 ORDER BY 1;
 id |    time
---------------------------------------------------------------------
 15 | 02-01-2009
 16 | 02-01-2010
 17 | 02-01-2011
 18 | 02-01-2012
 19 | 02-02-2009
 20 | 02-02-2010
(6 rows)

-- test INSERT/SELECT
-- INSERT/SELECT from partition to partitioned table
INSERT INTO partitioning_test SELECT * FROM partitioning_test_2011;
-- INSERT/SELECT from partitioned table to partition
INSERT INTO partitioning_test_2012 SELECT * FROM partitioning_test WHERE time >= '2012-01-01' AND time < '2013-01-01';
-- see the data is loaded to shards (rows in the given range should be duplicated)
SELECT * FROM partitioning_test WHERE time >= '2011-01-01' AND time < '2013-01-01' ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  5 | 06-06-2012
  5 | 06-06-2012
  6 | 07-07-2012
  6 | 07-07-2012
 11 | 01-01-2011
 11 | 01-01-2011
 12 | 01-01-2012
 12 | 01-01-2012
 17 | 02-01-2011
 17 | 02-01-2011
 18 | 02-01-2012
 18 | 02-01-2012
(12 rows)

-- test UPDATE
-- (1) UPDATE partitioned table
UPDATE partitioning_test SET time = '2013-07-07' WHERE id = 7;
-- (2) UPDATE partition directly
UPDATE partitioning_test_2013 SET time = '2013-08-08' WHERE id = 8;
-- (3) UPDATE only the parent (noop)
UPDATE ONLY partitioning_test SET time = '2013-09-09' WHERE id = 7;
-- (4) DELETE from only the parent (noop)
DELETE FROM ONLY partitioning_test WHERE id = 7;
-- see that only (1) and (2) had an effect
SELECT * FROM partitioning_test WHERE id = 7 OR id = 8 ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  7 | 07-07-2013
  8 | 08-08-2013
(2 rows)

-- UPDATE that tries to move a row to a non-existing partition (this should fail)
UPDATE partitioning_test SET time = '2020-07-07' WHERE id = 7;
ERROR:  no partition of relation "partitioning_test_1660001" found for row
DETAIL:  Partition key of the failing row contains ("time") = (2020-07-07).
CONTEXT:  while executing command on localhost:xxxxx
-- UPDATE with subqueries on partitioned table
UPDATE
    partitioning_test
SET
    time = time + INTERVAL '1 day'
WHERE
    id IN (SELECT id FROM partitioning_test WHERE id = 1);
-- UPDATE with subqueries on partition
UPDATE
    partitioning_test_2009
SET
    time = time + INTERVAL '1 month'
WHERE
    id IN (SELECT id FROM partitioning_test WHERE id = 2);
-- see the data is updated
SELECT * FROM partitioning_test WHERE id = 1 OR id = 2 ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  1 | 06-07-2009
  2 | 07-07-2010
(2 rows)

-- test DELETE
-- DELETE from partitioned table
DELETE FROM partitioning_test WHERE id = 9;
-- DELETE from partition directly
DELETE FROM partitioning_test_2010 WHERE id = 10;
-- see the data is deleted
SELECT * FROM partitioning_test WHERE id = 9 OR id = 10 ORDER BY 1;
 id | time
---------------------------------------------------------------------
(0 rows)

-- create default partition
CREATE TABLE partitioning_test_default PARTITION OF partitioning_test DEFAULT;
\d+ partitioning_test
                       Partitioned table "public.partitioning_test"
 Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description
---------------------------------------------------------------------
 id     | integer |           |          |         | plain   |              |
 time   | date    |           |          |         | plain   |              |
Partition key: RANGE ("time")
Partitions: partitioning_test_2009 FOR VALUES FROM ('01-01-2009') TO ('01-01-2010'),
            partitioning_test_2010 FOR VALUES FROM ('01-01-2010') TO ('01-01-2011'),
            partitioning_test_2011 FOR VALUES FROM ('01-01-2011') TO ('01-01-2012'),
            partitioning_test_2012 FOR VALUES FROM ('01-01-2012') TO ('01-01-2013'),
            partitioning_test_2013 FOR VALUES FROM ('01-01-2013') TO ('01-01-2014'),
            partitioning_test_default DEFAULT

INSERT INTO partitioning_test VALUES(21, '2014-02-02');
INSERT INTO partitioning_test VALUES(22, '2015-04-02');
-- see they are inserted into default partition
SELECT * FROM partitioning_test WHERE id > 20 ORDER BY 1, 2;
 id |    time
---------------------------------------------------------------------
 21 | 02-02-2014
 22 | 04-02-2015
(2 rows)

SELECT * FROM partitioning_test_default ORDER BY 1, 2;
 id |    time
---------------------------------------------------------------------
 21 | 02-02-2014
 22 | 04-02-2015
(2 rows)

-- create a new partition (will fail)
CREATE TABLE partitioning_test_2014 PARTITION OF partitioning_test FOR VALUES FROM ('2014-01-01') TO ('2015-01-01');
ERROR:  updated partition constraint for default partition would be violated by some row
CONTEXT:  while executing command on localhost:xxxxx
BEGIN;
ALTER TABLE partitioning_test DETACH PARTITION partitioning_test_default;
CREATE TABLE partitioning_test_2014 PARTITION OF partitioning_test FOR VALUES FROM ('2014-01-01') TO ('2015-01-01');
INSERT INTO partitioning_test SELECT * FROM partitioning_test_default WHERE time >= '2014-01-01' AND time < '2015-01-01';
DELETE FROM partitioning_test_default WHERE time >= '2014-01-01' AND time < '2015-01-01';
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_default DEFAULT;
END;
-- see data is in the table, but some moved out from default partition
SELECT * FROM partitioning_test WHERE id > 20 ORDER BY 1, 2;
 id |    time
---------------------------------------------------------------------
 21 | 02-02-2014
 22 | 04-02-2015
(2 rows)

SELECT * FROM partitioning_test_default ORDER BY 1, 2;
 id |    time
---------------------------------------------------------------------
 22 | 04-02-2015
(1 row)

-- multi-shard UPDATE on partitioned table
UPDATE partitioning_test SET time = time + INTERVAL '1 day';
-- see rows are UPDATED
SELECT * FROM partitioning_test ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  1 | 06-08-2009
  2 | 07-08-2010
  3 | 09-10-2009
  4 | 03-04-2010
  5 | 06-07-2012
  5 | 06-07-2012
  6 | 07-08-2012
  6 | 07-08-2012
  7 | 07-08-2013
  8 | 08-09-2013
 11 | 01-02-2011
 11 | 01-02-2011
 12 | 01-02-2012
 12 | 01-02-2012
 13 | 01-03-2009
 14 | 01-04-2009
 15 | 02-02-2009
 16 | 02-02-2010
 17 | 02-02-2011
 17 | 02-02-2011
 18 | 02-02-2012
 18 | 02-02-2012
 19 | 02-03-2009
 20 | 02-03-2010
 21 | 02-03-2014
 22 | 04-03-2015
(26 rows)

-- multi-shard UPDATE on partition directly
UPDATE partitioning_test_2009 SET time = time + INTERVAL '1 day';
-- see rows are UPDATED
SELECT * FROM partitioning_test_2009 ORDER BY 1;
 id |    time
---------------------------------------------------------------------
  1 | 06-09-2009
  3 | 09-11-2009
 13 | 01-04-2009
 14 | 01-05-2009
 15 | 02-03-2009
 19 | 02-04-2009
(6 rows)

-- test multi-shard UPDATE which fails in workers (updated value is outside of partition bounds)
UPDATE partitioning_test_2009 SET time = time + INTERVAL '6 month';
ERROR:  new row for relation "partitioning_test_2009_1660005" violates partition constraint
DETAIL:  Failing row contains (3, 2010-03-11).
CONTEXT:  while executing command on localhost:xxxxx
--
-- DDL in distributed partitioned tables
--
-- test CREATE INDEX
-- CREATE INDEX on partitioned table - this will error out
-- on earlier versions of postgres earlier than 11.
CREATE INDEX partitioning_index ON partitioning_test(id);
-- CREATE INDEX on partition
CREATE INDEX partitioning_2009_index ON partitioning_test_2009(id);
-- CREATE INDEX CONCURRENTLY on partition
CREATE INDEX CONCURRENTLY partitioned_2010_index ON partitioning_test_2010(id);
-- see index is created
SELECT tablename, indexname FROM pg_indexes WHERE tablename LIKE 'partitioning_test_%' ORDER BY indexname;
         tablename         |            indexname
---------------------------------------------------------------------
 partitioning_test_2010    | partitioned_2010_index
 partitioning_test_2009    | partitioning_2009_index
 partitioning_test_2009    | partitioning_test_2009_id_idx
 partitioning_test_2010    | partitioning_test_2010_id_idx
 partitioning_test_2011    | partitioning_test_2011_id_idx
 partitioning_test_2012    | partitioning_test_2012_id_idx
 partitioning_test_2013    | partitioning_test_2013_id_idx
 partitioning_test_2014    | partitioning_test_2014_id_idx
 partitioning_test_default | partitioning_test_default_id_idx
(9 rows)

-- test drop
-- indexes created on parent table can only be dropped on parent table
-- ie using the same index name
-- following will fail
DROP INDEX partitioning_test_2009_id_idx;
ERROR:  cannot drop index partitioning_test_2009_id_idx because index partitioning_index requires it
HINT:  You can drop index partitioning_index instead.
-- but dropping index on parent table will succeed
DROP INDEX partitioning_index;
-- this index was already created on partition table
DROP INDEX partitioning_2009_index;
-- test drop index on non-distributed, partitioned table
CREATE TABLE non_distributed_partitioned_table(a int, b int) PARTITION BY RANGE (a);
CREATE TABLE non_distributed_partitioned_table_1 PARTITION OF non_distributed_partitioned_table
FOR VALUES FROM (0) TO (10);
CREATE INDEX non_distributed_partitioned_table_index ON non_distributed_partitioned_table(a);
-- see index is created
SELECT tablename, indexname FROM pg_indexes WHERE tablename LIKE 'non_distributed_partitioned_table_%' ORDER BY indexname;
              tablename              |                 indexname
---------------------------------------------------------------------
 non_distributed_partitioned_table_1 | non_distributed_partitioned_table_1_a_idx
(1 row)

-- drop the index and see it is dropped
DROP INDEX non_distributed_partitioned_table_index;
SELECT tablename, indexname FROM pg_indexes WHERE tablename LIKE 'non_distributed%' ORDER BY indexname;
 tablename | indexname
---------------------------------------------------------------------
(0 rows)

-- test add COLUMN
-- add COLUMN to partitioned table
ALTER TABLE partitioning_test ADD new_column int;
-- add COLUMN to partition - this will error out
ALTER TABLE partitioning_test_2010 ADD new_column_2 int;
ERROR:  cannot add column to a partition
-- see additional column is created
SELECT name, type FROM table_attrs WHERE relid = 'partitioning_test'::regclass ORDER BY 1;
    name    |  type
---------------------------------------------------------------------
 id         | integer
 new_column | integer
 time       | date
(3 rows)

SELECT name, type FROM table_attrs WHERE relid = 'partitioning_test_2010'::regclass ORDER BY 1;
    name    |  type
---------------------------------------------------------------------
 id         | integer
 new_column | integer
 time       | date
(3 rows)

-- test add PRIMARY KEY
-- add PRIMARY KEY to partitioned table - this will error out
ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_primary PRIMARY KEY (id);
ERROR:  unique constraint on partitioned table must include all partitioning columns
DETAIL:  PRIMARY KEY constraint on table "partitioning_test" lacks column "time" which is part of the partition key.
-- ADD PRIMARY KEY to partition
ALTER TABLE partitioning_test_2009 ADD CONSTRAINT partitioning_2009_primary PRIMARY KEY (id);
-- see PRIMARY KEY is created
SELECT
    table_name,
    constraint_name,
    constraint_type
FROM
    information_schema.table_constraints
WHERE
    table_name = 'partitioning_test_2009' AND
    constraint_name = 'partitioning_2009_primary';
       table_name       |      constraint_name      | constraint_type
---------------------------------------------------------------------
 partitioning_test_2009 | partitioning_2009_primary | PRIMARY KEY
(1 row)

-- however, you can add primary key if it contains both distribution and partition key
ALTER TABLE partitioning_hash_test ADD CONSTRAINT partitioning_hash_primary PRIMARY KEY (id, subid);
-- see PRIMARY KEY is created
SELECT
    table_name,
    constraint_name,
    constraint_type
FROM
    information_schema.table_constraints
WHERE
    table_name LIKE 'partitioning_hash_test%' AND
    constraint_type = 'PRIMARY KEY'
ORDER BY 1;
        table_name        |        constraint_name        | constraint_type
---------------------------------------------------------------------
 partitioning_hash_test   | partitioning_hash_primary     | PRIMARY KEY
 partitioning_hash_test_0 | partitioning_hash_test_0_pkey | PRIMARY KEY
 partitioning_hash_test_1 | partitioning_hash_test_1_pkey | PRIMARY KEY
 partitioning_hash_test_2 | partitioning_hash_test_2_pkey | PRIMARY KEY
(4 rows)

-- test ADD FOREIGN CONSTRAINT
-- add FOREIGN CONSTRAINT to partitioned table -- this will error out (it is a self reference)
ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_foreign FOREIGN KEY (id) REFERENCES partitioning_test_2009 (id);
ERROR:  cannot ALTER TABLE "partitioning_test_2009" because it is being used by active queries in this session
-- add FOREIGN CONSTRAINT to partition
INSERT INTO partitioning_test_2009 VALUES (5, '2009-06-06');
INSERT INTO partitioning_test_2009 VALUES (6, '2009-07-07');
INSERT INTO partitioning_test_2009 VALUES(12, '2009-02-01');
INSERT INTO partitioning_test_2009 VALUES(18, '2009-02-01');
ALTER TABLE partitioning_test_2012 ADD CONSTRAINT partitioning_2012_foreign FOREIGN KEY (id) REFERENCES partitioning_test_2009 (id) ON DELETE CASCADE;
-- see FOREIGN KEY is created
SELECT "Constraint" FROM table_fkeys WHERE relid = 'partitioning_test_2012'::regclass ORDER BY 1;
        Constraint
---------------------------------------------------------------------
 partitioning_2012_foreign
(1 row)

-- test ON DELETE CASCADE works
DELETE FROM partitioning_test_2009 WHERE id = 5;
-- see that element is deleted from both partitions
SELECT * FROM partitioning_test_2009 WHERE id = 5 ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

SELECT * FROM partitioning_test_2012 WHERE id = 5 ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

-- test DETACH partition
ALTER TABLE partitioning_test DETACH PARTITION partitioning_test_2009;
-- see DETACHed partitions content is not accessible from partitioning_test;
SELECT * FROM partitioning_test WHERE time >= '2009-01-01' AND time < '2010-01-01' ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

-- delete from default partition
DELETE FROM partitioning_test WHERE time >= '2015-01-01';
SELECT * FROM partitioning_test_default;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

-- create a reference table for foreign key test
CREATE TABLE partitioning_test_reference(id int PRIMARY KEY, subid int);
INSERT INTO partitioning_test_reference SELECT a, a FROM generate_series(1, 50) a;
SELECT create_reference_table('partitioning_test_reference');
NOTICE:  Copying data from local table...
NOTICE:  copying the data has completed
DETAIL:  The local data in the table is no longer visible, but is still on disk.
HINT:  To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.partitioning_test_reference$$)
 create_reference_table
---------------------------------------------------------------------

(1 row)

ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_reference_fkey FOREIGN KEY (id) REFERENCES partitioning_test_reference(id) ON DELETE CASCADE;
CREATE TABLE partitioning_test_foreign_key(id int PRIMARY KEY, value int);
SELECT create_distributed_table('partitioning_test_foreign_key', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

INSERT INTO partitioning_test_foreign_key SELECT * FROM partitioning_test_reference;
ALTER TABLE partitioning_hash_test ADD CONSTRAINT partitioning_reference_fk_test FOREIGN KEY (id) REFERENCES partitioning_test_foreign_key(id) ON DELETE CASCADE;
-- check foreign keys on partitions
SELECT
	table_name, constraint_name, constraint_type FROm information_schema.table_constraints
WHERE
	table_name LIKE 'partitioning_hash_test%' AND
	constraint_type = 'FOREIGN KEY'
ORDER BY
	1,2;
        table_name        |        constraint_name         | constraint_type
---------------------------------------------------------------------
 partitioning_hash_test   | partitioning_reference_fk_test | FOREIGN KEY
 partitioning_hash_test_0 | partitioning_reference_fk_test | FOREIGN KEY
 partitioning_hash_test_1 | partitioning_reference_fk_test | FOREIGN KEY
 partitioning_hash_test_2 | partitioning_reference_fk_test | FOREIGN KEY
(4 rows)

-- check foreign keys on partition shards
-- there is some text ordering issue regarding table name
-- forcing integer sort by extracting shardid
CREATE TYPE foreign_key_details AS (table_name text, constraint_name text, constraint_type text);
SELECT right(table_name, 7)::int as shardid, * FROM (
	SELECT (json_populate_record(NULL::foreign_key_details,
	json_array_elements_text(result::json)::json )).*
	FROM run_command_on_workers($$
		SELECT
			COALESCE(json_agg(row_to_json(q)), '[]'::json)
		FROM (
			SELECT
				table_name, constraint_name, constraint_type
			FROM information_schema.table_constraints
			WHERE
				table_name SIMILAR TO 'partitioning_hash_test%\d{2,}' AND
				constraint_type = 'FOREIGN KEY'
			ORDER BY 1, 2, 3
			) q
		$$) ) w
ORDER BY 1, 2, 3, 4;
 shardid |            table_name            |            constraint_name             | constraint_type
---------------------------------------------------------------------
 1660012 | partitioning_hash_test_1660012   | partitioning_reference_fk_test_1660012 | FOREIGN KEY
 1660013 | partitioning_hash_test_1660013   | partitioning_reference_fk_test_1660013 | FOREIGN KEY
 1660014 | partitioning_hash_test_1660014   | partitioning_reference_fk_test_1660014 | FOREIGN KEY
 1660015 | partitioning_hash_test_1660015   | partitioning_reference_fk_test_1660015 | FOREIGN KEY
 1660016 | partitioning_hash_test_0_1660016 | partitioning_reference_fk_test_1660012 | FOREIGN KEY
 1660017 | partitioning_hash_test_0_1660017 | partitioning_reference_fk_test_1660013 | FOREIGN KEY
 1660018 | partitioning_hash_test_0_1660018 | partitioning_reference_fk_test_1660014 | FOREIGN KEY
 1660019 | partitioning_hash_test_0_1660019 | partitioning_reference_fk_test_1660015 | FOREIGN KEY
 1660020 | partitioning_hash_test_1_1660020 | partitioning_reference_fk_test_1660012 | FOREIGN KEY
 1660021 | partitioning_hash_test_1_1660021 | partitioning_reference_fk_test_1660013 | FOREIGN KEY
 1660022 | partitioning_hash_test_1_1660022 | partitioning_reference_fk_test_1660014 | FOREIGN KEY
 1660023 | partitioning_hash_test_1_1660023 | partitioning_reference_fk_test_1660015 | FOREIGN KEY
 1660032 | partitioning_hash_test_2_1660032 | partitioning_reference_fk_test_1660012 | FOREIGN KEY
 1660033 | partitioning_hash_test_2_1660033 | partitioning_reference_fk_test_1660013 | FOREIGN KEY
 1660034 | partitioning_hash_test_2_1660034 | partitioning_reference_fk_test_1660014 | FOREIGN KEY
 1660035 | partitioning_hash_test_2_1660035 | partitioning_reference_fk_test_1660015 | FOREIGN KEY
(16 rows)

DROP TYPE  foreign_key_details;
-- set replication factor back to 1 since it gots reset
-- after connection re-establishment
SET citus.shard_replication_factor TO 1;
SELECT * FROM partitioning_test WHERE id = 11 or id = 12;
 id |    time    | new_column
---------------------------------------------------------------------
 11 | 01-02-2011 |
 11 | 01-02-2011 |
 12 | 01-02-2012 |
 12 | 01-02-2012 |
(4 rows)

DELETE FROM partitioning_test_reference WHERE id = 11 or id = 12;
SELECT * FROM partitioning_hash_test ORDER BY 1, 2;
 id | subid
---------------------------------------------------------------------
  1 |     2
  2 |    13
  3 |     7
  4 |     4
  8 |     5
  9 |    12
(6 rows)

DELETE FROM partitioning_test_foreign_key WHERE id = 2 OR id = 9;
-- see data is deleted from referencing table
SELECT * FROM partitioning_test WHERE id = 11 or id = 12;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

SELECT * FROM partitioning_hash_test ORDER BY 1, 2;
 id | subid
---------------------------------------------------------------------
  1 |     2
  3 |     7
  4 |     4
  8 |     5
(4 rows)

--
-- Transaction tests
--
-- DDL in transaction
BEGIN;
ALTER TABLE partitioning_test ADD newer_column int;
-- see additional column is created
SELECT name, type FROM table_attrs WHERE relid = 'partitioning_test'::regclass ORDER BY 1;
     name     |  type
---------------------------------------------------------------------
 id           | integer
 new_column   | integer
 newer_column | integer
 time         | date
(4 rows)

ROLLBACK;
-- see rollback is successful
SELECT name, type FROM table_attrs WHERE relid = 'partitioning_test'::regclass ORDER BY 1;
    name    |  type
---------------------------------------------------------------------
 id         | integer
 new_column | integer
 time       | date
(3 rows)

-- COPY in transaction
BEGIN;
COPY partitioning_test FROM STDIN WITH CSV;
-- see the data is loaded to shards
SELECT * FROM partitioning_test WHERE id = 22 ORDER BY 1;
 id |    time    | new_column
---------------------------------------------------------------------
 22 | 01-01-2010 |         22
(1 row)

SELECT * FROM partitioning_test WHERE id = 23 ORDER BY 1;
 id |    time    | new_column
---------------------------------------------------------------------
 23 | 01-01-2011 |         23
(1 row)

SELECT * FROM partitioning_test WHERE id = 24 ORDER BY 1;
 id |    time    | new_column
---------------------------------------------------------------------
 24 | 01-01-2013 |         24
(1 row)

ROLLBACK;
-- see rollback is successful
SELECT * FROM partitioning_test WHERE id >= 22 ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

-- DML in transaction
BEGIN;
-- INSERT in transaction
INSERT INTO partitioning_test VALUES(25, '2010-02-02');
-- see the data is loaded to shards
SELECT * FROM partitioning_test WHERE id = 25 ORDER BY 1;
 id |    time    | new_column
---------------------------------------------------------------------
 25 | 02-02-2010 |
(1 row)

-- INSERT/SELECT in transaction
INSERT INTO partitioning_test SELECT * FROM partitioning_test WHERE id = 25;
-- see the data is loaded to shards
SELECT * FROM partitioning_test WHERE id = 25 ORDER BY 1;
 id |    time    | new_column
---------------------------------------------------------------------
 25 | 02-02-2010 |
 25 | 02-02-2010 |
(2 rows)

-- UPDATE in transaction
UPDATE partitioning_test SET time = '2010-10-10' WHERE id = 25;
-- see the data is updated
SELECT * FROM partitioning_test WHERE id = 25 ORDER BY 1;
 id |    time    | new_column
---------------------------------------------------------------------
 25 | 10-10-2010 |
 25 | 10-10-2010 |
(2 rows)

-- perform operations on partition and partitioned tables together
INSERT INTO partitioning_test VALUES(26, '2010-02-02', 26);
INSERT INTO partitioning_test_2010 VALUES(26, '2010-02-02', 26);
COPY partitioning_test FROM STDIN WITH CSV;
COPY partitioning_test_2010 FROM STDIN WITH CSV;
-- see the data is loaded to shards (we should see 4 rows with same content)
SELECT * FROM partitioning_test WHERE id = 26 ORDER BY 1;
 id |    time    | new_column
---------------------------------------------------------------------
 26 | 02-02-2010 |         26
 26 | 02-02-2010 |         26
 26 | 02-02-2010 |         26
 26 | 02-02-2010 |         26
(4 rows)

ROLLBACK;
-- see rollback is successful
SELECT * FROM partitioning_test WHERE id = 26 ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

-- DETACH and DROP in a transaction
BEGIN;
ALTER TABLE partitioning_test DETACH PARTITION partitioning_test_2011;
DROP TABLE partitioning_test_2011;
COMMIT;
-- see DROPed partitions content is not accessible
SELECT * FROM partitioning_test WHERE time >= '2011-01-01' AND time < '2012-01-01' ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

--
-- Misc tests
--
-- test TRUNCATE
-- test TRUNCATE partition
TRUNCATE partitioning_test_2012;
-- see partition is TRUNCATEd
SELECT * FROM partitioning_test_2012 ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

-- test TRUNCATE partitioned table
TRUNCATE partitioning_test;
-- see partitioned table is TRUNCATEd
SELECT * FROM partitioning_test ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

-- test DROP
-- test DROP partition
INSERT INTO partitioning_test_2010 VALUES(27, '2010-02-01');
DROP TABLE partitioning_test_2010;
-- see DROPped partitions content is not accessible from partitioning_test;
SELECT * FROM partitioning_test WHERE time >= '2010-01-01' AND time < '2011-01-01' ORDER BY 1;
 id | time | new_column
---------------------------------------------------------------------
(0 rows)

-- test DROP partitioned table
DROP TABLE partitioning_test;
DROP TABLE partitioning_test_reference;
-- dropping the parent should CASCADE to the children as well
SELECT table_name FROM information_schema.tables WHERE table_name LIKE 'partitioning_test%' ORDER BY 1;
          table_name
---------------------------------------------------------------------
 partitioning_test_2009
 partitioning_test_failure
 partitioning_test_foreign_key
(3 rows)

-- test distributing partitioned table colocated with non-partitioned table
CREATE TABLE partitioned_users_table (user_id int, time timestamp, value_1 int, value_2 int, value_3 float, value_4 bigint) PARTITION BY RANGE (time);
CREATE TABLE partitioned_events_table (user_id int, time timestamp, event_type int, value_2 int, value_3 float, value_4 bigint) PARTITION BY RANGE (time);
SELECT create_distributed_table('partitioned_users_table', 'user_id', colocate_with => 'users_table');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT create_distributed_table('partitioned_events_table', 'user_id', colocate_with => 'events_table');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- INSERT/SELECT from regular table to partitioned table
CREATE TABLE partitioned_users_table_2009 PARTITION OF partitioned_users_table FOR VALUES FROM ('2017-01-01') TO ('2018-01-01');
CREATE TABLE partitioned_events_table_2009 PARTITION OF partitioned_events_table FOR VALUES FROM ('2017-01-01') TO ('2018-01-01');
INSERT INTO partitioned_events_table SELECT * FROM events_table;
INSERT INTO partitioned_users_table_2009 SELECT * FROM users_table;
-- test distributed partitions are indeed colocated with the parent table
CREATE TABLE sensors(measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);
CREATE TABLE sensors_old PARTITION OF sensors FOR VALUES FROM ('2000-01-01') TO ('2020-01-01');
CREATE TABLE sensors_2020_01_01 PARTITION OF sensors FOR VALUES FROM ('2020-01-01') TO ('2020-02-01');
CREATE TABLE sensors_new PARTITION OF sensors DEFAULT;
SELECT create_distributed_table('sensors', 'measureid', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT count(DISTINCT colocationid) FROM pg_dist_partition
WHERE logicalrelid IN ('sensors'::regclass, 'sensors_old'::regclass, 'sensors_2020_01_01'::regclass, 'sensors_new'::regclass);
 count
---------------------------------------------------------------------
     1
(1 row)

CREATE TABLE local_sensors(measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);
CREATE TABLE local_sensors_old PARTITION OF local_sensors FOR VALUES FROM ('2000-01-01') TO ('2020-01-01');
CREATE TABLE local_sensors_2020_01_01 PARTITION OF local_sensors FOR VALUES FROM ('2020-01-01') TO ('2020-02-01');
CREATE TABLE local_sensors_new PARTITION OF local_sensors DEFAULT;
SELECT create_distributed_table('local_sensors', 'measureid', colocate_with:='sensors');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT count(DISTINCT colocationid) FROM pg_dist_partition
WHERE logicalrelid IN ('sensors'::regclass, 'sensors_old'::regclass, 'sensors_2020_01_01'::regclass, 'sensors_new'::regclass,
'local_sensors'::regclass, 'local_sensors_old'::regclass, 'local_sensors_2020_01_01'::regclass, 'local_sensors_new'::regclass);
 count
---------------------------------------------------------------------
     1
(1 row)

DROP TABLE sensors;
DROP TABLE local_sensors;
--
-- Complex JOINs, subqueries, UNIONs etc...
--
-- subquery with UNIONs on partitioned table
SELECT ("final_query"."event_types") as types, count(*) AS sumOfEventType
FROM
  (SELECT *, random()
   FROM
     (SELECT
        "t"."user_id", "t"."time", unnest("t"."collected_events") AS "event_types"
      FROM
        (SELECT
            "t1"."user_id", min("t1"."time") AS "time", array_agg(("t1"."event") ORDER BY TIME ASC, event DESC) AS collected_events
         FROM(
                  (SELECT
                    "events"."user_id", "events"."time", 0 AS event
                   FROM
                    partitioned_events_table as  "events"
                   WHERE
                    event_type IN (1, 2) )
               UNION
                    (SELECT
                        "events"."user_id", "events"."time", 1 AS event
                     FROM
                        partitioned_events_table as "events"
                     WHERE
                        event_type IN (3, 4) )
               UNION
                    (SELECT
                        "events"."user_id", "events"."time", 2 AS event
                     FROM
                        partitioned_events_table as  "events"
                     WHERE
                        event_type IN (5, 6) )
               UNION
                    (SELECT
                        "events"."user_id", "events"."time", 3 AS event
                     FROM
                        partitioned_events_table as "events"
                     WHERE
                        event_type IN (1, 6))) t1
         GROUP BY "t1"."user_id") AS t) "q"
) AS final_query
GROUP BY types
ORDER BY types;
 types | sumofeventtype
---------------------------------------------------------------------
     0 |             43
     1 |             44
     2 |              8
     3 |             25
(4 rows)

-- subquery with UNIONs on partitioned table, but only scan (empty) parent for some
SELECT ("final_query"."event_types") as types, count(*) AS sumOfEventType
FROM
  (SELECT *, random()
   FROM
     (SELECT
        "t"."user_id", "t"."time", unnest("t"."collected_events") AS "event_types"
      FROM
        (SELECT
            "t1"."user_id", min("t1"."time") AS "time", array_agg(("t1"."event") ORDER BY TIME ASC, event DESC) AS collected_events
         FROM(
                  (SELECT
                    "events"."user_id", "events"."time", 0 AS event
                   FROM
                    partitioned_events_table as  "events"
                   WHERE
                    event_type IN (1, 2) )
               UNION
                    (SELECT
                        "events"."user_id", "events"."time", 1 AS event
                     FROM
                        partitioned_events_table as "events"
                     WHERE
                        event_type IN (3, 4) )
               UNION
                    (SELECT
                        "events"."user_id", "events"."time", 2 AS event
                     FROM
                        ONLY partitioned_events_table as  "events"
                     WHERE
                        event_type IN (5, 6) )
               UNION
                    (SELECT
                        "events"."user_id", "events"."time", 3 AS event
                     FROM
                        ONLY partitioned_events_table as "events"
                     WHERE
                        event_type IN (1, 6))) t1
         GROUP BY "t1"."user_id") AS t) "q"
) AS final_query
GROUP BY types
ORDER BY types;
 types | sumofeventtype
---------------------------------------------------------------------
     0 |             43
     1 |             44
(2 rows)

-- UNION and JOIN on both partitioned and regular tables
SELECT ("final_query"."event_types") as types, count(*) AS sumOfEventType
FROM
  (SELECT
      *, random()
    FROM
     (SELECT
        "t"."user_id", "t"."time", unnest("t"."collected_events") AS "event_types"
      FROM
        (SELECT
            "t1"."user_id", min("t1"."time") AS "time", array_agg(("t1"."event") ORDER BY TIME ASC, event DESC) AS collected_events
          FROM (
                (SELECT
                    *
                 FROM
                   (SELECT
                          "events"."time", 0 AS event, "events"."user_id"
                    FROM
                      partitioned_events_table as "events"
                    WHERE
                      event_type IN (1, 2)) events_subquery_1)
                UNION
                 (SELECT *
                  FROM
                    (
                          SELECT * FROM
                          (
                              SELECT
                                max("events"."time"),
                                0 AS event,
                                "events"."user_id"
                              FROM
                                events_table as  "events", users_table as "users"
                              WHERE
                                events.user_id = users.user_id AND
                                event_type IN (1, 2)
                                GROUP BY   "events"."user_id"
                          ) as events_subquery_5
                     ) events_subquery_2)
               UNION
                 (SELECT *
                  FROM
                    (SELECT
                        "events"."time", 2 AS event, "events"."user_id"
                     FROM
                        partitioned_events_table as  "events"
                     WHERE
                      event_type IN (3, 4)) events_subquery_3)
               UNION
                 (SELECT *
                  FROM
                    (SELECT
                       "events"."time", 3 AS event, "events"."user_id"
                     FROM
                      events_table as "events"
                     WHERE
                      event_type IN (5, 6)) events_subquery_4)
                 ) t1
         GROUP BY "t1"."user_id") AS t) "q"
INNER JOIN
     (SELECT
        "users"."user_id"
      FROM
        partitioned_users_table as "users"
      WHERE
        value_1 > 2 and value_1 < 5) AS t
     ON (t.user_id = q.user_id)) as final_query
GROUP BY
  types
ORDER BY
  types;
 types | sumofeventtype
---------------------------------------------------------------------
     0 |            367
     2 |            360
     3 |             57
(3 rows)

-- test LIST partitioning
CREATE TABLE list_partitioned_events_table (user_id int, time date, event_type int, value_2 int, value_3 float, value_4 bigint) PARTITION BY LIST (time);
CREATE TABLE list_partitioned_events_table_2014_01_01_05 PARTITION OF list_partitioned_events_table FOR VALUES IN ('2017-11-21', '2017-11-22', '2017-11-23', '2017-11-24', '2017-11-25');
CREATE TABLE list_partitioned_events_table_2014_01_06_10 PARTITION OF list_partitioned_events_table FOR VALUES IN ('2017-11-26', '2017-11-27', '2017-11-28', '2017-11-29', '2017-11-30');
CREATE TABLE list_partitioned_events_table_2014_01_11_15 PARTITION OF list_partitioned_events_table FOR VALUES IN ('2017-12-01', '2017-12-02', '2017-12-03', '2017-12-04', '2017-12-05');
-- test distributing partitioned table colocated with another partitioned table
SELECT create_distributed_table('list_partitioned_events_table', 'user_id', colocate_with => 'partitioned_events_table');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- INSERT/SELECT from partitioned table to partitioned table
INSERT INTO
    list_partitioned_events_table
SELECT
    user_id,
    date_trunc('day', time) as time,
    event_type,
    value_2,
    value_3,
    value_4
FROM
    events_table
WHERE
    time >= '2017-11-21' AND
    time <= '2017-12-01';
-- LEFT JOINs used with INNER JOINs on range partitioned table, list partitioned table and non-partitioned table
SELECT
count(*) AS cnt, "generated_group_field"
 FROM
  (SELECT
      "eventQuery"."user_id", random(), generated_group_field
   FROM
     (SELECT
        "multi_group_wrapper_1".*, generated_group_field, random()
      FROM
        (SELECT *
         FROM
           (SELECT
              "list_partitioned_events_table"."time", "list_partitioned_events_table"."user_id" as event_user_id
            FROM
             list_partitioned_events_table as "list_partitioned_events_table"
            WHERE
              user_id > 2) "temp_data_queries"
           INNER JOIN
           (SELECT
              "users"."user_id"
            FROM
              partitioned_users_table as "users"
            WHERE
              user_id > 2 and value_2 = 1) "user_filters_1"
           ON ("temp_data_queries".event_user_id = "user_filters_1".user_id)) AS "multi_group_wrapper_1"
        LEFT JOIN
        (SELECT
            "users"."user_id" AS "user_id", value_2 AS "generated_group_field"
         FROM
          partitioned_users_table as "users") "left_group_by_1"
        ON ("left_group_by_1".user_id = "multi_group_wrapper_1".event_user_id)) "eventQuery") "pushedDownQuery"
  GROUP BY
    "generated_group_field"
  ORDER BY
    cnt DESC, generated_group_field ASC
  LIMIT 10;
 cnt  | generated_group_field
---------------------------------------------------------------------
 1851 |                     1
 1077 |                     4
  963 |                     2
  955 |                     3
  768 |                     5
  639 |                     0
(6 rows)

--
-- Additional partitioning features
--
-- test multi column partitioning
CREATE TABLE multi_column_partitioning(c1 int, c2 int) PARTITION BY RANGE (c1, c2);
CREATE TABLE multi_column_partitioning_0_0_10_0 PARTITION OF multi_column_partitioning FOR VALUES FROM (0, 0) TO (10, 0);
SELECT create_distributed_table('multi_column_partitioning', 'c1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- test INSERT to multi-column partitioned table
INSERT INTO multi_column_partitioning VALUES(1, 1);
INSERT INTO multi_column_partitioning_0_0_10_0 VALUES(5, -5);
-- test INSERT to multi-column partitioned table where no suitable partition exists
INSERT INTO multi_column_partitioning VALUES(10, 1);
ERROR:  no partition of relation "multi_column_partitioning_1660133" found for row
DETAIL:  Partition key of the failing row contains (c1, c2) = (10, 1).
CONTEXT:  while executing command on localhost:xxxxx
-- test with MINVALUE/MAXVALUE
CREATE TABLE multi_column_partitioning_10_max_20_min PARTITION OF multi_column_partitioning FOR VALUES FROM (10, MAXVALUE) TO (20, MINVALUE);
-- test INSERT to partition with MINVALUE/MAXVALUE bounds
INSERT INTO multi_column_partitioning VALUES(11, -11);
INSERT INTO multi_column_partitioning_10_max_20_min VALUES(19, -19);
-- test INSERT to multi-column partitioned table where no suitable partition exists
INSERT INTO multi_column_partitioning VALUES(20, -20);
ERROR:  no partition of relation "multi_column_partitioning_1660133" found for row
DETAIL:  Partition key of the failing row contains (c1, c2) = (20, -20).
CONTEXT:  while executing command on localhost:xxxxx
-- see data is loaded to multi-column partitioned table
SELECT * FROM multi_column_partitioning ORDER BY 1, 2;
 c1 | c2
---------------------------------------------------------------------
  1 |   1
  5 |  -5
 11 | -11
 19 | -19
(4 rows)

--
-- Tests for locks on partitioned tables
--
CREATE TABLE partitioning_locks(id int, ref_id int, time date) PARTITION BY RANGE (time);
-- create its partitions
CREATE TABLE partitioning_locks_2009 PARTITION OF partitioning_locks FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
CREATE TABLE partitioning_locks_2010 PARTITION OF partitioning_locks FOR VALUES FROM ('2010-01-01') TO ('2011-01-01');
-- distribute partitioned table
SELECT create_distributed_table('partitioning_locks', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- test locks on router SELECT
BEGIN;
SELECT * FROM partitioning_locks WHERE id = 1 ORDER BY 1, 2;
 id | ref_id | time
---------------------------------------------------------------------
(0 rows)

SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |      mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2010 | relation | AccessShareLock
(3 rows)

COMMIT;
-- test locks on real-time SELECT
BEGIN;
SELECT * FROM partitioning_locks ORDER BY 1, 2;
 id | ref_id | time
---------------------------------------------------------------------
(0 rows)

SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |      mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2010 | relation | AccessShareLock
(3 rows)

COMMIT;
BEGIN;
SELECT * FROM partitioning_locks AS pl1 JOIN partitioning_locks AS pl2 ON pl1.id = pl2.ref_id ORDER BY 1, 2;
 id | ref_id | time | id | ref_id | time
---------------------------------------------------------------------
(0 rows)

SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |      mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2010 | relation | AccessShareLock
(3 rows)

COMMIT;
-- test locks on INSERT
BEGIN;
INSERT INTO partitioning_locks VALUES(1, 1, '2009-01-01');
SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |       mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks      | relation | RowExclusiveLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2009 | relation | RowExclusiveLock
 partitioning_locks_2010 | relation | AccessShareLock
 partitioning_locks_2010 | relation | RowExclusiveLock
(6 rows)

COMMIT;
-- test locks on UPDATE
BEGIN;
UPDATE partitioning_locks SET time = '2009-02-01' WHERE id = 1;
SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |       mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks      | relation | RowExclusiveLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2009 | relation | RowExclusiveLock
 partitioning_locks_2010 | relation | AccessShareLock
 partitioning_locks_2010 | relation | RowExclusiveLock
(6 rows)

COMMIT;
-- test locks on DELETE
BEGIN;
DELETE FROM partitioning_locks WHERE id = 1;
SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |       mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks      | relation | RowExclusiveLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2009 | relation | RowExclusiveLock
 partitioning_locks_2010 | relation | AccessShareLock
 partitioning_locks_2010 | relation | RowExclusiveLock
(6 rows)

COMMIT;
-- test locks on INSERT/SELECT
CREATE TABLE partitioning_locks_for_select(id int, ref_id int, time date);
SELECT create_distributed_table('partitioning_locks_for_select', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

BEGIN;
INSERT INTO partitioning_locks SELECT * FROM partitioning_locks_for_select;
SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
           relation            | locktype |       mode
---------------------------------------------------------------------
 partitioning_locks            | relation | AccessShareLock
 partitioning_locks            | relation | RowExclusiveLock
 partitioning_locks_2009       | relation | AccessShareLock
 partitioning_locks_2009       | relation | RowExclusiveLock
 partitioning_locks_2010       | relation | AccessShareLock
 partitioning_locks_2010       | relation | RowExclusiveLock
 partitioning_locks_for_select | relation | AccessShareLock
(7 rows)

COMMIT;
-- test locks on coordinator INSERT/SELECT
BEGIN;
INSERT INTO partitioning_locks SELECT * FROM partitioning_locks_for_select LIMIT 5;
SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
           relation            | locktype |       mode
---------------------------------------------------------------------
 partitioning_locks            | relation | AccessShareLock
 partitioning_locks            | relation | RowExclusiveLock
 partitioning_locks_2009       | relation | RowExclusiveLock
 partitioning_locks_2010       | relation | RowExclusiveLock
 partitioning_locks_for_select | relation | AccessShareLock
(5 rows)

COMMIT;
-- test locks on multi-shard UPDATE
BEGIN;
UPDATE partitioning_locks SET time = '2009-03-01';
SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |       mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks      | relation | RowExclusiveLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2009 | relation | RowExclusiveLock
 partitioning_locks_2010 | relation | AccessShareLock
 partitioning_locks_2010 | relation | RowExclusiveLock
(6 rows)

COMMIT;
-- test locks on DDL
BEGIN;
ALTER TABLE partitioning_locks ADD COLUMN new_column int;
SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |        mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessExclusiveLock
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks_2009 | relation | AccessExclusiveLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2010 | relation | AccessExclusiveLock
 partitioning_locks_2010 | relation | AccessShareLock
(6 rows)

COMMIT;
-- test locks on TRUNCATE
BEGIN;
TRUNCATE partitioning_locks;
SELECT relation::regclass, locktype, mode FROM pg_locks WHERE relation::regclass::text LIKE 'partitioning_locks%' AND pid = pg_backend_pid() ORDER BY 1, 2, 3;
        relation         | locktype |        mode
---------------------------------------------------------------------
 partitioning_locks      | relation | AccessExclusiveLock
 partitioning_locks      | relation | AccessShareLock
 partitioning_locks_2009 | relation | AccessExclusiveLock
 partitioning_locks_2009 | relation | AccessShareLock
 partitioning_locks_2009 | relation | ShareLock
 partitioning_locks_2010 | relation | AccessExclusiveLock
 partitioning_locks_2010 | relation | AccessShareLock
 partitioning_locks_2010 | relation | ShareLock
(8 rows)

COMMIT;
CREATE VIEW lockinfo AS
    SELECT
        logicalrelid,
        CASE
            WHEN l.objsubid = 5 THEN 'shard'
            WHEN l.objsubid = 4 THEN 'shard_metadata'
            ELSE 'colocated_shards_metadata'
        END AS locktype,
        mode
    FROM
        pg_locks AS l JOIN (select row_number() over (partition by logicalrelid order by shardminvalue) -1 as shardintervalindex, * from pg_dist_shard) AS s
    ON
        (l.objsubid IN (4, 5) AND l.objid = s.shardid )
        OR (l.objsubid = 8
            AND l.objid IN (select colocationid from pg_dist_partition AS p where p.logicalrelid = s.logicalrelid)
            AND l.classid = shardintervalindex
        )
    WHERE
        logicalrelid IN ('partitioning_locks', 'partitioning_locks_2009', 'partitioning_locks_2010')
        AND pid = pg_backend_pid()
        AND l.locktype = 'advisory'
    ORDER BY
        1, 2, 3;
-- test shard resource locks with multi-shard UPDATE
BEGIN;
UPDATE partitioning_locks_2009 SET time = '2009-03-01';
-- see the locks on parent table
SELECT * FROM lockinfo;
      logicalrelid       |         locktype          |           mode
---------------------------------------------------------------------
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | shard                     | ShareUpdateExclusiveLock
 partitioning_locks      | shard                     | ShareUpdateExclusiveLock
 partitioning_locks      | shard                     | ShareUpdateExclusiveLock
 partitioning_locks      | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2009 | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2009 | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2009 | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
(20 rows)

COMMIT;
-- test shard resource locks with TRUNCATE
BEGIN;
TRUNCATE partitioning_locks_2009;
-- see the locks on parent table
SELECT * FROM lockinfo;
      logicalrelid       |         locktype          |   mode
---------------------------------------------------------------------
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
(12 rows)

COMMIT;
-- test shard resource locks with INSERT/SELECT
BEGIN;
INSERT INTO partitioning_locks_2009 SELECT * FROM partitioning_locks WHERE time >= '2009-01-01' AND time < '2010-01-01';
-- see the locks on parent table
SELECT * FROM lockinfo;
      logicalrelid       |         locktype          |           mode
---------------------------------------------------------------------
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | colocated_shards_metadata | ShareLock
 partitioning_locks      | shard                     | ShareUpdateExclusiveLock
 partitioning_locks      | shard                     | ShareUpdateExclusiveLock
 partitioning_locks      | shard                     | ShareUpdateExclusiveLock
 partitioning_locks      | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | colocated_shards_metadata | ShareLock
 partitioning_locks_2009 | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2009 | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2009 | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2009 | shard                     | ShareUpdateExclusiveLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
 partitioning_locks_2010 | colocated_shards_metadata | ShareLock
(20 rows)

COMMIT;
DROP VIEW lockinfo;
DROP TABLE
IF EXISTS
    partitioning_test_2009,
    partitioned_events_table,
    partitioned_users_table,
    list_partitioned_events_table,
    multi_column_partitioning,
    partitioning_locks,
    partitioning_locks_for_select;
-- make sure we can create a partitioned table with streaming replication
SET citus.shard_replication_factor TO 1;
CREATE TABLE partitioning_test(id int, time date) PARTITION BY RANGE (time);
CREATE TABLE partitioning_test_2009 PARTITION OF partitioning_test FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
SELECT create_distributed_table('partitioning_test', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE partitioning_test;
-- make sure we can attach partitions to a distributed table in a schema
CREATE SCHEMA partitioning_schema;
CREATE TABLE partitioning_schema."schema-test"(id int, time date) PARTITION BY RANGE (time);
SELECT create_distributed_table('partitioning_schema."schema-test"', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE partitioning_schema."schema-test_2009"(id int, time date);
ALTER TABLE partitioning_schema."schema-test" ATTACH PARTITION partitioning_schema."schema-test_2009" FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
-- attached partition is distributed as well
SELECT
	logicalrelid
FROM
	pg_dist_partition
WHERE
	logicalrelid IN ('partitioning_schema."schema-test"'::regclass, 'partitioning_schema."schema-test_2009"'::regclass)
ORDER BY 1;
              logicalrelid
---------------------------------------------------------------------
 partitioning_schema."schema-test"
 partitioning_schema."schema-test_2009"
(2 rows)

SELECT
	logicalrelid, count(*)
FROM
    pg_dist_shard
WHERE
    logicalrelid IN ('partitioning_schema."schema-test"'::regclass, 'partitioning_schema."schema-test_2009"'::regclass)
GROUP BY
	logicalrelid
ORDER BY
	1,2;
              logicalrelid              | count
---------------------------------------------------------------------
 partitioning_schema."schema-test"      |     4
 partitioning_schema."schema-test_2009" |     4
(2 rows)

DROP TABLE partitioning_schema."schema-test";
-- make sure we can create partition of a distributed table in a schema
CREATE TABLE partitioning_schema."schema-test"(id int, time date) PARTITION BY RANGE (time);
SELECT create_distributed_table('partitioning_schema."schema-test"', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE partitioning_schema."schema-test_2009" PARTITION OF partitioning_schema."schema-test" FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
-- newly created partition is distributed as well
SELECT
	logicalrelid
FROM
	pg_dist_partition
WHERE
	logicalrelid IN ('partitioning_schema."schema-test"'::regclass, 'partitioning_schema."schema-test_2009"'::regclass)
ORDER BY 1;
              logicalrelid
---------------------------------------------------------------------
 partitioning_schema."schema-test"
 partitioning_schema."schema-test_2009"
(2 rows)

SELECT
	logicalrelid, count(*)
FROM
    pg_dist_shard
WHERE
    logicalrelid IN ('partitioning_schema."schema-test"'::regclass, 'partitioning_schema."schema-test_2009"'::regclass)
GROUP BY
	logicalrelid
ORDER BY
	1,2;
              logicalrelid              | count
---------------------------------------------------------------------
 partitioning_schema."schema-test"      |     4
 partitioning_schema."schema-test_2009" |     4
(2 rows)

DROP TABLE partitioning_schema."schema-test";
-- make sure creating partitioned tables works while search_path is set
CREATE TABLE partitioning_schema."schema-test"(id int, time date) PARTITION BY RANGE (time);
SET search_path = partitioning_schema;
SELECT create_distributed_table('"schema-test"', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE partitioning_schema."schema-test_2009" PARTITION OF "schema-test" FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
-- newly created partition is distributed as well
SELECT
	logicalrelid
FROM
	pg_dist_partition
WHERE
	logicalrelid IN ('partitioning_schema."schema-test"'::regclass, 'partitioning_schema."schema-test_2009"'::regclass)
ORDER BY 1;
    logicalrelid
---------------------------------------------------------------------
 "schema-test"
 "schema-test_2009"
(2 rows)

SELECT
	logicalrelid, count(*)
FROM
    pg_dist_shard
WHERE
    logicalrelid IN ('partitioning_schema."schema-test"'::regclass, 'partitioning_schema."schema-test_2009"'::regclass)
GROUP BY
	logicalrelid
ORDER BY
	1,2;
    logicalrelid    | count
---------------------------------------------------------------------
 "schema-test"      |     4
 "schema-test_2009" |     4
(2 rows)

SET citus.next_shard_id TO 1660300;
-- test we don't deadlock when attaching and detaching partitions from partitioned
-- tables with foreign keys
CREATE TABLE reference_table(id int PRIMARY KEY);
SELECT create_reference_table('reference_table');
 create_reference_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE reference_table_2(id int PRIMARY KEY);
SELECT create_reference_table('reference_table_2');
 create_reference_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE partitioning_test(id int, time date) PARTITION BY RANGE (time);
CREATE TABLE partitioning_test_2008 PARTITION OF partitioning_test FOR VALUES FROM ('2008-01-01') TO ('2009-01-01');
CREATE TABLE partitioning_test_2009 (LIKE partitioning_test);
CREATE TABLE partitioning_test_2010 (LIKE partitioning_test);
CREATE TABLE partitioning_test_2011 (LIKE partitioning_test);
-- distributing partitioning_test will also distribute partitioning_test_2008
SELECT create_distributed_table('partitioning_test', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT create_distributed_table('partitioning_test_2009', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT create_distributed_table('partitioning_test_2010', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT create_distributed_table('partitioning_test_2011', 'id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_reference_fkey
    FOREIGN KEY (id) REFERENCES reference_table(id) ON DELETE CASCADE;
ALTER TABLE partitioning_test_2009 ADD CONSTRAINT partitioning_reference_fkey_2009
    FOREIGN KEY (id) REFERENCES reference_table(id) ON DELETE CASCADE;
INSERT INTO partitioning_test_2010 VALUES (1, '2010-02-01');
-- This should fail because of foreign key constraint violation
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2010
      FOR VALUES FROM ('2010-01-01') TO ('2011-01-01');
ERROR:  insert or update on table "partitioning_test_2010_1660314" violates foreign key constraint "partitioning_reference_fkey_1660302"
DETAIL:  Key (id)=(X) is not present in table "reference_table_1660300".
CONTEXT:  while executing command on localhost:xxxxx
-- Truncate, so attaching again won't fail
TRUNCATE partitioning_test_2010;
-- Attach a table which already has the same constraint
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2009
      FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
-- Attach a table which doesn't have the constraint
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2010
      FOR VALUES FROM ('2010-01-01') TO ('2011-01-01');
-- Attach a table which has a different constraint
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2011
      FOR VALUES FROM ('2011-01-01') TO ('2012-01-01');
SELECT parent_table, partition_column, partition, from_value, to_value FROM time_partitions;
               parent_table               | partition_column |                 partition                  | from_value |  to_value
---------------------------------------------------------------------
 "schema-test"                            | time             | "schema-test_2009"                         | 01-01-2009 | 01-01-2010
 partitioning_test                        | time             | partitioning_test_2008                     | 01-01-2008 | 01-01-2009
 partitioning_test                        | time             | partitioning_test_2009                     | 01-01-2009 | 01-01-2010
 partitioning_test                        | time             | partitioning_test_2010                     | 01-01-2010 | 01-01-2011
 partitioning_test                        | time             | partitioning_test_2011                     | 01-01-2011 | 01-01-2012
 public.non_distributed_partitioned_table | a                | public.non_distributed_partitioned_table_1 | 0          | 10
(6 rows)

-- create the same partition to verify it behaves like in plain PG
CREATE TABLE partitioning_test_2011 PARTITION OF partitioning_test FOR VALUES FROM ('2011-01-01') TO ('2012-01-01');
ERROR:  relation "partitioning_test_2011" already exists
CREATE TABLE IF NOT EXISTS partitioning_test_2011 PARTITION OF partitioning_test FOR VALUES FROM ('2011-01-01') TO ('2012-01-01');
NOTICE:  relation "partitioning_test_2011" already exists, skipping
-- verify we can create a partition that doesn't already exist with IF NOT EXISTS
CREATE TABLE IF NOT EXISTS partitioning_test_2013 PARTITION OF partitioning_test FOR VALUES FROM ('2013-01-01') TO ('2014-01-01');
SELECT logicalrelid FROM pg_dist_partition WHERE logicalrelid IN ('partitioning_test', 'partitioning_test_2013') ORDER BY 1;
      logicalrelid
---------------------------------------------------------------------
 partitioning_test
 partitioning_test_2013
(2 rows)

-- create the same table but that is not a partition and verify it behaves like in plain PG
CREATE TABLE not_partition(time date);
CREATE TABLE not_partition PARTITION OF partitioning_test FOR VALUES FROM ('2011-01-01') TO ('2012-01-01');
ERROR:  relation "not_partition" already exists
CREATE TABLE IF NOT EXISTS not_partition PARTITION OF partitioning_test FOR VALUES FROM ('2011-01-01') TO ('2012-01-01');
NOTICE:  relation "not_partition" already exists, skipping
DROP TABLE not_partition;
-- verify it skips when the partition with the same name belongs to another table
CREATE TABLE another_table(id int, time date) PARTITION BY RANGE (time);
CREATE TABLE partition_of_other_table PARTITION OF another_table FOR VALUES FROM ('2014-01-01') TO ('2015-01-01');
CREATE TABLE partition_of_other_table PARTITION OF partitioning_test FOR VALUES FROM ('2014-01-01') TO ('2015-01-01');
ERROR:  relation "partition_of_other_table" already exists
CREATE TABLE IF NOT EXISTS partition_of_other_table PARTITION OF partitioning_test FOR VALUES FROM ('2014-01-01') TO ('2015-01-01');
NOTICE:  relation "partition_of_other_table" already exists, skipping
ALTER TABLE another_table DETACH PARTITION partition_of_other_table;
DROP TABLE another_table, partition_of_other_table;
-- test fix_pre_citus10_partitioned_table_constraint_names udf
SELECT fix_pre_citus10_partitioned_table_constraint_names('partitioning_test');
 fix_pre_citus10_partitioned_table_constraint_names
---------------------------------------------------------------------

(1 row)

SELECT fix_pre_citus10_partitioned_table_constraint_names();
 fix_pre_citus10_partitioned_table_constraint_names
---------------------------------------------------------------------
 partitioning_test
 "schema-test"
 public.partitioning_hash_test
 public.partitioning_test_failure
(4 rows)

-- the following should fail
SELECT fix_pre_citus10_partitioned_table_constraint_names('public.non_distributed_partitioned_table');
ERROR:  fix_pre_citus10_partitioned_table_constraint_names can only be called for distributed partitioned tables
SELECT fix_pre_citus10_partitioned_table_constraint_names('reference_table');
ERROR:  could not fix partition constraints: relation does not exist or is not partitioned
ALTER TABLE partitioning_test DETACH PARTITION partitioning_test_2008;
ALTER TABLE partitioning_test DETACH PARTITION partitioning_test_2009;
ALTER TABLE partitioning_test DETACH PARTITION partitioning_test_2010;
ALTER TABLE partitioning_test DETACH PARTITION partitioning_test_2011;
ALTER TABLE partitioning_test DETACH PARTITION partitioning_test_2013;
DROP TABLE partitioning_test_2008, partitioning_test_2009, partitioning_test_2010,
           partitioning_test_2011, partitioning_test_2013, reference_table_2;
-- verify this doesn't crash and gives a debug message for dropped table
SET client_min_messages TO DEBUG1;
DROP TABLE partitioning_test, reference_table;
DEBUG:  drop cascades to constraint partitioning_reference_fkey on table partitioning_schema.partitioning_test
DETAIL:  from localhost:xxxxx
CONTEXT:  SQL statement "SELECT master_remove_distributed_table_metadata_from_workers(v_obj.objid, v_obj.schema_name, v_obj.object_name)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
DEBUG:  drop cascades to constraint partitioning_reference_fkey on table partitioning_schema.partitioning_test
DETAIL:  from localhost:xxxxx
CONTEXT:  SQL statement "SELECT master_remove_distributed_table_metadata_from_workers(v_obj.objid, v_obj.schema_name, v_obj.object_name)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
DEBUG:  switching to sequential query execution mode
DETAIL:  Table "<dropped>" is modified, which might lead to data inconsistencies or distributed deadlocks via parallel accesses to hash distributed tables due to foreign keys. Any parallel modification to those hash distributed tables in the same transaction can only be executed in sequential query execution mode
CONTEXT:  SQL statement "SELECT citus_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name, drop_shards_metadata_only := false)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
CONTEXT:  SQL statement "SELECT citus_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name, drop_shards_metadata_only := false)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
DEBUG:  drop cascades to 2 other objects
DETAIL:  drop cascades to constraint partitioning_reference_fkey_1660302 on table partitioning_schema.partitioning_test_1660302
drop cascades to constraint partitioning_reference_fkey_1660304 on table partitioning_schema.partitioning_test_1660304
DETAIL:  from localhost:xxxxx
CONTEXT:  SQL statement "SELECT citus_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name, drop_shards_metadata_only := false)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
DEBUG:  drop cascades to 2 other objects
DETAIL:  drop cascades to constraint partitioning_reference_fkey_1660303 on table partitioning_schema.partitioning_test_1660303
drop cascades to constraint partitioning_reference_fkey_1660305 on table partitioning_schema.partitioning_test_1660305
DETAIL:  from localhost:xxxxx
CONTEXT:  SQL statement "SELECT citus_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name, drop_shards_metadata_only := false)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
RESET client_min_messages;
RESET SEARCH_PATH;
-- not timestamp partitioned
CREATE TABLE not_time_partitioned (x int, y int) PARTITION BY RANGE (x);
CREATE TABLE not_time_partitioned_p0 PARTITION OF not_time_partitioned DEFAULT;
CREATE TABLE not_time_partitioned_p1 PARTITION OF not_time_partitioned FOR VALUES FROM (1) TO (2);
SELECT parent_table, partition_column, partition, from_value, to_value FROM time_partitions;
           parent_table            | partition_column |               partition                | from_value |  to_value
---------------------------------------------------------------------
 non_distributed_partitioned_table | a                | non_distributed_partitioned_table_1    | 0          | 10
 not_time_partitioned              | x                | not_time_partitioned_p1                | 1          | 2
 not_time_partitioned              | x                | not_time_partitioned_p0                |            |
 partitioning_schema."schema-test" | time             | partitioning_schema."schema-test_2009" | 01-01-2009 | 01-01-2010
(4 rows)

SELECT * FROM time_partition_range('not_time_partitioned_p1');
 lower_bound | upper_bound
---------------------------------------------------------------------
 1           | 2
(1 row)

DROP TABLE not_time_partitioned;
-- multi-column partitioned
CREATE TABLE multi_column_partitioned (x date, y date) PARTITION BY RANGE (x, y);
CREATE TABLE multi_column_partitioned_p1 PARTITION OF multi_column_partitioned  FOR VALUES FROM ('2020-01-01', '2020-01-01') TO ('2020-12-31','2020-12-31');
SELECT parent_table, partition_column, partition, from_value, to_value FROM time_partitions;
           parent_table            | partition_column |               partition                | from_value |  to_value
---------------------------------------------------------------------
 non_distributed_partitioned_table | a                | non_distributed_partitioned_table_1    | 0          | 10
 partitioning_schema."schema-test" | time             | partitioning_schema."schema-test_2009" | 01-01-2009 | 01-01-2010
(2 rows)

SELECT * FROM time_partition_range('multi_column_partitioned_p1');
ERROR:  relation "multi_column_partitioned_p1" is a partition with multiple partition columns
DETAIL:  time_partition_range can only be used for partitions of range-partitioned tables with a single partition column
DROP TABLE multi_column_partitioned;
-- not-range-partitioned
CREATE TABLE list_partitioned (x date, y date) PARTITION BY LIST (x);
CREATE TABLE list_partitioned_p1 PARTITION OF list_partitioned FOR VALUES IN ('2020-01-01');
SELECT parent_table, partition_column, partition, from_value, to_value FROM time_partitions;
           parent_table            | partition_column |               partition                | from_value |  to_value
---------------------------------------------------------------------
 non_distributed_partitioned_table | a                | non_distributed_partitioned_table_1    | 0          | 10
 partitioning_schema."schema-test" | time             | partitioning_schema."schema-test_2009" | 01-01-2009 | 01-01-2010
(2 rows)

SELECT * FROM time_partition_range('list_partitioned_p1');
ERROR:  relation "list_partitioned_p1" is not a range partition
DETAIL:  time_partition_range can only be used for partitions of range-partitioned tables with a single partition column
DROP TABLE list_partitioned;
-- error out when inheriting a distributed table
CREATE TABLE test_inheritance(a int, b int);
SELECT create_distributed_table('test_inheritance','a');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE local_inheritance (k int) INHERITS (test_inheritance);
ERROR:  non-distributed tables cannot inherit distributed tables
DROP TABLE test_inheritance;
-- test worker partitioned table size functions
CREATE TABLE "events.Energy Added" (user_id int, time timestamp with time zone, data jsonb, PRIMARY KEY (user_id, time )) PARTITION BY RANGE ("time");
SELECT create_distributed_table('"events.Energy Added"', 'user_id', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE "Energy Added_17634"  PARTITION OF "events.Energy Added" FOR VALUES  FROM ('2018-04-13 00:00:00+00') TO ('2018-04-14 00:00:00+00');
-- test shard cost by disk size function
SET client_min_messages TO DEBUG1;
SELECT citus_shard_cost_by_disk_size(shardid) FROM pg_dist_shard WHERE logicalrelid = '"events.Energy Added"'::regclass ORDER BY shardid LIMIT 1;
DEBUG:  skipping child tables for relation named: events.Energy Added
 citus_shard_cost_by_disk_size
---------------------------------------------------------------------
                   1.04874e+08
(1 row)

RESET client_min_messages;
CREATE INDEX idx_btree_hobbies ON "events.Energy Added" USING BTREE ((data->>'location'));
 \c - - - :worker_1_port
-- should not be zero because of TOAST, vm, fms
SELECT worker_partitioned_table_size(oid) FROM pg_class WHERE relname LIKE '%events.Energy Added%' ORDER BY relname LIMIT 1;
 worker_partitioned_table_size
---------------------------------------------------------------------
                          8192
(1 row)

-- should be zero since no data
SELECT worker_partitioned_relation_size(oid) FROM pg_class WHERE relname LIKE '%events.Energy Added%' ORDER BY relname LIMIT 1;
 worker_partitioned_relation_size
---------------------------------------------------------------------
                                0
(1 row)

-- should not be zero because of indexes + pg_table_size()
SELECT worker_partitioned_relation_total_size(oid) FROM pg_class WHERE relname LIKE '%events.Energy Added%' ORDER BY relname LIMIT 1;
 worker_partitioned_relation_total_size
---------------------------------------------------------------------
                                  24576
(1 row)

 \c - - - :master_port
DROP TABLE "events.Energy Added";
-- test we skip the foreign key validation query on coordinator
-- that happens when attaching a non-distributed partition to a distributed-partitioned table
-- with a foreign key to another distributed table
SET search_path = partitioning_schema;
SET citus.shard_replication_factor = 1;
CREATE TABLE another_distributed_table (x int primary key, y int);
SELECT create_distributed_table('another_distributed_table','x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE distributed_parent_table (
  event_id serial NOT NULL REFERENCES another_distributed_table (x),
  event_time timestamptz NOT NULL DEFAULT now())
  PARTITION BY RANGE (event_time);
SELECT create_distributed_table('distributed_parent_table', 'event_id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE non_distributed_child_1 (event_id int NOT NULL, event_time timestamptz NOT NULL DEFAULT now());
ALTER TABLE distributed_parent_table ATTACH PARTITION non_distributed_child_1 FOR VALUES FROM ('2021-06-30') TO ('2021-07-01');
-- check DEFAULT partition behaves as expected
CREATE TABLE non_distributed_child_2 (event_id int NOT NULL, event_time timestamptz NOT NULL DEFAULT now());
ALTER TABLE distributed_parent_table ATTACH PARTITION non_distributed_child_2 DEFAULT;
-- check adding another partition when default partition exists
CREATE TABLE non_distributed_child_3 (event_id int NOT NULL, event_time timestamptz NOT NULL DEFAULT now());
ALTER TABLE distributed_parent_table ATTACH PARTITION non_distributed_child_3 FOR VALUES FROM ('2021-07-30') TO ('2021-08-01');
-- Test time partition utility UDFs
-- a) test get_missing_time_partition_ranges
-- 1) test get_missing_time_partition_ranges with date partitioned table
CREATE TABLE date_partitioned_table(
 measureid integer,
 eventdate date,
 measure_data jsonb) PARTITION BY RANGE(eventdate);
SELECT create_distributed_table('date_partitioned_table','measureid');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- test interval must be multiple days for date partitioned table
SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '6 hours', '2022-01-01', '2021-01-01');
ERROR:  partition interval of date partitioned table must be day or multiple days
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '1 week 1 day 1 hour', '2022-01-01', '2021-01-01');
ERROR:  partition interval of date partitioned table must be day or multiple days
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
-- test with various intervals
SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '1 day', '2021-02-01', '2021-01-01');
           partition_name           | range_from_value | range_to_value
---------------------------------------------------------------------
 date_partitioned_table_p2021_01_01 | 01-01-2021       | 01-02-2021
 date_partitioned_table_p2021_01_02 | 01-02-2021       | 01-03-2021
 date_partitioned_table_p2021_01_03 | 01-03-2021       | 01-04-2021
 date_partitioned_table_p2021_01_04 | 01-04-2021       | 01-05-2021
 date_partitioned_table_p2021_01_05 | 01-05-2021       | 01-06-2021
 date_partitioned_table_p2021_01_06 | 01-06-2021       | 01-07-2021
 date_partitioned_table_p2021_01_07 | 01-07-2021       | 01-08-2021
 date_partitioned_table_p2021_01_08 | 01-08-2021       | 01-09-2021
 date_partitioned_table_p2021_01_09 | 01-09-2021       | 01-10-2021
 date_partitioned_table_p2021_01_10 | 01-10-2021       | 01-11-2021
 date_partitioned_table_p2021_01_11 | 01-11-2021       | 01-12-2021
 date_partitioned_table_p2021_01_12 | 01-12-2021       | 01-13-2021
 date_partitioned_table_p2021_01_13 | 01-13-2021       | 01-14-2021
 date_partitioned_table_p2021_01_14 | 01-14-2021       | 01-15-2021
 date_partitioned_table_p2021_01_15 | 01-15-2021       | 01-16-2021
 date_partitioned_table_p2021_01_16 | 01-16-2021       | 01-17-2021
 date_partitioned_table_p2021_01_17 | 01-17-2021       | 01-18-2021
 date_partitioned_table_p2021_01_18 | 01-18-2021       | 01-19-2021
 date_partitioned_table_p2021_01_19 | 01-19-2021       | 01-20-2021
 date_partitioned_table_p2021_01_20 | 01-20-2021       | 01-21-2021
 date_partitioned_table_p2021_01_21 | 01-21-2021       | 01-22-2021
 date_partitioned_table_p2021_01_22 | 01-22-2021       | 01-23-2021
 date_partitioned_table_p2021_01_23 | 01-23-2021       | 01-24-2021
 date_partitioned_table_p2021_01_24 | 01-24-2021       | 01-25-2021
 date_partitioned_table_p2021_01_25 | 01-25-2021       | 01-26-2021
 date_partitioned_table_p2021_01_26 | 01-26-2021       | 01-27-2021
 date_partitioned_table_p2021_01_27 | 01-27-2021       | 01-28-2021
 date_partitioned_table_p2021_01_28 | 01-28-2021       | 01-29-2021
 date_partitioned_table_p2021_01_29 | 01-29-2021       | 01-30-2021
 date_partitioned_table_p2021_01_30 | 01-30-2021       | 01-31-2021
 date_partitioned_table_p2021_01_31 | 01-31-2021       | 02-01-2021
(31 rows)

SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '1 week', '2022-01-01', '2021-01-01');
         partition_name          | range_from_value | range_to_value
---------------------------------------------------------------------
 date_partitioned_table_p2020w53 | 12-28-2020       | 01-04-2021
 date_partitioned_table_p2021w01 | 01-04-2021       | 01-11-2021
 date_partitioned_table_p2021w02 | 01-11-2021       | 01-18-2021
 date_partitioned_table_p2021w03 | 01-18-2021       | 01-25-2021
 date_partitioned_table_p2021w04 | 01-25-2021       | 02-01-2021
 date_partitioned_table_p2021w05 | 02-01-2021       | 02-08-2021
 date_partitioned_table_p2021w06 | 02-08-2021       | 02-15-2021
 date_partitioned_table_p2021w07 | 02-15-2021       | 02-22-2021
 date_partitioned_table_p2021w08 | 02-22-2021       | 03-01-2021
 date_partitioned_table_p2021w09 | 03-01-2021       | 03-08-2021
 date_partitioned_table_p2021w10 | 03-08-2021       | 03-15-2021
 date_partitioned_table_p2021w11 | 03-15-2021       | 03-22-2021
 date_partitioned_table_p2021w12 | 03-22-2021       | 03-29-2021
 date_partitioned_table_p2021w13 | 03-29-2021       | 04-05-2021
 date_partitioned_table_p2021w14 | 04-05-2021       | 04-12-2021
 date_partitioned_table_p2021w15 | 04-12-2021       | 04-19-2021
 date_partitioned_table_p2021w16 | 04-19-2021       | 04-26-2021
 date_partitioned_table_p2021w17 | 04-26-2021       | 05-03-2021
 date_partitioned_table_p2021w18 | 05-03-2021       | 05-10-2021
 date_partitioned_table_p2021w19 | 05-10-2021       | 05-17-2021
 date_partitioned_table_p2021w20 | 05-17-2021       | 05-24-2021
 date_partitioned_table_p2021w21 | 05-24-2021       | 05-31-2021
 date_partitioned_table_p2021w22 | 05-31-2021       | 06-07-2021
 date_partitioned_table_p2021w23 | 06-07-2021       | 06-14-2021
 date_partitioned_table_p2021w24 | 06-14-2021       | 06-21-2021
 date_partitioned_table_p2021w25 | 06-21-2021       | 06-28-2021
 date_partitioned_table_p2021w26 | 06-28-2021       | 07-05-2021
 date_partitioned_table_p2021w27 | 07-05-2021       | 07-12-2021
 date_partitioned_table_p2021w28 | 07-12-2021       | 07-19-2021
 date_partitioned_table_p2021w29 | 07-19-2021       | 07-26-2021
 date_partitioned_table_p2021w30 | 07-26-2021       | 08-02-2021
 date_partitioned_table_p2021w31 | 08-02-2021       | 08-09-2021
 date_partitioned_table_p2021w32 | 08-09-2021       | 08-16-2021
 date_partitioned_table_p2021w33 | 08-16-2021       | 08-23-2021
 date_partitioned_table_p2021w34 | 08-23-2021       | 08-30-2021
 date_partitioned_table_p2021w35 | 08-30-2021       | 09-06-2021
 date_partitioned_table_p2021w36 | 09-06-2021       | 09-13-2021
 date_partitioned_table_p2021w37 | 09-13-2021       | 09-20-2021
 date_partitioned_table_p2021w38 | 09-20-2021       | 09-27-2021
 date_partitioned_table_p2021w39 | 09-27-2021       | 10-04-2021
 date_partitioned_table_p2021w40 | 10-04-2021       | 10-11-2021
 date_partitioned_table_p2021w41 | 10-11-2021       | 10-18-2021
 date_partitioned_table_p2021w42 | 10-18-2021       | 10-25-2021
 date_partitioned_table_p2021w43 | 10-25-2021       | 11-01-2021
 date_partitioned_table_p2021w44 | 11-01-2021       | 11-08-2021
 date_partitioned_table_p2021w45 | 11-08-2021       | 11-15-2021
 date_partitioned_table_p2021w46 | 11-15-2021       | 11-22-2021
 date_partitioned_table_p2021w47 | 11-22-2021       | 11-29-2021
 date_partitioned_table_p2021w48 | 11-29-2021       | 12-06-2021
 date_partitioned_table_p2021w49 | 12-06-2021       | 12-13-2021
 date_partitioned_table_p2021w50 | 12-13-2021       | 12-20-2021
 date_partitioned_table_p2021w51 | 12-20-2021       | 12-27-2021
 date_partitioned_table_p2021w52 | 12-27-2021       | 01-03-2022
(53 rows)

SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '1 month', '2022-01-01', '2021-01-01');
         partition_name          | range_from_value | range_to_value
---------------------------------------------------------------------
 date_partitioned_table_p2021_01 | 01-01-2021       | 02-01-2021
 date_partitioned_table_p2021_02 | 02-01-2021       | 03-01-2021
 date_partitioned_table_p2021_03 | 03-01-2021       | 04-01-2021
 date_partitioned_table_p2021_04 | 04-01-2021       | 05-01-2021
 date_partitioned_table_p2021_05 | 05-01-2021       | 06-01-2021
 date_partitioned_table_p2021_06 | 06-01-2021       | 07-01-2021
 date_partitioned_table_p2021_07 | 07-01-2021       | 08-01-2021
 date_partitioned_table_p2021_08 | 08-01-2021       | 09-01-2021
 date_partitioned_table_p2021_09 | 09-01-2021       | 10-01-2021
 date_partitioned_table_p2021_10 | 10-01-2021       | 11-01-2021
 date_partitioned_table_p2021_11 | 11-01-2021       | 12-01-2021
 date_partitioned_table_p2021_12 | 12-01-2021       | 01-01-2022
(12 rows)

SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '3 months', '2022-01-01', '2021-01-01');
         partition_name         | range_from_value | range_to_value
---------------------------------------------------------------------
 date_partitioned_table_p2021q1 | 01-01-2021       | 04-01-2021
 date_partitioned_table_p2021q2 | 04-01-2021       | 07-01-2021
 date_partitioned_table_p2021q3 | 07-01-2021       | 10-01-2021
 date_partitioned_table_p2021q4 | 10-01-2021       | 01-01-2022
(4 rows)

SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '6 months', '2022-01-01', '2021-01-01');
         partition_name          | range_from_value | range_to_value
---------------------------------------------------------------------
 date_partitioned_table_p2021_01 | 01-01-2021       | 07-01-2021
 date_partitioned_table_p2021_07 | 07-01-2021       | 01-01-2022
(2 rows)

-- test with from_date > to_date
SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '1 day', '2021-01-01', '2021-02-01');
 partition_name | range_from_value | range_to_value
---------------------------------------------------------------------
(0 rows)

-- test with existing partitions
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-02');
  SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '1 day', '2021-01-05', '2020-12-30');
           partition_name           | range_from_value | range_to_value
---------------------------------------------------------------------
 date_partitioned_table_p2020_12_30 | 12-30-2020       | 12-31-2020
 date_partitioned_table_p2020_12_31 | 12-31-2020       | 01-01-2021
 date_partitioned_table_p2021_01_02 | 01-02-2021       | 01-03-2021
 date_partitioned_table_p2021_01_03 | 01-03-2021       | 01-04-2021
 date_partitioned_table_p2021_01_04 | 01-04-2021       | 01-05-2021
(5 rows)

  SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '2 days', '2021-01-05', '2020-12-30');
ERROR:  partition date_partitioned_table_2021_01_01 with the range from 01-01-2021 to 01-02-2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-02');
  CREATE TABLE date_partitioned_table_2021_01_02 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-02') TO ('2021-01-03');
  SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '1 day', '2021-01-05', '2020-12-30');
           partition_name           | range_from_value | range_to_value
---------------------------------------------------------------------
 date_partitioned_table_p2020_12_30 | 12-30-2020       | 12-31-2020
 date_partitioned_table_p2020_12_31 | 12-31-2020       | 01-01-2021
 date_partitioned_table_p2021_01_03 | 01-03-2021       | 01-04-2021
 date_partitioned_table_p2021_01_04 | 01-04-2021       | 01-05-2021
(4 rows)

  SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '2 days', '2021-01-05', '2020-12-30');
ERROR:  partition date_partitioned_table_2021_01_01 with the range from 01-01-2021 to 01-02-2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-03');
  CREATE TABLE date_partitioned_table_2021_01_02 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-05') TO ('2021-01-07');
  SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '2 days', '2021-01-15', '2020-12-30');
           partition_name           | range_from_value | range_to_value
---------------------------------------------------------------------
 date_partitioned_table_p2020_12_30 | 12-30-2020       | 01-01-2021
 date_partitioned_table_p2021_01_03 | 01-03-2021       | 01-05-2021
 date_partitioned_table_p2021_01_07 | 01-07-2021       | 01-09-2021
 date_partitioned_table_p2021_01_09 | 01-09-2021       | 01-11-2021
 date_partitioned_table_p2021_01_11 | 01-11-2021       | 01-13-2021
 date_partitioned_table_p2021_01_13 | 01-13-2021       | 01-15-2021
(6 rows)

ROLLBACK;
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-02');
  CREATE TABLE date_partitioned_table_2021_01_02 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-02') TO ('2021-01-04');
  SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '2 days', '2021-01-05', '2020-12-30');
ERROR:  partition date_partitioned_table_2021_01_01 with the range from 01-01-2021 to 01-02-2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-03');
  CREATE TABLE date_partitioned_table_2021_01_02 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-04') TO ('2021-01-06');
  SELECT * FROM get_missing_time_partition_ranges('date_partitioned_table', INTERVAL '2 days', '2021-01-15', '2020-12-30');
ERROR:  partition date_partitioned_table_2021_01_02 with the range from 01-04-2021 to 01-06-2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
DROP TABLE date_partitioned_table;
-- 2) test timestamp with time zone partitioend table
CREATE TABLE tstz_partitioned_table(
 measureid integer,
 eventdatetime timestamp with time zone,
 measure_data jsonb) PARTITION BY RANGE(eventdatetime);
SELECT create_distributed_table('tstz_partitioned_table','measureid');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- test with various intervals
SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '30 minutes', '2021-01-01 12:00:00', '2021-01-01 00:00:00');
             partition_name              |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 PST | Fri Jan 01 00:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0030 | Fri Jan 01 00:30:00 2021 PST | Fri Jan 01 01:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 PST | Fri Jan 01 01:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0130 | Fri Jan 01 01:30:00 2021 PST | Fri Jan 01 02:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 PST | Fri Jan 01 02:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0230 | Fri Jan 01 02:30:00 2021 PST | Fri Jan 01 03:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 PST | Fri Jan 01 03:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0330 | Fri Jan 01 03:30:00 2021 PST | Fri Jan 01 04:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 PST | Fri Jan 01 04:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0430 | Fri Jan 01 04:30:00 2021 PST | Fri Jan 01 05:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 PST | Fri Jan 01 05:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0530 | Fri Jan 01 05:30:00 2021 PST | Fri Jan 01 06:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 PST | Fri Jan 01 06:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0630 | Fri Jan 01 06:30:00 2021 PST | Fri Jan 01 07:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 PST | Fri Jan 01 07:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0730 | Fri Jan 01 07:30:00 2021 PST | Fri Jan 01 08:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 PST | Fri Jan 01 08:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0830 | Fri Jan 01 08:30:00 2021 PST | Fri Jan 01 09:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 PST | Fri Jan 01 09:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0930 | Fri Jan 01 09:30:00 2021 PST | Fri Jan 01 10:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 PST | Fri Jan 01 10:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1030 | Fri Jan 01 10:30:00 2021 PST | Fri Jan 01 11:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 PST | Fri Jan 01 11:30:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1130 | Fri Jan 01 11:30:00 2021 PST | Fri Jan 01 12:00:00 2021 PST
(24 rows)

SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '1 hour', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
             partition_name              |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 PST | Fri Jan 01 01:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 PST | Fri Jan 01 02:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 PST | Fri Jan 01 03:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 PST | Fri Jan 01 04:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 PST | Fri Jan 01 05:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 PST | Fri Jan 01 06:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 PST | Fri Jan 01 07:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 PST | Fri Jan 01 08:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 PST | Fri Jan 01 09:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 PST | Fri Jan 01 10:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 PST | Fri Jan 01 11:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 PST | Fri Jan 01 12:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 PST | Fri Jan 01 13:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1300 | Fri Jan 01 13:00:00 2021 PST | Fri Jan 01 14:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1400 | Fri Jan 01 14:00:00 2021 PST | Fri Jan 01 15:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1500 | Fri Jan 01 15:00:00 2021 PST | Fri Jan 01 16:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1600 | Fri Jan 01 16:00:00 2021 PST | Fri Jan 01 17:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1700 | Fri Jan 01 17:00:00 2021 PST | Fri Jan 01 18:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 PST | Fri Jan 01 19:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1900 | Fri Jan 01 19:00:00 2021 PST | Fri Jan 01 20:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_2000 | Fri Jan 01 20:00:00 2021 PST | Fri Jan 01 21:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_2100 | Fri Jan 01 21:00:00 2021 PST | Fri Jan 01 22:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_2200 | Fri Jan 01 22:00:00 2021 PST | Fri Jan 01 23:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_2300 | Fri Jan 01 23:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST
(24 rows)

SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '6 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
             partition_name              |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 PST | Fri Jan 01 06:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 PST | Fri Jan 01 12:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 PST | Fri Jan 01 18:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST
(4 rows)

SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '12 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
             partition_name              |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 PST | Fri Jan 01 12:00:00 2021 PST
 tstz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST
(2 rows)

SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2021-01-01 00:00:00');
           partition_name           |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2021_01_01 | Fri Jan 01 00:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 PST | Sun Jan 03 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 PST | Mon Jan 04 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 PST | Tue Jan 05 00:00:00 2021 PST
(4 rows)

SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '1 week', '2021-01-15 00:00:00', '2021-01-01 00:00:00');
         partition_name          |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2020w53 | Mon Dec 28 00:00:00 2020 PST | Mon Jan 04 00:00:00 2021 PST
 tstz_partitioned_table_p2021w01 | Mon Jan 04 00:00:00 2021 PST | Mon Jan 11 00:00:00 2021 PST
 tstz_partitioned_table_p2021w02 | Mon Jan 11 00:00:00 2021 PST | Mon Jan 18 00:00:00 2021 PST
(3 rows)

-- test with from_date > to_date
SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '1 day', '2021-01-01 00:00:00', '2021-01-05 00:00:00');
 partition_name | range_from_value | range_to_value
---------------------------------------------------------------------
(0 rows)

-- test with existing partitions
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
           partition_name           |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 PST | Thu Dec 31 00:00:00 2020 PST
 tstz_partitioned_table_p2020_12_31 | Thu Dec 31 00:00:00 2020 PST | Fri Jan 01 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 PST | Sun Jan 03 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 PST | Mon Jan 04 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 PST | Tue Jan 05 00:00:00 2021 PST
(5 rows)

  SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tstz_partitioned_table_2021_01_01 with the range from Fri Jan 01 00:00:00 2021 PST to Sat Jan 02 00:00:00 2021 PST does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  CREATE TABLE tstz_partitioned_table_2021_01_02 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-02 00:00:00') TO ('2021-01-03 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
           partition_name           |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 PST | Thu Dec 31 00:00:00 2020 PST
 tstz_partitioned_table_p2020_12_31 | Thu Dec 31 00:00:00 2020 PST | Fri Jan 01 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 PST | Mon Jan 04 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 PST | Tue Jan 05 00:00:00 2021 PST
(4 rows)

  SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tstz_partitioned_table_2021_01_01 with the range from Fri Jan 01 00:00:00 2021 PST to Sat Jan 02 00:00:00 2021 PST does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-03 00:00:00');
  CREATE TABLE tstz_partitioned_table_2021_01_02 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-05 00:00:00') TO ('2021-01-07 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '2 days', '2021-01-15 00:00:00', '2020-12-30 00:00:00');
           partition_name           |       range_from_value       |        range_to_value
---------------------------------------------------------------------
 tstz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 PST | Fri Jan 01 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 PST | Tue Jan 05 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_07 | Thu Jan 07 00:00:00 2021 PST | Sat Jan 09 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_09 | Sat Jan 09 00:00:00 2021 PST | Mon Jan 11 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_11 | Mon Jan 11 00:00:00 2021 PST | Wed Jan 13 00:00:00 2021 PST
 tstz_partitioned_table_p2021_01_13 | Wed Jan 13 00:00:00 2021 PST | Fri Jan 15 00:00:00 2021 PST
(6 rows)

ROLLBACK;
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  CREATE TABLE tstz_partitioned_table_2021_01_02 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-02 00:00:00') TO ('2021-01-04 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tstz_partitioned_table_2021_01_01 with the range from Fri Jan 01 00:00:00 2021 PST to Sat Jan 02 00:00:00 2021 PST does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-03 00:00:00');
  CREATE TABLE tstz_partitioned_table_2021_01_02 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-04 00:00:00') TO ('2021-01-06 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '2 days', '2021-01-15 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tstz_partitioned_table_2021_01_02 with the range from Mon Jan 04 00:00:00 2021 PST to Wed Jan 06 00:00:00 2021 PST does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
DROP TABLE tstz_partitioned_table;
-- 3) test timestamp without time zone partitioend table
CREATE TABLE tswtz_partitioned_table(
 measureid integer,
 eventdatetime timestamp without time zone,
 measure_data jsonb) PARTITION BY RANGE(eventdatetime);
SELECT create_distributed_table('tswtz_partitioned_table','measureid');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- test with various intervals
SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '30 minutes', '2021-01-01 12:00:00', '2021-01-01 00:00:00');
              partition_name              |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 00:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0030 | Fri Jan 01 00:30:00 2021 | Fri Jan 01 01:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 | Fri Jan 01 01:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0130 | Fri Jan 01 01:30:00 2021 | Fri Jan 01 02:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 | Fri Jan 01 02:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0230 | Fri Jan 01 02:30:00 2021 | Fri Jan 01 03:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 | Fri Jan 01 03:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0330 | Fri Jan 01 03:30:00 2021 | Fri Jan 01 04:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 | Fri Jan 01 04:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0430 | Fri Jan 01 04:30:00 2021 | Fri Jan 01 05:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 | Fri Jan 01 05:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0530 | Fri Jan 01 05:30:00 2021 | Fri Jan 01 06:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 06:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0630 | Fri Jan 01 06:30:00 2021 | Fri Jan 01 07:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 | Fri Jan 01 07:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0730 | Fri Jan 01 07:30:00 2021 | Fri Jan 01 08:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 | Fri Jan 01 08:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0830 | Fri Jan 01 08:30:00 2021 | Fri Jan 01 09:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 | Fri Jan 01 09:30:00 2021
 tswtz_partitioned_table_p2021_01_01_0930 | Fri Jan 01 09:30:00 2021 | Fri Jan 01 10:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 | Fri Jan 01 10:30:00 2021
 tswtz_partitioned_table_p2021_01_01_1030 | Fri Jan 01 10:30:00 2021 | Fri Jan 01 11:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 | Fri Jan 01 11:30:00 2021
 tswtz_partitioned_table_p2021_01_01_1130 | Fri Jan 01 11:30:00 2021 | Fri Jan 01 12:00:00 2021
(24 rows)

SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '1 hour', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
              partition_name              |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 01:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 | Fri Jan 01 02:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 | Fri Jan 01 03:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 | Fri Jan 01 04:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 | Fri Jan 01 05:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 | Fri Jan 01 06:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 07:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 | Fri Jan 01 08:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 | Fri Jan 01 09:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 | Fri Jan 01 10:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 | Fri Jan 01 11:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 | Fri Jan 01 12:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 | Fri Jan 01 13:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1300 | Fri Jan 01 13:00:00 2021 | Fri Jan 01 14:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1400 | Fri Jan 01 14:00:00 2021 | Fri Jan 01 15:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1500 | Fri Jan 01 15:00:00 2021 | Fri Jan 01 16:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1600 | Fri Jan 01 16:00:00 2021 | Fri Jan 01 17:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1700 | Fri Jan 01 17:00:00 2021 | Fri Jan 01 18:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 | Fri Jan 01 19:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1900 | Fri Jan 01 19:00:00 2021 | Fri Jan 01 20:00:00 2021
 tswtz_partitioned_table_p2021_01_01_2000 | Fri Jan 01 20:00:00 2021 | Fri Jan 01 21:00:00 2021
 tswtz_partitioned_table_p2021_01_01_2100 | Fri Jan 01 21:00:00 2021 | Fri Jan 01 22:00:00 2021
 tswtz_partitioned_table_p2021_01_01_2200 | Fri Jan 01 22:00:00 2021 | Fri Jan 01 23:00:00 2021
 tswtz_partitioned_table_p2021_01_01_2300 | Fri Jan 01 23:00:00 2021 | Sat Jan 02 00:00:00 2021
(24 rows)

SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '6 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
              partition_name              |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 06:00:00 2021
 tswtz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 12:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 | Fri Jan 01 18:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 | Sat Jan 02 00:00:00 2021
(4 rows)

SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '12 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
              partition_name              |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 12:00:00 2021
 tswtz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 | Sat Jan 02 00:00:00 2021
(2 rows)

SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2021-01-01 00:00:00');
           partition_name            |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2021_01_01 | Fri Jan 01 00:00:00 2021 | Sat Jan 02 00:00:00 2021
 tswtz_partitioned_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 | Sun Jan 03 00:00:00 2021
 tswtz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 | Mon Jan 04 00:00:00 2021
 tswtz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 | Tue Jan 05 00:00:00 2021
(4 rows)

SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '1 week', '2021-01-15 00:00:00', '2021-01-01 00:00:00');
          partition_name          |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2020w53 | Mon Dec 28 00:00:00 2020 | Mon Jan 04 00:00:00 2021
 tswtz_partitioned_table_p2021w01 | Mon Jan 04 00:00:00 2021 | Mon Jan 11 00:00:00 2021
 tswtz_partitioned_table_p2021w02 | Mon Jan 11 00:00:00 2021 | Mon Jan 18 00:00:00 2021
(3 rows)

-- test with from_date > to_date
SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '1 day', '2021-01-01 00:00:00', '2021-01-05 00:00:00');
 partition_name | range_from_value | range_to_value
---------------------------------------------------------------------
(0 rows)

-- test with existing partitions
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2021_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
           partition_name            |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 | Thu Dec 31 00:00:00 2020
 tswtz_partitioned_table_p2020_12_31 | Thu Dec 31 00:00:00 2020 | Fri Jan 01 00:00:00 2021
 tswtz_partitioned_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 | Sun Jan 03 00:00:00 2021
 tswtz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 | Mon Jan 04 00:00:00 2021
 tswtz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 | Tue Jan 05 00:00:00 2021
(5 rows)

  SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tswtz_partitioned_table_2021_01_01 with the range from Fri Jan 01 00:00:00 2021 to Sat Jan 02 00:00:00 2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2021_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  CREATE TABLE tswtz_partitioned_table_2021_01_02 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-02 00:00:00') TO ('2021-01-03 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
           partition_name            |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 | Thu Dec 31 00:00:00 2020
 tswtz_partitioned_table_p2020_12_31 | Thu Dec 31 00:00:00 2020 | Fri Jan 01 00:00:00 2021
 tswtz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 | Mon Jan 04 00:00:00 2021
 tswtz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 | Tue Jan 05 00:00:00 2021
(4 rows)

  SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tswtz_partitioned_table_2021_01_01 with the range from Fri Jan 01 00:00:00 2021 to Sat Jan 02 00:00:00 2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2021_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-03 00:00:00');
  CREATE TABLE tswtz_partitioned_table_2021_01_02 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-05 00:00:00') TO ('2021-01-07 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-15 00:00:00', '2020-12-30 00:00:00');
           partition_name            |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 tswtz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 | Fri Jan 01 00:00:00 2021
 tswtz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 | Tue Jan 05 00:00:00 2021
 tswtz_partitioned_table_p2021_01_07 | Thu Jan 07 00:00:00 2021 | Sat Jan 09 00:00:00 2021
 tswtz_partitioned_table_p2021_01_09 | Sat Jan 09 00:00:00 2021 | Mon Jan 11 00:00:00 2021
 tswtz_partitioned_table_p2021_01_11 | Mon Jan 11 00:00:00 2021 | Wed Jan 13 00:00:00 2021
 tswtz_partitioned_table_p2021_01_13 | Wed Jan 13 00:00:00 2021 | Fri Jan 15 00:00:00 2021
(6 rows)

ROLLBACK;
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2021_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  CREATE TABLE tswtz_partitioned_table_2021_01_02 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-02 00:00:00') TO ('2021-01-04 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tswtz_partitioned_table_2021_01_01 with the range from Fri Jan 01 00:00:00 2021 to Sat Jan 02 00:00:00 2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2021_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-03 00:00:00');
  CREATE TABLE tswtz_partitioned_table_2021_01_02 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-04 00:00:00') TO ('2021-01-06 00:00:00');
  SELECT * FROM get_missing_time_partition_ranges('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-15 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tswtz_partitioned_table_2021_01_02 with the range from Mon Jan 04 00:00:00 2021 to Wed Jan 06 00:00:00 2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
DROP TABLE tswtz_partitioned_table;
-- 4) test with weird name
CREATE TABLE "test !/ \n _dist_123_table"(
 measureid integer,
 eventdatetime timestamp without time zone,
 measure_data jsonb) PARTITION BY RANGE(eventdatetime);
SELECT create_distributed_table('"test !/ \n _dist_123_table"','measureid');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- test with various intervals
SELECT * FROM get_missing_time_partition_ranges('"test !/ \n _dist_123_table"', INTERVAL '30 minutes', '2021-01-01 12:00:00', '2021-01-01 00:00:00');
               partition_name                |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 test !/ \n _dist_123_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 00:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0030 | Fri Jan 01 00:30:00 2021 | Fri Jan 01 01:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 | Fri Jan 01 01:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0130 | Fri Jan 01 01:30:00 2021 | Fri Jan 01 02:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 | Fri Jan 01 02:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0230 | Fri Jan 01 02:30:00 2021 | Fri Jan 01 03:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 | Fri Jan 01 03:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0330 | Fri Jan 01 03:30:00 2021 | Fri Jan 01 04:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 | Fri Jan 01 04:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0430 | Fri Jan 01 04:30:00 2021 | Fri Jan 01 05:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 | Fri Jan 01 05:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0530 | Fri Jan 01 05:30:00 2021 | Fri Jan 01 06:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 06:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0630 | Fri Jan 01 06:30:00 2021 | Fri Jan 01 07:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 | Fri Jan 01 07:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0730 | Fri Jan 01 07:30:00 2021 | Fri Jan 01 08:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 | Fri Jan 01 08:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0830 | Fri Jan 01 08:30:00 2021 | Fri Jan 01 09:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 | Fri Jan 01 09:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0930 | Fri Jan 01 09:30:00 2021 | Fri Jan 01 10:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 | Fri Jan 01 10:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_1030 | Fri Jan 01 10:30:00 2021 | Fri Jan 01 11:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 | Fri Jan 01 11:30:00 2021
 test !/ \n _dist_123_table_p2021_01_01_1130 | Fri Jan 01 11:30:00 2021 | Fri Jan 01 12:00:00 2021
(24 rows)

SELECT * FROM get_missing_time_partition_ranges('"test !/ \n _dist_123_table"', INTERVAL '1 hour', '2021-01-01 12:00:00', '2021-01-01 00:00:00');
               partition_name                |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 test !/ \n _dist_123_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 01:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 | Fri Jan 01 02:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 | Fri Jan 01 03:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 | Fri Jan 01 04:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 | Fri Jan 01 05:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 | Fri Jan 01 06:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 07:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 | Fri Jan 01 08:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 | Fri Jan 01 09:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 | Fri Jan 01 10:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 | Fri Jan 01 11:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 | Fri Jan 01 12:00:00 2021
(12 rows)

SELECT * FROM get_missing_time_partition_ranges('"test !/ \n _dist_123_table"', INTERVAL '6 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
               partition_name                |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 test !/ \n _dist_123_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 06:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 12:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 | Fri Jan 01 18:00:00 2021
 test !/ \n _dist_123_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 | Sat Jan 02 00:00:00 2021
(4 rows)

SELECT * FROM get_missing_time_partition_ranges('"test !/ \n _dist_123_table"', INTERVAL '1 day', '2021-01-03 00:00:00', '2021-01-01 00:00:00');
             partition_name             |     range_from_value     |      range_to_value
---------------------------------------------------------------------
 test !/ \n _dist_123_table_p2021_01_01 | Fri Jan 01 00:00:00 2021 | Sat Jan 02 00:00:00 2021
 test !/ \n _dist_123_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 | Sun Jan 03 00:00:00 2021
(2 rows)

DROP TABLE "test !/ \n _dist_123_table";
-- b) test create_time_partitions
-- 1) test create_time_partitions with date partitioned table
CREATE TABLE date_partitioned_table(
 measureid integer,
 eventdate date,
 measure_data jsonb) PARTITION BY RANGE(eventdate);
-- test interval must be multiple days for date partitioned table
SELECT create_time_partitions('date_partitioned_table', INTERVAL '6 hours', '2022-01-01', '2021-01-01');
ERROR:  partition interval of date partitioned table must be day or multiple days
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
SELECT create_time_partitions('date_partitioned_table', INTERVAL '1 week 1 day 1 hour', '2022-01-01', '2021-01-01');
ERROR:  partition interval of date partitioned table must be day or multiple days
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
-- test with various intervals
BEGIN;
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '1 day', '2021-02-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |             partition              | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_01 | 01-01-2021 | 01-02-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_02 | 01-02-2021 | 01-03-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_03 | 01-03-2021 | 01-04-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_04 | 01-04-2021 | 01-05-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_05 | 01-05-2021 | 01-06-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_06 | 01-06-2021 | 01-07-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_07 | 01-07-2021 | 01-08-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_08 | 01-08-2021 | 01-09-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_09 | 01-09-2021 | 01-10-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_10 | 01-10-2021 | 01-11-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_11 | 01-11-2021 | 01-12-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_12 | 01-12-2021 | 01-13-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_13 | 01-13-2021 | 01-14-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_14 | 01-14-2021 | 01-15-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_15 | 01-15-2021 | 01-16-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_16 | 01-16-2021 | 01-17-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_17 | 01-17-2021 | 01-18-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_18 | 01-18-2021 | 01-19-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_19 | 01-19-2021 | 01-20-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_20 | 01-20-2021 | 01-21-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_21 | 01-21-2021 | 01-22-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_22 | 01-22-2021 | 01-23-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_23 | 01-23-2021 | 01-24-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_24 | 01-24-2021 | 01-25-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_25 | 01-25-2021 | 01-26-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_26 | 01-26-2021 | 01-27-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_27 | 01-27-2021 | 01-28-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_28 | 01-28-2021 | 01-29-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_29 | 01-29-2021 | 01-30-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_30 | 01-30-2021 | 01-31-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_31 | 01-31-2021 | 02-01-2021 | heap
(31 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '1 week', '2022-01-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |            partition            | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_table | eventdate        | date_partitioned_table_p2020w53 | 12-28-2020 | 01-04-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w01 | 01-04-2021 | 01-11-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w02 | 01-11-2021 | 01-18-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w03 | 01-18-2021 | 01-25-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w04 | 01-25-2021 | 02-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w05 | 02-01-2021 | 02-08-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w06 | 02-08-2021 | 02-15-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w07 | 02-15-2021 | 02-22-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w08 | 02-22-2021 | 03-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w09 | 03-01-2021 | 03-08-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w10 | 03-08-2021 | 03-15-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w11 | 03-15-2021 | 03-22-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w12 | 03-22-2021 | 03-29-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w13 | 03-29-2021 | 04-05-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w14 | 04-05-2021 | 04-12-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w15 | 04-12-2021 | 04-19-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w16 | 04-19-2021 | 04-26-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w17 | 04-26-2021 | 05-03-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w18 | 05-03-2021 | 05-10-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w19 | 05-10-2021 | 05-17-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w20 | 05-17-2021 | 05-24-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w21 | 05-24-2021 | 05-31-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w22 | 05-31-2021 | 06-07-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w23 | 06-07-2021 | 06-14-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w24 | 06-14-2021 | 06-21-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w25 | 06-21-2021 | 06-28-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w26 | 06-28-2021 | 07-05-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w27 | 07-05-2021 | 07-12-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w28 | 07-12-2021 | 07-19-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w29 | 07-19-2021 | 07-26-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w30 | 07-26-2021 | 08-02-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w31 | 08-02-2021 | 08-09-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w32 | 08-09-2021 | 08-16-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w33 | 08-16-2021 | 08-23-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w34 | 08-23-2021 | 08-30-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w35 | 08-30-2021 | 09-06-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w36 | 09-06-2021 | 09-13-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w37 | 09-13-2021 | 09-20-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w38 | 09-20-2021 | 09-27-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w39 | 09-27-2021 | 10-04-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w40 | 10-04-2021 | 10-11-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w41 | 10-11-2021 | 10-18-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w42 | 10-18-2021 | 10-25-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w43 | 10-25-2021 | 11-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w44 | 11-01-2021 | 11-08-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w45 | 11-08-2021 | 11-15-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w46 | 11-15-2021 | 11-22-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w47 | 11-22-2021 | 11-29-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w48 | 11-29-2021 | 12-06-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w49 | 12-06-2021 | 12-13-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w50 | 12-13-2021 | 12-20-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w51 | 12-20-2021 | 12-27-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021w52 | 12-27-2021 | 01-03-2022 | heap
(53 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '1 month', '2022-01-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |            partition            | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01 | 01-01-2021 | 02-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_02 | 02-01-2021 | 03-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_03 | 03-01-2021 | 04-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_04 | 04-01-2021 | 05-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_05 | 05-01-2021 | 06-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_06 | 06-01-2021 | 07-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_07 | 07-01-2021 | 08-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_08 | 08-01-2021 | 09-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_09 | 09-01-2021 | 10-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_10 | 10-01-2021 | 11-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_11 | 11-01-2021 | 12-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_12 | 12-01-2021 | 01-01-2022 | heap
(12 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '3 months', '2022-01-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |           partition            | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_table | eventdate        | date_partitioned_table_p2021q1 | 01-01-2021 | 04-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021q2 | 04-01-2021 | 07-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021q3 | 07-01-2021 | 10-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021q4 | 10-01-2021 | 01-01-2022 | heap
(4 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '6 months', '2022-01-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |            partition            | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01 | 01-01-2021 | 07-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_07 | 07-01-2021 | 01-01-2022 | heap
(2 rows)

ROLLBACK;
-- test with from_date > to_date
SELECT * FROM create_time_partitions('date_partitioned_table', INTERVAL '1 day', '2021-01-01', '2021-02-01');
ERROR:  start_from (Mon Feb 01 00:00:00 2021 PST) must be older than end_at (Fri Jan 01 00:00:00 2021 PST)
CONTEXT:  PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
-- test with existing partitions
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-02');
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '1 day', '2021-01-05', '2020-12-30');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |             partition              | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_table | eventdate        | date_partitioned_table_2021_01_01  | 01-01-2021 | 01-02-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2020_12_30 | 12-30-2020 | 12-31-2020 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2020_12_31 | 12-31-2020 | 01-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_02 | 01-02-2021 | 01-03-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_03 | 01-03-2021 | 01-04-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_04 | 01-04-2021 | 01-05-2021 | heap
(6 rows)

  SELECT create_time_partitions('date_partitioned_table', INTERVAL '2 days', '2021-01-15', '2020-12-25');
ERROR:  partition date_partitioned_table_p2020_12_30 with the range from 12-30-2020 to 12-31-2020 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-02');
  CREATE TABLE date_partitioned_table_2021_01_02 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-02') TO ('2021-01-03');
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '1 day', '2021-01-05', '2020-12-30');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |             partition              | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_table | eventdate        | date_partitioned_table_2021_01_01  | 01-01-2021 | 01-02-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_2021_01_02  | 01-02-2021 | 01-03-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2020_12_30 | 12-30-2020 | 12-31-2020 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2020_12_31 | 12-31-2020 | 01-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_03 | 01-03-2021 | 01-04-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_04 | 01-04-2021 | 01-05-2021 | heap
(6 rows)

  SELECT create_time_partitions('date_partitioned_table', INTERVAL '2 days', '2021-01-05', '2020-12-30');
ERROR:  partition date_partitioned_table_p2020_12_30 with the range from 12-30-2020 to 12-31-2020 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-03');
  CREATE TABLE date_partitioned_table_2021_01_02 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-05') TO ('2021-01-07');
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '2 days', '2021-01-15', '2020-12-30');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |             partition              | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_table | eventdate        | date_partitioned_table_2021_01_01  | 01-01-2021 | 01-03-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_2021_01_02  | 01-05-2021 | 01-07-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2020_12_30 | 12-30-2020 | 01-01-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_03 | 01-03-2021 | 01-05-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_07 | 01-07-2021 | 01-09-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_09 | 01-09-2021 | 01-11-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_11 | 01-11-2021 | 01-13-2021 | heap
 date_partitioned_table | eventdate        | date_partitioned_table_p2021_01_13 | 01-13-2021 | 01-15-2021 | heap
(8 rows)

ROLLBACK;
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-02');
  CREATE TABLE date_partitioned_table_2020_01_02 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-02') TO ('2021-01-04');
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '1 day', '2021-01-05', '2020-12-30');
ERROR:  partition date_partitioned_table_2020_01_02 with the range from 01-02-2021 to 01-04-2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
BEGIN;
  CREATE TABLE date_partitioned_table_2021_01_01 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2021-01-03');
  CREATE TABLE date_partitioned_table_2021_01_02 PARTITION OF date_partitioned_table FOR VALUES FROM ('2021-01-04') TO ('2021-01-06');
  SELECT create_time_partitions('date_partitioned_table', INTERVAL '2 days', '2021-01-15', '2020-12-30');
ERROR:  partition date_partitioned_table_2021_01_02 with the range from 01-04-2021 to 01-06-2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
DROP TABLE date_partitioned_table;
-- 2) test timestamp with time zone partitioend table
CREATE TABLE tstz_partitioned_table(
 measureid integer,
 eventdatetime timestamp with time zone,
 measure_data jsonb) PARTITION BY RANGE(eventdatetime);
-- test with various intervals
BEGIN;
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '30 minutes', '2021-01-01 12:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |                partition                |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 PST | Fri Jan 01 00:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0030 | Fri Jan 01 00:30:00 2021 PST | Fri Jan 01 01:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 PST | Fri Jan 01 01:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0130 | Fri Jan 01 01:30:00 2021 PST | Fri Jan 01 02:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 PST | Fri Jan 01 02:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0230 | Fri Jan 01 02:30:00 2021 PST | Fri Jan 01 03:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 PST | Fri Jan 01 03:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0330 | Fri Jan 01 03:30:00 2021 PST | Fri Jan 01 04:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 PST | Fri Jan 01 04:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0430 | Fri Jan 01 04:30:00 2021 PST | Fri Jan 01 05:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 PST | Fri Jan 01 05:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0530 | Fri Jan 01 05:30:00 2021 PST | Fri Jan 01 06:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 PST | Fri Jan 01 06:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0630 | Fri Jan 01 06:30:00 2021 PST | Fri Jan 01 07:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 PST | Fri Jan 01 07:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0730 | Fri Jan 01 07:30:00 2021 PST | Fri Jan 01 08:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 PST | Fri Jan 01 08:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0830 | Fri Jan 01 08:30:00 2021 PST | Fri Jan 01 09:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 PST | Fri Jan 01 09:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0930 | Fri Jan 01 09:30:00 2021 PST | Fri Jan 01 10:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 PST | Fri Jan 01 10:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1030 | Fri Jan 01 10:30:00 2021 PST | Fri Jan 01 11:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 PST | Fri Jan 01 11:30:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1130 | Fri Jan 01 11:30:00 2021 PST | Fri Jan 01 12:00:00 2021 PST | heap
(24 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '1 hour', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |                partition                |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 PST | Fri Jan 01 01:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 PST | Fri Jan 01 02:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 PST | Fri Jan 01 03:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 PST | Fri Jan 01 04:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 PST | Fri Jan 01 05:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 PST | Fri Jan 01 06:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 PST | Fri Jan 01 07:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 PST | Fri Jan 01 08:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 PST | Fri Jan 01 09:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 PST | Fri Jan 01 10:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 PST | Fri Jan 01 11:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 PST | Fri Jan 01 12:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 PST | Fri Jan 01 13:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1300 | Fri Jan 01 13:00:00 2021 PST | Fri Jan 01 14:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1400 | Fri Jan 01 14:00:00 2021 PST | Fri Jan 01 15:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1500 | Fri Jan 01 15:00:00 2021 PST | Fri Jan 01 16:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1600 | Fri Jan 01 16:00:00 2021 PST | Fri Jan 01 17:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1700 | Fri Jan 01 17:00:00 2021 PST | Fri Jan 01 18:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 PST | Fri Jan 01 19:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1900 | Fri Jan 01 19:00:00 2021 PST | Fri Jan 01 20:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_2000 | Fri Jan 01 20:00:00 2021 PST | Fri Jan 01 21:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_2100 | Fri Jan 01 21:00:00 2021 PST | Fri Jan 01 22:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_2200 | Fri Jan 01 22:00:00 2021 PST | Fri Jan 01 23:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_2300 | Fri Jan 01 23:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST | heap
(24 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '6 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |                partition                |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 PST | Fri Jan 01 06:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 PST | Fri Jan 01 12:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 PST | Fri Jan 01 18:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST | heap
(4 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '12 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |                partition                |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 PST | Fri Jan 01 12:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST | heap
(2 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |             partition              |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_01 | Fri Jan 01 00:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 PST | Sun Jan 03 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 PST | Mon Jan 04 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 PST | Tue Jan 05 00:00:00 2021 PST | heap
(4 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '1 week', '2021-01-15 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |            partition            |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2020w53 | Mon Dec 28 00:00:00 2020 PST | Mon Jan 04 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021w01 | Mon Jan 04 00:00:00 2021 PST | Mon Jan 11 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021w02 | Mon Jan 11 00:00:00 2021 PST | Mon Jan 18 00:00:00 2021 PST | heap
(3 rows)

ROLLBACK;
-- test with from_date > to_date
SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '1 day', '2021-01-01 00:00:00', '2021-01-05 00:00:00');
ERROR:  start_from (Tue Jan 05 00:00:00 2021 PST) must be older than end_at (Fri Jan 01 00:00:00 2021 PST)
CONTEXT:  PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
-- test with existing partitions
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |             partition              |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_2021_01_01  | Fri Jan 01 00:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 PST | Thu Dec 31 00:00:00 2020 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2020_12_31 | Thu Dec 31 00:00:00 2020 PST | Fri Jan 01 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 PST | Sun Jan 03 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 PST | Mon Jan 04 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 PST | Tue Jan 05 00:00:00 2021 PST | heap
(6 rows)

  SELECT * FROM get_missing_time_partition_ranges('tstz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tstz_partitioned_table_p2020_12_30 with the range from Wed Dec 30 00:00:00 2020 PST to Thu Dec 31 00:00:00 2020 PST does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
ROLLBACK;
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  CREATE TABLE tstz_partitioned_table_2021_01_02 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-02 00:00:00') TO ('2021-01-03 00:00:00');
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |             partition              |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_2021_01_01  | Fri Jan 01 00:00:00 2021 PST | Sat Jan 02 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_2021_01_02  | Sat Jan 02 00:00:00 2021 PST | Sun Jan 03 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 PST | Thu Dec 31 00:00:00 2020 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2020_12_31 | Thu Dec 31 00:00:00 2020 PST | Fri Jan 01 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 PST | Mon Jan 04 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 PST | Tue Jan 05 00:00:00 2021 PST | heap
(6 rows)

  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tstz_partitioned_table_p2020_12_30 with the range from Wed Dec 30 00:00:00 2020 PST to Thu Dec 31 00:00:00 2020 PST does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-03 00:00:00');
  CREATE TABLE tstz_partitioned_table_2021_01_02 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-05 00:00:00') TO ('2021-01-07 00:00:00');
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '2 days', '2021-01-15 00:00:00', '2020-12-30 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tstz_partitioned_table'::regclass ORDER BY 3;
      parent_table      | partition_column |             partition              |          from_value          |           to_value           | access_method
---------------------------------------------------------------------
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_2021_01_01  | Fri Jan 01 00:00:00 2021 PST | Sun Jan 03 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_2021_01_02  | Tue Jan 05 00:00:00 2021 PST | Thu Jan 07 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 PST | Fri Jan 01 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 PST | Tue Jan 05 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_07 | Thu Jan 07 00:00:00 2021 PST | Sat Jan 09 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_09 | Sat Jan 09 00:00:00 2021 PST | Mon Jan 11 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_11 | Mon Jan 11 00:00:00 2021 PST | Wed Jan 13 00:00:00 2021 PST | heap
 tstz_partitioned_table | eventdatetime    | tstz_partitioned_table_p2021_01_13 | Wed Jan 13 00:00:00 2021 PST | Fri Jan 15 00:00:00 2021 PST | heap
(8 rows)

ROLLBACK;
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  CREATE TABLE tstz_partitioned_table_2021_01_02 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-02 00:00:00') TO ('2021-01-04 00:00:00');
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tstz_partitioned_table_2021_01_01 with the range from Fri Jan 01 00:00:00 2021 PST to Sat Jan 02 00:00:00 2021 PST does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
BEGIN;
  CREATE TABLE tstz_partitioned_table_2021_01_01 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-03 00:00:00');
  CREATE TABLE tstz_partitioned_table_2021_01_02 PARTITION OF tstz_partitioned_table FOR VALUES FROM ('2021-01-04 00:00:00') TO ('2021-01-06 00:00:00');
  SELECT create_time_partitions('tstz_partitioned_table', INTERVAL '2 days', '2021-01-15 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tstz_partitioned_table_2021_01_02 with the range from Mon Jan 04 00:00:00 2021 PST to Wed Jan 06 00:00:00 2021 PST does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
DROP TABLE tstz_partitioned_table;
-- 3) test timestamp without time zone partitioend table
CREATE TABLE tswtz_partitioned_table(
 measureid integer,
 eventdatetime timestamp without time zone,
 measure_data jsonb) PARTITION BY RANGE(eventdatetime);
SELECT create_distributed_table('tswtz_partitioned_table','measureid');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

BEGIN;
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '30 minutes', '2021-01-01 12:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |                partition                 |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 00:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0030 | Fri Jan 01 00:30:00 2021 | Fri Jan 01 01:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 | Fri Jan 01 01:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0130 | Fri Jan 01 01:30:00 2021 | Fri Jan 01 02:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 | Fri Jan 01 02:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0230 | Fri Jan 01 02:30:00 2021 | Fri Jan 01 03:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 | Fri Jan 01 03:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0330 | Fri Jan 01 03:30:00 2021 | Fri Jan 01 04:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 | Fri Jan 01 04:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0430 | Fri Jan 01 04:30:00 2021 | Fri Jan 01 05:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 | Fri Jan 01 05:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0530 | Fri Jan 01 05:30:00 2021 | Fri Jan 01 06:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 06:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0630 | Fri Jan 01 06:30:00 2021 | Fri Jan 01 07:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 | Fri Jan 01 07:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0730 | Fri Jan 01 07:30:00 2021 | Fri Jan 01 08:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 | Fri Jan 01 08:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0830 | Fri Jan 01 08:30:00 2021 | Fri Jan 01 09:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 | Fri Jan 01 09:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0930 | Fri Jan 01 09:30:00 2021 | Fri Jan 01 10:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 | Fri Jan 01 10:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1030 | Fri Jan 01 10:30:00 2021 | Fri Jan 01 11:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 | Fri Jan 01 11:30:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1130 | Fri Jan 01 11:30:00 2021 | Fri Jan 01 12:00:00 2021 | heap
(24 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '1 hour', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |                partition                 |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 01:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0100 | Fri Jan 01 01:00:00 2021 | Fri Jan 01 02:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0200 | Fri Jan 01 02:00:00 2021 | Fri Jan 01 03:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0300 | Fri Jan 01 03:00:00 2021 | Fri Jan 01 04:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0400 | Fri Jan 01 04:00:00 2021 | Fri Jan 01 05:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0500 | Fri Jan 01 05:00:00 2021 | Fri Jan 01 06:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 07:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0700 | Fri Jan 01 07:00:00 2021 | Fri Jan 01 08:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0800 | Fri Jan 01 08:00:00 2021 | Fri Jan 01 09:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0900 | Fri Jan 01 09:00:00 2021 | Fri Jan 01 10:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1000 | Fri Jan 01 10:00:00 2021 | Fri Jan 01 11:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1100 | Fri Jan 01 11:00:00 2021 | Fri Jan 01 12:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 | Fri Jan 01 13:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1300 | Fri Jan 01 13:00:00 2021 | Fri Jan 01 14:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1400 | Fri Jan 01 14:00:00 2021 | Fri Jan 01 15:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1500 | Fri Jan 01 15:00:00 2021 | Fri Jan 01 16:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1600 | Fri Jan 01 16:00:00 2021 | Fri Jan 01 17:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1700 | Fri Jan 01 17:00:00 2021 | Fri Jan 01 18:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 | Fri Jan 01 19:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1900 | Fri Jan 01 19:00:00 2021 | Fri Jan 01 20:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_2000 | Fri Jan 01 20:00:00 2021 | Fri Jan 01 21:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_2100 | Fri Jan 01 21:00:00 2021 | Fri Jan 01 22:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_2200 | Fri Jan 01 22:00:00 2021 | Fri Jan 01 23:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_2300 | Fri Jan 01 23:00:00 2021 | Sat Jan 02 00:00:00 2021 | heap
(24 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '6 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |                partition                 |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 06:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0600 | Fri Jan 01 06:00:00 2021 | Fri Jan 01 12:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 | Fri Jan 01 18:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1800 | Fri Jan 01 18:00:00 2021 | Sat Jan 02 00:00:00 2021 | heap
(4 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '12 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |                partition                 |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_0000 | Fri Jan 01 00:00:00 2021 | Fri Jan 01 12:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01_1200 | Fri Jan 01 12:00:00 2021 | Sat Jan 02 00:00:00 2021 | heap
(2 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |              partition              |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_01 | Fri Jan 01 00:00:00 2021 | Sat Jan 02 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 | Sun Jan 03 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 | Mon Jan 04 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 | Tue Jan 05 00:00:00 2021 | heap
(4 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '1 week', '2021-01-15 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |            partition             |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2020w53 | Mon Dec 28 00:00:00 2020 | Mon Jan 04 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021w01 | Mon Jan 04 00:00:00 2021 | Mon Jan 11 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021w02 | Mon Jan 11 00:00:00 2021 | Mon Jan 18 00:00:00 2021 | heap
(3 rows)

ROLLBACK;
-- test with from_date > to_date
SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '1 day', '2021-01-01 00:00:00', '2021-01-05 00:00:00');
ERROR:  start_from (Tue Jan 05 00:00:00 2021 PST) must be older than end_at (Fri Jan 01 00:00:00 2021 PST)
CONTEXT:  PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
-- test with existing partitions
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2021_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |              partition              |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_2021_01_01  | Fri Jan 01 00:00:00 2021 | Sat Jan 02 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 | Thu Dec 31 00:00:00 2020 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2020_12_31 | Thu Dec 31 00:00:00 2020 | Fri Jan 01 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_02 | Sat Jan 02 00:00:00 2021 | Sun Jan 03 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 | Mon Jan 04 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 | Tue Jan 05 00:00:00 2021 | heap
(6 rows)

  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tswtz_partitioned_table_p2020_12_30 with the range from Wed Dec 30 00:00:00 2020 to Thu Dec 31 00:00:00 2020 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2021_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  CREATE TABLE tswtz_partitioned_table_2021_01_02 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-02 00:00:00') TO ('2021-01-03 00:00:00');
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '1 day', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |              partition              |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_2021_01_01  | Fri Jan 01 00:00:00 2021 | Sat Jan 02 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_2021_01_02  | Sat Jan 02 00:00:00 2021 | Sun Jan 03 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 | Thu Dec 31 00:00:00 2020 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2020_12_31 | Thu Dec 31 00:00:00 2020 | Fri Jan 01 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 | Mon Jan 04 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_04 | Mon Jan 04 00:00:00 2021 | Tue Jan 05 00:00:00 2021 | heap
(6 rows)

  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tswtz_partitioned_table_p2020_12_30 with the range from Wed Dec 30 00:00:00 2020 to Thu Dec 31 00:00:00 2020 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2020_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-03 00:00:00');
  CREATE TABLE tswtz_partitioned_table_2020_01_02 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-05 00:00:00') TO ('2021-01-07 00:00:00');
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-15 00:00:00', '2020-12-30 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'tswtz_partitioned_table'::regclass ORDER BY 3;
      parent_table       | partition_column |              partition              |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_2020_01_01  | Fri Jan 01 00:00:00 2021 | Sun Jan 03 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_2020_01_02  | Tue Jan 05 00:00:00 2021 | Thu Jan 07 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2020_12_30 | Wed Dec 30 00:00:00 2020 | Fri Jan 01 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_03 | Sun Jan 03 00:00:00 2021 | Tue Jan 05 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_07 | Thu Jan 07 00:00:00 2021 | Sat Jan 09 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_09 | Sat Jan 09 00:00:00 2021 | Mon Jan 11 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_11 | Mon Jan 11 00:00:00 2021 | Wed Jan 13 00:00:00 2021 | heap
 tswtz_partitioned_table | eventdatetime    | tswtz_partitioned_table_p2021_01_13 | Wed Jan 13 00:00:00 2021 | Fri Jan 15 00:00:00 2021 | heap
(8 rows)

ROLLBACK;
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2020_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-02 00:00:00');
  CREATE TABLE tswtz_partitioned_table_2020_01_02 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-02 00:00:00') TO ('2021-01-04 00:00:00');
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-05 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tswtz_partitioned_table_2020_01_01 with the range from Fri Jan 01 00:00:00 2021 to Sat Jan 02 00:00:00 2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
BEGIN;
  CREATE TABLE tswtz_partitioned_table_2020_01_01 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2021-01-03 00:00:00');
  CREATE TABLE tswtz_partitioned_table_2020_01_02 PARTITION OF tswtz_partitioned_table FOR VALUES FROM ('2021-01-04 00:00:00') TO ('2021-01-06 00:00:00');
  SELECT create_time_partitions('tswtz_partitioned_table', INTERVAL '2 days', '2021-01-15 00:00:00', '2020-12-30 00:00:00');
ERROR:  partition tswtz_partitioned_table_2020_01_02 with the range from Mon Jan 04 00:00:00 2021 to Wed Jan 06 00:00:00 2021 does not align with the initial partition given the partition interval
HINT:  Only use partitions of the same size, without gaps between partitions.
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
ROLLBACK;
DROP TABLE tswtz_partitioned_table;
-- 4) test with weird name
CREATE TABLE "test !/ \n _dist_123_table"(
 measureid integer,
 eventdatetime timestamp without time zone,
 measure_data jsonb) PARTITION BY RANGE(eventdatetime);
SELECT create_distributed_table('"test !/ \n _dist_123_table"','measureid');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- test with various intervals
BEGIN;
  SELECT create_time_partitions('"test !/ \n _dist_123_table"', INTERVAL '30 minutes', '2021-01-01 12:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = '"test !/ \n _dist_123_table"'::regclass ORDER BY 3;
         parent_table         | partition_column |                   partition                   |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0000" | Fri Jan 01 00:00:00 2021 | Fri Jan 01 00:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0030" | Fri Jan 01 00:30:00 2021 | Fri Jan 01 01:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0100" | Fri Jan 01 01:00:00 2021 | Fri Jan 01 01:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0130" | Fri Jan 01 01:30:00 2021 | Fri Jan 01 02:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0200" | Fri Jan 01 02:00:00 2021 | Fri Jan 01 02:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0230" | Fri Jan 01 02:30:00 2021 | Fri Jan 01 03:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0300" | Fri Jan 01 03:00:00 2021 | Fri Jan 01 03:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0330" | Fri Jan 01 03:30:00 2021 | Fri Jan 01 04:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0400" | Fri Jan 01 04:00:00 2021 | Fri Jan 01 04:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0430" | Fri Jan 01 04:30:00 2021 | Fri Jan 01 05:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0500" | Fri Jan 01 05:00:00 2021 | Fri Jan 01 05:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0530" | Fri Jan 01 05:30:00 2021 | Fri Jan 01 06:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0600" | Fri Jan 01 06:00:00 2021 | Fri Jan 01 06:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0630" | Fri Jan 01 06:30:00 2021 | Fri Jan 01 07:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0700" | Fri Jan 01 07:00:00 2021 | Fri Jan 01 07:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0730" | Fri Jan 01 07:30:00 2021 | Fri Jan 01 08:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0800" | Fri Jan 01 08:00:00 2021 | Fri Jan 01 08:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0830" | Fri Jan 01 08:30:00 2021 | Fri Jan 01 09:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0900" | Fri Jan 01 09:00:00 2021 | Fri Jan 01 09:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0930" | Fri Jan 01 09:30:00 2021 | Fri Jan 01 10:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_1000" | Fri Jan 01 10:00:00 2021 | Fri Jan 01 10:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_1030" | Fri Jan 01 10:30:00 2021 | Fri Jan 01 11:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_1100" | Fri Jan 01 11:00:00 2021 | Fri Jan 01 11:30:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_1130" | Fri Jan 01 11:30:00 2021 | Fri Jan 01 12:00:00 2021 | heap
(24 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('"test !/ \n _dist_123_table"', INTERVAL '6 hours', '2021-01-02 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = '"test !/ \n _dist_123_table"'::regclass ORDER BY 3;
         parent_table         | partition_column |                   partition                   |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0000" | Fri Jan 01 00:00:00 2021 | Fri Jan 01 06:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_0600" | Fri Jan 01 06:00:00 2021 | Fri Jan 01 12:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_1200" | Fri Jan 01 12:00:00 2021 | Fri Jan 01 18:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01_1800" | Fri Jan 01 18:00:00 2021 | Sat Jan 02 00:00:00 2021 | heap
(4 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('"test !/ \n _dist_123_table"', INTERVAL '1 day', '2021-01-03 00:00:00', '2021-01-01 00:00:00');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = '"test !/ \n _dist_123_table"'::regclass ORDER BY 3;
         parent_table         | partition_column |                partition                 |        from_value        |         to_value         | access_method
---------------------------------------------------------------------
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_01" | Fri Jan 01 00:00:00 2021 | Sat Jan 02 00:00:00 2021 | heap
 "test !/ \n _dist_123_table" | eventdatetime    | "test !/ \n _dist_123_table_p2021_01_02" | Sat Jan 02 00:00:00 2021 | Sun Jan 03 00:00:00 2021 | heap
(2 rows)

ROLLBACK;
DROP TABLE "test !/ \n _dist_123_table";
-- 5) test with distributed table
CREATE TABLE date_distributed_partitioned_table(
 measureid integer,
 eventdate date,
 measure_data jsonb) PARTITION BY RANGE(eventdate);
SELECT create_distributed_table('date_distributed_partitioned_table', 'measureid');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- test interval must be multiple days for date partitioned table
SELECT create_time_partitions('date_distributed_partitioned_table', INTERVAL '6 hours', '2022-01-01', '2021-01-01');
ERROR:  partition interval of date partitioned table must be day or multiple days
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
SELECT create_time_partitions('date_distributed_partitioned_table', INTERVAL '1 week 1 day 1 hour', '2022-01-01', '2021-01-01');
ERROR:  partition interval of date partitioned table must be day or multiple days
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
-- test with various intervals
BEGIN;
  SELECT create_time_partitions('date_distributed_partitioned_table', INTERVAL '1 day', '2021-02-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_distributed_partitioned_table'::regclass ORDER BY 3;
            parent_table            | partition_column |                   partition                    | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_01 | 01-01-2021 | 01-02-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_02 | 01-02-2021 | 01-03-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_03 | 01-03-2021 | 01-04-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_04 | 01-04-2021 | 01-05-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_05 | 01-05-2021 | 01-06-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_06 | 01-06-2021 | 01-07-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_07 | 01-07-2021 | 01-08-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_08 | 01-08-2021 | 01-09-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_09 | 01-09-2021 | 01-10-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_10 | 01-10-2021 | 01-11-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_11 | 01-11-2021 | 01-12-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_12 | 01-12-2021 | 01-13-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_13 | 01-13-2021 | 01-14-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_14 | 01-14-2021 | 01-15-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_15 | 01-15-2021 | 01-16-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_16 | 01-16-2021 | 01-17-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_17 | 01-17-2021 | 01-18-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_18 | 01-18-2021 | 01-19-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_19 | 01-19-2021 | 01-20-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_20 | 01-20-2021 | 01-21-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_21 | 01-21-2021 | 01-22-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_22 | 01-22-2021 | 01-23-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_23 | 01-23-2021 | 01-24-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_24 | 01-24-2021 | 01-25-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_25 | 01-25-2021 | 01-26-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_26 | 01-26-2021 | 01-27-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_27 | 01-27-2021 | 01-28-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_28 | 01-28-2021 | 01-29-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_29 | 01-29-2021 | 01-30-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_30 | 01-30-2021 | 01-31-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021_01_31 | 01-31-2021 | 02-01-2021 | heap
(31 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('date_distributed_partitioned_table', INTERVAL '1 week', '2022-01-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_distributed_partitioned_table'::regclass ORDER BY 3;
            parent_table            | partition_column |                  partition                  | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2020w53 | 12-28-2020 | 01-04-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w01 | 01-04-2021 | 01-11-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w02 | 01-11-2021 | 01-18-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w03 | 01-18-2021 | 01-25-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w04 | 01-25-2021 | 02-01-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w05 | 02-01-2021 | 02-08-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w06 | 02-08-2021 | 02-15-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w07 | 02-15-2021 | 02-22-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w08 | 02-22-2021 | 03-01-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w09 | 03-01-2021 | 03-08-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w10 | 03-08-2021 | 03-15-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w11 | 03-15-2021 | 03-22-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w12 | 03-22-2021 | 03-29-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w13 | 03-29-2021 | 04-05-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w14 | 04-05-2021 | 04-12-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w15 | 04-12-2021 | 04-19-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w16 | 04-19-2021 | 04-26-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w17 | 04-26-2021 | 05-03-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w18 | 05-03-2021 | 05-10-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w19 | 05-10-2021 | 05-17-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w20 | 05-17-2021 | 05-24-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w21 | 05-24-2021 | 05-31-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w22 | 05-31-2021 | 06-07-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w23 | 06-07-2021 | 06-14-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w24 | 06-14-2021 | 06-21-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w25 | 06-21-2021 | 06-28-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w26 | 06-28-2021 | 07-05-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w27 | 07-05-2021 | 07-12-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w28 | 07-12-2021 | 07-19-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w29 | 07-19-2021 | 07-26-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w30 | 07-26-2021 | 08-02-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w31 | 08-02-2021 | 08-09-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w32 | 08-09-2021 | 08-16-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w33 | 08-16-2021 | 08-23-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w34 | 08-23-2021 | 08-30-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w35 | 08-30-2021 | 09-06-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w36 | 09-06-2021 | 09-13-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w37 | 09-13-2021 | 09-20-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w38 | 09-20-2021 | 09-27-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w39 | 09-27-2021 | 10-04-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w40 | 10-04-2021 | 10-11-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w41 | 10-11-2021 | 10-18-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w42 | 10-18-2021 | 10-25-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w43 | 10-25-2021 | 11-01-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w44 | 11-01-2021 | 11-08-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w45 | 11-08-2021 | 11-15-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w46 | 11-15-2021 | 11-22-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w47 | 11-22-2021 | 11-29-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w48 | 11-29-2021 | 12-06-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w49 | 12-06-2021 | 12-13-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w50 | 12-13-2021 | 12-20-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w51 | 12-20-2021 | 12-27-2021 | heap
 date_distributed_partitioned_table | eventdate        | date_distributed_partitioned_table_p2021w52 | 12-27-2021 | 01-03-2022 | heap
(53 rows)

ROLLBACK;
DROP TABLE date_distributed_partitioned_table;
-- pi test with parameter names
CREATE TABLE pi_table(
  event_id bigserial,
  event_time timestamptz default now(),
  payload text) PARTITION BY RANGE (event_time);
BEGIN;
  SELECT create_time_partitions('pi_table', start_from := '2021-08-01', end_at := '2021-10-01', partition_interval := pi() * interval '1 day');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'pi_table'::regclass ORDER BY 3;
 parent_table | partition_column |      partition       |             from_value             |              to_value              | access_method
---------------------------------------------------------------------
 pi_table     | event_time       | pi_table_p2021_08_01 | Sun Aug 01 00:00:00 2021 PDT       | Wed Aug 04 03:23:53.60527 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_04 | Wed Aug 04 03:23:53.60527 2021 PDT | Sat Aug 07 06:47:47.21054 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_07 | Sat Aug 07 06:47:47.21054 2021 PDT | Tue Aug 10 10:11:40.81581 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_10 | Tue Aug 10 10:11:40.81581 2021 PDT | Fri Aug 13 13:35:34.42108 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_13 | Fri Aug 13 13:35:34.42108 2021 PDT | Mon Aug 16 16:59:28.02635 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_16 | Mon Aug 16 16:59:28.02635 2021 PDT | Thu Aug 19 20:23:21.63162 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_19 | Thu Aug 19 20:23:21.63162 2021 PDT | Sun Aug 22 23:47:15.23689 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_22 | Sun Aug 22 23:47:15.23689 2021 PDT | Thu Aug 26 03:11:08.84216 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_26 | Thu Aug 26 03:11:08.84216 2021 PDT | Sun Aug 29 06:35:02.44743 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_08_29 | Sun Aug 29 06:35:02.44743 2021 PDT | Wed Sep 01 09:58:56.0527 2021 PDT  | heap
 pi_table     | event_time       | pi_table_p2021_09_01 | Wed Sep 01 09:58:56.0527 2021 PDT  | Sat Sep 04 13:22:49.65797 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_04 | Sat Sep 04 13:22:49.65797 2021 PDT | Tue Sep 07 16:46:43.26324 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_07 | Tue Sep 07 16:46:43.26324 2021 PDT | Fri Sep 10 20:10:36.86851 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_10 | Fri Sep 10 20:10:36.86851 2021 PDT | Mon Sep 13 23:34:30.47378 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_13 | Mon Sep 13 23:34:30.47378 2021 PDT | Fri Sep 17 02:58:24.07905 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_17 | Fri Sep 17 02:58:24.07905 2021 PDT | Mon Sep 20 06:22:17.68432 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_20 | Mon Sep 20 06:22:17.68432 2021 PDT | Thu Sep 23 09:46:11.28959 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_23 | Thu Sep 23 09:46:11.28959 2021 PDT | Sun Sep 26 13:10:04.89486 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_26 | Sun Sep 26 13:10:04.89486 2021 PDT | Wed Sep 29 16:33:58.50013 2021 PDT | heap
 pi_table     | event_time       | pi_table_p2021_09_29 | Wed Sep 29 16:33:58.50013 2021 PDT | Sat Oct 02 19:57:52.1054 2021 PDT  | heap
(20 rows)

ROLLBACK;
DROP TABLE pi_table;
-- 6) test with citus local table
CREATE TABLE date_partitioned_citus_local_table(
 measureid integer,
 eventdate date,
 measure_data jsonb) PARTITION BY RANGE(eventdate);
SELECT citus_add_local_table_to_metadata('date_partitioned_citus_local_table');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

-- test interval must be multiple days for date partitioned table
SELECT create_time_partitions('date_partitioned_citus_local_table', INTERVAL '6 hours', '2022-01-01', '2021-01-01');
ERROR:  partition interval of date partitioned table must be day or multiple days
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
SELECT create_time_partitions('date_partitioned_citus_local_table', INTERVAL '1 week 1 day 1 hour', '2022-01-01', '2021-01-01');
ERROR:  partition interval of date partitioned table must be day or multiple days
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
-- test with various intervals
BEGIN;
  SELECT create_time_partitions('date_partitioned_citus_local_table', INTERVAL '1 day', '2021-02-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_citus_local_table'::regclass ORDER BY 3;
            parent_table            | partition_column |                   partition                    | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_01 | 01-01-2021 | 01-02-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_02 | 01-02-2021 | 01-03-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_03 | 01-03-2021 | 01-04-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_04 | 01-04-2021 | 01-05-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_05 | 01-05-2021 | 01-06-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_06 | 01-06-2021 | 01-07-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_07 | 01-07-2021 | 01-08-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_08 | 01-08-2021 | 01-09-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_09 | 01-09-2021 | 01-10-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_10 | 01-10-2021 | 01-11-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_11 | 01-11-2021 | 01-12-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_12 | 01-12-2021 | 01-13-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_13 | 01-13-2021 | 01-14-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_14 | 01-14-2021 | 01-15-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_15 | 01-15-2021 | 01-16-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_16 | 01-16-2021 | 01-17-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_17 | 01-17-2021 | 01-18-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_18 | 01-18-2021 | 01-19-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_19 | 01-19-2021 | 01-20-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_20 | 01-20-2021 | 01-21-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_21 | 01-21-2021 | 01-22-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_22 | 01-22-2021 | 01-23-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_23 | 01-23-2021 | 01-24-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_24 | 01-24-2021 | 01-25-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_25 | 01-25-2021 | 01-26-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_26 | 01-26-2021 | 01-27-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_27 | 01-27-2021 | 01-28-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_28 | 01-28-2021 | 01-29-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_29 | 01-29-2021 | 01-30-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_30 | 01-30-2021 | 01-31-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_31 | 01-31-2021 | 02-01-2021 | heap
(31 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('date_partitioned_citus_local_table', INTERVAL '1 week', '2022-01-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_citus_local_table'::regclass ORDER BY 3;
            parent_table            | partition_column |                  partition                  | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2020w53 | 12-28-2020 | 01-04-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w01 | 01-04-2021 | 01-11-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w02 | 01-11-2021 | 01-18-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w03 | 01-18-2021 | 01-25-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w04 | 01-25-2021 | 02-01-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w05 | 02-01-2021 | 02-08-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w06 | 02-08-2021 | 02-15-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w07 | 02-15-2021 | 02-22-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w08 | 02-22-2021 | 03-01-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w09 | 03-01-2021 | 03-08-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w10 | 03-08-2021 | 03-15-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w11 | 03-15-2021 | 03-22-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w12 | 03-22-2021 | 03-29-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w13 | 03-29-2021 | 04-05-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w14 | 04-05-2021 | 04-12-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w15 | 04-12-2021 | 04-19-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w16 | 04-19-2021 | 04-26-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w17 | 04-26-2021 | 05-03-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w18 | 05-03-2021 | 05-10-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w19 | 05-10-2021 | 05-17-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w20 | 05-17-2021 | 05-24-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w21 | 05-24-2021 | 05-31-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w22 | 05-31-2021 | 06-07-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w23 | 06-07-2021 | 06-14-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w24 | 06-14-2021 | 06-21-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w25 | 06-21-2021 | 06-28-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w26 | 06-28-2021 | 07-05-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w27 | 07-05-2021 | 07-12-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w28 | 07-12-2021 | 07-19-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w29 | 07-19-2021 | 07-26-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w30 | 07-26-2021 | 08-02-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w31 | 08-02-2021 | 08-09-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w32 | 08-09-2021 | 08-16-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w33 | 08-16-2021 | 08-23-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w34 | 08-23-2021 | 08-30-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w35 | 08-30-2021 | 09-06-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w36 | 09-06-2021 | 09-13-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w37 | 09-13-2021 | 09-20-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w38 | 09-20-2021 | 09-27-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w39 | 09-27-2021 | 10-04-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w40 | 10-04-2021 | 10-11-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w41 | 10-11-2021 | 10-18-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w42 | 10-18-2021 | 10-25-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w43 | 10-25-2021 | 11-01-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w44 | 11-01-2021 | 11-08-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w45 | 11-08-2021 | 11-15-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w46 | 11-15-2021 | 11-22-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w47 | 11-22-2021 | 11-29-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w48 | 11-29-2021 | 12-06-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w49 | 12-06-2021 | 12-13-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w50 | 12-13-2021 | 12-20-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w51 | 12-20-2021 | 12-27-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021w52 | 12-27-2021 | 01-03-2022 | heap
(53 rows)

ROLLBACK;
set client_min_messages to error;
DROP TABLE date_partitioned_citus_local_table;
-- also test with foreign key
CREATE TABLE date_partitioned_citus_local_table(
 measureid integer,
 eventdate date,
 measure_data jsonb, PRIMARY KEY (measureid, eventdate)) PARTITION BY RANGE(eventdate);
SELECT citus_add_local_table_to_metadata('date_partitioned_citus_local_table');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

-- test interval must be multiple days for date partitioned table
SELECT create_time_partitions('date_partitioned_citus_local_table', INTERVAL '1 day', '2021-02-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

CREATE TABLE date_partitioned_citus_local_table_2(
 measureid integer,
 eventdate date,
 measure_data jsonb, PRIMARY KEY (measureid, eventdate)) PARTITION BY RANGE(eventdate);
SELECT citus_add_local_table_to_metadata('date_partitioned_citus_local_table_2');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

ALTER TABLE date_partitioned_citus_local_table_2 ADD CONSTRAINT fkey_1 FOREIGN KEY (measureid, eventdate) REFERENCES date_partitioned_citus_local_table(measureid, eventdate);
SELECT create_time_partitions('date_partitioned_citus_local_table_2', INTERVAL '1 day', '2021-02-01', '2021-01-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

-- after the above work, these should also work for creating new partitions
BEGIN;
  SELECT create_time_partitions('date_partitioned_citus_local_table', INTERVAL '1 day', '2021-03-01', '2021-02-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_citus_local_table'::regclass ORDER BY 3;
            parent_table            | partition_column |                   partition                    | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_01 | 01-01-2021 | 01-02-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_02 | 01-02-2021 | 01-03-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_03 | 01-03-2021 | 01-04-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_04 | 01-04-2021 | 01-05-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_05 | 01-05-2021 | 01-06-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_06 | 01-06-2021 | 01-07-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_07 | 01-07-2021 | 01-08-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_08 | 01-08-2021 | 01-09-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_09 | 01-09-2021 | 01-10-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_10 | 01-10-2021 | 01-11-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_11 | 01-11-2021 | 01-12-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_12 | 01-12-2021 | 01-13-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_13 | 01-13-2021 | 01-14-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_14 | 01-14-2021 | 01-15-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_15 | 01-15-2021 | 01-16-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_16 | 01-16-2021 | 01-17-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_17 | 01-17-2021 | 01-18-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_18 | 01-18-2021 | 01-19-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_19 | 01-19-2021 | 01-20-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_20 | 01-20-2021 | 01-21-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_21 | 01-21-2021 | 01-22-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_22 | 01-22-2021 | 01-23-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_23 | 01-23-2021 | 01-24-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_24 | 01-24-2021 | 01-25-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_25 | 01-25-2021 | 01-26-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_26 | 01-26-2021 | 01-27-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_27 | 01-27-2021 | 01-28-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_28 | 01-28-2021 | 01-29-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_29 | 01-29-2021 | 01-30-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_30 | 01-30-2021 | 01-31-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_31 | 01-31-2021 | 02-01-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_01 | 02-01-2021 | 02-02-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_02 | 02-02-2021 | 02-03-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_03 | 02-03-2021 | 02-04-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_04 | 02-04-2021 | 02-05-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_05 | 02-05-2021 | 02-06-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_06 | 02-06-2021 | 02-07-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_07 | 02-07-2021 | 02-08-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_08 | 02-08-2021 | 02-09-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_09 | 02-09-2021 | 02-10-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_10 | 02-10-2021 | 02-11-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_11 | 02-11-2021 | 02-12-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_12 | 02-12-2021 | 02-13-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_13 | 02-13-2021 | 02-14-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_14 | 02-14-2021 | 02-15-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_15 | 02-15-2021 | 02-16-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_16 | 02-16-2021 | 02-17-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_17 | 02-17-2021 | 02-18-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_18 | 02-18-2021 | 02-19-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_19 | 02-19-2021 | 02-20-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_20 | 02-20-2021 | 02-21-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_21 | 02-21-2021 | 02-22-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_22 | 02-22-2021 | 02-23-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_23 | 02-23-2021 | 02-24-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_24 | 02-24-2021 | 02-25-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_25 | 02-25-2021 | 02-26-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_26 | 02-26-2021 | 02-27-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_27 | 02-27-2021 | 02-28-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_02_28 | 02-28-2021 | 03-01-2021 | heap
(59 rows)

ROLLBACK;
BEGIN;
  SELECT create_time_partitions('date_partitioned_citus_local_table_2', INTERVAL '1 day', '2021-03-01', '2021-02-01');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'date_partitioned_citus_local_table'::regclass ORDER BY 3;
            parent_table            | partition_column |                   partition                    | from_value |  to_value  | access_method
---------------------------------------------------------------------
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_01 | 01-01-2021 | 01-02-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_02 | 01-02-2021 | 01-03-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_03 | 01-03-2021 | 01-04-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_04 | 01-04-2021 | 01-05-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_05 | 01-05-2021 | 01-06-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_06 | 01-06-2021 | 01-07-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_07 | 01-07-2021 | 01-08-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_08 | 01-08-2021 | 01-09-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_09 | 01-09-2021 | 01-10-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_10 | 01-10-2021 | 01-11-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_11 | 01-11-2021 | 01-12-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_12 | 01-12-2021 | 01-13-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_13 | 01-13-2021 | 01-14-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_14 | 01-14-2021 | 01-15-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_15 | 01-15-2021 | 01-16-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_16 | 01-16-2021 | 01-17-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_17 | 01-17-2021 | 01-18-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_18 | 01-18-2021 | 01-19-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_19 | 01-19-2021 | 01-20-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_20 | 01-20-2021 | 01-21-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_21 | 01-21-2021 | 01-22-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_22 | 01-22-2021 | 01-23-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_23 | 01-23-2021 | 01-24-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_24 | 01-24-2021 | 01-25-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_25 | 01-25-2021 | 01-26-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_26 | 01-26-2021 | 01-27-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_27 | 01-27-2021 | 01-28-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_28 | 01-28-2021 | 01-29-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_29 | 01-29-2021 | 01-30-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_30 | 01-30-2021 | 01-31-2021 | heap
 date_partitioned_citus_local_table | eventdate        | date_partitioned_citus_local_table_p2021_01_31 | 01-31-2021 | 02-01-2021 | heap
(31 rows)

ROLLBACK;
set client_min_messages to notice;
-- 7) test with bigint partition column
CREATE FUNCTION nanos_to_timestamptz(nanos bigint) RETURNS timestamptz LANGUAGE plpgsql AS
$$
DECLARE
  value timestamptz;
BEGIN
  select to_timestamp(nanos * 1.0 / 1000000000) into value;
  return value;
END;
$$;
CREATE CAST (bigint AS timestamptz) WITH FUNCTION nanos_to_timestamptz(bigint);
CREATE FUNCTION timestamptz_to_nanos(ts timestamptz) RETURNS bigint LANGUAGE plpgsql AS
$$
DECLARE
  value bigint;
BEGIN
  select extract(epoch from ts) * 1000000000 into value;
  return value;
END;
$$;
CREATE CAST (timestamptz AS bigint) WITH FUNCTION timestamptz_to_nanos(timestamptz);
CREATE TABLE bigint_partitioned_table (timestamp bigint, description text) partition by range (timestamp);
BEGIN;
  SELECT create_time_partitions('bigint_partitioned_table', INTERVAL '1 month', '2023-05-01', '2023-01-1');
 create_time_partitions
---------------------------------------------------------------------
 t
(1 row)

  SELECT * FROM time_partitions WHERE parent_table = 'bigint_partitioned_table'::regclass ORDER BY 3;
       parent_table       | partition_column |             partition             |     from_value      |      to_value       | access_method
---------------------------------------------------------------------
 bigint_partitioned_table | timestamp        | bigint_partitioned_table_p2023_01 | 1672560000000000000 | 1675238400000000000 | heap
 bigint_partitioned_table | timestamp        | bigint_partitioned_table_p2023_02 | 1675238400000000000 | 1677657600000000000 | heap
 bigint_partitioned_table | timestamp        | bigint_partitioned_table_p2023_03 | 1677657600000000000 | 1680332400000000000 | heap
 bigint_partitioned_table | timestamp        | bigint_partitioned_table_p2023_04 | 1680332400000000000 | 1682924400000000000 | heap
(4 rows)

ROLLBACK;
DROP CAST (bigint AS timestamptz);
DROP CAST (timestamptz AS bigint);
-- c) test drop_old_time_partitions
-- 1) test with date partitioned table
CREATE TABLE date_partitioned_table_to_exp (event_date date, event int) partition by range (event_date);
SELECT create_distributed_table('date_partitioned_table_to_exp', 'event');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE date_partitioned_table_to_exp_d00 PARTITION OF date_partitioned_table_to_exp FOR VALUES FROM ('2000-01-01') TO ('2009-12-31');
CREATE TABLE date_partitioned_table_to_exp_d10 PARTITION OF date_partitioned_table_to_exp FOR VALUES FROM ('2010-01-01') TO ('2019-12-31');
CREATE TABLE date_partitioned_table_to_exp_d20 PARTITION OF date_partitioned_table_to_exp FOR VALUES FROM ('2020-01-01') TO ('2029-12-31');
INSERT INTO date_partitioned_table_to_exp VALUES ('2005-01-01', 1);
INSERT INTO date_partitioned_table_to_exp VALUES ('2015-01-01', 2);
INSERT INTO date_partitioned_table_to_exp VALUES ('2025-01-01', 3);
\set VERBOSITY terse
-- expire no partitions
CALL drop_old_time_partitions('date_partitioned_table_to_exp', '1999-01-01');
SELECT partition FROM time_partitions WHERE parent_table = 'date_partitioned_table_to_exp'::regclass ORDER BY partition::text;
             partition
---------------------------------------------------------------------
 date_partitioned_table_to_exp_d00
 date_partitioned_table_to_exp_d10
 date_partitioned_table_to_exp_d20
(3 rows)

-- expire 2 old partitions
CALL drop_old_time_partitions('date_partitioned_table_to_exp', '2021-01-01');
NOTICE:  dropping date_partitioned_table_to_exp_d00 with start time 01-01-2000 and end time 12-31-2009
NOTICE:  dropping date_partitioned_table_to_exp_d10 with start time 01-01-2010 and end time 12-31-2019
SELECT partition FROM time_partitions WHERE parent_table = 'date_partitioned_table_to_exp'::regclass ORDER BY partition::text;
             partition
---------------------------------------------------------------------
 date_partitioned_table_to_exp_d20
(1 row)

\set VERBOSITY default
DROP TABLE date_partitioned_table_to_exp;
-- 2) test with timestamptz partitioned table
CREATE TABLE tstz_partitioned_table_to_exp (event_time timestamptz, event int) partition by range (event_time);
SELECT create_distributed_table('tstz_partitioned_table_to_exp', 'event');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE tstz_partitioned_table_to_exp_d0 PARTITION OF tstz_partitioned_table_to_exp FOR VALUES FROM ('2021-01-01 02:00:00+00') TO ('2021-01-01 06:00:00+00');
CREATE TABLE tstz_partitioned_table_to_exp_d1 PARTITION OF tstz_partitioned_table_to_exp FOR VALUES FROM ('2021-01-01 06:00:00+00') TO ('2021-01-01 10:00:00+00');
CREATE TABLE tstz_partitioned_table_to_exp_d2 PARTITION OF tstz_partitioned_table_to_exp FOR VALUES FROM ('2021-01-01 10:00:00+00') TO ('2021-01-01 14:00:00+00');
INSERT INTO tstz_partitioned_table_to_exp VALUES ('2021-01-01 03:00:00+00', 1);
INSERT INTO tstz_partitioned_table_to_exp VALUES ('2021-01-01 09:00:00+00', 2);
INSERT INTO tstz_partitioned_table_to_exp VALUES ('2021-01-01 13:00:00+00', 3);
\set VERBOSITY terse
-- expire no partitions
CALL drop_old_time_partitions('tstz_partitioned_table_to_exp', '2021-01-01 01:00:00+00');
SELECT partition FROM time_partitions WHERE parent_table = 'tstz_partitioned_table_to_exp'::regclass ORDER BY partition::text;
            partition
---------------------------------------------------------------------
 tstz_partitioned_table_to_exp_d0
 tstz_partitioned_table_to_exp_d1
 tstz_partitioned_table_to_exp_d2
(3 rows)

-- expire 2 old partitions
CALL drop_old_time_partitions('tstz_partitioned_table_to_exp', '2021-01-01 12:00:00+00');
NOTICE:  dropping tstz_partitioned_table_to_exp_d0 with start time Thu Dec 31 18:00:00 2020 PST and end time Thu Dec 31 22:00:00 2020 PST
NOTICE:  dropping tstz_partitioned_table_to_exp_d1 with start time Thu Dec 31 22:00:00 2020 PST and end time Fri Jan 01 02:00:00 2021 PST
SELECT partition FROM time_partitions WHERE parent_table = 'tstz_partitioned_table_to_exp'::regclass ORDER BY partition::text;
            partition
---------------------------------------------------------------------
 tstz_partitioned_table_to_exp_d2
(1 row)

\set VERBOSITY default
DROP TABLE tstz_partitioned_table_to_exp;
-- 3) test with weird table name
CREATE TABLE "test !/ \n _dist_123_table_exp" (event_time timestamptz, event int) partition by range (event_time);
SELECT create_distributed_table('"test !/ \n _dist_123_table_exp"', 'event');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE tstz_partitioned_table_to_exp_d0 PARTITION OF "test !/ \n _dist_123_table_exp" FOR VALUES FROM ('2021-01-01 02:00:00+00') TO ('2021-01-01 06:00:00+00');
CREATE TABLE tstz_partitioned_table_to_exp_d1 PARTITION OF "test !/ \n _dist_123_table_exp" FOR VALUES FROM ('2021-01-01 06:00:00+00') TO ('2021-01-01 10:00:00+00');
CREATE TABLE tstz_partitioned_table_to_exp_d2 PARTITION OF "test !/ \n _dist_123_table_exp" FOR VALUES FROM ('2021-01-01 10:00:00+00') TO ('2021-01-01 14:00:00+00');
INSERT INTO "test !/ \n _dist_123_table_exp" VALUES ('2021-01-01 03:00:00+00', 1);
INSERT INTO "test !/ \n _dist_123_table_exp" VALUES ('2021-01-01 09:00:00+00', 2);
INSERT INTO "test !/ \n _dist_123_table_exp" VALUES ('2021-01-01 13:00:00+00', 3);
\set VERBOSITY terse
-- expire no partitions
CALL drop_old_time_partitions('"test !/ \n _dist_123_table_exp"', '2021-01-01 01:00:00+00');
SELECT partition FROM time_partitions WHERE parent_table = '"test !/ \n _dist_123_table_exp"'::regclass ORDER BY partition::text;
            partition
---------------------------------------------------------------------
 tstz_partitioned_table_to_exp_d0
 tstz_partitioned_table_to_exp_d1
 tstz_partitioned_table_to_exp_d2
(3 rows)

-- expire 2 old partitions
CALL drop_old_time_partitions('"test !/ \n _dist_123_table_exp"', '2021-01-01 12:00:00+00');
NOTICE:  dropping tstz_partitioned_table_to_exp_d0 with start time Thu Dec 31 18:00:00 2020 PST and end time Thu Dec 31 22:00:00 2020 PST
NOTICE:  dropping tstz_partitioned_table_to_exp_d1 with start time Thu Dec 31 22:00:00 2020 PST and end time Fri Jan 01 02:00:00 2021 PST
SELECT partition FROM time_partitions WHERE parent_table = '"test !/ \n _dist_123_table_exp"'::regclass ORDER BY partition::text;
            partition
---------------------------------------------------------------------
 tstz_partitioned_table_to_exp_d2
(1 row)

\set VERBOSITY default
DROP TABLE "test !/ \n _dist_123_table_exp";
-- 4) test with citus local tables
CREATE TABLE date_partitioned_table_to_exp (event_date date, event int) partition by range (event_date);
SELECT citus_add_local_table_to_metadata('date_partitioned_table_to_exp');
 citus_add_local_table_to_metadata
---------------------------------------------------------------------

(1 row)

CREATE TABLE date_partitioned_table_to_exp_d00 PARTITION OF date_partitioned_table_to_exp FOR VALUES FROM ('2000-01-01') TO ('2009-12-31');
CREATE TABLE date_partitioned_table_to_exp_d10 PARTITION OF date_partitioned_table_to_exp FOR VALUES FROM ('2010-01-01') TO ('2019-12-31');
CREATE TABLE date_partitioned_table_to_exp_d20 PARTITION OF date_partitioned_table_to_exp FOR VALUES FROM ('2020-01-01') TO ('2029-12-31');
\set VERBOSITY terse
-- expire no partitions
CALL drop_old_time_partitions('date_partitioned_table_to_exp', '1999-01-01');
SELECT partition FROM time_partitions WHERE parent_table = 'date_partitioned_table_to_exp'::regclass ORDER BY partition::text;
             partition
---------------------------------------------------------------------
 date_partitioned_table_to_exp_d00
 date_partitioned_table_to_exp_d10
 date_partitioned_table_to_exp_d20
(3 rows)

-- expire 2 old partitions
CALL drop_old_time_partitions('date_partitioned_table_to_exp', '2021-01-01');
NOTICE:  dropping date_partitioned_table_to_exp_d00 with start time 01-01-2000 and end time 12-31-2009
NOTICE:  dropping date_partitioned_table_to_exp_d10 with start time 01-01-2010 and end time 12-31-2019
SELECT partition FROM time_partitions WHERE parent_table = 'date_partitioned_table_to_exp'::regclass ORDER BY partition::text;
             partition
---------------------------------------------------------------------
 date_partitioned_table_to_exp_d20
(1 row)

\set VERBOSITY default
set client_min_messages to error;
DROP TABLE date_partitioned_table_to_exp;
DROP TABLE date_partitioned_citus_local_table CASCADE;
DROP TABLE date_partitioned_citus_local_table_2;
set client_min_messages to notice;
-- d) invalid tables for helper UDFs
CREATE TABLE multiple_partition_column_table(
  event_id bigserial,
  event_time timestamptz,
  payload text) PARTITION BY RANGE (event_time, event_id);
SELECT create_time_partitions('multiple_partition_column_table', INTERVAL '1 month', now() + INTERVAL '1 year');
ERROR:  partitioned tables with multiple partition columns are not supported
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
CALL drop_old_time_partitions('multiple_partition_column_table', now());
ERROR:  partitioned tables with multiple partition columns are not supported
CONTEXT:  PL/pgSQL function drop_old_time_partitions(regclass,timestamp with time zone) line XX at RAISE
DROP TABLE multiple_partition_column_table;
CREATE TABLE invalid_partition_column_table(
  event_id bigserial,
  event_time bigint,
  payload text) PARTITION BY RANGE (event_time);
SELECT create_time_partitions('invalid_partition_column_table', INTERVAL '1 month', now() + INTERVAL '1 year');
ERROR:  type of the partition column of the table invalid_partition_column_table must be date, timestamp or timestamptz
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
CALL drop_old_time_partitions('invalid_partition_column_table', now());
ERROR:  type of the partition column of the table invalid_partition_column_table must be date, timestamp or timestamptz
CONTEXT:  PL/pgSQL function drop_old_time_partitions(regclass,timestamp with time zone) line XX at RAISE
DROP TABLE invalid_partition_column_table;
CREATE TABLE non_partitioned_table(
  event_id bigserial,
  event_time timestamptz,
  payload text);
SELECT create_time_partitions('non_partitioned_table', INTERVAL '1 month', now() + INTERVAL '1 year');
ERROR:  non_partitioned_table is not partitioned
CONTEXT:  PL/pgSQL function get_missing_time_partition_ranges(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at RAISE
PL/pgSQL function create_time_partitions(regclass,interval,timestamp with time zone,timestamp with time zone) line XX at FOR over SELECT rows
CALL drop_old_time_partitions('non_partitioned_table', now());
ERROR:  non_partitioned_table is not partitioned
CONTEXT:  PL/pgSQL function drop_old_time_partitions(regclass,timestamp with time zone) line XX at RAISE
DROP TABLE non_partitioned_table;
-- https://github.com/citusdata/citus/issues/4962
SELECT stop_metadata_sync_to_node('localhost', :worker_1_port);
NOTICE:  dropping metadata on the node (localhost,57637)
 stop_metadata_sync_to_node
---------------------------------------------------------------------

(1 row)

SET citus.shard_replication_factor TO 1;
SET citus.next_shard_id TO 361168;
CREATE TABLE part_table_with_very_long_name (
    dist_col integer,
    long_named_integer_col integer,
    long_named_part_col timestamp
) PARTITION BY RANGE (long_named_part_col);
CREATE TABLE part_table_with_long_long_long_long_name
PARTITION OF part_table_with_very_long_name
FOR VALUES FROM ('2010-01-01') TO ('2015-01-01');
SELECT create_distributed_table('part_table_with_very_long_name', 'dist_col');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE INDEX ON part_table_with_very_long_name
USING btree (long_named_integer_col, long_named_part_col);
-- index is created
SELECT tablename, indexname FROM pg_indexes
WHERE schemaname = 'partitioning_schema' AND tablename ilike '%part_table_with_%' ORDER BY 1, 2;
                tablename                 |                            indexname
---------------------------------------------------------------------
 part_table_with_long_long_long_long_name | part_table_with_long_long_lon_long_named_integer_col_long_n_idx
 part_table_with_very_long_name           | part_table_with_very_long_nam_long_named_integer_col_long_n_idx
(2 rows)

-- should work properly - no names clashes
SET client_min_messages TO WARNING;
SELECT 1 FROM citus_activate_node('localhost', :worker_1_port);
 ?column?
---------------------------------------------------------------------
        1
(1 row)

RESET client_min_messages;
\c - - - :worker_1_port
-- check that indexes are named properly
SELECT tablename, indexname FROM pg_indexes
WHERE schemaname = 'partitioning_schema' AND tablename ilike '%part_table_with_%' ORDER BY 1, 2;
                    tablename                    |                            indexname
---------------------------------------------------------------------
 part_table_with_long_long_long_long_name        | part_table_with_long_long_lon_long_named_integer_col_long_n_idx
 part_table_with_long_long_long_long_name_361172 | part_table_with_long_long_lon_long_named_intege_f9175544_361172
 part_table_with_long_long_long_long_name_361174 | part_table_with_long_long_lon_long_named_intege_f9175544_361174
 part_table_with_very_long_name                  | part_table_with_very_long_nam_long_named_integer_col_long_n_idx
 part_table_with_very_long_name_361168           | part_table_with_very_long_nam_long_named_intege_73d4b078_361168
 part_table_with_very_long_name_361170           | part_table_with_very_long_nam_long_named_intege_73d4b078_361170
(6 rows)

\c - - - :master_port
SET search_path TO partitioning_schema;
-- create parent table
CREATE TABLE stxdinp(i int, a int, b int) PARTITION BY RANGE (i);
-- create partition
CREATE TABLE stxdinp1 PARTITION OF stxdinp FOR VALUES FROM (1) TO (100);
-- populate table
INSERT INTO stxdinp SELECT 1, a/100, a/100 FROM generate_series(1, 999) a;
-- create extended statistics
CREATE STATISTICS stxdinp ON a, b FROM stxdinp;
-- distribute parent table
SELECT create_distributed_table('stxdinp', 'i');
NOTICE:  Copying data from local table...
NOTICE:  copying the data has completed
DETAIL:  The local data in the table is no longer visible, but is still on disk.
HINT:  To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$partitioning_schema.stxdinp1$$)
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- run select query, works fine
SELECT a, b FROM stxdinp GROUP BY 1, 2;
 a | b
---------------------------------------------------------------------
 1 | 1
 3 | 3
 7 | 7
 2 | 2
 8 | 8
 0 | 0
 5 | 5
 6 | 6
 9 | 9
 4 | 4
(10 rows)

-- partitions are processed recursively for PG15+
VACUUM ANALYZE stxdinp;
SELECT a, b FROM stxdinp GROUP BY 1, 2;
 a | b
---------------------------------------------------------------------
 1 | 1
 3 | 3
 7 | 7
 2 | 2
 8 | 8
 0 | 0
 5 | 5
 6 | 6
 9 | 9
 4 | 4
(10 rows)

DROP SCHEMA partitioning_schema CASCADE;
NOTICE:  drop cascades to 8 other objects
DETAIL:  drop cascades to table "schema-test"
drop cascades to table another_distributed_table
drop cascades to table distributed_parent_table
drop cascades to function nanos_to_timestamptz(bigint)
drop cascades to function timestamptz_to_nanos(timestamp with time zone)
drop cascades to table bigint_partitioned_table
drop cascades to table part_table_with_very_long_name
drop cascades to table stxdinp
RESET search_path;
DROP TABLE IF EXISTS
	partitioning_hash_test,
	partitioning_test_failure,
	non_distributed_partitioned_table,
	partitioning_test_foreign_key;
