Ensure that INSERT ... SELECT into a table with OIDs never copies row OIDs
authorTom Lane <[email protected]>
Sun, 8 Feb 2009 18:02:27 +0000 (18:02 +0000)
committerTom Lane <[email protected]>
Sun, 8 Feb 2009 18:02:27 +0000 (18:02 +0000)
from the source table.  This could never happen anyway before 8.4 because
the executor invariably applied a "junk filter" to rows due to be inserted;
but now that we skip doing that when it's not necessary, the case can occur.
Problem noted 2008-11-27 by KaiGai Kohei, though I misunderstood what he
was on about at the time (the opacity of the patch he proposed didn't help).

src/backend/executor/execMain.c

index 0dcb28544a6eff6908067c89ecf6121704f2c4df..7931926a340ef2e1e102efd11f6ae53643afbf1b 100644 (file)
@@ -1766,6 +1766,21 @@ ExecInsert(TupleTableSlot *slot,
        resultRelInfo = estate->es_result_relation_info;
        resultRelationDesc = resultRelInfo->ri_RelationDesc;
 
+       /*
+        * If the result relation has OIDs, force the tuple's OID to zero so that
+        * heap_insert will assign a fresh OID.  Usually the OID already will be
+        * zero at this point, but there are corner cases where the plan tree can
+        * return a tuple extracted literally from some table with the same
+        * rowtype.
+        *
+        * XXX if we ever wanted to allow users to assign their own OIDs to new
+        * rows, this'd be the place to do it.  For the moment, we make a point
+        * of doing this before calling triggers, so that a user-supplied trigger
+        * could hack the OID if desired.
+        */
+       if (resultRelationDesc->rd_rel->relhasoids)
+               HeapTupleSetOid(tuple, InvalidOid);
+
        /* BEFORE ROW INSERT Triggers */
        if (resultRelInfo->ri_TrigDesc &&
                resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
@@ -3033,6 +3048,12 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self)
         */
        tuple = ExecMaterializeSlot(slot);
 
+       /*
+        * force assignment of new OID (see comments in ExecInsert)
+        */
+       if (myState->rel->rd_rel->relhasoids)
+               HeapTupleSetOid(tuple, InvalidOid);
+
        heap_insert(myState->rel,
                                tuple,
                                myState->estate->es_output_cid,