aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c97
1 files changed, 96 insertions, 1 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 66c1b95135a..3a95064442c 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.111 2004/06/05 19:48:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.112 2004/06/06 20:30:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -194,6 +194,8 @@ static void ATSimpleRecursion(List **wqueue, Relation rel,
AlterTableCmd *cmd, bool recurse);
static void ATOneLevelRecursion(List **wqueue, Relation rel,
AlterTableCmd *cmd);
+static void find_composite_type_dependencies(Oid typeOid,
+ const char *origTblName);
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
AlterTableCmd *cmd);
static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
@@ -2282,6 +2284,18 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
newrel = NULL;
/*
+ * If we need to rewrite the table, the operation has to be propagated
+ * to tables that use this table's rowtype as a column type.
+ *
+ * (Eventually this will probably become true for scans as well, but
+ * at the moment a composite type does not enforce any constraints,
+ * so it's not necessary/appropriate to enforce them just during ALTER.)
+ */
+ if (newrel)
+ find_composite_type_dependencies(oldrel->rd_rel->reltype,
+ RelationGetRelationName(oldrel));
+
+ /*
* Generate the constraint and default execution states
*/
@@ -2606,6 +2620,87 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
}
}
+
+/*
+ * find_composite_type_dependencies
+ *
+ * Check to see if a table's rowtype is being used as a column in some
+ * other table (possibly nested several levels deep in composite types!).
+ * Eventually, we'd like to propagate the check or rewrite operation
+ * into other such tables, but for now, just error out if we find any.
+ *
+ * We assume that functions and views depending on the type are not reasons
+ * to reject the ALTER. (How safe is this really?)
+ */
+static void
+find_composite_type_dependencies(Oid typeOid, const char *origTblName)
+{
+ Relation depRel;
+ ScanKeyData key[2];
+ SysScanDesc depScan;
+ HeapTuple depTup;
+
+ /*
+ * We scan pg_depend to find those things that depend on the rowtype.
+ * (We assume we can ignore refobjsubid for a rowtype.)
+ */
+ depRel = relation_openr(DependRelationName, AccessShareLock);
+
+ ScanKeyInit(&key[0],
+ Anum_pg_depend_refclassid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelOid_pg_type));
+ ScanKeyInit(&key[1],
+ Anum_pg_depend_refobjid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(typeOid));
+
+ depScan = systable_beginscan(depRel, DependReferenceIndex, true,
+ SnapshotNow, 2, key);
+
+ while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
+ {
+ Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
+ Relation rel;
+ Form_pg_attribute att;
+
+ /* Ignore dependees that aren't user columns of relations */
+ /* (we assume system columns are never of rowtypes) */
+ if (pg_depend->classid != RelOid_pg_class ||
+ pg_depend->objsubid <= 0)
+ continue;
+
+ rel = relation_open(pg_depend->objid, AccessShareLock);
+ att = rel->rd_att->attrs[pg_depend->objsubid - 1];
+
+ if (rel->rd_rel->relkind == RELKIND_RELATION)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot alter table \"%s\" because column \"%s\".\"%s\" uses its rowtype",
+ origTblName,
+ RelationGetRelationName(rel),
+ NameStr(att->attname))));
+ }
+ else if (OidIsValid(rel->rd_rel->reltype))
+ {
+ /*
+ * A view or composite type itself isn't a problem, but we must
+ * recursively check for indirect dependencies via its rowtype.
+ */
+ find_composite_type_dependencies(rel->rd_rel->reltype,
+ origTblName);
+ }
+
+ relation_close(rel, AccessShareLock);
+ }
+
+ systable_endscan(depScan);
+
+ relation_close(depRel, AccessShareLock);
+}
+
+
/*
* ALTER TABLE ADD COLUMN
*