diff --git a/src/backend/access/common/reloptions_gp.c b/src/backend/access/common/reloptions_gp.c index c15afa0b60c..35025cba92b 100644 --- a/src/backend/access/common/reloptions_gp.c +++ b/src/backend/access/common/reloptions_gp.c @@ -1635,6 +1635,10 @@ find_crsd(const char *column, List *stenc) * 'colDefs' - list of ColumnDefs * 'stenc' - list of ColumnReferenceStorageDirectives * 'withOptions' - list of WITH options + * 'parentenc' - list of ColumnReferenceStorageDirectives explicitly defined for + * parent partition + * 'explicitOnly' - Only return explicitly defined column encoding values + * to be used for child partitions * * ENCODING options can be attached to column definitions, like * "mycolumn integer ENCODING ..."; these go into ColumnDefs. They diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 7169ff4cfa8..08cc10590de 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1129,15 +1129,17 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, * legitimately error out, it is prefered to call it before updating the * catalog in heap_create_with_catalog(). * - * For RELKIND_PARTITIONED_TABLE, let the transformation of attribute - * encoding happen. We don't store it for parent partition in - * pg_attribute_encoding table. Transformed encoding will be used to - * create child partition create stmts, hence avoid marking it NIL as - * well. + * For RELKIND_PARTITIONED_TABLE, we will create a list of encodings + * for the root partition to add to pg_attribute_encoding which includes + * explicitly specified column encodings and values picked from defaults + * We will also transform the stmt->attr_encodings to be passed down to + * create child partition create stmts which would only include explicitly + * specified column encodings from the current root partition * * This is done in dispatcher (and in utility mode). In QE, we receive * the already-processed options from the QD. */ + if ((relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW || relkind == RELKIND_DIRECTORY_TABLE || (relkind == RELKIND_PARTITIONED_TABLE && OidIsValid(accessMethodId))) && @@ -1336,7 +1338,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, cooked_constraints = list_concat(cooked_constraints, newCookedDefaults); } - if (relkind == RELKIND_PARTITIONED_TABLE && rel->rd_rel->relam == AO_COLUMN_TABLE_AM_OID) + if (relkind == RELKIND_PARTITIONED_TABLE && RelationIsAoCols(rel)) { const TableAmRoutine *tam = GetTableAmRoutineByAmId(rel->rd_rel->relam); List *part_attr_encodings = @@ -1349,11 +1351,11 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, false, accessMethodId != AO_COLUMN_TABLE_AM_OID && !stmt->partbound && !stmt->partspec - /* errorOnEncodingClause */, true); + /* errorOnEncodingClause */, true /* appendonly */); AddRelationAttributeEncodings(rel, part_attr_encodings); } - else if (stmt->attr_encodings && (relkind != RELKIND_PARTITIONED_TABLE)) + else if (stmt->attr_encodings && RelationIsAoCols(rel)) AddRelationAttributeEncodings(rel, stmt->attr_encodings); /* diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 3b411103c19..a418b16dd91 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -317,4 +317,5 @@ extern List *build_ao_rel_storage_opts(List *opts, Relation rel); extern relopt_value * parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts); + #endif /* RELOPTIONS_H */ diff --git a/src/test/regress/expected/alter_table_set.out b/src/test/regress/expected/alter_table_set.out index ca4b4bece8d..e97e503ee1d 100644 --- a/src/test/regress/expected/alter_table_set.out +++ b/src/test/regress/expected/alter_table_set.out @@ -52,3 +52,246 @@ select count(*) > 0 as has_different_distribution from t (1 row) +-- ALTER TABLE ... SET for partition tables +CREATE TABLE part_relopt(a int, b int) WITH (fillfactor=90) PARTITION BY RANGE(a); +CREATE TABLE part_relopt_1 partition OF part_relopt FOR VALUES FROM (1) to (100); +CREATE TABLE part_relopt_2 partition OF part_relopt FOR VALUES FROM (100) to (200) PARTITION BY RANGE(a); +CREATE TABLE part_relopt_2_1 partition OF part_relopt_2 FOR VALUES FROM (100) to (150); +CREATE TABLE part_relopt_2_2 partition OF part_relopt_2 FOR VALUES FROM (150) to (200); +INSERT INTO part_relopt SELECT i,i FROM generate_series(1,199) i; +-- All tables inherit the same reloptions as the root. +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions +-----------------+----------------- + part_relopt | {fillfactor=90} + part_relopt_1 | {fillfactor=90} + part_relopt_2 | {fillfactor=90} + part_relopt_2_1 | {fillfactor=90} + part_relopt_2_2 | {fillfactor=90} +(5 rows) + +-- Set reloptions of the root, all child including subpartitions should inherit them too. +ALTER TABLE part_relopt SET (fillfactor=80); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions +-----------------+----------------- + part_relopt | {fillfactor=80} + part_relopt_1 | {fillfactor=80} + part_relopt_2 | {fillfactor=80} + part_relopt_2_1 | {fillfactor=80} + part_relopt_2_2 | {fillfactor=80} +(5 rows) + +-- Altering it again with the same reloptions. Nothing should change. +ALTER TABLE part_relopt SET (fillfactor=80); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions +-----------------+----------------- + part_relopt | {fillfactor=80} + part_relopt_1 | {fillfactor=80} + part_relopt_2 | {fillfactor=80} + part_relopt_2_1 | {fillfactor=80} + part_relopt_2_2 | {fillfactor=80} +(5 rows) + +-- Altering a subpartition root, should apply and only apply to the subpartition root/child. +ALTER TABLE part_relopt_2 SET (fillfactor=70); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions +-----------------+----------------- + part_relopt | {fillfactor=80} + part_relopt_1 | {fillfactor=80} + part_relopt_2 | {fillfactor=70} + part_relopt_2_1 | {fillfactor=70} + part_relopt_2_2 | {fillfactor=70} +(5 rows) + +-- Altering the partition root but with ONLY keyword. Should affect future child but not affect existing child. +ALTER TABLE ONLY part_relopt SET (fillfactor=60); +CREATE TABLE part_relopt_3 partition OF part_relopt FOR VALUES FROM (200) to (300); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions +-----------------+----------------- + part_relopt | {fillfactor=60} + part_relopt_1 | {fillfactor=80} + part_relopt_2 | {fillfactor=70} + part_relopt_2_1 | {fillfactor=70} + part_relopt_2_2 | {fillfactor=70} + part_relopt_3 | {fillfactor=60} +(6 rows) + +-- Altering one child partition, should only affect that child. +ALTER TABLE part_relopt_1 SET (fillfactor=50); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions +-----------------+----------------- + part_relopt | {fillfactor=60} + part_relopt_1 | {fillfactor=50} + part_relopt_2 | {fillfactor=70} + part_relopt_2_1 | {fillfactor=70} + part_relopt_2_2 | {fillfactor=70} + part_relopt_3 | {fillfactor=60} +(6 rows) + +-- RESET one subpartition, then the entire hierarchy +ALTER TABLE part_relopt_2 RESET(fillfactor); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions +-----------------+----------------- + part_relopt | {fillfactor=60} + part_relopt_1 | {fillfactor=50} + part_relopt_2 | + part_relopt_2_1 | + part_relopt_2_2 | + part_relopt_3 | {fillfactor=60} +(6 rows) + +ALTER TABLE part_relopt RESET(fillfactor); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions +-----------------+------------ + part_relopt | + part_relopt_1 | + part_relopt_2 | + part_relopt_2_1 | + part_relopt_2_2 | + part_relopt_3 | +(6 rows) + +-- Check setting reloptions for AO and AOCO tables too. +-- Also, for these tables we check pg_appendonly and pg_attribute_encoding too. +-- AO table: +ALTER TABLE part_relopt SET ACCESS METHOD ao_row WITH (compresstype=zlib, compresslevel=5); +SELECT c.relname, c.reloptions, a.blocksize, a.compresslevel FROM pg_class c LEFT JOIN pg_appendonly a ON a.relid = c.oid WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions | blocksize | compresslevel +-----------------+-------------------------------------+-----------+--------------- + part_relopt | {compresstype=zlib,compresslevel=5} | | + part_relopt_1 | {compresstype=zlib,compresslevel=5} | 32768 | 5 + part_relopt_2 | {compresstype=zlib,compresslevel=5} | | + part_relopt_2_1 | {compresstype=zlib,compresslevel=5} | 32768 | 5 + part_relopt_2_2 | {compresstype=zlib,compresslevel=5} | 32768 | 5 + part_relopt_3 | {compresstype=zlib,compresslevel=5} | 32768 | 5 +(6 rows) + +ALTER TABLE part_relopt SET (compresslevel=7); +SELECT c.relname, c.reloptions, a.blocksize, a.compresslevel FROM pg_class c LEFT JOIN pg_appendonly a ON a.relid = c.oid WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions | blocksize | compresslevel +-----------------+-------------------------------------+-----------+--------------- + part_relopt | {compresstype=zlib,compresslevel=7} | | + part_relopt_1 | {compresstype=zlib,compresslevel=7} | 32768 | 7 + part_relopt_2 | {compresstype=zlib,compresslevel=7} | | + part_relopt_2_1 | {compresstype=zlib,compresslevel=7} | 32768 | 7 + part_relopt_2_2 | {compresstype=zlib,compresslevel=7} | 32768 | 7 + part_relopt_3 | {compresstype=zlib,compresslevel=7} | 32768 | 7 +(6 rows) + +--AOCO table: +ALTER TABLE part_relopt SET ACCESS METHOD ao_column WITH (compresstype=rle_type, compresslevel=1); +SELECT c.relname, c.reloptions, a.blocksize, a.compresslevel FROM pg_class c LEFT JOIN pg_appendonly a ON a.relid = c.oid WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions | blocksize | compresslevel +-----------------+-----------------------------------------+-----------+--------------- + part_relopt | {compresstype=rle_type,compresslevel=1} | | + part_relopt_1 | {compresstype=rle_type,compresslevel=1} | 32768 | 1 + part_relopt_2 | {compresstype=rle_type,compresslevel=1} | | + part_relopt_2_1 | {compresstype=rle_type,compresslevel=1} | 32768 | 1 + part_relopt_2_2 | {compresstype=rle_type,compresslevel=1} | 32768 | 1 + part_relopt_3 | {compresstype=rle_type,compresslevel=1} | 32768 | 1 +(6 rows) + +SELECT c.relname, a.attnum, a.attoptions FROM pg_attribute_encoding a, pg_class c WHERE a.attrelid = c.oid AND c.relname LIKE 'part_relopt%'; + relname | attnum | attoptions +-----------------+--------+--------------------------------------------------------- + part_relopt | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_1 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2_1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2_1 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2_2 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2_2 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_3 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_3 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} +(12 rows) + +ALTER TABLE part_relopt SET (compresslevel=3); +SELECT c.relname, c.reloptions, a.blocksize, a.compresslevel FROM pg_class c LEFT JOIN pg_appendonly a ON a.relid = c.oid WHERE c.relname LIKE 'part_relopt%'; + relname | reloptions | blocksize | compresslevel +-----------------+-----------------------------------------+-----------+--------------- + part_relopt | {compresstype=rle_type,compresslevel=3} | | + part_relopt_1 | {compresstype=rle_type,compresslevel=3} | 32768 | 3 + part_relopt_2 | {compresstype=rle_type,compresslevel=3} | | + part_relopt_2_1 | {compresstype=rle_type,compresslevel=3} | 32768 | 3 + part_relopt_2_2 | {compresstype=rle_type,compresslevel=3} | 32768 | 3 + part_relopt_3 | {compresstype=rle_type,compresslevel=3} | 32768 | 3 +(6 rows) + +SELECT c.relname, a.attnum, a.attoptions FROM pg_attribute_encoding a, pg_class c WHERE a.attrelid = c.oid AND c.relname LIKE 'part_relopt%'; + relname | attnum | attoptions +-----------------+--------+--------------------------------------------------------- + part_relopt | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_1 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2_1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2_1 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2_2 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_2_2 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_3 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + part_relopt_3 | 1 | {compresstype=rle_type,compresslevel=1,blocksize=32768} +(12 rows) + +-- Check mixed AMs in the partition hierarchy. Currently we error out. +CREATE TABLE part_relopt2(a int, b int) PARTITION BY RANGE(a); +CREATE TABLE part_1 partition OF part_relopt2 FOR VALUES FROM (100) to (200); +CREATE TABLE part_2 partition OF part_relopt2 FOR VALUES FROM (200) to (300) PARTITION BY RANGE (a); +CREATE TABLE part_2_1 partition OF part_2 FOR VALUES FROM (200) to (250); +-- error out because of the first child +ALTER TABLE part_1 SET ACCESS METHOD ao_row; +ALTER TABLE part_relopt2 SET (fillfactor=70); +ERROR: cannot alter reloptions for "part_relopt2" because one of the child tables "part_1" has different access method +HINT: Alter tables individually or change the child's AM to be same as parent. +-- check subpartition too: error out because of the subpartition child +ALTER TABLE part_1 SET ACCESS METHOD heap; +ALTER TABLE part_2_1 SET ACCESS METHOD ao_row; +ALTER TABLE part_relopt2 SET (fillfactor=70); +ERROR: cannot alter reloptions for "part_relopt2" because one of the child tables "part_2_1" has different access method +HINT: Alter tables individually or change the child's AM to be same as parent. +-- SET individual child, and check if RESET works. +ALTER TABLE part_1 SET (fillfactor=70); +ALTER TABLE part_2_1 SET (blocksize=65536); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname = 'part_1' OR c.relname = 'part_2_1'; + relname | reloptions +----------+------------------- + part_2_1 | {blocksize=65536} + part_1 | {fillfactor=70} +(2 rows) + +ALTER TABLE part_relopt2 RESET(fillfactor); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname = 'part_1' OR c.relname = 'part_2_1'; + relname | reloptions +----------+------------------- + part_2_1 | {blocksize=65536} + part_1 | +(2 rows) + +ALTER TABLE part_relopt2 RESET(blocksize); +SELECT c.relname, c.reloptions FROM pg_class c WHERE c.relname = 'part_1' OR c.relname = 'part_2_1'; + relname | reloptions +----------+------------ + part_2_1 | + part_1 | +(2 rows) + +-- Data is intact +SELECT count(*) FROM part_relopt; + count +------- + 199 +(1 row) + +DROP TABLE part_relopt; +DROP TABLE part_relopt2; diff --git a/src/test/regress/expected/column_compression.out b/src/test/regress/expected/column_compression.out index 53624540ffd..d61b03a32bf 100644 --- a/src/test/regress/expected/column_compression.out +++ b/src/test/regress/expected/column_compression.out @@ -765,6 +765,12 @@ execute ccddlcheck; ccddl_1_prt_p2_2_prt_sp1 | l | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} (20 rows) +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'ccddl'::regclass; + level | pg_get_expr +-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(SUBPARTITION sp1 VALUES (1, 2, 3, 4, 5), COLUMN i ENCODING (compresstype=zlib), COLUMN j ENCODING (compresstype=rle_type), COLUMN k ENCODING (compresstype=zlib), COLUMN l ENCODING (compresstype=zlib)) +(1 row) + insert into ccddl select 1, (i % 19) + 1, ((i+3) % 5) + 1, i+3 from generate_series(1, 100) i; select * from ccddl; i | j | k | l @@ -1227,6 +1233,12 @@ execute ccddlcheck; ccddl_1_prt_p1_2_prt_sp1 | j | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} (6 rows) +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'ccddl'::regclass; + level | pg_get_expr +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(SUBPARTITION sp1 START (1::integer) END (20::integer), COLUMN i ENCODING (compresstype=zlib), COLUMN j ENCODING (compresstype=rle_type)) +(1 row) + alter table ccddl alter partition p1 split partition sp1 at (10) into (partition sp2, partition sp3); execute ccddlcheck; relname | attname | filenum | attoptions @@ -1303,6 +1315,12 @@ execute ccddlcheck; ccddl_1_prt_1_2_prt_1_3_prt_usa | day | 4 | {compresstype=none,compresslevel=0,blocksize=32768} ccddl_1_prt_1_2_prt_1_3_prt_usa | region | 5 | {compresstype=rle_type,compresslevel=1,blocksize=32768} (20 rows) +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'ccddl'::regclass; + level | pg_get_expr +-------+------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE( START (1::integer) END (13::integer), COLUMN month ENCODING (compresstype=rle_type)) + 2 | SUBPARTITION TEMPLATE(SUBPARTITION usa VALUES ('usa'), COLUMN region ENCODING (compresstype=rle_type)) +(2 rows) -- Ensure we can read and write insert into ccddl select 1, 2008, 1, 2, 'usa' from generate_series(1, 100); @@ -1500,6 +1518,67 @@ execute ccddlcheck; ccddl_1_prt_p2_2_prt_sp1 | l | 4 | {compresstype=rle_type,compresslevel=1,blocksize=32768} (20 rows) +drop table ccddl; +-- multi level partitioning with column encoding inheritance +create table ccddl (a int ENCODING (compresslevel=1), + b int ENCODING (compresslevel=1), + c int ENCODING (compresslevel=1), + d int ENCODING (compresslevel=1), + e int, f int, g int, h int) + with (appendonly = true, orientation=column, compresslevel=5) + partition by range(a) subpartition by range(b) + (partition p1 start(1) end(10) + (subpartition sp1 start(1) end(5) + column a encoding(compresslevel=3), + column d encoding(compresslevel=3), + column f encoding(compresslevel=3), + column g encoding(compresslevel=3)), + column a encoding(compresslevel=2), + column b encoding(compresslevel=2), + column e encoding(compresslevel=2), + column g encoding(compresslevel=2)); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +execute ccddlcheck; + relname | attname | attoptions +--------------------------+---------+----------------------------------------------------- + ccddl | a | {compresslevel=1,compresstype=zlib,blocksize=32768} + ccddl | b | {compresslevel=1,compresstype=zlib,blocksize=32768} + ccddl | c | {compresslevel=1,compresstype=zlib,blocksize=32768} + ccddl | d | {compresslevel=1,compresstype=zlib,blocksize=32768} + ccddl | e | {compresslevel=5,compresstype=zlib,blocksize=32768} + ccddl | f | {compresslevel=5,compresstype=zlib,blocksize=32768} + ccddl | g | {compresslevel=5,compresstype=zlib,blocksize=32768} + ccddl | h | {compresslevel=5,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1 | a | {compresslevel=2,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1 | b | {compresslevel=2,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1 | c | {compresslevel=1,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1 | d | {compresslevel=1,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1 | e | {compresslevel=2,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1 | f | {compresslevel=5,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1 | g | {compresslevel=2,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1 | h | {compresslevel=5,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1_2_prt_sp1 | a | {compresslevel=3,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1_2_prt_sp1 | b | {compresslevel=2,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1_2_prt_sp1 | c | {compresslevel=1,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1_2_prt_sp1 | d | {compresslevel=3,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1_2_prt_sp1 | e | {compresslevel=2,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1_2_prt_sp1 | f | {compresslevel=3,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1_2_prt_sp1 | g | {compresslevel=3,compresstype=zlib,blocksize=32768} + ccddl_1_prt_p1_2_prt_sp1 | h | {compresslevel=5,compresstype=zlib,blocksize=32768} +(24 rows) + +insert into ccddl select 2,3 from generate_series(1, 100); +select * from ccddl limit 5; + a | b | c | d | e | f | g | h +---+---+---+---+---+---+---+--- + 2 | 3 | | | | | | + 2 | 3 | | | | | | + 2 | 3 | | | | | | + 2 | 3 | | | | | | + 2 | 3 | | | | | | +(5 rows) + drop table ccddl; -- Precedence test: c3 in the partition child must be zlib, not RLE_TYPE CREATE TABLE ccddl ( c1 int ENCODING (compresstype=zlib), @@ -1624,6 +1703,12 @@ execute ccddlcheck; ccddl_1_prt_newp_2_prt_sp1 | j | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} (33 rows) +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'ccddl'::regclass; + level | pg_get_expr +-------+------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(SUBPARTITION sp1 VALUES (1), DEFAULT COLUMN ENCODING (compresstype=zlib)) +(1 row) + drop table ccddl; ----------------------------------------------------------------------- -- Partitioning support diff --git a/src/test/regress/expected/gp_partition_template.out b/src/test/regress/expected/gp_partition_template.out new file mode 100644 index 00000000000..02aff5c3f0e --- /dev/null +++ b/src/test/regress/expected/gp_partition_template.out @@ -0,0 +1,889 @@ +-- Test GPDB specific partitioning parser for subpartition template +-- Subpartition by RANGE +CREATE TABLE subpart_range_templ (id int, year date, letter char(1)) + DISTRIBUTED BY (id, letter, year) + PARTITION BY list (letter) + subpartition by range (year) + SUBPARTITION TEMPLATE ( + subpartition r1 START (date '2001-01-01') END (date '2003-01-01'), + subpartition r2 START (date '2003-01-01') END (date '2005-01-01') EVERY (interval '1 year'), + DEFAULT SUBPARTITION other_year ) + ( + PARTITION a VALUES ('A'), + PARTITION b VALUES ('B'), + DEFAULT PARTITION other_letter + ); +-- Subpartition template should be stored in catalog +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_templ'::regclass; + level | pg_get_expr +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION other_year, SUBPARTITION r1 START ('01-01-2001'::date) END ('01-01-2003'::date), SUBPARTITION r2 START ('01-01-2003'::date) END ('01-01-2005'::date) Every ('@ 1 year'::interval)) +(1 row) + +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +---------------------------------------------------------+----------------------------------------+--------+-------+-------------------------------------------------- + subpart_range_templ | | f | 0 | + subpart_range_templ_1_prt_other_letter | subpart_range_templ | f | 1 | DEFAULT + subpart_range_templ_1_prt_a | subpart_range_templ | f | 1 | FOR VALUES IN ('A') + subpart_range_templ_1_prt_b | subpart_range_templ | f | 1 | FOR VALUES IN ('B') + subpart_range_templ_1_prt_other_letter_2_prt_other_year | subpart_range_templ_1_prt_other_letter | t | 2 | DEFAULT + subpart_range_templ_1_prt_other_letter_2_prt_r1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_other_letter_2_prt_r2_1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_other_letter_2_prt_r2_2 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_a_2_prt_other_year | subpart_range_templ_1_prt_a | t | 2 | DEFAULT + subpart_range_templ_1_prt_a_2_prt_r1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_a_2_prt_r2_1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_a_2_prt_r2_2 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_b_2_prt_other_year | subpart_range_templ_1_prt_b | t | 2 | DEFAULT + subpart_range_templ_1_prt_b_2_prt_r1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_b_2_prt_r2_1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_b_2_prt_r2_2 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') +(16 rows) + +-- ADD PARTITION should create subpartitions +ALTER TABLE subpart_range_templ ADD PARTITION c VALUES ('C'); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +---------------------------------------------------------+----------------------------------------+--------+-------+-------------------------------------------------- + subpart_range_templ | | f | 0 | + subpart_range_templ_1_prt_other_letter | subpart_range_templ | f | 1 | DEFAULT + subpart_range_templ_1_prt_a | subpart_range_templ | f | 1 | FOR VALUES IN ('A') + subpart_range_templ_1_prt_b | subpart_range_templ | f | 1 | FOR VALUES IN ('B') + subpart_range_templ_1_prt_other_letter_2_prt_other_year | subpart_range_templ_1_prt_other_letter | t | 2 | DEFAULT + subpart_range_templ_1_prt_other_letter_2_prt_r1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_other_letter_2_prt_r2_1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_other_letter_2_prt_r2_2 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_a_2_prt_other_year | subpart_range_templ_1_prt_a | t | 2 | DEFAULT + subpart_range_templ_1_prt_a_2_prt_r1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_a_2_prt_r2_1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_a_2_prt_r2_2 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_b_2_prt_other_year | subpart_range_templ_1_prt_b | t | 2 | DEFAULT + subpart_range_templ_1_prt_b_2_prt_r1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_b_2_prt_r2_1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_b_2_prt_r2_2 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_c | subpart_range_templ | f | 1 | FOR VALUES IN ('C') + subpart_range_templ_1_prt_c_2_prt_other_year | subpart_range_templ_1_prt_c | t | 2 | DEFAULT + subpart_range_templ_1_prt_c_2_prt_r1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_c_2_prt_r2_1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_c_2_prt_r2_2 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') +(21 rows) + +-- ADD PARTITION with subpartition definition spec should fail +ALTER TABLE subpart_range_templ ADD PARTITION d VALUES ('D') (SUBPARTITION r3 START (date '2003-01-01') END (date '2005-01-01')); +ERROR: subpartition configuration conflicts with subpartition template +LINE 1: ...subpart_range_templ ADD PARTITION d VALUES ('D') (SUBPARTITI... + ^ +-- Remove subpartition template +ALTER TABLE subpart_range_templ SET SUBPARTITION TEMPLATE(); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_templ'::regclass; + level | pg_get_expr +-------+------------- +(0 rows) + +-- ADD PARTITION with subpartition definition spec now should work +ALTER TABLE subpart_range_templ ADD PARTITION d VALUES ('D') (SUBPARTITION r3 START (date '2003-01-01') END (date '2005-01-01')); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +---------------------------------------------------------+----------------------------------------+--------+-------+-------------------------------------------------- + subpart_range_templ | | f | 0 | + subpart_range_templ_1_prt_other_letter | subpart_range_templ | f | 1 | DEFAULT + subpart_range_templ_1_prt_a | subpart_range_templ | f | 1 | FOR VALUES IN ('A') + subpart_range_templ_1_prt_b | subpart_range_templ | f | 1 | FOR VALUES IN ('B') + subpart_range_templ_1_prt_other_letter_2_prt_other_year | subpart_range_templ_1_prt_other_letter | t | 2 | DEFAULT + subpart_range_templ_1_prt_other_letter_2_prt_r1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_other_letter_2_prt_r2_1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_other_letter_2_prt_r2_2 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_a_2_prt_other_year | subpart_range_templ_1_prt_a | t | 2 | DEFAULT + subpart_range_templ_1_prt_a_2_prt_r1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_a_2_prt_r2_1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_a_2_prt_r2_2 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_b_2_prt_other_year | subpart_range_templ_1_prt_b | t | 2 | DEFAULT + subpart_range_templ_1_prt_b_2_prt_r1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_b_2_prt_r2_1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_b_2_prt_r2_2 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_c | subpart_range_templ | f | 1 | FOR VALUES IN ('C') + subpart_range_templ_1_prt_c_2_prt_other_year | subpart_range_templ_1_prt_c | t | 2 | DEFAULT + subpart_range_templ_1_prt_c_2_prt_r1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_c_2_prt_r2_1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_c_2_prt_r2_2 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_d | subpart_range_templ | f | 1 | FOR VALUES IN ('D') + subpart_range_templ_1_prt_d_2_prt_r3 | subpart_range_templ_1_prt_d | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2005') +(23 rows) + +-- Set a new invalid subpartition template should fail +ALTER TABLE subpart_range_templ SET SUBPARTITION TEMPLATE +( + subpartition r4 START (date '2020-01-01'), END (date '2021-01-01'), + subpartition r5 START (date '2021-01-01'), END (date '2023-01-01'), + DEFAULT SUBPARTITION yet_another_year +); +ERROR: cannot derive ending value of partition based upon starting of next partition +LINE 3: subpartition r4 START (date '2020-01-01'), END (date '20... + ^ +-- Set a new valid subpartition template +ALTER TABLE subpart_range_templ SET SUBPARTITION TEMPLATE +( + subpartition r4 START (date '2020-01-01') EXCLUSIVE END (date '2021-01-01') INCLUSIVE, + subpartition r5 START (date '2021-01-01') EXCLUSIVE END (date '2023-01-01') INCLUSIVE EVERY (interval '1 year'), + DEFAULT SUBPARTITION yet_another_year +); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_templ'::regclass; + level | pg_get_expr +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION yet_another_year, SUBPARTITION r4 START ('01-02-2020'::date) END ('01-02-2021'::date), SUBPARTITION r5 START ('01-02-2021'::date) END ('01-02-2023'::date) Every ('@ 1 year'::interval)) +(1 row) + +-- ADD PARTITION should create subpartitions according to the new template +ALTER TABLE subpart_range_templ ADD PARTITION e VALUES ('E'); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +---------------------------------------------------------+----------------------------------------+--------+-------+-------------------------------------------------- + subpart_range_templ | | f | 0 | + subpart_range_templ_1_prt_other_letter | subpart_range_templ | f | 1 | DEFAULT + subpart_range_templ_1_prt_a | subpart_range_templ | f | 1 | FOR VALUES IN ('A') + subpart_range_templ_1_prt_b | subpart_range_templ | f | 1 | FOR VALUES IN ('B') + subpart_range_templ_1_prt_other_letter_2_prt_other_year | subpart_range_templ_1_prt_other_letter | t | 2 | DEFAULT + subpart_range_templ_1_prt_other_letter_2_prt_r1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_other_letter_2_prt_r2_1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_other_letter_2_prt_r2_2 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_a_2_prt_other_year | subpart_range_templ_1_prt_a | t | 2 | DEFAULT + subpart_range_templ_1_prt_a_2_prt_r1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_a_2_prt_r2_1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_a_2_prt_r2_2 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_b_2_prt_other_year | subpart_range_templ_1_prt_b | t | 2 | DEFAULT + subpart_range_templ_1_prt_b_2_prt_r1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_b_2_prt_r2_1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_b_2_prt_r2_2 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_c | subpart_range_templ | f | 1 | FOR VALUES IN ('C') + subpart_range_templ_1_prt_c_2_prt_other_year | subpart_range_templ_1_prt_c | t | 2 | DEFAULT + subpart_range_templ_1_prt_c_2_prt_r1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_c_2_prt_r2_1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_c_2_prt_r2_2 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_d | subpart_range_templ | f | 1 | FOR VALUES IN ('D') + subpart_range_templ_1_prt_d_2_prt_r3 | subpart_range_templ_1_prt_d | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2005') + subpart_range_templ_1_prt_e | subpart_range_templ | f | 1 | FOR VALUES IN ('E') + subpart_range_templ_1_prt_e_2_prt_yet_another_year | subpart_range_templ_1_prt_e | t | 2 | DEFAULT + subpart_range_templ_1_prt_e_2_prt_r4 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2020') TO ('01-02-2021') + subpart_range_templ_1_prt_e_2_prt_r5_1 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2021') TO ('01-02-2022') + subpart_range_templ_1_prt_e_2_prt_r5_2 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2022') TO ('01-02-2023') +(28 rows) + +-- Set a new subpartition template w/ WITH clause +ALTER TABLE subpart_range_templ SET SUBPARTITION TEMPLATE + ( + subpartition r4 END (date '2020-01-01') WITH (appendonly=true, compresslevel=5), + DEFAULT SUBPARTITION yet_another_year + ); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_templ'::regclass; + level | pg_get_expr +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION yet_another_year, SUBPARTITION r4 END ('01-01-2020'::date), WITH (appendonly=true, orientation=column, compresslevel=5)) +(1 row) + +ALTER TABLE subpart_range_templ ADD PARTITION f VALUES ('F'); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +---------------------------------------------------------+----------------------------------------+--------+-------+-------------------------------------------------- + subpart_range_templ | | f | 0 | + subpart_range_templ_1_prt_other_letter | subpart_range_templ | f | 1 | DEFAULT + subpart_range_templ_1_prt_a | subpart_range_templ | f | 1 | FOR VALUES IN ('A') + subpart_range_templ_1_prt_b | subpart_range_templ | f | 1 | FOR VALUES IN ('B') + subpart_range_templ_1_prt_other_letter_2_prt_other_year | subpart_range_templ_1_prt_other_letter | t | 2 | DEFAULT + subpart_range_templ_1_prt_other_letter_2_prt_r1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_other_letter_2_prt_r2_1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_other_letter_2_prt_r2_2 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_a_2_prt_other_year | subpart_range_templ_1_prt_a | t | 2 | DEFAULT + subpart_range_templ_1_prt_a_2_prt_r1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_a_2_prt_r2_1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_a_2_prt_r2_2 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_b_2_prt_other_year | subpart_range_templ_1_prt_b | t | 2 | DEFAULT + subpart_range_templ_1_prt_b_2_prt_r1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_b_2_prt_r2_1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_b_2_prt_r2_2 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_c | subpart_range_templ | f | 1 | FOR VALUES IN ('C') + subpart_range_templ_1_prt_c_2_prt_other_year | subpart_range_templ_1_prt_c | t | 2 | DEFAULT + subpart_range_templ_1_prt_c_2_prt_r1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_c_2_prt_r2_1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_c_2_prt_r2_2 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_d | subpart_range_templ | f | 1 | FOR VALUES IN ('D') + subpart_range_templ_1_prt_d_2_prt_r3 | subpart_range_templ_1_prt_d | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2005') + subpart_range_templ_1_prt_e | subpart_range_templ | f | 1 | FOR VALUES IN ('E') + subpart_range_templ_1_prt_e_2_prt_yet_another_year | subpart_range_templ_1_prt_e | t | 2 | DEFAULT + subpart_range_templ_1_prt_e_2_prt_r4 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2020') TO ('01-02-2021') + subpart_range_templ_1_prt_e_2_prt_r5_1 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2021') TO ('01-02-2022') + subpart_range_templ_1_prt_e_2_prt_r5_2 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2022') TO ('01-02-2023') + subpart_range_templ_1_prt_f | subpart_range_templ | f | 1 | FOR VALUES IN ('F') + subpart_range_templ_1_prt_f_2_prt_yet_another_year | subpart_range_templ_1_prt_f | t | 2 | DEFAULT + subpart_range_templ_1_prt_f_2_prt_r4 | subpart_range_templ_1_prt_f | t | 2 | FOR VALUES FROM (MINVALUE) TO ('01-01-2020') +(31 rows) + +ALTER TABLE subpart_range_templ SET SUBPARTITION TEMPLATE + ( + subpartition r4 START (date '2020-01-01') EXCLUSIVE WITH (appendonly=true, orientation=column, compresslevel=5), + DEFAULT SUBPARTITION yet_another_year + ); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_templ'::regclass; + level | pg_get_expr +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION yet_another_year, SUBPARTITION r4 START ('01-02-2020'::date), WITH (appendonly=true, orientation=row, compresslevel=5)) +(1 row) + +ALTER TABLE subpart_range_templ ADD PARTITION g VALUES ('G'); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +---------------------------------------------------------+----------------------------------------+--------+-------+-------------------------------------------------- + subpart_range_templ | | f | 0 | + subpart_range_templ_1_prt_other_letter | subpart_range_templ | f | 1 | DEFAULT + subpart_range_templ_1_prt_a | subpart_range_templ | f | 1 | FOR VALUES IN ('A') + subpart_range_templ_1_prt_b | subpart_range_templ | f | 1 | FOR VALUES IN ('B') + subpart_range_templ_1_prt_other_letter_2_prt_other_year | subpart_range_templ_1_prt_other_letter | t | 2 | DEFAULT + subpart_range_templ_1_prt_other_letter_2_prt_r1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_other_letter_2_prt_r2_1 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_other_letter_2_prt_r2_2 | subpart_range_templ_1_prt_other_letter | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_a_2_prt_other_year | subpart_range_templ_1_prt_a | t | 2 | DEFAULT + subpart_range_templ_1_prt_a_2_prt_r1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_a_2_prt_r2_1 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_a_2_prt_r2_2 | subpart_range_templ_1_prt_a | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_b_2_prt_other_year | subpart_range_templ_1_prt_b | t | 2 | DEFAULT + subpart_range_templ_1_prt_b_2_prt_r1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_b_2_prt_r2_1 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_b_2_prt_r2_2 | subpart_range_templ_1_prt_b | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_c | subpart_range_templ | f | 1 | FOR VALUES IN ('C') + subpart_range_templ_1_prt_c_2_prt_other_year | subpart_range_templ_1_prt_c | t | 2 | DEFAULT + subpart_range_templ_1_prt_c_2_prt_r1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + subpart_range_templ_1_prt_c_2_prt_r2_1 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + subpart_range_templ_1_prt_c_2_prt_r2_2 | subpart_range_templ_1_prt_c | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') + subpart_range_templ_1_prt_d | subpart_range_templ | f | 1 | FOR VALUES IN ('D') + subpart_range_templ_1_prt_d_2_prt_r3 | subpart_range_templ_1_prt_d | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2005') + subpart_range_templ_1_prt_e | subpart_range_templ | f | 1 | FOR VALUES IN ('E') + subpart_range_templ_1_prt_e_2_prt_yet_another_year | subpart_range_templ_1_prt_e | t | 2 | DEFAULT + subpart_range_templ_1_prt_e_2_prt_r4 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2020') TO ('01-02-2021') + subpart_range_templ_1_prt_e_2_prt_r5_1 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2021') TO ('01-02-2022') + subpart_range_templ_1_prt_e_2_prt_r5_2 | subpart_range_templ_1_prt_e | t | 2 | FOR VALUES FROM ('01-02-2022') TO ('01-02-2023') + subpart_range_templ_1_prt_f | subpart_range_templ | f | 1 | FOR VALUES IN ('F') + subpart_range_templ_1_prt_f_2_prt_yet_another_year | subpart_range_templ_1_prt_f | t | 2 | DEFAULT + subpart_range_templ_1_prt_f_2_prt_r4 | subpart_range_templ_1_prt_f | t | 2 | FOR VALUES FROM (MINVALUE) TO ('01-01-2020') + subpart_range_templ_1_prt_g | subpart_range_templ | f | 1 | FOR VALUES IN ('G') + subpart_range_templ_1_prt_g_2_prt_yet_another_year | subpart_range_templ_1_prt_g | t | 2 | DEFAULT + subpart_range_templ_1_prt_g_2_prt_r4 | subpart_range_templ_1_prt_g | t | 2 | FOR VALUES FROM ('01-02-2020') TO (MAXVALUE) +(34 rows) + +-- Multi-level RANGE subpartitioning using templates +CREATE TABLE subpart_range_templ_multilevel (id int, year int, month int, day int, + region text) + DISTRIBUTED BY (id) + PARTITION BY RANGE (year) + SUBPARTITION BY RANGE (month) + SUBPARTITION TEMPLATE ( + START (11) END (12) EVERY (1), + DEFAULT SUBPARTITION other_months ) + SUBPARTITION BY RANGE (day) + SUBPARTITION TEMPLATE ( + START (7) END (15) EVERY (7), + DEFAULT SUBPARTITION other_days ) + ( START (2022) END (2023) EVERY (1)); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_templ_multilevel'::regclass; + level | pg_get_expr +-------+------------------------------------------------------------------------------------------------------------ + 1 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION other_months, START (11::integer) END (12::integer) Every (1)) + 2 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION other_days, START (7::integer) END (15::integer) Every (7)) +(2 rows) + +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ_multilevel') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +-----------------------------------------------------------------+-----------------------------------------------------------+--------+-------+---------------------------------- + subpart_range_templ_multilevel | | f | 0 | + subpart_range_templ_multilevel_1_prt_1 | subpart_range_templ_multilevel | f | 1 | FOR VALUES FROM (2022) TO (2023) + subpart_range_templ_multilevel_1_prt_1_2_prt_other_months | subpart_range_templ_multilevel_1_prt_1 | f | 2 | DEFAULT + subpart_range_templ_multilevel_1_prt_1_2_prt_2 | subpart_range_templ_multilevel_1_prt_1 | f | 2 | FOR VALUES FROM (11) TO (12) + subpart_range_templ_multilevel_1_prt_1_2_prt_o_3_prt_other_days | subpart_range_templ_multilevel_1_prt_1_2_prt_other_months | t | 3 | DEFAULT + subpart_range_templ_multilevel_1_prt_1_2_prt_other_mont_3_prt_2 | subpart_range_templ_multilevel_1_prt_1_2_prt_other_months | t | 3 | FOR VALUES FROM (7) TO (14) + subpart_range_templ_multilevel_1_prt_1_2_prt_other_mont_3_prt_3 | subpart_range_templ_multilevel_1_prt_1_2_prt_other_months | t | 3 | FOR VALUES FROM (14) TO (15) + subpart_range_templ_multilevel_1_prt_1_2_prt_2_3_prt_other_days | subpart_range_templ_multilevel_1_prt_1_2_prt_2 | t | 3 | DEFAULT + subpart_range_templ_multilevel_1_prt_1_2_prt_2_3_prt_2 | subpart_range_templ_multilevel_1_prt_1_2_prt_2 | t | 3 | FOR VALUES FROM (7) TO (14) + subpart_range_templ_multilevel_1_prt_1_2_prt_2_3_prt_3 | subpart_range_templ_multilevel_1_prt_1_2_prt_2 | t | 3 | FOR VALUES FROM (14) TO (15) +(10 rows) + +-- ADD PARTITION should create subpartitions according to the templates +ALTER TABLE subpart_range_templ_multilevel ADD PARTITION new_part START (2023) END (2024); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ_multilevel') As t, pg_class As c WHERE relid = oid AND t.relid::regclass::text like '%new_part%' ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +-----------------------------------------------------------------+-------------------------------------------------------+--------+-------+---------------------------------- + subpart_range_templ_multilevel_1_prt_new_part | subpart_range_templ_multilevel | f | 1 | FOR VALUES FROM (2023) TO (2024) + subpart_range_templ_multilevel_1_prt_new_part_2_prt_2 | subpart_range_templ_multilevel_1_prt_new_part | f | 2 | FOR VALUES FROM (11) TO (12) + subpart_range_templ_multilevel_1_prt_new_part__3_prt_other_days | subpart_range_templ_multilevel_1_prt_new_part_2_prt_2 | t | 3 | DEFAULT + subpart_range_templ_multilevel_1_prt_new_part_2_prt_2_3_prt_2 | subpart_range_templ_multilevel_1_prt_new_part_2_prt_2 | t | 3 | FOR VALUES FROM (7) TO (14) + subpart_range_templ_multilevel_1_prt_new_part_2_prt_2_3_prt_3 | subpart_range_templ_multilevel_1_prt_new_part_2_prt_2 | t | 3 | FOR VALUES FROM (14) TO (15) +(5 rows) + +-- Remove level 1 subpartition template +ALTER TABLE subpart_range_templ_multilevel SET SUBPARTITION TEMPLATE(); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_templ_multilevel'::regclass; + level | pg_get_expr +-------+--------------------------------------------------------------------------------------------------------- + 2 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION other_days, START (7::integer) END (15::integer) Every (7)) +(1 row) + +-- ADD PARTITION should create subpartitions according to the level 1 partition definition spec and level 2 subpartition templates +ALTER TABLE subpart_range_templ_multilevel Add partition oct START (10) END (11) (SUBPARTITION new_days START (15) END (30)); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_templ_multilevel') As t, pg_class As c WHERE relid = oid AND t.relid::regclass::text LIKE '%oct%' ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +-----------------------------------------------------------------+---------------------------------------------------------+--------+-------+------------------------------ + subpart_range_templ_multilevel_1_prt_oct | subpart_range_templ_multilevel | f | 1 | FOR VALUES FROM (10) TO (11) + subpart_range_templ_multilevel_1_prt_oct_2_prt_new_days | subpart_range_templ_multilevel_1_prt_oct | f | 2 | FOR VALUES FROM (15) TO (30) + subpart_range_templ_multilevel_1_prt_oct_2_prt_3_prt_other_days | subpart_range_templ_multilevel_1_prt_oct_2_prt_new_days | t | 3 | DEFAULT + subpart_range_templ_multilevel_1_prt_oct_2_prt_new_days_3_prt_2 | subpart_range_templ_multilevel_1_prt_oct_2_prt_new_days | t | 3 | FOR VALUES FROM (7) TO (14) + subpart_range_templ_multilevel_1_prt_oct_2_prt_new_days_3_prt_3 | subpart_range_templ_multilevel_1_prt_oct_2_prt_new_days | t | 3 | FOR VALUES FROM (14) TO (15) +(5 rows) + +-- Remove level 2 subpartition template, this works but no syntax will be available to add new partitions at any level +ALTER TABLE subpart_range_templ_multilevel ALTER PARTITION new_part SET SUBPARTITION TEMPLATE(); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_templ_multilevel'::regclass; + level | pg_get_expr +-------+------------- +(0 rows) + +-- Can't ADD PARTITION because subpartition template at the last level is missing +ALTER TABLE subpart_range_templ_multilevel Add partition oct START (10) END (11) (SUBPARTITION new_days START (15) END (30)); +ERROR: relation "subpart_range_templ_multilevel_1_prt_oct" already exists +-- Multi-level subpartition using template at the last level +CREATE TABLE subpart_range_mixedtempl (a int, dropped int, b int, c int, d int) + DISTRIBUTED RANDOMLY + PARTITION BY RANGE (b) + SUBPARTITION BY RANGE (c) + SUBPARTITION BY RANGE (d) + SUBPARTITION TEMPLATE ( + SUBPARTITION c_low start (1) end (5), + SUBPARTITION c_hi start (5) end (10), + DEFAULT SUBPARTITION def_d + ) + ( + PARTITION b_low start (0) end (3) + ( + SUBPARTITION c_low start (11) end (22) every (10), + DEFAULT SUBPARTITION def_c + ), + PARTITION b_mid start (3) end (6) + ( + SUBPARTITION c_mid start (22) end (32) every (10) + ) + ); +-- Subpartition template should be stored in catalog +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_range_mixedtempl'::regclass; + level | pg_get_expr +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 2 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION def_d, SUBPARTITION c_low START (1::integer) END (5::integer), SUBPARTITION c_hi START (5::integer) END (10::integer)) +(1 row) + +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_mixedtempl') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +----------------------------------------------------------------+----------------------------------------------------+--------+-------+------------------------------ + subpart_range_mixedtempl | | f | 0 | + subpart_range_mixedtempl_1_prt_b_low | subpart_range_mixedtempl | f | 1 | FOR VALUES FROM (0) TO (3) + subpart_range_mixedtempl_1_prt_b_mid | subpart_range_mixedtempl | f | 1 | FOR VALUES FROM (3) TO (6) + subpart_range_mixedtempl_1_prt_b_low_2_prt_def_c | subpart_range_mixedtempl_1_prt_b_low | f | 2 | DEFAULT + subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_1 | subpart_range_mixedtempl_1_prt_b_low | f | 2 | FOR VALUES FROM (11) TO (21) + subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_2 | subpart_range_mixedtempl_1_prt_b_low | f | 2 | FOR VALUES FROM (21) TO (22) + subpart_range_mixedtempl_1_prt_b_mid_2_prt_c_mid_1 | subpart_range_mixedtempl_1_prt_b_mid | f | 2 | FOR VALUES FROM (22) TO (32) + subpart_range_mixedtempl_1_prt_b_low_2_prt_def_c_3_prt_def_d | subpart_range_mixedtempl_1_prt_b_low_2_prt_def_c | t | 3 | DEFAULT + subpart_range_mixedtempl_1_prt_b_low_2_prt_def_c_3_prt_c_low | subpart_range_mixedtempl_1_prt_b_low_2_prt_def_c | t | 3 | FOR VALUES FROM (1) TO (5) + subpart_range_mixedtempl_1_prt_b_low_2_prt_def_c_3_prt_c_hi | subpart_range_mixedtempl_1_prt_b_low_2_prt_def_c | t | 3 | FOR VALUES FROM (5) TO (10) + subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_1_3_prt_def_d | subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_1 | t | 3 | DEFAULT + subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_1_3_prt_c_low | subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_1 | t | 3 | FOR VALUES FROM (1) TO (5) + subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_1_3_prt_c_hi | subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_1 | t | 3 | FOR VALUES FROM (5) TO (10) + subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_2_3_prt_def_d | subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_2 | t | 3 | DEFAULT + subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_2_3_prt_c_low | subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_2 | t | 3 | FOR VALUES FROM (1) TO (5) + subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_2_3_prt_c_hi | subpart_range_mixedtempl_1_prt_b_low_2_prt_c_low_2 | t | 3 | FOR VALUES FROM (5) TO (10) + subpart_range_mixedtempl_1_prt_b_mid_2_prt_c_mid_1_3_prt_def_d | subpart_range_mixedtempl_1_prt_b_mid_2_prt_c_mid_1 | t | 3 | DEFAULT + subpart_range_mixedtempl_1_prt_b_mid_2_prt_c_mid_1_3_prt_c_low | subpart_range_mixedtempl_1_prt_b_mid_2_prt_c_mid_1 | t | 3 | FOR VALUES FROM (1) TO (5) + subpart_range_mixedtempl_1_prt_b_mid_2_prt_c_mid_1_3_prt_c_hi | subpart_range_mixedtempl_1_prt_b_mid_2_prt_c_mid_1 | t | 3 | FOR VALUES FROM (5) TO (10) +(19 rows) + +-- ADD PARTITION without subpartition definition spec for level 2 should fail +ALTER TABLE subpart_range_mixedtempl ADD PARTITION b_high START (6) END (9); +ERROR: no partitions specified at depth 2 +-- ADD PARTITION with subpartition definition spec for level 2 should fail if EVERY is specified in level 1 partition definition spec +ALTER TABLE subpart_range_mixedtempl ADD PARTITION b_high START (6) END (9) every (3) (subpartition c_high start(32) end (50)); +ERROR: syntax error at or near "every" +LINE 1: ...mixedtempl ADD PARTITION b_high START (6) END (9) every (3) ... + ^ +-- ADD PARTITION with subpartition definition spec for level 2 should fail if there is more than one subpartition at level 2. +ALTER TABLE subpart_range_mixedtempl ADD PARTITION b_high START (6) END (9) (subpartition c_high start(32) end (50) every (15)); +ERROR: relation "subpart_range_mixedtempl_1_prt_b_high_2_prt_c_high__3_prt_def_d" already exists +-- ADD PARTITION with subpartition definition spec for level 2 should create level 3 subpartitions according to the template +ALTER TABLE subpart_range_mixedtempl ADD PARTITION b_high START (6) END (9) (subpartition c_high start(32) end (50) every (50)); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_range_mixedtempl') As t, pg_class As c WHERE relid = oid AND t.relid::regclass::text LIKE '%b_high%' ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +-----------------------------------------------------------------+------------------------------------------------------+--------+-------+------------------------------ + subpart_range_mixedtempl_1_prt_b_high | subpart_range_mixedtempl | f | 1 | FOR VALUES FROM (6) TO (9) + subpart_range_mixedtempl_1_prt_b_high_2_prt_c_high_1 | subpart_range_mixedtempl_1_prt_b_high | f | 2 | FOR VALUES FROM (32) TO (50) + subpart_range_mixedtempl_1_prt_b_high_2_prt_c_high__3_prt_def_d | subpart_range_mixedtempl_1_prt_b_high_2_prt_c_high_1 | t | 3 | DEFAULT + subpart_range_mixedtempl_1_prt_b_high_2_prt_c_high__3_prt_c_low | subpart_range_mixedtempl_1_prt_b_high_2_prt_c_high_1 | t | 3 | FOR VALUES FROM (1) TO (5) + subpart_range_mixedtempl_1_prt_b_high_2_prt_c_high_1_3_prt_c_hi | subpart_range_mixedtempl_1_prt_b_high_2_prt_c_high_1 | t | 3 | FOR VALUES FROM (5) TO (10) +(5 rows) + +-- Subpartitioned by LIST +CREATE TABLE subpart_list_templ (trans_id int, date date, amount + decimal(9,2), region text) + DISTRIBUTED BY (trans_id) + PARTITION BY RANGE (date) + SUBPARTITION BY LIST (region) + SUBPARTITION TEMPLATE + ( SUBPARTITION usa VALUES ('usa'), + SUBPARTITION asia VALUES ('asia'), + SUBPARTITION europe VALUES ('europe'), + DEFAULT SUBPARTITION other_regions) + (START (date '2020-01-01') INCLUSIVE + END (date '2022-01-01') EXCLUSIVE + EVERY (INTERVAL '1 year'), + DEFAULT PARTITION outlying_dates ); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_list_templ'::regclass; + level | pg_get_expr +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(DEFAULT SUBPARTITION other_regions, SUBPARTITION usa VALUES ('usa'), SUBPARTITION asia VALUES ('asia'), SUBPARTITION europe VALUES ('europe')) +(1 row) + +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_list_templ') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +-------------------------------------------------------------+-----------------------------------------+--------+-------+-------------------------------------------------- + subpart_list_templ | | f | 0 | + subpart_list_templ_1_prt_outlying_dates | subpart_list_templ | f | 1 | DEFAULT + subpart_list_templ_1_prt_2 | subpart_list_templ | f | 1 | FOR VALUES FROM ('01-01-2020') TO ('01-01-2021') + subpart_list_templ_1_prt_3 | subpart_list_templ | f | 1 | FOR VALUES FROM ('01-01-2021') TO ('01-01-2022') + subpart_list_templ_1_prt_outlying_dates_2_prt_other_regions | subpart_list_templ_1_prt_outlying_dates | t | 2 | DEFAULT + subpart_list_templ_1_prt_outlying_dates_2_prt_usa | subpart_list_templ_1_prt_outlying_dates | t | 2 | FOR VALUES IN ('usa') + subpart_list_templ_1_prt_outlying_dates_2_prt_asia | subpart_list_templ_1_prt_outlying_dates | t | 2 | FOR VALUES IN ('asia') + subpart_list_templ_1_prt_outlying_dates_2_prt_europe | subpart_list_templ_1_prt_outlying_dates | t | 2 | FOR VALUES IN ('europe') + subpart_list_templ_1_prt_2_2_prt_other_regions | subpart_list_templ_1_prt_2 | t | 2 | DEFAULT + subpart_list_templ_1_prt_2_2_prt_usa | subpart_list_templ_1_prt_2 | t | 2 | FOR VALUES IN ('usa') + subpart_list_templ_1_prt_2_2_prt_asia | subpart_list_templ_1_prt_2 | t | 2 | FOR VALUES IN ('asia') + subpart_list_templ_1_prt_2_2_prt_europe | subpart_list_templ_1_prt_2 | t | 2 | FOR VALUES IN ('europe') + subpart_list_templ_1_prt_3_2_prt_other_regions | subpart_list_templ_1_prt_3 | t | 2 | DEFAULT + subpart_list_templ_1_prt_3_2_prt_usa | subpart_list_templ_1_prt_3 | t | 2 | FOR VALUES IN ('usa') + subpart_list_templ_1_prt_3_2_prt_asia | subpart_list_templ_1_prt_3 | t | 2 | FOR VALUES IN ('asia') + subpart_list_templ_1_prt_3_2_prt_europe | subpart_list_templ_1_prt_3 | t | 2 | FOR VALUES IN ('europe') +(16 rows) + +ALTER TABLE subpart_list_templ ADD PARTITION year_2023 START (date '2022-01-01') EXCLUSIVE END (date '2023-01-01') INCLUSIVE; +-- ADD PARTITION should create subpartitions according to the template +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_list_templ') As t, pg_class As c WHERE relid = oid AND t.relid::regclass::text LIKE '%year_2023%' ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +--------------------------------------------------------+------------------------------------+--------+-------+-------------------------------------------------- + subpart_list_templ_1_prt_year_2023 | subpart_list_templ | f | 1 | FOR VALUES FROM ('01-02-2022') TO ('01-02-2023') + subpart_list_templ_1_prt_year_2023_2_prt_other_regions | subpart_list_templ_1_prt_year_2023 | t | 2 | DEFAULT + subpart_list_templ_1_prt_year_2023_2_prt_usa | subpart_list_templ_1_prt_year_2023 | t | 2 | FOR VALUES IN ('usa') + subpart_list_templ_1_prt_year_2023_2_prt_asia | subpart_list_templ_1_prt_year_2023 | t | 2 | FOR VALUES IN ('asia') + subpart_list_templ_1_prt_year_2023_2_prt_europe | subpart_list_templ_1_prt_year_2023 | t | 2 | FOR VALUES IN ('europe') +(5 rows) + +-- Subpartitioning without any template should work as usual +CREATE TABLE notemplate (a int, dropped int, b int, c int, d int) + DISTRIBUTED RANDOMLY + PARTITION BY RANGE (b) + SUBPARTITION BY RANGE (c) + ( + PARTITION b_low start (0) end (3) + ( + SUBPARTITION c_low start (1) end (5), + SUBPARTITION c_hi start (5) end (10), + DEFAULT SUBPARTITION def + ), + PARTITION b_mid start (3) end (6) + ( + SUBPARTITION c_low start (1) end (5), + SUBPARTITION c_hi start (5) end (10) + ) + ); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'notemplate'::regclass; + level | pg_get_expr +-------+------------- +(0 rows) + +-- This should fail due to missing subpartition definition spec +ALTER TABLE notemplate ADD partition b_hi START (6) END (9); +ERROR: no partitions specified at depth 2 +-- This should work +ALTER TABLE notemplate ADD partition b_hi START (6) END (9) (subpartition c_low START (1) END (7)); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('notemplate') As t, pg_class As c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +------------------------------------+------------------------+--------+-------+----------------------------- + notemplate | | f | 0 | + notemplate_1_prt_b_low | notemplate | f | 1 | FOR VALUES FROM (0) TO (3) + notemplate_1_prt_b_mid | notemplate | f | 1 | FOR VALUES FROM (3) TO (6) + notemplate_1_prt_b_low_2_prt_def | notemplate_1_prt_b_low | t | 2 | DEFAULT + notemplate_1_prt_b_low_2_prt_c_low | notemplate_1_prt_b_low | t | 2 | FOR VALUES FROM (1) TO (5) + notemplate_1_prt_b_low_2_prt_c_hi | notemplate_1_prt_b_low | t | 2 | FOR VALUES FROM (5) TO (10) + notemplate_1_prt_b_mid_2_prt_c_low | notemplate_1_prt_b_mid | t | 2 | FOR VALUES FROM (1) TO (5) + notemplate_1_prt_b_mid_2_prt_c_hi | notemplate_1_prt_b_mid | t | 2 | FOR VALUES FROM (5) TO (10) + notemplate_1_prt_b_hi | notemplate | f | 1 | FOR VALUES FROM (6) TO (9) + notemplate_1_prt_b_hi_2_prt_c_low | notemplate_1_prt_b_hi | t | 2 | FOR VALUES FROM (1) TO (7) +(10 rows) + +-- Subpartition templates with encoding clauses +prepare encoding_check as +select attrelid::regclass as relname, + attnum, attoptions from pg_class c, pg_attribute_encoding e +where c.relname like 'subpart_templ_encoding%' and c.oid=e.attrelid +order by relname, attnum; +-- Range partition with enclause +DROP TABLE IF EXISTS subpart_templ_encoding; +NOTICE: table "subpart_templ_encoding" does not exist, skipping +create table subpart_templ_encoding (i int, j int, k int, l int) + with (appendonly = true, orientation=column) + partition by range(j) + subpartition by range (k) + subpartition template( + subpartition sp1 start (100) end (200) every (50), + column i encoding(compresstype=zlib), + column j encoding(compresstype=RLE_TYPE), + column k encoding(compresstype=zlib), + column l encoding(compresstype=zlib) + ) +( partition p1 start(1) end(10), + partition p2 start(10) end(20) +); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'i' as the Greenplum Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_templ_encoding'::regclass; + level | pg_get_expr +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + 1 | SUBPARTITION TEMPLATE(SUBPARTITION sp1 START (100::integer) END (200::integer) Every (50), COLUMN i ENCODING (compresstype=zlib), COLUMN j ENCODING (compresstype=rle_type), COLUMN k ENCODING (compresstype=zlib), COLUMN l ENCODING (compresstype=zlib)) +(1 row) + +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_templ_encoding') AS t, pg_class AS c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +---------------------------------------------+---------------------------------+--------+-------+-------------------------------- + subpart_templ_encoding | | f | 0 | + subpart_templ_encoding_1_prt_p1 | subpart_templ_encoding | f | 1 | FOR VALUES FROM (1) TO (10) + subpart_templ_encoding_1_prt_p2 | subpart_templ_encoding | f | 1 | FOR VALUES FROM (10) TO (20) + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | subpart_templ_encoding_1_prt_p1 | t | 2 | FOR VALUES FROM (100) TO (150) + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | subpart_templ_encoding_1_prt_p1 | t | 2 | FOR VALUES FROM (150) TO (200) + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | subpart_templ_encoding_1_prt_p2 | t | 2 | FOR VALUES FROM (100) TO (150) + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | subpart_templ_encoding_1_prt_p2 | t | 2 | FOR VALUES FROM (150) TO (200) +(7 rows) + +EXECUTE encoding_check; + relname | attnum | attoptions +---------------------------------------------+--------+--------------------------------------------------------- + subpart_templ_encoding | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} +(28 rows) + +-- FIXME: the new partitions should have the encodings specified in the template +ALTER TABLE subpart_templ_encoding ADD PARTITION p3 START (30) END (40); +EXECUTE encoding_check; + relname | attnum | attoptions +---------------------------------------------+--------+--------------------------------------------------------- + subpart_templ_encoding | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_1 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1_2 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_1 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1_2 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p3 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1_1 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1_1 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1_1 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1_1 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1_2 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1_2 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1_2 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1_2 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} +(40 rows) + +-- List partition with enclause +DROP TABLE IF EXISTS subpart_templ_encoding; +create table subpart_templ_encoding (i int, j int, k int, l int) + with (appendonly = true, orientation=column) + partition by range(j) + subpartition by list (k) + subpartition template( + subpartition sp1 values(1, 2, 3, 4, 5) , + column i encoding(compresstype=zlib), + column j encoding(compresstype=RLE_TYPE), + column k encoding(compresstype=zlib), + column l encoding(compresstype=zlib) + ) +( partition p1 start(1) end(10), + partition p2 start(10) end(20) +); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'i' as the Greenplum Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'subpart_templ_encoding'::regclass; + level | pg_get_expr +-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(SUBPARTITION sp1 VALUES (1, 2, 3, 4, 5), COLUMN i ENCODING (compresstype=zlib), COLUMN j ENCODING (compresstype=rle_type), COLUMN k ENCODING (compresstype=zlib), COLUMN l ENCODING (compresstype=zlib)) +(1 row) + +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('subpart_templ_encoding') AS t, pg_class AS c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +-------------------------------------------+---------------------------------+--------+-------+------------------------------- + subpart_templ_encoding | | f | 0 | + subpart_templ_encoding_1_prt_p1 | subpart_templ_encoding | f | 1 | FOR VALUES FROM (1) TO (10) + subpart_templ_encoding_1_prt_p2 | subpart_templ_encoding | f | 1 | FOR VALUES FROM (10) TO (20) + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | subpart_templ_encoding_1_prt_p1 | t | 2 | FOR VALUES IN (1, 2, 3, 4, 5) + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | subpart_templ_encoding_1_prt_p2 | t | 2 | FOR VALUES IN (1, 2, 3, 4, 5) +(5 rows) + +EXECUTE encoding_check; + relname | attnum | attoptions +-------------------------------------------+--------+--------------------------------------------------------- + subpart_templ_encoding | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} +(20 rows) + +-- FIXME: the new partitions should have the encodings specified in the template +ALTER TABLE subpart_templ_encoding ADD PARTITION p3 START (30) END (40); +EXECUTE encoding_check; + relname | attnum | attoptions +-------------------------------------------+--------+--------------------------------------------------------- + subpart_templ_encoding | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p2 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p1_2_prt_sp1 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | 1 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | 2 | {compresstype=rle_type,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | 3 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p2_2_prt_sp1 | 4 | {compresstype=zlib,compresslevel=1,blocksize=32768} + subpart_templ_encoding_1_prt_p3 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1 | 1 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1 | 2 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1 | 3 | {compresstype=none,blocksize=32768,compresslevel=0} + subpart_templ_encoding_1_prt_p3_2_prt_sp1 | 4 | {compresstype=none,blocksize=32768,compresslevel=0} +(28 rows) + +-- Partition specific ENCODING clause is not supported in SUBPARTITION TEMPLATE +create table template_partelem_enc (i int, j int, k int, l int) + with (appendonly = true, orientation=column) + partition by range(j) + subpartition by range (k) + subpartition template( + subpartition sp1 start (100) end (200) every (50) column i encoding(compresstype=RLE_TYPE), + column i encoding(compresstype=zlib), + column j encoding(compresstype=RLE_TYPE), + column k encoding(compresstype=zlib), + column l encoding(compresstype=zlib) + ) +( partition p1 start(1) end(10), + partition p2 start(10) end(20) +); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'i' as the Greenplum Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: partition specific ENCODING clause not supported in SUBPARTITION TEMPLATE +LINE 6: subpartition sp1 start (100) end (200) every (50) co... + ^ +-- More tests on SET SUBPARTITION TEMPLATE +CREATE TABLE set_templ_test (id int, year date, letter char(1)) + DISTRIBUTED BY (id, letter, year) + PARTITION BY list (letter); +-- Can't SET SUBPARTITION TEMPLATE when level 1 partition is not present +ALTER TABLE set_templ_test SET SUBPARTITION TEMPLATE( + subpartition r1 START (date '2001-01-01') END (date '2003-01-01'), + subpartition r2 START (date '2003-01-01') END (date '2005-01-01') EVERY (interval '1 year') + ); +ERROR: GPDB SET SUBPARTITION TEMPLATE syntax needs at least one sibling to exist +-- Add a level 1 partition but the partition itself is not a partitioned table +CREATE TABLE set_templ_test_c PARTITION OF set_templ_test FOR VALUES IN ('C'); +NOTICE: table has parent, setting distribution columns to match parent table +-- Can't SET SUBPARTITION TEMPLATE when level 1 partition is not partitioned +ALTER TABLE set_templ_test SET SUBPARTITION TEMPLATE( + subpartition r1 START (date '2001-01-01') END (date '2003-01-01'), + subpartition r2 START (date '2003-01-01') END (date '2005-01-01') EVERY (interval '1 year') + ); +ERROR: level 1 is not partitioned and hence can't set subpartition template for the same +-- Add another level 1 partition that IS a partitioned table +CREATE TABLE set_templ_test_d PARTITION OF set_templ_test FOR VALUES IN ('D') + PARTITION BY range (year); +NOTICE: table has parent, setting distribution columns to match parent table +-- Can't SET SUBPARTITION TEMPLATE when the FIRST level 1 child partition is not partitioned +ALTER TABLE set_templ_test SET SUBPARTITION TEMPLATE( + subpartition r1 START (date '2001-01-01') END (date '2003-01-01'), + subpartition r2 START (date '2003-01-01') END (date '2005-01-01') EVERY (interval '1 year') + ); +ERROR: level 1 is not partitioned and hence can't set subpartition template for the same +-- Add another level 1 partition that IS a partitioned table (but has zero child) +-- and will be treated as the FIRST child on this level +CREATE TABLE set_templ_test_b PARTITION OF set_templ_test FOR VALUES IN ('B') + PARTITION BY range (year); +NOTICE: table has parent, setting distribution columns to match parent table +-- Can't SET SUBPARTITION TEMPLATE when sibling level 2 partition is not present +ALTER TABLE set_templ_test SET SUBPARTITION TEMPLATE( + subpartition r1 START (date '2001-01-01') END (date '2003-01-01'), + subpartition r2 START (date '2003-01-01') END (date '2005-01-01') EVERY (interval '1 year') + ); +ERROR: GPDB SET SUBPARTITION TEMPLATE syntax needs at least one sibling to exist +-- Add a level 2 partition as the child of the first level 1 partition +CREATE TABLE set_templ_test_b_sp1 PARTITION OF set_templ_test_b FOR VALUES FROM (date '2021-01-01') TO (date '2022-01-01'); +NOTICE: table has parent, setting distribution columns to match parent table +-- SET SUBPARTITION TEMPLATE should work +ALTER TABLE set_templ_test SET SUBPARTITION TEMPLATE( + subpartition r1 START (date '2001-01-01') END (date '2003-01-01'), + subpartition r2 START (date '2003-01-01') END (date '2005-01-01') EVERY (interval '1 year') + ); +SELECT level, pg_get_expr(template, relid) from gp_partition_template t WHERE t.relid = 'set_templ_test'::regclass; + level | pg_get_expr +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1 | SUBPARTITION TEMPLATE(SUBPARTITION r1 START ('01-01-2001'::date) END ('01-01-2003'::date), SUBPARTITION r2 START ('01-01-2003'::date) END ('01-01-2005'::date) Every ('@ 1 year'::interval)) +(1 row) + +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('set_templ_test') AS t, pg_class AS c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +----------------------+------------------+--------+-------+-------------------------------------------------- + set_templ_test | | f | 0 | + set_templ_test_c | set_templ_test | t | 1 | FOR VALUES IN ('C') + set_templ_test_d | set_templ_test | f | 1 | FOR VALUES IN ('D') + set_templ_test_b | set_templ_test | f | 1 | FOR VALUES IN ('B') + set_templ_test_b_sp1 | set_templ_test_b | t | 2 | FOR VALUES FROM ('01-01-2021') TO ('01-01-2022') +(5 rows) + +-- ADD PARTITION should created subpartitions according to the template +ALTER TABLE set_templ_test ADD PARTITION e VALUES ('E'); +SELECT t.*, pg_get_expr(relpartbound, oid) FROM pg_partition_tree('set_templ_test') AS t, pg_class AS c WHERE relid = oid ORDER BY 1,5; + relid | parentrelid | isleaf | level | pg_get_expr +-----------------------------------+------------------------+--------+-------+-------------------------------------------------- + set_templ_test | | f | 0 | + set_templ_test_c | set_templ_test | t | 1 | FOR VALUES IN ('C') + set_templ_test_d | set_templ_test | f | 1 | FOR VALUES IN ('D') + set_templ_test_b | set_templ_test | f | 1 | FOR VALUES IN ('B') + set_templ_test_b_sp1 | set_templ_test_b | t | 2 | FOR VALUES FROM ('01-01-2021') TO ('01-01-2022') + set_templ_test_1_prt_e | set_templ_test | f | 1 | FOR VALUES IN ('E') + set_templ_test_1_prt_e_2_prt_r1 | set_templ_test_1_prt_e | t | 2 | FOR VALUES FROM ('01-01-2001') TO ('01-01-2003') + set_templ_test_1_prt_e_2_prt_r2_1 | set_templ_test_1_prt_e | t | 2 | FOR VALUES FROM ('01-01-2003') TO ('01-01-2004') + set_templ_test_1_prt_e_2_prt_r2_2 | set_templ_test_1_prt_e | t | 2 | FOR VALUES FROM ('01-01-2004') TO ('01-01-2005') +(9 rows) + +-- Add a level 1 partition that is partitioned BY LIST rather than by range, +-- and it will be treated as the FIRST child on this level +CREATE TABLE set_templ_test_a PARTITION OF set_templ_test FOR VALUES IN ('A') + PARTITION BY list (year); +NOTICE: table has parent, setting distribution columns to match parent table +CREATE TABLE set_templ_test_a_sp1 PARTITION OF set_templ_test_a FOR VALUES IN (date '2022-01-01'); +NOTICE: table has parent, setting distribution columns to match parent table +-- Can't ADD PARTITION because the RANGE boundary spec in the stored partition template +-- doesn't match the LIST partition strategy of the FIRST level 1 partition +ALTER TABLE set_templ_test ADD PARTITION f VALUES ('F'); +ERROR: invalid boundary specification for LIST partition +LINE 1: ALTER TABLE set_templ_test ADD PARTITION f VALUES ('F'); + ^ +-- Drop the FIRST level 1 partition +DROP TABLE set_templ_test_a; +-- Add a level 1 partition that is partitioned by multi-column range partition key, +-- and it will be treated as the FIRST child on this level +CREATE TABLE set_templ_test_a PARTITION OF set_templ_test FOR VALUES IN ('A') + PARTITION BY range (year, letter); +NOTICE: table has parent, setting distribution columns to match parent table +CREATE TABLE set_templ_test_a_sp2 PARTITION OF set_templ_test_a + FOR VALUES FROM (date '2022-01-01', 'A') TO (date '2022-01-01', 'K'); +NOTICE: table has parent, setting distribution columns to match parent table +-- Can't ADD PARTITION because the boundary spec in the stored partition template +-- doesn't match the first level 1 partition's partition key +ALTER TABLE set_templ_test ADD PARTITION f VALUES ('F'); +ERROR: too many columns for RANGE partition -- only one column is allowed +HINT: To create multi-column range partitioned table, use PostgreSQL's grammar. For example: +create table z (a int, b int, c int) partition by range(b, c); +create table z1 partition of z for values from (10, 10) TO (20, 20); +-- Drop the FIRST level 1 partition +DROP TABLE set_templ_test_a; +-- Add a level 1 partition who's partition key is an expression +CREATE TABLE set_templ_test_a PARTITION OF set_templ_test FOR VALUES IN ('A') + PARTITION BY range (abs(id+1)); +NOTICE: table has parent, setting distribution columns to match parent table +CREATE TABLE set_templ_test_a_sp3 PARTITION OF set_templ_test_a + FOR VALUES FROM (1) TO (10); +NOTICE: table has parent, setting distribution columns to match parent table +-- Can't ADD PARTITION because level 1 first partition's partition key has expression +ALTER TABLE set_templ_test ADD PARTITION f VALUES ('F'); +ERROR: SUBPARTITION BY contain expressions. Cannot ADD PARTITION if expressions in partition key using legacy syntax +HINT: Table was created using new partition syntax. Hence, use CREATE TABLE... PARTITION OF instead. +-- Reset SUBPARTITION TEMPLATE +ALTER TABLE set_templ_test SET SUBPARTITION TEMPLATE(); +ALTER TABLE set_templ_test SET SUBPARTITION TEMPLATE( + subpartition r1 START (date '2001-01-01') END (date '2003-01-01'), + subpartition r2 START (date '2003-01-01') END (date '2005-01-01') EVERY (interval '1 year') + ); +ERROR: expressions in partition key not supported in legacy GPDB partition syntax diff --git a/src/test/regress/expected/partition_storage.out b/src/test/regress/expected/partition_storage.out index 4b26601f571..fc89ad3e95a 100644 --- a/src/test/regress/expected/partition_storage.out +++ b/src/test/regress/expected/partition_storage.out @@ -67,6 +67,32 @@ NOTICE: table doesn't have 'DISTRIBUTED BY' clause, defaulting to distribution alter table pt_heap_tab exchange partition for ('def') with table co_can; -- AO exchanged with CO alter table pt_heap_tab exchange partition for ('pqr') with table heap_can; -- CO exchanged with Heap --Check for the storage properties and indexes of the two tables involved in the exchange + \d+ pt_heap_tab + Partitioned table "public.pt_heap_tab" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------+---------+-----------+----------+---------+----------+--------------+------------- + a | integer | | | | plain | | + b | text | | | | extended | | + c | integer | | | | plain | | + d | integer | | | | plain | | + e | numeric | | | | main | | + success | boolean | | | | plain | | +Partition key: LIST (b) +Indexes: + "heap_idx1" btree (a) WHERE c > 10 + "heap_idx2" btree (upper(b)) +Partitions: pt_heap_tab_1_prt_abc1 FOR VALUES IN ('abc', 'abc2'), + pt_heap_tab_1_prt_abc2 FOR VALUES IN ('abc1'), + pt_heap_tab_1_prt_def FOR VALUES IN ('def', 'def1', 'def3'), + pt_heap_tab_1_prt_ghi1 FOR VALUES IN ('ghi', 'ghi2'), + pt_heap_tab_1_prt_ghi2 FOR VALUES IN ('ghi1'), + pt_heap_tab_1_prt_jkl FOR VALUES IN ('jkl', 'jkl1', 'jkl2'), + pt_heap_tab_1_prt_mno FOR VALUES IN ('mno', 'mno1', 'mno2'), + pt_heap_tab_1_prt_pqr FOR VALUES IN ('pqr', 'pqr1', 'pqr2'), + pt_heap_tab_1_prt_xyz1 FOR VALUES IN ('xyz', 'xyz2'), + pt_heap_tab_1_prt_xyz2 FOR VALUES IN ('xyz1') +Distributed by: (a) + \d+ heap_can Table "public.heap_can" Column | Type | Collation | Nullable | Default | Storage | Stats target | Compression Type | Compression Level | Block Size | Description @@ -204,6 +230,33 @@ NOTICE: table doesn't have 'DISTRIBUTED BY' clause, defaulting to distribution alter table pt_ao_tab exchange partition for ('def') with table co_can; --AO tab exchanged with CO alter table pt_ao_tab exchange partition for ('pqr') with table heap_can; --CO tab exchanged with Heap --Check for the storage properties and indexes of the two tables involved in the exchange + \d+ pt_ao_tab + Partitioned table "public.pt_ao_tab" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------+---------+-----------+----------+---------+----------+--------------+------------- + a | integer | | | | plain | | + b | text | | | | extended | | + c | integer | | | | plain | | + d | integer | | | | plain | | + e | numeric | | | | main | | + success | boolean | | | | plain | | +Partition key: LIST (b) +Indexes: + "ao_idx1" btree (a) WHERE c > 10 + "ao_idx2" btree (upper(b)) +Partitions: pt_ao_tab_1_prt_abc1 FOR VALUES IN ('abc', 'abc2'), + pt_ao_tab_1_prt_abc2 FOR VALUES IN ('abc1'), + pt_ao_tab_1_prt_def FOR VALUES IN ('def', 'def1', 'def3'), + pt_ao_tab_1_prt_ghi1 FOR VALUES IN ('ghi', 'ghi2'), + pt_ao_tab_1_prt_ghi2 FOR VALUES IN ('ghi1'), + pt_ao_tab_1_prt_jkl FOR VALUES IN ('jkl', 'jkl1', 'jkl2'), + pt_ao_tab_1_prt_mno FOR VALUES IN ('mno', 'mno1', 'mno2'), + pt_ao_tab_1_prt_pqr FOR VALUES IN ('pqr', 'pqr1', 'pqr2'), + pt_ao_tab_1_prt_stu FOR VALUES IN ('stu', 'stu1', 'stu2'), + pt_ao_tab_1_prt_xyz1 FOR VALUES IN ('xyz', 'xyz2'), + pt_ao_tab_1_prt_xyz2 FOR VALUES IN ('xyz1') +Distributed by: (a) + \d+ heap_can Table "public.heap_can" Column | Type | Collation | Nullable | Default | Storage | Stats target | Compression Type | Compression Level | Block Size | Description @@ -351,6 +404,33 @@ NOTICE: table doesn't have 'DISTRIBUTED BY' clause, defaulting to distribution alter table pt_co_tab exchange partition for ('pqr') with table co_can; -- AO exchanged with CO alter table pt_co_tab exchange partition for ('xyz1') with table heap_can; -- CO exchanged with Heap --Check for the storage properties and indexes of the two tables involved in the exchange + \d+ pt_co_tab + Partitioned table "public.pt_co_tab" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Compression Type | Compression Level | Block Size | Description +---------+---------+-----------+----------+---------+----------+--------------+------------------+-------------------+------------+------------- + a | integer | | | | plain | | none | 0 | 32768 | + b | text | | | | extended | | none | 0 | 32768 | + c | integer | | | | plain | | none | 0 | 32768 | + d | integer | | | | plain | | none | 0 | 32768 | + e | numeric | | | | main | | none | 0 | 32768 | + success | boolean | | | | plain | | none | 0 | 32768 | +Partition key: LIST (b) +Indexes: + "co_idx1" btree (a) WHERE c > 10 + "co_idx2" btree (upper(b)) +Partitions: pt_co_tab_1_prt_abc1 FOR VALUES IN ('abc', 'abc2'), + pt_co_tab_1_prt_abc2 FOR VALUES IN ('abc1'), + pt_co_tab_1_prt_def FOR VALUES IN ('def', 'def1', 'def3'), + pt_co_tab_1_prt_ghi1 FOR VALUES IN ('ghi', 'ghi2'), + pt_co_tab_1_prt_ghi2 FOR VALUES IN ('ghi1'), + pt_co_tab_1_prt_jkl FOR VALUES IN ('jkl', 'jkl1', 'jkl2'), + pt_co_tab_1_prt_mno FOR VALUES IN ('mno', 'mno1', 'mno2'), + pt_co_tab_1_prt_pqr FOR VALUES IN ('pqr', 'pqr1', 'pqr2'), + pt_co_tab_1_prt_stu FOR VALUES IN ('stu', 'stu1', 'stu2'), + pt_co_tab_1_prt_xyz1 FOR VALUES IN ('xyz', 'xyz2'), + pt_co_tab_1_prt_xyz2 FOR VALUES IN ('xyz1') +Distributed by: (a) + \d+ heap_can Table "public.heap_can" Column | Type | Collation | Nullable | Default | Storage | Stats target | Compression Type | Compression Level | Block Size | Description @@ -480,6 +560,34 @@ NOTICE: table doesn't have 'DISTRIBUTED BY' clause, defaulting to distribution alter table pt_heap_tab_rng exchange partition heap1 with table ao_can; -- HEAP <=> AO alter table pt_heap_tab_rng exchange partition newao with table co_can; -- AO <=> CO alter table pt_heap_tab_rng exchange partition newco with table heap_can; -- CO <=> HEAP + \d+ pt_heap_tab_rng + Partitioned table "public.pt_heap_tab_rng" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------+---------+-----------+----------+---------+----------+--------------+------------- + a | integer | | | | plain | | + b | text | | | | extended | | + c | integer | | | | plain | | + d | integer | | | | plain | | + e | numeric | | | | main | | + success | boolean | | | | plain | | +Partition key: RANGE (a) +Indexes: + "heap_rng_idx1" btree (a) WHERE c > 10 + "heap_rng_idx2" btree (upper(b)) +Partitions: pt_heap_tab_rng_1_prt_2 FOR VALUES FROM (1) TO (6), + pt_heap_tab_rng_1_prt_3 FOR VALUES FROM (6) TO (11), + pt_heap_tab_rng_1_prt_4 FOR VALUES FROM (11) TO (16), + pt_heap_tab_rng_1_prt_5 FOR VALUES FROM (16) TO (20), + pt_heap_tab_rng_1_prt_ao1 FOR VALUES FROM (25) TO (27), + pt_heap_tab_rng_1_prt_ao2 FOR VALUES FROM (27) TO (30), + pt_heap_tab_rng_1_prt_co1 FOR VALUES FROM (31) TO (33), + pt_heap_tab_rng_1_prt_co2 FOR VALUES FROM (33) TO (35), + pt_heap_tab_rng_1_prt_heap1 FOR VALUES FROM (21) TO (23), + pt_heap_tab_rng_1_prt_heap2 FOR VALUES FROM (23) TO (25), + pt_heap_tab_rng_1_prt_newao FOR VALUES FROM (40) TO (45), + pt_heap_tab_rng_1_prt_newco FOR VALUES FROM (36) TO (40) +Distributed by: (a) + \d+ ao_can Table "public.ao_can" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description @@ -604,6 +712,35 @@ NOTICE: table doesn't have 'DISTRIBUTED BY' clause, defaulting to distribution alter table pt_ao_tab_rng exchange partition newheap with table ao_can; -- HEAP <=> AO alter table pt_ao_tab_rng exchange partition ao1 with table co_can;-- AO <=> CO alter table pt_ao_tab_rng exchange partition newco with table heap_can; --CO <=> HEAP + \d+ pt_ao_tab_rng + Partitioned table "public.pt_ao_tab_rng" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------+---------+-----------+----------+---------+----------+--------------+------------- + a | integer | | | | plain | | + b | text | | | | extended | | + c | integer | | | | plain | | + d | integer | | | | plain | | + e | numeric | | | | main | | + success | boolean | | | | plain | | +Partition key: RANGE (a) +Indexes: + "ao_rng_idx1" btree (a) WHERE c > 10 + "ao_rng_idx2" btree (upper(b)) +Partitions: pt_ao_tab_rng_1_prt_2 FOR VALUES FROM (1) TO (6), + pt_ao_tab_rng_1_prt_3 FOR VALUES FROM (6) TO (11), + pt_ao_tab_rng_1_prt_4 FOR VALUES FROM (11) TO (16), + pt_ao_tab_rng_1_prt_5 FOR VALUES FROM (16) TO (20), + pt_ao_tab_rng_1_prt_ao1 FOR VALUES FROM (25) TO (27), + pt_ao_tab_rng_1_prt_ao2 FOR VALUES FROM (27) TO (30), + pt_ao_tab_rng_1_prt_co1 FOR VALUES FROM (31) TO (33), + pt_ao_tab_rng_1_prt_co2 FOR VALUES FROM (33) TO (35), + pt_ao_tab_rng_1_prt_heap1 FOR VALUES FROM (21) TO (23), + pt_ao_tab_rng_1_prt_heap2 FOR VALUES FROM (23) TO (25), + pt_ao_tab_rng_1_prt_newco FOR VALUES FROM (36) TO (40), + pt_ao_tab_rng_1_prt_newheap FOR VALUES FROM (40) TO (45) +Distributed by: (a) +Options: compresstype=zlib, compresslevel=1 + \d+ ao_can Table "public.ao_can" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description @@ -729,6 +866,35 @@ NOTICE: table doesn't have 'DISTRIBUTED BY' clause, defaulting to distribution alter table pt_co_tab_rng exchange partition newheap with table ao_can;-- HEAP <=> AO alter table pt_co_tab_rng exchange partition newao with table co_can; -- AO <=> CO alter table pt_co_tab_rng exchange partition co1 with table heap_can; -- CO <=> HEAP + \d+ pt_co_tab_rng + Partitioned table "public.pt_co_tab_rng" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Compression Type | Compression Level | Block Size | Description +---------+---------+-----------+----------+---------+----------+--------------+------------------+-------------------+------------+------------- + a | integer | | | | plain | | zlib | 1 | 32768 | + b | text | | | | extended | | zlib | 1 | 32768 | + c | integer | | | | plain | | zlib | 1 | 32768 | + d | integer | | | | plain | | zlib | 1 | 32768 | + e | numeric | | | | main | | zlib | 1 | 32768 | + success | boolean | | | | plain | | zlib | 1 | 32768 | +Partition key: RANGE (a) +Indexes: + "co_rng_idx1" btree (a) WHERE c > 10 + "co_rng_idx2" btree (upper(b)) +Partitions: pt_co_tab_rng_1_prt_2 FOR VALUES FROM (1) TO (6), + pt_co_tab_rng_1_prt_3 FOR VALUES FROM (6) TO (11), + pt_co_tab_rng_1_prt_4 FOR VALUES FROM (11) TO (16), + pt_co_tab_rng_1_prt_5 FOR VALUES FROM (16) TO (20), + pt_co_tab_rng_1_prt_ao1 FOR VALUES FROM (25) TO (27), + pt_co_tab_rng_1_prt_ao2 FOR VALUES FROM (27) TO (30), + pt_co_tab_rng_1_prt_co1 FOR VALUES FROM (31) TO (33), + pt_co_tab_rng_1_prt_co2 FOR VALUES FROM (33) TO (35), + pt_co_tab_rng_1_prt_heap1 FOR VALUES FROM (21) TO (23), + pt_co_tab_rng_1_prt_heap2 FOR VALUES FROM (23) TO (25), + pt_co_tab_rng_1_prt_newao FOR VALUES FROM (36) TO (40), + pt_co_tab_rng_1_prt_newheap FOR VALUES FROM (40) TO (45) +Distributed by: (a) +Options: compresstype=zlib, compresslevel=1 + \d+ ao_can Table "public.ao_can" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description diff --git a/src/test/regress/sql/column_compression.sql b/src/test/regress/sql/column_compression.sql index 5849a935d3a..041a73e86c3 100644 --- a/src/test/regress/sql/column_compression.sql +++ b/src/test/regress/sql/column_compression.sql @@ -452,6 +452,30 @@ partition by range(i) subpartition by range(j) execute ccddlcheck; drop table ccddl; +-- multi level partitioning with column encoding inheritance +create table ccddl (a int ENCODING (compresslevel=1), + b int ENCODING (compresslevel=1), + c int ENCODING (compresslevel=1), + d int ENCODING (compresslevel=1), + e int, f int, g int, h int) + with (appendonly = true, orientation=column, compresslevel=5) + partition by range(a) subpartition by range(b) + (partition p1 start(1) end(10) + (subpartition sp1 start(1) end(5) + column a encoding(compresslevel=3), + column d encoding(compresslevel=3), + column f encoding(compresslevel=3), + column g encoding(compresslevel=3)), + column a encoding(compresslevel=2), + column b encoding(compresslevel=2), + column e encoding(compresslevel=2), + column g encoding(compresslevel=2)); + +execute ccddlcheck; + +insert into ccddl select 2,3 from generate_series(1, 100); +select * from ccddl limit 5; +drop table ccddl; -- Precedence test: c3 in the partition child must be zlib, not RLE_TYPE CREATE TABLE ccddl ( c1 int ENCODING (compresstype=zlib), diff --git a/src/test/regress/sql/partition_storage.sql b/src/test/regress/sql/partition_storage.sql index fa3b0716cde..eab41a775be 100644 --- a/src/test/regress/sql/partition_storage.sql +++ b/src/test/regress/sql/partition_storage.sql @@ -60,6 +60,7 @@ alter table pt_heap_tab exchange partition for ('pqr') with table heap_can; -- CO exchanged with Heap --Check for the storage properties and indexes of the two tables involved in the exchange + \d+ pt_heap_tab \d+ heap_can \d+ co_can \d+ ao_can @@ -146,6 +147,7 @@ drop table if exists co_can cascade; alter table pt_ao_tab exchange partition for ('pqr') with table heap_can; --CO tab exchanged with Heap --Check for the storage properties and indexes of the two tables involved in the exchange + \d+ pt_ao_tab \d+ heap_can \d+ co_can \d+ ao_can @@ -239,6 +241,7 @@ drop table if exists co_can cascade; alter table pt_co_tab exchange partition for ('xyz1') with table heap_can; -- CO exchanged with Heap --Check for the storage properties and indexes of the two tables involved in the exchange + \d+ pt_co_tab \d+ heap_can \d+ co_can \d+ ao_can @@ -315,6 +318,7 @@ drop table if exists co_can cascade; alter table pt_heap_tab_rng exchange partition newao with table co_can; -- AO <=> CO alter table pt_heap_tab_rng exchange partition newco with table heap_can; -- CO <=> HEAP + \d+ pt_heap_tab_rng \d+ ao_can \d+ co_can \d+ heap_can @@ -386,6 +390,7 @@ drop table if exists co_can cascade; alter table pt_ao_tab_rng exchange partition ao1 with table co_can;-- AO <=> CO alter table pt_ao_tab_rng exchange partition newco with table heap_can; --CO <=> HEAP + \d+ pt_ao_tab_rng \d+ ao_can \d+ co_can \d+ heap_can @@ -458,6 +463,7 @@ drop table if exists co_can cascade; alter table pt_co_tab_rng exchange partition newao with table co_can; -- AO <=> CO alter table pt_co_tab_rng exchange partition co1 with table heap_can; -- CO <=> HEAP + \d+ pt_co_tab_rng \d+ ao_can \d+ co_can \d+ heap_can