diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index 4cbaaccaf7..fb0e987387 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -398,7 +398,13 @@ WITH ( MODULUS numeric_literal, REM - Column STORAGE settings are also copied from parent tables. + Column storage and compression settings are inherited from parent + tables. If a column is inherited from multiple tables, the storage + settings or any explicit compression settings for the column must be the + same in all parent tables, else an error is reported. Storage or + compression settings explicitly specified for the new table override any + inherited settings and can also be used to override conflicting + inherited settings. diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index fe47be38d0..ee604cea29 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -974,3 +974,26 @@ makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace) return pstrdup(buf); } + +/* + * GetAttributeStorageName + * returns the name corresponding to a typstorage/attstorage enum value. + */ +const char * +GetAttributeStorageName(char c) +{ + switch (c) + { + case TYPSTORAGE_PLAIN: + return "PLAIN"; + case TYPSTORAGE_EXTERNAL: + return "EXTERNAL"; + case TYPSTORAGE_EXTENDED: + return "EXTENDED"; + case TYPSTORAGE_MAIN: + return "MAIN"; + default: + elog(ERROR, "invalid storage type %c", c); + return NULL; + } +} diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 86ea3a228b..237eeeec67 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -350,6 +350,16 @@ typedef struct ForeignTruncateInfo #define child_dependency_type(child_is_partition) \ ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL) +/* + * Bogus property string to track conflict in inherited properties of a column. + * It is currently used for storage and compression specifications, but may be + * used for other string specifications in future. It can be any string which + * does not look like a valid compression or storage method. It is meant to be + * used by MergeAttributes() and its minions. It is not expected to be stored + * on disk. + */ +static const char *conflicting_column_property = "*** conflicting column property ***"; + static void truncate_check_rel(Oid relid, Form_pg_class reltuple); static void truncate_check_perms(Oid relid, Form_pg_class reltuple); static void truncate_check_activity(Relation rel); @@ -360,7 +370,8 @@ static List *MergeAttributes(List *columns, const List *supers, char relpersiste List **supnotnulls); static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr); static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef); -static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef); +static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef, + bool *have_deferred_conflicts); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); static void StoreCatalogInheritance(Oid relationId, List *supers, @@ -620,7 +631,6 @@ static ObjectAddress ATExecSetCompression(Relation rel, const char *column, Node *newValue, LOCKMODE lockmode); static void index_copy_data(Relation rel, RelFileLocator newrlocator); -static const char *storage_name(char c); static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg); @@ -1363,9 +1373,7 @@ BuildDescForRelation(const List *columns) att->attidentity = entry->identity; att->attgenerated = entry->generated; att->attcompression = GetAttributeCompression(att->atttypid, entry->compression); - if (entry->storage) - att->attstorage = entry->storage; - else if (entry->storage_name) + if (entry->storage_name) att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name); } @@ -2388,28 +2396,6 @@ truncate_check_activity(Relation rel) CheckTableNotInUse(rel, "TRUNCATE"); } -/* - * storage_name - * returns the name corresponding to a typstorage/attstorage enum value - */ -static const char * -storage_name(char c) -{ - switch (c) - { - case TYPSTORAGE_PLAIN: - return "PLAIN"; - case TYPSTORAGE_EXTERNAL: - return "EXTERNAL"; - case TYPSTORAGE_EXTENDED: - return "EXTENDED"; - case TYPSTORAGE_MAIN: - return "MAIN"; - default: - return "???"; - } -} - /*---------- * MergeAttributes * Returns new schema given initial schema and superclasses. @@ -2483,7 +2469,7 @@ MergeAttributes(List *columns, const List *supers, char relpersistence, List *inh_columns = NIL; List *constraints = NIL; List *nnconstraints = NIL; - bool have_bogus_defaults = false; + bool have_deferred_conflicts = false; int child_attno; static Node bogus_marker = {0}; /* marks conflicting defaults */ List *saved_columns = NIL; @@ -2720,11 +2706,10 @@ MergeAttributes(List *columns, const List *supers, char relpersistence, */ newdef = makeColumnDef(attributeName, attribute->atttypid, attribute->atttypmod, attribute->attcollation); - newdef->storage = attribute->attstorage; + newdef->storage_name = GetAttributeStorageName(attribute->attstorage); newdef->generated = attribute->attgenerated; if (CompressionMethodIsValid(attribute->attcompression)) - newdef->compression = - pstrdup(GetCompressionMethodName(attribute->attcompression)); + newdef->compression = GetCompressionMethodName(attribute->attcompression); /* * Regular inheritance children are independent enough not to @@ -2744,7 +2729,8 @@ MergeAttributes(List *columns, const List *supers, char relpersistence, /* * Yes, try to merge the two column definitions. */ - mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef); + mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef, + &have_deferred_conflicts); newattmap->attnums[parent_attno - 1] = exist_attno; @@ -2867,7 +2853,7 @@ MergeAttributes(List *columns, const List *supers, char relpersistence, else if (!equal(def->cooked_default, this_default)) { def->cooked_default = &bogus_marker; - have_bogus_defaults = true; + have_deferred_conflicts = true; } } @@ -3077,10 +3063,10 @@ MergeAttributes(List *columns, const List *supers, char relpersistence, } /* - * If we found any conflicting parent default values, check to make sure - * they were overridden by the child. + * If we found any conflicting parent default values or conflicting parent + * properties, check to make sure they were overridden by the child. */ - if (have_bogus_defaults) + if (have_deferred_conflicts) { foreach(lc, columns) { @@ -3101,6 +3087,20 @@ MergeAttributes(List *columns, const List *supers, char relpersistence, def->colname), errhint("To resolve the conflict, specify a default explicitly."))); } + + if (def->compression == conflicting_column_property) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("column \"%s\" inherits conflicting compression methods", + def->colname), + errhint("To resolve the conflict, specify a compression method explicitly."))); + + if (def->storage_name == conflicting_column_property) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("column \"%s\" inherits conflicting storage methods", + def->colname), + errhint("To resolve the conflict, specify a storage method explicitly."))); } } @@ -3250,33 +3250,18 @@ MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const inhdef->identity = newdef->identity; /* - * Copy storage parameter + * Child storage specification, if any, overrides inherited storage + * property. */ - if (inhdef->storage == 0) - inhdef->storage = newdef->storage; - else if (newdef->storage != 0 && inhdef->storage != newdef->storage) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("column \"%s\" has a storage parameter conflict", - attributeName), - errdetail("%s versus %s", - storage_name(inhdef->storage), - storage_name(newdef->storage)))); + if (newdef->storage_name != NULL) + inhdef->storage_name = newdef->storage_name; /* - * Copy compression parameter + * Child compression specification, if any, overrides inherited + * compression property. */ - if (inhdef->compression == NULL) + if (newdef->compression != NULL) inhdef->compression = newdef->compression; - else if (newdef->compression != NULL) - { - if (strcmp(inhdef->compression, newdef->compression) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("column \"%s\" has a compression method conflict", - attributeName), - errdetail("%s versus %s", inhdef->compression, newdef->compression))); - } /* * Merge of not-null constraints = OR 'em together @@ -3343,6 +3328,10 @@ MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const * 'exist_attno' is the number the existing matching attribute in inh_columns. * 'newdef' is the new parent column/attribute definition to be merged. * + * Output arguments: + * 'have_deferred_conflicts' is set to true if there is a conflict in inherited + * compression properties; remains unchanged otherwise. + * * The matching ColumnDef in 'inh_columns' list is modified and returned. * * Notes: @@ -3356,7 +3345,8 @@ MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const static ColumnDef * MergeInheritedAttribute(List *inh_columns, int exist_attno, - const ColumnDef *newdef) + const ColumnDef *newdef, + bool *have_deferred_conflicts) { char *attributeName = newdef->colname; ColumnDef *prevdef; @@ -3403,28 +3393,26 @@ MergeInheritedAttribute(List *inh_columns, /* * Copy/check storage parameter */ - if (prevdef->storage == 0) - prevdef->storage = newdef->storage; - else if (prevdef->storage != newdef->storage) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("inherited column \"%s\" has a storage parameter conflict", - attributeName), - errdetail("%s versus %s", - storage_name(prevdef->storage), - storage_name(newdef->storage)))); + if (prevdef->storage_name == NULL) + prevdef->storage_name = newdef->storage_name; + else if (newdef->storage_name != NULL && + strcmp(prevdef->storage_name, newdef->storage_name) != 0) + { + prevdef->storage_name = conflicting_column_property; + *have_deferred_conflicts = true; + } /* * Copy/check compression parameter */ if (prevdef->compression == NULL) prevdef->compression = newdef->compression; - else if (strcmp(prevdef->compression, newdef->compression) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("column \"%s\" has a compression method conflict", - attributeName), - errdetail("%s versus %s", prevdef->compression, newdef->compression))); + else if (newdef->compression != NULL && + strcmp(prevdef->compression, newdef->compression) != 0) + { + prevdef->compression = conflicting_column_property; + *have_deferred_conflicts = true; + } /* * Check for GENERATED conflicts diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index a02332a1ec..86b8dcfe7e 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -500,7 +500,7 @@ makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid) n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->storage = 0; + n->storage_name = NULL; n->raw_default = NULL; n->cooked_default = NULL; n->collClause = NULL; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 130f7fc7c3..60b31d9f85 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -3754,7 +3754,6 @@ columnDef: ColId Typename opt_column_storage opt_column_compression create_gener n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->storage = 0; n->raw_default = NULL; n->cooked_default = NULL; n->collOid = InvalidOid; @@ -3776,7 +3775,7 @@ columnOptions: ColId ColQualList n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->storage = 0; + n->storage_name = NULL; n->raw_default = NULL; n->cooked_default = NULL; n->collOid = InvalidOid; @@ -3795,7 +3794,7 @@ columnOptions: ColId ColQualList n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->storage = 0; + n->storage_name = NULL; n->raw_default = NULL; n->cooked_default = NULL; n->collOid = InvalidOid; @@ -13858,7 +13857,7 @@ TableFuncElement: ColId Typename opt_collate_clause n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->storage = 0; + n->storage_name = NULL; n->raw_default = NULL; n->cooked_default = NULL; n->collClause = (CollateClause *) $3; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index c7efd8d8ce..8dcf794ca2 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -1134,15 +1134,14 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla /* Likewise, copy storage if requested */ if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) - def->storage = attribute->attstorage; + def->storage_name = GetAttributeStorageName(attribute->attstorage); else - def->storage = 0; + def->storage_name = NULL; /* Likewise, copy compression if requested */ if ((table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) != 0 && CompressionMethodIsValid(attribute->attcompression)) - def->compression = - pstrdup(GetCompressionMethodName(attribute->attcompression)); + def->compression = GetCompressionMethodName(attribute->attcompression); else def->compression = NULL; diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index e925969732..38ca117480 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -404,4 +404,6 @@ extern bool moveArrayTypeName(Oid typeOid, const char *typeName, extern char *makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace); +extern const char *GetAttributeStorageName(char storage); + #endif /* PG_TYPE_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 476d55dd24..d5b08ded44 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -712,13 +712,12 @@ typedef struct ColumnDef NodeTag type; char *colname; /* name of column */ TypeName *typeName; /* type of column */ - char *compression; /* compression method for column */ + const char *compression; /* compression method for column */ int inhcount; /* number of times column is inherited */ bool is_local; /* column has local (non-inherited) def'n */ bool is_not_null; /* NOT NULL constraint specified? */ bool is_from_type; /* column definition came from table type */ - char storage; /* attstorage setting, or 0 for default */ - char *storage_name; /* attstorage setting name or NULL for default */ + const char *storage_name; /* attstorage setting name or NULL for default */ Node *raw_default; /* default value (untransformed parse tree) */ Node *cooked_default; /* default value (transformed expr tree) */ char identity; /* attidentity setting */ diff --git a/src/test/regress/expected/compression.out b/src/test/regress/expected/compression.out index 834b7555cb..c22a71f8bd 100644 --- a/src/test/regress/expected/compression.out +++ b/src/test/regress/expected/compression.out @@ -223,15 +223,102 @@ SELECT pg_column_compression(f1) FROM cmpart2; pglz (1 row) --- test compression with inheritance, error -CREATE TABLE cminh() INHERITS(cmdata, cmdata1); -NOTICE: merging multiple inherited definitions of column "f1" -ERROR: column "f1" has a compression method conflict -DETAIL: pglz versus lz4 -CREATE TABLE cminh(f1 TEXT COMPRESSION lz4) INHERITS(cmdata); +-- test compression with inheritance +CREATE TABLE cmparent1 (f1 TEXT COMPRESSION pglz); +INSERT INTO cmparent1 VALUES ('cmparent1_' || repeat('1234567890', 1000)); +CREATE TABLE cmparent2 (f1 TEXT COMPRESSION lz4); +INSERT INTO cmparent2 VALUES ('cmparent2_' || repeat('1234567890', 1000)); +CREATE TABLE ncmparent (f1 TEXT); -- parent without compression +INSERT INTO ncmparent VALUES ('ncmparent_' || repeat('1234567890', 1000)); +CREATE TABLE cminh1(f1 TEXT) INHERITS(cmparent1); NOTICE: merging column "f1" with inherited definition -ERROR: column "f1" has a compression method conflict -DETAIL: pglz versus lz4 +INSERT INTO cminh1 VALUES ('cminh1_' || repeat('1234567890', 1000)); +CREATE TABLE cminh2(f1 TEXT) INHERITS(ncmparent, cmparent1); +NOTICE: merging multiple inherited definitions of column "f1" +NOTICE: merging column "f1" with inherited definition +INSERT INTO cminh2 VALUES ('cminh2_' || repeat('1234567890', 1000)); +CREATE TABLE cminh3(f1 TEXT) INHERITS(cmparent1, ncmparent); +NOTICE: merging multiple inherited definitions of column "f1" +NOTICE: merging column "f1" with inherited definition +INSERT INTO cminh3 VALUES ('cminh3_' || repeat('1234567890', 1000)); +-- conflicting compression methods from parents +CREATE TABLE cminh() INHERITS(cmparent1, cmparent2); --error +NOTICE: merging multiple inherited definitions of column "f1" +ERROR: column "f1" inherits conflicting compression methods +HINT: To resolve the conflict, specify a compression method explicitly. +CREATE TABLE cminh(f1 TEXT) INHERITS(cmparent1, cmparent2); --error +NOTICE: merging multiple inherited definitions of column "f1" +NOTICE: merging column "f1" with inherited definition +ERROR: column "f1" inherits conflicting compression methods +HINT: To resolve the conflict, specify a compression method explicitly. +-- child compression specification takes precedence, even if parent's +-- compression conflict +CREATE TABLE cminh4(f1 TEXT COMPRESSION lz4) INHERITS(cmparent1); +NOTICE: merging column "f1" with inherited definition +INSERT INTO cminh4 VALUES ('cminh4_' || repeat('1234567890', 1000)); +CREATE TABLE cminh5(f1 TEXT COMPRESSION pglz) INHERITS(cmparent1, cmparent2); +NOTICE: merging multiple inherited definitions of column "f1" +NOTICE: merging column "f1" with inherited definition +INSERT INTO cminh5 VALUES ('cminh5_' || repeat('1234567890', 1000)); +SELECT tableoid::regclass, pg_column_compression(f1) FROM cmparent1; + tableoid | pg_column_compression +-----------+----------------------- + cmparent1 | pglz + cminh1 | pglz + cminh2 | pglz + cminh3 | pglz + cminh4 | lz4 + cminh5 | pglz +(6 rows) + +SELECT tableoid::regclass, pg_column_compression(f1) FROM cmparent2; + tableoid | pg_column_compression +-----------+----------------------- + cmparent2 | lz4 + cminh5 | pglz +(2 rows) + +SELECT tableoid::regclass, pg_column_compression(f1) FROM ncmparent; + tableoid | pg_column_compression +-----------+----------------------- + ncmparent | pglz + cminh2 | pglz + cminh3 | pglz +(3 rows) + +-- ALTER compression specification in child +ALTER TABLE cminh1 ALTER COLUMN f1 SET COMPRESSION lz4; +INSERT INTO cminh1 VALUES ('cminh1_lz4_' || repeat('1234567890', 1000)); +SELECT pg_column_compression(f1) FROM cminh1; + pg_column_compression +----------------------- + pglz + lz4 +(2 rows) + +-- INHERIT through ALTER TABLE +CREATE TABLE cminh6 (f1 TEXT); +INSERT INTO cminh6 VALUES ('cminh6_' || repeat('1234567890', 1000)); +ALTER TABLE cminh6 INHERIT cmparent1; +INSERT INTO cminh6 VALUES ('cminh6_inh_' || repeat('1234567890', 1000)); +SELECT pg_column_compression(f1) FROM cminh6; + pg_column_compression +----------------------- + pglz + pglz +(2 rows) + +CREATE TABLE cminh7 (f1 TEXT COMPRESSION lz4); +INSERT INTO cminh7 VALUES ('cminh7_' || repeat('1234567890', 1000)); +ALTER TABLE cminh7 INHERIT cmparent1; +INSERT INTO cminh7 VALUES ('cminh7_inh_' || repeat('1234567890', 1000)); +SELECT pg_column_compression(f1) FROM cminh7; + pg_column_compression +----------------------- + lz4 + lz4 +(2 rows) + -- test default_toast_compression GUC SET default_toast_compression = ''; ERROR: invalid value for parameter "default_toast_compression": "" diff --git a/src/test/regress/expected/compression_1.out b/src/test/regress/expected/compression_1.out index ddcd137c49..d70155d5d0 100644 --- a/src/test/regress/expected/compression_1.out +++ b/src/test/regress/expected/compression_1.out @@ -216,13 +216,112 @@ SELECT pg_column_compression(f1) FROM cmpart2; ----------------------- (0 rows) --- test compression with inheritance, error -CREATE TABLE cminh() INHERITS(cmdata, cmdata1); -ERROR: relation "cmdata1" does not exist -CREATE TABLE cminh(f1 TEXT COMPRESSION lz4) INHERITS(cmdata); +-- test compression with inheritance +CREATE TABLE cmparent1 (f1 TEXT COMPRESSION pglz); +INSERT INTO cmparent1 VALUES ('cmparent1_' || repeat('1234567890', 1000)); +CREATE TABLE cmparent2 (f1 TEXT COMPRESSION lz4); +ERROR: compression method lz4 not supported +DETAIL: This functionality requires the server to be built with lz4 support. +INSERT INTO cmparent2 VALUES ('cmparent2_' || repeat('1234567890', 1000)); +ERROR: relation "cmparent2" does not exist +LINE 1: INSERT INTO cmparent2 VALUES ('cmparent2_' || repeat('123456... + ^ +CREATE TABLE ncmparent (f1 TEXT); -- parent without compression +INSERT INTO ncmparent VALUES ('ncmparent_' || repeat('1234567890', 1000)); +CREATE TABLE cminh1(f1 TEXT) INHERITS(cmparent1); NOTICE: merging column "f1" with inherited definition -ERROR: column "f1" has a compression method conflict -DETAIL: pglz versus lz4 +INSERT INTO cminh1 VALUES ('cminh1_' || repeat('1234567890', 1000)); +CREATE TABLE cminh2(f1 TEXT) INHERITS(ncmparent, cmparent1); +NOTICE: merging multiple inherited definitions of column "f1" +NOTICE: merging column "f1" with inherited definition +INSERT INTO cminh2 VALUES ('cminh2_' || repeat('1234567890', 1000)); +CREATE TABLE cminh3(f1 TEXT) INHERITS(cmparent1, ncmparent); +NOTICE: merging multiple inherited definitions of column "f1" +NOTICE: merging column "f1" with inherited definition +INSERT INTO cminh3 VALUES ('cminh3_' || repeat('1234567890', 1000)); +-- conflicting compression methods from parents +CREATE TABLE cminh() INHERITS(cmparent1, cmparent2); --error +ERROR: relation "cmparent2" does not exist +CREATE TABLE cminh(f1 TEXT) INHERITS(cmparent1, cmparent2); --error +ERROR: relation "cmparent2" does not exist +-- child compression specification takes precedence, even if parent's +-- compression conflict +CREATE TABLE cminh4(f1 TEXT COMPRESSION lz4) INHERITS(cmparent1); +NOTICE: merging column "f1" with inherited definition +ERROR: compression method lz4 not supported +DETAIL: This functionality requires the server to be built with lz4 support. +INSERT INTO cminh4 VALUES ('cminh4_' || repeat('1234567890', 1000)); +ERROR: relation "cminh4" does not exist +LINE 1: INSERT INTO cminh4 VALUES ('cminh4_' || repeat('1234567890',... + ^ +CREATE TABLE cminh5(f1 TEXT COMPRESSION pglz) INHERITS(cmparent1, cmparent2); +ERROR: relation "cmparent2" does not exist +INSERT INTO cminh5 VALUES ('cminh5_' || repeat('1234567890', 1000)); +ERROR: relation "cminh5" does not exist +LINE 1: INSERT INTO cminh5 VALUES ('cminh5_' || repeat('1234567890',... + ^ +SELECT tableoid::regclass, pg_column_compression(f1) FROM cmparent1; + tableoid | pg_column_compression +-----------+----------------------- + cmparent1 | pglz + cminh1 | pglz + cminh2 | pglz + cminh3 | pglz +(4 rows) + +SELECT tableoid::regclass, pg_column_compression(f1) FROM cmparent2; +ERROR: relation "cmparent2" does not exist +LINE 1: ...ableoid::regclass, pg_column_compression(f1) FROM cmparent2; + ^ +SELECT tableoid::regclass, pg_column_compression(f1) FROM ncmparent; + tableoid | pg_column_compression +-----------+----------------------- + ncmparent | pglz + cminh2 | pglz + cminh3 | pglz +(3 rows) + +-- ALTER compression specification in child +ALTER TABLE cminh1 ALTER COLUMN f1 SET COMPRESSION lz4; +ERROR: compression method lz4 not supported +DETAIL: This functionality requires the server to be built with lz4 support. +INSERT INTO cminh1 VALUES ('cminh1_lz4_' || repeat('1234567890', 1000)); +SELECT pg_column_compression(f1) FROM cminh1; + pg_column_compression +----------------------- + pglz + pglz +(2 rows) + +-- INHERIT through ALTER TABLE +CREATE TABLE cminh6 (f1 TEXT); +INSERT INTO cminh6 VALUES ('cminh6_' || repeat('1234567890', 1000)); +ALTER TABLE cminh6 INHERIT cmparent1; +INSERT INTO cminh6 VALUES ('cminh6_inh_' || repeat('1234567890', 1000)); +SELECT pg_column_compression(f1) FROM cminh6; + pg_column_compression +----------------------- + pglz + pglz +(2 rows) + +CREATE TABLE cminh7 (f1 TEXT COMPRESSION lz4); +ERROR: compression method lz4 not supported +DETAIL: This functionality requires the server to be built with lz4 support. +INSERT INTO cminh7 VALUES ('cminh7_' || repeat('1234567890', 1000)); +ERROR: relation "cminh7" does not exist +LINE 1: INSERT INTO cminh7 VALUES ('cminh7_' || repeat('1234567890',... + ^ +ALTER TABLE cminh7 INHERIT cmparent1; +ERROR: relation "cminh7" does not exist +INSERT INTO cminh7 VALUES ('cminh7_inh_' || repeat('1234567890', 1000)); +ERROR: relation "cminh7" does not exist +LINE 1: INSERT INTO cminh7 VALUES ('cminh7_inh_' || repeat('12345678... + ^ +SELECT pg_column_compression(f1) FROM cminh7; +ERROR: relation "cminh7" does not exist +LINE 1: SELECT pg_column_compression(f1) FROM cminh7; + ^ -- test default_toast_compression GUC SET default_toast_compression = ''; ERROR: invalid value for parameter "default_toast_compression": "" diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index 61956773ff..fb786d35a3 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -445,12 +445,10 @@ SELECT s.stxname, objsubid, description FROM pg_description, pg_statistic_ext s CREATE TABLE inh_error1 () INHERITS (ctlt1, ctlt4); NOTICE: merging multiple inherited definitions of column "a" -ERROR: inherited column "a" has a storage parameter conflict -DETAIL: MAIN versus EXTENDED -CREATE TABLE inh_error2 (LIKE ctlt4 INCLUDING STORAGE) INHERITS (ctlt1); +ERROR: column "a" inherits conflicting storage methods +HINT: To resolve the conflict, specify a storage method explicitly. +CREATE TABLE ctlt14_inh_like (LIKE ctlt4 INCLUDING STORAGE) INHERITS (ctlt1); NOTICE: merging column "a" with inherited definition -ERROR: column "a" has a storage parameter conflict -DETAIL: MAIN versus EXTENDED -- Check that LIKE isn't confused by a system catalog of the same name CREATE TABLE pg_attrdef (LIKE ctlt1 INCLUDING ALL); \d+ public.pg_attrdef @@ -493,7 +491,9 @@ Statistics objects: ROLLBACK; DROP TABLE ctlt1, ctlt2, ctlt3, ctlt4, ctlt12_storage, ctlt12_comments, ctlt1_inh, ctlt13_inh, ctlt13_like, ctlt_all, ctla, ctlb CASCADE; -NOTICE: drop cascades to table inhe +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table inhe +drop cascades to table ctlt14_inh_like -- LIKE must respect NO INHERIT property of constraints CREATE TABLE noinh_con_copy (a int CHECK (a > 0) NO INHERIT); CREATE TABLE noinh_con_copy1 (LIKE noinh_con_copy INCLUDING CONSTRAINTS); diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 130a924228..1e6cc8e9ba 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -3419,3 +3419,41 @@ UPDATE errtst_parent SET partid = 30, data = data + 10 WHERE partid = 20; ERROR: no partition of relation "errtst_parent" found for row DETAIL: Partition key of the failing row contains (partid) = (30). DROP TABLE errtst_parent; +-- storage and inheritance +CREATE TABLE stparent1 (a TEXT STORAGE plain); +CREATE TABLE stparent2 (a TEXT); +-- child inherits parent's storage properties, if they do not conflict +CREATE TABLE stchild1 (a TEXT) INHERITS (stparent1); +NOTICE: merging column "a" with inherited definition +CREATE TABLE stchild2 (a TEXT) INHERITS (stparent1, stparent2); +NOTICE: merging multiple inherited definitions of column "a" +NOTICE: merging column "a" with inherited definition +ERROR: column "a" inherits conflicting storage methods +HINT: To resolve the conflict, specify a storage method explicitly. +-- child overrides parent's storage properties even if they conflict +CREATE TABLE stchild3 (a TEXT STORAGE main) INHERITS (stparent1); +NOTICE: merging column "a" with inherited definition +CREATE TABLE stchild4 (a TEXT STORAGE main) INHERITS (stparent1, stparent2); +NOTICE: merging multiple inherited definitions of column "a" +NOTICE: merging column "a" with inherited definition +-- child storage properties are not changed when inheriting after creation. +CREATE TABLE stchild5 (a TEXT); +ALTER TABLE stchild5 INHERIT stparent1; +CREATE TABLE stchild6 (a TEXT STORAGE main); +ALTER TABLE stchild6 INHERIT stparent1; +SELECT attrelid::regclass, attname, attstorage FROM pg_attribute + WHERE (attrelid::regclass::name like 'stparent%' + OR attrelid::regclass::name like 'stchild%') + and attname = 'a' + ORDER BY 1, 2; + attrelid | attname | attstorage +-----------+---------+------------ + stparent1 | a | p + stparent2 | a | x + stchild1 | a | p + stchild3 | a | m + stchild4 | a | m + stchild5 | a | x + stchild6 | a | m +(7 rows) + diff --git a/src/test/regress/sql/compression.sql b/src/test/regress/sql/compression.sql index 7179a5002e..ad8e7afd2a 100644 --- a/src/test/regress/sql/compression.sql +++ b/src/test/regress/sql/compression.sql @@ -93,9 +93,46 @@ INSERT INTO cmpart VALUES (repeat('123456789', 4004)); SELECT pg_column_compression(f1) FROM cmpart1; SELECT pg_column_compression(f1) FROM cmpart2; --- test compression with inheritance, error -CREATE TABLE cminh() INHERITS(cmdata, cmdata1); -CREATE TABLE cminh(f1 TEXT COMPRESSION lz4) INHERITS(cmdata); +-- test compression with inheritance +CREATE TABLE cmparent1 (f1 TEXT COMPRESSION pglz); +INSERT INTO cmparent1 VALUES ('cmparent1_' || repeat('1234567890', 1000)); +CREATE TABLE cmparent2 (f1 TEXT COMPRESSION lz4); +INSERT INTO cmparent2 VALUES ('cmparent2_' || repeat('1234567890', 1000)); +CREATE TABLE ncmparent (f1 TEXT); -- parent without compression +INSERT INTO ncmparent VALUES ('ncmparent_' || repeat('1234567890', 1000)); +CREATE TABLE cminh1(f1 TEXT) INHERITS(cmparent1); +INSERT INTO cminh1 VALUES ('cminh1_' || repeat('1234567890', 1000)); +CREATE TABLE cminh2(f1 TEXT) INHERITS(ncmparent, cmparent1); +INSERT INTO cminh2 VALUES ('cminh2_' || repeat('1234567890', 1000)); +CREATE TABLE cminh3(f1 TEXT) INHERITS(cmparent1, ncmparent); +INSERT INTO cminh3 VALUES ('cminh3_' || repeat('1234567890', 1000)); +-- conflicting compression methods from parents +CREATE TABLE cminh() INHERITS(cmparent1, cmparent2); --error +CREATE TABLE cminh(f1 TEXT) INHERITS(cmparent1, cmparent2); --error +-- child compression specification takes precedence, even if parent's +-- compression conflict +CREATE TABLE cminh4(f1 TEXT COMPRESSION lz4) INHERITS(cmparent1); +INSERT INTO cminh4 VALUES ('cminh4_' || repeat('1234567890', 1000)); +CREATE TABLE cminh5(f1 TEXT COMPRESSION pglz) INHERITS(cmparent1, cmparent2); +INSERT INTO cminh5 VALUES ('cminh5_' || repeat('1234567890', 1000)); +SELECT tableoid::regclass, pg_column_compression(f1) FROM cmparent1; +SELECT tableoid::regclass, pg_column_compression(f1) FROM cmparent2; +SELECT tableoid::regclass, pg_column_compression(f1) FROM ncmparent; +-- ALTER compression specification in child +ALTER TABLE cminh1 ALTER COLUMN f1 SET COMPRESSION lz4; +INSERT INTO cminh1 VALUES ('cminh1_lz4_' || repeat('1234567890', 1000)); +SELECT pg_column_compression(f1) FROM cminh1; +-- INHERIT through ALTER TABLE +CREATE TABLE cminh6 (f1 TEXT); +INSERT INTO cminh6 VALUES ('cminh6_' || repeat('1234567890', 1000)); +ALTER TABLE cminh6 INHERIT cmparent1; +INSERT INTO cminh6 VALUES ('cminh6_inh_' || repeat('1234567890', 1000)); +SELECT pg_column_compression(f1) FROM cminh6; +CREATE TABLE cminh7 (f1 TEXT COMPRESSION lz4); +INSERT INTO cminh7 VALUES ('cminh7_' || repeat('1234567890', 1000)); +ALTER TABLE cminh7 INHERIT cmparent1; +INSERT INTO cminh7 VALUES ('cminh7_inh_' || repeat('1234567890', 1000)); +SELECT pg_column_compression(f1) FROM cminh7; -- test default_toast_compression GUC SET default_toast_compression = ''; diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql index 4929d373a2..9c5758a72b 100644 --- a/src/test/regress/sql/create_table_like.sql +++ b/src/test/regress/sql/create_table_like.sql @@ -168,7 +168,7 @@ SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_clas SELECT s.stxname, objsubid, description FROM pg_description, pg_statistic_ext s WHERE classoid = 'pg_statistic_ext'::regclass AND objoid = s.oid AND s.stxrelid = 'ctlt_all'::regclass ORDER BY s.stxname, objsubid; CREATE TABLE inh_error1 () INHERITS (ctlt1, ctlt4); -CREATE TABLE inh_error2 (LIKE ctlt4 INCLUDING STORAGE) INHERITS (ctlt1); +CREATE TABLE ctlt14_inh_like (LIKE ctlt4 INCLUDING STORAGE) INHERITS (ctlt1); -- Check that LIKE isn't confused by a system catalog of the same name CREATE TABLE pg_attrdef (LIKE ctlt1 INCLUDING ALL); diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index 0ef9a61bc1..6e629121ae 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -1354,3 +1354,23 @@ UPDATE errtst_parent SET partid = 0, data = data + 10 WHERE partid = 20; UPDATE errtst_parent SET partid = 30, data = data + 10 WHERE partid = 20; DROP TABLE errtst_parent; + +-- storage and inheritance +CREATE TABLE stparent1 (a TEXT STORAGE plain); +CREATE TABLE stparent2 (a TEXT); +-- child inherits parent's storage properties, if they do not conflict +CREATE TABLE stchild1 (a TEXT) INHERITS (stparent1); +CREATE TABLE stchild2 (a TEXT) INHERITS (stparent1, stparent2); +-- child overrides parent's storage properties even if they conflict +CREATE TABLE stchild3 (a TEXT STORAGE main) INHERITS (stparent1); +CREATE TABLE stchild4 (a TEXT STORAGE main) INHERITS (stparent1, stparent2); +-- child storage properties are not changed when inheriting after creation. +CREATE TABLE stchild5 (a TEXT); +ALTER TABLE stchild5 INHERIT stparent1; +CREATE TABLE stchild6 (a TEXT STORAGE main); +ALTER TABLE stchild6 INHERIT stparent1; +SELECT attrelid::regclass, attname, attstorage FROM pg_attribute + WHERE (attrelid::regclass::name like 'stparent%' + OR attrelid::regclass::name like 'stchild%') + and attname = 'a' + ORDER BY 1, 2;