diff options
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/commands/indexcmds.c | 3 | ||||
| -rw-r--r-- | src/backend/executor/execIndexing.c | 8 | ||||
| -rw-r--r-- | src/backend/executor/execPartition.c | 5 | ||||
| -rw-r--r-- | src/backend/executor/nodeModifyTable.c | 2 | ||||
| -rw-r--r-- | src/backend/optimizer/util/plancat.c | 27 | ||||
| -rw-r--r-- | src/backend/utils/time/snapmgr.c | 2 |
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); } } |
