diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 836e0845c0..b53f6ed3ac 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -9578,7 +9578,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), @@ -9704,20 +9708,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; @@ -9726,6 +9736,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 b78a84e83e..90d09b6b57 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -723,6 +723,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 f97d7e5e4d..ef0674b41a 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -208,6 +208,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;