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),
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;
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.
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
-- Test non-inheritable parent constraints
create table p1(ff1 int);
alter table p1 add constraint p1chk check (ff1 > 0) no inherit;
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
+
-- Test non-inheritable parent constraints
create table p1(ff1 int);
alter table p1 add constraint p1chk check (ff1 > 0) no inherit;