diff options
author | Tom Lane | 2016-07-04 20:09:11 +0000 |
---|---|---|
committer | Tom Lane | 2016-07-04 20:09:11 +0000 |
commit | 9c810a2edccaffe0ff48b50d31c47a155e4f9815 (patch) | |
tree | 62b834fa1bba35c137e555c757559fce72aa70d3 /src/backend/executor/execIndexing.c | |
parent | 29a2195de645759d66ee7e77c4c05b2c4aeb6729 (diff) |
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: <[email protected]>
Diffstat (limited to 'src/backend/executor/execIndexing.c')
-rw-r--r-- | src/backend/executor/execIndexing.c | 19 |
1 files changed, 12 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; |