1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-01 01:04:50 +03:00

Handle OID column inheritance correctly in ALTER TABLE ... INHERIT.

Inheritance operations must treat the OID column, if any, much like
regular user columns.  But MergeAttributesIntoExisting() neglected to
do that, leading to weird results after a table with OIDs is associated
to a parent with OIDs via ALTER TABLE ... INHERIT.

Report and patch by Amit Langote, reviewed by Ashutosh Bapat, some
adjustments by me.  It's been broken all along, so back-patch to
all supported branches.

Discussion: https://postgr.es/m/cb13cfe7-a48c-5720-c383-bb843ab28298@lab.ntt.co.jp
This commit is contained in:
Tom Lane 2017-01-04 18:00:11 -05:00
parent 44f7afba79
commit d86f40009b
3 changed files with 117 additions and 2 deletions

View File

@ -1605,8 +1605,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
* execute if the user attempts to create a table with hundreds of * execute if the user attempts to create a table with hundreds of
* thousands of columns. * thousands of columns.
* *
* Note that we also need to check that we do not exceed this figure * Note that we also need to check that we do not exceed this figure after
* after including columns from inherited relations. * including columns from inherited relations.
*/ */
if (list_length(schema) > MaxHeapAttributeNumber) if (list_length(schema) > MaxHeapAttributeNumber)
ereport(ERROR, ereport(ERROR,
@ -10902,6 +10902,46 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
} }
} }
/*
* If the parent has an OID column, so must the child, and we'd better
* update the child's attinhcount and attislocal the same as for normal
* columns. We needn't check data type or not-nullness though.
*/
if (tupleDesc->tdhasoid)
{
/*
* Here we match by column number not name; the match *must* be the
* system column, not some random column named "oid".
*/
tuple = SearchSysCacheCopy2(ATTNUM,
ObjectIdGetDatum(RelationGetRelid(child_rel)),
Int16GetDatum(ObjectIdAttributeNumber));
if (HeapTupleIsValid(tuple))
{
Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
/* See comments above; these changes should be the same */
childatt->attinhcount++;
if (child_is_partition)
{
Assert(childatt->attinhcount == 1);
childatt->attislocal = false;
}
simple_heap_update(attrrel, &tuple->t_self, tuple);
CatalogUpdateIndexes(attrrel, tuple);
heap_freetuple(tuple);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("child table is missing column \"%s\"",
"oid")));
}
}
heap_close(attrrel, RowExclusiveLock); heap_close(attrrel, RowExclusiveLock);
} }

View File

@ -612,6 +612,55 @@ select * from d;
32 | one | two | three 32 | one | two | three
(1 row) (1 row)
-- 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);
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
attinhcount | attislocal
-------------+------------
1 | f
(1 row)
drop table oid_child;
create table oid_child (a int) without oids;
alter table oid_child inherit oid_parent; -- fail
ERROR: table "oid_child" without OIDs cannot inherit from table "oid_parent" with OIDs
alter table oid_child set with oids;
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
attinhcount | attislocal
-------------+------------
0 | t
(1 row)
alter table oid_child inherit oid_parent;
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
attinhcount | attislocal
-------------+------------
1 | t
(1 row)
alter table oid_child set without oids; -- fail
ERROR: cannot drop inherited column "oid"
alter table oid_parent set without oids;
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
attinhcount | attislocal
-------------+------------
0 | t
(1 row)
alter table oid_child set without oids;
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
attinhcount | attislocal
-------------+------------
(0 rows)
drop table oid_parent cascade;
NOTICE: drop cascades to table oid_child
-- Test non-inheritable parent constraints -- Test non-inheritable parent constraints
create table p1(ff1 int); create table p1(ff1 int);
alter table p1 add constraint p1chk check (ff1 > 0) no inherit; alter table p1 add constraint p1chk check (ff1 > 0) no inherit;

View File

@ -145,6 +145,32 @@ insert into d values('test','one','two','three');
alter table a alter column aa type integer using bit_length(aa); alter table a alter column aa type integer using bit_length(aa);
select * from d; select * from d;
-- 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);
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
drop table oid_child;
create table oid_child (a int) without oids;
alter table oid_child inherit oid_parent; -- fail
alter table oid_child set with oids;
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
alter table oid_child inherit oid_parent;
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
alter table oid_child set without oids; -- fail
alter table oid_parent set without oids;
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
alter table oid_child set without oids;
select attinhcount, attislocal from pg_attribute
where attrelid = 'oid_child'::regclass and attname = 'oid';
drop table oid_parent cascade;
-- Test non-inheritable parent constraints -- Test non-inheritable parent constraints
create table p1(ff1 int); create table p1(ff1 int);
alter table p1 add constraint p1chk check (ff1 > 0) no inherit; alter table p1 add constraint p1chk check (ff1 > 0) no inherit;