提交 bb3da43e 编写于 作者: T Tom Lane

Allow use of table rowtypes directly as column types of other tables.

Instead of prohibiting that, put code into ALTER TABLE to reject ALTERs
that would affect other tables' columns.  Eventually we will probably
want to extend ALTER TABLE to actually do something useful here, but
in the meantime it seems wrong to forbid the feature completely just
because ALTER isn't fully baked.
上级 19e3bdd6
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.268 2004/06/06 04:52:55 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.269 2004/06/06 20:30:07 tgl Exp $
*
*
* INTERFACE ROUTINES
......@@ -416,10 +416,7 @@ CheckAttributeType(const char *attname, Oid atttypid)
* Warn user, but don't fail, if column to be created has UNKNOWN type
* (usually as a result of a 'retrieve into' - jolly)
*
* Refuse any attempt to create a pseudo-type column or one that uses a
* non-standalone composite type. (We could support using table rowtypes
* as attributes, if we were willing to make ALTER TABLE hugely more
* complex, but for now let's limit the damage ...)
* Refuse any attempt to create a pseudo-type column.
*/
if (atttypid == UNKNOWNOID)
ereport(WARNING,
......@@ -435,16 +432,6 @@ CheckAttributeType(const char *attname, Oid atttypid)
errmsg("column \"%s\" has pseudo-type %s",
attname, format_type_be(atttypid))));
}
else if (att_typtype == 'c')
{
Oid typrelid = get_typ_typrelid(atttypid);
if (get_rel_relkind(typrelid) != RELKIND_COMPOSITE_TYPE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has composite type %s",
attname, format_type_be(atttypid))));
}
}
/* --------------------------------
......
......@@ -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,
......@@ -2281,6 +2283,18 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
else
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
*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册