@@ -269,8 +269,11 @@ static void ATSimpleRecursion(List **wqueue, Relation rel,
269269AlterTableCmd * cmd ,bool recurse ,LOCKMODE lockmode );
270270static void ATOneLevelRecursion (List * * wqueue ,Relation rel ,
271271AlterTableCmd * cmd ,LOCKMODE lockmode );
272- static void find_typed_table_dependencies (Oid typeOid ,const char * typeName );
273- static void ATPrepAddColumn (List * * wqueue ,Relation rel ,bool recurse ,
272+ static void ATTypedTableRecursion (List * * wqueue ,Relation rel ,AlterTableCmd * cmd ,
273+ LOCKMODE lockmode );
274+ static List * find_typed_table_dependencies (Oid typeOid ,const char * typeName ,
275+ DropBehavior behavior );
276+ static void ATPrepAddColumn (List * * wqueue ,Relation rel ,bool recurse ,bool recursing ,
274277AlterTableCmd * cmd ,LOCKMODE lockmode );
275278static void ATExecAddColumn (AlteredTableInfo * tab ,Relation rel ,
276279ColumnDef * colDef ,bool isOid ,LOCKMODE lockmode );
@@ -290,7 +293,8 @@ static void ATExecSetOptions(Relation rel, const char *colName,
290293Node * options ,bool isReset ,LOCKMODE lockmode );
291294static void ATExecSetStorage (Relation rel ,const char * colName ,
292295Node * newValue ,LOCKMODE lockmode );
293- static void ATPrepDropColumn (Relation rel ,bool recurse ,AlterTableCmd * cmd );
296+ static void ATPrepDropColumn (List * * wqueue ,Relation rel ,bool recurse ,bool recursing ,
297+ AlterTableCmd * cmd ,LOCKMODE lockmode );
294298static void ATExecDropColumn (List * * wqueue ,Relation rel ,const char * colName ,
295299DropBehavior behavior ,
296300bool recurse ,bool recursing ,
@@ -1942,14 +1946,16 @@ setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
19421946
19431947
19441948/*
1945- *renameatt -changes the name of a attribute in a relation
1949+ *renameatt_internal -workhorse for renameatt
19461950 */
1947- void
1948- renameatt (Oid myrelid ,
1949- const char * oldattname ,
1950- const char * newattname ,
1951- bool recurse ,
1952- int expected_parents )
1951+ static void
1952+ renameatt_internal (Oid myrelid ,
1953+ const char * oldattname ,
1954+ const char * newattname ,
1955+ bool recurse ,
1956+ bool recursing ,
1957+ int expected_parents ,
1958+ DropBehavior behavior )
19531959{
19541960Relation targetrelation ;
19551961Relation attrelation ;
@@ -1964,15 +1970,11 @@ renameatt(Oid myrelid,
19641970 */
19651971targetrelation = relation_open (myrelid ,AccessExclusiveLock );
19661972
1967- if (targetrelation -> rd_rel -> reloftype )
1973+ if (targetrelation -> rd_rel -> reloftype && ! recursing )
19681974ereport (ERROR ,
19691975(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
19701976errmsg ("cannot rename column of typed table" )));
19711977
1972- if (targetrelation -> rd_rel -> relkind == RELKIND_COMPOSITE_TYPE )
1973- find_typed_table_dependencies (targetrelation -> rd_rel -> reltype ,
1974- RelationGetRelationName (targetrelation ));
1975-
19761978/*
19771979 * Renaming the columns of sequences or toast tables doesn't actually
19781980 * break anything from the system's point of view, since internal
@@ -2038,7 +2040,7 @@ renameatt(Oid myrelid,
20382040if (childrelid == myrelid )
20392041continue ;
20402042/* note we need not recurse again */
2041- renameatt (childrelid ,oldattname ,newattname , false,numparents );
2043+ renameatt_internal (childrelid ,oldattname ,newattname , false,true, numparents , behavior );
20422044}
20432045}
20442046else
@@ -2057,6 +2059,20 @@ renameatt(Oid myrelid,
20572059oldattname )));
20582060}
20592061
2062+ /* rename attributes in typed tables of composite type */
2063+ if (targetrelation -> rd_rel -> relkind == RELKIND_COMPOSITE_TYPE )
2064+ {
2065+ List * child_oids ;
2066+ ListCell * lo ;
2067+
2068+ child_oids = find_typed_table_dependencies (targetrelation -> rd_rel -> reltype ,
2069+ RelationGetRelationName (targetrelation ),
2070+ behavior );
2071+
2072+ foreach (lo ,child_oids )
2073+ renameatt_internal (lfirst_oid (lo ),oldattname ,newattname , true, true,0 ,behavior );
2074+ }
2075+
20602076attrelation = heap_open (AttributeRelationId ,RowExclusiveLock );
20612077
20622078atttup = SearchSysCacheCopyAttName (myrelid ,oldattname );
@@ -2116,6 +2132,22 @@ renameatt(Oid myrelid,
21162132}
21172133
21182134
2135+ /*
2136+ *renameatt- changes the name of a attribute in a relation
2137+ */
2138+ void
2139+ renameatt (Oid myrelid ,RenameStmt * stmt )
2140+ {
2141+ renameatt_internal (myrelid ,
2142+ stmt -> subname ,/* old att name */
2143+ stmt -> newname ,/* new att name */
2144+ interpretInhOption (stmt -> relation -> inhOpt ),/* recursive? */
2145+ false,/* recursing? */
2146+ 0 ,/* expected inhcount */
2147+ stmt -> behavior );
2148+ }
2149+
2150+
21192151/*
21202152 * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW RENAME
21212153 *
@@ -2649,14 +2681,14 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
26492681case AT_AddColumn :/* ADD COLUMN */
26502682ATSimplePermissions (rel , false, true);
26512683/* Performs own recursion */
2652- ATPrepAddColumn (wqueue ,rel ,recurse ,cmd ,lockmode );
2684+ ATPrepAddColumn (wqueue ,rel ,recurse ,recursing , cmd ,lockmode );
26532685pass = AT_PASS_ADD_COL ;
26542686break ;
26552687case AT_AddColumnToView :/* add column via CREATE OR REPLACE
26562688 * VIEW */
26572689ATSimplePermissions (rel , true, false);
26582690/* Performs own recursion */
2659- ATPrepAddColumn (wqueue ,rel ,recurse ,cmd ,lockmode );
2691+ ATPrepAddColumn (wqueue ,rel ,recurse ,recursing , cmd ,lockmode );
26602692pass = AT_PASS_ADD_COL ;
26612693break ;
26622694case AT_ColumnDefault :/* ALTER COLUMN DEFAULT */
@@ -2704,7 +2736,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
27042736break ;
27052737case AT_DropColumn :/* DROP COLUMN */
27062738ATSimplePermissions (rel , false, true);
2707- ATPrepDropColumn (rel ,recurse ,cmd );
2739+ ATPrepDropColumn (wqueue , rel ,recurse ,recursing , cmd , lockmode );
27082740/* Recursion occurs during execution phase */
27092741pass = AT_PASS_DROP ;
27102742break ;
@@ -3671,6 +3703,37 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
36713703}
36723704}
36733705
3706+ /*
3707+ * ATTypedTableRecursion
3708+ *
3709+ * Propagate ALTER TYPE operations to the typed tables of that type.
3710+ * Also check the RESTRICT/CASCADE behavior.
3711+ */
3712+ static void
3713+ ATTypedTableRecursion (List * * wqueue ,Relation rel ,AlterTableCmd * cmd ,
3714+ LOCKMODE lockmode )
3715+ {
3716+ ListCell * child ;
3717+ List * children ;
3718+
3719+ Assert (rel -> rd_rel -> relkind == RELKIND_COMPOSITE_TYPE );
3720+
3721+ children = find_typed_table_dependencies (rel -> rd_rel -> reltype ,
3722+ RelationGetRelationName (rel ),
3723+ cmd -> behavior );
3724+
3725+ foreach (child ,children )
3726+ {
3727+ Oid childrelid = lfirst_oid (child );
3728+ Relation childrel ;
3729+
3730+ childrel = relation_open (childrelid ,lockmode );
3731+ CheckTableNotInUse (childrel ,"ALTER TABLE" );
3732+ ATPrepCmd (wqueue ,childrel ,cmd , false, true,lockmode );
3733+ relation_close (childrel ,NoLock );
3734+ }
3735+ }
3736+
36743737
36753738/*
36763739 * find_composite_type_dependencies
@@ -3778,17 +3841,17 @@ find_composite_type_dependencies(Oid typeOid,
37783841 * find_typed_table_dependencies
37793842 *
37803843 * Check to see if a composite type is being used as the type of a
3781- * typed table. Eventually, we'd like to propagate the alter
3782- * operation into such tables, but for now, just error out if we find
3783- * any.
3844+ * typed table. Abort if any are found and behavior is RESTRICT.
3845+ * Else return the list of tables.
37843846 */
3785- static void
3786- find_typed_table_dependencies (Oid typeOid ,const char * typeName )
3847+ static List *
3848+ find_typed_table_dependencies (Oid typeOid ,const char * typeName , DropBehavior behavior )
37873849{
37883850Relation classRel ;
37893851ScanKeyData key [1 ];
37903852HeapScanDesc scan ;
37913853HeapTuple tuple ;
3854+ List * result = NIL ;
37923855
37933856classRel = heap_open (RelationRelationId ,AccessShareLock );
37943857
@@ -3801,14 +3864,20 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName)
38013864
38023865if (HeapTupleIsValid (tuple = heap_getnext (scan ,ForwardScanDirection )))
38033866{
3804- ereport (ERROR ,
3805- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
3806- errmsg ("cannot alter type \"%s\" because it is the type of a typed table" ,
3807- typeName )));
3867+ if (behavior == DROP_RESTRICT )
3868+ ereport (ERROR ,
3869+ (errcode (ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST ),
3870+ errmsg ("cannot alter type \"%s\" because it is the type of a typed table" ,
3871+ typeName ),
3872+ errhint ("Use ALTER ... CASCADE to alter the typed tables too." )));
3873+ else
3874+ result = lappend_oid (result ,HeapTupleGetOid (tuple ));
38083875}
38093876
38103877heap_endscan (scan );
38113878heap_close (classRel ,AccessShareLock );
3879+
3880+ return result ;
38123881}
38133882
38143883
@@ -3821,10 +3890,10 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName)
38213890 * AlterTableCmd's.
38223891 */
38233892static void
3824- ATPrepAddColumn (List * * wqueue ,Relation rel ,bool recurse ,
3893+ ATPrepAddColumn (List * * wqueue ,Relation rel ,bool recurse ,bool recursing ,
38253894AlterTableCmd * cmd ,LOCKMODE lockmode )
38263895{
3827- if (rel -> rd_rel -> reloftype )
3896+ if (rel -> rd_rel -> reloftype && ! recursing )
38283897ereport (ERROR ,
38293898(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
38303899errmsg ("cannot add column to typed table" )));
@@ -3860,8 +3929,7 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
38603929}
38613930
38623931if (rel -> rd_rel -> relkind == RELKIND_COMPOSITE_TYPE )
3863- find_typed_table_dependencies (rel -> rd_rel -> reltype ,
3864- RelationGetRelationName (rel ));
3932+ ATTypedTableRecursion (wqueue ,rel ,cmd ,lockmode );
38653933}
38663934
38673935static void
@@ -4162,7 +4230,7 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
41624230cdef -> storage = 0 ;
41634231cmd -> def = (Node * )cdef ;
41644232}
4165- ATPrepAddColumn (wqueue ,rel ,recurse ,cmd ,lockmode );
4233+ ATPrepAddColumn (wqueue ,rel ,recurse ,false, cmd ,lockmode );
41664234}
41674235
41684236/*
@@ -4586,18 +4654,17 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
45864654 * correctly.)
45874655 */
45884656static void
4589- ATPrepDropColumn (Relation rel ,bool recurse ,AlterTableCmd * cmd )
4657+ ATPrepDropColumn (List * * wqueue ,Relation rel ,bool recurse ,bool recursing ,
4658+ AlterTableCmd * cmd ,LOCKMODE lockmode )
45904659{
4591- if (rel -> rd_rel -> reloftype )
4660+ if (rel -> rd_rel -> reloftype && ! recursing )
45924661ereport (ERROR ,
45934662(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
45944663errmsg ("cannot drop column from typed table" )));
45954664
45964665if (rel -> rd_rel -> relkind == RELKIND_COMPOSITE_TYPE )
4597- find_typed_table_dependencies (rel -> rd_rel -> reltype ,
4598- RelationGetRelationName (rel ));
4666+ ATTypedTableRecursion (wqueue ,rel ,cmd ,lockmode );
45994667
4600- /* No command-specific prep needed except saving recurse flag */
46014668if (recurse )
46024669cmd -> subtype = AT_DropColumnRecurse ;
46034670}
@@ -6060,7 +6127,7 @@ ATPrepAlterColumnType(List **wqueue,
60606127NewColumnValue * newval ;
60616128ParseState * pstate = make_parsestate (NULL );
60626129
6063- if (rel -> rd_rel -> reloftype )
6130+ if (rel -> rd_rel -> reloftype && ! recursing )
60646131ereport (ERROR ,
60656132(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
60666133errmsg ("cannot alter column type of typed table" )));
@@ -6178,9 +6245,6 @@ ATPrepAlterColumnType(List **wqueue,
61786245find_composite_type_dependencies (rel -> rd_rel -> reltype ,
61796246NULL ,
61806247RelationGetRelationName (rel ));
6181-
6182- find_typed_table_dependencies (rel -> rd_rel -> reltype ,
6183- RelationGetRelationName (rel ));
61846248}
61856249
61866250ReleaseSysCache (tuple );
@@ -6198,6 +6262,9 @@ ATPrepAlterColumnType(List **wqueue,
61986262(errcode (ERRCODE_INVALID_TABLE_DEFINITION ),
61996263errmsg ("type of inherited column \"%s\" must be changed in child tables too" ,
62006264colName )));
6265+
6266+ if (tab -> relkind == RELKIND_COMPOSITE_TYPE )
6267+ ATTypedTableRecursion (wqueue ,rel ,cmd ,lockmode );
62016268}
62026269
62036270static void