Handle OID column inheritance correctly in ALTER TABLE ... INHERIT.
authorTom Lane
Wed, 4 Jan 2017 23:00:12 +0000 (18:00 -0500)
committerTom Lane
Wed, 4 Jan 2017 23:00:12 +0000 (18:00 -0500)
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

src/backend/commands/tablecmds.c
src/test/regress/expected/inherit.out
src/test/regress/sql/inherit.sql

index 327ef08b17c499c9fbb17ad9c4c0c132344dcaa7..5098358d5c18de500d4182e100d30ea7c43caa54 100644 (file)
@@ -9356,6 +9356,39 @@ 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++;
+           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);
 }
 
index 6a6b840217f7a6d4d679ba74725758cb0f4d1733..0782242a62a7b89f82f165cffda21bf79ae5e09d 100644 (file)
@@ -612,6 +612,55 @@ select * from d;
  32 | one | two | three
 (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
 create table p1(ff1 int);
 alter table p1 add constraint p1chk check (ff1 > 0) no inherit;
index d65839899c1f3d26797e0d0e99609eaa183efc50..0e390cda3e4d31899bb4c30fe146da81d7e0b569 100644 (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);
 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
 create table p1(ff1 int);
 alter table p1 add constraint p1chk check (ff1 > 0) no inherit;