Improve compression and storage support with inheritance

A child table can specify a compression or storage method different
from its parents.  This was previously an error.  (But this was
inconsistently enforced because for example the settings could be
changed later using ALTER TABLE.)  This now also allows an explicit
override if multiple parents have different compression or storage
settings, which was previously an error that could not be overridden.

The compression and storage properties remains unchanged in a child
inheriting from parent(s) after its creation, i.e., when using ALTER
TABLE ...  INHERIT.  (This is not changed.)

Before this change, the error detail would mention the first pair of
conflicting parent compression or storage methods.  But with this
change it waits till the child specification is considered by which
time we may have encountered many such conflicting pairs.  Hence the
error detail after this change does not include the conflicting
compression/storage methods.  Those can be obtained from parent
definitions if necessary.  The code to maintain list of all
conflicting methods or even the first conflicting pair does not seem
worth the convenience it offers.  This change is inline with what we
do with conflicting default values.

Before this commit, the specified storage method could be stored in
ColumnDef::storage (CREATE TABLE ... LIKE) or ColumnDef::storage_name
(CREATE TABLE ...).  This caused the MergeChildAttribute() and
MergeInheritedAttribute() to ignore a storage method specified in the
child definition since it looked only at ColumnDef::storage.  This
commit removes ColumnDef::storage and instead uses
ColumnDef::storage_name to save any storage method specification. This
is similar to how compression method specification is handled.

Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/24656cec-d6ef-4d15-8b5b-e8dfc9c833a7@eisentraut.org
This commit is contained in:
Peter Eisentraut 2024-02-16 11:51:35 +01:00
parent e85732dac0
commit 0413a55699
15 changed files with 409 additions and 112 deletions

View File

@ -398,7 +398,13 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
</para>
<para>
Column <literal>STORAGE</literal> 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.
</para>
<para>

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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": ""

View File

@ -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": ""

View File

@ -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);

View File

@ -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)

View File

@ -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 = '';

View File

@ -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);

View File

@ -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;