diff --git a/Makefile b/Makefile index ef5d850..bdf96be 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,10 @@ EXTENSION = hypopg EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/") TESTS = $(wildcard test/sql/*.sql) -REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS)) +REGRESS = hypo_setup \ + hypo_index \ + hypo_table + REGRESS_OPTS = --inputdir=test PG_CONFIG ?= pg_config diff --git a/expected/hypopg.out b/expected/hypo_index.out similarity index 93% rename from expected/hypopg.out rename to expected/hypo_index.out index e51e948..00015b3 100644 --- a/expected/hypopg.out +++ b/expected/hypo_index.out @@ -1,17 +1,4 @@ --- SETUP -CREATE OR REPLACE FUNCTION do_explain(stmt text) RETURNS table(a text) AS -$_$ -DECLARE - ret text; -BEGIN - FOR ret IN EXECUTE format('EXPLAIN (FORMAT text) %s', stmt) LOOP - a := ret; - RETURN next ; - END LOOP; -END; -$_$ -LANGUAGE plpgsql; -CREATE EXTENSION hypopg; +-- Hypothetical index tests CREATE TABLE hypo (id integer, val text); INSERT INTO hypo SELECT i, 'line ' || i FROM generate_series(1,100000) f(i); diff --git a/expected/hypo_setup.out b/expected/hypo_setup.out new file mode 100644 index 0000000..7b34af1 --- /dev/null +++ b/expected/hypo_setup.out @@ -0,0 +1,16 @@ +-- General setup +-- Create extension +CREATE EXTENSION hypopg; +-- Create do_explain function +CREATE OR REPLACE FUNCTION do_explain(stmt text) RETURNS table(a text) AS +$_$ +DECLARE + ret text; +BEGIN + FOR ret IN EXECUTE format('EXPLAIN (FORMAT text) %s', stmt) LOOP + a := ret; + RETURN next ; + END LOOP; +END; +$_$ +LANGUAGE plpgsql; diff --git a/expected/hypo_table.out b/expected/hypo_table.out new file mode 100644 index 0000000..7ce05a3 --- /dev/null +++ b/expected/hypo_table.out @@ -0,0 +1,726 @@ +-- Creating real and hypothetical tables" +-- =====================================" +-- Real tables +-- ----------- +-- 1. Range partition +DROP TABLE IF EXISTS part_range; +NOTICE: table "part_range" does not exist, skipping +CREATE TABLE part_range (id integer, val text) PARTITION BY RANGE (id); +CREATE TABLE part_range_1_10000 PARTITION OF part_range FOR VALUES FROM (1) TO (10000); +CREATE TABLE part_range_10000_20000 PARTITION OF part_range FOR VALUES FROM (10000) TO (20000); +CREATE TABLE part_range_20000_30000 PARTITION OF part_range FOR VALUES FROM (20000) TO (30000); +INSERT INTO part_range SELECT i, 'line ' || i FROM generate_series(1, 29999) i; +-- 2. List partitioning +DROP TABLE IF EXISTS part_list; +NOTICE: table "part_list" does not exist, skipping +CREATE TABLE part_list (id integer, id_key integer, val text) PARTITION BY LIST (id_key); +CREATE TABLE part_list_1_2_3 PARTITION OF part_list FOR VALUES IN (1, 2, 3); +CREATE TABLE part_list_4_5_6_8_10 PARTITION OF part_list FOR VALUES IN (4, 5, 6, 8, 10); +CREATE TABLE part_list_7_9 PARTITION OF part_list FOR VALUES IN (7, 9); +INSERT INTO part_list SELECT i, (i % 9) + 1, 'line ' || i FROM generate_series(1, 50000) i; +-- 3. Hash partitioning +DROP TABLE IF EXISTS part_hash; +NOTICE: table "part_hash" does not exist, skipping +CREATE TABLE part_hash (id integer, val text) PARTITION BY HASH (id); +CREATE TABLE part_hash_0 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 0); +CREATE TABLE part_hash_1 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 1); +CREATE TABLE part_hash_2 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 2); +CREATE TABLE part_hash_3 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 3); +CREATE TABLE part_hash_4 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 4); +CREATE TABLE part_hash_5 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 5); +CREATE TABLE part_hash_6 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 6); +CREATE TABLE part_hash_7 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 7); +CREATE TABLE part_hash_8 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 8); +CREATE TABLE part_hash_9 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 9); +INSERT INTO part_hash SELECT i, 'line ' || i FROM generate_series(1, 90000) i; +-- 4. Multi level range +DROP TABLE IF EXISTS part_multi; +NOTICE: table "part_multi" does not exist, skipping +CREATE TABLE part_multi(dpt smallint, dt date, val text) PARTITION BY LIST (dpt); +CREATE TABLE part_multi_1 PARTITION OF part_multi FOR VALUES IN (1) PARTITION BY RANGE(dt); +CREATE TABLE part_multi_1_q1 PARTITION OF part_multi_1 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$) PARTITION BY RANGE (dt); +CREATE TABLE part_multi_1_q1_a PARTITION OF part_multi_1_q1 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-02-01$$); +CREATE TABLE part_multi_1_q1_b PARTITION OF part_multi_1_q1 FOR VALUES FROM ($$2015-02-01$$) TO ($$2015-04-01$$); +CREATE TABLE part_multi_1_q2 PARTITION OF part_multi_1 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$); +CREATE TABLE part_multi_1_q3 PARTITION OF part_multi_1 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$); +CREATE TABLE part_multi_1_q4 PARTITION OF part_multi_1 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$); +CREATE TABLE part_multi_2 PARTITION OF part_multi FOR VALUES IN (2) PARTITION BY RANGE(dt); +CREATE TABLE part_multi_2_q1 PARTITION OF part_multi_2 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$); +CREATE TABLE part_multi_2_q2 PARTITION OF part_multi_2 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$); +CREATE TABLE part_multi_2_q3 PARTITION OF part_multi_2 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$); +CREATE TABLE part_multi_2_q4 PARTITION OF part_multi_2 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$); +CREATE TABLE part_multi_3 PARTITION OF part_multi FOR VALUES IN (3) PARTITION BY RANGE(dt); +CREATE TABLE part_multi_3_q1 PARTITION OF part_multi_3 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$); +CREATE TABLE part_multi_3_q2 PARTITION OF part_multi_3 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$); +CREATE TABLE part_multi_3_q3 PARTITION OF part_multi_3 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$); +CREATE TABLE part_multi_3_q4 PARTITION OF part_multi_3 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$); +INSERT INTO part_multi select (i%3)+1, '2015-01-01'::date + interval '1 day' * (i%365), 'val ' || i FROM generate_series(1,10000) i; +-- Hypothetical tables +-- ------------------- +-- 0. Dropping any hypothetical object +SELECT * FROM hypopg_reset_index(); + hypopg_reset_index +-------------------- + +(1 row) + +SELECT * FROM hypopg_reset_table(); + hypopg_reset_table +-------------------- + +(1 row) + +-- 1. Range partition +DROP TABLE IF EXISTS hypo_part_range; +NOTICE: table "hypo_part_range" does not exist, skipping +CREATE TABLE hypo_part_range (id integer, val text); +INSERT INTO hypo_part_range SELECT i, 'line ' || i FROM generate_series(1, 29999) i; +SELECT * FROM hypopg_partition_table('hypo_part_range', 'PARTITION BY RANGE (id)'); + hypopg_partition_table +------------------------ + t +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_range_1_10000', 'PARTITION OF hypo_part_range FOR VALUES FROM (1) TO (10000)'); + tablename +------------------------- + hypo_part_range_1_10000 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_range_10000_20000', 'PARTITION OF hypo_part_range FOR VALUES FROM (10000) TO (20000)'); + tablename +----------------------------- + hypo_part_range_10000_20000 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_range_20000_30000', 'PARTITION OF hypo_part_range FOR VALUES FROM (20000) TO (30000)'); + tablename +----------------------------- + hypo_part_range_20000_30000 +(1 row) + +-- 2. List partitioning +DROP TABLE IF EXISTS hypo_part_list; +NOTICE: table "hypo_part_list" does not exist, skipping +CREATE TABLE hypo_part_list (id integer, id_key integer, val text); +INSERT INTO hypo_part_list SELECT i, (i % 9) + 1, 'line ' || i FROM generate_series(1, 50000) i; +SELECT * FROM hypopg_partition_table('hypo_part_list', 'PARTITION BY LIST (id_key)'); + hypopg_partition_table +------------------------ + t +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_list_1_2_3', 'PARTITION OF hypo_part_list FOR VALUES IN (1, 2, 3)'); + tablename +---------------------- + hypo_part_list_1_2_3 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_list_4_5_6_8_10', 'PARTITION OF hypo_part_list FOR VALUES IN (4, 5, 6, 8, 10)'); + tablename +--------------------------- + hypo_part_list_4_5_6_8_10 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_list_7_9', 'PARTITION OF hypo_part_list FOR VALUES IN (7, 9)'); + tablename +-------------------- + hypo_part_list_7_9 +(1 row) + +-- 3. Hash partitioning +DROP TABLE IF EXISTS hypo_part_hash; +NOTICE: table "hypo_part_hash" does not exist, skipping +CREATE TABLE hypo_part_hash (id integer, val text); +INSERT INTO hypo_part_hash SELECT i, 'line ' || i FROM generate_series(1, 90000) i; +SELECT * FROM hypopg_partition_table('hypo_part_hash', 'PARTITION BY HASH (id)'); + hypopg_partition_table +------------------------ + t +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_0', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 0)'); + tablename +------------------ + hypo_part_hash_0 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_1', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 1)'); + tablename +------------------ + hypo_part_hash_1 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_2', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 2)'); + tablename +------------------ + hypo_part_hash_2 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_3', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 3)'); + tablename +------------------ + hypo_part_hash_3 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_4', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 4)'); + tablename +------------------ + hypo_part_hash_4 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_5', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 5)'); + tablename +------------------ + hypo_part_hash_5 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_6', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 6)'); + tablename +------------------ + hypo_part_hash_6 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_7', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 7)'); + tablename +------------------ + hypo_part_hash_7 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_8', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 8)'); + tablename +------------------ + hypo_part_hash_8 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_9', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 9)'); + tablename +------------------ + hypo_part_hash_9 +(1 row) + +-- 4. Multi level range +DROP TABLE IF EXISTS hypo_part_multi; +NOTICE: table "hypo_part_multi" does not exist, skipping +CREATE TABLE hypo_part_multi(dpt smallint, dt date, val text); +INSERT INTO hypo_part_multi select (i%3)+1, '2015-01-01'::date + interval '1 day' * (i%365), 'val ' || i FROM generate_series(1,10000) i; +SELECT * FROM hypopg_partition_table('hypo_part_multi', 'PARTITION BY LIST (dpt)'); + hypopg_partition_table +------------------------ + t +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1', 'PARTITION OF hypo_part_multi FOR VALUES IN (1)', 'PARTITION BY RANGE(dt)'); + tablename +------------------- + hypo_part_multi_1 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q1', 'PARTITION OF hypo_part_multi_1 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$)','PARTITION BY RANGE (dt)'); + tablename +---------------------- + hypo_part_multi_1_q1 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q1_a', 'PARTITION OF hypo_part_multi_1_q1 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-02-01$$)'); + tablename +------------------------ + hypo_part_multi_1_q1_a +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q1_b', 'PARTITION OF hypo_part_multi_1_q1 FOR VALUES FROM ($$2015-02-01$$) TO ($$2015-04-01$$)'); + tablename +------------------------ + hypo_part_multi_1_q1_b +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q2', 'PARTITION OF hypo_part_multi_1 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$)'); + tablename +---------------------- + hypo_part_multi_1_q2 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q3', 'PARTITION OF hypo_part_multi_1 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$)'); + tablename +---------------------- + hypo_part_multi_1_q3 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q4', 'PARTITION OF hypo_part_multi_1 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$)'); + tablename +---------------------- + hypo_part_multi_1_q4 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2', 'PARTITION OF hypo_part_multi FOR VALUES IN (2)', 'PARTITION BY RANGE(dt)'); + tablename +------------------- + hypo_part_multi_2 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2_q1', 'PARTITION OF hypo_part_multi_2 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$)'); + tablename +---------------------- + hypo_part_multi_2_q1 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2_q2', 'PARTITION OF hypo_part_multi_2 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$)'); + tablename +---------------------- + hypo_part_multi_2_q2 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2_q3', 'PARTITION OF hypo_part_multi_2 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$)'); + tablename +---------------------- + hypo_part_multi_2_q3 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2_q4', 'PARTITION OF hypo_part_multi_2 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$)'); + tablename +---------------------- + hypo_part_multi_2_q4 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3', 'PARTITION OF hypo_part_multi FOR VALUES IN (3)', 'PARTITION BY RANGE(dt)'); + tablename +------------------- + hypo_part_multi_3 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3_q1', 'PARTITION OF hypo_part_multi_3 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$)'); + tablename +---------------------- + hypo_part_multi_3_q1 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3_q2', 'PARTITION OF hypo_part_multi_3 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$)'); + tablename +---------------------- + hypo_part_multi_3_q2 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3_q3', 'PARTITION OF hypo_part_multi_3 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$)'); + tablename +---------------------- + hypo_part_multi_3_q3 +(1 row) + +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3_q4', 'PARTITION OF hypo_part_multi_3 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$)'); + tablename +---------------------- + hypo_part_multi_3_q4 +(1 row) + +-- Maintenance +-- ----------- +VACUUM ANALYZE; +-- Test deparsing +-- ============== +SELECT relid = rootid AS is_root, tablename, parentid IS NULL parentid_is_null, + parentid IS NOT NULL AS parentid_is_not_null, + partition_by_clause, partition_bounds +FROM hypopg_table(); + is_root | tablename | parentid_is_null | parentid_is_not_null | partition_by_clause | partition_bounds +---------+-----------------------------+------------------+----------------------+----------------------------+-------------------------------------------------- + t | hypo_part_range | t | f | PARTITION BY RANGE (id) | + f | hypo_part_range_1_10000 | f | t | | FOR VALUES FROM (1) TO (10000) + f | hypo_part_range_10000_20000 | f | t | | FOR VALUES FROM (10000) TO (20000) + f | hypo_part_range_20000_30000 | f | t | | FOR VALUES FROM (20000) TO (30000) + t | hypo_part_list | t | f | PARTITION BY LIST (id_key) | + f | hypo_part_list_1_2_3 | f | t | | FOR VALUES IN (1, 2, 3) + f | hypo_part_list_4_5_6_8_10 | f | t | | FOR VALUES IN (4, 5, 6, 8, 10) + f | hypo_part_list_7_9 | f | t | | FOR VALUES IN (7, 9) + t | hypo_part_hash | t | f | PARTITION BY HASH (id) | + f | hypo_part_hash_0 | f | t | | FOR VALUES WITH (modulus 10, remainder 0) + f | hypo_part_hash_1 | f | t | | FOR VALUES WITH (modulus 10, remainder 1) + f | hypo_part_hash_2 | f | t | | FOR VALUES WITH (modulus 10, remainder 2) + f | hypo_part_hash_3 | f | t | | FOR VALUES WITH (modulus 10, remainder 3) + f | hypo_part_hash_4 | f | t | | FOR VALUES WITH (modulus 10, remainder 4) + f | hypo_part_hash_5 | f | t | | FOR VALUES WITH (modulus 10, remainder 5) + f | hypo_part_hash_6 | f | t | | FOR VALUES WITH (modulus 10, remainder 6) + f | hypo_part_hash_7 | f | t | | FOR VALUES WITH (modulus 10, remainder 7) + f | hypo_part_hash_8 | f | t | | FOR VALUES WITH (modulus 10, remainder 8) + f | hypo_part_hash_9 | f | t | | FOR VALUES WITH (modulus 10, remainder 9) + t | hypo_part_multi | t | f | PARTITION BY LIST (dpt) | + f | hypo_part_multi_1 | f | t | PARTITION BY RANGE (dt) | FOR VALUES IN ('1') + f | hypo_part_multi_1_q1 | f | t | PARTITION BY RANGE (dt) | FOR VALUES FROM ('01-01-2015') TO ('04-01-2015') + f | hypo_part_multi_1_q1_a | f | t | | FOR VALUES FROM ('01-01-2015') TO ('02-01-2015') + f | hypo_part_multi_1_q1_b | f | t | | FOR VALUES FROM ('02-01-2015') TO ('04-01-2015') + f | hypo_part_multi_1_q2 | f | t | | FOR VALUES FROM ('04-01-2015') TO ('07-01-2015') + f | hypo_part_multi_1_q3 | f | t | | FOR VALUES FROM ('07-01-2015') TO ('10-01-2015') + f | hypo_part_multi_1_q4 | f | t | | FOR VALUES FROM ('10-01-2015') TO ('01-01-2016') + f | hypo_part_multi_2 | f | t | PARTITION BY RANGE (dt) | FOR VALUES IN ('2') + f | hypo_part_multi_2_q1 | f | t | | FOR VALUES FROM ('01-01-2015') TO ('04-01-2015') + f | hypo_part_multi_2_q2 | f | t | | FOR VALUES FROM ('04-01-2015') TO ('07-01-2015') + f | hypo_part_multi_2_q3 | f | t | | FOR VALUES FROM ('07-01-2015') TO ('10-01-2015') + f | hypo_part_multi_2_q4 | f | t | | FOR VALUES FROM ('10-01-2015') TO ('01-01-2016') + f | hypo_part_multi_3 | f | t | PARTITION BY RANGE (dt) | FOR VALUES IN ('3') + f | hypo_part_multi_3_q1 | f | t | | FOR VALUES FROM ('01-01-2015') TO ('04-01-2015') + f | hypo_part_multi_3_q2 | f | t | | FOR VALUES FROM ('04-01-2015') TO ('07-01-2015') + f | hypo_part_multi_3_q3 | f | t | | FOR VALUES FROM ('07-01-2015') TO ('10-01-2015') + f | hypo_part_multi_3_q4 | f | t | | FOR VALUES FROM ('10-01-2015') TO ('01-01-2016') +(37 rows) + +-- Test hypothetical partitioning behavior +-- ======================================= +-- Simple queries +-- -------------- +-- Real tables +-- ----------- +-- 1. Range partition +EXPLAIN (COSTS OFF) SELECT * FROM part_range; + QUERY PLAN +------------------------------------------ + Append + -> Seq Scan on part_range_1_10000 + -> Seq Scan on part_range_10000_20000 + -> Seq Scan on part_range_20000_30000 +(4 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_range WHERE id = 42; + QUERY PLAN +-------------------------------------- + Append + -> Seq Scan on part_range_1_10000 + Filter: (id = 42) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_range WHERE id < 15000; + QUERY PLAN +------------------------------------------ + Append + -> Seq Scan on part_range_1_10000 + Filter: (id < 15000) + -> Seq Scan on part_range_10000_20000 + Filter: (id < 15000) +(5 rows) + +-- 2. List partitioning +EXPLAIN (COSTS OFF) SELECT * FROM part_list; + QUERY PLAN +---------------------------------------- + Append + -> Seq Scan on part_list_1_2_3 + -> Seq Scan on part_list_4_5_6_8_10 + -> Seq Scan on part_list_7_9 +(4 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_list WHERE id < 42; + QUERY PLAN +---------------------------------------- + Append + -> Seq Scan on part_list_1_2_3 + Filter: (id < 42) + -> Seq Scan on part_list_4_5_6_8_10 + Filter: (id < 42) + -> Seq Scan on part_list_7_9 + Filter: (id < 42) +(7 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_list WHERE id < 15000; + QUERY PLAN +---------------------------------------- + Append + -> Seq Scan on part_list_1_2_3 + Filter: (id < 15000) + -> Seq Scan on part_list_4_5_6_8_10 + Filter: (id < 15000) + -> Seq Scan on part_list_7_9 + Filter: (id < 15000) +(7 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_list WHERE id_key < 5; + QUERY PLAN +---------------------------------------- + Append + -> Seq Scan on part_list_1_2_3 + Filter: (id_key < 5) + -> Seq Scan on part_list_4_5_6_8_10 + Filter: (id_key < 5) +(5 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_list WHERE id_key = 7; + QUERY PLAN +--------------------------------- + Append + -> Seq Scan on part_list_7_9 + Filter: (id_key = 7) +(3 rows) + +-- 3. Hash partitioning +EXPLAIN (COSTS OFF) SELECT * FROM part_hash; + QUERY PLAN +------------------------------- + Append + -> Seq Scan on part_hash_0 + -> Seq Scan on part_hash_1 + -> Seq Scan on part_hash_2 + -> Seq Scan on part_hash_3 + -> Seq Scan on part_hash_4 + -> Seq Scan on part_hash_5 + -> Seq Scan on part_hash_6 + -> Seq Scan on part_hash_7 + -> Seq Scan on part_hash_8 + -> Seq Scan on part_hash_9 +(11 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_hash WHERE id = 42; + QUERY PLAN +------------------------------- + Append + -> Seq Scan on part_hash_4 + Filter: (id = 42) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_hash WHERE id < 15000; + QUERY PLAN +------------------------------- + Append + -> Seq Scan on part_hash_0 + Filter: (id < 15000) + -> Seq Scan on part_hash_1 + Filter: (id < 15000) + -> Seq Scan on part_hash_2 + Filter: (id < 15000) + -> Seq Scan on part_hash_3 + Filter: (id < 15000) + -> Seq Scan on part_hash_4 + Filter: (id < 15000) + -> Seq Scan on part_hash_5 + Filter: (id < 15000) + -> Seq Scan on part_hash_6 + Filter: (id < 15000) + -> Seq Scan on part_hash_7 + Filter: (id < 15000) + -> Seq Scan on part_hash_8 + Filter: (id < 15000) + -> Seq Scan on part_hash_9 + Filter: (id < 15000) +(21 rows) + +-- 4. Multi level range +EXPLAIN (COSTS OFF) SELECT * FROM part_multi; + QUERY PLAN +------------------------------------- + Append + -> Seq Scan on part_multi_1_q1_a + -> Seq Scan on part_multi_1_q1_b + -> Seq Scan on part_multi_1_q2 + -> Seq Scan on part_multi_1_q3 + -> Seq Scan on part_multi_1_q4 + -> Seq Scan on part_multi_2_q1 + -> Seq Scan on part_multi_2_q2 + -> Seq Scan on part_multi_2_q3 + -> Seq Scan on part_multi_2_q4 + -> Seq Scan on part_multi_3_q1 + -> Seq Scan on part_multi_3_q2 + -> Seq Scan on part_multi_3_q3 + -> Seq Scan on part_multi_3_q4 +(14 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_multi WHERE dpt = 2; + QUERY PLAN +----------------------------------- + Append + -> Seq Scan on part_multi_2_q1 + Filter: (dpt = 2) + -> Seq Scan on part_multi_2_q2 + Filter: (dpt = 2) + -> Seq Scan on part_multi_2_q3 + Filter: (dpt = 2) + -> Seq Scan on part_multi_2_q4 + Filter: (dpt = 2) +(9 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM part_multi WHERE dt >= '2015-01-05' AND dt < '2015-01-10'; + QUERY PLAN +---------------------------------------------------------------------------- + Append + -> Seq Scan on part_multi_1_q1_a + Filter: ((dt >= '01-05-2015'::date) AND (dt < '01-10-2015'::date)) + -> Seq Scan on part_multi_2_q1 + Filter: ((dt >= '01-05-2015'::date) AND (dt < '01-10-2015'::date)) + -> Seq Scan on part_multi_3_q1 + Filter: ((dt >= '01-05-2015'::date) AND (dt < '01-10-2015'::date)) +(7 rows) + +-- Hypothetical tables +-- ------------------" +-- 1. Range partition +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_range; + QUERY PLAN +--------------------------------------------------------------- + Append + -> Seq Scan on hypo_part_range hypo_part_range_1_10000 + -> Seq Scan on hypo_part_range hypo_part_range_10000_20000 + -> Seq Scan on hypo_part_range hypo_part_range_20000_30000 +(4 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_range WHERE id = 42; + QUERY PLAN +----------------------------------------------------------- + Append + -> Seq Scan on hypo_part_range hypo_part_range_1_10000 + Filter: (id = 42) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_range WHERE id < 15000; + QUERY PLAN +--------------------------------------------------------------- + Append + -> Seq Scan on hypo_part_range hypo_part_range_1_10000 + Filter: (id < 15000) + -> Seq Scan on hypo_part_range hypo_part_range_10000_20000 + Filter: (id < 15000) +(5 rows) + +-- 2. List partitioning +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list; + QUERY PLAN +------------------------------------------------------------ + Append + -> Seq Scan on hypo_part_list hypo_part_list_1_2_3 + -> Seq Scan on hypo_part_list hypo_part_list_4_5_6_8_10 + -> Seq Scan on hypo_part_list hypo_part_list_7_9 +(4 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list WHERE id < 42; + QUERY PLAN +------------------------------------------------------------ + Append + -> Seq Scan on hypo_part_list hypo_part_list_1_2_3 + Filter: (id < 42) + -> Seq Scan on hypo_part_list hypo_part_list_4_5_6_8_10 + Filter: (id < 42) + -> Seq Scan on hypo_part_list hypo_part_list_7_9 + Filter: (id < 42) +(7 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list WHERE id < 15000; + QUERY PLAN +------------------------------------------------------------ + Append + -> Seq Scan on hypo_part_list hypo_part_list_1_2_3 + Filter: (id < 15000) + -> Seq Scan on hypo_part_list hypo_part_list_4_5_6_8_10 + Filter: (id < 15000) + -> Seq Scan on hypo_part_list hypo_part_list_7_9 + Filter: (id < 15000) +(7 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list WHERE id_key < 5; + QUERY PLAN +------------------------------------------------------------ + Append + -> Seq Scan on hypo_part_list hypo_part_list_1_2_3 + Filter: (id_key < 5) + -> Seq Scan on hypo_part_list hypo_part_list_4_5_6_8_10 + Filter: (id_key < 5) +(5 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list WHERE id_key = 7; + QUERY PLAN +----------------------------------------------------- + Append + -> Seq Scan on hypo_part_list hypo_part_list_7_9 + Filter: (id_key = 7) +(3 rows) + +-- 3. Hash partitioning +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_hash; + QUERY PLAN +--------------------------------------------------- + Append + -> Seq Scan on hypo_part_hash hypo_part_hash_0 + -> Seq Scan on hypo_part_hash hypo_part_hash_1 + -> Seq Scan on hypo_part_hash hypo_part_hash_2 + -> Seq Scan on hypo_part_hash hypo_part_hash_3 + -> Seq Scan on hypo_part_hash hypo_part_hash_4 + -> Seq Scan on hypo_part_hash hypo_part_hash_5 + -> Seq Scan on hypo_part_hash hypo_part_hash_6 + -> Seq Scan on hypo_part_hash hypo_part_hash_7 + -> Seq Scan on hypo_part_hash hypo_part_hash_8 + -> Seq Scan on hypo_part_hash hypo_part_hash_9 +(11 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_hash WHERE id = 42; + QUERY PLAN +--------------------------------------------------- + Append + -> Seq Scan on hypo_part_hash hypo_part_hash_4 + Filter: (id = 42) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_hash WHERE id < 15000; + QUERY PLAN +--------------------------------------------------- + Append + -> Seq Scan on hypo_part_hash hypo_part_hash_0 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_1 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_2 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_3 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_4 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_5 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_6 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_7 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_8 + Filter: (id < 15000) + -> Seq Scan on hypo_part_hash hypo_part_hash_9 + Filter: (id < 15000) +(21 rows) + +-- 4. Multi level range +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_multi; + QUERY PLAN +---------------------------------------------------------- + Append + -> Seq Scan on hypo_part_multi hypo_part_multi_1_q1_a + -> Seq Scan on hypo_part_multi hypo_part_multi_1_q1_b + -> Seq Scan on hypo_part_multi hypo_part_multi_1_q2 + -> Seq Scan on hypo_part_multi hypo_part_multi_1_q3 + -> Seq Scan on hypo_part_multi hypo_part_multi_1_q4 + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q1 + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q2 + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q3 + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q4 + -> Seq Scan on hypo_part_multi hypo_part_multi_3_q1 + -> Seq Scan on hypo_part_multi hypo_part_multi_3_q2 + -> Seq Scan on hypo_part_multi hypo_part_multi_3_q3 + -> Seq Scan on hypo_part_multi hypo_part_multi_3_q4 +(14 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_multi WHERE dpt = 2; + QUERY PLAN +-------------------------------------------------------- + Append + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q1 + Filter: (dpt = 2) + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q2 + Filter: (dpt = 2) + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q3 + Filter: (dpt = 2) + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q4 + Filter: (dpt = 2) +(9 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_multi WHERE dt >= '2015-01-05' AND dt < '2015-01-10'; + QUERY PLAN +---------------------------------------------------------------------------- + Append + -> Seq Scan on hypo_part_multi hypo_part_multi_1_q1_a + Filter: ((dt >= '01-05-2015'::date) AND (dt < '01-10-2015'::date)) + -> Seq Scan on hypo_part_multi hypo_part_multi_2_q1 + Filter: ((dt >= '01-05-2015'::date) AND (dt < '01-10-2015'::date)) + -> Seq Scan on hypo_part_multi hypo_part_multi_3_q1 + Filter: ((dt >= '01-05-2015'::date) AND (dt < '01-10-2015'::date)) +(7 rows) + diff --git a/test/sql/hypopg.sql b/test/sql/hypo_index.sql similarity index 90% rename from test/sql/hypopg.sql rename to test/sql/hypo_index.sql index 3aac4af..63550ee 100644 --- a/test/sql/hypopg.sql +++ b/test/sql/hypo_index.sql @@ -1,18 +1,4 @@ --- SETUP -CREATE OR REPLACE FUNCTION do_explain(stmt text) RETURNS table(a text) AS -$_$ -DECLARE - ret text; -BEGIN - FOR ret IN EXECUTE format('EXPLAIN (FORMAT text) %s', stmt) LOOP - a := ret; - RETURN next ; - END LOOP; -END; -$_$ -LANGUAGE plpgsql; - -CREATE EXTENSION hypopg; +-- Hypothetical index tests CREATE TABLE hypo (id integer, val text); diff --git a/test/sql/hypo_setup.sql b/test/sql/hypo_setup.sql new file mode 100644 index 0000000..a4d55c8 --- /dev/null +++ b/test/sql/hypo_setup.sql @@ -0,0 +1,18 @@ +-- General setup + +-- Create extension +CREATE EXTENSION hypopg; + +-- Create do_explain function +CREATE OR REPLACE FUNCTION do_explain(stmt text) RETURNS table(a text) AS +$_$ +DECLARE + ret text; +BEGIN + FOR ret IN EXECUTE format('EXPLAIN (FORMAT text) %s', stmt) LOOP + a := ret; + RETURN next ; + END LOOP; +END; +$_$ +LANGUAGE plpgsql; diff --git a/test/sql/hypo_table.sql b/test/sql/hypo_table.sql new file mode 100644 index 0000000..f3a3264 --- /dev/null +++ b/test/sql/hypo_table.sql @@ -0,0 +1,172 @@ +-- Creating real and hypothetical tables" +-- =====================================" + +-- Real tables +-- ----------- +-- 1. Range partition +DROP TABLE IF EXISTS part_range; +CREATE TABLE part_range (id integer, val text) PARTITION BY RANGE (id); +CREATE TABLE part_range_1_10000 PARTITION OF part_range FOR VALUES FROM (1) TO (10000); +CREATE TABLE part_range_10000_20000 PARTITION OF part_range FOR VALUES FROM (10000) TO (20000); +CREATE TABLE part_range_20000_30000 PARTITION OF part_range FOR VALUES FROM (20000) TO (30000); +INSERT INTO part_range SELECT i, 'line ' || i FROM generate_series(1, 29999) i; +-- 2. List partitioning +DROP TABLE IF EXISTS part_list; +CREATE TABLE part_list (id integer, id_key integer, val text) PARTITION BY LIST (id_key); +CREATE TABLE part_list_1_2_3 PARTITION OF part_list FOR VALUES IN (1, 2, 3); +CREATE TABLE part_list_4_5_6_8_10 PARTITION OF part_list FOR VALUES IN (4, 5, 6, 8, 10); +CREATE TABLE part_list_7_9 PARTITION OF part_list FOR VALUES IN (7, 9); +INSERT INTO part_list SELECT i, (i % 9) + 1, 'line ' || i FROM generate_series(1, 50000) i; +-- 3. Hash partitioning +DROP TABLE IF EXISTS part_hash; +CREATE TABLE part_hash (id integer, val text) PARTITION BY HASH (id); +CREATE TABLE part_hash_0 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 0); +CREATE TABLE part_hash_1 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 1); +CREATE TABLE part_hash_2 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 2); +CREATE TABLE part_hash_3 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 3); +CREATE TABLE part_hash_4 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 4); +CREATE TABLE part_hash_5 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 5); +CREATE TABLE part_hash_6 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 6); +CREATE TABLE part_hash_7 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 7); +CREATE TABLE part_hash_8 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 8); +CREATE TABLE part_hash_9 PARTITION OF part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 9); +INSERT INTO part_hash SELECT i, 'line ' || i FROM generate_series(1, 90000) i; +-- 4. Multi level range +DROP TABLE IF EXISTS part_multi; +CREATE TABLE part_multi(dpt smallint, dt date, val text) PARTITION BY LIST (dpt); +CREATE TABLE part_multi_1 PARTITION OF part_multi FOR VALUES IN (1) PARTITION BY RANGE(dt); +CREATE TABLE part_multi_1_q1 PARTITION OF part_multi_1 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$) PARTITION BY RANGE (dt); +CREATE TABLE part_multi_1_q1_a PARTITION OF part_multi_1_q1 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-02-01$$); +CREATE TABLE part_multi_1_q1_b PARTITION OF part_multi_1_q1 FOR VALUES FROM ($$2015-02-01$$) TO ($$2015-04-01$$); +CREATE TABLE part_multi_1_q2 PARTITION OF part_multi_1 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$); +CREATE TABLE part_multi_1_q3 PARTITION OF part_multi_1 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$); +CREATE TABLE part_multi_1_q4 PARTITION OF part_multi_1 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$); +CREATE TABLE part_multi_2 PARTITION OF part_multi FOR VALUES IN (2) PARTITION BY RANGE(dt); +CREATE TABLE part_multi_2_q1 PARTITION OF part_multi_2 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$); +CREATE TABLE part_multi_2_q2 PARTITION OF part_multi_2 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$); +CREATE TABLE part_multi_2_q3 PARTITION OF part_multi_2 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$); +CREATE TABLE part_multi_2_q4 PARTITION OF part_multi_2 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$); +CREATE TABLE part_multi_3 PARTITION OF part_multi FOR VALUES IN (3) PARTITION BY RANGE(dt); +CREATE TABLE part_multi_3_q1 PARTITION OF part_multi_3 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$); +CREATE TABLE part_multi_3_q2 PARTITION OF part_multi_3 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$); +CREATE TABLE part_multi_3_q3 PARTITION OF part_multi_3 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$); +CREATE TABLE part_multi_3_q4 PARTITION OF part_multi_3 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$); +INSERT INTO part_multi select (i%3)+1, '2015-01-01'::date + interval '1 day' * (i%365), 'val ' || i FROM generate_series(1,10000) i; + +-- Hypothetical tables +-- ------------------- +-- 0. Dropping any hypothetical object +SELECT * FROM hypopg_reset_index(); +SELECT * FROM hypopg_reset_table(); +-- 1. Range partition +DROP TABLE IF EXISTS hypo_part_range; +CREATE TABLE hypo_part_range (id integer, val text); +INSERT INTO hypo_part_range SELECT i, 'line ' || i FROM generate_series(1, 29999) i; +SELECT * FROM hypopg_partition_table('hypo_part_range', 'PARTITION BY RANGE (id)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_range_1_10000', 'PARTITION OF hypo_part_range FOR VALUES FROM (1) TO (10000)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_range_10000_20000', 'PARTITION OF hypo_part_range FOR VALUES FROM (10000) TO (20000)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_range_20000_30000', 'PARTITION OF hypo_part_range FOR VALUES FROM (20000) TO (30000)'); +-- 2. List partitioning +DROP TABLE IF EXISTS hypo_part_list; +CREATE TABLE hypo_part_list (id integer, id_key integer, val text); +INSERT INTO hypo_part_list SELECT i, (i % 9) + 1, 'line ' || i FROM generate_series(1, 50000) i; +SELECT * FROM hypopg_partition_table('hypo_part_list', 'PARTITION BY LIST (id_key)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_list_1_2_3', 'PARTITION OF hypo_part_list FOR VALUES IN (1, 2, 3)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_list_4_5_6_8_10', 'PARTITION OF hypo_part_list FOR VALUES IN (4, 5, 6, 8, 10)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_list_7_9', 'PARTITION OF hypo_part_list FOR VALUES IN (7, 9)'); +-- 3. Hash partitioning +DROP TABLE IF EXISTS hypo_part_hash; +CREATE TABLE hypo_part_hash (id integer, val text); +INSERT INTO hypo_part_hash SELECT i, 'line ' || i FROM generate_series(1, 90000) i; +SELECT * FROM hypopg_partition_table('hypo_part_hash', 'PARTITION BY HASH (id)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_0', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 0)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_1', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 1)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_2', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 2)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_3', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 3)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_4', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 4)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_5', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 5)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_6', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 6)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_7', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 7)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_8', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 8)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_hash_9', 'PARTITION OF hypo_part_hash FOR VALUES WITH (MODULUS 10, REMAINDER 9)'); +-- 4. Multi level range +DROP TABLE IF EXISTS hypo_part_multi; +CREATE TABLE hypo_part_multi(dpt smallint, dt date, val text); +INSERT INTO hypo_part_multi select (i%3)+1, '2015-01-01'::date + interval '1 day' * (i%365), 'val ' || i FROM generate_series(1,10000) i; +SELECT * FROM hypopg_partition_table('hypo_part_multi', 'PARTITION BY LIST (dpt)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1', 'PARTITION OF hypo_part_multi FOR VALUES IN (1)', 'PARTITION BY RANGE(dt)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q1', 'PARTITION OF hypo_part_multi_1 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$)','PARTITION BY RANGE (dt)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q1_a', 'PARTITION OF hypo_part_multi_1_q1 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-02-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q1_b', 'PARTITION OF hypo_part_multi_1_q1 FOR VALUES FROM ($$2015-02-01$$) TO ($$2015-04-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q2', 'PARTITION OF hypo_part_multi_1 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q3', 'PARTITION OF hypo_part_multi_1 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_1_q4', 'PARTITION OF hypo_part_multi_1 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2', 'PARTITION OF hypo_part_multi FOR VALUES IN (2)', 'PARTITION BY RANGE(dt)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2_q1', 'PARTITION OF hypo_part_multi_2 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2_q2', 'PARTITION OF hypo_part_multi_2 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2_q3', 'PARTITION OF hypo_part_multi_2 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_2_q4', 'PARTITION OF hypo_part_multi_2 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3', 'PARTITION OF hypo_part_multi FOR VALUES IN (3)', 'PARTITION BY RANGE(dt)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3_q1', 'PARTITION OF hypo_part_multi_3 FOR VALUES FROM ($$2015-01-01$$) TO ($$2015-04-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3_q2', 'PARTITION OF hypo_part_multi_3 FOR VALUES FROM ($$2015-04-01$$) TO ($$2015-07-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3_q3', 'PARTITION OF hypo_part_multi_3 FOR VALUES FROM ($$2015-07-01$$) TO ($$2015-10-01$$)'); +SELECT tablename FROM hypopg_add_partition('hypo_part_multi_3_q4', 'PARTITION OF hypo_part_multi_3 FOR VALUES FROM ($$2015-10-01$$) TO ($$2016-01-01$$)'); + +-- Maintenance +-- ----------- +VACUUM ANALYZE; + +-- Test deparsing +-- ============== +SELECT relid = rootid AS is_root, tablename, parentid IS NULL parentid_is_null, + parentid IS NOT NULL AS parentid_is_not_null, + partition_by_clause, partition_bounds +FROM hypopg_table(); + +-- Test hypothetical partitioning behavior +-- ======================================= + +-- Simple queries +-- -------------- + +-- Real tables +-- ----------- +-- 1. Range partition +EXPLAIN (COSTS OFF) SELECT * FROM part_range; +EXPLAIN (COSTS OFF) SELECT * FROM part_range WHERE id = 42; +EXPLAIN (COSTS OFF) SELECT * FROM part_range WHERE id < 15000; +-- 2. List partitioning +EXPLAIN (COSTS OFF) SELECT * FROM part_list; +EXPLAIN (COSTS OFF) SELECT * FROM part_list WHERE id < 42; +EXPLAIN (COSTS OFF) SELECT * FROM part_list WHERE id < 15000; +EXPLAIN (COSTS OFF) SELECT * FROM part_list WHERE id_key < 5; +EXPLAIN (COSTS OFF) SELECT * FROM part_list WHERE id_key = 7; +-- 3. Hash partitioning +EXPLAIN (COSTS OFF) SELECT * FROM part_hash; +EXPLAIN (COSTS OFF) SELECT * FROM part_hash WHERE id = 42; +EXPLAIN (COSTS OFF) SELECT * FROM part_hash WHERE id < 15000; +-- 4. Multi level range +EXPLAIN (COSTS OFF) SELECT * FROM part_multi; +EXPLAIN (COSTS OFF) SELECT * FROM part_multi WHERE dpt = 2; +EXPLAIN (COSTS OFF) SELECT * FROM part_multi WHERE dt >= '2015-01-05' AND dt < '2015-01-10'; + +-- Hypothetical tables +-- ------------------" +-- 1. Range partition +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_range; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_range WHERE id = 42; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_range WHERE id < 15000; +-- 2. List partitioning +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list WHERE id < 42; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list WHERE id < 15000; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list WHERE id_key < 5; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_list WHERE id_key = 7; +-- 3. Hash partitioning +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_hash; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_hash WHERE id = 42; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_hash WHERE id < 15000; +-- 4. Multi level range +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_multi; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_multi WHERE dpt = 2; +EXPLAIN (COSTS OFF) SELECT * FROM hypo_part_multi WHERE dt >= '2015-01-05' AND dt < '2015-01-10';