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

Fix failure to handle conflicts in non-arbiter exclusion constraints.

ExecInsertIndexTuples treated an exclusion constraint as subject to
noDupErr processing even when it was not listed in arbiterIndexes, and
would therefore not error out for a conflict in such a constraint, instead
returning it as an arbiter-index failure.  That led to an infinite loop in
ExecInsert, since ExecCheckIndexConstraints ignored the index as-intended
and therefore didn't throw the expected error.  To fix, make the exclusion
constraint code path use the same condition as the index_insert call does
to decide whether no-error-for-duplicates behavior is appropriate.  While
at it, refactor a little bit to avoid unnecessary list_member_oid calls.
(That surely wouldn't save anything worth noticing, but I find the code
a bit clearer this way.)

Per bug report from Heikki Rauhala.  Back-patch to 9.5 where ON CONFLICT
was introduced.

Report: <4C976D6B-76B4-434C-8052-D009F7B7AEDA@reaktor.fi>
This commit is contained in:
Tom Lane
2016-07-04 16:09:11 -04:00
parent 29a2195de6
commit 9c810a2edc
3 changed files with 49 additions and 7 deletions

View File

@ -704,3 +704,26 @@ insert into dropcol(key, keep1, keep2) values(1, '5', 5) on conflict(key)
;
DROP TABLE dropcol;
-- check handling of regular btree constraint along with gist constraint
create table twoconstraints (f1 int unique, f2 box,
exclude using gist(f2 with &&));
insert into twoconstraints values(1, '((0,0),(1,1))');
insert into twoconstraints values(1, '((2,2),(3,3))'); -- fail on f1
ERROR: duplicate key value violates unique constraint "twoconstraints_f1_key"
DETAIL: Key (f1)=(1) already exists.
insert into twoconstraints values(2, '((0,0),(1,2))'); -- fail on f2
ERROR: conflicting key value violates exclusion constraint "twoconstraints_f2_excl"
DETAIL: Key (f2)=((1,2),(0,0)) conflicts with existing key (f2)=((1,1),(0,0)).
insert into twoconstraints values(2, '((0,0),(1,2))')
on conflict on constraint twoconstraints_f1_key do nothing; -- fail on f2
ERROR: conflicting key value violates exclusion constraint "twoconstraints_f2_excl"
DETAIL: Key (f2)=((1,2),(0,0)) conflicts with existing key (f2)=((1,1),(0,0)).
insert into twoconstraints values(2, '((0,0),(1,2))')
on conflict on constraint twoconstraints_f2_excl do nothing; -- do nothing
select * from twoconstraints;
f1 | f2
----+-------------
1 | (1,1),(0,0)
(1 row)
drop table twoconstraints;

View File

@ -407,3 +407,17 @@ insert into dropcol(key, keep1, keep2) values(1, '5', 5) on conflict(key)
;
DROP TABLE dropcol;
-- check handling of regular btree constraint along with gist constraint
create table twoconstraints (f1 int unique, f2 box,
exclude using gist(f2 with &&));
insert into twoconstraints values(1, '((0,0),(1,1))');
insert into twoconstraints values(1, '((2,2),(3,3))'); -- fail on f1
insert into twoconstraints values(2, '((0,0),(1,2))'); -- fail on f2
insert into twoconstraints values(2, '((0,0),(1,2))')
on conflict on constraint twoconstraints_f1_key do nothing; -- fail on f2
insert into twoconstraints values(2, '((0,0),(1,2))')
on conflict on constraint twoconstraints_f2_excl do nothing; -- do nothing
select * from twoconstraints;
drop table twoconstraints;