summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/execIndexing.c19
-rw-r--r--src/test/regress/expected/insert_conflict.out23
-rw-r--r--src/test/regress/sql/insert_conflict.sql14
3 files changed, 49 insertions, 7 deletions
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index c819d19db42..0e2d834ed1d 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -259,6 +259,9 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
* the same is done for non-deferred constraints, but report
* if conflict was speculative or deferred conflict to caller)
*
+ * If 'arbiterIndexes' is nonempty, noDupErr applies only to
+ * those indexes. NIL means noDupErr applies to all indexes.
+ *
* CAUTION: this must not be called for a HOT update.
* We can't defend against that here for lack of info.
* Should we change the API to make it safer?
@@ -308,19 +311,15 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
{
Relation indexRelation = relationDescs[i];
IndexInfo *indexInfo;
+ bool applyNoDupErr;
IndexUniqueCheck checkUnique;
bool satisfiesConstraint;
- bool arbiter;
if (indexRelation == NULL)
continue;
indexInfo = indexInfoArray[i];
- /* Record if speculative insertion arbiter */
- arbiter = list_member_oid(arbiterIndexes,
- indexRelation->rd_index->indexrelid);
-
/* If the index is marked as read-only, ignore it */
if (!indexInfo->ii_ReadyForInserts)
continue;
@@ -358,6 +357,12 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
values,
isnull);
+ /* Check whether to apply noDupErr to this index */
+ applyNoDupErr = noDupErr &&
+ (arbiterIndexes == NIL ||
+ list_member_oid(arbiterIndexes,
+ indexRelation->rd_index->indexrelid));
+
/*
* The index AM does the actual insertion, plus uniqueness checking.
*
@@ -373,7 +378,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
*/
if (!indexRelation->rd_index->indisunique)
checkUnique = UNIQUE_CHECK_NO;
- else if (noDupErr && (arbiterIndexes == NIL || arbiter))
+ else if (applyNoDupErr)
checkUnique = UNIQUE_CHECK_PARTIAL;
else if (indexRelation->rd_index->indimmediate)
checkUnique = UNIQUE_CHECK_YES;
@@ -407,7 +412,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
bool violationOK;
CEOUC_WAIT_MODE waitMode;
- if (noDupErr)
+ if (applyNoDupErr)
{
violationOK = true;
waitMode = CEOUC_LIVELOCK_PREVENTING_WAIT;
diff --git a/src/test/regress/expected/insert_conflict.out b/src/test/regress/expected/insert_conflict.out
index 6f4ec867d9f..155774ecfab 100644
--- a/src/test/regress/expected/insert_conflict.out
+++ b/src/test/regress/expected/insert_conflict.out
@@ -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;
diff --git a/src/test/regress/sql/insert_conflict.sql b/src/test/regress/sql/insert_conflict.sql
index 94b1b0aadee..190c6055623 100644
--- a/src/test/regress/sql/insert_conflict.sql
+++ b/src/test/regress/sql/insert_conflict.sql
@@ -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;