Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/backend/access/common/reloptions_gp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 10 additions & 8 deletions src/backend/commands/tablecmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))) &&
Expand Down Expand Up @@ -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 =
Expand All @@ -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);

/*
Expand Down
1 change: 1 addition & 0 deletions src/include/access/reloptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
243 changes: 243 additions & 0 deletions src/test/regress/expected/alter_table_set.out
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Loading