summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/indexcmds.c3
-rw-r--r--src/backend/executor/execIndexing.c8
-rw-r--r--src/backend/executor/execPartition.c5
-rw-r--r--src/backend/executor/nodeModifyTable.c2
-rw-r--r--src/backend/optimizer/util/plancat.c27
-rw-r--r--src/backend/utils/time/snapmgr.c2
6 files changed, 40 insertions, 7 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 5712fac3697..a8033be4bff 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1789,6 +1789,7 @@ DefineIndex(Oid tableId,
* before the reference snap was taken, we have to wait out any
* transactions that might have older snapshots.
*/
+ INJECTION_POINT("define-index-before-set-valid", NULL);
pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE,
PROGRESS_CREATEIDX_PHASE_WAIT_3);
WaitForOlderSnapshots(limitXmin, true);
@@ -4229,6 +4230,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
* indexes with the correct names.
*/
+ INJECTION_POINT("reindex-relation-concurrently-before-swap", NULL);
StartTransactionCommand();
/*
@@ -4307,6 +4309,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
* index_drop() for more details.
*/
+ INJECTION_POINT("reindex-relation-concurrently-before-set-dead", NULL);
pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE,
PROGRESS_CREATEIDX_PHASE_WAIT_4);
WaitForLockersMultiple(lockTags, AccessExclusiveLock, true);
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 401606f840a..d1cbab58799 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -114,6 +114,7 @@
#include "executor/executor.h"
#include "nodes/nodeFuncs.h"
#include "storage/lmgr.h"
+#include "utils/injection_point.h"
#include "utils/multirangetypes.h"
#include "utils/rangetypes.h"
#include "utils/snapmgr.h"
@@ -943,6 +944,13 @@ retry:
ExecDropSingleTupleTableSlot(existing_slot);
+#ifdef USE_INJECTION_POINTS
+ if (conflict)
+ INJECTION_POINT("check-exclusion-or-unique-constraint-conflict", NULL);
+ else
+ INJECTION_POINT("check-exclusion-or-unique-constraint-no-conflict", NULL);
+#endif
+
return !conflict;
}
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index aa12e9ad2ea..0dcce181f09 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -722,8 +722,9 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
/*
* If the resulting lists are of inequal length, something is wrong.
- * (This shouldn't happen, since arbiter index selection should not
- * pick up an invalid index.)
+ * XXX This may happen because we don't match the lists correctly when
+ * a partitioned index is being processed by REINDEX CONCURRENTLY.
+ * FIXME later.
*/
if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) !=
list_length(arbiterIndexes))
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 00429326c34..e44f1223886 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -68,6 +68,7 @@
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/datum.h"
+#include "utils/injection_point.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
@@ -1186,6 +1187,7 @@ ExecInsert(ModifyTableContext *context,
* if we're going to go ahead with the insertion, instead of
* waiting for the whole transaction to complete.
*/
+ INJECTION_POINT("exec-insert-before-insert-speculative", NULL);
specToken = SpeculativeInsertionLockAcquire(GetCurrentTransactionId());
/* insert the tuple, with the speculative token */
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index d950bd93002..7af9a2064e3 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -814,6 +814,7 @@ infer_arbiter_indexes(PlannerInfo *root)
/* Results */
List *results = NIL;
+ bool foundValid = false;
/*
* Quickly return NIL for ON CONFLICT DO NOTHING without an inference
@@ -907,7 +908,22 @@ infer_arbiter_indexes(PlannerInfo *root)
idxRel = index_open(indexoid, rte->rellockmode);
idxForm = idxRel->rd_index;
- if (!idxForm->indisvalid)
+ /*
+ * Ignore indexes that aren't indisready, because we cannot trust
+ * their catalog structure yet. However, if any indexes are marked
+ * indisready but not yet indisvalid, we still consider them, because
+ * they might turn valid while we're running. Doing it this way
+ * allows a concurrent transaction with a slightly later catalog
+ * snapshot infer the same set of indexes, which is critical to
+ * prevent spurious 'duplicate key' errors.
+ *
+ * However, another critical aspect is that a unique index that isn't
+ * yet marked indisvalid=true might not be complete yet, meaning it
+ * wouldn't detect possible duplicate rows. In order to prevent false
+ * negatives, we require that we include in the set of inferred
+ * indexes at least one index that is marked valid.
+ */
+ if (!idxForm->indisready)
goto next;
/*
@@ -929,10 +945,9 @@ infer_arbiter_indexes(PlannerInfo *root)
errmsg("ON CONFLICT DO UPDATE not supported with exclusion constraints")));
results = lappend_oid(results, idxForm->indexrelid);
- list_free(indexList);
+ foundValid |= idxForm->indisvalid;
index_close(idxRel, NoLock);
- table_close(relation, NoLock);
- return results;
+ break;
}
else if (indexOidFromConstraint != InvalidOid)
{
@@ -1033,6 +1048,7 @@ infer_arbiter_indexes(PlannerInfo *root)
goto next;
results = lappend_oid(results, idxForm->indexrelid);
+ foundValid |= idxForm->indisvalid;
next:
index_close(idxRel, NoLock);
}
@@ -1040,7 +1056,8 @@ next:
list_free(indexList);
table_close(relation, NoLock);
- if (results == NIL)
+ /* We require at least one indisvalid index */
+ if (results == NIL || !foundValid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("there is no unique or exclusion constraint matching the ON CONFLICT specification")));
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 65561cc6bc3..24f73a49d27 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -119,6 +119,7 @@
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
+#include "utils/injection_point.h"
#include "utils/memutils.h"
#include "utils/resowner.h"
#include "utils/snapmgr.h"
@@ -458,6 +459,7 @@ InvalidateCatalogSnapshot(void)
pairingheap_remove(&RegisteredSnapshots, &CatalogSnapshot->ph_node);
CatalogSnapshot = NULL;
SnapshotResetXmin();
+ INJECTION_POINT("invalidate-catalog-snapshot-end", NULL);
}
}