diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 63ee33dd30..c8efaa23b1 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.132 2004/09/16 16:58:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.133 2004/09/23 23:20:24 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -237,6 +237,8 @@ static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab); static void ATPostAlterTypeParse(char *cmd, List **wqueue); static void ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId); +static void change_owner_recurse_to_sequences(Oid relationOid, + int32 newOwnerSysId); static void ATExecClusterOn(Relation rel, const char *indexName); static void ATExecDropCluster(Relation rel); static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, @@ -5121,8 +5123,10 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) HeapTuple tuple; Form_pg_class tuple_class; - /* Get exclusive lock till end of transaction on the target table */ - /* Use relation_open here so that we work on indexes... */ + /* + * Get exclusive lock till end of transaction on the target table. + * Use relation_open so that we can work on indexes and sequences. + */ target_rel = relation_open(relationOid, AccessExclusiveLock); /* Get its pg_class tuple, too */ @@ -5202,8 +5206,8 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) /* * If we are operating on a table, also change the ownership of - * any indexes that belong to the table, as well as the table's - * toast table (if it has one) + * any indexes and sequences that belong to the table, as well as + * the table's toast table (if it has one) */ if (tuple_class->relkind == RELKIND_RELATION || tuple_class->relkind == RELKIND_TOASTVALUE) @@ -5226,6 +5230,9 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) /* If it has a toast table, recurse to change its ownership */ if (tuple_class->reltoastrelid != InvalidOid) ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerSysId); + + /* If it has dependent sequences, recurse to change them too */ + change_owner_recurse_to_sequences(relationOid, newOwnerSysId); } } @@ -5234,6 +5241,73 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) relation_close(target_rel, NoLock); } +/* + * change_owner_recurse_to_sequences + * + * Helper function for ATExecChangeOwner. Examines pg_depend searching + * for sequences that are dependent on serial columns, and changes their + * ownership. + */ +static void +change_owner_recurse_to_sequences(Oid relationOid, int32 newOwnerSysId) +{ + Relation depRel; + SysScanDesc scan; + ScanKeyData key[2]; + HeapTuple tup; + + /* + * SERIAL sequences are those having an internal dependency on one + * of the table's columns (we don't care *which* column, exactly). + */ + depRel = heap_openr(DependRelationName, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelOid_pg_class)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relationOid)); + /* we leave refobjsubid unspecified */ + + scan = systable_beginscan(depRel, DependReferenceIndex, true, + SnapshotNow, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup); + Relation seqRel; + + /* skip dependencies other than internal dependencies on columns */ + if (depForm->refobjsubid == 0 || + depForm->classid != RelOid_pg_class || + depForm->objsubid != 0 || + depForm->deptype != DEPENDENCY_INTERNAL) + continue; + + /* Use relation_open just in case it's an index */ + seqRel = relation_open(depForm->objid, AccessExclusiveLock); + + /* skip non-sequence relations */ + if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE) + { + /* No need to keep the lock */ + relation_close(seqRel, AccessExclusiveLock); + continue; + } + + /* We don't need to close the sequence while we alter it. */ + ATExecChangeOwner(depForm->objid, newOwnerSysId); + + /* Now we can close it. Keep the lock till end of transaction. */ + relation_close(seqRel, NoLock); + } + + systable_endscan(scan); +} + /* * ALTER TABLE CLUSTER ON *