Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7112d41

Browse files
author
Commitfest Bot
committed
[CF 5160] v9 - Issues with ON CONFLICT UPDATE and REINDEX CONCURRENTLY
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5160 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/CADzfLwWtK9R3GvEp7ANfO3pE3dbpD3T99f9aGFMwV4HSerHE5w@mail.gmail.com Author(s): Michail Nikolaev
2 parents 470273d + 3c7afd5 commit 7112d41

18 files changed

+1567
-50
lines changed

src/backend/commands/indexcmds.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1790,6 +1790,7 @@ DefineIndex(Oid tableId,
17901790
* before the reference snap was taken, we have to wait out any
17911791
* transactions that might have older snapshots.
17921792
*/
1793+
INJECTION_POINT("define_index_before_set_valid", NULL);
17931794
pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE,
17941795
PROGRESS_CREATEIDX_PHASE_WAIT_3);
17951796
WaitForOlderSnapshots(limitXmin, true);
@@ -4195,7 +4196,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
41954196
* the same time to make sure we only get constraint violations from the
41964197
* indexes with the correct names.
41974198
*/
4198-
4199+
INJECTION_POINT("reindex_relation_concurrently_before_swap", NULL);
41994200
StartTransactionCommand();
42004201

42014202
/*
@@ -4274,6 +4275,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
42744275
* index_drop() for more details.
42754276
*/
42764277

4278+
INJECTION_POINT("reindex_relation_concurrently_before_set_dead", NULL);
42774279
pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE,
42784280
PROGRESS_CREATEIDX_PHASE_WAIT_4);
42794281
WaitForLockersMultiple(lockTags, AccessExclusiveLock, true);

src/backend/executor/execIndexing.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
#include "utils/multirangetypes.h"
118118
#include "utils/rangetypes.h"
119119
#include "utils/snapmgr.h"
120+
#include "utils/injection_point.h"
120121

121122
/* waitMode argument to check_exclusion_or_unique_constraint() */
122123
typedef enum
@@ -942,6 +943,8 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index,
942943
econtext->ecxt_scantuple = save_scantuple;
943944

944945
ExecDropSingleTupleTableSlot(existing_slot);
946+
if (!conflict)
947+
INJECTION_POINT("check_exclusion_or_unique_constraint_no_conflict", NULL);
945948

946949
return !conflict;
947950
}

src/backend/executor/execPartition.c

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,48 @@ ExecFindPartition(ModifyTableState *mtstate,
486486
return rri;
487487
}
488488

489+
/*
490+
* IsIndexCompatibleAsArbiter
491+
* Checks if the indexes are identical in terms of being used
492+
* as arbiters for the INSERT ON CONFLICT operation by comparing
493+
* them to the provided arbiter index.
494+
*
495+
* Returns the true if indexes are compatible.
496+
*/
497+
static bool
498+
IsIndexCompatibleAsArbiter(Relation arbiterIndexRelation,
499+
IndexInfo *arbiterIndexInfo,
500+
Relation indexRelation,
501+
IndexInfo *indexInfo)
502+
{
503+
int i;
504+
505+
if (arbiterIndexInfo->ii_Unique != indexInfo->ii_Unique)
506+
return false;
507+
/* it is not supported for cases of exclusion constraints. */
508+
if (arbiterIndexInfo->ii_ExclusionOps != NULL || indexInfo->ii_ExclusionOps != NULL)
509+
return false;
510+
if (arbiterIndexRelation->rd_index->indnkeyatts != indexRelation->rd_index->indnkeyatts)
511+
return false;
512+
513+
for (i = 0; i < indexRelation->rd_index->indnkeyatts; i++)
514+
{
515+
int arbiterAttoNo = arbiterIndexRelation->rd_index->indkey.values[i];
516+
int attoNo = indexRelation->rd_index->indkey.values[i];
517+
if (arbiterAttoNo != attoNo)
518+
return false;
519+
}
520+
521+
if (list_difference(RelationGetIndexExpressions(arbiterIndexRelation),
522+
RelationGetIndexExpressions(indexRelation)) != NIL)
523+
return false;
524+
525+
if (list_difference(RelationGetIndexPredicate(arbiterIndexRelation),
526+
RelationGetIndexPredicate(indexRelation)) != NIL)
527+
return false;
528+
return true;
529+
}
530+
489531
/*
490532
* ExecInitPartitionInfo
491533
* Lock the partition and initialize ResultRelInfo. Also setup other
@@ -696,6 +738,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
696738
if (rootResultRelInfo->ri_onConflictArbiterIndexes != NIL)
697739
{
698740
List *childIdxs;
741+
List *nonAncestorIdxs = NIL;
742+
int i, j, additional_arbiters = 0;
699743

700744
childIdxs = RelationGetIndexList(leaf_part_rri->ri_RelationDesc);
701745

@@ -706,23 +750,74 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
706750
ListCell *lc2;
707751

708752
ancestors = get_partition_ancestors(childIdx);
709-
foreach(lc2, rootResultRelInfo->ri_onConflictArbiterIndexes)
753+
if (ancestors)
710754
{
711-
if (list_member_oid(ancestors, lfirst_oid(lc2)))
712-
arbiterIndexes = lappend_oid(arbiterIndexes, childIdx);
755+
foreach(lc2, rootResultRelInfo->ri_onConflictArbiterIndexes)
756+
{
757+
if (list_member_oid(ancestors, lfirst_oid(lc2)))
758+
arbiterIndexes = lappend_oid(arbiterIndexes, childIdx);
759+
}
713760
}
761+
else /* No ancestor was found for that index. Save it for rechecking later. */
762+
nonAncestorIdxs = lappend_oid(nonAncestorIdxs, childIdx);
714763
list_free(ancestors);
715764
}
716-
}
717765

718-
/*
719-
* If the resulting lists are of inequal length, something is wrong.
720-
* (This shouldn't happen, since arbiter index selection should not
721-
* pick up an invalid index.)
722-
*/
723-
if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) !=
724-
list_length(arbiterIndexes))
725-
elog(ERROR, "invalid arbiter index list");
766+
/*
767+
* If any non-ancestor indexes are found, we need to compare them with other
768+
* indexes of the relation that will be used as arbiters. This is necessary
769+
* when a partitioned index is processed by REINDEX CONCURRENTLY. Both indexes
770+
* must be considered as arbiters to ensure that all concurrent transactions
771+
* use the same set of arbiters.
772+
*/
773+
if (nonAncestorIdxs)
774+
{
775+
for (i = 0; i < leaf_part_rri->ri_NumIndices; i++)
776+
{
777+
if (list_member_oid(nonAncestorIdxs, leaf_part_rri->ri_IndexRelationDescs[i]->rd_index->indexrelid))
778+
{
779+
Relation nonAncestorIndexRelation = leaf_part_rri->ri_IndexRelationDescs[i];
780+
IndexInfo *nonAncestorIndexInfo = leaf_part_rri->ri_IndexRelationInfo[i];
781+
Assert(!list_member_oid(arbiterIndexes, nonAncestorIndexRelation->rd_index->indexrelid));
782+
783+
/* It is too early to us non-ready indexes as arbiters */
784+
if (!nonAncestorIndexInfo->ii_ReadyForInserts)
785+
continue;
786+
787+
for (j = 0; j < leaf_part_rri->ri_NumIndices; j++)
788+
{
789+
if (list_member_oid(arbiterIndexes,
790+
leaf_part_rri->ri_IndexRelationDescs[j]->rd_index->indexrelid))
791+
{
792+
Relation arbiterIndexRelation = leaf_part_rri->ri_IndexRelationDescs[j];
793+
IndexInfo *arbiterIndexInfo = leaf_part_rri->ri_IndexRelationInfo[j];
794+
795+
/* If non-ancestor index are compatible to arbiter - use it as arbiter too. */
796+
if (IsIndexCompatibleAsArbiter(arbiterIndexRelation, arbiterIndexInfo,
797+
nonAncestorIndexRelation, nonAncestorIndexInfo))
798+
{
799+
arbiterIndexes = lappend_oid(arbiterIndexes,
800+
nonAncestorIndexRelation->rd_index->indexrelid);
801+
additional_arbiters++;
802+
}
803+
}
804+
}
805+
}
806+
}
807+
}
808+
list_free(nonAncestorIdxs);
809+
810+
/*
811+
* If the resulting lists are of inequal length, something is wrong.
812+
* (This shouldn't happen, since arbiter index selection should not
813+
* pick up a non-ready index.)
814+
*
815+
* But we need to consider an additional arbiter indexes also.
816+
*/
817+
if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) !=
818+
list_length(arbiterIndexes) - additional_arbiters)
819+
elog(ERROR, "invalid arbiter index list");
820+
}
726821
leaf_part_rri->ri_onConflictArbiterIndexes = arbiterIndexes;
727822

728823
/*

src/backend/executor/nodeModifyTable.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#include "utils/datum.h"
7070
#include "utils/rel.h"
7171
#include "utils/snapmgr.h"
72+
#include "utils/injection_point.h"
7273

7374

7475
typedef struct MTTargetRelLookup
@@ -1178,6 +1179,7 @@ ExecInsert(ModifyTableContext *context,
11781179
return NULL;
11791180
}
11801181
}
1182+
INJECTION_POINT("exec_insert_before_insert_speculative", NULL);
11811183

11821184
/*
11831185
* Before we start insertion proper, acquire our "speculative

0 commit comments

Comments
 (0)