diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index c0a0165c84a..7d034d26415 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8768,7 +8768,11 @@ ATPrepAlterColumnType(List **wqueue, errmsg("cannot alter system column \"%s\"", colName))); - /* Don't alter inherited columns */ + /* + * Don't alter inherited columns. At outer level, there had better not be + * any inherited definition; when recursing, we assume this was checked at + * the parent level (see below). + */ if (attTup->attinhcount > 0 && !recursing) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), @@ -8892,20 +8896,26 @@ ATPrepAlterColumnType(List **wqueue, if (recurse) { Oid relid = RelationGetRelid(rel); - ListCell *child; - List *children; + List *child_oids, + *child_numparents; + ListCell *lo, + *li; - children = find_all_inheritors(relid, lockmode, NULL); + child_oids = find_all_inheritors(relid, lockmode, + &child_numparents); /* * find_all_inheritors does the recursive search of the inheritance * hierarchy, so all we have to do is process all of the relids in the * list that it returns. */ - foreach(child, children) + forboth(lo, child_oids, li, child_numparents) { - Oid childrelid = lfirst_oid(child); + Oid childrelid = lfirst_oid(lo); + int numparents = lfirst_int(li); Relation childrel; + HeapTuple childtuple; + Form_pg_attribute childattTup; if (childrelid == relid) continue; @@ -8914,6 +8924,29 @@ ATPrepAlterColumnType(List **wqueue, childrel = relation_open(childrelid, NoLock); CheckTableNotInUse(childrel, "ALTER TABLE"); + /* + * Verify that the child doesn't have any inherited definitions of + * this column that came from outside this inheritance hierarchy. + * (renameatt makes a similar test, though in a different way + * because of its different recursion mechanism.) + */ + childtuple = SearchSysCacheAttName(RelationGetRelid(childrel), + colName); + if (!HeapTupleIsValid(childtuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + colName, RelationGetRelationName(childrel)))); + childattTup = (Form_pg_attribute) GETSTRUCT(childtuple); + + if (childattTup->attinhcount > numparents) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot alter inherited column \"%s\" of relation \"%s\"", + colName, RelationGetRelationName(childrel)))); + + ReleaseSysCache(childtuple); + /* * Remap the attribute numbers. If no USING expression was * specified, there is no need for this step. diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 79ea0c5774e..a5654889806 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -701,6 +701,16 @@ select * from d; 32 | one | two | three (1 row) +-- The above verified that we can change the type of a multiply-inherited +-- column; but we should reject that if any definition was inherited from +-- an unrelated parent. +create temp table parent1(f1 int, f2 int); +create temp table parent2(f1 int, f3 bigint); +create temp table childtab(f4 int) inherits(parent1, parent2); +NOTICE: merging multiple inherited definitions of column "f1" +alter table parent1 alter column f1 type bigint; -- fail, conflict w/parent2 +ERROR: cannot alter inherited column "f1" of relation "childtab" +alter table parent1 alter column f2 type bigint; -- ok -- check that oid column is handled properly during alter table inherit create table oid_parent (a int) with oids; create table oid_child () inherits (oid_parent); diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index 101a0394f87..485442fef9d 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -191,6 +191,15 @@ insert into d values('test','one','two','three'); alter table a alter column aa type integer using bit_length(aa); select * from d; +-- The above verified that we can change the type of a multiply-inherited +-- column; but we should reject that if any definition was inherited from +-- an unrelated parent. +create temp table parent1(f1 int, f2 int); +create temp table parent2(f1 int, f3 bigint); +create temp table childtab(f4 int) inherits(parent1, parent2); +alter table parent1 alter column f1 type bigint; -- fail, conflict w/parent2 +alter table parent1 alter column f2 type bigint; -- ok + -- check that oid column is handled properly during alter table inherit create table oid_parent (a int) with oids;