Fix ON CONFLICT DO UPDATE for tables with oids.
authorAndres Freund <andres@anarazel.de>
Mon, 28 Sep 2015 17:12:48 +0000 (19:12 +0200)
committerAndres Freund <andres@anarazel.de>
Mon, 28 Sep 2015 17:29:44 +0000 (19:29 +0200)
When taking the UPDATE path in an INSERT .. ON CONFLICT .. UPDATE tables
with oids were not supported. The tuple generated by the update target
list was projected without space for an oid - a simple oversight.

Reported-By: Peter Geoghegan
Author: Andres Freund
Backpatch: 9.5, where ON CONFLICT was introduced

src/backend/executor/nodeModifyTable.c
src/test/regress/expected/insert_conflict.out
src/test/regress/sql/insert_conflict.sql

index 1ef76d092859311abdc28afe7992e6783e25e72a..dabaea991096998c78d61653569c59c30546bd24 100644 (file)
@@ -1678,7 +1678,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 
        /* create target slot for UPDATE SET projection */
        tupDesc = ExecTypeFromTL((List *) node->onConflictSet,
-                                false);
+                        resultRelInfo->ri_RelationDesc->rd_rel->relhasoids);
        mtstate->mt_conflproj = ExecInitExtraTupleSlot(mtstate->ps.state);
        ExecSetSlotDescriptor(mtstate->mt_conflproj, tupDesc);
 
index 09b67db43c186ead376ee49c46007d251bc66129..1399f3c796224da54962189dc24d075e4a62e1ac 100644 (file)
@@ -507,3 +507,62 @@ insert into excluded values(1, '2') on conflict (key) do update set data = 3 RET
 
 -- clean up
 drop table excluded;
+-- Check tables w/o oids are handled correctly
+create table testoids(key int primary key, data text) without oids;
+-- first without oids
+insert into testoids values(1, '1') on conflict (key) do update set data = excluded.data RETURNING *;
+ key | data 
+-----+------
+   1 | 1
+(1 row)
+
+insert into testoids values(1, '2') on conflict (key) do update set data = excluded.data RETURNING *;
+ key | data 
+-----+------
+   1 | 2
+(1 row)
+
+-- add oids
+alter table testoids set with oids;
+-- update existing row, that didn't have an oid
+insert into testoids values(1, '3') on conflict (key) do update set data = excluded.data RETURNING *;
+ key | data 
+-----+------
+   1 | 3
+(1 row)
+
+-- insert a new row
+insert into testoids values(2, '1') on conflict (key) do update set data = excluded.data RETURNING *;
+ key | data 
+-----+------
+   2 | 1
+(1 row)
+
+-- and update it
+insert into testoids values(2, '2') on conflict (key) do update set data = excluded.data RETURNING *;
+ key | data 
+-----+------
+   2 | 2
+(1 row)
+
+-- remove oids again, test
+alter table testoids set without oids;
+insert into testoids values(1, '4') on conflict (key) do update set data = excluded.data RETURNING *;
+ key | data 
+-----+------
+   1 | 4
+(1 row)
+
+insert into testoids values(3, '1') on conflict (key) do update set data = excluded.data RETURNING *;
+ key | data 
+-----+------
+   3 | 1
+(1 row)
+
+insert into testoids values(3, '2') on conflict (key) do update set data = excluded.data RETURNING *;
+ key | data 
+-----+------
+   3 | 2
+(1 row)
+
+DROP TABLE testoids;
index e981e67fd27b922a572b04ed238e279918048799..efa902ec121c5483a417a020c7717ff865b5ac75 100644 (file)
@@ -295,3 +295,25 @@ insert into excluded values(1, '2') on conflict (key) do update set data = 3 RET
 
 -- clean up
 drop table excluded;
+
+
+-- Check tables w/o oids are handled correctly
+create table testoids(key int primary key, data text) without oids;
+-- first without oids
+insert into testoids values(1, '1') on conflict (key) do update set data = excluded.data RETURNING *;
+insert into testoids values(1, '2') on conflict (key) do update set data = excluded.data RETURNING *;
+-- add oids
+alter table testoids set with oids;
+-- update existing row, that didn't have an oid
+insert into testoids values(1, '3') on conflict (key) do update set data = excluded.data RETURNING *;
+-- insert a new row
+insert into testoids values(2, '1') on conflict (key) do update set data = excluded.data RETURNING *;
+-- and update it
+insert into testoids values(2, '2') on conflict (key) do update set data = excluded.data RETURNING *;
+-- remove oids again, test
+alter table testoids set without oids;
+insert into testoids values(1, '4') on conflict (key) do update set data = excluded.data RETURNING *;
+insert into testoids values(3, '1') on conflict (key) do update set data = excluded.data RETURNING *;
+insert into testoids values(3, '2') on conflict (key) do update set data = excluded.data RETURNING *;
+
+DROP TABLE testoids;