Propagate ALTER TYPE operations to typed tables
authorPeter Eisentraut <peter_e@gmx.net>
Tue, 23 Nov 2010 20:50:17 +0000 (22:50 +0200)
committerPeter Eisentraut <peter_e@gmx.net>
Tue, 23 Nov 2010 20:50:17 +0000 (22:50 +0200)
This adds RESTRICT/CASCADE flags to ALTER TYPE ... ADD/DROP/ALTER/
RENAME ATTRIBUTE to control whether to alter typed tables as well.

doc/src/sgml/ref/alter_type.sgml
src/backend/commands/alter.c
src/backend/commands/tablecmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/include/commands/tablecmds.h
src/include/nodes/parsenodes.h
src/test/regress/expected/alter_table.out
src/test/regress/sql/alter_table.sql

index 33413450c37e42fa8c9b9bc37cda29f52066f321..09db0cc8b2d7aa380460e4f7e16f54928a2f8970 100644 (file)
@@ -26,15 +26,15 @@ PostgreSQL documentation
 ALTER TYPE <replaceable class="PARAMETER">name</replaceable> <replaceable class="PARAMETER">action</replaceable> [, ... ]
 ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
 ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> TO <replaceable class="PARAMETER">new_attribute_name</replaceable>
-ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
+ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable> [ CASCADE | RESTRICT ]
 ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
 ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replaceable class="PARAMETER">new_enum_value</replaceable> [ { BEFORE | AFTER } <replaceable class="PARAMETER">existing_enum_value</replaceable> ]
 
 <phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
 
-    ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable>
-    DROP ATTRIBUTE [ IF EXISTS ] <replaceable class="PARAMETER">attribute_name</replaceable>
-    ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable>
+    ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ]
+    DROP ATTRIBUTE [ IF EXISTS ] <replaceable class="PARAMETER">attribute_name</replaceable> [ CASCADE | RESTRICT ]
+    ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -116,6 +116,26 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replacea
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+    <term><literal>CASCADE</literal></term>
+    <listitem>
+     <para>
+      Automatically propagate the operation to typed tables of the
+      type being altered.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>RESTRICT</literal></term>
+    <listitem>
+     <para>
+      Refuse the operation if the type being altered is the type of a
+      typed table.  This is the default.
+     </para>
+    </listitem>
+   </varlistentry>
   </variablelist>
   </para>
 
index 794d355944d3bec337deef3f4fa59336587c2fd3..0d0227d04ad96f0389e7caa2be797f220970562b 100644 (file)
@@ -125,11 +125,7 @@ ExecRenameStmt(RenameStmt *stmt)
                        }
                    case OBJECT_COLUMN:
                    case OBJECT_ATTRIBUTE:
-                       renameatt(relid,
-                                 stmt->subname,        /* old att name */
-                                 stmt->newname,        /* new att name */
-                                 interpretInhOption(stmt->relation->inhOpt),   /* recursive? */
-                                 0);   /* expected inhcount */
+                       renameatt(relid, stmt);
                        break;
                    case OBJECT_TRIGGER:
                        renametrig(relid,
index 11171eaa9901c322511d5508d2f64961a43c4af2..e8808e28c68ce397d0e87ce73122d94efe924570 100644 (file)
@@ -269,8 +269,11 @@ static void ATSimpleRecursion(List **wqueue, Relation rel,
                  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
 static void ATOneLevelRecursion(List **wqueue, Relation rel,
                    AlterTableCmd *cmd, LOCKMODE lockmode);
-static void find_typed_table_dependencies(Oid typeOid, const char *typeName);
-static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
+static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
+                                 LOCKMODE lockmode);
+static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
+                                          DropBehavior behavior);
+static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                AlterTableCmd *cmd, LOCKMODE lockmode);
 static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
                ColumnDef *colDef, bool isOid, LOCKMODE lockmode);
@@ -290,7 +293,8 @@ static void ATExecSetOptions(Relation rel, const char *colName,
                 Node *options, bool isReset, LOCKMODE lockmode);
 static void ATExecSetStorage(Relation rel, const char *colName,
                 Node *newValue, LOCKMODE lockmode);
-static void ATPrepDropColumn(Relation rel, bool recurse, AlterTableCmd *cmd);
+static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
+                            AlterTableCmd *cmd, LOCKMODE lockmode);
 static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
                 DropBehavior behavior,
                 bool recurse, bool recursing,
@@ -1942,14 +1946,16 @@ setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
 
 
 /*
- *     renameatt       - changes the name of a attribute in a relation
+ *     renameatt_internal      - workhorse for renameatt
  */
-void
-renameatt(Oid myrelid,
-         const char *oldattname,
-         const char *newattname,
-         bool recurse,
-         int expected_parents)
+static void
+renameatt_internal(Oid myrelid,
+                  const char *oldattname,
+                  const char *newattname,
+                  bool recurse,
+                  bool recursing,
+                  int expected_parents,
+                  DropBehavior behavior)
 {
    Relation    targetrelation;
    Relation    attrelation;
@@ -1964,15 +1970,11 @@ renameatt(Oid myrelid,
     */
    targetrelation = relation_open(myrelid, AccessExclusiveLock);
 
-   if (targetrelation->rd_rel->reloftype)
+   if (targetrelation->rd_rel->reloftype && !recursing)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cannot rename column of typed table")));
 
-   if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-       find_typed_table_dependencies(targetrelation->rd_rel->reltype,
-                                     RelationGetRelationName(targetrelation));
-
    /*
     * Renaming the columns of sequences or toast tables doesn't actually
     * break anything from the system's point of view, since internal
@@ -2038,7 +2040,7 @@ renameatt(Oid myrelid,
            if (childrelid == myrelid)
                continue;
            /* note we need not recurse again */
-           renameatt(childrelid, oldattname, newattname, false, numparents);
+           renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
        }
    }
    else
@@ -2057,6 +2059,20 @@ renameatt(Oid myrelid,
                            oldattname)));
    }
 
+   /* rename attributes in typed tables of composite type */
+   if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+   {
+       List       *child_oids;
+       ListCell   *lo;
+
+       child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
+                                                  RelationGetRelationName(targetrelation),
+                                                  behavior);
+
+       foreach(lo, child_oids)
+           renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
+   }
+
    attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
 
    atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
@@ -2116,6 +2132,22 @@ renameatt(Oid myrelid,
 }
 
 
+/*
+ *     renameatt       - changes the name of a attribute in a relation
+ */
+void
+renameatt(Oid myrelid, RenameStmt *stmt)
+{
+   renameatt_internal(myrelid,
+                      stmt->subname,       /* old att name */
+                      stmt->newname,       /* new att name */
+                      interpretInhOption(stmt->relation->inhOpt),  /* recursive? */
+                      false,  /* recursing? */
+                      0,   /* expected inhcount */
+                      stmt->behavior);
+}
+
+
 /*
  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW RENAME
  *
@@ -2649,14 +2681,14 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
        case AT_AddColumn:      /* ADD COLUMN */
            ATSimplePermissions(rel, false, true);
            /* Performs own recursion */
-           ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
+           ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
            pass = AT_PASS_ADD_COL;
            break;
        case AT_AddColumnToView:        /* add column via CREATE OR REPLACE
                                         * VIEW */
            ATSimplePermissions(rel, true, false);
            /* Performs own recursion */
-           ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
+           ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
            pass = AT_PASS_ADD_COL;
            break;
        case AT_ColumnDefault:  /* ALTER COLUMN DEFAULT */
@@ -2704,7 +2736,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
            break;
        case AT_DropColumn:     /* DROP COLUMN */
            ATSimplePermissions(rel, false, true);
-           ATPrepDropColumn(rel, recurse, cmd);
+           ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
            /* Recursion occurs during execution phase */
            pass = AT_PASS_DROP;
            break;
@@ -3671,6 +3703,37 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
    }
 }
 
+/*
+ * ATTypedTableRecursion
+ *
+ * Propagate ALTER TYPE operations to the typed tables of that type.
+ * Also check the RESTRICT/CASCADE behavior.
+ */
+static void
+ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
+                     LOCKMODE lockmode)
+{
+   ListCell   *child;
+   List       *children;
+
+   Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
+
+   children = find_typed_table_dependencies(rel->rd_rel->reltype,
+                                            RelationGetRelationName(rel),
+                                            cmd->behavior);
+
+   foreach(child, children)
+   {
+       Oid         childrelid = lfirst_oid(child);
+       Relation    childrel;
+
+       childrel = relation_open(childrelid, lockmode);
+       CheckTableNotInUse(childrel, "ALTER TABLE");
+       ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
+       relation_close(childrel, NoLock);
+   }
+}
+
 
 /*
  * find_composite_type_dependencies
@@ -3778,17 +3841,17 @@ find_composite_type_dependencies(Oid typeOid,
  * find_typed_table_dependencies
  *
  * Check to see if a composite type is being used as the type of a
- * typed table.  Eventually, we'd like to propagate the alter
- * operation into such tables, but for now, just error out if we find
- * any.
+ * typed table.  Abort if any are found and behavior is RESTRICT.
+ * Else return the list of tables.
  */
-static void
-find_typed_table_dependencies(Oid typeOid, const char *typeName)
+static List *
+find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
 {
    Relation    classRel;
    ScanKeyData key[1];
    HeapScanDesc scan;
    HeapTuple   tuple;
+   List       *result = NIL;
 
    classRel = heap_open(RelationRelationId, AccessShareLock);
 
@@ -3801,14 +3864,20 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName)
 
    if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
    {
-       ereport(ERROR,
-               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                errmsg("cannot alter type \"%s\" because it is the type of a typed table",
-                       typeName)));
+       if (behavior == DROP_RESTRICT)
+           ereport(ERROR,
+                   (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
+                    errmsg("cannot alter type \"%s\" because it is the type of a typed table",
+                           typeName),
+                    errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
+       else
+           result = lappend_oid(result, HeapTupleGetOid(tuple));
    }
 
    heap_endscan(scan);
    heap_close(classRel, AccessShareLock);
+
+   return result;
 }
 
 
@@ -3821,10 +3890,10 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName)
  * AlterTableCmd's.
  */
 static void
-ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
+ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
                AlterTableCmd *cmd, LOCKMODE lockmode)
 {
-   if (rel->rd_rel->reloftype)
+   if (rel->rd_rel->reloftype && !recursing)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cannot add column to typed table")));
@@ -3860,8 +3929,7 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
    }
 
    if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-       find_typed_table_dependencies(rel->rd_rel->reltype,
-                                     RelationGetRelationName(rel));
+       ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
 }
 
 static void
@@ -4162,7 +4230,7 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
        cdef->storage = 0;
        cmd->def = (Node *) cdef;
    }
-   ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
+   ATPrepAddColumn(wqueue, rel, recurse, false, cmd, lockmode);
 }
 
 /*
@@ -4586,18 +4654,17 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
  * correctly.)
  */
 static void
-ATPrepDropColumn(Relation rel, bool recurse, AlterTableCmd *cmd)
+ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
+                AlterTableCmd *cmd, LOCKMODE lockmode)
 {
-   if (rel->rd_rel->reloftype)
+   if (rel->rd_rel->reloftype && !recursing)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cannot drop column from typed table")));
 
    if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-       find_typed_table_dependencies(rel->rd_rel->reltype,
-                                     RelationGetRelationName(rel));
+       ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
 
-   /* No command-specific prep needed except saving recurse flag */
    if (recurse)
        cmd->subtype = AT_DropColumnRecurse;
 }
@@ -6060,7 +6127,7 @@ ATPrepAlterColumnType(List **wqueue,
    NewColumnValue *newval;
    ParseState *pstate = make_parsestate(NULL);
 
-   if (rel->rd_rel->reloftype)
+   if (rel->rd_rel->reloftype && !recursing)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cannot alter column type of typed table")));
@@ -6178,9 +6245,6 @@ ATPrepAlterColumnType(List **wqueue,
        find_composite_type_dependencies(rel->rd_rel->reltype,
                                         NULL,
                                         RelationGetRelationName(rel));
-
-       find_typed_table_dependencies(rel->rd_rel->reltype,
-                                     RelationGetRelationName(rel));
    }
 
    ReleaseSysCache(tuple);
@@ -6198,6 +6262,9 @@ ATPrepAlterColumnType(List **wqueue,
                (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                 errmsg("type of inherited column \"%s\" must be changed in child tables too",
                        colName)));
+
+   if (tab->relkind == RELKIND_COMPOSITE_TYPE)
+       ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
 }
 
 static void
index e91044bc4adb314b570b5c6d94f1e8fad4489b70..bbfbab2e39bd75e16f9b0f07147f3e60c325c0b4 100644 (file)
@@ -2803,6 +2803,7 @@ _copyRenameStmt(RenameStmt *from)
    COPY_NODE_FIELD(objarg);
    COPY_STRING_FIELD(subname);
    COPY_STRING_FIELD(newname);
+   COPY_SCALAR_FIELD(behavior);
 
    return newnode;
 }
index 73b28f96c0e8f47d35d6ca6a4051fa2f10d3d71c..be4b835585c4260d14ddf4d4771c0b50d0182912 100644 (file)
@@ -1306,6 +1306,7 @@ _equalRenameStmt(RenameStmt *a, RenameStmt *b)
    COMPARE_NODE_FIELD(objarg);
    COMPARE_STRING_FIELD(subname);
    COMPARE_STRING_FIELD(newname);
+   COMPARE_SCALAR_FIELD(behavior);
 
    return true;
 }
index d9b20746fa1d2469b42d9f3061f20ae1f2ceca32..f0c2cd06ea6358b598a02bb579ac288c562b2cdf 100644 (file)
@@ -2003,41 +2003,43 @@ alter_type_cmds:
        ;
 
 alter_type_cmd:
-           /* ALTER TYPE <name> ADD ATTRIBUTE <coldef> */
-           ADD_P ATTRIBUTE TableFuncElement
+           /* ALTER TYPE <name> ADD ATTRIBUTE <coldef> [RESTRICT|CASCADE] */
+           ADD_P ATTRIBUTE TableFuncElement opt_drop_behavior
                {
                    AlterTableCmd *n = makeNode(AlterTableCmd);
                    n->subtype = AT_AddColumn;
                    n->def = $3;
+                   n->behavior = $4;
                    $$ = (Node *)n;
                }
-           /* ALTER TYPE <name> DROP ATTRIBUTE IF EXISTS <attname> */
-           | DROP ATTRIBUTE IF_P EXISTS ColId
+           /* ALTER TYPE <name> DROP ATTRIBUTE IF EXISTS <attname> [RESTRICT|CASCADE] */
+           | DROP ATTRIBUTE IF_P EXISTS ColId opt_drop_behavior
                {
                    AlterTableCmd *n = makeNode(AlterTableCmd);
                    n->subtype = AT_DropColumn;
                    n->name = $5;
-                   n->behavior = DROP_RESTRICT; /* currently no effect */
+                   n->behavior = $6;
                    n->missing_ok = TRUE;
                    $$ = (Node *)n;
                }
-           /* ALTER TYPE <name> DROP ATTRIBUTE <attname> */
+           /* ALTER TYPE <name> DROP ATTRIBUTE <attname> [RESTRICT|CASCADE] */
            | DROP ATTRIBUTE ColId opt_drop_behavior
                {
                    AlterTableCmd *n = makeNode(AlterTableCmd);
                    n->subtype = AT_DropColumn;
                    n->name = $3;
-                   n->behavior = DROP_RESTRICT; /* currently no effect */
+                   n->behavior = $4;
                    n->missing_ok = FALSE;
                    $$ = (Node *)n;
                }
-           /* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> */
-           | ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename
+           /* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> [RESTRICT|CASCADE] */
+           | ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_drop_behavior
                {
                    AlterTableCmd *n = makeNode(AlterTableCmd);
                    n->subtype = AT_AlterColumnType;
                    n->name = $3;
                    n->def = (Node *) $6;
+                   n->behavior = $7;
                    $$ = (Node *)n;
                }
        ;
@@ -6005,13 +6007,14 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
                    n->newname = $6;
                    $$ = (Node *)n;
                }
-           | ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name
+           | ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name opt_drop_behavior
                {
                    RenameStmt *n = makeNode(RenameStmt);
                    n->renameType = OBJECT_ATTRIBUTE;
                    n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
                    n->subname = $6;
                    n->newname = $8;
+                   n->behavior = $9;
                    $$ = (Node *)n;
                }
        ;
index aed3960e497cac3f8d4771e5b51b1b62421f8dc5..ad932d397958f0d2ecca23d521e7432b59f65edb 100644 (file)
@@ -42,11 +42,7 @@ extern void CheckTableNotInUse(Relation rel, const char *stmt);
 
 extern void ExecuteTruncate(TruncateStmt *stmt);
 
-extern void renameatt(Oid myrelid,
-         const char *oldattname,
-         const char *newattname,
-         bool recurse,
-         int expected_parents);
+extern void renameatt(Oid myrelid, RenameStmt *stmt);
 
 extern void RenameRelation(Oid myrelid,
               const char *newrelname,
index a320be4d899c2d13b85a01676f7e2de4e915dcc1..d6cfafea711f4a25c99662257112794075a874e5 100644 (file)
@@ -2073,6 +2073,7 @@ typedef struct RenameStmt
    char       *subname;        /* name of contained object (column, rule,
                                 * trigger, etc) */
    char       *newname;        /* the new name */
+   DropBehavior behavior;      /* RESTRICT or CASCADE behavior */
 } RenameStmt;
 
 /* ----------------------
index d6c5827c68b8e1b9711ecf6451997bd8f18a9439..b68dfd4fc2641d2fbb0d3d79dc9af0b1483c711d 100644 (file)
@@ -1760,13 +1760,100 @@ ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
 ERROR:  cannot alter type "test_type1" because column "test_tbl1"."y" uses it
 CREATE TYPE test_type2 AS (a int, b text);
 CREATE TABLE test_tbl2 OF test_type2;
+\d test_type2
+Composite type "public.test_type2"
+ Column |  Type   
+--------+---------
+ a      | integer
+ b      | text
+
+\d test_tbl2
+   Table "public.test_tbl2"
+ Column |  Type   | Modifiers 
+--------+---------+-----------
+ a      | integer | 
+ b      | text    | 
+Typed table of type: test_type2
+
 ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails
 ERROR:  cannot alter type "test_type2" because it is the type of a typed table
+HINT:  Use ALTER ... CASCADE to alter the typed tables too.
+ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE;
+\d test_type2
+Composite type "public.test_type2"
+ Column |  Type   
+--------+---------
+ a      | integer
+ b      | text
+ c      | text
+
+\d test_tbl2
+   Table "public.test_tbl2"
+ Column |  Type   | Modifiers 
+--------+---------+-----------
+ a      | integer | 
+ b      | text    | 
+ c      | text    | 
+Typed table of type: test_type2
+
 ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails
 ERROR:  cannot alter type "test_type2" because it is the type of a typed table
+HINT:  Use ALTER ... CASCADE to alter the typed tables too.
+ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE;
+\d test_type2
+Composite type "public.test_type2"
+ Column |       Type        
+--------+-------------------
+ a      | integer
+ b      | character varying
+ c      | text
+
+\d test_tbl2
+        Table "public.test_tbl2"
+ Column |       Type        | Modifiers 
+--------+-------------------+-----------
+ a      | integer           | 
+ b      | character varying | 
+ c      | text              | 
+Typed table of type: test_type2
+
 ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails
 ERROR:  cannot alter type "test_type2" because it is the type of a typed table
-ALTER TYPE test_type2 RENAME ATTRIBUTE b TO bb; -- fails
+HINT:  Use ALTER ... CASCADE to alter the typed tables too.
+ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE;
+\d test_type2
+Composite type "public.test_type2"
+ Column |  Type   
+--------+---------
+ a      | integer
+ c      | text
+
+\d test_tbl2
+   Table "public.test_tbl2"
+ Column |  Type   | Modifiers 
+--------+---------+-----------
+ a      | integer | 
+ c      | text    | 
+Typed table of type: test_type2
+
+ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails
 ERROR:  cannot alter type "test_type2" because it is the type of a typed table
+HINT:  Use ALTER ... CASCADE to alter the typed tables too.
+ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE;
+\d test_type2
+Composite type "public.test_type2"
+ Column |  Type   
+--------+---------
+ aa     | integer
+ c      | text
+
+\d test_tbl2
+   Table "public.test_tbl2"
+ Column |  Type   | Modifiers 
+--------+---------+-----------
+ aa     | integer | 
+ c      | text    | 
+Typed table of type: test_type2
+
 CREATE TYPE test_type_empty AS ();
 DROP TYPE test_type_empty;
index c6015cbb4016c21004fa34f213fd960c1e7448d2..98a68d587729cd49d375fe588b915ee04132c9c0 100644 (file)
@@ -1272,10 +1272,28 @@ ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
 
 CREATE TYPE test_type2 AS (a int, b text);
 CREATE TABLE test_tbl2 OF test_type2;
+\d test_type2
+\d test_tbl2
+
 ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails
+ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE;
+\d test_type2
+\d test_tbl2
+
 ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails
+ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE;
+\d test_type2
+\d test_tbl2
+
 ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails
-ALTER TYPE test_type2 RENAME ATTRIBUTE b TO bb; -- fails
+ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE;
+\d test_type2
+\d test_tbl2
+
+ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails
+ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE;
+\d test_type2
+\d test_tbl2
 
 CREATE TYPE test_type_empty AS ();
 DROP TYPE test_type_empty;