@@ -486,6 +486,48 @@ ExecFindPartition(ModifyTableState *mtstate,
486
486
return rri ;
487
487
}
488
488
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
+
489
531
/*
490
532
* ExecInitPartitionInfo
491
533
* Lock the partition and initialize ResultRelInfo. Also setup other
@@ -696,6 +738,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
696
738
if (rootResultRelInfo -> ri_onConflictArbiterIndexes != NIL )
697
739
{
698
740
List * childIdxs ;
741
+ List * nonAncestorIdxs = NIL ;
742
+ int i , j , additional_arbiters = 0 ;
699
743
700
744
childIdxs = RelationGetIndexList (leaf_part_rri -> ri_RelationDesc );
701
745
@@ -706,23 +750,74 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
706
750
ListCell * lc2 ;
707
751
708
752
ancestors = get_partition_ancestors (childIdx );
709
- foreach ( lc2 , rootResultRelInfo -> ri_onConflictArbiterIndexes )
753
+ if ( ancestors )
710
754
{
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
+ }
713
760
}
761
+ else /* No ancestor was found for that index. Save it for rechecking later. */
762
+ nonAncestorIdxs = lappend_oid (nonAncestorIdxs , childIdx );
714
763
list_free (ancestors );
715
764
}
716
- }
717
765
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
+ }
726
821
leaf_part_rri -> ri_onConflictArbiterIndexes = arbiterIndexes ;
727
822
728
823
/*
0 commit comments