Skip to content

Commit 38c4d9f

Browse files
michail-nikolaevCommitfest Bot
authored andcommitted
Modify the infer_arbiter_indexes function to consider both indisvalid and indisready indexes. Ensure that at least one indisvalid index is still required.
The change ensures that all concurrent transactions utilize the same set of indexes as arbiters. This uniformity is required to avoid conditions that could lead to "duplicate key value violates unique constraint" errors during UPSERT operations. The patch resolves the issues in the following specs: * reindex_concurrently_upsert * index_concurrently_upsert * index_concurrently_upsert_predicate Despite the patch, the following specs are still affected: * reindex_concurrently_upsert_partitioned * reindex_concurrently_upsert_on_constraint
1 parent bb368fd commit 38c4d9f

File tree

1 file changed

+13
-5
lines changed

1 file changed

+13
-5
lines changed

src/backend/optimizer/util/plancat.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,7 @@ infer_arbiter_indexes(PlannerInfo *root)
814814

815815
/* Results */
816816
List *results = NIL;
817+
bool foundValid = false;
817818

818819
/*
819820
* Quickly return NIL for ON CONFLICT DO NOTHING without an inference
@@ -907,7 +908,13 @@ infer_arbiter_indexes(PlannerInfo *root)
907908
idxRel = index_open(indexoid, rte->rellockmode);
908909
idxForm = idxRel->rd_index;
909910

910-
if (!idxForm->indisvalid)
911+
/*
912+
* We need to consider both indisvalid and indisready indexes because
913+
* them may become indisvalid before execution phase. It is required
914+
* to keep set of indexes used as arbiter to be the same for all
915+
* concurrent transactions.
916+
*/
917+
if (!idxForm->indisready)
911918
goto next;
912919

913920
/*
@@ -929,10 +936,9 @@ infer_arbiter_indexes(PlannerInfo *root)
929936
errmsg("ON CONFLICT DO UPDATE not supported with exclusion constraints")));
930937

931938
results = lappend_oid(results, idxForm->indexrelid);
932-
list_free(indexList);
939+
foundValid |= idxForm->indisvalid;
933940
index_close(idxRel, NoLock);
934-
table_close(relation, NoLock);
935-
return results;
941+
break;
936942
}
937943
else if (indexOidFromConstraint != InvalidOid)
938944
{
@@ -1033,14 +1039,16 @@ infer_arbiter_indexes(PlannerInfo *root)
10331039
goto next;
10341040

10351041
results = lappend_oid(results, idxForm->indexrelid);
1042+
foundValid |= idxForm->indisvalid;
10361043
next:
10371044
index_close(idxRel, NoLock);
10381045
}
10391046

10401047
list_free(indexList);
10411048
table_close(relation, NoLock);
10421049

1043-
if (results == NIL)
1050+
/* It is required to have at least one indisvalid index during the planning. */
1051+
if (results == NIL || !foundValid)
10441052
ereport(ERROR,
10451053
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
10461054
errmsg("there is no unique or exclusion constraint matching the ON CONFLICT specification")));

0 commit comments

Comments
 (0)