Improve compression and storage support with inheritance
authorPeter Eisentraut <peter@eisentraut.org>
Fri, 16 Feb 2024 10:51:35 +0000 (11:51 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Fri, 16 Feb 2024 12:27:46 +0000 (13:27 +0100)
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

15 files changed:
doc/src/sgml/ref/create_table.sgml
src/backend/catalog/pg_type.c
src/backend/commands/tablecmds.c
src/backend/nodes/makefuncs.c
src/backend/parser/gram.y
src/backend/parser/parse_utilcmd.c
src/include/catalog/pg_type.h
src/include/nodes/parsenodes.h
src/test/regress/expected/compression.out
src/test/regress/expected/compression_1.out
src/test/regress/expected/create_table_like.out
src/test/regress/expected/inherit.out
src/test/regress/sql/compression.sql
src/test/regress/sql/create_table_like.sql
src/test/regress/sql/inherit.sql

index 4cbaaccaf7cd80f6416f85884cba2d3f361e2e7d..fb0e98738773db8004f7743dcd7aba6940e4010c 100644 (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>
index fe47be38d0e39fb6aa1511ed7d1d170da82a4987..ee604cea294b17d37b4af1372d5fea944df5fcc0 100644 (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;
+   }
+}
index 86ea3a228b65639d84163edec3effc6c97ed8932..237eeeec67e0dfd6282d1b4e9bcef5ac504b3d6e 100644 (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
index a02332a1ecb1a71a8d3a0f65cff13f59062d5e0d..86b8dcfe7ea6c50df4d9b75499406b371e71ee25 100644 (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;
index 130f7fc7c3f0a04116e5a5af5c24216f5b968872..60b31d9f852dd8fbf330d28a185f2fc9d7a1e98e 100644 (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;
index c7efd8d8cee13016fe588cf8f0266197111719f6..8dcf794ca278b29271a7eda166376708cfaf7913 100644 (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;
 
index e9259697321dae6519f38db1390561adf35eec5a..38ca1174806c3bb816aadf25b518077cba44b06a 100644 (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 */
index 476d55dd2408eb7907e023d5475cc42b496d70dd..d5b08ded4464f4f9bd3c1639aa8c96fbc3c93642 100644 (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 */
index 834b7555cbc8036e37a984d2d942774cd042865b..c22a71f8bd4612ffbfb67073d92d1b26446ae3f5 100644 (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);
+-- 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
+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"
-ERROR:  column "f1" has a compression method conflict
-DETAIL:  pglz versus lz4
-CREATE TABLE cminh(f1 TEXT COMPRESSION lz4) INHERITS(cmdata);
 NOTICE:  merging column "f1" with inherited definition
-ERROR:  column "f1" has a compression method conflict
-DETAIL:  pglz versus lz4
+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": ""
index ddcd137c495bd31614058b6769bc1e08b733b39e..d70155d5d01973036e921e02e9c6c6f17f6145d9 100644 (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": ""
index 61956773ffd79a3d2b805f63c6eafec1d505a8d1..fb786d35a3eaa72adb520b60ef5d0964c3f0fd1b 100644 (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);
index 130a92422889ace43e1fed73dc4873639639e11c..1e6cc8e9ba443a78f71625069cb57ac80fa005ad 100644 (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)
+
index 7179a5002ec5da6d15836a641d680ea908cb5e1d..ad8e7afd2a5fb32bd5c89f6a659fdba1002b7e72 100644 (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 = '';
index 4929d373a2f114d8a6d3c01c8f348fbe210822ba..9c5758a72b7f2bdfe7a42de52bb57c4b662d7f4d 100644 (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);
index 0ef9a61bc16b677e211ad88df033b4ae8aa5f74b..6e629121aefe971db2ae2f0c738fdfe605bd20e6 100644 (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;